yaxunl created this revision.
yaxunl added reviewers: Anastasia, pxli168.
yaxunl added subscribers: cfe-commits, tstellarAMD.

OpenCL builtin functions to_{global|local|private} accepts argument of pointer 
type to arbitrary pointee type, and return a pointer to the same pointee type 
in different addr space, i.e.

  global gentype *to_global(gentype *p);

It is not desirable to declare it as

  global void *to_global(void *);

in opencl header file since it misses diagnostics and generates extra bitcasts.

This patch implements these builtin functions as Clang builtin functions. In 
the builtin def file they are defined to have signature void*(void*). When 
handling call expressions, their declarations are re-written to have correct 
parameter type and return type corresponding to the call argument.

http://reviews.llvm.org/D19932

Files:
  include/clang/Basic/Builtins.def
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/AST/Decl.cpp
  lib/CodeGen/CGBuiltin.cpp
  lib/Sema/SemaChecking.cpp
  lib/Sema/SemaExpr.cpp
  test/CodeGenOpenCL/to_addr_builtin.cl
  test/SemaOpenCL/to_addr_builtin.cl

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
+
+}
Index: test/CodeGenOpenCL/to_addr_builtin.cl
===================================================================
--- /dev/null
+++ test/CodeGenOpenCL/to_addr_builtin.cl
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -triple spir-unknown-unknown -emit-llvm -O0 -cl-std=CL2.0 -o - %s | FileCheck %s
+
+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_globalPU3AS1v(i32 addrspace(1)* %{{.*}})
+  glob = to_global(glob);
+  
+  //CHECK: call i32 addrspace(1)* @_Z9to_globalPU3AS3v(i32 addrspace(3)* %{{.*}})
+  glob = to_global(loc);
+ 
+   //CHECK: call i32 addrspace(1)* @_Z9to_globalPv(i32* %{{.*}})
+  glob = to_global(priv);
+ 
+   //CHECK: call i32 addrspace(1)* @_Z9to_globalPU3AS4v(i32 addrspace(4)* %{{.*}})
+  glob = to_global(gen);
+  
+  //CHECK: call i32 addrspace(3)* @_Z8to_localPU3AS1v(i32 addrspace(1)* %{{.*}})
+  loc = to_local(glob);
+
+  //CHECK: call i32 addrspace(3)* @_Z8to_localPU3AS3v(i32 addrspace(3)* %{{.*}})
+  loc = to_local(loc);
+
+  //CHECK: call i32 addrspace(3)* @_Z8to_localPv(i32* %{{.*}})
+  loc = to_local(priv);
+
+  //CHECK: call i32 addrspace(3)* @_Z8to_localPU3AS4v(i32 addrspace(4)* %{{.*}})
+  loc = to_local(gen);
+
+  //CHECK: call i32* @_Z10to_privatePU3AS1v(i32 addrspace(1)* %{{.*}})
+  priv = to_private(glob);
+
+  //CHECK: call i32* @_Z10to_privatePU3AS3v(i32 addrspace(3)* %{{.*}})
+  priv = to_private(loc);
+
+  //CHECK: call i32* @_Z10to_privatePv(i32* %{{.*}})
+  priv = to_private(priv);
+
+  //CHECK: call i32* @_Z10to_privatePU3AS4v(i32 addrspace(4)* %{{.*}})
+  priv = to_private(gen);
+
+  PA pA;
+  GA gA = to_global(pA);
+  };
+}
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<FunctionDecl>(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: 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<FunctionDecl>(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/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<llvm::Type *>(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/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<OverloadableAttr>())
+  // OpenCL builtin functions can be overloaded.
+  if (hasAttr<OverloadableAttr>() && !Context.getLangOpts().OpenCL)
     return 0;
 
   if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
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: 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
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to