]> granicus.if.org Git - clang/commitdiff
Sema: Accept pointers to any address space for builtin functions
authorTom Stellard <thomas.stellard@amd.com>
Tue, 31 Mar 2015 16:39:02 +0000 (16:39 +0000)
committerTom Stellard <thomas.stellard@amd.com>
Tue, 31 Mar 2015 16:39:02 +0000 (16:39 +0000)
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

include/clang/Basic/Builtins.def
include/clang/Basic/Builtins.h
lib/Sema/SemaExpr.cpp
test/CodeGenOpenCL/memcpy.cl [new file with mode: 0644]
test/Sema/builtins.cl [new file with mode: 0644]

index a92d41250c627c5964f8f8deb08daccf8430b6d7..192790749be89b09e5f82a276cf97b0456260de1 100644 (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
index 3ce2255c86464f2d9ca490c5c42e24fc3ae134f1..27428ad81cb8b2cf6ba84ef7cd1f2367d1321a6f 100644 (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);
index 6eac5b6a93662d1bf057c90768af723ab2dda1d0..d6e6ab4ec86693a4e72c711ea29e3046cfd5faaf 100644 (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)) {
diff --git a/test/CodeGenOpenCL/memcpy.cl b/test/CodeGenOpenCL/memcpy.cl
new file mode 100644 (file)
index 0000000..cb27803
--- /dev/null
@@ -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 (file)
index 0000000..8cde8f3
--- /dev/null
@@ -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);
+}