yaxunl created this revision.
yaxunl added reviewers: Anastasia, bader, pxli168.
yaxunl added subscribers: cfe-commits, tstellarAMD.

Currently Clang use int32 to represent sampler_t, which have been a source of 
issue for some backends, because in some backends sampler_t cannot be 
represented by int32. They have to depend on kernel argument metadata and use 
IPA to find the sampler arguments and global variables and transform them to 
target specific sampler type.

This patch uses opaque struct pointer type __sampler* for sampler_t. For each 
sampler constant, it generates a global var of struct type 
__sampler_initializer.  It also generates a function call 
__translate_sampler_initializer for each reference of global vars of 
__sampler_initializer type. e.g.
 
  sampler_t s = ADDR | NORM | FILT;
 
  void f() {
    g(s);
  }
 
 => Llvm bitcode equivalent to (assuming __sampler is the opaque struct type to 
represent sampler_t):
 
  // opaque struct type for sampler
  struct __sampler;
  // concrete sampler initializer struct type
  struct __sampler_initializer {
    int addr;
    int normalization;
    int filter;
  };

  constant __sampler *__attribute__((always_inline)) 
__translate_sampler_initializer(struct __sampler_initializer); // a builtin 
function for translating sampler initializer
 
  constant struct __sampler_initializer _SI = {ADDR, NORM, FILT};
  void f() {
    constant __sampler *_s = __translate_sampler_initializer(_SI);
    g(_s);
  }

 Each builtin library can implement its own __initialize_sampler(). Since the 
real sampler type tends to be architecture dependent, allowing it to be 
initialized by a library function simplifies backend design. A typical 
implementation of __initialize_sampler could be a table lookup of real sampler 
literal values. Since its argument is always a literal, the returned pointer is 
known at compile time and easily optimized to finally become some literal 
values directly put into image read instructions.
 
The advantage of this representation is:

  # Robust - can be optimized without losing information
  # Easy to implement – can be implemented by library instead of pass

The implementation of the design is to introduce an internal sampler 
initializer type and translates each sampler variable to sampler initializer 
type in AST, and introduces cast from integer to sampler initializer and cast 
from sampler initializer to sampler. In codegen, sampler type is translated to 
opaque __sampler* type, sampler initializer type is translated to concrete 
__sampler_initializer type. The cast from sampler initializer to sampler is 
translated to function call __translate_sampler_initializer.

This patch is partly based on Alexey Sotkin's work in Khronos Clang 
(https://github.com/KhronosGroup/SPIR/commit/3d4eec61623502fc306e8c67c9868be2b136e42b).

http://reviews.llvm.org/D21567

Files:
  include/clang/AST/ASTContext.h
  include/clang/AST/BuiltinTypes.def
  include/clang/AST/OperationKinds.def
  include/clang/AST/Type.h
  include/clang/Basic/DiagnosticGroups.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Basic/LangOptions.def
  include/clang/Driver/CC1Options.td
  include/clang/Sema/Overload.h
  include/clang/Serialization/ASTBitCodes.h
  lib/AST/ASTContext.cpp
  lib/AST/Expr.cpp
  lib/AST/ExprConstant.cpp
  lib/AST/ItaniumMangle.cpp
  lib/AST/MicrosoftMangle.cpp
  lib/AST/NSAPI.cpp
  lib/AST/Type.cpp
  lib/AST/TypeLoc.cpp
  lib/CodeGen/CGDebugInfo.cpp
  lib/CodeGen/CGDebugInfo.h
  lib/CodeGen/CGExpr.cpp
  lib/CodeGen/CGExprAgg.cpp
  lib/CodeGen/CGExprComplex.cpp
  lib/CodeGen/CGExprConstant.cpp
  lib/CodeGen/CGExprScalar.cpp
  lib/CodeGen/CGOpenCLRuntime.cpp
  lib/CodeGen/CodeGenModule.cpp
  lib/CodeGen/CodeGenModule.h
  lib/CodeGen/CodeGenTypes.cpp
  lib/CodeGen/ItaniumCXXABI.cpp
  lib/Edit/RewriteObjCFoundationAPI.cpp
  lib/Frontend/CompilerInvocation.cpp
  lib/Index/USRGeneration.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaExprCXX.cpp
  lib/Sema/SemaInit.cpp
  lib/Sema/SemaOverload.cpp
  lib/Serialization/ASTCommon.cpp
  lib/Serialization/ASTReader.cpp
  lib/StaticAnalyzer/Core/ExprEngineC.cpp
  test/CodeGenOpenCL/opencl_types.cl
  test/CodeGenOpenCL/sampler.cl
  test/SemaOpenCL/sampler_t.cl
  tools/libclang/CIndex.cpp

Index: tools/libclang/CIndex.cpp
===================================================================
--- tools/libclang/CIndex.cpp
+++ tools/libclang/CIndex.cpp
@@ -1466,6 +1466,7 @@
   case BuiltinType::Id:
 #include "clang/Basic/OpenCLImageTypes.def"
   case BuiltinType::OCLSampler:
+  case BuiltinType::OCLSamplerInit:
   case BuiltinType::OCLEvent:
   case BuiltinType::OCLClkEvent:
   case BuiltinType::OCLQueue:
Index: test/SemaOpenCL/sampler_t.cl
===================================================================
--- test/SemaOpenCL/sampler_t.cl
+++ test/SemaOpenCL/sampler_t.cl
@@ -13,6 +13,7 @@
   const sampler_t const_smp = 7;
   foo(glb_smp);
   foo(const_smp);
+  foo(argsmp);
   foo(5); // expected-error {{sampler_t variable required - got 'int'}}
   sampler_t sa[] = {argsmp, const_smp}; // expected-error {{array of 'sampler_t' type is invalid in OpenCL}}
 }
Index: test/CodeGenOpenCL/sampler.cl
===================================================================
--- /dev/null
+++ test/CodeGenOpenCL/sampler.cl
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 %s -emit-llvm -triple spir-unknown-unknown -o - -O0 -cl-sampler-type i32 | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -triple spir-unknown-unknown -o - -O0 | FileCheck -check-prefix CHECK-SAMPLER-TYPE %s
+
+#define CLK_ADDRESS_CLAMP_TO_EDGE       2
+#define CLK_NORMALIZED_COORDS_TRUE      1
+#define CLK_FILTER_NEAREST              0x10
+#define CLK_FILTER_LINEAR               0x20
+
+constant sampler_t glb_smp = CLK_ADDRESS_CLAMP_TO_EDGE | CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_LINEAR;
+// CHECK: @glb_smp = global i32 35
+
+// CHECK-SAMPLER-TYPE: %__sampler_initializer = type { i32, i32, i32 }
+// CHECK-SAMPLER-TYPE: %__sampler = type opaque
+// CHECK-SAMPLER-TYPE: [[glb_smp_init:@[-a-zA-Z$._][-a-zA-Z$._0-9]*]] = internal addrspace(2) constant %__sampler_initializer { i32 1, i32 1, i32 1 }
+// CHECK-SAMPLER-TYPE: @glb_smp = global %__sampler_initializer addrspace(2)* [[glb_smp_init]]
+// CHECK-SAMPLER-TYPE: [[smp_init:@[-a-zA-Z$._][-a-zA-Z$._0-9]*]] = internal addrspace(2) constant %__sampler_initializer { i32 1, i32 1, i32 0 }
+
+void fnc4smp(sampler_t s) {}
+// CHECK: define spir_func void @fnc4smp(i32
+// CHECK-SAMPLER-TYPE: define spir_func void @fnc4smp(%__sampler addrspace(2)* %
+
+kernel void foo() {
+  sampler_t smp = CLK_ADDRESS_CLAMP_TO_EDGE | CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_NEAREST;
+  // CHECK-LABEL: define spir_kernel void @foo()
+  // CHECK: alloca i32
+  // CHECK-SAMPLER-TYPE-LABEL: define spir_kernel void @foo()
+  // CHECK-SAMPLER-TYPE: [[smp_ptr:%[A-Za-z0-9_\.]+]] = alloca %__sampler_initializer addrspace(2)*
+  // CHECK-SAMPLER-TYPE: store %__sampler_initializer addrspace(2)* [[smp_init]], %__sampler_initializer addrspace(2)** [[smp_ptr]]
+
+  fnc4smp(smp);
+  // CHECK: store i32 19,
+  // CHECK: call spir_func void @fnc4smp(i32
+  // CHECK-SAMPLER-TYPE: [[SINIT:%[0-9]+]] = load %__sampler_initializer addrspace(2)*, %__sampler_initializer addrspace(2)** [[smp_ptr]]
+  // CHECK-SAMPLER-TYPE: [[SAMP:%[0-9]+]] = call %__sampler addrspace(2)* @__translate_sampler_initializer(%__sampler_initializer addrspace(2)* [[SINIT]])
+  // CHECK-SAMPLER-TYPE: call spir_func void @fnc4smp(%__sampler addrspace(2)* [[SAMP]])
+
+  fnc4smp(glb_smp);
+  // CHECK: call spir_func void @fnc4smp(i32
+  // CHECK-SAMPLER-TYPE: [[SINIT:%[0-9]+]] = load %__sampler_initializer addrspace(2)*, %__sampler_initializer addrspace(2)** @glb_smp
+  // CHECK-SAMPLER-TYPE: [[SAMP:%[0-9]+]] = call %__sampler addrspace(2)* @__translate_sampler_initializer(%__sampler_initializer addrspace(2)* [[SINIT]])
+  // CHECK-SAMPLER-TYPE: call spir_func void @fnc4smp(%__sampler addrspace(2)* [[SAMP]])
+}
Index: test/CodeGenOpenCL/opencl_types.cl
===================================================================
--- test/CodeGenOpenCL/opencl_types.cl
+++ /dev/null
@@ -1,40 +0,0 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - -O0 | FileCheck %s
-
-constant sampler_t glb_smp = 7;
-// CHECK: constant i32 7
-
-void fnc1(image1d_t img) {}
-// CHECK: @fnc1(%opencl.image1d_ro_t*
-
-void fnc1arr(image1d_array_t img) {}
-// CHECK: @fnc1arr(%opencl.image1d_array_ro_t*
-
-void fnc1buff(image1d_buffer_t img) {}
-// CHECK: @fnc1buff(%opencl.image1d_buffer_ro_t*
-
-void fnc2(image2d_t img) {}
-// CHECK: @fnc2(%opencl.image2d_ro_t*
-
-void fnc2arr(image2d_array_t img) {}
-// CHECK: @fnc2arr(%opencl.image2d_array_ro_t*
-
-void fnc3(image3d_t img) {}
-// CHECK: @fnc3(%opencl.image3d_ro_t*
-
-void fnc4smp(sampler_t s) {}
-// CHECK-LABEL: define {{.*}}void @fnc4smp(i32
-
-kernel void foo(image1d_t img) {
-  sampler_t smp = 5;
-  // CHECK: alloca i32
-  event_t evt;
-  // CHECK: alloca %opencl.event_t*
-  // CHECK: store i32 5,
-  fnc4smp(smp);
-  // CHECK: call {{.*}}void @fnc4smp(i32
-  fnc4smp(glb_smp);
-  // CHECK: call {{.*}}void @fnc4smp(i32
-}
-
-void __attribute__((overloadable)) bad1(image1d_t b, image2d_t c, image2d_t d) {}
-// CHECK-LABEL: @{{_Z4bad114ocl_image1d_ro14ocl_image2d_roS0_|"\\01\?bad1@@\$\$J0YAXPAUocl_image1d_ro@@PAUocl_image2d_ro@@1@Z"}}
Index: lib/StaticAnalyzer/Core/ExprEngineC.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -341,6 +341,8 @@
       case CK_AnyPointerToBlockPointerCast:
       case CK_ObjCObjectLValueCast:
       case CK_ZeroToOCLEvent:
+      case CK_IntToOCLSamplerInitializer:
+      case CK_OCLSamplerInitializerToSampler:
       case CK_LValueBitCast: {
         // Delegate to SValBuilder to process.
         SVal V = state->getSVal(Ex, LCtx);
Index: lib/Serialization/ASTReader.cpp
===================================================================
--- lib/Serialization/ASTReader.cpp
+++ lib/Serialization/ASTReader.cpp
@@ -6087,6 +6087,9 @@
     case PREDEF_TYPE_SAMPLER_ID:
       T = Context.OCLSamplerTy;
       break;
+    case PREDEF_TYPE_SAMPLER_INIT_ID:
+      T = Context.OCLSamplerInitTy;
+      break;
     case PREDEF_TYPE_EVENT_ID:
       T = Context.OCLEventTy;
       break;
Index: lib/Serialization/ASTCommon.cpp
===================================================================
--- lib/Serialization/ASTCommon.cpp
+++ lib/Serialization/ASTCommon.cpp
@@ -138,6 +138,9 @@
   case BuiltinType::OCLSampler:
     ID = PREDEF_TYPE_SAMPLER_ID;
     break;
+  case BuiltinType::OCLSamplerInit:
+    ID = PREDEF_TYPE_SAMPLER_ID;
+    break;
   case BuiltinType::OCLEvent:
     ID = PREDEF_TYPE_EVENT_ID;
     break;
Index: lib/Sema/SemaOverload.cpp
===================================================================
--- lib/Sema/SemaOverload.cpp
+++ lib/Sema/SemaOverload.cpp
@@ -1738,7 +1738,11 @@
              From->EvaluateKnownConstInt(S.getASTContext()) == 0) {
     SCS.Second = ICK_Zero_Event_Conversion;
     FromType = ToType;
-  } else {
+  } else if (ToType->isSamplerT() && From->getType()->isSamplerInitT()) {
+    SCS.Second = ICK_Sampler_Conversion;
+    FromType = ToType;
+  }
+  else {
     // No second conversion required.
     SCS.Second = ICK_Identity;
   }
@@ -5105,6 +5109,7 @@
   case ICK_TransparentUnionConversion:
   case ICK_Writeback_Conversion:
   case ICK_Zero_Event_Conversion:
+  case ICK_Sampler_Conversion:
   case ICK_C_Only_Conversion:
     return false;
 
Index: lib/Sema/SemaInit.cpp
===================================================================
--- lib/Sema/SemaInit.cpp
+++ lib/Sema/SemaInit.cpp
@@ -4886,7 +4886,8 @@
                                         QualType DestType,
                                         Expr *Initializer) {
   if (!S.getLangOpts().OpenCL || !DestType->isSamplerT() ||
-    !Initializer->isIntegerConstantExpr(S.getASTContext()))
+      (!Initializer->isIntegerConstantExpr(S.Context) &&
+      !Initializer->getType()->isSamplerInitT()))
     return false;
 
   Sequence.AddOCLSamplerInitStep(DestType);
@@ -6882,19 +6883,27 @@
     }
 
     case SK_OCLSamplerInit: {
-      assert(Step->Type->isSamplerT() && 
-             "Sampler initialization on non-sampler type.");
-
-      QualType SourceType = CurInit.get()->getType();
-
+      Expr *Init = CurInit.get();
+      QualType SourceType = Init->getType();
       if (Entity.isParameterKind()) {
-        if (!SourceType->isSamplerT())
+        if (SourceType->isSamplerInitT()) {
+          Init->setValueKind(VK_RValue);
+          CurInit = S.ImpCastExprToType(Init, Step->Type,
+                                        CK_OCLSamplerInitializerToSampler);
+        } else if (!SourceType->isSamplerT())
           S.Diag(Kind.getLocation(), diag::err_sampler_argument_required)
             << SourceType;
-      } else if (Entity.getKind() != InitializedEntity::EK_Variable) {
-        llvm_unreachable("Invalid EntityKind!");
+      } else {
+        if (!Init->isConstantInitializer(S.Context, false))
+          S.Diag(Kind.getLocation(),
+                 diag::err_sampler_initializer_not_constant);
+        if (!SourceType->isIntegerType() ||
+            32 != S.Context.getIntWidth(SourceType))
+          S.Diag(Kind.getLocation(), diag::err_sampler_initializer_not_integer)
+            << SourceType;
+        CurInit = S.ImpCastExprToType(Init, S.Context.OCLSamplerInitTy,
+                                      CK_IntToOCLSamplerInitializer);
       }
-
       break;
     }
     case SK_OCLZeroEvent: {
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -3678,6 +3678,11 @@
                              From->getValueKind()).get();
     break;
 
+  case ICK_Sampler_Conversion:
+    From = ImpCastExprToType(From, ToType,
+                             CK_OCLSamplerInitializerToSampler).get();
+    break;
+
   case ICK_Lvalue_To_Rvalue:
   case ICK_Array_To_Pointer:
   case ICK_Function_To_Pointer:
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -7587,6 +7587,16 @@
     }
   }
 
+  if (LHSType->isSamplerT() && RHSType->isIntegerType()) {
+    Kind = CK_IntToOCLSamplerInitializer;
+    return Compatible;
+  }
+
+  if (LHSType->isSpecificBuiltinType(BuiltinType::OCLSamplerInit) &&
+      RHSType->isSamplerT()) {
+    Kind = CK_OCLSamplerInitializerToSampler;
+    return Compatible;
+  }
   return Incompatible;
 }
 
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -10248,6 +10248,9 @@
       var->setInvalidDecl();
       return;
     }
+
+    if (var->getType()->isSamplerT())
+      var->setType(Context.OCLSamplerInitTy);
   }
 
   // In Objective-C, don't allow jumps past the implicit initialization of a
Index: lib/Index/USRGeneration.cpp
===================================================================
--- lib/Index/USRGeneration.cpp
+++ lib/Index/USRGeneration.cpp
@@ -635,6 +635,7 @@
         case BuiltinType::OCLNDRange:
         case BuiltinType::OCLReserveID:
         case BuiltinType::OCLSampler:
+        case BuiltinType::OCLSamplerInit:
           IgnoreResults = true;
           return;
         case BuiltinType::ObjCId:
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -2125,6 +2125,17 @@
   Opts.SanitizeAddressFieldPadding =
       getLastArgIntValue(Args, OPT_fsanitize_address_field_padding, 0, Diags);
   Opts.SanitizerBlacklistFiles = Args.getAllArgValues(OPT_fsanitize_blacklist);
+  if(const Arg* A = Args.getLastArg(OPT_cl_sampler_type)) {
+      Opts.CLSamplerOpaque  = llvm::StringSwitch<int>(A->getValue())
+        .Case("i32", 0)
+        .Case("opaque", 1)
+        .Default(2);
+      if(Opts.CLSamplerOpaque == 2)
+        Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args)
+                                                  << A->getValue();
+  } else
+    Opts.CLSamplerOpaque = 1;
+
 }
 
 static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
Index: lib/Edit/RewriteObjCFoundationAPI.cpp
===================================================================
--- lib/Edit/RewriteObjCFoundationAPI.cpp
+++ lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -1076,6 +1076,8 @@
     case CK_CopyAndAutoreleaseBlockObject:
     case CK_BuiltinFnToFnPtr:
     case CK_ZeroToOCLEvent:
+    case CK_IntToOCLSamplerInitializer:
+    case CK_OCLSamplerInitializerToSampler:
       return false;
 
     case CK_BooleanToSignedIntegral:
Index: lib/CodeGen/ItaniumCXXABI.cpp
===================================================================
--- lib/CodeGen/ItaniumCXXABI.cpp
+++ lib/CodeGen/ItaniumCXXABI.cpp
@@ -2542,6 +2542,7 @@
     case BuiltinType::Id:
 #include "clang/Basic/OpenCLImageTypes.def"
     case BuiltinType::OCLSampler:
+    case BuiltinType::OCLSamplerInit:
     case BuiltinType::OCLEvent:
     case BuiltinType::OCLClkEvent:
     case BuiltinType::OCLQueue:
Index: lib/CodeGen/CodeGenTypes.cpp
===================================================================
--- lib/CodeGen/CodeGenTypes.cpp
+++ lib/CodeGen/CodeGenTypes.cpp
@@ -469,6 +469,7 @@
     case BuiltinType::Id:
 #include "clang/Basic/OpenCLImageTypes.def"
     case BuiltinType::OCLSampler:
+    case BuiltinType::OCLSamplerInit:
     case BuiltinType::OCLEvent:
     case BuiltinType::OCLClkEvent:
     case BuiltinType::OCLQueue:
Index: lib/CodeGen/CodeGenModule.h
===================================================================
--- lib/CodeGen/CodeGenModule.h
+++ lib/CodeGen/CodeGenModule.h
@@ -1147,6 +1147,12 @@
 
   llvm::SanitizerStatReport &getSanStats();
 
+  llvm::Constant*
+  createIntToSamplerConversion(const Expr *E,
+                               CodeGenFunction *CGF,
+                               llvm::GlobalVariable *InsertBefore = nullptr,
+                               StringRef Name = "");
+
 private:
   llvm::Constant *
   GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty, GlobalDecl D,
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp
+++ lib/CodeGen/CodeGenModule.cpp
@@ -4307,3 +4307,60 @@
 
   return *SanStats;
 }
+llvm::Constant*
+CodeGenModule::createIntToSamplerConversion(const Expr *E,
+                                            CodeGenFunction *CGF,
+                                            llvm::GlobalVariable *InsertBefore,
+                                            StringRef Name) {
+  llvm::Constant *C = EmitConstantExpr(E, E->getType(), CGF);
+  assert(C && "Sampler must be initialized by constant");
+  assert(isa<llvm::ConstantInt>(C) && "Sampler must be initialized by integer");
+  if (!getLangOpts().CLSamplerOpaque)
+    return C;
+
+  llvm::StructType*
+    ConstSamplerTy = TheModule.getTypeByName("__sampler_initializer");
+  if (!ConstSamplerTy ) {
+    llvm::Type* Elements[] = {Int32Ty, Int32Ty, Int32Ty};
+    ConstSamplerTy = llvm::StructType::create(VMContext, Elements,
+                                              "__sampler_initializer");
+  }
+  const llvm::ConstantInt *CI = static_cast<llvm::ConstantInt*>(C);
+  const uint64_t SamplerValue = CI->getValue().getZExtValue();
+  // 32-bit value of sampler's initializer is interpreted as
+  // bit-field with the following structure:
+  // |unspecified|Filter|Addressing Mode| Normalized Coords|
+  // |31        6|5    4|3             1|                 0|
+  // This structure corresponds to values of sampler properties from opencl.h
+  // Mapping these bits to values defined by SPIR-V specification.
+  unsigned NormalizedCoords = 0x01 & SamplerValue;
+  unsigned AddressingMode  = (0x0E & SamplerValue) >> 1;
+  unsigned FilterMode      = (0x30 & SamplerValue) >> 4;
+  // In SPIR sampler's filter bits are defined as the following
+  // #define CLK_FILTER_NEAREST 0x10
+  // #define CLK_FILTER_LINEAR 0x20
+  // corresponding to 1 and 2 in bits 4-5.
+  // SPIR-V defines sampler filter mode enum as: nearest=0, linear=1,
+  // Therefore, to convert FilterMode from SPIR to SPIR-V,
+  // FilterMode value must be decremented
+  if (FilterMode == 1 || FilterMode == 2)
+    --FilterMode;
+   else
+    getDiags().Report(Context.getFullLoc(E->getLocStart()),
+      diag::warn_sampler_initializer_invalid_bits) << "Filter Mode";
+  if (AddressingMode > 4)
+    getDiags().Report(Context.getFullLoc(E->getLocStart()),
+      diag::warn_sampler_initializer_invalid_bits) << "Addressing Mode";
+
+  llvm::Constant *Initializer = llvm::ConstantStruct::get(ConstSamplerTy,
+    llvm::ConstantInt::get(Int32Ty, AddressingMode),
+    llvm::ConstantInt::get(Int32Ty, NormalizedCoords),
+    llvm::ConstantInt::get(Int32Ty, FilterMode),
+    nullptr);
+  auto AS = Context.getTargetAddressSpace(LangAS::opencl_constant);
+  return new llvm::GlobalVariable(TheModule, ConstSamplerTy, true,
+                                  llvm::GlobalVariable::InternalLinkage,
+                                  Initializer, Name + ".sampler.init",
+                                  InsertBefore,
+                                  llvm::GlobalVariable::NotThreadLocal, AS);
+}
Index: lib/CodeGen/CGOpenCLRuntime.cpp
===================================================================
--- lib/CodeGen/CGOpenCLRuntime.cpp
+++ lib/CodeGen/CGOpenCLRuntime.cpp
@@ -47,7 +47,24 @@
         ImgAddrSpc);
 #include "clang/Basic/OpenCLImageTypes.def"
   case BuiltinType::OCLSampler:
-    return llvm::IntegerType::get(Ctx, 32);
+    if (CGM.getLangOpts().CLSamplerOpaque)
+      return llvm::PointerType::get(llvm::StructType::create(
+                           Ctx, "__sampler"),
+                           CGM.getContext().getTargetAddressSpace(
+                           LangAS::opencl_constant));
+    else
+      return llvm::IntegerType::get(Ctx, 32);
+  case BuiltinType::OCLSamplerInit:
+    if (CGM.getLangOpts().CLSamplerOpaque) {
+      auto Int32Ty = llvm::IntegerType::get(Ctx, 32);
+      llvm::Type* Elements[] = {Int32Ty, Int32Ty, Int32Ty};
+      return llvm::PointerType::get(llvm::StructType::create(
+                           Ctx, Elements, "__sampler_initializer"),
+                           CGM.getContext().getTargetAddressSpace(
+                           LangAS::opencl_constant));
+    }
+    else
+      return llvm::IntegerType::get(Ctx, 32);
   case BuiltinType::OCLEvent:
     return llvm::PointerType::get(llvm::StructType::create(
                            Ctx, "opencl.event_t"), 0);
Index: lib/CodeGen/CGExprScalar.cpp
===================================================================
--- lib/CodeGen/CGExprScalar.cpp
+++ lib/CodeGen/CGExprScalar.cpp
@@ -1573,8 +1573,31 @@
     return llvm::Constant::getNullValue(ConvertType(DestTy));
   }
 
+  case CK_IntToOCLSamplerInitializer: {
+    if (!CGF.CGM.getLangOpts().CLSamplerOpaque)
+      return Visit(E);
+    return CGF.CGM.createIntToSamplerConversion(E, &CGF);
   }
 
+  case CK_OCLSamplerInitializerToSampler: {
+    if (!CGF.CGM.getLangOpts().CLSamplerOpaque)
+      return Visit(E);
+
+    auto SampInit = Visit(E);
+    auto SamplerTy = CGF.CGM.getModule().getTypeByName("__sampler");
+    if(!SamplerTy)
+      SamplerTy = llvm::StructType::create(VMContext, "__sampler");
+
+    auto AS = CGF.getContext().getTargetAddressSpace(LangAS::opencl_constant);
+    auto FTy = llvm::FunctionType::get(llvm::PointerType::get(SamplerTy, AS),
+                                       {SampInit->getType()}, false);
+    return CGF.Builder.CreateCall(
+      CGF.CGM.CreateRuntimeFunction(FTy, "__translate_sampler_initializer"),
+                                    {SampInit});
+  }
+
+  } // end of switch
+
   llvm_unreachable("unknown scalar cast");
 }
 
Index: lib/CodeGen/CGExprConstant.cpp
===================================================================
--- lib/CodeGen/CGExprConstant.cpp
+++ lib/CodeGen/CGExprConstant.cpp
@@ -690,6 +690,15 @@
     case CK_ConstructorConversion:
       return C;
 
+    case CK_IntToOCLSamplerInitializer: {
+      if (!CGM.getLangOpts().CLSamplerOpaque)
+        return C;
+      return CGM.createIntToSamplerConversion(subExpr, CGF);
+    }
+
+    case CK_OCLSamplerInitializerToSampler:
+      llvm_unreachable("saw dependent cast!");
+
     case CK_Dependent: llvm_unreachable("saw dependent cast!");
 
     case CK_BuiltinFnToFnPtr:
Index: lib/CodeGen/CGExprComplex.cpp
===================================================================
--- lib/CodeGen/CGExprComplex.cpp
+++ lib/CodeGen/CGExprComplex.cpp
@@ -484,6 +484,8 @@
   case CK_BuiltinFnToFnPtr:
   case CK_ZeroToOCLEvent:
   case CK_AddressSpaceConversion:
+  case CK_IntToOCLSamplerInitializer:
+  case CK_OCLSamplerInitializerToSampler:
     llvm_unreachable("invalid cast kind for complex value");
 
   case CK_FloatingRealToComplex:
Index: lib/CodeGen/CGExprAgg.cpp
===================================================================
--- lib/CodeGen/CGExprAgg.cpp
+++ lib/CodeGen/CGExprAgg.cpp
@@ -749,6 +749,8 @@
   case CK_BuiltinFnToFnPtr:
   case CK_ZeroToOCLEvent:
   case CK_AddressSpaceConversion:
+  case CK_IntToOCLSamplerInitializer:
+  case CK_OCLSamplerInitializerToSampler:
     llvm_unreachable("cast kind invalid for aggregate types");
   }
 }
Index: lib/CodeGen/CGExpr.cpp
===================================================================
--- lib/CodeGen/CGExpr.cpp
+++ lib/CodeGen/CGExpr.cpp
@@ -3584,6 +3584,8 @@
   case CK_ARCExtendBlockObject:
   case CK_CopyAndAutoreleaseBlockObject:
   case CK_AddressSpaceConversion:
+  case CK_IntToOCLSamplerInitializer:
+  case CK_OCLSamplerInitializerToSampler:
     return EmitUnsupportedLValue(E, "unexpected cast lvalue");
 
   case CK_Dependent:
Index: lib/CodeGen/CGDebugInfo.h
===================================================================
--- lib/CodeGen/CGDebugInfo.h
+++ lib/CodeGen/CGDebugInfo.h
@@ -67,6 +67,8 @@
 #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
   llvm::DIType *SingletonId = nullptr;
 #include "clang/Basic/OpenCLImageTypes.def"
+  llvm::DIType *OCLSamplerDITy = nullptr;
+  llvm::DIType *OCLSamplerInitDITy = nullptr;
   llvm::DIType *OCLEventDITy = nullptr;
   llvm::DIType *OCLClkEventDITy = nullptr;
   llvm::DIType *OCLQueueDITy = nullptr;
Index: lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- lib/CodeGen/CGDebugInfo.cpp
+++ lib/CodeGen/CGDebugInfo.cpp
@@ -474,9 +474,16 @@
                                     SingletonId);
 #include "clang/Basic/OpenCLImageTypes.def"
   case BuiltinType::OCLSampler:
-    return DBuilder.createBasicType(
+    if (!CGM.getLangOpts().CLSamplerOpaque)
+      return DBuilder.createBasicType(
         "opencl_sampler_t", CGM.getContext().getTypeSize(BT),
         CGM.getContext().getTypeAlign(BT), llvm::dwarf::DW_ATE_unsigned);
+    else
+      return getOrCreateStructPtrType("opencl_sampler_t",
+                                      OCLSamplerInitDITy);
+  case BuiltinType::OCLSamplerInit:
+    return getOrCreateStructPtrType("opencl_sampler_initializer_t",
+                                    OCLSamplerInitDITy);
   case BuiltinType::OCLEvent:
     return getOrCreateStructPtrType("opencl_event_t", OCLEventDITy);
   case BuiltinType::OCLClkEvent:
Index: lib/AST/TypeLoc.cpp
===================================================================
--- lib/AST/TypeLoc.cpp
+++ lib/AST/TypeLoc.cpp
@@ -338,6 +338,7 @@
   case BuiltinType::Id:
 #include "clang/Basic/OpenCLImageTypes.def"
   case BuiltinType::OCLSampler:
+  case BuiltinType::OCLSamplerInit:
   case BuiltinType::OCLEvent:
   case BuiltinType::OCLClkEvent:
   case BuiltinType::OCLQueue:
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp
+++ lib/AST/Type.cpp
@@ -2595,6 +2595,8 @@
 #include "clang/Basic/OpenCLImageTypes.def"
   case OCLSampler:
     return "sampler_t";
+  case OCLSamplerInit:
+    return "samper_initializer_t";
   case OCLEvent:
     return "event_t";
   case OCLClkEvent:
@@ -3570,6 +3572,7 @@
     case BuiltinType::Id:
 #include "clang/Basic/OpenCLImageTypes.def"
     case BuiltinType::OCLSampler:
+    case BuiltinType::OCLSamplerInit:
     case BuiltinType::OCLEvent:
     case BuiltinType::OCLClkEvent:
     case BuiltinType::OCLQueue:
Index: lib/AST/NSAPI.cpp
===================================================================
--- lib/AST/NSAPI.cpp
+++ lib/AST/NSAPI.cpp
@@ -450,6 +450,7 @@
   case BuiltinType::Id:
 #include "clang/Basic/OpenCLImageTypes.def"
   case BuiltinType::OCLSampler:
+  case BuiltinType::OCLSamplerInit:
   case BuiltinType::OCLEvent:
   case BuiltinType::OCLClkEvent:
   case BuiltinType::OCLQueue:
Index: lib/AST/MicrosoftMangle.cpp
===================================================================
--- lib/AST/MicrosoftMangle.cpp
+++ lib/AST/MicrosoftMangle.cpp
@@ -1732,6 +1732,10 @@
     Out << "PA";
     mangleArtificalTagType(TTK_Struct, "ocl_sampler");
     break;
+  case BuiltinType::OCLSamplerInit:
+    Out << "PA";
+    mangleArtificalTagType(TTK_Struct, "ocl_sampler_init");
+    break;
   case BuiltinType::OCLEvent:
     Out << "PA";
     mangleArtificalTagType(TTK_Struct, "ocl_event");
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -2107,6 +2107,9 @@
   case BuiltinType::OCLSampler:
     Out << "11ocl_sampler";
     break;
+  case BuiltinType::OCLSamplerInit:
+    Out << "16ocl_sampler_init";
+    break;
   case BuiltinType::OCLEvent:
     Out << "9ocl_event";
     break;
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -6359,6 +6359,7 @@
     case BuiltinType::Id:
 #include "clang/Basic/OpenCLImageTypes.def"
     case BuiltinType::OCLSampler:
+    case BuiltinType::OCLSamplerInit:
     case BuiltinType::OCLEvent:
     case BuiltinType::OCLClkEvent:
     case BuiltinType::OCLQueue:
@@ -7970,6 +7971,8 @@
   case CK_ZeroToOCLEvent:
   case CK_NonAtomicToAtomic:
   case CK_AddressSpaceConversion:
+  case CK_IntToOCLSamplerInitializer:
+  case CK_OCLSamplerInitializerToSampler:
     llvm_unreachable("invalid cast kind for integral value");
 
   case CK_BitCast:
@@ -8461,6 +8464,8 @@
   case CK_ZeroToOCLEvent:
   case CK_NonAtomicToAtomic:
   case CK_AddressSpaceConversion:
+  case CK_IntToOCLSamplerInitializer:
+  case CK_OCLSamplerInitializerToSampler:
     llvm_unreachable("invalid cast kind for complex value");
 
   case CK_LValueToRValue:
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp
+++ lib/AST/Expr.cpp
@@ -1570,6 +1570,8 @@
   case CK_ARCReclaimReturnedObject:
   case CK_ARCExtendBlockObject:
   case CK_ZeroToOCLEvent:
+  case CK_IntToOCLSamplerInitializer:
+  case CK_OCLSamplerInitializerToSampler:
     assert(!getType()->isBooleanType() && "unheralded conversion to bool");
     goto CheckNoBasePath;
 
@@ -2748,7 +2750,9 @@
         CE->getCastKind() == CK_ToUnion ||
         CE->getCastKind() == CK_ConstructorConversion ||
         CE->getCastKind() == CK_NonAtomicToAtomic ||
-        CE->getCastKind() == CK_AtomicToNonAtomic)
+        CE->getCastKind() == CK_AtomicToNonAtomic ||
+        CE->getCastKind() == CK_IntToOCLSamplerInitializer ||
+        CE->getCastKind() == CK_OCLSamplerInitializerToSampler)
       return CE->getSubExpr()->isConstantInitializer(Ctx, false, Culprit);
 
     break;
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -1091,6 +1091,7 @@
 #include "clang/Basic/OpenCLImageTypes.def"
 
     InitBuiltinType(OCLSamplerTy, BuiltinType::OCLSampler);
+    InitBuiltinType(OCLSamplerInitTy, BuiltinType::OCLSamplerInit);
     InitBuiltinType(OCLEventTy, BuiltinType::OCLEvent);
     InitBuiltinType(OCLClkEventTy, BuiltinType::OCLClkEvent);
     InitBuiltinType(OCLQueueTy, BuiltinType::OCLQueue);
@@ -1662,10 +1663,22 @@
       Align = Target->getPointerAlign(0);
       break;
     case BuiltinType::OCLSampler:
-      // Samplers are modeled as integers.
-      Width = Target->getIntWidth();
-      Align = Target->getIntAlign();
+      if (!getLangOpts().CLSamplerOpaque) {
+        // Samplers are modeled as integers.
+        Width = Target->getIntWidth();
+        Align = Target->getIntAlign();
+      } else {
+        auto AS = getTargetAddressSpace(LangAS::opencl_constant);
+        Width = Target->getPointerWidth(AS);
+        Align = Target->getPointerAlign(AS);
+      }
+      break;
+    case BuiltinType::OCLSamplerInit: {
+      auto AS = getTargetAddressSpace(LangAS::opencl_constant);
+      Width = Target->getPointerWidth(AS);
+      Align = Target->getPointerAlign(AS);
       break;
+    }
     case BuiltinType::OCLEvent:
     case BuiltinType::OCLClkEvent:
     case BuiltinType::OCLQueue:
@@ -5512,6 +5525,7 @@
     case BuiltinType::OCLNDRange:
     case BuiltinType::OCLReserveID:
     case BuiltinType::OCLSampler:
+    case BuiltinType::OCLSamplerInit:
     case BuiltinType::Dependent:
 #define BUILTIN_TYPE(KIND, ID)
 #define PLACEHOLDER_TYPE(KIND, ID) \
Index: include/clang/Serialization/ASTBitCodes.h
===================================================================
--- include/clang/Serialization/ASTBitCodes.h
+++ include/clang/Serialization/ASTBitCodes.h
@@ -796,6 +796,8 @@
       PREDEF_TYPE_OMP_ARRAY_SECTION = 43,
       /// \brief The '__float128' type
       PREDEF_TYPE_FLOAT128_ID = 44,
+      /// \brief Internal OpenCL sampler initializer type
+      PREDEF_TYPE_SAMPLER_INIT_ID = 45,
       /// \brief OpenCL image types with auto numeration
 #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
       PREDEF_TYPE_##Id##_ID,
Index: include/clang/Sema/Overload.h
===================================================================
--- include/clang/Sema/Overload.h
+++ include/clang/Sema/Overload.h
@@ -84,6 +84,7 @@
     ICK_Writeback_Conversion,  ///< Objective-C ARC writeback conversion
     ICK_Zero_Event_Conversion, ///< Zero constant to event (OpenCL1.2 6.12.10)
     ICK_C_Only_Conversion,     ///< Conversions allowed in C, but not C++
+    ICK_Sampler_Conversion,    ///< Sampler initializer to sampler for OpenCL
     ICK_Num_Conversion_Kinds,  ///< The number of conversion kinds
   };
 
Index: include/clang/Driver/CC1Options.td
===================================================================
--- include/clang/Driver/CC1Options.td
+++ include/clang/Driver/CC1Options.td
@@ -687,6 +687,8 @@
   HelpText<"OpenCL language standard to compile for">;
 def cl_denorms_are_zero : Flag<["-"], "cl-denorms-are-zero">,
   HelpText<"OpenCL only. Allow denormals to be flushed to zero">;
+def cl_sampler_type : Separate<["-"], "cl-sampler-type">,
+  HelpText<"OpenCL only. Specify type of sampler to emit. Valid values: \"opaque\"(default), \"i32\"">;
 
 //===----------------------------------------------------------------------===//
 // CUDA Options
Index: include/clang/Basic/LangOptions.def
===================================================================
--- include/clang/Basic/LangOptions.def
+++ include/clang/Basic/LangOptions.def
@@ -255,6 +255,8 @@
                                            "field padding (0: none, 1:least "
                                            "aggressive, 2: more aggressive)")
 
+LANGOPT(CLSamplerOpaque, 1, 0, "Emit sampler as a pointer to opaque structure")
+
 #undef LANGOPT
 #undef COMPATIBLE_LANGOPT
 #undef BENIGN_LANGOPT
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -7827,6 +7827,12 @@
   "the event_t type can only be used with __private address space qualifier">;
 def err_expected_kernel_void_return_type : Error<
   "kernel must have void return type">;
+def err_sampler_initializer_not_integer : Error<
+  "sampler_t initialization requires 32-bit integer, not %0">;
+def warn_sampler_initializer_invalid_bits : Warning<
+  "Sampler initializer has invalid %0 bits">, InGroup<SpirCompat>;
+def err_sampler_initializer_not_constant : Error<
+  "sampler_t initialization requires compile time constant">;
 def err_sampler_argument_required : Error<
   "sampler_t variable required - got %0">;
 def err_wrong_sampler_addressspace: Error<
Index: include/clang/Basic/DiagnosticGroups.td
===================================================================
--- include/clang/Basic/DiagnosticGroups.td
+++ include/clang/Basic/DiagnosticGroups.td
@@ -871,3 +871,7 @@
 def OptionIgnored : DiagGroup<"option-ignored">;
 
 def UnknownArgument : DiagGroup<"unknown-argument">;
+
+// A warning group for warnings about code that clang accepts when
+// compiling OpenCL C/C++ but which is not compatible with the SPIR spec.
+def SpirCompat : DiagGroup<"spir-compat">;
\ No newline at end of file
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -1738,6 +1738,7 @@
   bool isImageType() const;                     // Any OpenCL image type
 
   bool isSamplerT() const;                      // OpenCL sampler_t
+  bool isSamplerInitT() const;                  // Internal sampler_init_t
   bool isEventT() const;                        // OpenCL event_t
   bool isClkEventT() const;                     // OpenCL clk_event_t
   bool isQueueT() const;                        // OpenCL queue_t
@@ -5597,6 +5598,10 @@
   return isSpecificBuiltinType(BuiltinType::OCLSampler);
 }
 
+inline bool Type::isSamplerInitT() const {
+  return isSpecificBuiltinType(BuiltinType::OCLSamplerInit);
+}
+
 inline bool Type::isEventT() const {
   return isSpecificBuiltinType(BuiltinType::OCLEvent);
 }
@@ -5630,7 +5635,8 @@
 
 inline bool Type::isOpenCLSpecificType() const {
   return isSamplerT() || isEventT() || isImageType() || isClkEventT() ||
-         isQueueT() || isNDRangeT() || isReserveIDT() || isPipeType();
+         isQueueT() || isNDRangeT() || isReserveIDT() || isPipeType() ||
+         isSamplerInitT();
 }
 
 inline bool Type::isTemplateTypeParmType() const {
Index: include/clang/AST/OperationKinds.def
===================================================================
--- include/clang/AST/OperationKinds.def
+++ include/clang/AST/OperationKinds.def
@@ -324,6 +324,11 @@
 // Convert a pointer to a different address space.
 CAST_OPERATION(AddressSpaceConversion)
 
+// Convert an integer initializer to an OpenCL sampler initializer.
+CAST_OPERATION(IntToOCLSamplerInitializer)
+
+// Convert an OpenCL sampler initializer to OpenCL sampler.
+CAST_OPERATION(OCLSamplerInitializerToSampler)
 
 //===- Binary Operations  -------------------------------------------------===//
 // Operators listed in order of precedence.
Index: include/clang/AST/BuiltinTypes.def
===================================================================
--- include/clang/AST/BuiltinTypes.def
+++ include/clang/AST/BuiltinTypes.def
@@ -160,6 +160,9 @@
 // OpenCL sampler_t.
 BUILTIN_TYPE(OCLSampler, OCLSamplerTy)
 
+// Internal OpenCL sampler initializer type.
+BUILTIN_TYPE(OCLSamplerInit, OCLSamplerInitTy)
+
 // OpenCL event_t.
 BUILTIN_TYPE(OCLEvent, OCLEventTy)
 
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h
+++ include/clang/AST/ASTContext.h
@@ -906,7 +906,7 @@
 #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
   CanQualType SingletonId;
 #include "clang/Basic/OpenCLImageTypes.def"
-  CanQualType OCLSamplerTy, OCLEventTy, OCLClkEventTy;
+  CanQualType OCLSamplerTy, OCLSamplerInitTy, OCLEventTy, OCLClkEventTy;
   CanQualType OCLQueueTy, OCLNDRangeTy, OCLReserveIDTy;
   CanQualType OMPArraySectionTy;
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to