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.

llvm-svn: 233706
This commit is contained in:
Tom Stellard 2015-03-31 16:39:02 +00:00
parent bf441f4ffa
commit b919c7d9eb
5 changed files with 118 additions and 4 deletions

View File

@ -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

View File

@ -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);

View File

@ -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<FunctionProtoType>(DeclType);
if (!Context.BuiltinInfo.hasPtrArgsOrResult(FDecl->getBuiltinID()) ||
!FT || FT->isVariadic() || ArgExprs.size() != FT->getNumParams())
return nullptr;
bool NeedsNewDecl = false;
unsigned i = 0;
SmallVector<QualType, 8> 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<ParmVarDecl*, 16> Params;
FT = cast<FunctionProtoType>(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<UnaryOperator>(NakedFn))
if (UnOp->getOpcode() == UO_AddrOf)
NakedFn = UnOp->getSubExpr()->IgnoreParens();
if (isa<DeclRefExpr>(NakedFn))
if (isa<DeclRefExpr>(NakedFn)) {
NDecl = cast<DeclRefExpr>(NakedFn)->getDecl();
else if (isa<MemberExpr>(NakedFn))
FunctionDecl *FDecl = dyn_cast<FunctionDecl>(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<MemberExpr>(NakedFn))
NDecl = cast<MemberExpr>(NakedFn)->getMemberDecl();
if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(NDecl)) {

View File

@ -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);
}

View File

@ -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);
}