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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits