Index: include/clang/Basic/Builtins.def =================================================================== --- include/clang/Basic/Builtins.def +++ include/clang/Basic/Builtins.def @@ -1288,6 +1288,11 @@ LANGBUILTIN(get_pipe_num_packets, "Ui.", "tn", OCLC_LANG) LANGBUILTIN(get_pipe_max_packets, "Ui.", "tn", OCLC_LANG) +// OpenCL v2.0 s6.13.9 - Address space qualifier functions. +LANGBUILTIN(to_global, "v*v*", "tn", OCLC_LANG) +LANGBUILTIN(to_local, "v*v*", "tn", OCLC_LANG) +LANGBUILTIN(to_private, "v*v*", "tn", OCLC_LANG) + #undef BUILTIN #undef LIBBUILTIN #undef LANGBUILTIN Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -498,6 +498,8 @@ def err_arm_invalid_specialreg : Error<"invalid special register for builtin">; def err_invalid_cpu_supports : Error<"invalid cpu feature string for builtin">; def err_builtin_needs_feature : Error<"%0 needs target feature %1">; +def err_builtin_needs_opencl_version + : Error<"%0 needs OpenCL version %1%select{| or above}2">; def err_function_needs_feature : Error<"always_inline function %1 requires target feature '%2', but would " "be inlined into function %0 that is compiled without support for " @@ -7860,6 +7862,11 @@ def err_opencl_extern_block_declaration : Error< "invalid block variable declaration - using 'extern' storage class is disallowed">; +// OpenCL v2.0 s6.13.9 - Address space qualifier functions. +def err_opencl_builtin_to_addr_arg_num : Error< + "invalid number of arguments to function: %0">; +def err_opencl_builtin_to_addr_invalid_arg : Error< + "invalid argument %0 to function: %1">; } // end of sema category let CategoryName = "OpenMP Issue" in { Index: lib/AST/Decl.cpp =================================================================== --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -2719,7 +2719,8 @@ // If the function is marked "overloadable", it has a different mangled name // and is not the C library function. - if (hasAttr()) + // OpenCL builtin functions can be overloaded. + if (hasAttr() && !Context.getLangOpts().OpenCL) return 0; if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) Index: lib/CodeGen/CGBuiltin.cpp =================================================================== --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -2124,6 +2124,20 @@ Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name), {Arg0})); } + // OpenCL v2.0 s6.13.9 Address space qualifier functions. + case Builtin::BIto_global: + case Builtin::BIto_local: + case Builtin::BIto_private: { + Value *Arg0 = EmitScalarExpr(E->getArg(0)); + llvm::Type *ArgTys[] = {Arg0->getType()}; + llvm::FunctionType *FTy = llvm::FunctionType::get( + ConvertType(E->getType()), llvm::ArrayRef(ArgTys), + false); + return RValue::get( + Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, + CGM.getMangledName(E->getDirectCallee())), {Arg0})); + } + case Builtin::BIprintf: if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) return EmitCUDADevicePrintfCallExpr(E, ReturnValue); Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -455,6 +455,40 @@ return false; } +// \brief Performs semantic analysis for the to_global/local/private call. +// \param S Reference to the semantic analyzer. +// \param BuiltinID ID of the builtin function. +// \param Call A pointer to the builtin call. +// \return True if a semantic error has been found, false otherwise. +static bool SemaBuiltinToAddr(Sema &S, unsigned BuiltinID, CallExpr *Call) { + // OpenCL v2.0 s6.13.9 - Address space qualifier functions. + if (S.getLangOpts().OpenCLVersion < 200) { + S.Diag(Call->getLocStart(), diag::err_builtin_needs_opencl_version) + << Call->getDirectCallee() << "2.0" << 1 << Call->getSourceRange(); + return true; + } + + if (Call->getNumArgs() != 1) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_to_addr_arg_num) + << Call->getDirectCallee() << Call->getSourceRange(); + return true; + } + + auto RT = Call->getArg(0)->getType(); + if (!RT->isPointerType() || RT->getPointeeType().getCanonicalType() + .getQualifiers().getAddressSpace() == LangAS::opencl_constant) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_to_addr_invalid_arg) + << Call->getArg(0) << Call->getDirectCallee() << Call->getSourceRange(); + return true; + } + + // Builtin functions with custom check need to set the correct type of call + // expression by themselves since Sema::BuildResolvedCallExpr does not do that. + Call->setType(cast(Call->getCalleeDecl())->getReturnType()); + + return false; +} + ExprResult Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, CallExpr *TheCall) { @@ -789,6 +823,12 @@ if (SemaBuiltinPipePackets(*this, TheCall)) return ExprError(); break; + case Builtin::BIto_global: + case Builtin::BIto_local: + case Builtin::BIto_private: + if (SemaBuiltinToAddr(*this, BuiltinID, TheCall)) + return ExprError(); + break; } // Since the target specific builtins for each arch overlap, only check those Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -5055,6 +5055,61 @@ return Callee->getMinRequiredArguments() <= NumArgs; } +/// OpenCL to_addr function accepts pointers to arbitrary type as argument. +/// This function change the original declaration to match the argument. +/// \return nullptr if this builtin is not OpenCL to_addr builtin function or +/// there is no need to change the function declaration. +static FunctionDecl * +rewriteBuiltinFunctionDeclForOpenCLToAddr(Sema *Sema, ASTContext &Context, + const FunctionDecl *FDecl, + MultiExprArg ArgExprs) { + auto ID = FDecl->getBuiltinID(); + if (ID != Builtin::BIto_global && + ID != Builtin::BIto_local && + ID != Builtin::BIto_private) + return nullptr; + + auto ArgT = ArgExprs[0]->getType(); + if (!ArgT->isPointerType()) + return nullptr; + + auto RT = ArgT->getPointeeType().getCanonicalType(); + auto Qual = RT.getQualifiers(); + switch (ID) { + case Builtin::BIto_global: + Qual.setAddressSpace(LangAS::opencl_global); + break; + case Builtin::BIto_local: + Qual.setAddressSpace(LangAS::opencl_local); + break; + default: + Qual.removeAddressSpace(); + } + RT = Sema->Context.getPointerType( + Sema->Context.getQualifiedType(RT.getUnqualifiedType(), Qual)); + + QualType ParmTy[] = {ArgT}; + FunctionProtoType::ExtProtoInfo EPI; + QualType OverloadTy = Context.getFunctionType(RT, ParmTy, EPI); + DeclContext *Parent = Context.getTranslationUnitDecl(); + FunctionDecl *OverloadDecl = FunctionDecl::Create(Context, Parent, + FDecl->getLocation(), + FDecl->getLocation(), + FDecl->getIdentifier(), + OverloadTy, + /*TInfo=*/nullptr, + SC_Extern, false, + /*hasPrototype=*/true); + ParmVarDecl *Parm[] = { + ParmVarDecl::Create(Context, OverloadDecl, SourceLocation(), + SourceLocation(), nullptr, ArgT, + /*TInfo=*/nullptr, SC_None, nullptr)}; + Parm[0]->setScopeInfo(0, 0); + OverloadDecl->setParams(Parm); + OverloadDecl->addAttr(OverloadableAttr::CreateImplicit(Sema->Context)); + return OverloadDecl; +} + /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma /// locations. @@ -5164,10 +5219,17 @@ FunctionDecl *FDecl = dyn_cast(NDecl); if (FDecl && FDecl->getBuiltinID()) { - // Rewrite the function decl for this builtin by replacing parameters - // with no explicit address space with the address space of the arguments - // in ArgExprs. - if ((FDecl = rewriteBuiltinFunctionDecl(this, Context, FDecl, ArgExprs))) { + // Rewrite the function decl for OpenCL to_addr builtin. + if (FunctionDecl *NFDecl = rewriteBuiltinFunctionDeclForOpenCLToAddr( + this, Context, FDecl, ArgExprs)) + FDecl = NFDecl; + else { + // Rewrite the function decl for this builtin by replacing parameters + // with no explicit address space with the address space of the arguments + // in ArgExprs. + FDecl = rewriteBuiltinFunctionDecl(this, Context, FDecl, ArgExprs); + } + if (FDecl) { NDecl = FDecl; Fn = DeclRefExpr::Create(Context, FDecl->getQualifierLoc(), SourceLocation(), FDecl, false, Index: test/CodeGenOpenCL/to_addr_builtin.cl =================================================================== --- /dev/null +++ test/CodeGenOpenCL/to_addr_builtin.cl @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -triple spir-unknown-unknown -emit-llvm -O0 -cl-std=CL2.0 -o - %s | FileCheck %s + +// CHECK: %[[A:.*]] = type { float, float, float } +typedef struct { + float x,y,z; +} A; +typedef private A *PA; +typedef global A *GA; + +void test(void) { + global int *glob; + local int *loc; + private int *priv; + generic int *gen; + + //CHECK: call i32 addrspace(1)* @_Z9to_globalPU3AS1i(i32 addrspace(1)* %{{.*}}) + glob = to_global(glob); + + //CHECK: call i32 addrspace(1)* @_Z9to_globalPU3AS3i(i32 addrspace(3)* %{{.*}}) + glob = to_global(loc); + + //CHECK: call i32 addrspace(1)* @_Z9to_globalPi(i32* %{{.*}}) + glob = to_global(priv); + + //CHECK: call i32 addrspace(1)* @_Z9to_globalPU3AS4i(i32 addrspace(4)* %{{.*}}) + glob = to_global(gen); + + //CHECK: call i32 addrspace(3)* @_Z8to_localPU3AS1i(i32 addrspace(1)* %{{.*}}) + loc = to_local(glob); + + //CHECK: call i32 addrspace(3)* @_Z8to_localPU3AS3i(i32 addrspace(3)* %{{.*}}) + loc = to_local(loc); + + //CHECK: call i32 addrspace(3)* @_Z8to_localPi(i32* %{{.*}}) + loc = to_local(priv); + + //CHECK: call i32 addrspace(3)* @_Z8to_localPU3AS4i(i32 addrspace(4)* %{{.*}}) + loc = to_local(gen); + + //CHECK: call i32* @_Z10to_privatePU3AS1i(i32 addrspace(1)* %{{.*}}) + priv = to_private(glob); + + //CHECK: call i32* @_Z10to_privatePU3AS3i(i32 addrspace(3)* %{{.*}}) + priv = to_private(loc); + + //CHECK: call i32* @_Z10to_privatePi(i32* %{{.*}}) + priv = to_private(priv); + + //CHECK: call i32* @_Z10to_privatePU3AS4i(i32 addrspace(4)* %{{.*}}) + priv = to_private(gen); + + //CHECK; call %[[A]] addrspace(1)* @_Z9to_globalP1A(%[[A]]* %{{.*}}) + PA pA; + GA gA = to_global(pA); +} Index: test/SemaOpenCL/to_addr_builtin.cl =================================================================== --- /dev/null +++ test/SemaOpenCL/to_addr_builtin.cl @@ -0,0 +1,38 @@ +// RUN: %clang_cc1 -verify -fsyntax-only %s +// RUN: %clang_cc1 -verify -fsyntax-only -cl-std=CL2.0 %s + +void test(void) { + global int *glob; + local int *loc; + constant int *con; + + glob = to_global(glob, loc); +#if __OPENCL_C_VERSION__ < CL_VERSION_2_0 + // expected-error@-2{{'to_global' needs OpenCL version 2.0 or above}} +#else + // expected-error@-4{{invalid number of arguments to function: 'to_global'}} +#endif + + int x; + glob = to_global(x); +#if __OPENCL_C_VERSION__ < CL_VERSION_2_0 + // expected-error@-2{{'to_global' needs OpenCL version 2.0 or above}} +#else + // expected-error@-4{{invalid argument x to function: 'to_global'}} +#endif + + glob = to_global(con); +#if __OPENCL_C_VERSION__ < CL_VERSION_2_0 + // expected-error@-2{{'to_global' needs OpenCL version 2.0 or above}} +#else + // expected-error@-4{{invalid argument con to function: 'to_global'}} +#endif + + loc = to_global(glob); +#if __OPENCL_C_VERSION__ < CL_VERSION_2_0 + // expected-error@-2{{'to_global' needs OpenCL version 2.0 or above}} +#else + // expected-error@-4{{assigning '__global int *' to '__local int *' changes address space of pointer}} +#endif + +}