Skip to content

Commit 2d6988a

Browse files
committed
[InstCombine] Add restrict reassoc for the operands of fmul
According the discussion, except the fmul itself, all its operands should also have reassoc flag. Add new API m_AllowReassoc to check reassoc flag
1 parent 1752b9e commit 2d6988a

File tree

3 files changed

+99
-37
lines changed

3 files changed

+99
-37
lines changed

llvm/include/llvm/IR/PatternMatch.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,22 @@ template <typename T> inline OneUse_match<T> m_OneUse(const T &SubPattern) {
6868
return SubPattern;
6969
}
7070

71+
template <typename SubPattern_t> struct AllowReassoc_match {
72+
SubPattern_t SubPattern;
73+
74+
AllowReassoc_match(const SubPattern_t &SP) : SubPattern(SP) {}
75+
76+
template <typename OpTy> bool match(OpTy *V) {
77+
auto *I = dyn_cast<FPMathOperator>(V);
78+
return I && I->hasAllowReassoc() && SubPattern.match(I);
79+
}
80+
};
81+
82+
template <typename T>
83+
inline AllowReassoc_match<T> m_AllowReassoc(const T &SubPattern) {
84+
return SubPattern;
85+
}
86+
7187
template <typename Class> struct class_match {
7288
template <typename ITy> bool match(ITy *V) { return isa<Class>(V); }
7389
};

llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -572,37 +572,35 @@ Instruction *InstCombinerImpl::foldFPSignBitOps(BinaryOperator &I) {
572572
}
573573

574574
Instruction *InstCombinerImpl::foldPowiReassoc(BinaryOperator &I) {
575-
Value *X, *Y, *Z;
576575
auto createPowiExpr = [](BinaryOperator &I, InstCombinerImpl &IC, Value *X,
577576
Value *Y, Value *Z) {
578-
Value *YZ;
579577
InstCombiner::BuilderTy &Builder = IC.Builder;
580-
581-
if (auto *C = dyn_cast<ConstantInt>(Z)) {
582-
if (C->isOne())
583-
YZ = Builder.CreateAdd(Y, ConstantInt::get(Y->getType(), 1));
584-
} else
585-
YZ = Builder.CreateAdd(Y, Z);
586-
578+
Value *YZ = Builder.CreateAdd(Y, Z);
587579
auto *NewPow = Builder.CreateIntrinsic(
588580
Intrinsic::powi, {X->getType(), YZ->getType()}, {X, YZ}, &I);
589581
return IC.replaceInstUsesWith(I, NewPow);
590582
};
591583

584+
Value *X, *Y, *Z;
585+
592586
// powi(X, Y) * X --> powi(X, Y+1)
593587
// X * powi(X, Y) --> powi(X, Y+1)
594-
if (match(&I, m_c_FMul(m_OneUse(m_Intrinsic<Intrinsic::powi>(m_Value(X),
595-
m_Value(Y))),
596-
m_Deferred(X))) &&
597-
willNotOverflowSignedAdd(Y, ConstantInt::get(Y->getType(), 1), I))
598-
return createPowiExpr(I, *this, X, Y, ConstantInt::get(Y->getType(), 1));
588+
if (match(&I, m_c_FMul(m_OneUse(m_AllowReassoc(m_Intrinsic<Intrinsic::powi>(
589+
m_Value(X), m_Value(Y)))),
590+
m_Deferred(X)))) {
591+
Constant *One = ConstantInt::get(Y->getType(), 1);
592+
if (willNotOverflowSignedAdd(Y, One, I))
593+
return createPowiExpr(I, *this, X, Y, One);
594+
}
599595

600596
// powi(x, y) * powi(x, z) -> powi(x, y + z)
601597
Value *Op0 = I.getOperand(0);
602598
Value *Op1 = I.getOperand(1);
603599
if (I.isOnlyUserOfAnyOperand() &&
604-
match(Op0, m_Intrinsic<Intrinsic::powi>(m_Value(X), m_Value(Y))) &&
605-
match(Op1, m_Intrinsic<Intrinsic::powi>(m_Specific(X), m_Value(Z))) &&
600+
match(Op0, m_AllowReassoc(
601+
m_Intrinsic<Intrinsic::powi>(m_Value(X), m_Value(Y)))) &&
602+
match(Op1, m_AllowReassoc(m_Intrinsic<Intrinsic::powi>(m_Specific(X),
603+
m_Value(Z)))) &&
606604
Y->getType() == Z->getType())
607605
return createPowiExpr(I, *this, X, Y, Z);
608606

llvm/test/Transforms/InstCombine/powi.ll

Lines changed: 69 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -125,22 +125,55 @@ entry:
125125
ret double %mul
126126
}
127127

128-
define double @powi_fmul_powi_no_reassoc(double %x, i32 %y, i32 %z) {
129-
; CHECK-LABEL: @powi_fmul_powi_no_reassoc(
128+
; Negative test: Missing reassoc flag on fmul
129+
define double @powi_fmul_powi_no_reassoc1(double %x, i32 %y, i32 %z) {
130+
; CHECK-LABEL: @powi_fmul_powi_no_reassoc1(
130131
; CHECK-NEXT: entry:
131-
; CHECK-NEXT: [[P1:%.*]] = tail call double @llvm.powi.f64.i32(double [[X:%.*]], i32 [[Y:%.*]])
132-
; CHECK-NEXT: [[P2:%.*]] = tail call double @llvm.powi.f64.i32(double [[X]], i32 [[Z:%.*]])
132+
; CHECK-NEXT: [[P1:%.*]] = tail call reassoc double @llvm.powi.f64.i32(double [[X:%.*]], i32 [[Y:%.*]])
133+
; CHECK-NEXT: [[P2:%.*]] = tail call reassoc double @llvm.powi.f64.i32(double [[X]], i32 [[Z:%.*]])
133134
; CHECK-NEXT: [[MUL:%.*]] = fmul double [[P2]], [[P1]]
134135
; CHECK-NEXT: ret double [[MUL]]
135136
;
136137
entry:
137-
%p1 = tail call double @llvm.powi.f64.i32(double %x, i32 %y)
138-
%p2 = tail call double @llvm.powi.f64.i32(double %x, i32 %z)
138+
%p1 = tail call reassoc double @llvm.powi.f64.i32(double %x, i32 %y)
139+
%p2 = tail call reassoc double @llvm.powi.f64.i32(double %x, i32 %z)
139140
%mul = fmul double %p2, %p1
140141
ret double %mul
141142
}
142143

144+
; Negative test: Missing reassoc flag on 2nd operand
145+
define double @powi_fmul_powi_no_reassoc2(double %x, i32 %y, i32 %z) {
146+
; CHECK-LABEL: @powi_fmul_powi_no_reassoc2(
147+
; CHECK-NEXT: entry:
148+
; CHECK-NEXT: [[P1:%.*]] = tail call reassoc double @llvm.powi.f64.i32(double [[X:%.*]], i32 [[Y:%.*]])
149+
; CHECK-NEXT: [[P2:%.*]] = tail call double @llvm.powi.f64.i32(double [[X]], i32 [[Z:%.*]])
150+
; CHECK-NEXT: [[MUL:%.*]] = fmul reassoc double [[P2]], [[P1]]
151+
; CHECK-NEXT: ret double [[MUL]]
152+
;
153+
entry:
154+
%p1 = tail call reassoc double @llvm.powi.f64.i32(double %x, i32 %y)
155+
%p2 = tail call double @llvm.powi.f64.i32(double %x, i32 %z)
156+
%mul = fmul reassoc double %p2, %p1
157+
ret double %mul
158+
}
143159

160+
; Negative test: Missing reassoc flag on 1st operand
161+
define double @powi_fmul_powi_no_reassoc3(double %x, i32 %y, i32 %z) {
162+
; CHECK-LABEL: @powi_fmul_powi_no_reassoc3(
163+
; CHECK-NEXT: entry:
164+
; CHECK-NEXT: [[P1:%.*]] = tail call double @llvm.powi.f64.i32(double [[X:%.*]], i32 [[Y:%.*]])
165+
; CHECK-NEXT: [[P2:%.*]] = tail call reassoc double @llvm.powi.f64.i32(double [[X]], i32 [[Z:%.*]])
166+
; CHECK-NEXT: [[MUL:%.*]] = fmul reassoc double [[P2]], [[P1]]
167+
; CHECK-NEXT: ret double [[MUL]]
168+
;
169+
entry:
170+
%p1 = tail call double @llvm.powi.f64.i32(double %x, i32 %y)
171+
%p2 = tail call reassoc double @llvm.powi.f64.i32(double %x, i32 %z)
172+
%mul = fmul reassoc double %p2, %p1
173+
ret double %mul
174+
}
175+
176+
; All of the fmul and its operands should have the reassoc flags
144177
define double @powi_fmul_powi(double %x, i32 %y, i32 %z) {
145178
; CHECK-LABEL: @powi_fmul_powi(
146179
; CHECK-NEXT: entry:
@@ -149,8 +182,8 @@ define double @powi_fmul_powi(double %x, i32 %y, i32 %z) {
149182
; CHECK-NEXT: ret double [[MUL]]
150183
;
151184
entry:
152-
%p1 = tail call double @llvm.powi.f64.i32(double %x, i32 %y)
153-
%p2 = tail call double @llvm.powi.f64.i32(double %x, i32 %z)
185+
%p1 = tail call reassoc double @llvm.powi.f64.i32(double %x, i32 %y)
186+
%p2 = tail call reassoc double @llvm.powi.f64.i32(double %x, i32 %z)
154187
%mul = fmul reassoc double %p2, %p1
155188
ret double %mul
156189
}
@@ -163,8 +196,8 @@ define double @powi_fmul_powi_fast_on_fmul(double %x, i32 %y, i32 %z) {
163196
; CHECK-NEXT: ret double [[MUL]]
164197
;
165198
entry:
166-
%p1 = tail call double @llvm.powi.f64.i32(double %x, i32 %y)
167-
%p2 = tail call double @llvm.powi.f64.i32(double %x, i32 %z)
199+
%p1 = tail call fast double @llvm.powi.f64.i32(double %x, i32 %y)
200+
%p2 = tail call fast double @llvm.powi.f64.i32(double %x, i32 %z)
168201
%mul = fmul fast double %p2, %p1
169202
ret double %mul
170203
}
@@ -192,42 +225,57 @@ define double @powi_fmul_powi_same_power(double %x, i32 %y, i32 %z) {
192225
; CHECK-NEXT: ret double [[MUL]]
193226
;
194227
entry:
195-
%p1 = tail call double @llvm.powi.f64.i32(double %x, i32 %y)
196-
%p2 = tail call double @llvm.powi.f64.i32(double %x, i32 %y)
228+
%p1 = tail call reassoc double @llvm.powi.f64.i32(double %x, i32 %y)
229+
%p2 = tail call reassoc double @llvm.powi.f64.i32(double %x, i32 %y)
230+
%mul = fmul reassoc double %p2, %p1
231+
ret double %mul
232+
}
233+
234+
define double @powi_fmul_powi_different_integer_types(double %x, i32 %y, i16 %z) {
235+
; CHECK-LABEL: @powi_fmul_powi_different_integer_types(
236+
; CHECK-NEXT: entry:
237+
; CHECK-NEXT: [[P1:%.*]] = tail call reassoc double @llvm.powi.f64.i32(double [[X:%.*]], i32 [[Y:%.*]])
238+
; CHECK-NEXT: [[P2:%.*]] = tail call reassoc double @llvm.powi.f64.i16(double [[X]], i16 [[Z:%.*]])
239+
; CHECK-NEXT: [[MUL:%.*]] = fmul reassoc double [[P2]], [[P1]]
240+
; CHECK-NEXT: ret double [[MUL]]
241+
;
242+
entry:
243+
%p1 = tail call reassoc double @llvm.powi.f64.i32(double %x, i32 %y)
244+
%p2 = tail call reassoc double @llvm.powi.f64.i16(double %x, i16 %z)
197245
%mul = fmul reassoc double %p2, %p1
198246
ret double %mul
199247
}
200248

201249
define double @powi_fmul_powi_use_first(double %x, i32 %y, i32 %z) {
202250
; CHECK-LABEL: @powi_fmul_powi_use_first(
203251
; CHECK-NEXT: entry:
204-
; CHECK-NEXT: [[P1:%.*]] = tail call double @llvm.powi.f64.i32(double [[X:%.*]], i32 [[Y:%.*]])
252+
; CHECK-NEXT: [[P1:%.*]] = tail call reassoc double @llvm.powi.f64.i32(double [[X:%.*]], i32 [[Y:%.*]])
205253
; CHECK-NEXT: tail call void @use(double [[P1]])
206254
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[Y]], [[Z:%.*]]
207255
; CHECK-NEXT: [[MUL:%.*]] = call reassoc double @llvm.powi.f64.i32(double [[X]], i32 [[TMP0]])
208256
; CHECK-NEXT: ret double [[MUL]]
209257
;
210258
entry:
211-
%p1 = tail call double @llvm.powi.f64.i32(double %x, i32 %y)
259+
%p1 = tail call reassoc double @llvm.powi.f64.i32(double %x, i32 %y)
212260
tail call void @use(double %p1)
213-
%p2 = tail call double @llvm.powi.f64.i32(double %x, i32 %z)
261+
%p2 = tail call reassoc double @llvm.powi.f64.i32(double %x, i32 %z)
214262
%mul = fmul reassoc double %p1, %p2
215263
ret double %mul
216264
}
217265

218266
define double @powi_fmul_powi_use_second(double %x, i32 %y, i32 %z) {
219267
; CHECK-LABEL: @powi_fmul_powi_use_second(
220268
; CHECK-NEXT: entry:
221-
; CHECK-NEXT: [[P1:%.*]] = tail call double @llvm.powi.f64.i32(double [[X:%.*]], i32 [[Z:%.*]])
269+
; CHECK-NEXT: [[P1:%.*]] = tail call reassoc double @llvm.powi.f64.i32(double [[X:%.*]], i32 [[Z:%.*]])
222270
; CHECK-NEXT: tail call void @use(double [[P1]])
223271
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[Y:%.*]], [[Z]]
224272
; CHECK-NEXT: [[MUL:%.*]] = call reassoc double @llvm.powi.f64.i32(double [[X]], i32 [[TMP0]])
225273
; CHECK-NEXT: ret double [[MUL]]
226274
;
227275
entry:
228-
%p1 = tail call double @llvm.powi.f64.i32(double %x, i32 %z)
276+
%p1 = tail call reassoc double @llvm.powi.f64.i32(double %x, i32 %z)
229277
tail call void @use(double %p1)
230-
%p2 = tail call double @llvm.powi.f64.i32(double %x, i32 %y)
278+
%p2 = tail call reassoc double @llvm.powi.f64.i32(double %x, i32 %y)
231279
%mul = fmul reassoc double %p2, %p1
232280
ret double %mul
233281
}
@@ -333,11 +381,11 @@ define double @fdiv_pow_powi_negative(double %x) {
333381
; Negative test: The 2nd powi argument is a variable
334382
define double @fdiv_pow_powi_negative_variable(double %x, i32 %y) {
335383
; CHECK-LABEL: @fdiv_pow_powi_negative_variable(
336-
; CHECK-NEXT: [[P1:%.*]] = call double @llvm.powi.f64.i32(double [[X:%.*]], i32 [[Y:%.*]])
384+
; CHECK-NEXT: [[P1:%.*]] = call reassoc double @llvm.powi.f64.i32(double [[X:%.*]], i32 [[Y:%.*]])
337385
; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc nnan double [[P1]], [[X]]
338386
; CHECK-NEXT: ret double [[DIV]]
339387
;
340-
%p1 = call double @llvm.powi.f64.i32(double %x, i32 %y)
388+
%p1 = call reassoc double @llvm.powi.f64.i32(double %x, i32 %y)
341389
%div = fdiv reassoc nnan double %p1, %x
342390
ret double %div
343391
}
@@ -348,7 +396,7 @@ define double @powi_fmul_powi_x(double noundef %x) {
348396
; CHECK-NEXT: [[MUL:%.*]] = call reassoc double @llvm.powi.f64.i32(double [[X:%.*]], i32 4)
349397
; CHECK-NEXT: ret double [[MUL]]
350398
;
351-
%p1 = tail call double @llvm.powi.f64.i32(double %x, i32 3)
399+
%p1 = tail call reassoc double @llvm.powi.f64.i32(double %x, i32 3)
352400
%mul = fmul reassoc double %p1, %x
353401
ret double %mul
354402
}

0 commit comments

Comments
 (0)