diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index e2eae7fb8327c..c6f14018a750f 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1465,11 +1465,15 @@ Value *InstCombinerImpl::foldLogicOfFCmps(FCmpInst *LHS, FCmpInst *RHS, // FCmp canonicalization ensures that (fcmp ord/uno X, X) and // (fcmp ord/uno X, C) will be transformed to (fcmp X, +0.0). - if (match(LHS1, m_PosZeroFP()) && match(RHS1, m_PosZeroFP())) + if (match(LHS1, m_PosZeroFP()) && match(RHS1, m_PosZeroFP())) { // Ignore the constants because they are obviously not NANs: // (fcmp ord x, 0.0) & (fcmp ord y, 0.0) -> (fcmp ord x, y) // (fcmp uno x, 0.0) | (fcmp uno y, 0.0) -> (fcmp uno x, y) + IRBuilder<>::FastMathFlagGuard FMFG(Builder); + Builder.setFastMathFlags(LHS->getFastMathFlags() & + RHS->getFastMathFlags()); return Builder.CreateFCmp(PredL, LHS0, RHS0); + } } if (IsAnd && stripSignOnlyFPOps(LHS0) == stripSignOnlyFPOps(RHS0)) { @@ -2728,47 +2732,31 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) { foldBooleanAndOr(Op0, Op1, I, /*IsAnd=*/true, /*IsLogical=*/false)) return replaceInstUsesWith(I, Res); - { - ICmpInst *LHS = dyn_cast(Op0); - ICmpInst *RHS = dyn_cast(Op1); - - // TODO: Base this on foldBooleanAndOr instead? - // TODO: Make this recursive; it's a little tricky because an arbitrary - // number of 'and' instructions might have to be created. - if (LHS && match(Op1, m_OneUse(m_LogicalAnd(m_Value(X), m_Value(Y))))) { - bool IsLogical = isa(Op1); - // LHS & (X && Y) --> (LHS && X) && Y - if (auto *Cmp = dyn_cast(X)) - if (Value *Res = - foldAndOrOfICmps(LHS, Cmp, I, /* IsAnd */ true, IsLogical)) - return replaceInstUsesWith(I, IsLogical - ? Builder.CreateLogicalAnd(Res, Y) - : Builder.CreateAnd(Res, Y)); - // LHS & (X && Y) --> X && (LHS & Y) - if (auto *Cmp = dyn_cast(Y)) - if (Value *Res = foldAndOrOfICmps(LHS, Cmp, I, /* IsAnd */ true, - /* IsLogical */ false)) - return replaceInstUsesWith(I, IsLogical - ? Builder.CreateLogicalAnd(X, Res) - : Builder.CreateAnd(X, Res)); - } - if (RHS && match(Op0, m_OneUse(m_LogicalAnd(m_Value(X), m_Value(Y))))) { - bool IsLogical = isa(Op0); - // (X && Y) & RHS --> (X && RHS) && Y - if (auto *Cmp = dyn_cast(X)) - if (Value *Res = - foldAndOrOfICmps(Cmp, RHS, I, /* IsAnd */ true, IsLogical)) - return replaceInstUsesWith(I, IsLogical - ? Builder.CreateLogicalAnd(Res, Y) - : Builder.CreateAnd(Res, Y)); - // (X && Y) & RHS --> X && (Y & RHS) - if (auto *Cmp = dyn_cast(Y)) - if (Value *Res = foldAndOrOfICmps(Cmp, RHS, I, /* IsAnd */ true, - /* IsLogical */ false)) - return replaceInstUsesWith(I, IsLogical - ? Builder.CreateLogicalAnd(X, Res) - : Builder.CreateAnd(X, Res)); - } + // TODO: Make this recursive; it's a little tricky because an arbitrary + // number of 'and' instructions might have to be created. + if (match(Op1, m_OneUse(m_LogicalAnd(m_Value(X), m_Value(Y))))) { + bool IsLogical = isa(Op1); + // Op0 & (X && Y) --> (Op0 && X) && Y + if (Value *Res = foldBooleanAndOr(Op0, X, I, /* IsAnd */ true, IsLogical)) + return replaceInstUsesWith(I, IsLogical ? Builder.CreateLogicalAnd(Res, Y) + : Builder.CreateAnd(Res, Y)); + // Op0 & (X && Y) --> X && (Op0 & Y) + if (Value *Res = foldBooleanAndOr(Op0, Y, I, /* IsAnd */ true, + /* IsLogical */ false)) + return replaceInstUsesWith(I, IsLogical ? Builder.CreateLogicalAnd(X, Res) + : Builder.CreateAnd(X, Res)); + } + if (match(Op0, m_OneUse(m_LogicalAnd(m_Value(X), m_Value(Y))))) { + bool IsLogical = isa(Op0); + // (X && Y) & Op1 --> (X && Op1) && Y + if (Value *Res = foldBooleanAndOr(X, Op1, I, /* IsAnd */ true, IsLogical)) + return replaceInstUsesWith(I, IsLogical ? Builder.CreateLogicalAnd(Res, Y) + : Builder.CreateAnd(Res, Y)); + // (X && Y) & Op1 --> X && (Y & Op1) + if (Value *Res = foldBooleanAndOr(Y, Op1, I, /* IsAnd */ true, + /* IsLogical */ false)) + return replaceInstUsesWith(I, IsLogical ? Builder.CreateLogicalAnd(X, Res) + : Builder.CreateAnd(X, Res)); } if (Instruction *FoldedFCmps = reassociateFCmps(I, Builder)) @@ -3829,48 +3817,31 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) { foldBooleanAndOr(Op0, Op1, I, /*IsAnd=*/false, /*IsLogical=*/false)) return replaceInstUsesWith(I, Res); - { - ICmpInst *LHS = dyn_cast(Op0); - ICmpInst *RHS = dyn_cast(Op1); - - // TODO: Base this on foldBooleanAndOr instead? - // TODO: Make this recursive; it's a little tricky because an arbitrary - // number of 'or' instructions might have to be created. - Value *X, *Y; - if (LHS && match(Op1, m_OneUse(m_LogicalOr(m_Value(X), m_Value(Y))))) { - bool IsLogical = isa(Op1); - // LHS | (X || Y) --> (LHS || X) || Y - if (auto *Cmp = dyn_cast(X)) - if (Value *Res = - foldAndOrOfICmps(LHS, Cmp, I, /* IsAnd */ false, IsLogical)) - return replaceInstUsesWith(I, IsLogical - ? Builder.CreateLogicalOr(Res, Y) - : Builder.CreateOr(Res, Y)); - // LHS | (X || Y) --> X || (LHS | Y) - if (auto *Cmp = dyn_cast(Y)) - if (Value *Res = foldAndOrOfICmps(LHS, Cmp, I, /* IsAnd */ false, - /* IsLogical */ false)) - return replaceInstUsesWith(I, IsLogical - ? Builder.CreateLogicalOr(X, Res) - : Builder.CreateOr(X, Res)); - } - if (RHS && match(Op0, m_OneUse(m_LogicalOr(m_Value(X), m_Value(Y))))) { - bool IsLogical = isa(Op0); - // (X || Y) | RHS --> (X || RHS) || Y - if (auto *Cmp = dyn_cast(X)) - if (Value *Res = - foldAndOrOfICmps(Cmp, RHS, I, /* IsAnd */ false, IsLogical)) - return replaceInstUsesWith(I, IsLogical - ? Builder.CreateLogicalOr(Res, Y) - : Builder.CreateOr(Res, Y)); - // (X || Y) | RHS --> X || (Y | RHS) - if (auto *Cmp = dyn_cast(Y)) - if (Value *Res = foldAndOrOfICmps(Cmp, RHS, I, /* IsAnd */ false, - /* IsLogical */ false)) - return replaceInstUsesWith(I, IsLogical - ? Builder.CreateLogicalOr(X, Res) - : Builder.CreateOr(X, Res)); - } + // TODO: Make this recursive; it's a little tricky because an arbitrary + // number of 'or' instructions might have to be created. + if (match(Op1, m_OneUse(m_LogicalOr(m_Value(X), m_Value(Y))))) { + bool IsLogical = isa(Op1); + // Op0 | (X || Y) --> (Op0 || X) || Y + if (Value *Res = foldBooleanAndOr(Op0, X, I, /* IsAnd */ false, IsLogical)) + return replaceInstUsesWith(I, IsLogical ? Builder.CreateLogicalOr(Res, Y) + : Builder.CreateOr(Res, Y)); + // Op0 | (X || Y) --> X || (Op0 | Y) + if (Value *Res = foldBooleanAndOr(Op0, Y, I, /* IsAnd */ false, + /* IsLogical */ false)) + return replaceInstUsesWith(I, IsLogical ? Builder.CreateLogicalOr(X, Res) + : Builder.CreateOr(X, Res)); + } + if (match(Op0, m_OneUse(m_LogicalOr(m_Value(X), m_Value(Y))))) { + bool IsLogical = isa(Op0); + // (X || Y) | Op1 --> (X || Op1) || Y + if (Value *Res = foldBooleanAndOr(X, Op1, I, /* IsAnd */ false, IsLogical)) + return replaceInstUsesWith(I, IsLogical ? Builder.CreateLogicalOr(Res, Y) + : Builder.CreateOr(Res, Y)); + // (X || Y) | Op1 --> X || (Y | Op1) + if (Value *Res = foldBooleanAndOr(Y, Op1, I, /* IsAnd */ false, + /* IsLogical */ false)) + return replaceInstUsesWith(I, IsLogical ? Builder.CreateLogicalOr(X, Res) + : Builder.CreateOr(X, Res)); } if (Instruction *FoldedFCmps = reassociateFCmps(I, Builder)) diff --git a/llvm/test/Transforms/InstCombine/and-fcmp.ll b/llvm/test/Transforms/InstCombine/and-fcmp.ll index 30b9fca6e97ad..c7bbc8ab56f9a 100644 --- a/llvm/test/Transforms/InstCombine/and-fcmp.ll +++ b/llvm/test/Transforms/InstCombine/and-fcmp.ll @@ -5044,11 +5044,9 @@ define i1 @isnormal_logical_select_0_fmf1(half %x) { define i1 @and_fcmp_reassoc1(i1 %x, double %a, double %b) { ; CHECK-LABEL: @and_fcmp_reassoc1( -; CHECK-NEXT: [[TMP1:%.*]] = fcmp ult double [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[CMP1:%.*]] = fcmp ugt double [[A]], [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = fcmp uno double [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[RETVAL:%.*]] = and i1 [[TMP1]], [[X:%.*]] -; CHECK-NEXT: [[RETVAL1:%.*]] = and i1 [[RETVAL]], [[CMP1]] -; CHECK-NEXT: ret i1 [[RETVAL1]] +; CHECK-NEXT: ret i1 [[RETVAL]] ; %cmp = fcmp ult double %a, %b %cmp1 = fcmp ugt double %a, %b @@ -5059,11 +5057,9 @@ define i1 @and_fcmp_reassoc1(i1 %x, double %a, double %b) { define i1 @and_fcmp_reassoc2(i1 %x, double %a, double %b) { ; CHECK-LABEL: @and_fcmp_reassoc2( -; CHECK-NEXT: [[TMP1:%.*]] = fcmp ult double [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[CMP1:%.*]] = fcmp ugt double [[A]], [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = fcmp uno double [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[RETVAL:%.*]] = and i1 [[X:%.*]], [[TMP1]] -; CHECK-NEXT: [[RETVAL1:%.*]] = and i1 [[RETVAL]], [[CMP1]] -; CHECK-NEXT: ret i1 [[RETVAL1]] +; CHECK-NEXT: ret i1 [[RETVAL]] ; %cmp = fcmp ult double %a, %b %cmp1 = fcmp ugt double %a, %b @@ -5074,11 +5070,9 @@ define i1 @and_fcmp_reassoc2(i1 %x, double %a, double %b) { define i1 @and_fcmp_reassoc3(i1 %x, double %a, double %b) { ; CHECK-LABEL: @and_fcmp_reassoc3( -; CHECK-NEXT: [[TMP1:%.*]] = fcmp ult double [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[CMP1:%.*]] = fcmp ugt double [[A]], [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = fcmp uno double [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[RETVAL:%.*]] = and i1 [[TMP1]], [[X:%.*]] -; CHECK-NEXT: [[RETVAL1:%.*]] = and i1 [[CMP1]], [[RETVAL]] -; CHECK-NEXT: ret i1 [[RETVAL1]] +; CHECK-NEXT: ret i1 [[RETVAL]] ; %cmp = fcmp ult double %a, %b %cmp1 = fcmp ugt double %a, %b @@ -5089,11 +5083,9 @@ define i1 @and_fcmp_reassoc3(i1 %x, double %a, double %b) { define i1 @and_fcmp_reassoc4(i1 %x, double %a, double %b) { ; CHECK-LABEL: @and_fcmp_reassoc4( -; CHECK-NEXT: [[TMP1:%.*]] = fcmp ult double [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[CMP1:%.*]] = fcmp ugt double [[A]], [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = fcmp uno double [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[RETVAL:%.*]] = and i1 [[X:%.*]], [[TMP1]] -; CHECK-NEXT: [[RETVAL1:%.*]] = and i1 [[CMP1]], [[RETVAL]] -; CHECK-NEXT: ret i1 [[RETVAL1]] +; CHECK-NEXT: ret i1 [[RETVAL]] ; %cmp = fcmp ult double %a, %b %cmp1 = fcmp ugt double %a, %b diff --git a/llvm/test/Transforms/InstCombine/or-fcmp.ll b/llvm/test/Transforms/InstCombine/or-fcmp.ll index a2842f7a45f59..193fe4b5cc722 100644 --- a/llvm/test/Transforms/InstCombine/or-fcmp.ll +++ b/llvm/test/Transforms/InstCombine/or-fcmp.ll @@ -54,7 +54,7 @@ define i1 @PR41069(double %a, double %b, double %c, double %d) { ; CHECK-LABEL: @PR41069( ; CHECK-NEXT: [[UNO1:%.*]] = fcmp uno double [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[TMP1:%.*]] = fcmp uno double [[D:%.*]], [[C:%.*]] -; CHECK-NEXT: [[R:%.*]] = or i1 [[TMP1]], [[UNO1]] +; CHECK-NEXT: [[R:%.*]] = or i1 [[UNO1]], [[TMP1]] ; CHECK-NEXT: ret i1 [[R]] ; %uno1 = fcmp uno double %a, %b @@ -87,7 +87,7 @@ define i1 @PR41069_commute(double %a, double %b, double %c, double %d) { ; CHECK-LABEL: @PR41069_commute( ; CHECK-NEXT: [[UNO1:%.*]] = fcmp uno double [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[TMP1:%.*]] = fcmp uno double [[D:%.*]], [[C:%.*]] -; CHECK-NEXT: [[R:%.*]] = or i1 [[TMP1]], [[UNO1]] +; CHECK-NEXT: [[R:%.*]] = or i1 [[UNO1]], [[TMP1]] ; CHECK-NEXT: ret i1 [[R]] ; %uno1 = fcmp uno double %a, %b @@ -4608,11 +4608,9 @@ define i1 @intersect_fmf_4(double %a, double %b) { define i1 @or_fcmp_reassoc1(i1 %x, double %a, double %b) { ; CHECK-LABEL: @or_fcmp_reassoc1( -; CHECK-NEXT: [[OR:%.*]] = fcmp olt double [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[CMP2:%.*]] = fcmp ogt double [[A]], [[B]] +; CHECK-NEXT: [[OR:%.*]] = fcmp one double [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[RETVAL:%.*]] = or i1 [[OR]], [[CMP1:%.*]] -; CHECK-NEXT: [[RETVAL1:%.*]] = or i1 [[RETVAL]], [[CMP2]] -; CHECK-NEXT: ret i1 [[RETVAL1]] +; CHECK-NEXT: ret i1 [[RETVAL]] ; %cmp = fcmp olt double %a, %b %cmp1 = fcmp ogt double %a, %b @@ -4623,11 +4621,9 @@ define i1 @or_fcmp_reassoc1(i1 %x, double %a, double %b) { define i1 @or_fcmp_reassoc2(i1 %x, double %a, double %b) { ; CHECK-LABEL: @or_fcmp_reassoc2( -; CHECK-NEXT: [[TMP1:%.*]] = fcmp olt double [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[CMP1:%.*]] = fcmp ogt double [[A]], [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = fcmp one double [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[RETVAL:%.*]] = or i1 [[X:%.*]], [[TMP1]] -; CHECK-NEXT: [[RETVAL1:%.*]] = or i1 [[RETVAL]], [[CMP1]] -; CHECK-NEXT: ret i1 [[RETVAL1]] +; CHECK-NEXT: ret i1 [[RETVAL]] ; %cmp = fcmp olt double %a, %b %cmp1 = fcmp ogt double %a, %b @@ -4638,11 +4634,9 @@ define i1 @or_fcmp_reassoc2(i1 %x, double %a, double %b) { define i1 @or_fcmp_reassoc3(i1 %x, double %a, double %b) { ; CHECK-LABEL: @or_fcmp_reassoc3( -; CHECK-NEXT: [[TMP1:%.*]] = fcmp olt double [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[CMP1:%.*]] = fcmp ogt double [[A]], [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = fcmp one double [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[RETVAL:%.*]] = or i1 [[TMP1]], [[X:%.*]] -; CHECK-NEXT: [[RETVAL1:%.*]] = or i1 [[CMP1]], [[RETVAL]] -; CHECK-NEXT: ret i1 [[RETVAL1]] +; CHECK-NEXT: ret i1 [[RETVAL]] ; %cmp = fcmp olt double %a, %b %cmp1 = fcmp ogt double %a, %b @@ -4653,11 +4647,9 @@ define i1 @or_fcmp_reassoc3(i1 %x, double %a, double %b) { define i1 @or_fcmp_reassoc4(i1 %x, double %a, double %b) { ; CHECK-LABEL: @or_fcmp_reassoc4( -; CHECK-NEXT: [[TMP1:%.*]] = fcmp olt double [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[CMP1:%.*]] = fcmp ogt double [[A]], [[B]] +; CHECK-NEXT: [[TMP1:%.*]] = fcmp one double [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[RETVAL:%.*]] = or i1 [[X:%.*]], [[TMP1]] -; CHECK-NEXT: [[RETVAL1:%.*]] = or i1 [[CMP1]], [[RETVAL]] -; CHECK-NEXT: ret i1 [[RETVAL1]] +; CHECK-NEXT: ret i1 [[RETVAL]] ; %cmp = fcmp olt double %a, %b %cmp1 = fcmp ogt double %a, %b