Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions include/LLVMSPIRVOpts.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,14 @@ class TranslatorOpts {
PreserveOCLKernelArgTypeMetadataThroughString = Value;
}

bool shouldEmitFunctionPtrAddrSpace() const noexcept {
return EmitFunctionPtrAddrSpace;
}

void setEmitFunctionPtrAddrSpace(bool Value) noexcept {
EmitFunctionPtrAddrSpace = Value;
}

void setBuiltinFormat(BuiltinFormat Value) noexcept {
SPIRVBuiltinFormat = Value;
}
Expand Down Expand Up @@ -281,6 +289,10 @@ class TranslatorOpts {
// kernel_arg_type_qual metadata through OpString
bool PreserveOCLKernelArgTypeMetadataThroughString = false;

// Controls if CodeSectionINTEL can be emitted and consumed with a dedicated
// address space
bool EmitFunctionPtrAddrSpace = false;

bool PreserveAuxData = false;

BuiltinFormat SPIRVBuiltinFormat = BuiltinFormat::Function;
Expand Down
4 changes: 4 additions & 0 deletions lib/SPIRV/SPIRVInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ enum SPIRAddressSpace {
SPIRAS_GlobalHost,
SPIRAS_Input,
SPIRAS_Output,
SPIRAS_CodeSectionINTEL,
SPIRAS_Count,
};

Expand All @@ -199,6 +200,8 @@ template <> inline void SPIRVMap<SPIRAddressSpace, std::string>::init() {
add(SPIRAS_Local, "Local");
add(SPIRAS_Generic, "Generic");
add(SPIRAS_Input, "Input");
add(SPIRAS_CodeSectionINTEL, "CodeSectionINTEL");

add(SPIRAS_GlobalDevice, "GlobalDevice");
add(SPIRAS_GlobalHost, "GlobalHost");
}
Expand All @@ -215,6 +218,7 @@ inline void SPIRVMap<SPIRAddressSpace, SPIRVStorageClassKind>::init() {
add(SPIRAS_Input, StorageClassInput);
add(SPIRAS_GlobalDevice, StorageClassDeviceOnlyINTEL);
add(SPIRAS_GlobalHost, StorageClassHostOnlyINTEL);
add(SPIRAS_CodeSectionINTEL, StorageClassCodeSectionINTEL);
}
typedef SPIRVMap<SPIRAddressSpace, SPIRVStorageClassKind> SPIRSPIRVAddrSpaceMap;

Expand Down
51 changes: 43 additions & 8 deletions lib/SPIRV/SPIRVReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,16 +348,21 @@ Type *SPIRVToLLVM::transType(SPIRVType *T, bool UseTPT) {
case internal::OpTypeTokenINTEL:
return mapType(T, Type::getTokenTy(*Context));
case OpTypePointer: {
const unsigned AS =
SPIRSPIRVAddrSpaceMap::rmap(T->getPointerStorageClass());
unsigned AS = SPIRSPIRVAddrSpaceMap::rmap(T->getPointerStorageClass());
if (AS == SPIRAS_CodeSectionINTEL && !BM->shouldEmitFunctionPtrAddrSpace())
AS = SPIRAS_Private;
if (BM->shouldEmitFunctionPtrAddrSpace() &&
T->getPointerElementType()->getOpCode() == OpTypeFunction)
AS = SPIRAS_CodeSectionINTEL;
Type *ElementTy = transType(T->getPointerElementType(), UseTPT);
if (UseTPT)
return TypedPointerType::get(ElementTy, AS);
return mapType(T, PointerType::get(ElementTy, AS));
}
case OpTypeUntypedPointerKHR: {
const unsigned AS =
SPIRSPIRVAddrSpaceMap::rmap(T->getPointerStorageClass());
unsigned AS = SPIRSPIRVAddrSpaceMap::rmap(T->getPointerStorageClass());
if (AS == SPIRAS_CodeSectionINTEL && !BM->shouldEmitFunctionPtrAddrSpace())
AS = SPIRAS_Private;
return mapType(T, PointerType::get(*Context, AS));
}
case OpTypeVector:
Expand Down Expand Up @@ -1469,6 +1474,17 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
case OpTypeMatrix:
case OpTypeArray: {
auto *AT = cast<ArrayType>(transType(BCC->getType()));
for (size_t I = 0; I != AT->getNumElements(); ++I) {
auto *ElemTy = AT->getElementType();
if (auto *ElemPtrTy = dyn_cast<PointerType>(ElemTy)) {
assert(isa<PointerType>(CV[I]->getType()) &&
"Constant type doesn't match constexpr array element type");
if (ElemPtrTy->getAddressSpace() !=
cast<PointerType>(CV[I]->getType())->getAddressSpace())
CV[I] = ConstantExpr::getAddrSpaceCast(CV[I], AT->getElementType());
}
}

return mapValue(BV, ConstantArray::get(AT, CV));
}
case OpTypeStruct: {
Expand All @@ -1485,7 +1501,12 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
!BCCTy->getElementType(I)->isPointerTy())
continue;

CV[I] = ConstantExpr::getBitCast(CV[I], BCCTy->getElementType(I));
if (cast<PointerType>(CV[I]->getType())->getAddressSpace() !=
cast<PointerType>(BCCTy->getElementType(I))->getAddressSpace())
CV[I] =
ConstantExpr::getAddrSpaceCast(CV[I], BCCTy->getElementType(I));
else
CV[I] = ConstantExpr::getBitCast(CV[I], BCCTy->getElementType(I));
}
}

Expand Down Expand Up @@ -1521,7 +1542,10 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
static_cast<SPIRVConstantFunctionPointerINTEL *>(BV);
SPIRVFunction *F = BC->getFunction();
BV->setName(F->getName());
return mapValue(BV, transFunction(F));
const unsigned AS = BM->shouldEmitFunctionPtrAddrSpace()
? SPIRAS_CodeSectionINTEL
: SPIRAS_Private;
return mapValue(BV, transFunction(F, AS));
}

case OpUndef:
Expand Down Expand Up @@ -3040,7 +3064,7 @@ void SPIRVToLLVM::transFunctionAttrs(SPIRVFunction *BF, Function *F) {
});
}

Function *SPIRVToLLVM::transFunction(SPIRVFunction *BF) {
Function *SPIRVToLLVM::transFunction(SPIRVFunction *BF, unsigned AS) {
auto Loc = FuncMap.find(BF);
if (Loc != FuncMap.end())
return Loc->second;
Expand Down Expand Up @@ -3088,7 +3112,7 @@ Function *SPIRVToLLVM::transFunction(SPIRVFunction *BF) {
}
Function *F = M->getFunction(FuncName);
if (!F)
F = Function::Create(FT, Linkage, FuncName, M);
F = Function::Create(FT, Linkage, AS, FuncName, M);
F = cast<Function>(mapValue(BF, F));
mapFunction(BF, F);

Expand Down Expand Up @@ -3495,6 +3519,17 @@ bool SPIRVToLLVM::translate() {
DbgTran->transDebugInst(EI);
}

for (auto *FP : BM->getFunctionPointers()) {
SPIRVConstantFunctionPointerINTEL *BC =
static_cast<SPIRVConstantFunctionPointerINTEL *>(FP);
SPIRVFunction *F = BC->getFunction();
FP->setName(F->getName());
const unsigned AS = BM->shouldEmitFunctionPtrAddrSpace()
? SPIRAS_CodeSectionINTEL
: SPIRAS_Private;
mapValue(FP, transFunction(F, AS));
}

for (unsigned I = 0, E = BM->getNumFunctions(); I != E; ++I) {
transFunction(BM->getFunction(I));
transUserSemantic(BM->getFunction(I));
Expand Down
2 changes: 1 addition & 1 deletion lib/SPIRV/SPIRVReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ class SPIRVToLLVM : private BuiltinCallHelper {
void transAuxDataInst(SPIRVExtInst *BC);
std::vector<Value *> transValue(const std::vector<SPIRVValue *> &,
Function *F, BasicBlock *);
Function *transFunction(SPIRVFunction *F);
Function *transFunction(SPIRVFunction *F, unsigned AS = SPIRAS_Private);
void transFunctionAttrs(SPIRVFunction *BF, Function *F);
Value *transBlockInvoke(SPIRVValue *Invoke, BasicBlock *BB);
Instruction *transWGSizeQueryBI(SPIRVInstruction *BI, BasicBlock *BB);
Expand Down
8 changes: 8 additions & 0 deletions lib/SPIRV/SPIRVWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,11 @@ SPIRVType *LLVMToSPIRVBase::transPointerType(Type *ET, unsigned AddrSpc) {
((AddrSpc == SPIRAS_GlobalDevice) || (AddrSpc == SPIRAS_GlobalHost))) {
return transPointerType(ET, SPIRAS_Global);
}
// Lower function pointer address space to private if
// spirv-emit-function-ptr-addr-space is not passed
if (AddrSpc == SPIRAS_CodeSectionINTEL &&
!BM->shouldEmitFunctionPtrAddrSpace())
return transPointerType(ET, SPIRAS_Private);
if (ST && !ST->isSized()) {
Op OpCode;
StringRef STName = ST->getName();
Expand Down Expand Up @@ -750,6 +755,9 @@ SPIRVType *LLVMToSPIRVBase::transPointerType(SPIRVType *ET, unsigned AddrSpc) {
return Loc->second;

SPIRVType *TranslatedTy = nullptr;
if (AddrSpc == SPIRAS_CodeSectionINTEL &&
!BM->shouldEmitFunctionPtrAddrSpace())
return transPointerType(ET, SPIRAS_Private);
if (BM->isAllowedToUseExtension(ExtensionID::SPV_KHR_untyped_pointers) &&
!(ET->isTypeArray() || ET->isTypeVector() || ET->isTypeImage() ||
ET->isTypeSampler() || ET->isTypePipe())) {
Expand Down
5 changes: 5 additions & 0 deletions lib/SPIRV/libSPIRV/SPIRVInstruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,11 @@ SPIRVInstruction *createInstFromSpecConstantOp(SPIRVSpecConstantOp *Inst) {
auto OC = static_cast<Op>(Ops[0]);
assert(isSpecConstantOpAllowedOp(OC) &&
"Op code not allowed for OpSpecConstantOp");
auto *Const = Inst->getOperand(1);
// LLVM would eliminate a bitcast from a function pointer in a constexpr
// context. Cut this short here to avoid necessity to align address spaces
if (OC == OpBitcast && Const->getOpCode() == OpConstantFunctionPointerINTEL)
return static_cast<SPIRVInstruction *>(Const);
Ops.erase(Ops.begin(), Ops.begin() + 1);
auto *BM = Inst->getModule();
auto *RetInst = SPIRVInstTemplateBase::create(
Expand Down
7 changes: 7 additions & 0 deletions lib/SPIRV/libSPIRV/SPIRVModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,13 @@ class SPIRVModuleImpl : public SPIRVModule {
SPIRVConstant *getLiteralAsConstant(unsigned Literal) override;
unsigned getNumFunctions() const override { return FuncVec.size(); }
unsigned getNumVariables() const override { return VariableVec.size(); }
std::vector<SPIRVValue *> getFunctionPointers() const override {
std::vector<SPIRVValue *> Res;
for (auto *C : ConstVec)
if (C->getOpCode() == OpConstantFunctionPointerINTEL)
Res.emplace_back(C);
return Res;
}
SourceLanguage getSourceLanguage(SPIRVWord *Ver = nullptr) const override {
if (Ver)
*Ver = SrcLangVer;
Expand Down
5 changes: 5 additions & 0 deletions lib/SPIRV/libSPIRV/SPIRVModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ class SPIRVModule {
virtual SPIRVMemoryModelKind getMemoryModel() const = 0;
virtual unsigned getNumFunctions() const = 0;
virtual unsigned getNumVariables() const = 0;
virtual std::vector<SPIRVValue *> getFunctionPointers() const = 0;
virtual SourceLanguage getSourceLanguage(SPIRVWord *) const = 0;
virtual std::set<std::string> &getSourceExtension() = 0;
virtual SPIRVValue *getValue(SPIRVId TheId) const = 0;
Expand Down Expand Up @@ -553,6 +554,10 @@ class SPIRVModule {
.shouldPreserveOCLKernelArgTypeMetadataThroughString();
}

bool shouldEmitFunctionPtrAddrSpace() const noexcept {
return TranslationOpts.shouldEmitFunctionPtrAddrSpace();
}

bool preserveAuxData() const noexcept {
return TranslationOpts.preserveAuxData();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
; RUN: llvm-as %s -o %t.bc
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: most of these tests are copies from SPV_INTEL_function_pointers/* tests with -spirv-emit-function-ptr-addr-space option added in reverse translation to check if addrspace(9) is generated. The only exception to this is function-pointer-dedicated-as.ll test

; RUN: llvm-spirv -spirv-ext=+SPV_INTEL_function_pointers -spirv-text %t.bc -o - | FileCheck %s --check-prefix=CHECK-SPIRV
; RUN: llvm-spirv -spirv-ext=+SPV_INTEL_function_pointers %t.bc -o %t.spv
; RUN: llvm-spirv -r -spirv-emit-function-ptr-addr-space %t.spv -o - | llvm-dis -o - | FileCheck %s --check-prefix=CHECK-LLVM

target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
target triple = "spir64-unknown-unknown"

; Check that aliases are dereferenced and translated to their aliasee values
; when used since they can't be translated directly.

; CHECK-SPIRV-DAG: Name [[#FOO:]] "foo"
; CHECK-SPIRV-DAG: Name [[#BAR:]] "bar"
; CHECK-SPIRV-DAG: Name [[#Y:]] "y"
; CHECK-SPIRV-DAG: Name [[#FOOPTR:]] "foo.alias"
; CHECK-SPIRV-DAG: Decorate [[#FOO]] LinkageAttributes "foo" Export
; CHECK-SPIRV-DAG: Decorate [[#BAR]] LinkageAttributes "bar" Export
; CHECK-SPIRV-DAG: TypeInt [[#I32:]] 32 0
; CHECK-SPIRV-DAG: TypeInt [[#I64:]] 64 0
; CHECK-SPIRV-DAG: TypeFunction [[#FOO_TYPE:]] [[#I32]] [[#I32]]
; CHECK-SPIRV-DAG: TypeVoid [[#VOID:]]
; CHECK-SPIRV-DAG: TypePointer [[#I64PTR:]] 7 [[#I64]]
; CHECK-SPIRV-DAG: TypeFunction [[#BAR_TYPE:]] [[#VOID]] [[#I64PTR]]
; CHECK-SPIRV-DAG: TypePointer [[#FOOPTR_TYPE:]] 7 [[#FOO_TYPE]]
; CHECK-SPIRV-DAG: ConstantFunctionPointerINTEL [[#FOOPTR_TYPE]] [[#FOOPTR]] [[#FOO]]

; CHECK-SPIRV: Function [[#I32]] [[#FOO]] 0 [[#FOO_TYPE]]

; CHECK-SPIRV: Function [[#VOID]] [[#BAR]] 0 [[#BAR_TYPE]]
; CHECK-SPIRV: FunctionParameter [[#I64PTR]] [[#Y]]
; CHECK-SPIRV: ConvertPtrToU [[#I64]] [[#PTRTOINT:]] [[#FOOPTR]]
; CHECK-SPIRV: Store [[#Y]] [[#PTRTOINT]] 2 8

; CHECK-LLVM: define spir_func i32 @foo(i32 %x) addrspace(9)

; CHECK-LLVM: define spir_kernel void @bar(ptr %y)
; CHECK-LLVM: [[PTRTOINT:%.*]] = ptrtoint ptr addrspace(9) @foo to i64
; CHECK-LLVM: store i64 [[PTRTOINT]], ptr %y, align 8

define spir_func i32 @foo(i32 %x) {
ret i32 %x
}

@foo.alias = internal alias i32 (i32), ptr @foo

define spir_kernel void @bar(ptr %y) {
store i64 ptrtoint (ptr @foo.alias to i64), ptr %y
ret void
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
; OpenCL C source:
; char foo(char a) {
; return a;
; }
; void bar() {
; int (*fun_ptr)(int) = &foo;
; fun_ptr(0);
; }

; RUN: llvm-as %s -o %t.bc
; RUN: llvm-spirv %t.bc -spirv-ext=+SPV_INTEL_function_pointers -o %t.spv
; RUN: llvm-spirv %t.spv -to-text -o %t.spt
; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV
; RUN: llvm-spirv -r -spirv-emit-function-ptr-addr-space %t.spv -o %t.r.bc
; RUN: llvm-dis %t.r.bc -o %t.r.ll
; RUN: FileCheck < %t.r.ll %s --check-prefix=CHECK-LLVM

; CHECK-SPIRV-DAG: TypeInt [[#I8:]] 8
; CHECK-SPIRV-DAG: TypeInt [[#I32:]] 32
; CHECK-SPIRV-DAG: TypeFunction [[#FOO_TY:]] [[#I8]] [[#I8]]
; CHECK-SPIRV-DAG: TypeFunction [[#DEST_TY:]] [[#I32]] [[#I32]]
; CHECK-SPIRV-DAG: TypePointer [[#DEST_TY_PTR:]] [[#]] [[#DEST_TY]]
; CHECK-SPIRV-DAG: TypePointer [[#FOO_TY_PTR:]] [[#]] [[#FOO_TY]]
; CHECK-SPIRV: ConstantFunctionPointerINTEL [[#FOO_TY_PTR]] [[#FOO_PTR:]] [[#FOO:]]
; CHECK-SPIRV: Function [[#]] [[#FOO]] [[#]] [[#FOO_TY]]

; CHECK-SPIRV: Bitcast [[#DEST_TY_PTR]] [[#]] [[#FOO_PTR]]

; CHECK-LLVM: bitcast ptr addrspace(9) @foo to ptr addrspace(9)

; ModuleID = './example.c'
source_filename = "./example.c"
target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
target triple = "spir"

; Function Attrs: noinline nounwind optnone
define dso_local spir_func signext i8 @foo(i8 signext %0) #0 {
ret i8 %0
}

; Function Attrs: noinline nounwind optnone
define dso_local spir_func void @bar() #0 {
%1 = call i32 @foo(i32 0)
ret void
}

attributes #0 = { noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.module.flags = !{!0}
!llvm.ident = !{!1}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git 0e1accd0f726eef2c47be9f37dd0a06cb50d207e)"}
Loading
Loading