Skip to content

Commit 3c90812

Browse files
[IROutliner] Avoid reusing PHINodes that have already been matched when merging outlined functions' phi node blocks
When there are two external phi nodes for two different outlined regions, when compressing the created phi nodes between the two regions, the matching for the second phi node in the second region matches the first phi node created for the first region rather than the second phi node created for the first region. This adds an extra output path where there should not be one. The fix is the ignore phi nodes that have already been matched for each region. Reviewer: paquette Differential Revision: https://reviews.llvm.org/D121312
1 parent 5fc70e5 commit 3c90812

File tree

2 files changed

+132
-5
lines changed

2 files changed

+132
-5
lines changed

llvm/lib/Transforms/IPO/IROutliner.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,11 +1559,14 @@ findCanonNumsForPHI(PHINode *PN, OutlinableRegion &Region,
15591559
/// \p PN in.
15601560
/// \param OutputMappings [in] - The mapping of output values from outlined
15611561
/// region to their original values.
1562+
/// \param UsedPhis [in, out] - The PHINodes in the block that have already been
1563+
/// matched.
15621564
/// \return the newly found or created PHINode in \p OverallPhiBlock.
15631565
static PHINode*
15641566
findOrCreatePHIInBlock(PHINode &PN, OutlinableRegion &Region,
15651567
BasicBlock *OverallPhiBlock,
1566-
const DenseMap<Value *, Value *> &OutputMappings) {
1568+
const DenseMap<Value *, Value *> &OutputMappings,
1569+
DenseSet<PHINode *> &UsedPHIs) {
15671570
OutlinableGroup &Group = *Region.Parent;
15681571

15691572
DenseSet<unsigned> PNCanonNums;
@@ -1579,14 +1582,20 @@ findOrCreatePHIInBlock(PHINode &PN, OutlinableRegion &Region,
15791582
// Find the Canonical Numbering for each PHINode, if it matches, we replace
15801583
// the uses of the PHINode we are searching for, with the found PHINode.
15811584
for (PHINode &CurrPN : OverallPhiBlock->phis()) {
1585+
// If this PHINode has already been matched to another PHINode to be merged,
1586+
// we skip it.
1587+
if (UsedPHIs.find(&CurrPN) != UsedPHIs.end())
1588+
continue;
1589+
15821590
CurrentCanonNums.clear();
15831591
findCanonNumsForPHI(&CurrPN, *FirstRegion, OutputMappings, CurrentCanonNums,
15841592
/* ReplacedWithOutlinedCall = */ true);
1585-
15861593
if (all_of(PNCanonNums, [&CurrentCanonNums](unsigned CanonNum) {
15871594
return CurrentCanonNums.contains(CanonNum);
1588-
}))
1595+
})) {
1596+
UsedPHIs.insert(&CurrPN);
15891597
return &CurrPN;
1598+
}
15901599
}
15911600

15921601
// If we've made it here, it means we weren't able to replace the PHINode, so
@@ -1646,6 +1655,7 @@ replaceArgumentUses(OutlinableRegion &Region,
16461655
if (FirstFunction)
16471656
DominatingFunction = Group.OutlinedFunction;
16481657
DominatorTree DT(*DominatingFunction);
1658+
DenseSet<PHINode *> UsedPHIs;
16491659

16501660
for (unsigned ArgIdx = 0; ArgIdx < Region.ExtractedFunction->arg_size();
16511661
ArgIdx++) {
@@ -1745,8 +1755,8 @@ replaceArgumentUses(OutlinableRegion &Region,
17451755
// For our PHINode, we find the combined canonical numbering, and
17461756
// attempt to find a matching PHINode in the overall PHIBlock. If we
17471757
// cannot, we copy the PHINode and move it into this new block.
1748-
PHINode *NewPN =
1749-
findOrCreatePHIInBlock(*PN, Region, OverallPhiBlock, OutputMappings);
1758+
PHINode *NewPN = findOrCreatePHIInBlock(*PN, Region, OverallPhiBlock,
1759+
OutputMappings, UsedPHIs);
17501760
NewI->setOperand(0, NewPN);
17511761
}
17521762

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs
2+
; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
3+
4+
; Make sure that when we merge phi nodes, we do not merge two different PHINodes
5+
; as the same phi node.
6+
7+
define void @f1() {
8+
bb1:
9+
%0 = add i32 1, 2
10+
%1 = add i32 3, 4
11+
%2 = add i32 5, 6
12+
%3 = add i32 7, 8
13+
br label %bb5
14+
bb2:
15+
%4 = mul i32 5, 4
16+
br label %bb5
17+
18+
placeholder:
19+
%a = sub i32 5, 4
20+
ret void
21+
22+
bb5:
23+
%phinode = phi i32 [5, %bb1], [5, %bb2]
24+
%phinode1 = phi i32 [5, %bb1], [5, %bb2]
25+
ret void
26+
}
27+
28+
define void @f2() {
29+
bb1:
30+
%0 = add i32 1, 2
31+
%1 = add i32 3, 4
32+
%2 = add i32 5, 6
33+
%3 = add i32 7, 8
34+
br label %bb5
35+
bb2:
36+
%4 = mul i32 5, 4
37+
br label %bb5
38+
39+
placeholder:
40+
%a = sub i32 5, 4
41+
ret void
42+
43+
bb5:
44+
%phinode = phi i32 [5, %bb1], [5, %bb2]
45+
%phinode1 = phi i32 [5, %bb1], [5, %bb2]
46+
ret void
47+
}
48+
; CHECK-LABEL: @f1(
49+
; CHECK-NEXT: bb1:
50+
; CHECK-NEXT: [[PHINODE1_CE_LOC:%.*]] = alloca i32, align 4
51+
; CHECK-NEXT: [[PHINODE_CE_LOC:%.*]] = alloca i32, align 4
52+
; CHECK-NEXT: [[LT_CAST:%.*]] = bitcast i32* [[PHINODE_CE_LOC]] to i8*
53+
; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 -1, i8* [[LT_CAST]])
54+
; CHECK-NEXT: [[LT_CAST1:%.*]] = bitcast i32* [[PHINODE1_CE_LOC]] to i8*
55+
; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 -1, i8* [[LT_CAST1]])
56+
; CHECK-NEXT: [[TARGETBLOCK:%.*]] = call i1 @outlined_ir_func_0(i32* [[PHINODE_CE_LOC]], i32* [[PHINODE1_CE_LOC]])
57+
; CHECK-NEXT: [[PHINODE_CE_RELOAD:%.*]] = load i32, i32* [[PHINODE_CE_LOC]], align 4
58+
; CHECK-NEXT: [[PHINODE1_CE_RELOAD:%.*]] = load i32, i32* [[PHINODE1_CE_LOC]], align 4
59+
; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 -1, i8* [[LT_CAST]])
60+
; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 -1, i8* [[LT_CAST1]])
61+
; CHECK-NEXT: br i1 [[TARGETBLOCK]], label [[BB5:%.*]], label [[BB1_AFTER_OUTLINE:%.*]]
62+
; CHECK: bb1_after_outline:
63+
; CHECK-NEXT: ret void
64+
; CHECK: bb5:
65+
; CHECK-NEXT: [[PHINODE:%.*]] = phi i32 [ [[PHINODE_CE_RELOAD]], [[BB1:%.*]] ]
66+
; CHECK-NEXT: [[PHINODE1:%.*]] = phi i32 [ [[PHINODE1_CE_RELOAD]], [[BB1]] ]
67+
; CHECK-NEXT: ret void
68+
;
69+
;
70+
; CHECK-LABEL: @f2(
71+
; CHECK-NEXT: bb1:
72+
; CHECK-NEXT: [[PHINODE1_CE_LOC:%.*]] = alloca i32, align 4
73+
; CHECK-NEXT: [[PHINODE_CE_LOC:%.*]] = alloca i32, align 4
74+
; CHECK-NEXT: [[LT_CAST:%.*]] = bitcast i32* [[PHINODE_CE_LOC]] to i8*
75+
; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 -1, i8* [[LT_CAST]])
76+
; CHECK-NEXT: [[LT_CAST1:%.*]] = bitcast i32* [[PHINODE1_CE_LOC]] to i8*
77+
; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 -1, i8* [[LT_CAST1]])
78+
; CHECK-NEXT: [[TARGETBLOCK:%.*]] = call i1 @outlined_ir_func_0(i32* [[PHINODE_CE_LOC]], i32* [[PHINODE1_CE_LOC]])
79+
; CHECK-NEXT: [[PHINODE_CE_RELOAD:%.*]] = load i32, i32* [[PHINODE_CE_LOC]], align 4
80+
; CHECK-NEXT: [[PHINODE1_CE_RELOAD:%.*]] = load i32, i32* [[PHINODE1_CE_LOC]], align 4
81+
; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 -1, i8* [[LT_CAST]])
82+
; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 -1, i8* [[LT_CAST1]])
83+
; CHECK-NEXT: br i1 [[TARGETBLOCK]], label [[BB5:%.*]], label [[BB1_AFTER_OUTLINE:%.*]]
84+
; CHECK: bb1_after_outline:
85+
; CHECK-NEXT: ret void
86+
; CHECK: bb5:
87+
; CHECK-NEXT: [[PHINODE:%.*]] = phi i32 [ [[PHINODE_CE_RELOAD]], [[BB1:%.*]] ]
88+
; CHECK-NEXT: [[PHINODE1:%.*]] = phi i32 [ [[PHINODE1_CE_RELOAD]], [[BB1]] ]
89+
; CHECK-NEXT: ret void
90+
;
91+
;
92+
; CHECK-LABEL: define internal i1 @outlined_ir_func_0(
93+
; CHECK-NEXT: newFuncRoot:
94+
; CHECK-NEXT: br label [[BB1_TO_OUTLINE:%.*]]
95+
; CHECK: bb1_to_outline:
96+
; CHECK-NEXT: [[TMP2:%.*]] = add i32 1, 2
97+
; CHECK-NEXT: [[TMP3:%.*]] = add i32 3, 4
98+
; CHECK-NEXT: [[TMP4:%.*]] = add i32 5, 6
99+
; CHECK-NEXT: [[TMP5:%.*]] = add i32 7, 8
100+
; CHECK-NEXT: br label [[BB5_SPLIT:%.*]]
101+
; CHECK: bb2:
102+
; CHECK-NEXT: [[TMP6:%.*]] = mul i32 5, 4
103+
; CHECK-NEXT: br label [[BB5_SPLIT]]
104+
; CHECK: placeholder:
105+
; CHECK-NEXT: [[A:%.*]] = sub i32 5, 4
106+
; CHECK-NEXT: br label [[BB1_AFTER_OUTLINE_EXITSTUB:%.*]]
107+
; CHECK: bb5.split:
108+
; CHECK-NEXT: [[PHINODE_CE:%.*]] = phi i32 [ 5, [[BB1_TO_OUTLINE]] ], [ 5, [[BB2:%.*]] ]
109+
; CHECK-NEXT: [[PHINODE1_CE:%.*]] = phi i32 [ 5, [[BB1_TO_OUTLINE]] ], [ 5, [[BB2]] ]
110+
; CHECK-NEXT: br label [[BB5_EXITSTUB:%.*]]
111+
; CHECK: bb5.exitStub:
112+
; CHECK-NEXT: store i32 [[PHINODE_CE]], i32* [[TMP0:%.*]], align 4
113+
; CHECK-NEXT: store i32 [[PHINODE1_CE]], i32* [[TMP1:%.*]], align 4
114+
; CHECK-NEXT: ret i1 true
115+
; CHECK: bb1_after_outline.exitStub:
116+
; CHECK-NEXT: ret i1 false
117+
;

0 commit comments

Comments
 (0)