yaxunl created this revision.
yaxunl added reviewers: arsenm, tstellarAMD, rjmccall.
yaxunl added a subscriber: cfe-commits.
Herald added subscribers: tony-tye, nhaehnle, wdng, kzhuravl.

In amdgcn target, null pointers in global, constant, and generic address space 
take value 0 but null pointers in private and local address space take value 
-1. Currently LLVM assumes all null pointers take value 0, which results in 
incorrectly translated IR. To workaround this issue, instead of emit null 
pointers in local and private address space, a null pointer in generic address 
space is emitted and casted to local and private address space.

A virtual member function translateNullPtr is added to TargetCodeGenInfo which 
by default does nothing. Each target can override this virtual function for 
translating null pointers.

A wrapper function translateNullPtr is added to CodegenModule to facilitate 
performing the target specific translation of null pointers.

This change has no effect on other targets except amdgcn target.


https://reviews.llvm.org/D26196

Files:
  lib/CodeGen/CGExprConstant.cpp
  lib/CodeGen/CGExprScalar.cpp
  lib/CodeGen/CodeGenModule.h
  lib/CodeGen/TargetInfo.cpp
  lib/CodeGen/TargetInfo.h
  test/CodeGenOpenCL/amdgpu-nullptr.cl

Index: test/CodeGenOpenCL/amdgpu-nullptr.cl
===================================================================
--- /dev/null
+++ test/CodeGenOpenCL/amdgpu-nullptr.cl
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -triple amdgcn -emit-llvm -o - | FileCheck %s
+
+// CHECK: @private_p = local_unnamed_addr addrspace(1) global i8* addrspacecast (i8 addrspace(4)* null to i8*), align 4
+private char *private_p = 0;
+
+// CHECK: @local_p = local_unnamed_addr addrspace(1) global i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), align 4
+local char *local_p = 0;
+
+// CHECK: @global_p = local_unnamed_addr addrspace(1) global i8 addrspace(1)* null, align 4
+global char *global_p = 0;
+
+// CHECK: @constant_p = local_unnamed_addr addrspace(1) global i8 addrspace(2)* null, align 4
+constant char *constant_p = 0;
+
+// CHECK: @generic_p = local_unnamed_addr addrspace(1) global i8 addrspace(4)* null, align 4
+generic char *generic_p = 0;
+
+// CHECK: icmp eq i8* %p, addrspacecast (i8 addrspace(4)* null to i8*)
+void cmp_private(private char* p) {
+  if (p != 0)
+    *p = 0;
+}
+
+// CHECK: icmp eq i8 addrspace(3)* %p, addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*)
+void cmp_local(local char* p) {
+  if (p != 0)
+    *p = 0;
+}
+
+// CHECK: icmp eq i8 addrspace(1)* %p, null
+void cmp_global(global char* p) {
+  if (p != 0)
+    *p = 0;
+}
+
+// CHECK: icmp eq i8 addrspace(2)* %p, null
+char cmp_constant(constant char* p) {
+  if (p != 0)
+    return *p;
+  else
+    return 0;
+}
+
+// CHECK: icmp eq i8 addrspace(4)* %p, null
+void cmp_generic(generic char* p) {
+  if (p != 0)
+    *p = 0;
+}
+
Index: lib/CodeGen/TargetInfo.h
===================================================================
--- lib/CodeGen/TargetInfo.h
+++ lib/CodeGen/TargetInfo.h
@@ -220,6 +220,13 @@
 
   /// Get LLVM calling convention for OpenCL kernel.
   virtual unsigned getOpenCLKernelCallingConv() const;
+
+  /// Translate null pointer to target specific value.
+  virtual llvm::Constant *translateNullPtr(const CodeGen::CodeGenModule &CGM,
+      llvm::Constant *C) const {
+    return C;
+  }
+
 };
 
 } // namespace CodeGen
Index: lib/CodeGen/TargetInfo.cpp
===================================================================
--- lib/CodeGen/TargetInfo.cpp
+++ lib/CodeGen/TargetInfo.cpp
@@ -6953,6 +6953,9 @@
   void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
                            CodeGen::CodeGenModule &M) const override;
   unsigned getOpenCLKernelCallingConv() const override;
+
+  llvm::Constant *translateNullPtr(const CodeGen::CodeGenModule &CGM,
+      llvm::Constant *C) const override;
 };
 
 }
@@ -7018,6 +7021,30 @@
   return llvm::CallingConv::AMDGPU_KERNEL;
 }
 
+// In amdgcn target the null pointer in global, constant, and generic
+// address space has value 0 but in private and local address space has
+// value -1. Currently LLVM assumes null pointers always have value 0,
+// which results in incorrectly transformed IR. Therefore, instead of
+// emitting null pointers in private and local address spaces, a null
+// pointer in generic address space is emitted which is casted to a
+// pointer in local or private address space.
+llvm::Constant *AMDGPUTargetCodeGenInfo::translateNullPtr(
+    const CodeGen::CodeGenModule &CGM, llvm::Constant *C) const {
+  if (!isa<llvm::ConstantPointerNull>(C))
+    return C;
+  auto PT = cast<llvm::PointerType>(C->getType());
+  auto &Ctx = CGM.getContext();
+  auto AS = PT->getAddressSpace();
+  if (CGM.getTarget().getTriple().getArch() != llvm::Triple::amdgcn ||
+    (AS != Ctx.getTargetAddressSpace(LangAS::opencl_local) && AS != 0))
+    return C;
+
+  auto NPT = llvm::PointerType::get(PT->getElementType(),
+      Ctx.getTargetAddressSpace(LangAS::opencl_generic));
+  return llvm::ConstantExpr::getAddrSpaceCast(
+      llvm::ConstantPointerNull::get(NPT), PT);
+}
+
 //===----------------------------------------------------------------------===//
 // SPARC v8 ABI Implementation.
 // Based on the SPARC Compliance Definition version 2.4.1.
Index: lib/CodeGen/CodeGenModule.h
===================================================================
--- lib/CodeGen/CodeGenModule.h
+++ lib/CodeGen/CodeGenModule.h
@@ -1152,6 +1152,9 @@
   llvm::Value *
   createOpenCLIntToSamplerConversion(const Expr *E, CodeGenFunction &CGF);
 
+  /// Perform target specific translation on null pointer.
+  llvm::Constant *translateNullPtr(llvm::Constant *C);
+
 private:
   llvm::Constant *
   GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty, GlobalDecl D,
Index: lib/CodeGen/CGExprScalar.cpp
===================================================================
--- lib/CodeGen/CGExprScalar.cpp
+++ lib/CodeGen/CGExprScalar.cpp
@@ -1449,12 +1449,13 @@
   case CK_FunctionToPointerDecay:
     return EmitLValue(E).getPointer();
 
-  case CK_NullToPointer:
+  case CK_NullToPointer: {
     if (MustVisitNullValue(E))
       (void) Visit(E);
 
-    return llvm::ConstantPointerNull::get(
-                               cast<llvm::PointerType>(ConvertType(DestTy)));
+    auto PT = cast<llvm::PointerType>(ConvertType(DestTy));
+    return CGF.CGM.translateNullPtr(llvm::ConstantPointerNull::get(PT));
+  }
 
   case CK_NullToMemberPointer: {
     if (MustVisitNullValue(E))
Index: lib/CodeGen/CGExprConstant.cpp
===================================================================
--- lib/CodeGen/CGExprConstant.cpp
+++ lib/CodeGen/CGExprConstant.cpp
@@ -16,6 +16,7 @@
 #include "CGObjCRuntime.h"
 #include "CGRecordLayout.h"
 #include "CodeGenModule.h"
+#include "TargetInfo.h"
 #include "clang/AST/APValue.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/RecordLayout.h"
@@ -1262,6 +1263,10 @@
   return C;
 }
 
+llvm::Constant *CodeGenModule::translateNullPtr(llvm::Constant *C) {
+  return getTargetCodeGenInfo().translateNullPtr(*this, C);
+}
+
 llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
                                                  QualType DestType,
                                                  CodeGenFunction *CGF) {
@@ -1329,7 +1334,8 @@
         C = llvm::ConstantExpr::getIntegerCast(
             C, getDataLayout().getIntPtrType(DestTy),
             /*isSigned=*/false);
-        return llvm::ConstantExpr::getIntToPtr(C, DestTy);
+        C = llvm::ConstantExpr::getIntToPtr(C, DestTy);
+        return translateNullPtr(C);
       }
 
       // If the types don't match this should only be a truncate.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to