[clang] Fix function pointer address space

Functions pointers should be created with program address space. This
patch introduces program address space in TargetInfo. Targets with
non-default (default is 0) address space for functions should explicitly
set this value. This patch fixes a crash on lvalue reference to function
pointer (in device code) when using oneAPI DPC++ compiler.

Differential Revision: https://reviews.llvm.org/D111566
This commit is contained in:
Elizabeth Andrews
2021-10-13 17:12:31 -07:00
parent 1fa4778d03
commit 4eaf5846d0
8 changed files with 58 additions and 12 deletions

View File

@@ -2727,13 +2727,9 @@ public:
QualType getFloatingTypeOfSizeWithinDomain(QualType typeSize,
QualType typeDomain) const;
unsigned getTargetAddressSpace(QualType T) const {
return getTargetAddressSpace(T.getQualifiers());
}
unsigned getTargetAddressSpace(QualType T) const;
unsigned getTargetAddressSpace(Qualifiers Q) const {
return getTargetAddressSpace(Q.getAddressSpace());
}
unsigned getTargetAddressSpace(Qualifiers Q) const;
unsigned getTargetAddressSpace(LangAS AS) const;

View File

@@ -212,6 +212,7 @@ protected:
unsigned char RegParmMax, SSERegParmMax;
TargetCXXABI TheCXXABI;
const LangASMap *AddrSpaceMap;
unsigned ProgramAddrSpace;
mutable StringRef PlatformName;
mutable VersionTuple PlatformMinVersion;
@@ -767,6 +768,9 @@ public:
return getTypeWidth(IntMaxType);
}
/// Return the address space for functions for the given target.
unsigned getProgramAddressSpace() const { return ProgramAddrSpace; }
// Return the size of unwind_word for this target.
virtual unsigned getUnwindWordWidth() const { return getPointerWidth(0); }

View File

@@ -11575,6 +11575,15 @@ uint64_t ASTContext::getTargetNullPointerValue(QualType QT) const {
return getTargetInfo().getNullPointerValue(AS);
}
unsigned ASTContext::getTargetAddressSpace(QualType T) const {
return T->isFunctionType() ? getTargetInfo().getProgramAddressSpace()
: getTargetAddressSpace(T.getQualifiers());
}
unsigned ASTContext::getTargetAddressSpace(Qualifiers Q) const {
return getTargetAddressSpace(Q.getAddressSpace());
}
unsigned ASTContext::getTargetAddressSpace(LangAS AS) const {
if (isTargetAddressSpace(AS))
return toTargetAddressSpace(AS);

View File

@@ -150,6 +150,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) {
PlatformMinVersion = VersionTuple();
MaxOpenCLWorkGroupSize = 1024;
ProgramAddrSpace = 0;
}
// Out of line virtual dtor for TargetInfo.

View File

@@ -55,6 +55,7 @@ public:
Int16Type = SignedInt;
Char32Type = UnsignedLong;
SigAtomicType = SignedChar;
ProgramAddrSpace = 1;
resetDataLayout("e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8");
}

View File

@@ -643,11 +643,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
llvm::Type *PointeeType = ConvertTypeForMem(ETy);
if (PointeeType->isVoidTy())
PointeeType = llvm::Type::getInt8Ty(getLLVMContext());
unsigned AS = PointeeType->isFunctionTy()
? getDataLayout().getProgramAddressSpace()
: Context.getTargetAddressSpace(ETy);
unsigned AS = Context.getTargetAddressSpace(ETy);
ResultType = llvm::PointerType::get(PointeeType, AS);
break;
}
@@ -748,7 +744,13 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
llvm::Type *PointeeType = CGM.getLangOpts().OpenCL
? CGM.getGenericBlockLiteralType()
: ConvertTypeForMem(FTy);
unsigned AS = Context.getTargetAddressSpace(FTy);
// Block pointers lower to function type. For function type,
// getTargetAddressSpace() returns default address space for
// function pointer i.e. program address space. Therefore, for block
// pointers, it is important to pass qualifiers when calling
// getTargetAddressSpace(), to ensure that we get the address space
// for data pointers and not function pointers.
unsigned AS = Context.getTargetAddressSpace(FTy.getQualifiers());
ResultType = llvm::PointerType::get(PointeeType, AS);
break;
}

View File

@@ -0,0 +1,8 @@
// RUN: %clang_cc1 -triple avr -emit-llvm %s -o - | FileCheck %s
int main() {
int (*p)();
return 0;
}
// CHECK: %p = alloca i16 (...) addrspace(1)*

View File

@@ -0,0 +1,25 @@
// RUN: %clang_cc1 -fsycl-is-device -emit-llvm -triple spir64 -verify -emit-llvm %s -o - | FileCheck %s
// expected-no-diagnostics
template <typename Name, typename Func>
__attribute__((sycl_kernel)) void kernel_single_task(const Func &kernelFunc) {
kernelFunc();
}
// CHECK: define dso_local spir_func{{.*}}invoke_function{{.*}}(i32 ()* %fptr, i32 addrspace(4)* %ptr)
void invoke_function(int (*fptr)(), int *ptr) {}
int f() { return 0; }
int main() {
kernel_single_task<class fake_kernel>([=]() {
int (*p)() = f;
int (&r)() = *p;
int a = 10;
invoke_function(p, &a);
invoke_function(r, &a);
invoke_function(f, &a);
});
return 0;
}