From: Tom Stellard Date: Tue, 31 Mar 2015 16:39:02 +0000 (+0000) Subject: Sema: Accept pointers to any address space for builtin functions X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=035326683424f8db89e186307ba5a37e1f9bd34f;p=clang Sema: Accept pointers to any address space for builtin functions As long as they don't have an address space explicitly defined. This allows builtins with pointer arguments to be used with OpenCL. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@233706 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def index a92d41250c..192790749b 100644 --- a/include/clang/Basic/Builtins.def +++ b/include/clang/Basic/Builtins.def @@ -56,7 +56,8 @@ // I -> Required to constant fold to an integer constant expression. // // Types may be postfixed with the following modifiers: -// * -> pointer (optionally followed by an address space number) +// * -> pointer (optionally followed by an address space number, if no address +// space is specified than any address space will be accepted) // & -> reference (optionally followed by an address space number) // C -> const // D -> volatile diff --git a/include/clang/Basic/Builtins.h b/include/clang/Basic/Builtins.h index 3ce2255c86..27428ad81c 100644 --- a/include/clang/Basic/Builtins.h +++ b/include/clang/Basic/Builtins.h @@ -143,6 +143,12 @@ public: return strchr(GetRecord(ID).Attributes, 't') != nullptr; } + /// \brief Determines whether this builtin has a result or any arguments which + /// are pointer types. + bool hasPtrArgsOrResult(unsigned ID) const { + return strchr(GetRecord(ID).Type, '*') != nullptr; + } + /// \brief Completely forget that the given ID was ever considered a builtin, /// e.g., because the user provided a conflicting signature. void ForgetBuiltin(unsigned ID, IdentifierTable &Table); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 6eac5b6a93..d6e6ab4ec8 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -4608,6 +4608,83 @@ static bool checkArgsForPlaceholders(Sema &S, MultiExprArg args) { return hasInvalid; } +/// If a builtin function has a pointer argument with no explicit address +/// space, than it should be able to accept a pointer to any address +/// space as input. In order to do this, we need to replace the +/// standard builtin declaration with one that uses the same address space +/// as the call. +/// +/// \returns nullptr If this builtin is not a candidate for a rewrite i.e. +/// it does not contain any pointer arguments without +/// an address space qualifer. Otherwise the rewritten +/// FunctionDecl is returned. +/// TODO: Handle pointer return types. +static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context, + const FunctionDecl *FDecl, + MultiExprArg ArgExprs) { + + QualType DeclType = FDecl->getType(); + const FunctionProtoType *FT = dyn_cast(DeclType); + + if (!Context.BuiltinInfo.hasPtrArgsOrResult(FDecl->getBuiltinID()) || + !FT || FT->isVariadic() || ArgExprs.size() != FT->getNumParams()) + return nullptr; + + bool NeedsNewDecl = false; + unsigned i = 0; + SmallVector OverloadParams; + + for (QualType ParamType : FT->param_types()) { + + // Convert array arguments to pointer to simplify type lookup. + Expr *Arg = Sema->DefaultFunctionArrayLvalueConversion(ArgExprs[i++]).get(); + QualType ArgType = Arg->getType(); + if (!ParamType->isPointerType() || + ParamType.getQualifiers().hasAddressSpace() || + !ArgType->isPointerType() || + !ArgType->getPointeeType().getQualifiers().hasAddressSpace()) { + OverloadParams.push_back(ParamType); + continue; + } + + NeedsNewDecl = true; + unsigned AS = ArgType->getPointeeType().getQualifiers().getAddressSpace(); + + QualType PointeeType = ParamType->getPointeeType(); + PointeeType = Context.getAddrSpaceQualType(PointeeType, AS); + OverloadParams.push_back(Context.getPointerType(PointeeType)); + } + + if (!NeedsNewDecl) + return nullptr; + + FunctionProtoType::ExtProtoInfo EPI; + QualType OverloadTy = Context.getFunctionType(FT->getReturnType(), + OverloadParams, 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); + SmallVector Params; + FT = cast(OverloadTy); + for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) { + QualType ParamType = FT->getParamType(i); + ParmVarDecl *Parm = + ParmVarDecl::Create(Context, OverloadDecl, SourceLocation(), + SourceLocation(), nullptr, ParamType, + /*TInfo=*/nullptr, SC_None, nullptr); + Parm->setScopeInfo(0, i); + Params.push_back(Parm); + } + OverloadDecl->setParams(Params); + 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. @@ -4711,10 +4788,24 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, if (UnaryOperator *UnOp = dyn_cast(NakedFn)) if (UnOp->getOpcode() == UO_AddrOf) NakedFn = UnOp->getSubExpr()->IgnoreParens(); - - if (isa(NakedFn)) + + if (isa(NakedFn)) { NDecl = cast(NakedFn)->getDecl(); - else if (isa(NakedFn)) + + FunctionDecl *FDecl = dyn_cast(NDecl); + if (FDecl && FDecl->getBuiltinID()) { + // Rewrite the function decl for this builtin by replacing paramaters + // with no explicit address space with the address space of the arguments + // in ArgExprs. + if ((FDecl = rewriteBuiltinFunctionDecl(this, Context, FDecl, ArgExprs))) { + NDecl = FDecl; + Fn = DeclRefExpr::Create(Context, FDecl->getQualifierLoc(), + SourceLocation(), FDecl, false, + SourceLocation(), FDecl->getType(), + Fn->getValueKind(), FDecl); + } + } + } else if (isa(NakedFn)) NDecl = cast(NakedFn)->getMemberDecl(); if (FunctionDecl *FD = dyn_cast_or_null(NDecl)) { diff --git a/test/CodeGenOpenCL/memcpy.cl b/test/CodeGenOpenCL/memcpy.cl new file mode 100644 index 0000000000..cb27803adf --- /dev/null +++ b/test/CodeGenOpenCL/memcpy.cl @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 %s -ffake-address-space-map -emit-llvm -o - | FileCheck %s + +// CHECK-LABEL: @test +// CHECK-NOT: addrspacecast +// CHECK: call void @llvm.memcpy.p1i8.p3i8 +kernel void test(global float *g, constant float *c) { + __builtin_memcpy(g, c, 32); +} diff --git a/test/Sema/builtins.cl b/test/Sema/builtins.cl new file mode 100644 index 0000000000..8cde8f3d10 --- /dev/null +++ b/test/Sema/builtins.cl @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic +// expected-no-diagnostics + +kernel void test(global float *out, global float *in, global int* in2) { + out[0] = __builtin_nanf(""); + __builtin_memcpy(out, in, 32); + out[0] = __builtin_frexpf(in[0], in2); +}