Skip to content

Commit bb1bc6a

Browse files
MrSidimsjsji
authored andcommitted
Introduce CodeSectionINTEL storage class (#2728)
This storage class is used for function pointers. It's added as based on cl_intel_function_pointers specification, it is not guaranteed that sizeof(void(*)(void) == sizeof(void *) - to allow consumers use this fact, we cannot say that function pointer belongs to the same storage class as data pointers. It wasn't added during initial implementation, now it's time to fill this gap. As it would be a breaking change its generation is added only under -spirv-emit-function-ptr-addr-space option. Also SPIR-V consumer may pass this option during reverse translation to get new address space even in a case, when OpConstantFunctionPointerINTEL doesn't reside in CodeSectionINTEL storage class. Expected behavior: No option is passed to the forward translation stage and function pointers are in addrspace(9): no CodeSectionINTEL storage class in SPIR-V The option is passed to the forward translation stage and function pointers are in addrepace(9): CodeSectionINTEL storage class is generated No option is passed to the reverse translation stage: function pointers are in private address space The option is passed to the reverse translation stage: function pointers are in addrspace(9) Spec: https://github.com/intel/llvm/blob/sycl/sycl/doc/design/spirv-extensions/SPV_INTEL_function_pointers.asciidoc The previous approach: #1392 Original commit: KhronosGroup/SPIRV-LLVM-Translator@46c9eb9ea9b4c6f
1 parent cb24494 commit bb1bc6a

24 files changed

+1362
-7
lines changed

llvm-spirv/include/LLVMSPIRVOpts.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,14 @@ class TranslatorOpts {
236236
PreserveOCLKernelArgTypeMetadataThroughString = Value;
237237
}
238238

239+
bool shouldEmitFunctionPtrAddrSpace() const noexcept {
240+
return EmitFunctionPtrAddrSpace;
241+
}
242+
243+
void setEmitFunctionPtrAddrSpace(bool Value) noexcept {
244+
EmitFunctionPtrAddrSpace = Value;
245+
}
246+
239247
void setBuiltinFormat(BuiltinFormat Value) noexcept {
240248
SPIRVBuiltinFormat = Value;
241249
}
@@ -287,6 +295,10 @@ class TranslatorOpts {
287295
// kernel_arg_type_qual metadata through OpString
288296
bool PreserveOCLKernelArgTypeMetadataThroughString = false;
289297

298+
// Controls if CodeSectionINTEL can be emitted and consumed with a dedicated
299+
// address space
300+
bool EmitFunctionPtrAddrSpace = false;
301+
290302
bool PreserveAuxData = false;
291303

292304
BuiltinFormat SPIRVBuiltinFormat = BuiltinFormat::Function;

llvm-spirv/lib/SPIRV/SPIRVInternal.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ enum SPIRAddressSpace {
189189
SPIRAS_GlobalHost,
190190
SPIRAS_Input,
191191
SPIRAS_Output,
192+
SPIRAS_CodeSectionINTEL,
192193
SPIRAS_Count,
193194
};
194195

@@ -199,6 +200,8 @@ template <> inline void SPIRVMap<SPIRAddressSpace, std::string>::init() {
199200
add(SPIRAS_Local, "Local");
200201
add(SPIRAS_Generic, "Generic");
201202
add(SPIRAS_Input, "Input");
203+
add(SPIRAS_CodeSectionINTEL, "CodeSectionINTEL");
204+
202205
add(SPIRAS_GlobalDevice, "GlobalDevice");
203206
add(SPIRAS_GlobalHost, "GlobalHost");
204207
}
@@ -215,6 +218,7 @@ inline void SPIRVMap<SPIRAddressSpace, SPIRVStorageClassKind>::init() {
215218
add(SPIRAS_Input, StorageClassInput);
216219
add(SPIRAS_GlobalDevice, StorageClassDeviceOnlyINTEL);
217220
add(SPIRAS_GlobalHost, StorageClassHostOnlyINTEL);
221+
add(SPIRAS_CodeSectionINTEL, StorageClassCodeSectionINTEL);
218222
}
219223
typedef SPIRVMap<SPIRAddressSpace, SPIRVStorageClassKind> SPIRSPIRVAddrSpaceMap;
220224

llvm-spirv/lib/SPIRV/SPIRVReader.cpp

Lines changed: 94 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -350,16 +350,21 @@ Type *SPIRVToLLVM::transType(SPIRVType *T, bool UseTPT) {
350350
case internal::OpTypeTokenINTEL:
351351
return mapType(T, Type::getTokenTy(*Context));
352352
case OpTypePointer: {
353-
const unsigned AS =
354-
SPIRSPIRVAddrSpaceMap::rmap(T->getPointerStorageClass());
353+
unsigned AS = SPIRSPIRVAddrSpaceMap::rmap(T->getPointerStorageClass());
354+
if (AS == SPIRAS_CodeSectionINTEL && !BM->shouldEmitFunctionPtrAddrSpace())
355+
AS = SPIRAS_Private;
356+
if (BM->shouldEmitFunctionPtrAddrSpace() &&
357+
T->getPointerElementType()->getOpCode() == OpTypeFunction)
358+
AS = SPIRAS_CodeSectionINTEL;
355359
Type *ElementTy = transType(T->getPointerElementType(), UseTPT);
356360
if (UseTPT)
357361
return TypedPointerType::get(ElementTy, AS);
358362
return mapType(T, PointerType::get(ElementTy, AS));
359363
}
360364
case OpTypeUntypedPointerKHR: {
361-
const unsigned AS =
362-
SPIRSPIRVAddrSpaceMap::rmap(T->getPointerStorageClass());
365+
unsigned AS = SPIRSPIRVAddrSpaceMap::rmap(T->getPointerStorageClass());
366+
if (AS == SPIRAS_CodeSectionINTEL && !BM->shouldEmitFunctionPtrAddrSpace())
367+
AS = SPIRAS_Private;
363368
return mapType(T, PointerType::get(*Context, AS));
364369
}
365370
case OpTypeVector:
@@ -1471,6 +1476,17 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
14711476
case OpTypeMatrix:
14721477
case OpTypeArray: {
14731478
auto *AT = cast<ArrayType>(transType(BCC->getType()));
1479+
for (size_t I = 0; I != AT->getNumElements(); ++I) {
1480+
auto *ElemTy = AT->getElementType();
1481+
if (auto *ElemPtrTy = dyn_cast<PointerType>(ElemTy)) {
1482+
assert(isa<PointerType>(CV[I]->getType()) &&
1483+
"Constant type doesn't match constexpr array element type");
1484+
if (ElemPtrTy->getAddressSpace() !=
1485+
cast<PointerType>(CV[I]->getType())->getAddressSpace())
1486+
CV[I] = ConstantExpr::getAddrSpaceCast(CV[I], AT->getElementType());
1487+
}
1488+
}
1489+
14741490
return mapValue(BV, ConstantArray::get(AT, CV));
14751491
}
14761492
case OpTypeStruct: {
@@ -1487,7 +1503,12 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
14871503
!BCCTy->getElementType(I)->isPointerTy())
14881504
continue;
14891505

1490-
CV[I] = ConstantExpr::getBitCast(CV[I], BCCTy->getElementType(I));
1506+
if (cast<PointerType>(CV[I]->getType())->getAddressSpace() !=
1507+
cast<PointerType>(BCCTy->getElementType(I))->getAddressSpace())
1508+
CV[I] =
1509+
ConstantExpr::getAddrSpaceCast(CV[I], BCCTy->getElementType(I));
1510+
else
1511+
CV[I] = ConstantExpr::getBitCast(CV[I], BCCTy->getElementType(I));
14911512
}
14921513
}
14931514

@@ -1523,7 +1544,10 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
15231544
static_cast<SPIRVConstantFunctionPointerINTEL *>(BV);
15241545
SPIRVFunction *F = BC->getFunction();
15251546
BV->setName(F->getName());
1526-
return mapValue(BV, transFunction(F));
1547+
const unsigned AS = BM->shouldEmitFunctionPtrAddrSpace()
1548+
? SPIRAS_CodeSectionINTEL
1549+
: SPIRAS_Private;
1550+
return mapValue(BV, transFunction(F, AS));
15271551
}
15281552

15291553
case OpUndef:
@@ -2997,6 +3021,58 @@ bool SPIRVToLLVM::foreachFuncCtlMask(SourceTy Source, FuncTy Func) {
29973021
return true;
29983022
}
29993023

3024+
void SPIRVToLLVM::transFunctionAttrs(SPIRVFunction *BF, Function *F) {
3025+
if (BF->hasDecorate(DecorationReferencedIndirectlyINTEL))
3026+
F->addFnAttr("referenced-indirectly");
3027+
if (isFuncNoUnwind())
3028+
F->addFnAttr(Attribute::NoUnwind);
3029+
foreachFuncCtlMask(BF, [&](Attribute::AttrKind Attr) { F->addFnAttr(Attr); });
3030+
3031+
for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E;
3032+
++I) {
3033+
auto *BA = BF->getArgument(I->getArgNo());
3034+
mapValue(BA, &(*I));
3035+
setName(&(*I), BA);
3036+
AttributeMask IllegalAttrs = AttributeFuncs::typeIncompatible(I->getType());
3037+
BA->foreachAttr([&](SPIRVFuncParamAttrKind Kind) {
3038+
// Skip this function parameter attribute as it will translated among
3039+
// OpenCL metadata
3040+
if (Kind == FunctionParameterAttributeRuntimeAlignedINTEL)
3041+
return;
3042+
Attribute::AttrKind LLVMKind = SPIRSPIRVFuncParamAttrMap::rmap(Kind);
3043+
if (IllegalAttrs.contains(LLVMKind))
3044+
return;
3045+
Type *AttrTy = nullptr;
3046+
switch (LLVMKind) {
3047+
case Attribute::AttrKind::ByVal:
3048+
case Attribute::AttrKind::StructRet:
3049+
AttrTy = transType(BA->getType()->getPointerElementType());
3050+
break;
3051+
default:
3052+
break; // do nothing
3053+
}
3054+
// Make sure to use a correct constructor for a typed/typeless attribute
3055+
auto A = AttrTy ? Attribute::get(*Context, LLVMKind, AttrTy)
3056+
: Attribute::get(*Context, LLVMKind);
3057+
I->addAttr(A);
3058+
});
3059+
3060+
AttrBuilder Builder(*Context);
3061+
SPIRVWord MaxOffset = 0;
3062+
if (BA->hasDecorate(DecorationMaxByteOffset, 0, &MaxOffset))
3063+
Builder.addDereferenceableAttr(MaxOffset);
3064+
SPIRVWord AlignmentBytes = 0;
3065+
if (BA->hasDecorate(DecorationAlignment, 0, &AlignmentBytes))
3066+
Builder.addAlignmentAttr(AlignmentBytes);
3067+
I->addAttrs(Builder);
3068+
}
3069+
BF->foreachReturnValueAttr([&](SPIRVFuncParamAttrKind Kind) {
3070+
if (Kind == FunctionParameterAttributeNoWrite)
3071+
return;
3072+
F->addRetAttr(SPIRSPIRVFuncParamAttrMap::rmap(Kind));
3073+
});
3074+
}
3075+
30003076
Function *SPIRVToLLVM::transFunction(SPIRVFunction *BF) {
30013077
auto Loc = FuncMap.find(BF);
30023078
if (Loc != FuncMap.end())
@@ -3026,7 +3102,7 @@ Function *SPIRVToLLVM::transFunction(SPIRVFunction *BF) {
30263102
}
30273103
Function *F = M->getFunction(FuncName);
30283104
if (!F)
3029-
F = Function::Create(FT, Linkage, FuncName, M);
3105+
F = Function::Create(FT, Linkage, AS, FuncName, M);
30303106
F = cast<Function>(mapValue(BF, F));
30313107
mapFunction(BF, F);
30323108

@@ -3481,6 +3557,17 @@ bool SPIRVToLLVM::translate() {
34813557
DbgTran->transDebugInst(EI);
34823558
}
34833559

3560+
for (auto *FP : BM->getFunctionPointers()) {
3561+
SPIRVConstantFunctionPointerINTEL *BC =
3562+
static_cast<SPIRVConstantFunctionPointerINTEL *>(FP);
3563+
SPIRVFunction *F = BC->getFunction();
3564+
FP->setName(F->getName());
3565+
const unsigned AS = BM->shouldEmitFunctionPtrAddrSpace()
3566+
? SPIRAS_CodeSectionINTEL
3567+
: SPIRAS_Private;
3568+
mapValue(FP, transFunction(F, AS));
3569+
}
3570+
34843571
for (unsigned I = 0, E = BM->getNumFunctions(); I != E; ++I) {
34853572
transFunction(BM->getFunction(I));
34863573
transUserSemantic(BM->getFunction(I));

llvm-spirv/lib/SPIRV/SPIRVReader.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ class SPIRVToLLVM : private BuiltinCallHelper {
104104
std::vector<Value *> transValue(const std::vector<SPIRVValue *> &,
105105
Function *F, BasicBlock *);
106106
Function *transFunction(SPIRVFunction *F);
107+
void transFunctionAttrs(SPIRVFunction *BF, Function *F);
107108
Value *transBlockInvoke(SPIRVValue *Invoke, BasicBlock *BB);
108109
Instruction *transWGSizeQueryBI(SPIRVInstruction *BI, BasicBlock *BB);
109110
Instruction *transSGSizeQueryBI(SPIRVInstruction *BI, BasicBlock *BB);

llvm-spirv/lib/SPIRV/SPIRVWriter.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,11 @@ SPIRVType *LLVMToSPIRVBase::transPointerType(Type *ET, unsigned AddrSpc) {
659659
((AddrSpc == SPIRAS_GlobalDevice) || (AddrSpc == SPIRAS_GlobalHost))) {
660660
return transPointerType(ET, SPIRAS_Global);
661661
}
662+
// Lower function pointer address space to private if
663+
// spirv-emit-function-ptr-addr-space is not passed
664+
if (AddrSpc == SPIRAS_CodeSectionINTEL &&
665+
!BM->shouldEmitFunctionPtrAddrSpace())
666+
return transPointerType(ET, SPIRAS_Private);
662667
if (ST && !ST->isSized()) {
663668
Op OpCode;
664669
StringRef STName = ST->getName();
@@ -754,6 +759,9 @@ SPIRVType *LLVMToSPIRVBase::transPointerType(SPIRVType *ET, unsigned AddrSpc) {
754759
return Loc->second;
755760

756761
SPIRVType *TranslatedTy = nullptr;
762+
if (AddrSpc == SPIRAS_CodeSectionINTEL &&
763+
!BM->shouldEmitFunctionPtrAddrSpace())
764+
return transPointerType(ET, SPIRAS_Private);
757765
if (BM->isAllowedToUseExtension(ExtensionID::SPV_KHR_untyped_pointers) &&
758766
!(ET->isTypeArray() || ET->isTypeVector() || ET->isTypeStruct() ||
759767
ET->isTypeImage() || ET->isTypeSampler() || ET->isTypePipe())) {

llvm-spirv/lib/SPIRV/libSPIRV/SPIRVInstruction.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,11 @@ SPIRVInstruction *createInstFromSpecConstantOp(SPIRVSpecConstantOp *Inst) {
282282
auto OC = static_cast<Op>(Ops[0]);
283283
assert(isSpecConstantOpAllowedOp(OC) &&
284284
"Op code not allowed for OpSpecConstantOp");
285+
auto *Const = Inst->getOperand(1);
286+
// LLVM would eliminate a bitcast from a function pointer in a constexpr
287+
// context. Cut this short here to avoid necessity to align address spaces
288+
if (OC == OpBitcast && Const->getOpCode() == OpConstantFunctionPointerINTEL)
289+
return static_cast<SPIRVInstruction *>(Const);
285290
Ops.erase(Ops.begin(), Ops.begin() + 1);
286291
auto *BM = Inst->getModule();
287292
auto *RetInst = SPIRVInstTemplateBase::create(

llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,13 @@ class SPIRVModuleImpl : public SPIRVModule {
142142
SPIRVConstant *getLiteralAsConstant(unsigned Literal) override;
143143
unsigned getNumFunctions() const override { return FuncVec.size(); }
144144
unsigned getNumVariables() const override { return VariableVec.size(); }
145+
std::vector<SPIRVValue *> getFunctionPointers() const override {
146+
std::vector<SPIRVValue *> Res;
147+
for (auto *C : ConstVec)
148+
if (C->getOpCode() == OpConstantFunctionPointerINTEL)
149+
Res.emplace_back(C);
150+
return Res;
151+
}
145152
SourceLanguage getSourceLanguage(SPIRVWord *Ver = nullptr) const override {
146153
if (Ver)
147154
*Ver = SrcLangVer;

llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ class SPIRVModule {
142142
virtual SPIRVMemoryModelKind getMemoryModel() const = 0;
143143
virtual unsigned getNumFunctions() const = 0;
144144
virtual unsigned getNumVariables() const = 0;
145+
virtual std::vector<SPIRVValue *> getFunctionPointers() const = 0;
145146
virtual SourceLanguage getSourceLanguage(SPIRVWord *) const = 0;
146147
virtual std::set<std::string> &getSourceExtension() = 0;
147148
virtual SPIRVValue *getValue(SPIRVId TheId) const = 0;
@@ -554,6 +555,10 @@ class SPIRVModule {
554555
.shouldPreserveOCLKernelArgTypeMetadataThroughString();
555556
}
556557

558+
bool shouldEmitFunctionPtrAddrSpace() const noexcept {
559+
return TranslationOpts.shouldEmitFunctionPtrAddrSpace();
560+
}
561+
557562
bool preserveAuxData() const noexcept {
558563
return TranslationOpts.preserveAuxData();
559564
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
; RUN: llvm-as %s -o %t.bc
2+
; RUN: llvm-spirv -spirv-ext=+SPV_INTEL_function_pointers -spirv-text %t.bc -o - | FileCheck %s --check-prefix=CHECK-SPIRV
3+
; RUN: llvm-spirv -spirv-ext=+SPV_INTEL_function_pointers %t.bc -o %t.spv
4+
; RUN: llvm-spirv -r -spirv-emit-function-ptr-addr-space %t.spv -o - | llvm-dis -o - | FileCheck %s --check-prefix=CHECK-LLVM
5+
6+
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
7+
target triple = "spir64-unknown-unknown"
8+
9+
; Check that aliases are dereferenced and translated to their aliasee values
10+
; when used since they can't be translated directly.
11+
12+
; CHECK-SPIRV-DAG: Name [[#FOO:]] "foo"
13+
; CHECK-SPIRV-DAG: Name [[#BAR:]] "bar"
14+
; CHECK-SPIRV-DAG: Name [[#Y:]] "y"
15+
; CHECK-SPIRV-DAG: Name [[#FOOPTR:]] "foo.alias"
16+
; CHECK-SPIRV-DAG: Decorate [[#FOO]] LinkageAttributes "foo" Export
17+
; CHECK-SPIRV-DAG: Decorate [[#BAR]] LinkageAttributes "bar" Export
18+
; CHECK-SPIRV-DAG: TypeInt [[#I32:]] 32 0
19+
; CHECK-SPIRV-DAG: TypeInt [[#I64:]] 64 0
20+
; CHECK-SPIRV-DAG: TypeFunction [[#FOO_TYPE:]] [[#I32]] [[#I32]]
21+
; CHECK-SPIRV-DAG: TypeVoid [[#VOID:]]
22+
; CHECK-SPIRV-DAG: TypePointer [[#I64PTR:]] 7 [[#I64]]
23+
; CHECK-SPIRV-DAG: TypeFunction [[#BAR_TYPE:]] [[#VOID]] [[#I64PTR]]
24+
; CHECK-SPIRV-DAG: TypePointer [[#FOOPTR_TYPE:]] 7 [[#FOO_TYPE]]
25+
; CHECK-SPIRV-DAG: ConstantFunctionPointerINTEL [[#FOOPTR_TYPE]] [[#FOOPTR]] [[#FOO]]
26+
27+
; CHECK-SPIRV: Function [[#I32]] [[#FOO]] 0 [[#FOO_TYPE]]
28+
29+
; CHECK-SPIRV: Function [[#VOID]] [[#BAR]] 0 [[#BAR_TYPE]]
30+
; CHECK-SPIRV: FunctionParameter [[#I64PTR]] [[#Y]]
31+
; CHECK-SPIRV: ConvertPtrToU [[#I64]] [[#PTRTOINT:]] [[#FOOPTR]]
32+
; CHECK-SPIRV: Store [[#Y]] [[#PTRTOINT]] 2 8
33+
34+
; CHECK-LLVM: define spir_func i32 @foo(i32 %x) addrspace(9)
35+
36+
; CHECK-LLVM: define spir_kernel void @bar(ptr %y)
37+
; CHECK-LLVM: [[PTRTOINT:%.*]] = ptrtoint ptr addrspace(9) @foo to i64
38+
; CHECK-LLVM: store i64 [[PTRTOINT]], ptr %y, align 8
39+
40+
define spir_func i32 @foo(i32 %x) {
41+
ret i32 %x
42+
}
43+
44+
@foo.alias = internal alias i32 (i32), ptr @foo
45+
46+
define spir_kernel void @bar(ptr %y) {
47+
store i64 ptrtoint (ptr @foo.alias to i64), ptr %y
48+
ret void
49+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
; OpenCL C source:
2+
; char foo(char a) {
3+
; return a;
4+
; }
5+
; void bar() {
6+
; int (*fun_ptr)(int) = &foo;
7+
; fun_ptr(0);
8+
; }
9+
10+
; RUN: llvm-as %s -o %t.bc
11+
; RUN: llvm-spirv %t.bc -spirv-ext=+SPV_INTEL_function_pointers -o %t.spv
12+
; RUN: llvm-spirv %t.spv -to-text -o %t.spt
13+
; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV
14+
; RUN: llvm-spirv -r -spirv-emit-function-ptr-addr-space %t.spv -o %t.r.bc
15+
; RUN: llvm-dis %t.r.bc -o %t.r.ll
16+
; RUN: FileCheck < %t.r.ll %s --check-prefix=CHECK-LLVM
17+
18+
; CHECK-SPIRV-DAG: TypeInt [[#I8:]] 8
19+
; CHECK-SPIRV-DAG: TypeInt [[#I32:]] 32
20+
; CHECK-SPIRV-DAG: TypeFunction [[#FOO_TY:]] [[#I8]] [[#I8]]
21+
; CHECK-SPIRV-DAG: TypeFunction [[#DEST_TY:]] [[#I32]] [[#I32]]
22+
; CHECK-SPIRV-DAG: TypePointer [[#DEST_TY_PTR:]] [[#]] [[#DEST_TY]]
23+
; CHECK-SPIRV-DAG: TypePointer [[#FOO_TY_PTR:]] [[#]] [[#FOO_TY]]
24+
; CHECK-SPIRV: ConstantFunctionPointerINTEL [[#FOO_TY_PTR]] [[#FOO_PTR:]] [[#FOO:]]
25+
; CHECK-SPIRV: Function [[#]] [[#FOO]] [[#]] [[#FOO_TY]]
26+
27+
; CHECK-SPIRV: Bitcast [[#DEST_TY_PTR]] [[#]] [[#FOO_PTR]]
28+
29+
; CHECK-LLVM: bitcast ptr addrspace(9) @foo to ptr addrspace(9)
30+
31+
; ModuleID = './example.c'
32+
source_filename = "./example.c"
33+
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"
34+
target triple = "spir"
35+
36+
; Function Attrs: noinline nounwind optnone
37+
define dso_local spir_func signext i8 @foo(i8 signext %0) #0 {
38+
ret i8 %0
39+
}
40+
41+
; Function Attrs: noinline nounwind optnone
42+
define dso_local spir_func void @bar() #0 {
43+
%1 = call i32 @foo(i32 0)
44+
ret void
45+
}
46+
47+
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" }
48+
49+
!llvm.module.flags = !{!0}
50+
!llvm.ident = !{!1}
51+
52+
!0 = !{i32 1, !"wchar_size", i32 4}
53+
!1 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git 0e1accd0f726eef2c47be9f37dd0a06cb50d207e)"}

0 commit comments

Comments
 (0)