aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/AST/OperationKinds.def2
-rw-r--r--clang/include/clang/Basic/DiagnosticGroups.td4
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td4
-rw-r--r--clang/lib/AST/ASTContext.cpp9
-rw-r--r--clang/lib/AST/Expr.cpp4
-rw-r--r--clang/lib/AST/ExprConstant.cpp2
-rw-r--r--clang/lib/CodeGen/CGDebugInfo.cpp5
-rw-r--r--clang/lib/CodeGen/CGDebugInfo.h1
-rw-r--r--clang/lib/CodeGen/CGExpr.cpp1
-rw-r--r--clang/lib/CodeGen/CGExprAgg.cpp1
-rw-r--r--clang/lib/CodeGen/CGExprComplex.cpp1
-rw-r--r--clang/lib/CodeGen/CGExprConstant.cpp3
-rw-r--r--clang/lib/CodeGen/CGExprScalar.cpp5
-rw-r--r--clang/lib/CodeGen/CGOpenCLRuntime.cpp11
-rw-r--r--clang/lib/CodeGen/CGOpenCLRuntime.h6
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp17
-rw-r--r--clang/lib/CodeGen/CodeGenModule.h3
-rw-r--r--clang/lib/Edit/RewriteObjCFoundationAPI.cpp1
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp7
-rw-r--r--clang/lib/Sema/SemaExpr.cpp5
-rw-r--r--clang/lib/Sema/SemaInit.cpp91
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp1
-rw-r--r--clang/test/CodeGenOpenCL/opencl_types.cl23
-rw-r--r--clang/test/CodeGenOpenCL/sampler.cl57
-rw-r--r--clang/test/SemaOpenCL/sampler_t.cl64
25 files changed, 294 insertions, 34 deletions
diff --git a/clang/include/clang/AST/OperationKinds.def b/clang/include/clang/AST/OperationKinds.def
index 82f494b..03a61e9 100644
--- a/clang/include/clang/AST/OperationKinds.def
+++ b/clang/include/clang/AST/OperationKinds.def
@@ -324,6 +324,8 @@ CAST_OPERATION(ZeroToOCLEvent)
// Convert a pointer to a different address space.
CAST_OPERATION(AddressSpaceConversion)
+// Convert an integer initializer to an OpenCL sampler.
+CAST_OPERATION(IntToOCLSampler)
//===- Binary Operations -------------------------------------------------===//
// Operators listed in order of precedence.
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 80136a3..4a5c021 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -876,3 +876,7 @@ def InvalidOrNonExistentDirectory : DiagGroup<"invalid-or-nonexistent-directory"
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
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 589b1c3..37b6dae 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7914,6 +7914,10 @@ def err_event_t_addr_space_qual : Error<
"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>, DefaultIgnore;
def err_sampler_argument_required : Error<
"sampler_t variable required - got %0">;
def err_wrong_sampler_addressspace: Error<
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index cf7f594..0d6ad9d 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -1734,11 +1734,12 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
Width = Target->getPointerWidth(0);
Align = Target->getPointerAlign(0);
break;
- case BuiltinType::OCLSampler:
- // Samplers are modeled as integers.
- Width = Target->getIntWidth();
- Align = Target->getIntAlign();
+ case BuiltinType::OCLSampler: {
+ auto AS = getTargetAddressSpace(LangAS::opencl_constant);
+ Width = Target->getPointerWidth(AS);
+ Align = Target->getPointerAlign(AS);
break;
+ }
case BuiltinType::OCLEvent:
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 71bbfdc..e835686 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -1569,6 +1569,7 @@ bool CastExpr::CastConsistency() const {
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
case CK_ZeroToOCLEvent:
+ case CK_IntToOCLSampler:
assert(!getType()->isBooleanType() && "unheralded conversion to bool");
goto CheckNoBasePath;
@@ -2747,7 +2748,8 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
CE->getCastKind() == CK_ToUnion ||
CE->getCastKind() == CK_ConstructorConversion ||
CE->getCastKind() == CK_NonAtomicToAtomic ||
- CE->getCastKind() == CK_AtomicToNonAtomic)
+ CE->getCastKind() == CK_AtomicToNonAtomic ||
+ CE->getCastKind() == CK_IntToOCLSampler)
return CE->getSubExpr()->isConstantInitializer(Ctx, false, Culprit);
break;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 760cda9..176f1ba 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -8056,6 +8056,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_ZeroToOCLEvent:
case CK_NonAtomicToAtomic:
case CK_AddressSpaceConversion:
+ case CK_IntToOCLSampler:
llvm_unreachable("invalid cast kind for integral value");
case CK_BitCast:
@@ -8547,6 +8548,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_ZeroToOCLEvent:
case CK_NonAtomicToAtomic:
case CK_AddressSpaceConversion:
+ case CK_IntToOCLSampler:
llvm_unreachable("invalid cast kind for complex value");
case CK_LValueToRValue:
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 9763e9b..b99b519 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -518,9 +518,8 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) {
SingletonId);
#include "clang/Basic/OpenCLImageTypes.def"
case BuiltinType::OCLSampler:
- return DBuilder.createBasicType(
- "opencl_sampler_t", CGM.getContext().getTypeSize(BT),
- CGM.getContext().getTypeAlign(BT), llvm::dwarf::DW_ATE_unsigned);
+ return getOrCreateStructPtrType("opencl_sampler_t",
+ OCLSamplerDITy);
case BuiltinType::OCLEvent:
return getOrCreateStructPtrType("opencl_event_t", OCLEventDITy);
case BuiltinType::OCLClkEvent:
diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h
index 70c1646..71c0df4 100644
--- a/clang/lib/CodeGen/CGDebugInfo.h
+++ b/clang/lib/CodeGen/CGDebugInfo.h
@@ -67,6 +67,7 @@ class CGDebugInfo {
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
llvm::DIType *SingletonId = nullptr;
#include "clang/Basic/OpenCLImageTypes.def"
+ llvm::DIType *OCLSamplerDITy = nullptr;
llvm::DIType *OCLEventDITy = nullptr;
llvm::DIType *OCLClkEventDITy = nullptr;
llvm::DIType *OCLQueueDITy = nullptr;
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 3e1ae36..039936a 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -3601,6 +3601,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_ARCExtendBlockObject:
case CK_CopyAndAutoreleaseBlockObject:
case CK_AddressSpaceConversion:
+ case CK_IntToOCLSampler:
return EmitUnsupportedLValue(E, "unexpected cast lvalue");
case CK_Dependent:
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 6d18843..f51330c 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -750,6 +750,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_BuiltinFnToFnPtr:
case CK_ZeroToOCLEvent:
case CK_AddressSpaceConversion:
+ case CK_IntToOCLSampler:
llvm_unreachable("cast kind invalid for aggregate types");
}
}
diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index e0d3fc4..af7f190 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -481,6 +481,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, Expr *Op,
case CK_BuiltinFnToFnPtr:
case CK_ZeroToOCLEvent:
case CK_AddressSpaceConversion:
+ case CK_IntToOCLSampler:
llvm_unreachable("invalid cast kind for complex value");
case CK_FloatingRealToComplex:
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index 803b3990..0e818e9 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -690,6 +690,9 @@ public:
case CK_ConstructorConversion:
return C;
+ case CK_IntToOCLSampler:
+ llvm_unreachable("global sampler variables are not generated");
+
case CK_Dependent: llvm_unreachable("saw dependent cast!");
case CK_BuiltinFnToFnPtr:
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 064bc95..343d3fb 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -1573,7 +1573,10 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
return llvm::Constant::getNullValue(ConvertType(DestTy));
}
- }
+ case CK_IntToOCLSampler:
+ return CGF.CGM.createOpenCLIntToSamplerConversion(E, CGF);
+
+ } // end of switch
llvm_unreachable("unknown scalar cast");
}
diff --git a/clang/lib/CodeGen/CGOpenCLRuntime.cpp b/clang/lib/CodeGen/CGOpenCLRuntime.cpp
index c0af6de..e4541d5 100644
--- a/clang/lib/CodeGen/CGOpenCLRuntime.cpp
+++ b/clang/lib/CodeGen/CGOpenCLRuntime.cpp
@@ -48,7 +48,7 @@ llvm::Type *CGOpenCLRuntime::convertOpenCLSpecificType(const Type *T) {
ImgAddrSpc);
#include "clang/Basic/OpenCLImageTypes.def"
case BuiltinType::OCLSampler:
- return llvm::IntegerType::get(Ctx, 32);
+ return getSamplerType();
case BuiltinType::OCLEvent:
return llvm::PointerType::get(llvm::StructType::create(
Ctx, "opencl.event_t"), 0);
@@ -77,3 +77,12 @@ llvm::Type *CGOpenCLRuntime::getPipeType() {
return PipeTy;
}
+
+llvm::PointerType *CGOpenCLRuntime::getSamplerType() {
+ if (!SamplerTy)
+ SamplerTy = llvm::PointerType::get(llvm::StructType::create(
+ CGM.getLLVMContext(), "opencl.sampler_t"),
+ CGM.getContext().getTargetAddressSpace(
+ LangAS::opencl_constant));
+ return SamplerTy;
+}
diff --git a/clang/lib/CodeGen/CGOpenCLRuntime.h b/clang/lib/CodeGen/CGOpenCLRuntime.h
index f1a7a31..41ead10 100644
--- a/clang/lib/CodeGen/CGOpenCLRuntime.h
+++ b/clang/lib/CodeGen/CGOpenCLRuntime.h
@@ -33,9 +33,11 @@ class CGOpenCLRuntime {
protected:
CodeGenModule &CGM;
llvm::Type *PipeTy;
+ llvm::PointerType *SamplerTy;
public:
- CGOpenCLRuntime(CodeGenModule &CGM) : CGM(CGM), PipeTy(nullptr) {}
+ CGOpenCLRuntime(CodeGenModule &CGM) : CGM(CGM), PipeTy(nullptr),
+ SamplerTy(nullptr) {}
virtual ~CGOpenCLRuntime();
/// Emit the IR required for a work-group-local variable declaration, and add
@@ -47,6 +49,8 @@ public:
virtual llvm::Type *convertOpenCLSpecificType(const Type *T);
virtual llvm::Type *getPipeType();
+
+ llvm::PointerType *getSamplerType();
};
}
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 96bb5bf..2affa57 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -2384,8 +2384,13 @@ void CodeGenModule::maybeSetTrivialComdat(const Decl &D,
/// Pass IsTentative as true if you want to create a tentative definition.
void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
bool IsTentative) {
- llvm::Constant *Init = nullptr;
+ // OpenCL global variables of sampler type are translated to function calls,
+ // therefore no need to be translated.
QualType ASTTy = D->getType();
+ if (getLangOpts().OpenCL && ASTTy->isSamplerT())
+ return;
+
+ llvm::Constant *Init = nullptr;
CXXRecordDecl *RD = ASTTy->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
bool NeedsGlobalCtor = false;
bool NeedsGlobalDtor = RD && !RD->hasTrivialDestructor();
@@ -4317,3 +4322,13 @@ llvm::SanitizerStatReport &CodeGenModule::getSanStats() {
return *SanStats;
}
+llvm::Value *
+CodeGenModule::createOpenCLIntToSamplerConversion(const Expr *E,
+ CodeGenFunction &CGF) {
+ llvm::Constant *C = EmitConstantExpr(E, E->getType(), &CGF);
+ auto SamplerT = getOpenCLRuntime().getSamplerType();
+ auto FTy = llvm::FunctionType::get(SamplerT, {C->getType()}, false);
+ return CGF.Builder.CreateCall(CreateRuntimeFunction(FTy,
+ "__translate_sampler_initializer"),
+ {C});
+}
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 9490499..5435445 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -1145,6 +1145,9 @@ public:
llvm::SanitizerStatReport &getSanStats();
+ llvm::Value *
+ createOpenCLIntToSamplerConversion(const Expr *E, CodeGenFunction &CGF);
+
private:
llvm::Constant *
GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty, GlobalDecl D,
diff --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
index 482c0f6..0ae1ec7 100644
--- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -1076,6 +1076,7 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
case CK_CopyAndAutoreleaseBlockObject:
case CK_BuiltinFnToFnPtr:
case CK_ZeroToOCLEvent:
+ case CK_IntToOCLSampler:
return false;
case CK_BooleanToSignedIntegral:
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 04da248..386e5773 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -2399,6 +2399,13 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
ParsePreprocessorArgs(Res.getPreprocessorOpts(), Args, FileMgr, Diags);
ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), Args,
Res.getFrontendOpts().ProgramAction);
+
+ // Turn on -Wspir-compat for SPIR target.
+ llvm::Triple T(Res.getTargetOpts().Triple);
+ auto Arch = T.getArch();
+ if (Arch == llvm::Triple::spir || Arch == llvm::Triple::spir64) {
+ Res.getDiagnosticOpts().Warnings.push_back("spir-compat");
+ }
return Success;
}
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 42c44b1..19a3d03 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7661,6 +7661,11 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
}
}
+ if (LHSType->isSamplerT() && RHSType->isIntegerType()) {
+ Kind = CK_IntToOCLSampler;
+ return Compatible;
+ }
+
return Incompatible;
}
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index af7fdc4..fc89694 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -4885,7 +4885,8 @@ static bool TryOCLSamplerInitialization(Sema &S,
QualType DestType,
Expr *Initializer) {
if (!S.getLangOpts().OpenCL || !DestType->isSamplerT() ||
- !Initializer->isIntegerConstantExpr(S.getASTContext()))
+ (!Initializer->isIntegerConstantExpr(S.Context) &&
+ !Initializer->getType()->isSamplerT()))
return false;
Sequence.AddOCLSamplerInitStep(DestType);
@@ -6903,19 +6904,93 @@ InitializationSequence::Perform(Sema &S,
}
case SK_OCLSamplerInit: {
- assert(Step->Type->isSamplerT() &&
+ // Sampler initialzation have 5 cases:
+ // 1. function argument passing
+ // 1a. argument is a file-scope variable
+ // 1b. argument is a function-scope variable
+ // 1c. argument is one of caller function's parameters
+ // 2. variable initialization
+ // 2a. initializing a file-scope variable
+ // 2b. initializing a function-scope variable
+ //
+ // For file-scope variables, since they cannot be initialized by function
+ // call of __translate_sampler_initializer in LLVM IR, their references
+ // need to be replaced by a cast from their literal initializers to
+ // sampler type. Since sampler variables can only be used in function
+ // calls as arguments, we only need to replace them when handling the
+ // argument passing.
+ assert(Step->Type->isSamplerT() &&
"Sampler initialization on non-sampler type.");
-
- QualType SourceType = CurInit.get()->getType();
-
+ Expr *Init = CurInit.get();
+ QualType SourceType = Init->getType();
+ // Case 1
if (Entity.isParameterKind()) {
- if (!SourceType->isSamplerT())
+ if (!SourceType->isSamplerT()) {
S.Diag(Kind.getLocation(), diag::err_sampler_argument_required)
<< SourceType;
- } else if (Entity.getKind() != InitializedEntity::EK_Variable) {
- llvm_unreachable("Invalid EntityKind!");
+ break;
+ } else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Init)) {
+ auto Var = cast<VarDecl>(DRE->getDecl());
+ // Case 1b and 1c
+ // No cast from integer to sampler is needed.
+ if (!Var->hasGlobalStorage()) {
+ CurInit = ImplicitCastExpr::Create(S.Context, Step->Type,
+ CK_LValueToRValue, Init,
+ /*BasePath=*/nullptr, VK_RValue);
+ break;
+ }
+ // Case 1a
+ // For function call with a file-scope sampler variable as argument,
+ // get the integer literal.
+ // Do not diagnose if the file-scope variable does not have initializer
+ // since this has already been diagnosed when parsing the variable
+ // declaration.
+ if (!Var->getInit() || !isa<ImplicitCastExpr>(Var->getInit()))
+ break;
+ Init = cast<ImplicitCastExpr>(const_cast<Expr*>(
+ Var->getInit()))->getSubExpr();
+ SourceType = Init->getType();
+ }
+ } else {
+ // Case 2
+ // Check initializer is 32 bit integer constant.
+ // If the initializer is taken from global variable, do not diagnose since
+ // this has already been done when parsing the variable declaration.
+ if (!Init->isConstantInitializer(S.Context, false))
+ break;
+
+ if (!SourceType->isIntegerType() ||
+ 32 != S.Context.getIntWidth(SourceType)) {
+ S.Diag(Kind.getLocation(), diag::err_sampler_initializer_not_integer)
+ << SourceType;
+ break;
+ }
+
+ llvm::APSInt Result;
+ Init->EvaluateAsInt(Result, S.Context);
+ const uint64_t SamplerValue = Result.getLimitedValue();
+ // 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 enum values of sampler properties
+ // defined in SPIR spec v1.2 and also opencl-c.h
+ unsigned AddressingMode = (0x0E & SamplerValue) >> 1;
+ unsigned FilterMode = (0x30 & SamplerValue) >> 4;
+ if (FilterMode != 1 && FilterMode != 2)
+ S.Diag(Kind.getLocation(),
+ diag::warn_sampler_initializer_invalid_bits)
+ << "Filter Mode";
+ if (AddressingMode > 4)
+ S.Diag(Kind.getLocation(),
+ diag::warn_sampler_initializer_invalid_bits)
+ << "Addressing Mode";
}
+ // Cases 1a, 2a and 2b
+ // Insert cast from integer to sampler.
+ CurInit = S.ImpCastExprToType(Init, S.Context.OCLSamplerTy,
+ CK_IntToOCLSampler);
break;
}
case SK_OCLZeroEvent: {
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 175225b..542399d 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -341,6 +341,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_AnyPointerToBlockPointerCast:
case CK_ObjCObjectLValueCast:
case CK_ZeroToOCLEvent:
+ case CK_IntToOCLSampler:
case CK_LValueBitCast: {
// Delegate to SValBuilder to process.
SVal V = state->getSVal(Ex, LCtx);
diff --git a/clang/test/CodeGenOpenCL/opencl_types.cl b/clang/test/CodeGenOpenCL/opencl_types.cl
index f20c740..73c57b7 100644
--- a/clang/test/CodeGenOpenCL/opencl_types.cl
+++ b/clang/test/CodeGenOpenCL/opencl_types.cl
@@ -1,9 +1,13 @@
// RUN: %clang_cc1 %s -triple "spir-unknown-unknown" -emit-llvm -o - -O0 | FileCheck %s --check-prefix=CHECK-SPIR
// RUN: %clang_cc1 %s -triple "amdgcn--amdhsa" -emit-llvm -o - -O0 | FileCheck %s --check-prefix=CHECK-AMDGCN
-constant sampler_t glb_smp = 7;
-// CHECK-SPIR: constant i32 7
-// CHECK-AMDGCN: addrspace(2) constant i32 7
+#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_NEAREST;
+// CHECK-SPIR-NOT: constant i32
void fnc1(image1d_t img) {}
// CHECK-SPIR: @fnc1(%opencl.image1d_ro_t addrspace(1)*
@@ -30,18 +34,19 @@ void fnc3(image3d_t img) {}
// CHECK-AMDGCN: @fnc3(%opencl.image3d_ro_t addrspace(2)*
void fnc4smp(sampler_t s) {}
-// CHECK-SPIR-LABEL: define {{.*}}void @fnc4smp(i32
+// CHECK-SPIR-LABEL: define {{.*}}void @fnc4smp(%opencl.sampler_t addrspace(2)*
+// CHECK-AMDGCN-LABEL: define {{.*}}void @fnc4smp(%opencl.sampler_t addrspace(2)*
kernel void foo(image1d_t img) {
- sampler_t smp = 5;
- // CHECK-SPIR: alloca i32
+ sampler_t smp = CLK_ADDRESS_CLAMP_TO_EDGE|CLK_NORMALIZED_COORDS_TRUE|CLK_FILTER_LINEAR;
+ // CHECK-SPIR: alloca %opencl.sampler_t addrspace(2)*
event_t evt;
// CHECK-SPIR: alloca %opencl.event_t*
- // CHECK-SPIR: store i32 5,
+ // CHECK-SPIR: store %opencl.sampler_t addrspace(2)*
fnc4smp(smp);
- // CHECK-SPIR: call {{.*}}void @fnc4smp(i32
+ // CHECK-SPIR: call {{.*}}void @fnc4smp(%opencl.sampler_t addrspace(2)*
fnc4smp(glb_smp);
- // CHECK-SPIR: call {{.*}}void @fnc4smp(i32
+ // CHECK-SPIR: call {{.*}}void @fnc4smp(%opencl.sampler_t addrspace(2)*
}
void __attribute__((overloadable)) bad1(image1d_t b, image2d_t c, image2d_t d) {}
diff --git a/clang/test/CodeGenOpenCL/sampler.cl b/clang/test/CodeGenOpenCL/sampler.cl
new file mode 100644
index 0000000..6fc8c2c
--- /dev/null
+++ b/clang/test/CodeGenOpenCL/sampler.cl
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 %s -emit-llvm -triple spir-unknown-unknown -o - -O0 | FileCheck %s
+//
+// This test covers 5 cases of sampler initialzation:
+// 1. function argument passing
+// 1a. argument is a file-scope variable
+// 1b. argument is a function-scope variable
+// 1c. argument is one of caller function's parameters
+// 2. variable initialization
+// 2a. initializing a file-scope variable
+// 2b. initializing a function-scope variable
+
+#define CLK_ADDRESS_CLAMP_TO_EDGE 2
+#define CLK_NORMALIZED_COORDS_TRUE 1
+#define CLK_FILTER_NEAREST 0x10
+#define CLK_FILTER_LINEAR 0x20
+
+// CHECK: %opencl.sampler_t = type opaque
+
+// Case 2a
+constant sampler_t glb_smp = CLK_ADDRESS_CLAMP_TO_EDGE | CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_LINEAR;
+// CHECK-NOT: glb_smp
+
+void fnc4smp(sampler_t s) {}
+// CHECK: define spir_func void @fnc4smp(%opencl.sampler_t addrspace(2)* %
+
+kernel void foo(sampler_t smp_par) {
+ // CHECK-LABEL: define spir_kernel void @foo(%opencl.sampler_t addrspace(2)* %smp_par)
+ // CHECK: [[smp_par_ptr:%[A-Za-z0-9_\.]+]] = alloca %opencl.sampler_t addrspace(2)*
+
+ // Case 2b
+ sampler_t smp = CLK_ADDRESS_CLAMP_TO_EDGE | CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_NEAREST;
+ // CHECK: [[smp_ptr:%[A-Za-z0-9_\.]+]] = alloca %opencl.sampler_t addrspace(2)*
+ // CHECK: [[SAMP:%[0-9]+]] = call %opencl.sampler_t addrspace(2)* @__translate_sampler_initializer(i32 19)
+ // CHECK: store %opencl.sampler_t addrspace(2)* [[SAMP]], %opencl.sampler_t addrspace(2)** [[smp_ptr]]
+
+ // Case 1b
+ fnc4smp(smp);
+ // CHECK-NOT: call %opencl.sampler_t addrspace(2)* @__translate_sampler_initializer(i32 19)
+ // CHECK: [[SAMP:%[0-9]+]] = load %opencl.sampler_t addrspace(2)*, %opencl.sampler_t addrspace(2)** [[smp_ptr]]
+ // CHECK: call spir_func void @fnc4smp(%opencl.sampler_t addrspace(2)* [[SAMP]])
+
+ // Case 1b
+ fnc4smp(smp);
+ // CHECK-NOT: call %opencl.sampler_t addrspace(2)* @__translate_sampler_initializer(i32 19)
+ // CHECK: [[SAMP:%[0-9]+]] = load %opencl.sampler_t addrspace(2)*, %opencl.sampler_t addrspace(2)** [[smp_ptr]]
+ // CHECK: call spir_func void @fnc4smp(%opencl.sampler_t addrspace(2)* [[SAMP]])
+
+ // Case 1a
+ fnc4smp(glb_smp);
+ // CHECK: [[SAMP:%[0-9]+]] = call %opencl.sampler_t addrspace(2)* @__translate_sampler_initializer(i32 35)
+ // CHECK: call spir_func void @fnc4smp(%opencl.sampler_t addrspace(2)* [[SAMP]])
+
+ // Case 1c
+ fnc4smp(smp_par);
+ // CHECK: [[SAMP:%[0-9]+]] = load %opencl.sampler_t addrspace(2)*, %opencl.sampler_t addrspace(2)** [[smp_par_ptr]]
+ // CHECK: call spir_func void @fnc4smp(%opencl.sampler_t addrspace(2)* [[SAMP]])
+}
diff --git a/clang/test/SemaOpenCL/sampler_t.cl b/clang/test/SemaOpenCL/sampler_t.cl
index 0553db8..c87b6da 100644
--- a/clang/test/SemaOpenCL/sampler_t.cl
+++ b/clang/test/SemaOpenCL/sampler_t.cl
@@ -1,6 +1,34 @@
// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -DCHECK_SAMPLER_VALUE -Wspir-compat -triple amdgcn--amdhsa
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -DCHECK_SAMPLER_VALUE -triple spir-unknown-unknown
-constant sampler_t glb_smp = 5;
+#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;
+constant sampler_t glb_smp2; // expected-error{{variable in constant address space must be initialized}}
+global sampler_t glb_smp3 = CLK_ADDRESS_CLAMP_TO_EDGE | CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_NEAREST; // expected-error{{sampler type cannot be used with the __local and __global address space qualifiers}}
+
+constant sampler_t glb_smp4 = 0;
+#ifdef CHECK_SAMPLER_VALUE
+// expected-warning@-2{{sampler initializer has invalid Filter Mode bits}}
+#endif
+
+constant sampler_t glb_smp5 = 0x1f;
+#ifdef CHECK_SAMPLER_VALUE
+// expected-warning@-2{{sampler initializer has invalid Addressing Mode bits}}
+#endif
+
+constant sampler_t glb_smp6 = glb_smp; // expected-error{{initializer element is not a compile-time constant}}
+
+int f(void);
+constant sampler_t glb_smp7 = f(); // expected-error{{initializer element is not a compile-time constant}}
+
+constant sampler_t glb_smp8 = 1.0f; // expected-error{{initializing '__constant sampler_t' with an expression of incompatible type 'float'}}
+
+constant sampler_t glb_smp9 = 0x100000000LL; // expected-error{{sampler_t initialization requires 32-bit integer, not 'long long'}}
void foo(sampler_t);
@@ -8,24 +36,50 @@ constant struct sampler_s {
sampler_t smp; // expected-error{{the 'sampler_t' type cannot be used to declare a structure or union field}}
} sampler_str = {0};
+sampler_t bad(void); //expected-error{{declaring function return value of type 'sampler_t' is not allowed}}
+
void kernel ker(sampler_t argsmp) {
local sampler_t smp; // expected-error{{sampler type cannot be used with the __local and __global address space qualifiers}}
- const sampler_t const_smp = 7;
+ const sampler_t const_smp = CLK_ADDRESS_CLAMP_TO_EDGE | CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_LINEAR;
+ const sampler_t const_smp2;
+ const sampler_t const_smp3 = const_smp;
+ const sampler_t const_smp4 = f();
+ const sampler_t const_smp5 = 1.0f; // expected-error{{initializing 'const sampler_t' with an expression of incompatible type 'float'}}
+ const sampler_t const_smp6 = 0x100000000LL; // expected-error{{sampler_t initialization requires 32-bit integer, not 'long long'}}
+
foo(glb_smp);
+ foo(glb_smp2);
+ foo(glb_smp3);
+ foo(glb_smp4);
+ foo(glb_smp5);
+ foo(glb_smp6);
+ foo(glb_smp7);
+ foo(glb_smp8);
+ foo(glb_smp9);
+ foo(smp);
+ foo(sampler_str.smp);
foo(const_smp);
+ foo(const_smp2);
+ foo(const_smp3);
+ foo(const_smp4);
+ foo(const_smp5);
+ foo(const_smp6);
+ 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}}
+ foo(sa[0]);
+ foo(bad());
}
void bad(sampler_t*); // expected-error{{pointer to type 'sampler_t' is invalid in OpenCL}}
void bar() {
- sampler_t smp1 = 7;
- sampler_t smp2 = 2;
+ sampler_t smp1 = CLK_ADDRESS_CLAMP_TO_EDGE | CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_LINEAR;
+ sampler_t smp2 = CLK_ADDRESS_CLAMP_TO_EDGE | CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_NEAREST;
smp1=smp2; //expected-error{{invalid operands to binary expression ('sampler_t' and 'sampler_t')}}
smp1+1; //expected-error{{invalid operands to binary expression ('sampler_t' and 'int')}}
&smp1; //expected-error{{invalid argument type 'sampler_t' to unary expression}}
*smp2; //expected-error{{invalid argument type 'sampler_t' to unary expression}}
+ foo(smp1+1); //expected-error{{invalid operands to binary expression ('sampler_t' and 'int')}}
}
-sampler_t bad(); //expected-error{{declaring function return value of type 'sampler_t' is not allowed}}