Skip to content

Commit b8ec205

Browse files
committed
[InstCombine] Support reassoc for foldLogicOfFCmps
We currently support simple reassociation for foldAndOrOfICmps(). Support the same for foldLogicOfFCmps() by going through the common foldBooleanAndOr() helper. This will also resolve the regression on llvm#112704, which is also due to missing reassoc support. I had to adjust one fold to add support for FMF flag preservation, otherwise there would be test regressions. There is a separate fold (reassociateFCmps) handling reassociation for *just* that specific case and it preserves FMF. Unfortuantely it's not rendered entirely redundant by this patch, because it handles one more level of reassociation as well.
1 parent 7d8d51e commit b8ec205

File tree

3 files changed

+74
-118
lines changed

3 files changed

+74
-118
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 56 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,11 +1465,16 @@ Value *InstCombinerImpl::foldLogicOfFCmps(FCmpInst *LHS, FCmpInst *RHS,
14651465

14661466
// FCmp canonicalization ensures that (fcmp ord/uno X, X) and
14671467
// (fcmp ord/uno X, C) will be transformed to (fcmp X, +0.0).
1468-
if (match(LHS1, m_PosZeroFP()) && match(RHS1, m_PosZeroFP()))
1468+
if (match(LHS1, m_PosZeroFP()) && match(RHS1, m_PosZeroFP())) {
14691469
// Ignore the constants because they are obviously not NANs:
14701470
// (fcmp ord x, 0.0) & (fcmp ord y, 0.0) -> (fcmp ord x, y)
14711471
// (fcmp uno x, 0.0) | (fcmp uno y, 0.0) -> (fcmp uno x, y)
1472+
IRBuilder<>::FastMathFlagGuard FMFG(Builder);
1473+
FastMathFlags FMF = LHS->getFastMathFlags();
1474+
FMF &= RHS->getFastMathFlags();
1475+
Builder.setFastMathFlags(FMF);
14721476
return Builder.CreateFCmp(PredL, LHS0, RHS0);
1477+
}
14731478
}
14741479

14751480
if (IsAnd && stripSignOnlyFPOps(LHS0) == stripSignOnlyFPOps(RHS0)) {
@@ -2728,47 +2733,31 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
27282733
foldBooleanAndOr(Op0, Op1, I, /*IsAnd=*/true, /*IsLogical=*/false))
27292734
return replaceInstUsesWith(I, Res);
27302735

2731-
{
2732-
ICmpInst *LHS = dyn_cast<ICmpInst>(Op0);
2733-
ICmpInst *RHS = dyn_cast<ICmpInst>(Op1);
2734-
2735-
// TODO: Base this on foldBooleanAndOr instead?
2736-
// TODO: Make this recursive; it's a little tricky because an arbitrary
2737-
// number of 'and' instructions might have to be created.
2738-
if (LHS && match(Op1, m_OneUse(m_LogicalAnd(m_Value(X), m_Value(Y))))) {
2739-
bool IsLogical = isa<SelectInst>(Op1);
2740-
// LHS & (X && Y) --> (LHS && X) && Y
2741-
if (auto *Cmp = dyn_cast<ICmpInst>(X))
2742-
if (Value *Res =
2743-
foldAndOrOfICmps(LHS, Cmp, I, /* IsAnd */ true, IsLogical))
2744-
return replaceInstUsesWith(I, IsLogical
2745-
? Builder.CreateLogicalAnd(Res, Y)
2746-
: Builder.CreateAnd(Res, Y));
2747-
// LHS & (X && Y) --> X && (LHS & Y)
2748-
if (auto *Cmp = dyn_cast<ICmpInst>(Y))
2749-
if (Value *Res = foldAndOrOfICmps(LHS, Cmp, I, /* IsAnd */ true,
2750-
/* IsLogical */ false))
2751-
return replaceInstUsesWith(I, IsLogical
2752-
? Builder.CreateLogicalAnd(X, Res)
2753-
: Builder.CreateAnd(X, Res));
2754-
}
2755-
if (RHS && match(Op0, m_OneUse(m_LogicalAnd(m_Value(X), m_Value(Y))))) {
2756-
bool IsLogical = isa<SelectInst>(Op0);
2757-
// (X && Y) & RHS --> (X && RHS) && Y
2758-
if (auto *Cmp = dyn_cast<ICmpInst>(X))
2759-
if (Value *Res =
2760-
foldAndOrOfICmps(Cmp, RHS, I, /* IsAnd */ true, IsLogical))
2761-
return replaceInstUsesWith(I, IsLogical
2762-
? Builder.CreateLogicalAnd(Res, Y)
2763-
: Builder.CreateAnd(Res, Y));
2764-
// (X && Y) & RHS --> X && (Y & RHS)
2765-
if (auto *Cmp = dyn_cast<ICmpInst>(Y))
2766-
if (Value *Res = foldAndOrOfICmps(Cmp, RHS, I, /* IsAnd */ true,
2767-
/* IsLogical */ false))
2768-
return replaceInstUsesWith(I, IsLogical
2769-
? Builder.CreateLogicalAnd(X, Res)
2770-
: Builder.CreateAnd(X, Res));
2771-
}
2736+
// TODO: Make this recursive; it's a little tricky because an arbitrary
2737+
// number of 'and' instructions might have to be created.
2738+
if (match(Op1, m_OneUse(m_LogicalAnd(m_Value(X), m_Value(Y))))) {
2739+
bool IsLogical = isa<SelectInst>(Op1);
2740+
// Op0 & (X && Y) --> (Op0 && X) && Y
2741+
if (Value *Res = foldBooleanAndOr(Op0, X, I, /* IsAnd */ true, IsLogical))
2742+
return replaceInstUsesWith(I, IsLogical ? Builder.CreateLogicalAnd(Res, Y)
2743+
: Builder.CreateAnd(Res, Y));
2744+
// Op0 & (X && Y) --> X && (Op0 & Y)
2745+
if (Value *Res = foldBooleanAndOr(Op0, Y, I, /* IsAnd */ true,
2746+
/* IsLogical */ false))
2747+
return replaceInstUsesWith(I, IsLogical ? Builder.CreateLogicalAnd(X, Res)
2748+
: Builder.CreateAnd(X, Res));
2749+
}
2750+
if (match(Op0, m_OneUse(m_LogicalAnd(m_Value(X), m_Value(Y))))) {
2751+
bool IsLogical = isa<SelectInst>(Op0);
2752+
// (X && Y) & Op1 --> (X && Op1) && Y
2753+
if (Value *Res = foldBooleanAndOr(X, Op1, I, /* IsAnd */ true, IsLogical))
2754+
return replaceInstUsesWith(I, IsLogical ? Builder.CreateLogicalAnd(Res, Y)
2755+
: Builder.CreateAnd(Res, Y));
2756+
// (X && Y) & Op1 --> X && (Y & Op1)
2757+
if (Value *Res = foldBooleanAndOr(Y, Op1, I, /* IsAnd */ true,
2758+
/* IsLogical */ false))
2759+
return replaceInstUsesWith(I, IsLogical ? Builder.CreateLogicalAnd(X, Res)
2760+
: Builder.CreateAnd(X, Res));
27722761
}
27732762

27742763
if (Instruction *FoldedFCmps = reassociateFCmps(I, Builder))
@@ -3829,48 +3818,31 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
38293818
foldBooleanAndOr(Op0, Op1, I, /*IsAnd=*/false, /*IsLogical=*/false))
38303819
return replaceInstUsesWith(I, Res);
38313820

3832-
{
3833-
ICmpInst *LHS = dyn_cast<ICmpInst>(Op0);
3834-
ICmpInst *RHS = dyn_cast<ICmpInst>(Op1);
3835-
3836-
// TODO: Base this on foldBooleanAndOr instead?
3837-
// TODO: Make this recursive; it's a little tricky because an arbitrary
3838-
// number of 'or' instructions might have to be created.
3839-
Value *X, *Y;
3840-
if (LHS && match(Op1, m_OneUse(m_LogicalOr(m_Value(X), m_Value(Y))))) {
3841-
bool IsLogical = isa<SelectInst>(Op1);
3842-
// LHS | (X || Y) --> (LHS || X) || Y
3843-
if (auto *Cmp = dyn_cast<ICmpInst>(X))
3844-
if (Value *Res =
3845-
foldAndOrOfICmps(LHS, Cmp, I, /* IsAnd */ false, IsLogical))
3846-
return replaceInstUsesWith(I, IsLogical
3847-
? Builder.CreateLogicalOr(Res, Y)
3848-
: Builder.CreateOr(Res, Y));
3849-
// LHS | (X || Y) --> X || (LHS | Y)
3850-
if (auto *Cmp = dyn_cast<ICmpInst>(Y))
3851-
if (Value *Res = foldAndOrOfICmps(LHS, Cmp, I, /* IsAnd */ false,
3852-
/* IsLogical */ false))
3853-
return replaceInstUsesWith(I, IsLogical
3854-
? Builder.CreateLogicalOr(X, Res)
3855-
: Builder.CreateOr(X, Res));
3856-
}
3857-
if (RHS && match(Op0, m_OneUse(m_LogicalOr(m_Value(X), m_Value(Y))))) {
3858-
bool IsLogical = isa<SelectInst>(Op0);
3859-
// (X || Y) | RHS --> (X || RHS) || Y
3860-
if (auto *Cmp = dyn_cast<ICmpInst>(X))
3861-
if (Value *Res =
3862-
foldAndOrOfICmps(Cmp, RHS, I, /* IsAnd */ false, IsLogical))
3863-
return replaceInstUsesWith(I, IsLogical
3864-
? Builder.CreateLogicalOr(Res, Y)
3865-
: Builder.CreateOr(Res, Y));
3866-
// (X || Y) | RHS --> X || (Y | RHS)
3867-
if (auto *Cmp = dyn_cast<ICmpInst>(Y))
3868-
if (Value *Res = foldAndOrOfICmps(Cmp, RHS, I, /* IsAnd */ false,
3869-
/* IsLogical */ false))
3870-
return replaceInstUsesWith(I, IsLogical
3871-
? Builder.CreateLogicalOr(X, Res)
3872-
: Builder.CreateOr(X, Res));
3873-
}
3821+
// TODO: Make this recursive; it's a little tricky because an arbitrary
3822+
// number of 'or' instructions might have to be created.
3823+
if (match(Op1, m_OneUse(m_LogicalOr(m_Value(X), m_Value(Y))))) {
3824+
bool IsLogical = isa<SelectInst>(Op1);
3825+
// Op0 | (X || Y) --> (Op0 || X) || Y
3826+
if (Value *Res = foldBooleanAndOr(Op0, X, I, /* IsAnd */ false, IsLogical))
3827+
return replaceInstUsesWith(I, IsLogical ? Builder.CreateLogicalOr(Res, Y)
3828+
: Builder.CreateOr(Res, Y));
3829+
// Op0 | (X || Y) --> X || (Op0 | Y)
3830+
if (Value *Res = foldBooleanAndOr(Op0, Y, I, /* IsAnd */ false,
3831+
/* IsLogical */ false))
3832+
return replaceInstUsesWith(I, IsLogical ? Builder.CreateLogicalOr(X, Res)
3833+
: Builder.CreateOr(X, Res));
3834+
}
3835+
if (match(Op0, m_OneUse(m_LogicalOr(m_Value(X), m_Value(Y))))) {
3836+
bool IsLogical = isa<SelectInst>(Op0);
3837+
// (X || Y) | Op1 --> (X || Op1) || Y
3838+
if (Value *Res = foldBooleanAndOr(X, Op1, I, /* IsAnd */ false, IsLogical))
3839+
return replaceInstUsesWith(I, IsLogical ? Builder.CreateLogicalOr(Res, Y)
3840+
: Builder.CreateOr(Res, Y));
3841+
// (X || Y) | Op1 --> X || (Y | Op1)
3842+
if (Value *Res = foldBooleanAndOr(Y, Op1, I, /* IsAnd */ false,
3843+
/* IsLogical */ false))
3844+
return replaceInstUsesWith(I, IsLogical ? Builder.CreateLogicalOr(X, Res)
3845+
: Builder.CreateOr(X, Res));
38743846
}
38753847

38763848
if (Instruction *FoldedFCmps = reassociateFCmps(I, Builder))

llvm/test/Transforms/InstCombine/and-fcmp.ll

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5044,11 +5044,9 @@ define i1 @isnormal_logical_select_0_fmf1(half %x) {
50445044

50455045
define i1 @and_fcmp_reassoc1(i1 %x, double %a, double %b) {
50465046
; CHECK-LABEL: @and_fcmp_reassoc1(
5047-
; CHECK-NEXT: [[TMP1:%.*]] = fcmp ult double [[A:%.*]], [[B:%.*]]
5048-
; CHECK-NEXT: [[CMP1:%.*]] = fcmp ugt double [[A]], [[B]]
5047+
; CHECK-NEXT: [[TMP1:%.*]] = fcmp uno double [[A:%.*]], [[B:%.*]]
50495048
; CHECK-NEXT: [[RETVAL:%.*]] = and i1 [[TMP1]], [[X:%.*]]
5050-
; CHECK-NEXT: [[RETVAL1:%.*]] = and i1 [[RETVAL]], [[CMP1]]
5051-
; CHECK-NEXT: ret i1 [[RETVAL1]]
5049+
; CHECK-NEXT: ret i1 [[RETVAL]]
50525050
;
50535051
%cmp = fcmp ult double %a, %b
50545052
%cmp1 = fcmp ugt double %a, %b
@@ -5059,11 +5057,9 @@ define i1 @and_fcmp_reassoc1(i1 %x, double %a, double %b) {
50595057

50605058
define i1 @and_fcmp_reassoc2(i1 %x, double %a, double %b) {
50615059
; CHECK-LABEL: @and_fcmp_reassoc2(
5062-
; CHECK-NEXT: [[TMP1:%.*]] = fcmp ult double [[A:%.*]], [[B:%.*]]
5063-
; CHECK-NEXT: [[CMP1:%.*]] = fcmp ugt double [[A]], [[B]]
5060+
; CHECK-NEXT: [[TMP1:%.*]] = fcmp uno double [[A:%.*]], [[B:%.*]]
50645061
; CHECK-NEXT: [[RETVAL:%.*]] = and i1 [[X:%.*]], [[TMP1]]
5065-
; CHECK-NEXT: [[RETVAL1:%.*]] = and i1 [[RETVAL]], [[CMP1]]
5066-
; CHECK-NEXT: ret i1 [[RETVAL1]]
5062+
; CHECK-NEXT: ret i1 [[RETVAL]]
50675063
;
50685064
%cmp = fcmp ult double %a, %b
50695065
%cmp1 = fcmp ugt double %a, %b
@@ -5074,11 +5070,9 @@ define i1 @and_fcmp_reassoc2(i1 %x, double %a, double %b) {
50745070

50755071
define i1 @and_fcmp_reassoc3(i1 %x, double %a, double %b) {
50765072
; CHECK-LABEL: @and_fcmp_reassoc3(
5077-
; CHECK-NEXT: [[TMP1:%.*]] = fcmp ult double [[A:%.*]], [[B:%.*]]
5078-
; CHECK-NEXT: [[CMP1:%.*]] = fcmp ugt double [[A]], [[B]]
5073+
; CHECK-NEXT: [[TMP1:%.*]] = fcmp uno double [[A:%.*]], [[B:%.*]]
50795074
; CHECK-NEXT: [[RETVAL:%.*]] = and i1 [[TMP1]], [[X:%.*]]
5080-
; CHECK-NEXT: [[RETVAL1:%.*]] = and i1 [[CMP1]], [[RETVAL]]
5081-
; CHECK-NEXT: ret i1 [[RETVAL1]]
5075+
; CHECK-NEXT: ret i1 [[RETVAL]]
50825076
;
50835077
%cmp = fcmp ult double %a, %b
50845078
%cmp1 = fcmp ugt double %a, %b
@@ -5089,11 +5083,9 @@ define i1 @and_fcmp_reassoc3(i1 %x, double %a, double %b) {
50895083

50905084
define i1 @and_fcmp_reassoc4(i1 %x, double %a, double %b) {
50915085
; CHECK-LABEL: @and_fcmp_reassoc4(
5092-
; CHECK-NEXT: [[TMP1:%.*]] = fcmp ult double [[A:%.*]], [[B:%.*]]
5093-
; CHECK-NEXT: [[CMP1:%.*]] = fcmp ugt double [[A]], [[B]]
5086+
; CHECK-NEXT: [[TMP1:%.*]] = fcmp uno double [[A:%.*]], [[B:%.*]]
50945087
; CHECK-NEXT: [[RETVAL:%.*]] = and i1 [[X:%.*]], [[TMP1]]
5095-
; CHECK-NEXT: [[RETVAL1:%.*]] = and i1 [[CMP1]], [[RETVAL]]
5096-
; CHECK-NEXT: ret i1 [[RETVAL1]]
5088+
; CHECK-NEXT: ret i1 [[RETVAL]]
50975089
;
50985090
%cmp = fcmp ult double %a, %b
50995091
%cmp1 = fcmp ugt double %a, %b

llvm/test/Transforms/InstCombine/or-fcmp.ll

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ define i1 @PR41069(double %a, double %b, double %c, double %d) {
5454
; CHECK-LABEL: @PR41069(
5555
; CHECK-NEXT: [[UNO1:%.*]] = fcmp uno double [[A:%.*]], [[B:%.*]]
5656
; CHECK-NEXT: [[TMP1:%.*]] = fcmp uno double [[D:%.*]], [[C:%.*]]
57-
; CHECK-NEXT: [[R:%.*]] = or i1 [[TMP1]], [[UNO1]]
57+
; CHECK-NEXT: [[R:%.*]] = or i1 [[UNO1]], [[TMP1]]
5858
; CHECK-NEXT: ret i1 [[R]]
5959
;
6060
%uno1 = fcmp uno double %a, %b
@@ -87,7 +87,7 @@ define i1 @PR41069_commute(double %a, double %b, double %c, double %d) {
8787
; CHECK-LABEL: @PR41069_commute(
8888
; CHECK-NEXT: [[UNO1:%.*]] = fcmp uno double [[A:%.*]], [[B:%.*]]
8989
; CHECK-NEXT: [[TMP1:%.*]] = fcmp uno double [[D:%.*]], [[C:%.*]]
90-
; CHECK-NEXT: [[R:%.*]] = or i1 [[TMP1]], [[UNO1]]
90+
; CHECK-NEXT: [[R:%.*]] = or i1 [[UNO1]], [[TMP1]]
9191
; CHECK-NEXT: ret i1 [[R]]
9292
;
9393
%uno1 = fcmp uno double %a, %b
@@ -4608,11 +4608,9 @@ define i1 @intersect_fmf_4(double %a, double %b) {
46084608

46094609
define i1 @or_fcmp_reassoc1(i1 %x, double %a, double %b) {
46104610
; CHECK-LABEL: @or_fcmp_reassoc1(
4611-
; CHECK-NEXT: [[OR:%.*]] = fcmp olt double [[A:%.*]], [[B:%.*]]
4612-
; CHECK-NEXT: [[CMP2:%.*]] = fcmp ogt double [[A]], [[B]]
4611+
; CHECK-NEXT: [[OR:%.*]] = fcmp one double [[A:%.*]], [[B:%.*]]
46134612
; CHECK-NEXT: [[RETVAL:%.*]] = or i1 [[OR]], [[CMP1:%.*]]
4614-
; CHECK-NEXT: [[RETVAL1:%.*]] = or i1 [[RETVAL]], [[CMP2]]
4615-
; CHECK-NEXT: ret i1 [[RETVAL1]]
4613+
; CHECK-NEXT: ret i1 [[RETVAL]]
46164614
;
46174615
%cmp = fcmp olt double %a, %b
46184616
%cmp1 = fcmp ogt double %a, %b
@@ -4623,11 +4621,9 @@ define i1 @or_fcmp_reassoc1(i1 %x, double %a, double %b) {
46234621

46244622
define i1 @or_fcmp_reassoc2(i1 %x, double %a, double %b) {
46254623
; CHECK-LABEL: @or_fcmp_reassoc2(
4626-
; CHECK-NEXT: [[TMP1:%.*]] = fcmp olt double [[A:%.*]], [[B:%.*]]
4627-
; CHECK-NEXT: [[CMP1:%.*]] = fcmp ogt double [[A]], [[B]]
4624+
; CHECK-NEXT: [[TMP1:%.*]] = fcmp one double [[A:%.*]], [[B:%.*]]
46284625
; CHECK-NEXT: [[RETVAL:%.*]] = or i1 [[X:%.*]], [[TMP1]]
4629-
; CHECK-NEXT: [[RETVAL1:%.*]] = or i1 [[RETVAL]], [[CMP1]]
4630-
; CHECK-NEXT: ret i1 [[RETVAL1]]
4626+
; CHECK-NEXT: ret i1 [[RETVAL]]
46314627
;
46324628
%cmp = fcmp olt double %a, %b
46334629
%cmp1 = fcmp ogt double %a, %b
@@ -4638,11 +4634,9 @@ define i1 @or_fcmp_reassoc2(i1 %x, double %a, double %b) {
46384634

46394635
define i1 @or_fcmp_reassoc3(i1 %x, double %a, double %b) {
46404636
; CHECK-LABEL: @or_fcmp_reassoc3(
4641-
; CHECK-NEXT: [[TMP1:%.*]] = fcmp olt double [[A:%.*]], [[B:%.*]]
4642-
; CHECK-NEXT: [[CMP1:%.*]] = fcmp ogt double [[A]], [[B]]
4637+
; CHECK-NEXT: [[TMP1:%.*]] = fcmp one double [[A:%.*]], [[B:%.*]]
46434638
; CHECK-NEXT: [[RETVAL:%.*]] = or i1 [[TMP1]], [[X:%.*]]
4644-
; CHECK-NEXT: [[RETVAL1:%.*]] = or i1 [[CMP1]], [[RETVAL]]
4645-
; CHECK-NEXT: ret i1 [[RETVAL1]]
4639+
; CHECK-NEXT: ret i1 [[RETVAL]]
46464640
;
46474641
%cmp = fcmp olt double %a, %b
46484642
%cmp1 = fcmp ogt double %a, %b
@@ -4653,11 +4647,9 @@ define i1 @or_fcmp_reassoc3(i1 %x, double %a, double %b) {
46534647

46544648
define i1 @or_fcmp_reassoc4(i1 %x, double %a, double %b) {
46554649
; CHECK-LABEL: @or_fcmp_reassoc4(
4656-
; CHECK-NEXT: [[TMP1:%.*]] = fcmp olt double [[A:%.*]], [[B:%.*]]
4657-
; CHECK-NEXT: [[CMP1:%.*]] = fcmp ogt double [[A]], [[B]]
4650+
; CHECK-NEXT: [[TMP1:%.*]] = fcmp one double [[A:%.*]], [[B:%.*]]
46584651
; CHECK-NEXT: [[RETVAL:%.*]] = or i1 [[X:%.*]], [[TMP1]]
4659-
; CHECK-NEXT: [[RETVAL1:%.*]] = or i1 [[CMP1]], [[RETVAL]]
4660-
; CHECK-NEXT: ret i1 [[RETVAL1]]
4652+
; CHECK-NEXT: ret i1 [[RETVAL]]
46614653
;
46624654
%cmp = fcmp olt double %a, %b
46634655
%cmp1 = fcmp ogt double %a, %b

0 commit comments

Comments
 (0)