From 7441a2bd4f9983e69fa66d8afb8a16753e6a8224 Mon Sep 17 00:00:00 2001 From: Yaxun Liu Date: Thu, 18 Aug 2016 19:34:04 +0000 Subject: [PATCH] [OpenCL] AMDGCN: Fix size_t type Pointers of certain GPUs in AMDGCN target in private address space is 32 bit but pointers in other address spaces are 64 bit. size_t type should be defined as 64 bit for these GPUs so that it could hold pointers in all address spaces. Also fixed issues in pointer arithmetic codegen by using pointer specific intptr type. Differential Revision: https://reviews.llvm.org/D23361 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@279121 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/TargetInfo.h | 5 ++ lib/Basic/TargetInfo.cpp | 5 +- lib/Basic/Targets.cpp | 4 ++ lib/CodeGen/CGExprScalar.cpp | 15 +++-- lib/CodeGen/CodeGenModule.cpp | 5 +- lib/CodeGen/CodeGenTypeCache.h | 5 ++ test/CodeGenOpenCL/size_t.cl | 110 +++++++++++++++++++++++++++++++ 7 files changed, 140 insertions(+), 9 deletions(-) create mode 100644 test/CodeGenOpenCL/size_t.cl diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index a9378f83af..de94cdacd2 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -294,6 +294,11 @@ public: return AddrSpace == 0 ? PointerAlign : getPointerAlignV(AddrSpace); } + /// \brief Return the maximum width of pointers on this target. + virtual uint64_t getMaxPointerWidth() const { + return PointerWidth; + } + /// \brief Return the size of '_Bool' and C++ 'bool' for this target, in bits. unsigned getBoolWidth() const { return BoolWidth; } diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index dec8b7cda4..592b877fad 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -306,8 +306,9 @@ void TargetInfo::adjust(const LangOptions &Opts) { } LongDoubleWidth = LongDoubleAlign = 128; - assert(PointerWidth == 32 || PointerWidth == 64); - bool Is32BitArch = PointerWidth == 32; + unsigned MaxPointerWidth = getMaxPointerWidth(); + assert(MaxPointerWidth == 32 || MaxPointerWidth == 64); + bool Is32BitArch = MaxPointerWidth == 32; SizeType = Is32BitArch ? UnsignedInt : UnsignedLong; PtrDiffType = Is32BitArch ? SignedInt : SignedLong; IntPtrType = Is32BitArch ? SignedInt : SignedLong; diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 793b25e928..36e6d4594f 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -2004,6 +2004,10 @@ public: } } + uint64_t getMaxPointerWidth() const override { + return getTriple().getArch() == llvm::Triple::amdgcn ? 64 : 32; + } + const char * getClobbers() const override { return ""; } diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index ba7f49b750..0af4c41816 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -787,7 +787,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, // Handle pointer conversions next: pointers can only be converted to/from // other pointers and integers. Check for pointer types in terms of LLVM, as // some native types (like Obj-C id) may map to a pointer type. - if (isa(DstTy)) { + if (auto DstPT = dyn_cast(DstTy)) { // The source value may be an integer, or a pointer. if (isa(SrcTy)) return Builder.CreateBitCast(Src, DstTy, "conv"); @@ -795,7 +795,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, assert(SrcType->isIntegerType() && "Not ptr->ptr or int->ptr conversion?"); // First, convert to the correct width so that we control the kind of // extension. - llvm::Type *MiddleTy = CGF.IntPtrTy; + llvm::Type *MiddleTy = CGF.CGM.getDataLayout().getIntPtrType(DstPT); bool InputSigned = SrcType->isSignedIntegerOrEnumerationType(); llvm::Value* IntResult = Builder.CreateIntCast(Src, MiddleTy, InputSigned, "conv"); @@ -1510,12 +1510,13 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { // First, convert to the correct width so that we control the kind of // extension. - llvm::Type *MiddleTy = CGF.IntPtrTy; + auto DestLLVMTy = ConvertType(DestTy); + llvm::Type *MiddleTy = CGF.CGM.getDataLayout().getIntPtrType(DestLLVMTy); bool InputSigned = E->getType()->isSignedIntegerOrEnumerationType(); llvm::Value* IntResult = Builder.CreateIntCast(Src, MiddleTy, InputSigned, "conv"); - return Builder.CreateIntToPtr(IntResult, ConvertType(DestTy)); + return Builder.CreateIntToPtr(IntResult, DestLLVMTy); } case CK_PointerToIntegral: assert(!DestTy->isBooleanType() && "bool should use PointerToBool"); @@ -2426,6 +2427,7 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF, Value *pointer = op.LHS; Expr *pointerOperand = expr->getLHS(); + auto PtrTy = cast(pointer->getType()); Value *index = op.RHS; Expr *indexOperand = expr->getRHS(); @@ -2436,11 +2438,12 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF, } unsigned width = cast(index->getType())->getBitWidth(); - if (width != CGF.PointerWidthInBits) { + auto &DL = CGF.CGM.getDataLayout(); + if (width != DL.getTypeSizeInBits(PtrTy)) { // Zero-extend or sign-extend the pointer value according to // whether the index is signed or not. bool isSigned = indexOperand->getType()->isSignedIntegerOrEnumerationType(); - index = CGF.Builder.CreateIntCast(index, CGF.PtrDiffTy, isSigned, + index = CGF.Builder.CreateIntCast(index, DL.getIntPtrType(PtrTy), isSigned, "idx.ext"); } diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 2dcccf4c6c..1d74e4cd83 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -101,10 +101,13 @@ CodeGenModule::CodeGenModule(ASTContext &C, const HeaderSearchOptions &HSO, PointerWidthInBits = C.getTargetInfo().getPointerWidth(0); PointerAlignInBytes = C.toCharUnitsFromBits(C.getTargetInfo().getPointerAlign(0)).getQuantity(); + SizeSizeInBytes = + C.toCharUnitsFromBits(C.getTargetInfo().getMaxPointerWidth()).getQuantity(); IntAlignInBytes = C.toCharUnitsFromBits(C.getTargetInfo().getIntAlign()).getQuantity(); IntTy = llvm::IntegerType::get(LLVMContext, C.getTargetInfo().getIntWidth()); - IntPtrTy = llvm::IntegerType::get(LLVMContext, PointerWidthInBits); + IntPtrTy = llvm::IntegerType::get(LLVMContext, + C.getTargetInfo().getMaxPointerWidth()); Int8PtrTy = Int8Ty->getPointerTo(0); Int8PtrPtrTy = Int8PtrTy->getPointerTo(0); diff --git a/lib/CodeGen/CodeGenTypeCache.h b/lib/CodeGen/CodeGenTypeCache.h index c32b66d129..47e26bcaa1 100644 --- a/lib/CodeGen/CodeGenTypeCache.h +++ b/lib/CodeGen/CodeGenTypeCache.h @@ -80,9 +80,14 @@ struct CodeGenTypeCache { union { unsigned char PointerAlignInBytes; unsigned char PointerSizeInBytes; + }; + + /// The size and alignment of size_t. + union { unsigned char SizeSizeInBytes; // sizeof(size_t) unsigned char SizeAlignInBytes; }; + CharUnits getSizeSize() const { return CharUnits::fromQuantity(SizeSizeInBytes); } diff --git a/test/CodeGenOpenCL/size_t.cl b/test/CodeGenOpenCL/size_t.cl new file mode 100644 index 0000000000..ed941e0185 --- /dev/null +++ b/test/CodeGenOpenCL/size_t.cl @@ -0,0 +1,110 @@ +// RUN: %clang_cc1 %s -cl-std=CL2.0 -finclude-default-header -emit-llvm -O0 -triple spir-unknown-unknown -o - | FileCheck --check-prefix=SZ32 %s +// RUN: %clang_cc1 %s -cl-std=CL2.0 -finclude-default-header -emit-llvm -O0 -triple spir64-unknown-unknown -o - | FileCheck --check-prefix=SZ64 --check-prefix=SZ64ONLY %s +// RUN: %clang_cc1 %s -cl-std=CL2.0 -finclude-default-header -emit-llvm -O0 -triple amdgcn-- -o - | FileCheck --check-prefix=SZ64 --check-prefix=AMDONLY %s + +//SZ32: define{{.*}} i32 @test_ptrtoint_private(i8* %x) +//SZ32: ptrtoint i8* %{{.*}} to i32 +//SZ64: define{{.*}} i64 @test_ptrtoint_private(i8* %x) +//SZ64: ptrtoint i8* %{{.*}} to i64 +size_t test_ptrtoint_private(private char* x) { + return (size_t)x; +} + +//SZ32: define{{.*}} i32 @test_ptrtoint_global(i8 addrspace(1)* %x) +//SZ32: ptrtoint i8 addrspace(1)* %{{.*}} to i32 +//SZ64: define{{.*}} i64 @test_ptrtoint_global(i8 addrspace(1)* %x) +//SZ64: ptrtoint i8 addrspace(1)* %{{.*}} to i64 +intptr_t test_ptrtoint_global(global char* x) { + return (intptr_t)x; +} + +//SZ32: define{{.*}} i32 @test_ptrtoint_constant(i8 addrspace(2)* %x) +//SZ32: ptrtoint i8 addrspace(2)* %{{.*}} to i32 +//SZ64: define{{.*}} i64 @test_ptrtoint_constant(i8 addrspace(2)* %x) +//SZ64: ptrtoint i8 addrspace(2)* %{{.*}} to i64 +uintptr_t test_ptrtoint_constant(constant char* x) { + return (uintptr_t)x; +} + +//SZ32: define{{.*}} i32 @test_ptrtoint_local(i8 addrspace(3)* %x) +//SZ32: ptrtoint i8 addrspace(3)* %{{.*}} to i32 +//SZ64: define{{.*}} i64 @test_ptrtoint_local(i8 addrspace(3)* %x) +//SZ64: ptrtoint i8 addrspace(3)* %{{.*}} to i64 +size_t test_ptrtoint_local(local char* x) { + return (size_t)x; +} + +//SZ32: define{{.*}} i32 @test_ptrtoint_generic(i8 addrspace(4)* %x) +//SZ32: ptrtoint i8 addrspace(4)* %{{.*}} to i32 +//SZ64: define{{.*}} i64 @test_ptrtoint_generic(i8 addrspace(4)* %x) +//SZ64: ptrtoint i8 addrspace(4)* %{{.*}} to i64 +size_t test_ptrtoint_generic(generic char* x) { + return (size_t)x; +} + +//SZ32: define{{.*}} i8* @test_inttoptr_private(i32 %x) +//SZ32: inttoptr i32 %{{.*}} to i8* +//SZ64: define{{.*}} i8* @test_inttoptr_private(i64 %x) +//AMDONLY: trunc i64 %{{.*}} to i32 +//AMDONLY: inttoptr i32 %{{.*}} to i8* +//SZ64ONLY: inttoptr i64 %{{.*}} to i8* +private char* test_inttoptr_private(size_t x) { + return (private char*)x; +} + +//SZ32: define{{.*}} i8 addrspace(1)* @test_inttoptr_global(i32 %x) +//SZ32: inttoptr i32 %{{.*}} to i8 addrspace(1)* +//SZ64: define{{.*}} i8 addrspace(1)* @test_inttoptr_global(i64 %x) +//SZ64: inttoptr i64 %{{.*}} to i8 addrspace(1)* +global char* test_inttoptr_global(size_t x) { + return (global char*)x; +} + +//SZ32: define{{.*}} i8 addrspace(3)* @test_add_local(i8 addrspace(3)* %x, i32 %y) +//SZ32: getelementptr inbounds i8, i8 addrspace(3)* %{{.*}}, i32 +//SZ64: define{{.*}} i8 addrspace(3)* @test_add_local(i8 addrspace(3)* %x, i64 %y) +//AMDONLY: trunc i64 %{{.*}} to i32 +//AMDONLY: getelementptr inbounds i8, i8 addrspace(3)* %{{.*}}, i32 +//SZ64ONLY: getelementptr inbounds i8, i8 addrspace(3)* %{{.*}}, i64 +local char* test_add_local(local char* x, ptrdiff_t y) { + return x + y; +} + +//SZ32: define{{.*}} i8 addrspace(1)* @test_add_global(i8 addrspace(1)* %x, i32 %y) +//SZ32: getelementptr inbounds i8, i8 addrspace(1)* %{{.*}}, i32 +//SZ64: define{{.*}} i8 addrspace(1)* @test_add_global(i8 addrspace(1)* %x, i64 %y) +//SZ64: getelementptr inbounds i8, i8 addrspace(1)* %{{.*}}, i64 +global char* test_add_global(global char* x, ptrdiff_t y) { + return x + y; +} + +//SZ32: define{{.*}} i32 @test_sub_local(i8 addrspace(3)* %x, i8 addrspace(3)* %y) +//SZ32: ptrtoint i8 addrspace(3)* %{{.*}} to i32 +//SZ32: ptrtoint i8 addrspace(3)* %{{.*}} to i32 +//SZ64: define{{.*}} i64 @test_sub_local(i8 addrspace(3)* %x, i8 addrspace(3)* %y) +//SZ64: ptrtoint i8 addrspace(3)* %{{.*}} to i64 +//SZ64: ptrtoint i8 addrspace(3)* %{{.*}} to i64 +ptrdiff_t test_sub_local(local char* x, local char *y) { + return x - y; +} + +//SZ32: define{{.*}} i32 @test_sub_private(i8* %x, i8* %y) +//SZ32: ptrtoint i8* %{{.*}} to i32 +//SZ32: ptrtoint i8* %{{.*}} to i32 +//SZ64: define{{.*}} i64 @test_sub_private(i8* %x, i8* %y) +//SZ64: ptrtoint i8* %{{.*}} to i64 +//SZ64: ptrtoint i8* %{{.*}} to i64 +ptrdiff_t test_sub_private(private char* x, private char *y) { + return x - y; +} + +//SZ32: define{{.*}} i32 @test_sub_mix(i8* %x, i8 addrspace(4)* %y) +//SZ32: ptrtoint i8* %{{.*}} to i32 +//SZ32: ptrtoint i8 addrspace(4)* %{{.*}} to i32 +//SZ64: define{{.*}} i64 @test_sub_mix(i8* %x, i8 addrspace(4)* %y) +//SZ64: ptrtoint i8* %{{.*}} to i64 +//SZ64: ptrtoint i8 addrspace(4)* %{{.*}} to i64 +ptrdiff_t test_sub_mix(private char* x, generic char *y) { + return x - y; +} + -- 2.40.0