Hi, here is an updated patch. I've addressed all comments except I did not add
a DensMap to rewriteBuiltinFunctionDecl(), I wasn't sure exactly how to use
this to speed up the function. I can still add this if people think it will
help. I did some profiling of a function with 100,000 __builtin_memcpy() calls
and this patch doesn't seem to increase compile time.
I also did not add handling for return types. I wasn't able to figure out how
to get the actual call expression which had the return type used in the code.
I added a TODO for this.
REPOSITORY
rL LLVM
http://reviews.llvm.org/D8082
Files:
include/clang/Basic/Builtins.def
include/clang/Basic/Builtins.h
lib/Sema/SemaExpr.cpp
test/CodeGenOpenCL/memcpy.cl
test/Sema/builtins.cl
EMAIL PREFERENCES
http://reviews.llvm.org/settings/panel/emailpreferences/
Index: include/clang/Basic/Builtins.def
===================================================================
--- include/clang/Basic/Builtins.def
+++ 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
Index: include/clang/Basic/Builtins.h
===================================================================
--- include/clang/Basic/Builtins.h
+++ include/clang/Basic/Builtins.h
@@ -143,6 +143,12 @@
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);
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -4563,6 +4563,83 @@
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.
@@ -4666,10 +4743,24 @@
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)) {
Index: test/CodeGenOpenCL/memcpy.cl
===================================================================
--- /dev/null
+++ 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);
+}
Index: test/Sema/builtins.cl
===================================================================
--- /dev/null
+++ 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);
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits