diff --git a/lib/Analysis/InstructionSimplify.cpp b/lib/Analysis/InstructionSimplify.cpp index 78ae0abf2a1..76af3dcd90e 100644 --- a/lib/Analysis/InstructionSimplify.cpp +++ b/lib/Analysis/InstructionSimplify.cpp @@ -1550,7 +1550,44 @@ static Value *simplifyOrOfICmps(ICmpInst *Op0, ICmpInst *Op1) { return nullptr; } -static Value *simplifyAndOrOfICmps(Value *Op0, Value *Op1, bool IsAnd) { +static Value *simplifyAndOrOfFCmps(FCmpInst *LHS, FCmpInst *RHS, bool IsAnd) { + Value *LHS0 = LHS->getOperand(0), *LHS1 = LHS->getOperand(1); + Value *RHS0 = RHS->getOperand(0), *RHS1 = RHS->getOperand(1); + if (LHS0->getType() != RHS0->getType()) + return nullptr; + + FCmpInst::Predicate PredL = LHS->getPredicate(), PredR = RHS->getPredicate(); + if ((PredL == FCmpInst::FCMP_ORD && PredR == FCmpInst::FCMP_ORD && IsAnd) || + (PredL == FCmpInst::FCMP_UNO && PredR == FCmpInst::FCMP_UNO && !IsAnd)) { + // (fcmp ord NNAN, X) & (fcmp ord X, Y) --> fcmp ord X, Y + // (fcmp ord NNAN, X) & (fcmp ord Y, X) --> fcmp ord Y, X + // (fcmp ord X, NNAN) & (fcmp ord X, Y) --> fcmp ord X, Y + // (fcmp ord X, NNAN) & (fcmp ord Y, X) --> fcmp ord Y, X + // (fcmp uno NNAN, X) | (fcmp uno X, Y) --> fcmp uno X, Y + // (fcmp uno NNAN, X) | (fcmp uno Y, X) --> fcmp uno Y, X + // (fcmp uno X, NNAN) | (fcmp uno X, Y) --> fcmp uno X, Y + // (fcmp uno X, NNAN) | (fcmp uno Y, X) --> fcmp uno Y, X + if ((isKnownNeverNaN(LHS0) && (LHS1 == RHS0 || LHS1 == RHS1)) || + (isKnownNeverNaN(LHS1) && (LHS0 == RHS0 || LHS0 == RHS1))) + return RHS; + + // (fcmp ord X, Y) & (fcmp ord NNAN, X) --> fcmp ord X, Y + // (fcmp ord Y, X) & (fcmp ord NNAN, X) --> fcmp ord Y, X + // (fcmp ord X, Y) & (fcmp ord X, NNAN) --> fcmp ord X, Y + // (fcmp ord Y, X) & (fcmp ord X, NNAN) --> fcmp ord Y, X + // (fcmp uno X, Y) | (fcmp uno NNAN, X) --> fcmp uno X, Y + // (fcmp uno Y, X) | (fcmp uno NNAN, X) --> fcmp uno Y, X + // (fcmp uno X, Y) | (fcmp uno X, NNAN) --> fcmp uno X, Y + // (fcmp uno Y, X) | (fcmp uno X, NNAN) --> fcmp uno Y, X + if ((isKnownNeverNaN(RHS0) && (RHS1 == LHS0 || RHS1 == LHS1)) || + (isKnownNeverNaN(RHS1) && (RHS0 == LHS0 || RHS0 == LHS1))) + return LHS; + } + + return nullptr; +} + +static Value *simplifyAndOrOfCmps(Value *Op0, Value *Op1, bool IsAnd) { // Look through casts of the 'and' operands to find compares. auto *Cast0 = dyn_cast(Op0); auto *Cast1 = dyn_cast(Op1); @@ -1560,13 +1597,18 @@ static Value *simplifyAndOrOfICmps(Value *Op0, Value *Op1, bool IsAnd) { Op1 = Cast1->getOperand(0); } - auto *Cmp0 = dyn_cast(Op0); - auto *Cmp1 = dyn_cast(Op1); - if (!Cmp0 || !Cmp1) - return nullptr; + Value *V = nullptr; + auto *ICmp0 = dyn_cast(Op0); + auto *ICmp1 = dyn_cast(Op1); + if (ICmp0 && ICmp1) + V = IsAnd ? simplifyAndOfICmps(ICmp0, ICmp1) : + simplifyOrOfICmps(ICmp0, ICmp1); + + auto *FCmp0 = dyn_cast(Op0); + auto *FCmp1 = dyn_cast(Op1); + if (FCmp0 && FCmp1) + V = simplifyAndOrOfFCmps(FCmp0, FCmp1, IsAnd); - Value *V = - IsAnd ? simplifyAndOfICmps(Cmp0, Cmp1) : simplifyOrOfICmps(Cmp0, Cmp1); if (!V) return nullptr; if (!Cast0) @@ -1645,7 +1687,7 @@ static Value *SimplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q, return Op1; } - if (Value *V = simplifyAndOrOfICmps(Op0, Op1, true)) + if (Value *V = simplifyAndOrOfCmps(Op0, Op1, true)) return V; // Try some generic simplifications for associative operations. @@ -1766,7 +1808,7 @@ static Value *SimplifyOrInst(Value *Op0, Value *Op1, const SimplifyQuery &Q, match(Op0, m_c_Xor(m_Not(m_Specific(A)), m_Specific(B))))) return Op0; - if (Value *V = simplifyAndOrOfICmps(Op0, Op1, false)) + if (Value *V = simplifyAndOrOfCmps(Op0, Op1, false)) return V; // Try some generic simplifications for associative operations. diff --git a/test/Transforms/InstSimplify/logic-of-fcmps.ll b/test/Transforms/InstSimplify/logic-of-fcmps.ll index 37e6a90d2af..e1288e52dda 100644 --- a/test/Transforms/InstSimplify/logic-of-fcmps.ll +++ b/test/Transforms/InstSimplify/logic-of-fcmps.ll @@ -5,10 +5,8 @@ define i1 @ord1(float %x, float %y) { ; CHECK-LABEL: @ord1( -; CHECK-NEXT: [[CMP1:%.*]] = fcmp ord float 0.000000e+00, %x ; CHECK-NEXT: [[CMP2:%.*]] = fcmp ord float %x, %y -; CHECK-NEXT: [[R:%.*]] = and i1 [[CMP1]], [[CMP2]] -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 [[CMP2]] ; %cmp1 = fcmp ord float 0.0, %x %cmp2 = fcmp ord float %x, %y @@ -18,10 +16,8 @@ define i1 @ord1(float %x, float %y) { define i1 @ord2(double %x, double %y) { ; CHECK-LABEL: @ord2( -; CHECK-NEXT: [[CMP1:%.*]] = fcmp ord double 4.200000e+01, %x ; CHECK-NEXT: [[CMP2:%.*]] = fcmp ord double %y, %x -; CHECK-NEXT: [[R:%.*]] = and i1 [[CMP1]], [[CMP2]] -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 [[CMP2]] ; %cmp1 = fcmp ord double 42.0, %x %cmp2 = fcmp ord double %y, %x @@ -31,10 +27,8 @@ define i1 @ord2(double %x, double %y) { define <2 x i1> @ord3(<2 x float> %x, <2 x float> %y) { ; CHECK-LABEL: @ord3( -; CHECK-NEXT: [[CMP1:%.*]] = fcmp ord <2 x float> %x, zeroinitializer ; CHECK-NEXT: [[CMP2:%.*]] = fcmp ord <2 x float> %x, %y -; CHECK-NEXT: [[R:%.*]] = and <2 x i1> [[CMP1]], [[CMP2]] -; CHECK-NEXT: ret <2 x i1> [[R]] +; CHECK-NEXT: ret <2 x i1> [[CMP2]] ; %cmp1 = fcmp ord <2 x float> %x, zeroinitializer %cmp2 = fcmp ord <2 x float> %x, %y @@ -44,10 +38,8 @@ define <2 x i1> @ord3(<2 x float> %x, <2 x float> %y) { define <2 x i1> @ord4(<2 x double> %x, <2 x double> %y) { ; CHECK-LABEL: @ord4( -; CHECK-NEXT: [[CMP1:%.*]] = fcmp ord <2 x double> %x, ; CHECK-NEXT: [[CMP2:%.*]] = fcmp ord <2 x double> %y, %x -; CHECK-NEXT: [[R:%.*]] = and <2 x i1> [[CMP1]], [[CMP2]] -; CHECK-NEXT: ret <2 x i1> [[R]] +; CHECK-NEXT: ret <2 x i1> [[CMP2]] ; %cmp1 = fcmp ord <2 x double> %x, %cmp2 = fcmp ord <2 x double> %y, %x @@ -57,11 +49,8 @@ define <2 x i1> @ord4(<2 x double> %x, <2 x double> %y) { define i1 @ord5(float %x, float %y) { ; CHECK-LABEL: @ord5( -; CHECK-NEXT: [[NNAN:%.*]] = fdiv nnan float %x, %y ; CHECK-NEXT: [[CMP1:%.*]] = fcmp ord float %x, %y -; CHECK-NEXT: [[CMP2:%.*]] = fcmp ord float [[NNAN]], %x -; CHECK-NEXT: [[R:%.*]] = and i1 [[CMP1]], [[CMP2]] -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 [[CMP1]] ; %nnan = fdiv nnan float %x, %y %cmp1 = fcmp ord float %x, %y @@ -73,9 +62,7 @@ define i1 @ord5(float %x, float %y) { define i1 @ord6(double %x, double %y) { ; CHECK-LABEL: @ord6( ; CHECK-NEXT: [[CMP1:%.*]] = fcmp ord double %y, %x -; CHECK-NEXT: [[CMP2:%.*]] = fcmp ord double 4.200000e+01, %x -; CHECK-NEXT: [[R:%.*]] = and i1 [[CMP1]], [[CMP2]] -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 [[CMP1]] ; %cmp1 = fcmp ord double %y, %x %cmp2 = fcmp ord double 42.0, %x @@ -86,9 +73,7 @@ define i1 @ord6(double %x, double %y) { define <2 x i1> @ord7(<2 x float> %x, <2 x float> %y) { ; CHECK-LABEL: @ord7( ; CHECK-NEXT: [[CMP1:%.*]] = fcmp ord <2 x float> %x, %y -; CHECK-NEXT: [[CMP2:%.*]] = fcmp ord <2 x float> %x, zeroinitializer -; CHECK-NEXT: [[R:%.*]] = and <2 x i1> [[CMP1]], [[CMP2]] -; CHECK-NEXT: ret <2 x i1> [[R]] +; CHECK-NEXT: ret <2 x i1> [[CMP1]] ; %cmp1 = fcmp ord <2 x float> %x, %y %cmp2 = fcmp ord <2 x float> %x, zeroinitializer @@ -99,9 +84,7 @@ define <2 x i1> @ord7(<2 x float> %x, <2 x float> %y) { define <2 x i1> @ord8(<2 x double> %x, <2 x double> %y) { ; CHECK-LABEL: @ord8( ; CHECK-NEXT: [[CMP1:%.*]] = fcmp ord <2 x double> %y, %x -; CHECK-NEXT: [[CMP2:%.*]] = fcmp ord <2 x double> %x, -; CHECK-NEXT: [[R:%.*]] = and <2 x i1> [[CMP1]], [[CMP2]] -; CHECK-NEXT: ret <2 x i1> [[R]] +; CHECK-NEXT: ret <2 x i1> [[CMP1]] ; %cmp1 = fcmp ord <2 x double> %y, %x %cmp2 = fcmp ord <2 x double> %x, @@ -111,10 +94,8 @@ define <2 x i1> @ord8(<2 x double> %x, <2 x double> %y) { define i1 @uno1(float %x, float %y) { ; CHECK-LABEL: @uno1( -; CHECK-NEXT: [[CMP1:%.*]] = fcmp uno float 0.000000e+00, %x ; CHECK-NEXT: [[CMP2:%.*]] = fcmp uno float %x, %y -; CHECK-NEXT: [[R:%.*]] = or i1 [[CMP1]], [[CMP2]] -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 [[CMP2]] ; %cmp1 = fcmp uno float 0.0, %x %cmp2 = fcmp uno float %x, %y @@ -124,10 +105,8 @@ define i1 @uno1(float %x, float %y) { define i1 @uno2(double %x, double %y) { ; CHECK-LABEL: @uno2( -; CHECK-NEXT: [[CMP1:%.*]] = fcmp uno double 4.200000e+01, %x ; CHECK-NEXT: [[CMP2:%.*]] = fcmp uno double %y, %x -; CHECK-NEXT: [[R:%.*]] = or i1 [[CMP1]], [[CMP2]] -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 [[CMP2]] ; %cmp1 = fcmp uno double 42.0, %x %cmp2 = fcmp uno double %y, %x @@ -137,10 +116,8 @@ define i1 @uno2(double %x, double %y) { define <2 x i1> @uno3(<2 x float> %x, <2 x float> %y) { ; CHECK-LABEL: @uno3( -; CHECK-NEXT: [[CMP1:%.*]] = fcmp uno <2 x float> %x, zeroinitializer ; CHECK-NEXT: [[CMP2:%.*]] = fcmp uno <2 x float> %x, %y -; CHECK-NEXT: [[R:%.*]] = or <2 x i1> [[CMP1]], [[CMP2]] -; CHECK-NEXT: ret <2 x i1> [[R]] +; CHECK-NEXT: ret <2 x i1> [[CMP2]] ; %cmp1 = fcmp uno <2 x float> %x, zeroinitializer %cmp2 = fcmp uno <2 x float> %x, %y @@ -150,10 +127,8 @@ define <2 x i1> @uno3(<2 x float> %x, <2 x float> %y) { define <2 x i1> @uno4(<2 x double> %x, <2 x double> %y) { ; CHECK-LABEL: @uno4( -; CHECK-NEXT: [[CMP1:%.*]] = fcmp uno <2 x double> %x, ; CHECK-NEXT: [[CMP2:%.*]] = fcmp uno <2 x double> %y, %x -; CHECK-NEXT: [[R:%.*]] = or <2 x i1> [[CMP1]], [[CMP2]] -; CHECK-NEXT: ret <2 x i1> [[R]] +; CHECK-NEXT: ret <2 x i1> [[CMP2]] ; %cmp1 = fcmp uno <2 x double> %x, %cmp2 = fcmp uno <2 x double> %y, %x @@ -164,9 +139,7 @@ define <2 x i1> @uno4(<2 x double> %x, <2 x double> %y) { define i1 @uno5(float %x, float %y) { ; CHECK-LABEL: @uno5( ; CHECK-NEXT: [[CMP1:%.*]] = fcmp uno float %x, %y -; CHECK-NEXT: [[CMP2:%.*]] = fcmp uno float 0.000000e+00, %x -; CHECK-NEXT: [[R:%.*]] = or i1 [[CMP1]], [[CMP2]] -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 [[CMP1]] ; %cmp1 = fcmp uno float %x, %y %cmp2 = fcmp uno float 0.0, %x @@ -177,9 +150,7 @@ define i1 @uno5(float %x, float %y) { define i1 @uno6(double %x, double %y) { ; CHECK-LABEL: @uno6( ; CHECK-NEXT: [[CMP1:%.*]] = fcmp uno double %y, %x -; CHECK-NEXT: [[CMP2:%.*]] = fcmp uno double 4.200000e+01, %x -; CHECK-NEXT: [[R:%.*]] = or i1 [[CMP1]], [[CMP2]] -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 [[CMP1]] ; %cmp1 = fcmp uno double %y, %x %cmp2 = fcmp uno double 42.0, %x @@ -189,11 +160,8 @@ define i1 @uno6(double %x, double %y) { define <2 x i1> @uno7(<2 x float> %x, <2 x float> %y) { ; CHECK-LABEL: @uno7( -; CHECK-NEXT: [[NNAN:%.*]] = fdiv nnan <2 x float> %x, %y ; CHECK-NEXT: [[CMP1:%.*]] = fcmp uno <2 x float> %x, %y -; CHECK-NEXT: [[CMP2:%.*]] = fcmp uno <2 x float> %x, [[NNAN]] -; CHECK-NEXT: [[R:%.*]] = or <2 x i1> [[CMP1]], [[CMP2]] -; CHECK-NEXT: ret <2 x i1> [[R]] +; CHECK-NEXT: ret <2 x i1> [[CMP1]] ; %nnan = fdiv nnan <2 x float> %x, %y %cmp1 = fcmp uno <2 x float> %x, %y @@ -205,9 +173,7 @@ define <2 x i1> @uno7(<2 x float> %x, <2 x float> %y) { define <2 x i1> @uno8(<2 x double> %x, <2 x double> %y) { ; CHECK-LABEL: @uno8( ; CHECK-NEXT: [[CMP1:%.*]] = fcmp uno <2 x double> %y, %x -; CHECK-NEXT: [[CMP2:%.*]] = fcmp uno <2 x double> %x, -; CHECK-NEXT: [[R:%.*]] = or <2 x i1> [[CMP1]], [[CMP2]] -; CHECK-NEXT: ret <2 x i1> [[R]] +; CHECK-NEXT: ret <2 x i1> [[CMP1]] ; %cmp1 = fcmp uno <2 x double> %y, %x %cmp2 = fcmp uno <2 x double> %x,