diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 93b601b22c3a3..01b0a089aab71 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -1857,27 +1857,31 @@ static Value *simplifyAndOrOfFCmps(const SimplifyQuery &Q, FCmpInst *LHS, return nullptr; FCmpInst::Predicate PredL = LHS->getPredicate(), PredR = RHS->getPredicate(); + auto AbsOrSelfLHS0 = m_CombineOr(m_Specific(LHS0), m_FAbs(m_Specific(LHS0))); if ((PredL == FCmpInst::FCMP_ORD || PredL == FCmpInst::FCMP_UNO) && ((FCmpInst::isOrdered(PredR) && IsAnd) || (FCmpInst::isUnordered(PredR) && !IsAnd))) { - // (fcmp ord X, 0) & (fcmp o** X, Y) --> fcmp o** X, Y - // (fcmp uno X, 0) & (fcmp o** X, Y) --> false - // (fcmp uno X, 0) | (fcmp u** X, Y) --> fcmp u** X, Y - // (fcmp ord X, 0) | (fcmp u** X, Y) --> true - if ((LHS0 == RHS0 || LHS0 == RHS1) && match(LHS1, m_PosZeroFP())) + // (fcmp ord X, 0) & (fcmp o** X/abs(X), Y) --> fcmp o** X/abs(X), Y + // (fcmp uno X, 0) & (fcmp o** X/abs(X), Y) --> false + // (fcmp uno X, 0) | (fcmp u** X/abs(X), Y) --> fcmp u** X/abs(X), Y + // (fcmp ord X, 0) | (fcmp u** X/abs(X), Y) --> true + if ((match(RHS0, AbsOrSelfLHS0) || match(RHS1, AbsOrSelfLHS0)) && + match(LHS1, m_PosZeroFP())) return FCmpInst::isOrdered(PredL) == FCmpInst::isOrdered(PredR) ? static_cast(RHS) : ConstantInt::getBool(LHS->getType(), !IsAnd); } + auto AbsOrSelfRHS0 = m_CombineOr(m_Specific(RHS0), m_FAbs(m_Specific(RHS0))); if ((PredR == FCmpInst::FCMP_ORD || PredR == FCmpInst::FCMP_UNO) && ((FCmpInst::isOrdered(PredL) && IsAnd) || (FCmpInst::isUnordered(PredL) && !IsAnd))) { - // (fcmp o** X, Y) & (fcmp ord X, 0) --> fcmp o** X, Y - // (fcmp o** X, Y) & (fcmp uno X, 0) --> false - // (fcmp u** X, Y) | (fcmp uno X, 0) --> fcmp u** X, Y - // (fcmp u** X, Y) | (fcmp ord X, 0) --> true - if ((RHS0 == LHS0 || RHS0 == LHS1) && match(RHS1, m_PosZeroFP())) + // (fcmp o** X/abs(X), Y) & (fcmp ord X, 0) --> fcmp o** X/abs(X), Y + // (fcmp o** X/abs(X), Y) & (fcmp uno X, 0) --> false + // (fcmp u** X/abs(X), Y) | (fcmp uno X, 0) --> fcmp u** X/abs(X), Y + // (fcmp u** X/abs(X), Y) | (fcmp ord X, 0) --> true + if ((match(LHS0, AbsOrSelfRHS0) || match(LHS1, AbsOrSelfRHS0)) && + match(RHS1, m_PosZeroFP())) return FCmpInst::isOrdered(PredL) == FCmpInst::isOrdered(PredR) ? static_cast(LHS) : ConstantInt::getBool(LHS->getType(), !IsAnd); diff --git a/llvm/test/CodeGen/AMDGPU/fp-classify.ll b/llvm/test/CodeGen/AMDGPU/fp-classify.ll index b1c8107c3d1dd..e7c425a2d2752 100644 --- a/llvm/test/CodeGen/AMDGPU/fp-classify.ll +++ b/llvm/test/CodeGen/AMDGPU/fp-classify.ll @@ -698,12 +698,9 @@ define amdgpu_kernel void @test_isfinite_pattern_4_f16(ptr addrspace(1) nocaptur ; SI-NEXT: s_mov_b32 s3, 0xf000 ; SI-NEXT: s_mov_b32 s2, -1 ; SI-NEXT: s_waitcnt lgkmcnt(0) -; SI-NEXT: v_cvt_f32_f16_e32 v0, s6 ; SI-NEXT: s_and_b32 s4, s6, 0x7fff -; SI-NEXT: v_cmp_o_f32_e32 vcc, v0, v0 ; SI-NEXT: s_cmpk_lt_i32 s4, 0x7c00 ; SI-NEXT: s_cselect_b64 s[4:5], -1, 0 -; SI-NEXT: s_and_b64 s[4:5], vcc, s[4:5] ; SI-NEXT: v_cndmask_b32_e64 v0, 0, 1, s[4:5] ; SI-NEXT: buffer_store_dword v0, off, s[0:3], 0 ; SI-NEXT: s_endpgm diff --git a/llvm/test/Transforms/InstCombine/create-class-from-logic-fcmp.ll b/llvm/test/Transforms/InstCombine/create-class-from-logic-fcmp.ll index 74a1e318d77ed..9a723e8bc89ff 100644 --- a/llvm/test/Transforms/InstCombine/create-class-from-logic-fcmp.ll +++ b/llvm/test/Transforms/InstCombine/create-class-from-logic-fcmp.ll @@ -990,7 +990,8 @@ define i1 @not_isnormalinf_or_inf(half %x) #0 { ; -> subnormal | zero | nan define i1 @not_isnormalinf_or_uno(half %x) #0 { ; CHECK-LABEL: @not_isnormalinf_or_uno( -; CHECK-NEXT: [[OR:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 243) +; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) +; CHECK-NEXT: [[OR:%.*]] = fcmp ult half [[FABS]], 0xH0400 ; CHECK-NEXT: ret i1 [[OR]] ; %fabs = call half @llvm.fabs.f16(half %x) @@ -1003,7 +1004,8 @@ define i1 @not_isnormalinf_or_uno(half %x) #0 { ; -> subnormal | zero | nan define i1 @not_isnormalinf_or_uno_nofabs(half %x) #0 { ; CHECK-LABEL: @not_isnormalinf_or_uno_nofabs( -; CHECK-NEXT: [[OR:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 243) +; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]]) +; CHECK-NEXT: [[OR:%.*]] = fcmp ult half [[FABS]], 0xH0400 ; CHECK-NEXT: ret i1 [[OR]] ; %fabs = call half @llvm.fabs.f16(half %x) diff --git a/llvm/test/Transforms/InstSimplify/logic-of-fcmps.ll b/llvm/test/Transforms/InstSimplify/logic-of-fcmps.ll index 3a8bf53b32cab..6aa0adb2f0e67 100644 --- a/llvm/test/Transforms/InstSimplify/logic-of-fcmps.ll +++ b/llvm/test/Transforms/InstSimplify/logic-of-fcmps.ll @@ -426,3 +426,68 @@ define i1 @olt_implies_olt_fail(float %x, float %y) { %ret = and i1 %olt, %olt2 ret i1 %ret } + +define i1 @and_ord_olt_abs(float %x, float %y) { +; CHECK-LABEL: @and_ord_olt_abs( +; CHECK-NEXT: [[ABSX:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]]) +; CHECK-NEXT: [[CMP2:%.*]] = fcmp olt float [[ABSX]], [[Y:%.*]] +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = fcmp ord float %x, 0.000000e+00 + %absx = call float @llvm.fabs.f32(float %x) + %cmp2 = fcmp olt float %absx, %y + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @and_ord_olt_abs_commuted1(float %x, float %y) { +; CHECK-LABEL: @and_ord_olt_abs_commuted1( +; CHECK-NEXT: [[ABSX:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]]) +; CHECK-NEXT: [[CMP2:%.*]] = fcmp olt float [[Y:%.*]], [[ABSX]] +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = fcmp ord float %x, 0.000000e+00 + %absx = call float @llvm.fabs.f32(float %x) + %cmp2 = fcmp olt float %y, %absx + %and = and i1 %cmp1, %cmp2 + ret i1 %and +} + +define i1 @and_ord_olt_abs_commuted2(float %x, float %y) { +; CHECK-LABEL: @and_ord_olt_abs_commuted2( +; CHECK-NEXT: [[ABSX:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]]) +; CHECK-NEXT: [[CMP2:%.*]] = fcmp olt float [[ABSX]], [[Y:%.*]] +; CHECK-NEXT: ret i1 [[CMP2]] +; + %cmp1 = fcmp ord float %x, 0.000000e+00 + %absx = call float @llvm.fabs.f32(float %x) + %cmp2 = fcmp olt float %absx, %y + %and = and i1 %cmp2, %cmp1 + ret i1 %and +} + +define i1 @or_ord_ult_abs(float %x, float %y) { +; CHECK-LABEL: @or_ord_ult_abs( +; CHECK-NEXT: ret i1 true +; + %cmp1 = fcmp ord float %x, 0.000000e+00 + %absx = call float @llvm.fabs.f32(float %x) + %cmp2 = fcmp ult float %absx, %y + %or = or i1 %cmp1, %cmp2 + ret i1 %or +} + +define i1 @and_ord_olt_absz(float %x, float %y, float %z) { +; CHECK-LABEL: @and_ord_olt_absz( +; CHECK-NEXT: [[CMP1:%.*]] = fcmp ord float [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: [[ABSZ:%.*]] = call float @llvm.fabs.f32(float [[Z:%.*]]) +; CHECK-NEXT: [[CMP2:%.*]] = fcmp olt float [[ABSZ]], [[Y:%.*]] +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]] +; CHECK-NEXT: ret i1 [[AND]] +; + %cmp1 = fcmp ord float %x, 0.000000e+00 + %absz = call float @llvm.fabs.f32(float %z) + %cmp2 = fcmp olt float %absz, %y + %and = and i1 %cmp1, %cmp2 + ret i1 %and +}