Skip to content

Commit 2ed8ff3

Browse files
[SPIR-V] Fix types of internal intrinsic functions and add a test case for __builtin_alloca() (#92265)
This PR generation of argument types of internal intrinsic functions `spv_const_composite` and `spv_track_constant`, so that composite constants of ConstantVector type preserve their correct type in transformation passes and can be successfully used further by LLVM intrinsic functions. The added test case serves two purposes: it is to check the above mentioned fix and to demonstrate that a call to __builtin_alloca() maps to instructions from SPV_INTEL_variable_length_array when this extension is available.
1 parent b6fa78d commit 2ed8ff3

File tree

4 files changed

+93
-38
lines changed

4 files changed

+93
-38
lines changed

llvm/docs/SPIRVUsage.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ SPIR-V backend, along with their descriptions and argument details.
298298
- `[Type, Type, Any Integer]`
299299
- Inserts an element into an aggregate type at a specified index. Allows for building and modifying arrays and vectors.
300300
* - `int_spv_const_composite`
301-
- 32-bit Integer
301+
- Type
302302
- `[Vararg]`
303303
- Constructs a composite type from given elements. Key for creating arrays, structs, and vectors from individual components.
304304
* - `int_spv_bitcast`

llvm/include/llvm/IR/IntrinsicsSPIRV.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ let TargetPrefix = "spv" in {
2727
def int_spv_insertv : Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_any_ty, llvm_vararg_ty]>;
2828
def int_spv_extractelt : Intrinsic<[llvm_any_ty], [llvm_any_ty, llvm_anyint_ty]>;
2929
def int_spv_insertelt : Intrinsic<[llvm_any_ty], [llvm_any_ty, llvm_any_ty, llvm_anyint_ty]>;
30-
def int_spv_const_composite : Intrinsic<[llvm_i32_ty], [llvm_vararg_ty]>;
30+
def int_spv_const_composite : Intrinsic<[llvm_any_ty], [llvm_vararg_ty]>;
3131
def int_spv_bitcast : Intrinsic<[llvm_any_ty], [llvm_any_ty]>;
3232
def int_spv_ptrcast : Intrinsic<[llvm_any_ty], [llvm_any_ty, llvm_metadata_ty, llvm_i32_ty], [ImmArg<ArgIndex<2>>]>;
3333
def int_spv_switch : Intrinsic<[], [llvm_any_ty, llvm_vararg_ty]>;

llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp

Lines changed: 43 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,9 @@ static bool isMemInstrToReplace(Instruction *I) {
167167
isa<ExtractValueInst>(I) || isa<AtomicCmpXchgInst>(I);
168168
}
169169

170-
static bool isAggrToReplace(const Value *V) {
171-
return isa<ConstantAggregate>(V) || isa<ConstantDataArray>(V) ||
170+
static bool isAggrConstForceInt32(const Value *V) {
171+
return isa<ConstantArray>(V) || isa<ConstantStruct>(V) ||
172+
isa<ConstantDataArray>(V) ||
172173
(isa<ConstantAggregateZero>(V) && !V->getType()->isVectorTy());
173174
}
174175

@@ -576,36 +577,42 @@ void SPIRVEmitIntrinsics::preprocessCompositeConstants(IRBuilder<> &B) {
576577
assert(I);
577578
bool KeepInst = false;
578579
for (const auto &Op : I->operands()) {
579-
auto BuildCompositeIntrinsic =
580-
[](Constant *AggrC, ArrayRef<Value *> Args, Value *Op, Instruction *I,
581-
IRBuilder<> &B, std::queue<Instruction *> &Worklist,
582-
bool &KeepInst, SPIRVEmitIntrinsics &SEI) {
583-
B.SetInsertPoint(I);
584-
auto *CCI =
585-
B.CreateIntrinsic(Intrinsic::spv_const_composite, {}, {Args});
586-
Worklist.push(CCI);
587-
I->replaceUsesOfWith(Op, CCI);
588-
KeepInst = true;
589-
SEI.AggrConsts[CCI] = AggrC;
590-
SEI.AggrConstTypes[CCI] = SEI.deduceNestedTypeHelper(AggrC);
591-
};
592-
593-
if (auto *AggrC = dyn_cast<ConstantAggregate>(Op)) {
594-
SmallVector<Value *> Args(AggrC->op_begin(), AggrC->op_end());
595-
BuildCompositeIntrinsic(AggrC, Args, Op, I, B, Worklist, KeepInst,
596-
*this);
597-
} else if (auto *AggrC = dyn_cast<ConstantDataArray>(Op)) {
580+
Constant *AggrConst = nullptr;
581+
Type *ResTy = nullptr;
582+
if (auto *COp = dyn_cast<ConstantVector>(Op)) {
583+
AggrConst = cast<Constant>(COp);
584+
ResTy = COp->getType();
585+
} else if (auto *COp = dyn_cast<ConstantArray>(Op)) {
586+
AggrConst = cast<Constant>(COp);
587+
ResTy = B.getInt32Ty();
588+
} else if (auto *COp = dyn_cast<ConstantStruct>(Op)) {
589+
AggrConst = cast<Constant>(COp);
590+
ResTy = B.getInt32Ty();
591+
} else if (auto *COp = dyn_cast<ConstantDataArray>(Op)) {
592+
AggrConst = cast<Constant>(COp);
593+
ResTy = B.getInt32Ty();
594+
} else if (auto *COp = dyn_cast<ConstantAggregateZero>(Op)) {
595+
if (!Op->getType()->isVectorTy()) {
596+
AggrConst = cast<Constant>(COp);
597+
ResTy = B.getInt32Ty();
598+
}
599+
}
600+
if (AggrConst) {
598601
SmallVector<Value *> Args;
599-
for (unsigned i = 0; i < AggrC->getNumElements(); ++i)
600-
Args.push_back(AggrC->getElementAsConstant(i));
601-
BuildCompositeIntrinsic(AggrC, Args, Op, I, B, Worklist, KeepInst,
602-
*this);
603-
} else if (isa<ConstantAggregateZero>(Op) &&
604-
!Op->getType()->isVectorTy()) {
605-
auto *AggrC = cast<ConstantAggregateZero>(Op);
606-
SmallVector<Value *> Args(AggrC->op_begin(), AggrC->op_end());
607-
BuildCompositeIntrinsic(AggrC, Args, Op, I, B, Worklist, KeepInst,
608-
*this);
602+
if (auto *COp = dyn_cast<ConstantDataSequential>(Op))
603+
for (unsigned i = 0; i < COp->getNumElements(); ++i)
604+
Args.push_back(COp->getElementAsConstant(i));
605+
else
606+
for (auto &COp : AggrConst->operands())
607+
Args.push_back(COp);
608+
B.SetInsertPoint(I);
609+
auto *CI =
610+
B.CreateIntrinsic(Intrinsic::spv_const_composite, {ResTy}, {Args});
611+
Worklist.push(CI);
612+
I->replaceUsesOfWith(Op, CI);
613+
KeepInst = true;
614+
AggrConsts[CI] = AggrConst;
615+
AggrConstTypes[CI] = deduceNestedTypeHelper(AggrConst);
609616
}
610617
}
611618
if (!KeepInst)
@@ -1054,8 +1061,8 @@ void SPIRVEmitIntrinsics::processGlobalValue(GlobalVariable &GV,
10541061
// by llvm IR general logic.
10551062
deduceElementTypeHelper(&GV);
10561063
Constant *Init = GV.getInitializer();
1057-
Type *Ty = isAggrToReplace(Init) ? B.getInt32Ty() : Init->getType();
1058-
Constant *Const = isAggrToReplace(Init) ? B.getInt32(1) : Init;
1064+
Type *Ty = isAggrConstForceInt32(Init) ? B.getInt32Ty() : Init->getType();
1065+
Constant *Const = isAggrConstForceInt32(Init) ? B.getInt32(1) : Init;
10591066
auto *InitInst = B.CreateIntrinsic(Intrinsic::spv_init_global,
10601067
{GV.getType(), Ty}, {&GV, Const});
10611068
InitInst->setArgOperand(1, Init);
@@ -1132,11 +1139,11 @@ void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I,
11321139
if (II && II->getIntrinsicID() == Intrinsic::spv_const_composite &&
11331140
TrackConstants) {
11341141
B.SetInsertPoint(I->getNextNode());
1135-
Type *Ty = B.getInt32Ty();
11361142
auto t = AggrConsts.find(I);
11371143
assert(t != AggrConsts.end());
1138-
auto *NewOp = buildIntrWithMD(Intrinsic::spv_track_constant, {Ty, Ty},
1139-
t->second, I, {}, B);
1144+
auto *NewOp =
1145+
buildIntrWithMD(Intrinsic::spv_track_constant,
1146+
{II->getType(), II->getType()}, t->second, I, {}, B);
11401147
I->replaceAllUsesWith(NewOp);
11411148
NewOp->setArgOperand(0, I);
11421149
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
; The goal of the test is to:
2+
; 1) check that composite constants of ConstantVector type preserve their
3+
; type and can be successfully used further in LLVM intrinsic functions;
4+
; 2) demonstrate that a call to __builtin_alloca() maps to instructions
5+
; from SPV_INTEL_variable_length_array when this extension is available.
6+
7+
; Test LLVM IR is an artificial example, but it's similar to what can be
8+
; generated by DPC++ compiler from the code snippet:
9+
; ...
10+
; size_t Sz = ...;
11+
; queue Q;
12+
; Q.submit([&](sycl::handler &CGH) {
13+
; ...
14+
; CGH.single_task([=](sycl::kernel_handler KH) SYCL_ESIMD_KERNEL {
15+
; int *PrivateArray = (int *)__builtin_alloca(sizeof(int) * Sz);
16+
; ...
17+
; simd<int, 8> InitVec(100, 10);
18+
; InitVec.copy_to(PrivateArray);
19+
; ...
20+
; });
21+
; }).wait();
22+
; ...
23+
24+
; RUN: not llc -O0 -mtriple=spirv64-unknown-unknown %s -o %t.spvt 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
25+
26+
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_variable_length_array %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
27+
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_variable_length_array %s -o - -filetype=obj | spirv-val %}
28+
29+
; CHECK-ERROR: LLVM ERROR: array allocation: this instruction requires the following SPIR-V extension: SPV_INTEL_variable_length_array
30+
31+
; CHECK-SPIRV: Capability VariableLengthArrayINTEL
32+
; CHECK-SPIRV: Extension "SPV_INTEL_variable_length_array"
33+
; CHECK-SPIRV: OpVariableLengthArrayINTEL %[[#]] %[[#]]
34+
35+
define spir_kernel void @foo(i64 %_arg_sz) {
36+
entry:
37+
%sz = shl i64 %_arg_sz, 2
38+
%p1 = alloca i8, i64 %sz, align 8
39+
%p4 = addrspacecast ptr %p1 to ptr addrspace(4)
40+
%i = ptrtoint ptr addrspace(4) %p4 to i64
41+
%splat_ins = insertelement <8 x i64> poison, i64 %i, i64 0
42+
%splat_v = shufflevector <8 x i64> %splat_ins, <8 x i64> poison, <8 x i32> zeroinitializer
43+
%sum_r = add <8 x i64> %splat_v, <i64 0, i64 4, i64 8, i64 12, i64 16, i64 20, i64 24, i64 28>
44+
call void @llvm.genx.svm.scatter.v8i1.v8i64.v8i32(<8 x i1> <i1 true, i1 true, i1 true, i1 true, i1 true, i1 true, i1 true, i1 true>, i32 0, <8 x i64> %sum_r, <8 x i32> <i32 100, i32 110, i32 120, i32 130, i32 140, i32 150, i32 160, i32 170>)
45+
ret void
46+
}
47+
48+
declare void @llvm.genx.svm.scatter.v8i1.v8i64.v8i32(<8 x i1>, i32, <8 x i64>, <8 x i32>)

0 commit comments

Comments
 (0)