yaxunl created this revision.
yaxunl added a reviewer: Anastasia.
yaxunl added subscribers: cfe-commits, b-sumner, bader.

__builtin_astype is used to cast OpenCL opaque types to other types, as such, 
it needs to be able to handle casting from and to pointer types correctly.

Current it cannot handle 1) casting between pointers of different addr spaces 
2) casting between pointer type and non-pointer types.

This patch fixes that.


https://reviews.llvm.org/D25123

Files:
  lib/CodeGen/CGExprScalar.cpp
  test/CodeGenOpenCL/as_type.cl

Index: test/CodeGenOpenCL/as_type.cl
===================================================================
--- test/CodeGenOpenCL/as_type.cl
+++ test/CodeGenOpenCL/as_type.cl
@@ -66,3 +66,42 @@
 int3 f8(char16 x) {
   return __builtin_astype(x, int3);
 }
+
+//CHECK: define spir_func i32 addrspace(1)* @addr_cast(i32* readnone %[[x:.*]])
+//CHECK: %[[cast:.*]] = addrspacecast i32* %[[x]] to i32 addrspace(1)*
+//CHECK: ret i32 addrspace(1)* %[[cast]]
+global int* addr_cast(int *x) {
+  return __builtin_astype(x, global int*);
+}
+
+//CHECK: define spir_func i32 addrspace(1)* @int_to_ptr(i32 %[[x:.*]])
+//CHECK: %[[cast:.*]] = inttoptr i32 %[[x]] to i32 addrspace(1)*
+//CHECK: ret i32 addrspace(1)* %[[cast]]
+global int* int_to_ptr(int x) {
+  return __builtin_astype(x, global int*);
+}
+
+//CHECK: define spir_func i32 @ptr_to_int(i32* %[[x:.*]])
+//CHECK: %[[cast:.*]] = ptrtoint i32* %[[x]] to i32
+//CHECK: ret i32 %[[cast]]
+int ptr_to_int(int *x) {
+  return __builtin_astype(x, int);
+}
+
+//CHECK: define spir_func <3 x i8> @ptr_to_char3(i32* %[[x:.*]])
+//CHECK: %[[cast1:.*]] = ptrtoint i32* %[[x]] to i32
+//CHECK: %[[cast2:.*]] = bitcast i32 %[[cast1]] to <4 x i8>
+//CHECK: %[[astype:.*]] = shufflevector <4 x i8> %[[cast2]], <4 x i8> undef, <3 x i32> <i32 0, i32 1, i32 2>
+//CHECK: ret <3 x i8> %[[astype]]
+char3 ptr_to_char3(int *x) {
+  return  __builtin_astype(x, char3);
+}
+
+//CHECK: define spir_func i32* @char3_to_ptr(<3 x i8> %[[x:.*]])
+//CHECK: %[[astype:.*]] = shufflevector <3 x i8> %[[x]], <3 x i8> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 undef>
+//CHECK: %[[cast1:.*]] = bitcast <4 x i8> %[[astype]] to i32
+//CHECK: %[[cast2:.*]] = inttoptr i32 %[[cast1]] to i32*
+//CHECK: ret i32* %[[cast2]]
+int* char3_to_ptr(char3 x) {
+  return __builtin_astype(x, int*);
+}
Index: lib/CodeGen/CGExprScalar.cpp
===================================================================
--- lib/CodeGen/CGExprScalar.cpp
+++ lib/CodeGen/CGExprScalar.cpp
@@ -3407,6 +3407,52 @@
   return Builder.CreateShuffleVector(Src, UnV, Mask);
 }
 
+// Create cast instructions for converting LLVM value \p Src to LLVM type \p
+// DstTy. \p Src has the same size as \p DstTy. Both are single value types
+// but could be scalar or vectors of different lengths, and either can be
+// pointer.
+// There are 4 cases:
+// 1. non-pointer -> non-pointer  : needs 1 bitcast
+// 2. pointer -> pointer          : needs 1 bitcast or addrspacecast
+// 3. pointer -> non-pointer
+//   a) pointer -> intptr_t       : needs 1 ptrtoint
+//   b) pointer -> non-intptr_t   : needs 1 ptrtoint then 1 bitcast
+// 4. non-pointer -> pointer
+//   a) intptr_t -> pointer       : needs 1 inttoptr
+//   b) non-intptr_t -> pointer   : needs 1 bitcast then 1 inttoptr
+// Note: for cases 3b and 4b two casts are required since LLVM casts do not
+// allow casting directly between pointer types and non-integer non-pointer
+// types.
+static Value *createCastsForTypeOfSameSize(CGBuilderTy &Builder,
+                                           const llvm::DataLayout &DL,
+                                           Value *Src, llvm::Type *DstTy,
+                                           StringRef Name = "") {
+  auto SrcTy = Src->getType();
+
+  // Case 1.
+  if (!SrcTy->isPointerTy() && !DstTy->isPointerTy())
+    return Builder.CreateBitCast(Src, DstTy, Name);
+
+  // Case 2.
+  if (SrcTy->isPointerTy() && DstTy->isPointerTy())
+    return Builder.CreatePointerBitCastOrAddrSpaceCast(Src, DstTy, Name);
+
+  // Case 3.
+  if (SrcTy->isPointerTy() && !DstTy->isPointerTy()) {
+    // Case 3b.
+    if (!DstTy->isIntegerTy())
+      Src = Builder.CreatePtrToInt(Src, DL.getIntPtrType(SrcTy));
+    // Cases 3a and 3b.
+    return Builder.CreateBitOrPointerCast(Src, DstTy, Name);
+  }
+
+  // Case 4b.
+  if (!SrcTy->isIntegerTy())
+    Src = Builder.CreateBitCast(Src, DL.getIntPtrType(DstTy));
+  // Cases 4a and 4b.
+  return Builder.CreateIntToPtr(Src, DstTy, Name);
+}
+
 Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) {
   Value *Src  = CGF.EmitScalarExpr(E->getSrcExpr());
   llvm::Type *DstTy = ConvertType(E->getType());
@@ -3421,7 +3467,8 @@
   // vector to get a vec4, then a bitcast if the target type is different.
   if (NumElementsSrc == 3 && NumElementsDst != 3) {
     Src = ConvertVec3AndVec4(Builder, CGF, Src, 4);
-    Src = Builder.CreateBitCast(Src, DstTy);
+    Src = createCastsForTypeOfSameSize(Builder, CGF.CGM.getDataLayout(), Src,
+                                       DstTy);
     Src->setName("astype");
     return Src;
   }
@@ -3431,13 +3478,15 @@
   // get a vec3.
   if (NumElementsSrc != 3 && NumElementsDst == 3) {
     auto Vec4Ty = llvm::VectorType::get(DstTy->getVectorElementType(), 4);
-    Src = Builder.CreateBitCast(Src, Vec4Ty);
+    Src = createCastsForTypeOfSameSize(Builder, CGF.CGM.getDataLayout(), Src,
+                                       Vec4Ty);
     Src = ConvertVec3AndVec4(Builder, CGF, Src, 3);
     Src->setName("astype");
     return Src;
   }
 
-  return Builder.CreateBitCast(Src, DstTy, "astype");
+  return Src = createCastsForTypeOfSameSize(Builder, CGF.CGM.getDataLayout(),
+                                            Src, DstTy, "astype");
 }
 
 Value *ScalarExprEmitter::VisitAtomicExpr(AtomicExpr *E) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to