Skip to content

Commit 7fa45af

Browse files
[SPIR-V] Ensure that internal intrinsic functions are inserted at the correct positions (#93552)
The goal of the PR is to ensure that newly inserted internal intrinsic functions are inserted at the correct positions, and don't break rules of instruction domination and PHI nodes grouping at top of basic block. This is a continuation of #92316 and #92536
1 parent 1e44a96 commit 7fa45af

File tree

2 files changed

+71
-11
lines changed

2 files changed

+71
-11
lines changed

llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,14 @@ static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I) {
181181
B.SetInsertPoint(I);
182182
}
183183

184+
static void setInsertPointAfterDef(IRBuilder<> &B, Instruction *I) {
185+
B.SetCurrentDebugLocation(I->getDebugLoc());
186+
if (I->getType()->isVoidTy())
187+
B.SetInsertPoint(I->getNextNode());
188+
else
189+
B.SetInsertPoint(*I->getInsertionPointAfterDef());
190+
}
191+
184192
static bool requireAssignType(Instruction *I) {
185193
IntrinsicInst *Intr = dyn_cast<IntrinsicInst>(I);
186194
if (Intr) {
@@ -560,14 +568,18 @@ void SPIRVEmitIntrinsics::preprocessUndefs(IRBuilder<> &B) {
560568

561569
while (!Worklist.empty()) {
562570
Instruction *I = Worklist.front();
571+
bool BPrepared = false;
563572
Worklist.pop();
564573

565574
for (auto &Op : I->operands()) {
566575
auto *AggrUndef = dyn_cast<UndefValue>(Op);
567576
if (!AggrUndef || !Op->getType()->isAggregateType())
568577
continue;
569578

570-
B.SetInsertPoint(I);
579+
if (!BPrepared) {
580+
setInsertPointSkippingPhis(B, I);
581+
BPrepared = true;
582+
}
571583
auto *IntrUndef = B.CreateIntrinsic(Intrinsic::spv_undef, {}, {});
572584
Worklist.push(IntrUndef);
573585
I->replaceUsesOfWith(Op, IntrUndef);
@@ -584,6 +596,7 @@ void SPIRVEmitIntrinsics::preprocessCompositeConstants(IRBuilder<> &B) {
584596

585597
while (!Worklist.empty()) {
586598
auto *I = Worklist.front();
599+
bool IsPhi = isa<PHINode>(I), BPrepared = false;
587600
assert(I);
588601
bool KeepInst = false;
589602
for (const auto &Op : I->operands()) {
@@ -615,7 +628,11 @@ void SPIRVEmitIntrinsics::preprocessCompositeConstants(IRBuilder<> &B) {
615628
else
616629
for (auto &COp : AggrConst->operands())
617630
Args.push_back(COp);
618-
B.SetInsertPoint(I);
631+
if (!BPrepared) {
632+
IsPhi ? B.SetInsertPointPastAllocas(I->getParent()->getParent())
633+
: B.SetInsertPoint(I);
634+
BPrepared = true;
635+
}
619636
auto *CI =
620637
B.CreateIntrinsic(Intrinsic::spv_const_composite, {ResTy}, {Args});
621638
Worklist.push(CI);
@@ -1111,8 +1128,7 @@ void SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *I,
11111128
isa<BitCastInst>(I))
11121129
return;
11131130

1114-
setInsertPointSkippingPhis(B, I->getNextNode());
1115-
1131+
setInsertPointAfterDef(B, I);
11161132
Type *ElemTy = deduceElementType(I);
11171133
Constant *EltTyConst = UndefValue::get(ElemTy);
11181134
unsigned AddressSpace = getPointerAddressSpace(I->getType());
@@ -1127,7 +1143,7 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
11271143
reportFatalOnTokenType(I);
11281144
Type *Ty = I->getType();
11291145
if (!Ty->isVoidTy() && !isPointerTy(Ty) && requireAssignType(I)) {
1130-
setInsertPointSkippingPhis(B, I->getNextNode());
1146+
setInsertPointAfterDef(B, I);
11311147
Type *TypeToAssign = Ty;
11321148
if (auto *II = dyn_cast<IntrinsicInst>(I)) {
11331149
if (II->getIntrinsicID() == Intrinsic::spv_const_composite ||
@@ -1149,7 +1165,7 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
11491165
if (isa<UndefValue>(Op) && Op->getType()->isAggregateType())
11501166
buildIntrWithMD(Intrinsic::spv_assign_type, {B.getInt32Ty()}, Op,
11511167
UndefValue::get(B.getInt32Ty()), {}, B);
1152-
else if (!isa<Instruction>(Op)) // TODO: This case could be removed
1168+
else if (!isa<Instruction>(Op))
11531169
buildIntrWithMD(Intrinsic::spv_assign_type, {Op->getType()}, Op, Op, {},
11541170
B);
11551171
}
@@ -1159,7 +1175,7 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
11591175
void SPIRVEmitIntrinsics::insertSpirvDecorations(Instruction *I,
11601176
IRBuilder<> &B) {
11611177
if (MDNode *MD = I->getMetadata("spirv.Decorations")) {
1162-
B.SetInsertPoint(I->getNextNode());
1178+
setInsertPointAfterDef(B, I);
11631179
B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {I->getType()},
11641180
{I, MetadataAsValue::get(I->getContext(), MD)});
11651181
}
@@ -1170,7 +1186,7 @@ void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I,
11701186
auto *II = dyn_cast<IntrinsicInst>(I);
11711187
if (II && II->getIntrinsicID() == Intrinsic::spv_const_composite &&
11721188
TrackConstants) {
1173-
B.SetInsertPoint(I->getNextNode());
1189+
setInsertPointAfterDef(B, I);
11741190
auto t = AggrConsts.find(I);
11751191
assert(t != AggrConsts.end());
11761192
auto *NewOp =
@@ -1179,6 +1195,7 @@ void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I,
11791195
I->replaceAllUsesWith(NewOp);
11801196
NewOp->setArgOperand(0, I);
11811197
}
1198+
bool IsPhi = isa<PHINode>(I), BPrepared = false;
11821199
for (const auto &Op : I->operands()) {
11831200
if ((isa<ConstantAggregateZero>(Op) && Op->getType()->isVectorTy()) ||
11841201
isa<PHINode>(I) || isa<SwitchInst>(I))
@@ -1188,7 +1205,11 @@ void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I,
11881205
if (II && ((II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
11891206
(II->paramHasAttr(OpNo, Attribute::ImmArg))))
11901207
continue;
1191-
B.SetInsertPoint(I);
1208+
if (!BPrepared) {
1209+
IsPhi ? B.SetInsertPointPastAllocas(I->getParent()->getParent())
1210+
: B.SetInsertPoint(I);
1211+
BPrepared = true;
1212+
}
11921213
Value *OpTyVal = Op;
11931214
if (Op->getType()->isTargetExtTy())
11941215
OpTyVal = Constant::getNullValue(
@@ -1201,7 +1222,7 @@ void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I,
12011222
}
12021223
if (I->hasName()) {
12031224
reportFatalOnTokenType(I);
1204-
setInsertPointSkippingPhis(B, I->getNextNode());
1225+
setInsertPointAfterDef(B, I);
12051226
std::vector<Value *> Args = {I};
12061227
addStringImm(I->getName(), B, Args);
12071228
B.CreateIntrinsic(Intrinsic::spv_assign_name, {I->getType()}, Args);
@@ -1345,7 +1366,7 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
13451366
for (auto *I : Worklist) {
13461367
TrackConstants = true;
13471368
if (!I->getType()->isVoidTy() || isa<StoreInst>(I))
1348-
B.SetInsertPoint(I->getNextNode());
1369+
setInsertPointAfterDef(B, I);
13491370
// Visitors return either the original/newly created instruction for further
13501371
// processing, nullptr otherwise.
13511372
I = visit(*I);
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
; The goal of the test is to check that newly inserted internal (spv)
2+
; intrinsic functions for PHI's operands are inserted at the correct
3+
; positions, and don't break rules of instruction domination and PHI nodes
4+
; grouping at top of basic block.
5+
6+
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
7+
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
8+
9+
; CHECK: OpFunction
10+
; CHECK: OpBranch
11+
; CHECK: OpLabel
12+
; CHECK: OpPhi
13+
; CHECK: OpPhi
14+
; CHECK: OpPhi
15+
16+
define spir_kernel void @foo(ptr addrspace(1) %_arg1) {
17+
entry:
18+
br label %l1
19+
20+
l1:
21+
%sw = phi <4 x double> [ %vec, %l2 ], [ <double 0.0, double 0.0, double 0.0, double poison>, %entry ]
22+
%in = phi <3 x double> [ %ins, %l2 ], [ zeroinitializer, %entry ]
23+
%r1 = phi i32 [ %r2, %l2 ], [ 0, %entry ]
24+
%c1 = icmp ult i32 %r1, 3
25+
br i1 %c1, label %l2, label %exit
26+
27+
l2:
28+
%r3 = zext nneg i32 %r1 to i64
29+
%r4 = getelementptr inbounds double, ptr addrspace(1) %_arg1, i64 %r3
30+
%r5 = load double, ptr addrspace(1) %r4, align 8
31+
%ins = insertelement <3 x double> %in, double %r5, i32 %r1
32+
%exp = shufflevector <3 x double> %ins, <3 x double> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 poison>
33+
%vec = shufflevector <4 x double> %exp, <4 x double> %sw, <4 x i32> <i32 0, i32 1, i32 2, i32 7>
34+
%r2 = add nuw nsw i32 %r1, 1
35+
br label %l1
36+
37+
exit:
38+
ret void
39+
}

0 commit comments

Comments
 (0)