Skip to content

Commit b3fa45b

Browse files
authored
[SimplifyCFG] Add support for hoisting commutative instructions (#104805)
This extends SimplifyCFG hoisting to also hoist instructions with commuted operands, for example a+b on one side and b+a on the other side. This should address the issue mentioned in: #91185 (comment)
1 parent c99347a commit b3fa45b

File tree

2 files changed

+31
-26
lines changed

2 files changed

+31
-26
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1583,6 +1583,26 @@ static void hoistLockstepIdenticalDbgVariableRecords(
15831583
}
15841584
}
15851585

1586+
static bool areIdenticalUpToCommutativity(const Instruction *I1,
1587+
const Instruction *I2) {
1588+
if (I1->isIdenticalToWhenDefined(I2))
1589+
return true;
1590+
1591+
if (auto *Cmp1 = dyn_cast<CmpInst>(I1))
1592+
if (auto *Cmp2 = dyn_cast<CmpInst>(I2))
1593+
return Cmp1->getPredicate() == Cmp2->getSwappedPredicate() &&
1594+
Cmp1->getOperand(0) == Cmp2->getOperand(1) &&
1595+
Cmp1->getOperand(1) == Cmp2->getOperand(0);
1596+
1597+
if (I1->isCommutative() && I1->isSameOperationAs(I2)) {
1598+
return I1->getOperand(0) == I2->getOperand(1) &&
1599+
I1->getOperand(1) == I2->getOperand(0) &&
1600+
equal(drop_begin(I1->operands(), 2), drop_begin(I2->operands(), 2));
1601+
}
1602+
1603+
return false;
1604+
}
1605+
15861606
/// Hoist any common code in the successor blocks up into the block. This
15871607
/// function guarantees that BB dominates all successors. If EqTermsOnly is
15881608
/// given, only perform hoisting in case both blocks only contain a terminator.
@@ -1676,7 +1696,7 @@ bool SimplifyCFGOpt::hoistCommonCodeFromSuccessors(BasicBlock *BB,
16761696
for (auto &SuccIter : OtherSuccIterRange) {
16771697
Instruction *I2 = &*SuccIter;
16781698
HasTerminator |= I2->isTerminator();
1679-
if (AllInstsAreIdentical && (!I1->isIdenticalToWhenDefined(I2) ||
1699+
if (AllInstsAreIdentical && (!areIdenticalUpToCommutativity(I1, I2) ||
16801700
MMRAMetadata(*I1) != MMRAMetadata(*I2)))
16811701
AllInstsAreIdentical = false;
16821702
}

llvm/test/Transforms/SimplifyCFG/hoist-common-code.ll

Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -159,16 +159,14 @@ declare void @foo()
159159

160160
define i1 @test_icmp_simple(i1 %c, i32 %a, i32 %b) {
161161
; CHECK-LABEL: @test_icmp_simple(
162+
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[A:%.*]], [[B:%.*]]
162163
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
163164
; CHECK: common.ret:
164-
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i1 [ [[CMP1:%.*]], [[IF]] ], [ [[CMP2:%.*]], [[ELSE]] ]
165-
; CHECK-NEXT: ret i1 [[COMMON_RET_OP]]
165+
; CHECK-NEXT: ret i1 [[CMP1]]
166166
; CHECK: if:
167-
; CHECK-NEXT: [[CMP1]] = icmp ult i32 [[A:%.*]], [[B:%.*]]
168167
; CHECK-NEXT: call void @foo()
169168
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
170169
; CHECK: else:
171-
; CHECK-NEXT: [[CMP2]] = icmp ugt i32 [[B]], [[A]]
172170
; CHECK-NEXT: call void @bar()
173171
; CHECK-NEXT: br label [[COMMON_RET]]
174172
;
@@ -187,13 +185,8 @@ else:
187185

188186
define void @test_icmp_complex(i1 %c, i32 %a, i32 %b) {
189187
; CHECK-LABEL: @test_icmp_complex(
190-
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
191-
; CHECK: if:
192188
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[A:%.*]], [[B:%.*]]
193189
; CHECK-NEXT: br i1 [[CMP1]], label [[IF2:%.*]], label [[ELSE2:%.*]]
194-
; CHECK: else:
195-
; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i32 [[B]], [[A]]
196-
; CHECK-NEXT: br i1 [[CMP2]], label [[IF2]], label [[ELSE2]]
197190
; CHECK: common.ret:
198191
; CHECK-NEXT: ret void
199192
; CHECK: if2:
@@ -280,16 +273,14 @@ else:
280273

281274
define i32 @test_binop(i1 %c, i32 %a, i32 %b) {
282275
; CHECK-LABEL: @test_binop(
276+
; CHECK-NEXT: [[OP1:%.*]] = add i32 [[A:%.*]], [[B:%.*]]
283277
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
284278
; CHECK: common.ret:
285-
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[OP1:%.*]], [[IF]] ], [ [[OP2:%.*]], [[ELSE]] ]
286-
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
279+
; CHECK-NEXT: ret i32 [[OP1]]
287280
; CHECK: if:
288-
; CHECK-NEXT: [[OP1]] = add i32 [[A:%.*]], [[B:%.*]]
289281
; CHECK-NEXT: call void @foo()
290282
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
291283
; CHECK: else:
292-
; CHECK-NEXT: [[OP2]] = add i32 [[B]], [[A]]
293284
; CHECK-NEXT: call void @bar()
294285
; CHECK-NEXT: br label [[COMMON_RET]]
295286
;
@@ -308,16 +299,14 @@ else:
308299

309300
define i32 @test_binop_flags(i1 %c, i32 %a, i32 %b) {
310301
; CHECK-LABEL: @test_binop_flags(
302+
; CHECK-NEXT: [[OP1:%.*]] = add nsw i32 [[A:%.*]], [[B:%.*]]
311303
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
312304
; CHECK: common.ret:
313-
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[OP1:%.*]], [[IF]] ], [ [[OP2:%.*]], [[ELSE]] ]
314-
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
305+
; CHECK-NEXT: ret i32 [[OP1]]
315306
; CHECK: if:
316-
; CHECK-NEXT: [[OP1]] = add nuw nsw i32 [[A:%.*]], [[B:%.*]]
317307
; CHECK-NEXT: call void @foo()
318308
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
319309
; CHECK: else:
320-
; CHECK-NEXT: [[OP2]] = add nsw i32 [[B]], [[A]]
321310
; CHECK-NEXT: call void @bar()
322311
; CHECK-NEXT: br label [[COMMON_RET]]
323312
;
@@ -392,16 +381,14 @@ else:
392381

393382
define i32 @test_intrin(i1 %c, i32 %a, i32 %b) {
394383
; CHECK-LABEL: @test_intrin(
384+
; CHECK-NEXT: [[OP1:%.*]] = call i32 @llvm.umin.i32(i32 [[A:%.*]], i32 [[B:%.*]])
395385
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
396386
; CHECK: common.ret:
397-
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[OP1:%.*]], [[IF]] ], [ [[OP2:%.*]], [[ELSE]] ]
398-
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
387+
; CHECK-NEXT: ret i32 [[OP1]]
399388
; CHECK: if:
400-
; CHECK-NEXT: [[OP1]] = call i32 @llvm.umin.i32(i32 [[A:%.*]], i32 [[B:%.*]])
401389
; CHECK-NEXT: call void @foo()
402390
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
403391
; CHECK: else:
404-
; CHECK-NEXT: [[OP2]] = call i32 @llvm.umin.i32(i32 [[B]], i32 [[A]])
405392
; CHECK-NEXT: call void @bar()
406393
; CHECK-NEXT: br label [[COMMON_RET]]
407394
;
@@ -448,16 +435,14 @@ else:
448435

449436
define float @test_intrin_3arg(i1 %c, float %a, float %b, float %d) {
450437
; CHECK-LABEL: @test_intrin_3arg(
438+
; CHECK-NEXT: [[OP1:%.*]] = call float @llvm.fma.f32(float [[A:%.*]], float [[B:%.*]], float [[D:%.*]])
451439
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
452440
; CHECK: common.ret:
453-
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi float [ [[OP1:%.*]], [[IF]] ], [ [[OP2:%.*]], [[ELSE]] ]
454-
; CHECK-NEXT: ret float [[COMMON_RET_OP]]
441+
; CHECK-NEXT: ret float [[OP1]]
455442
; CHECK: if:
456-
; CHECK-NEXT: [[OP1]] = call float @llvm.fma.f32(float [[A:%.*]], float [[B:%.*]], float [[D:%.*]])
457443
; CHECK-NEXT: call void @foo()
458444
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
459445
; CHECK: else:
460-
; CHECK-NEXT: [[OP2]] = call float @llvm.fma.f32(float [[B]], float [[A]], float [[D]])
461446
; CHECK-NEXT: call void @bar()
462447
; CHECK-NEXT: br label [[COMMON_RET]]
463448
;

0 commit comments

Comments
 (0)