Skip to content

Commit f1ef67d

Browse files
authored
LICM: extend hoist BO assoc to mul case (#106991)
Trivially extend hoistBOAssociation to also handle the BinaryOperator Mul. Alive2 proofs: https://alive2.llvm.org/ce/z/zjtR5g
1 parent 903d1c6 commit f1ef67d

File tree

3 files changed

+82
-14
lines changed

3 files changed

+82
-14
lines changed

llvm/lib/Transforms/Scalar/LICM.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2820,9 +2820,9 @@ static bool hoistBOAssociation(Instruction &I, Loop &L,
28202820
if (!BO || !BO->isAssociative())
28212821
return false;
28222822

2823-
// Only fold ADDs for now.
2823+
// TODO: Only hoist ADDs and MULs for now.
28242824
Instruction::BinaryOps Opcode = BO->getOpcode();
2825-
if (Opcode != Instruction::Add)
2825+
if (Opcode != Instruction::Add && Opcode != Instruction::Mul)
28262826
return false;
28272827

28282828
auto *BO0 = dyn_cast<BinaryOperator>(BO->getOperand(0));

llvm/test/Transforms/LICM/hoist-binop.ll

Lines changed: 78 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
22
; RUN: opt -S -passes=licm < %s | FileCheck %s
33

4-
; Fold ADD and remove old op if unused.
4+
; Hoist ADD and remove old op if unused.
55
define void @add_one_use(i64 %c1, i64 %c2) {
66
; CHECK-LABEL: @add_one_use(
77
; CHECK-NEXT: entry:
@@ -22,8 +22,28 @@ loop:
2222
br label %loop
2323
}
2424

25-
; Fold ADD and copy NUW if both ops have it.
26-
; https://alive2.llvm.org/ce/z/bPAT7Z
25+
; Hoist MUL and remove old op if unused.
26+
define void @mul_one_use(i64 %c1, i64 %c2) {
27+
; CHECK-LABEL: @mul_one_use(
28+
; CHECK-NEXT: entry:
29+
; CHECK-NEXT: [[FACTOR_OP_MUL:%.*]] = mul i64 [[C1:%.*]], [[C2:%.*]]
30+
; CHECK-NEXT: br label [[LOOP:%.*]]
31+
; CHECK: loop:
32+
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[STEP_ADD_REASS:%.*]], [[LOOP]] ]
33+
; CHECK-NEXT: [[STEP_ADD_REASS]] = mul i64 [[INDEX]], [[FACTOR_OP_MUL]]
34+
; CHECK-NEXT: br label [[LOOP]]
35+
;
36+
entry:
37+
br label %loop
38+
39+
loop:
40+
%index = phi i64 [ 0, %entry ], [ %index.next, %loop ]
41+
%step.add = mul i64 %index, %c1
42+
%index.next = mul i64 %step.add, %c2
43+
br label %loop
44+
}
45+
46+
; Hoist ADD and copy NUW if both ops have it.
2747
define void @add_nuw(i64 %c1, i64 %c2) {
2848
; CHECK-LABEL: @add_nuw(
2949
; CHECK-NEXT: entry:
@@ -47,7 +67,31 @@ loop:
4767
br label %loop
4868
}
4969

50-
; Fold ADD but don't copy NUW if only one op has it.
70+
; Hoist MUL and drop NUW even if both ops have it.
71+
define void @mul_nuw(i64 %c1, i64 %c2) {
72+
; CHECK-LABEL: @mul_nuw(
73+
; CHECK-NEXT: entry:
74+
; CHECK-NEXT: [[INVARIANT_OP:%.*]] = mul i64 [[C1:%.*]], [[C2:%.*]]
75+
; CHECK-NEXT: br label [[LOOP:%.*]]
76+
; CHECK: loop:
77+
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INDEX_NEXT_REASS:%.*]], [[LOOP]] ]
78+
; CHECK-NEXT: [[STEP_ADD:%.*]] = mul nuw i64 [[INDEX]], [[C1]]
79+
; CHECK-NEXT: call void @use(i64 [[STEP_ADD]])
80+
; CHECK-NEXT: [[INDEX_NEXT_REASS]] = mul i64 [[INDEX]], [[INVARIANT_OP]]
81+
; CHECK-NEXT: br label [[LOOP]]
82+
;
83+
entry:
84+
br label %loop
85+
86+
loop:
87+
%index = phi i64 [ 0, %entry ], [ %index.next, %loop ]
88+
%step.add = mul nuw i64 %index, %c1
89+
call void @use(i64 %step.add)
90+
%index.next = mul nuw i64 %step.add, %c2
91+
br label %loop
92+
}
93+
94+
; Hoist ADD but don't copy NUW if only one op has it.
5195
define void @add_no_nuw(i64 %c1, i64 %c2) {
5296
; CHECK-LABEL: @add_no_nuw(
5397
; CHECK-NEXT: entry:
@@ -71,7 +115,7 @@ loop:
71115
br label %loop
72116
}
73117

74-
; Fold ADD but don't copy NSW if one op has it.
118+
; Hoist ADD but don't copy NSW if one op has it.
75119
define void @add_no_nsw(i64 %c1, i64 %c2) {
76120
; CHECK-LABEL: @add_no_nsw(
77121
; CHECK-NEXT: entry:
@@ -95,7 +139,7 @@ loop:
95139
br label %loop
96140
}
97141

98-
; Fold ADD but don't copy NSW even if both ops have it.
142+
; Hoist ADD but don't copy NSW even if both ops have it.
99143
define void @add_no_nsw_2(i64 %c1, i64 %c2) {
100144
; CHECK-LABEL: @add_no_nsw_2(
101145
; CHECK-NEXT: entry:
@@ -119,7 +163,31 @@ loop:
119163
br label %loop
120164
}
121165

122-
; Don't fold if the ops are different (even if they are both associative).
166+
; Hoist MUL and drop NSW even if both ops have it.
167+
define void @mul_no_nsw_2(i64 %c1, i64 %c2) {
168+
; CHECK-LABEL: @mul_no_nsw_2(
169+
; CHECK-NEXT: entry:
170+
; CHECK-NEXT: [[INVARIANT_OP:%.*]] = mul i64 [[C1:%.*]], [[C2:%.*]]
171+
; CHECK-NEXT: br label [[LOOP:%.*]]
172+
; CHECK: loop:
173+
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INDEX_NEXT_REASS:%.*]], [[LOOP]] ]
174+
; CHECK-NEXT: [[STEP_ADD:%.*]] = mul nsw i64 [[INDEX]], [[C1]]
175+
; CHECK-NEXT: call void @use(i64 [[STEP_ADD]])
176+
; CHECK-NEXT: [[INDEX_NEXT_REASS]] = mul i64 [[INDEX]], [[INVARIANT_OP]]
177+
; CHECK-NEXT: br label [[LOOP]]
178+
;
179+
entry:
180+
br label %loop
181+
182+
loop:
183+
%index = phi i64 [ 0, %entry ], [ %index.next, %loop ]
184+
%step.add = mul nsw i64 %index, %c1
185+
call void @use(i64 %step.add)
186+
%index.next = mul nsw i64 %step.add, %c2
187+
br label %loop
188+
}
189+
190+
; Don't hoist if the ops are different (even if they are both associative).
123191
define void @diff_ops(i64 %c1, i64 %c2) {
124192
; CHECK-LABEL: @diff_ops(
125193
; CHECK-NEXT: entry:
@@ -142,7 +210,7 @@ loop:
142210
br label %loop
143211
}
144212

145-
; Don't fold if the ops are not associative.
213+
; Don't hoist if the ops are not associative.
146214
define void @noassoc_ops(i64 %c1, i64 %c2) {
147215
; CHECK-LABEL: @noassoc_ops(
148216
; CHECK-NEXT: entry:
@@ -165,7 +233,7 @@ loop:
165233
br label %loop
166234
}
167235

168-
; Don't fold floating-point ops, even if they are associative. This would be
236+
; Don't hoist floating-point ops, even if they are associative. This would be
169237
; valid, but is currently disabled.
170238
define void @fadd(float %c1, float %c2) {
171239
; CHECK-LABEL: @fadd(
@@ -189,7 +257,7 @@ loop:
189257
br label %loop
190258
}
191259

192-
; Don't fold if the intermediate op has more than two uses. This is an
260+
; Don't hoist if the intermediate op has more than two uses. This is an
193261
; heuristic that can be adjusted if warranted. Currently we are being
194262
; conservative to minimise potential impact in code size.
195263
define void @not_many_uses(i64 %c1, i64 %c2, i64 %c3) {

llvm/test/Transforms/LICM/update-scev-after-hoist.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
define i16 @main() {
55
; SCEV-EXPR-LABEL: 'main'
66
; SCEV-EXPR-NEXT: Classifying expressions for: @main
7-
; SCEV-EXPR-NEXT: %mul = phi i16 [ 1, %entry ], [ %mul.n.3, %loop ]
7+
; SCEV-EXPR-NEXT: %mul = phi i16 [ 1, %entry ], [ %mul.n.3.reass, %loop ]
88
; SCEV-EXPR-NEXT: --> %mul U: [0,-15) S: [-32768,32753) Exits: 4096 LoopDispositions: { %loop: Variant }
99
; SCEV-EXPR-NEXT: %div = phi i16 [ 32767, %entry ], [ %div.n.3, %loop ]
1010
; SCEV-EXPR-NEXT: --> %div U: [-2048,-32768) S: [-2048,-32768) Exits: 7 LoopDispositions: { %loop: Variant }
@@ -16,7 +16,7 @@ define i16 @main() {
1616
; SCEV-EXPR-NEXT: --> %div.n.1 U: [-8192,8192) S: [-8192,8192) Exits: 1 LoopDispositions: { %loop: Variant }
1717
; SCEV-EXPR-NEXT: %div.n.2 = sdiv i16 %div.n.1, 2
1818
; SCEV-EXPR-NEXT: --> %div.n.2 U: [-4096,4096) S: [-4096,4096) Exits: 0 LoopDispositions: { %loop: Variant }
19-
; SCEV-EXPR-NEXT: %mul.n.3 = mul i16 %mul.n.reass.reass, 2
19+
; SCEV-EXPR-NEXT: %mul.n.3.reass = mul i16 %mul, 16
2020
; SCEV-EXPR-NEXT: --> (16 * %mul) U: [0,-15) S: [-32768,32753) Exits: 0 LoopDispositions: { %loop: Variant }
2121
; SCEV-EXPR-NEXT: %div.n.3 = sdiv i16 %div.n.2, 2
2222
; SCEV-EXPR-NEXT: --> %div.n.3 U: [-2048,2048) S: [-2048,2048) Exits: 0 LoopDispositions: { %loop: Variant }

0 commit comments

Comments
 (0)