Skip to content

Commit ec93e70

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 #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 9c928d0 commit ec93e70

File tree

3 files changed

+74
-118
lines changed

3 files changed

+74
-118
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

+56-84
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))
@@ -3827,48 +3816,31 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
38273816
foldBooleanAndOr(Op0, Op1, I, /*IsAnd=*/false, /*IsLogical=*/false))
38283817
return replaceInstUsesWith(I, Res);
38293818

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

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

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

+8-16
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

+10-18
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)