Skip to content

Commit ca5ece8

Browse files
authored
[InstSimplify] Simplify fcmp implied by dominating fcmp (llvm#161090)
This patch simplifies an fcmp into true/false if it is implied by a dominating fcmp. As an initial support, it only handles two cases: + `fcmp pred1, X, Y -> fcmp pred2, X, Y`: use set operations. + `fcmp pred1, X, C1 -> fcmp pred2, X, C2`: use `ConstantFPRange` and set operations. Note: It doesn't fix llvm#70985, as the second fcmp in the motivating case is not dominated by the edge. We may need to adjust JumpThreading to handle this case. Comptime impact (~+0.1%): https://llvm-compile-time-tracker.com/compare.php?from=a728f213c863e4dd19f8969a417148d2951323c0&to=8ca70404fb0d66a824f39d83050ac38e2f1b25b9&stat=instructions:u IR diff: dtcxzyw/llvm-opt-benchmark#2848
1 parent 0338350 commit ca5ece8

File tree

5 files changed

+303
-14
lines changed

5 files changed

+303
-14
lines changed

llvm/lib/Analysis/InstructionSimplify.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4164,6 +4164,10 @@ static Value *simplifyFCmpInst(CmpPredicate Pred, Value *LHS, Value *RHS,
41644164
return ConstantInt::get(RetTy, Pred == CmpInst::FCMP_UNO);
41654165
}
41664166

4167+
if (std::optional<bool> Res =
4168+
isImpliedByDomCondition(Pred, LHS, RHS, Q.CxtI, Q.DL))
4169+
return ConstantInt::getBool(RetTy, *Res);
4170+
41674171
const APFloat *C = nullptr;
41684172
match(RHS, m_APFloatAllowPoison(C));
41694173
std::optional<KnownFPClass> FullKnownClassLHS;

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 89 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "llvm/IR/Attributes.h"
4040
#include "llvm/IR/BasicBlock.h"
4141
#include "llvm/IR/Constant.h"
42+
#include "llvm/IR/ConstantFPRange.h"
4243
#include "llvm/IR/ConstantRange.h"
4344
#include "llvm/IR/Constants.h"
4445
#include "llvm/IR/DerivedTypes.h"
@@ -9474,6 +9475,69 @@ isImpliedCondICmps(CmpPredicate LPred, const Value *L0, const Value *L1,
94749475
return std::nullopt;
94759476
}
94769477

9478+
/// Return true if LHS implies RHS (expanded to its components as "R0 RPred R1")
9479+
/// is true. Return false if LHS implies RHS is false. Otherwise, return
9480+
/// std::nullopt if we can't infer anything.
9481+
static std::optional<bool>
9482+
isImpliedCondFCmps(FCmpInst::Predicate LPred, const Value *L0, const Value *L1,
9483+
FCmpInst::Predicate RPred, const Value *R0, const Value *R1,
9484+
const DataLayout &DL, bool LHSIsTrue) {
9485+
// The rest of the logic assumes the LHS condition is true. If that's not the
9486+
// case, invert the predicate to make it so.
9487+
if (!LHSIsTrue)
9488+
LPred = FCmpInst::getInversePredicate(LPred);
9489+
9490+
// We can have non-canonical operands, so try to normalize any common operand
9491+
// to L0/R0.
9492+
if (L0 == R1) {
9493+
std::swap(R0, R1);
9494+
RPred = FCmpInst::getSwappedPredicate(RPred);
9495+
}
9496+
if (R0 == L1) {
9497+
std::swap(L0, L1);
9498+
LPred = FCmpInst::getSwappedPredicate(LPred);
9499+
}
9500+
if (L1 == R1) {
9501+
// If we have L0 == R0 and L1 == R1, then make L1/R1 the constants.
9502+
if (L0 != R0 || match(L0, m_ImmConstant())) {
9503+
std::swap(L0, L1);
9504+
LPred = ICmpInst::getSwappedCmpPredicate(LPred);
9505+
std::swap(R0, R1);
9506+
RPred = ICmpInst::getSwappedCmpPredicate(RPred);
9507+
}
9508+
}
9509+
9510+
// Can we infer anything when the two compares have matching operands?
9511+
if (L0 == R0 && L1 == R1) {
9512+
if ((LPred & RPred) == LPred)
9513+
return true;
9514+
if ((LPred & ~RPred) == LPred)
9515+
return false;
9516+
}
9517+
9518+
// See if we can infer anything if operand-0 matches and we have at least one
9519+
// constant.
9520+
const APFloat *L1C, *R1C;
9521+
if (L0 == R0 && match(L1, m_APFloat(L1C)) && match(R1, m_APFloat(R1C))) {
9522+
if (std::optional<ConstantFPRange> DomCR =
9523+
ConstantFPRange::makeExactFCmpRegion(LPred, *L1C)) {
9524+
if (std::optional<ConstantFPRange> ImpliedCR =
9525+
ConstantFPRange::makeExactFCmpRegion(RPred, *R1C)) {
9526+
if (ImpliedCR->contains(*DomCR))
9527+
return true;
9528+
}
9529+
if (std::optional<ConstantFPRange> ImpliedCR =
9530+
ConstantFPRange::makeExactFCmpRegion(
9531+
FCmpInst::getInversePredicate(RPred), *R1C)) {
9532+
if (ImpliedCR->contains(*DomCR))
9533+
return false;
9534+
}
9535+
}
9536+
}
9537+
9538+
return std::nullopt;
9539+
}
9540+
94779541
/// Return true if LHS implies RHS is true. Return false if LHS implies RHS is
94789542
/// false. Otherwise, return std::nullopt if we can't infer anything. We
94799543
/// expect the RHS to be an icmp and the LHS to be an 'and', 'or', or a 'select'
@@ -9529,15 +9593,24 @@ llvm::isImpliedCondition(const Value *LHS, CmpPredicate RHSPred,
95299593
LHSIsTrue = !LHSIsTrue;
95309594

95319595
// Both LHS and RHS are icmps.
9532-
if (const auto *LHSCmp = dyn_cast<ICmpInst>(LHS))
9533-
return isImpliedCondICmps(LHSCmp->getCmpPredicate(), LHSCmp->getOperand(0),
9534-
LHSCmp->getOperand(1), RHSPred, RHSOp0, RHSOp1,
9535-
DL, LHSIsTrue);
9536-
const Value *V;
9537-
if (match(LHS, m_NUWTrunc(m_Value(V))))
9538-
return isImpliedCondICmps(CmpInst::ICMP_NE, V,
9539-
ConstantInt::get(V->getType(), 0), RHSPred,
9540-
RHSOp0, RHSOp1, DL, LHSIsTrue);
9596+
if (RHSOp0->getType()->getScalarType()->isIntOrPtrTy()) {
9597+
if (const auto *LHSCmp = dyn_cast<ICmpInst>(LHS))
9598+
return isImpliedCondICmps(LHSCmp->getCmpPredicate(),
9599+
LHSCmp->getOperand(0), LHSCmp->getOperand(1),
9600+
RHSPred, RHSOp0, RHSOp1, DL, LHSIsTrue);
9601+
const Value *V;
9602+
if (match(LHS, m_NUWTrunc(m_Value(V))))
9603+
return isImpliedCondICmps(CmpInst::ICMP_NE, V,
9604+
ConstantInt::get(V->getType(), 0), RHSPred,
9605+
RHSOp0, RHSOp1, DL, LHSIsTrue);
9606+
} else {
9607+
assert(RHSOp0->getType()->isFPOrFPVectorTy() &&
9608+
"Expected floating point type only!");
9609+
if (const auto *LHSCmp = dyn_cast<FCmpInst>(LHS))
9610+
return isImpliedCondFCmps(LHSCmp->getPredicate(), LHSCmp->getOperand(0),
9611+
LHSCmp->getOperand(1), RHSPred, RHSOp0, RHSOp1,
9612+
DL, LHSIsTrue);
9613+
}
95419614

95429615
/// The LHS should be an 'or', 'and', or a 'select' instruction. We expect
95439616
/// the RHS to be an icmp.
@@ -9574,6 +9647,13 @@ std::optional<bool> llvm::isImpliedCondition(const Value *LHS, const Value *RHS,
95749647
return InvertRHS ? !*Implied : *Implied;
95759648
return std::nullopt;
95769649
}
9650+
if (const FCmpInst *RHSCmp = dyn_cast<FCmpInst>(RHS)) {
9651+
if (auto Implied = isImpliedCondition(
9652+
LHS, RHSCmp->getPredicate(), RHSCmp->getOperand(0),
9653+
RHSCmp->getOperand(1), DL, LHSIsTrue, Depth))
9654+
return InvertRHS ? !*Implied : *Implied;
9655+
return std::nullopt;
9656+
}
95779657

95789658
const Value *V;
95799659
if (match(RHS, m_NUWTrunc(m_Value(V)))) {

llvm/test/CodeGen/AMDGPU/sgpr-copy.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ endif: ; preds = %else, %if
256256
define amdgpu_kernel void @copy1(ptr addrspace(1) %out, ptr addrspace(1) %in0) {
257257
entry:
258258
%tmp = load float, ptr addrspace(1) %in0
259-
%tmp1 = fcmp oeq float %tmp, 0.000000e+00
259+
%tmp1 = fcmp one float %tmp, 0.000000e+00
260260
br i1 %tmp1, label %if0, label %endif
261261

262262
if0: ; preds = %entry

llvm/test/Transforms/InstCombine/clamp-to-minmax.ll

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,10 +172,8 @@ define float @clamp_negative_wrong_const(float %x) {
172172
; Like @clamp_test_1 but both are min
173173
define float @clamp_negative_same_op(float %x) {
174174
; CHECK-LABEL: @clamp_negative_same_op(
175-
; CHECK-NEXT: [[INNER_CMP_INV:%.*]] = fcmp fast oge float [[X:%.*]], 2.550000e+02
176-
; CHECK-NEXT: [[INNER_SEL:%.*]] = select nnan ninf i1 [[INNER_CMP_INV]], float 2.550000e+02, float [[X]]
177-
; CHECK-NEXT: [[OUTER_CMP:%.*]] = fcmp fast ult float [[X]], 1.000000e+00
178-
; CHECK-NEXT: [[R:%.*]] = select i1 [[OUTER_CMP]], float [[INNER_SEL]], float 1.000000e+00
175+
; CHECK-NEXT: [[OUTER_CMP_INV:%.*]] = fcmp fast oge float [[X:%.*]], 1.000000e+00
176+
; CHECK-NEXT: [[R:%.*]] = select nnan ninf i1 [[OUTER_CMP_INV]], float 1.000000e+00, float [[X]]
179177
; CHECK-NEXT: ret float [[R]]
180178
;
181179
%inner_cmp = fcmp fast ult float %x, 255.0

llvm/test/Transforms/InstSimplify/domcondition.ll

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,3 +278,210 @@ end:
278278
}
279279

280280
declare void @foo(i32)
281+
282+
283+
define i1 @simplify_fcmp_implied_by_dom_cond_range_true(float %x) {
284+
; CHECK-LABEL: @simplify_fcmp_implied_by_dom_cond_range_true(
285+
; CHECK-NEXT: [[CMP:%.*]] = fcmp olt float [[X:%.*]], 0.000000e+00
286+
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
287+
; CHECK: if.then:
288+
; CHECK-NEXT: ret i1 true
289+
; CHECK: if.else:
290+
; CHECK-NEXT: ret i1 false
291+
;
292+
%cmp = fcmp olt float %x, 0.0
293+
br i1 %cmp, label %if.then, label %if.else
294+
295+
if.then:
296+
%cmp2 = fcmp olt float %x, 1.0
297+
ret i1 %cmp2
298+
299+
if.else:
300+
ret i1 false
301+
}
302+
303+
define i1 @simplify_fcmp_in_else_implied_by_dom_cond_range_true(float %x) {
304+
; CHECK-LABEL: @simplify_fcmp_in_else_implied_by_dom_cond_range_true(
305+
; CHECK-NEXT: [[CMP:%.*]] = fcmp olt float [[X:%.*]], 1.000000e+00
306+
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
307+
; CHECK: if.then:
308+
; CHECK-NEXT: ret i1 true
309+
; CHECK: if.else:
310+
; CHECK-NEXT: ret i1 true
311+
;
312+
%cmp = fcmp olt float %x, 1.0
313+
br i1 %cmp, label %if.then, label %if.else
314+
315+
if.then:
316+
ret i1 true
317+
318+
if.else:
319+
%cmp2 = fcmp uge float %x, 0.5
320+
ret i1 %cmp2
321+
}
322+
323+
define i1 @simplify_fcmp_implied_by_dom_cond_range_false(float %x) {
324+
; CHECK-LABEL: @simplify_fcmp_implied_by_dom_cond_range_false(
325+
; CHECK-NEXT: [[CMP:%.*]] = fcmp olt float [[X:%.*]], 0.000000e+00
326+
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
327+
; CHECK: if.then:
328+
; CHECK-NEXT: ret i1 false
329+
; CHECK: if.else:
330+
; CHECK-NEXT: ret i1 false
331+
;
332+
%cmp = fcmp olt float %x, 0.0
333+
br i1 %cmp, label %if.then, label %if.else
334+
335+
if.then:
336+
%cmp2 = fcmp ogt float %x, 1.0
337+
ret i1 %cmp2
338+
339+
if.else:
340+
ret i1 false
341+
}
342+
343+
define i1 @simplify_fcmp_implied_by_dom_cond_pred_true(float %x, float %y) {
344+
; CHECK-LABEL: @simplify_fcmp_implied_by_dom_cond_pred_true(
345+
; CHECK-NEXT: [[CMP:%.*]] = fcmp olt float [[X:%.*]], [[Y:%.*]]
346+
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
347+
; CHECK: if.then:
348+
; CHECK-NEXT: ret i1 true
349+
; CHECK: if.else:
350+
; CHECK-NEXT: ret i1 false
351+
;
352+
%cmp = fcmp olt float %x, %y
353+
br i1 %cmp, label %if.then, label %if.else
354+
355+
if.then:
356+
%cmp2 = fcmp ole float %x, %y
357+
ret i1 %cmp2
358+
359+
if.else:
360+
ret i1 false
361+
}
362+
363+
define i1 @simplify_fcmp_implied_by_dom_cond_pred_false(float %x, float %y) {
364+
; CHECK-LABEL: @simplify_fcmp_implied_by_dom_cond_pred_false(
365+
; CHECK-NEXT: [[CMP:%.*]] = fcmp olt float [[X:%.*]], [[Y:%.*]]
366+
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
367+
; CHECK: if.then:
368+
; CHECK-NEXT: ret i1 false
369+
; CHECK: if.else:
370+
; CHECK-NEXT: ret i1 false
371+
;
372+
%cmp = fcmp olt float %x, %y
373+
br i1 %cmp, label %if.then, label %if.else
374+
375+
if.then:
376+
%cmp2 = fcmp ogt float %x, %y
377+
ret i1 %cmp2
378+
379+
if.else:
380+
ret i1 false
381+
}
382+
383+
define i1 @simplify_fcmp_implied_by_dom_cond_pred_commuted(float %x, float %y) {
384+
; CHECK-LABEL: @simplify_fcmp_implied_by_dom_cond_pred_commuted(
385+
; CHECK-NEXT: [[CMP:%.*]] = fcmp olt float [[X:%.*]], [[Y:%.*]]
386+
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
387+
; CHECK: if.then:
388+
; CHECK-NEXT: ret i1 true
389+
; CHECK: if.else:
390+
; CHECK-NEXT: ret i1 false
391+
;
392+
%cmp = fcmp olt float %x, %y
393+
br i1 %cmp, label %if.then, label %if.else
394+
395+
if.then:
396+
%cmp2 = fcmp oge float %y, %x
397+
ret i1 %cmp2
398+
399+
if.else:
400+
ret i1 false
401+
}
402+
403+
; Negative tests
404+
405+
define i1 @simplify_fcmp_implied_by_dom_cond_wrong_range(float %x) {
406+
; CHECK-LABEL: @simplify_fcmp_implied_by_dom_cond_wrong_range(
407+
; CHECK-NEXT: [[CMP:%.*]] = fcmp olt float [[X:%.*]], 0.000000e+00
408+
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
409+
; CHECK: if.then:
410+
; CHECK-NEXT: [[CMP2:%.*]] = fcmp olt float [[X]], -1.000000e+00
411+
; CHECK-NEXT: ret i1 [[CMP2]]
412+
; CHECK: if.else:
413+
; CHECK-NEXT: ret i1 false
414+
;
415+
%cmp = fcmp olt float %x, 0.0
416+
br i1 %cmp, label %if.then, label %if.else
417+
418+
if.then:
419+
%cmp2 = fcmp olt float %x, -1.0
420+
ret i1 %cmp2
421+
422+
if.else:
423+
ret i1 false
424+
}
425+
426+
define i1 @simplify_fcmp_implied_by_dom_cond_range_mismatched_operand(float %x, float %y) {
427+
; CHECK-LABEL: @simplify_fcmp_implied_by_dom_cond_range_mismatched_operand(
428+
; CHECK-NEXT: [[CMP:%.*]] = fcmp olt float [[X:%.*]], 0.000000e+00
429+
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
430+
; CHECK: if.then:
431+
; CHECK-NEXT: [[CMP2:%.*]] = fcmp olt float [[Y:%.*]], 1.000000e+00
432+
; CHECK-NEXT: ret i1 [[CMP2]]
433+
; CHECK: if.else:
434+
; CHECK-NEXT: ret i1 false
435+
;
436+
%cmp = fcmp olt float %x, 0.0
437+
br i1 %cmp, label %if.then, label %if.else
438+
439+
if.then:
440+
%cmp2 = fcmp olt float %y, 1.0
441+
ret i1 %cmp2
442+
443+
if.else:
444+
ret i1 false
445+
}
446+
447+
define i1 @simplify_fcmp_implied_by_dom_cond_wrong_pred(float %x, float %y) {
448+
; CHECK-LABEL: @simplify_fcmp_implied_by_dom_cond_wrong_pred(
449+
; CHECK-NEXT: [[CMP:%.*]] = fcmp ole float [[X:%.*]], [[Y:%.*]]
450+
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
451+
; CHECK: if.then:
452+
; CHECK-NEXT: [[CMP2:%.*]] = fcmp olt float [[X]], [[Y]]
453+
; CHECK-NEXT: ret i1 [[CMP2]]
454+
; CHECK: if.else:
455+
; CHECK-NEXT: ret i1 false
456+
;
457+
%cmp = fcmp ole float %x, %y
458+
br i1 %cmp, label %if.then, label %if.else
459+
460+
if.then:
461+
%cmp2 = fcmp olt float %x, %y
462+
ret i1 %cmp2
463+
464+
if.else:
465+
ret i1 false
466+
}
467+
468+
define i1 @simplify_fcmp_implied_by_dom_cond_pred_mismatched_operand(float %x, float %y, float %z) {
469+
; CHECK-LABEL: @simplify_fcmp_implied_by_dom_cond_pred_mismatched_operand(
470+
; CHECK-NEXT: [[CMP:%.*]] = fcmp olt float [[X:%.*]], [[Y:%.*]]
471+
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
472+
; CHECK: if.then:
473+
; CHECK-NEXT: [[CMP2:%.*]] = fcmp ole float [[X]], [[Z:%.*]]
474+
; CHECK-NEXT: ret i1 [[CMP2]]
475+
; CHECK: if.else:
476+
; CHECK-NEXT: ret i1 false
477+
;
478+
%cmp = fcmp olt float %x, %y
479+
br i1 %cmp, label %if.then, label %if.else
480+
481+
if.then:
482+
%cmp2 = fcmp ole float %x, %z
483+
ret i1 %cmp2
484+
485+
if.else:
486+
ret i1 false
487+
}

0 commit comments

Comments
 (0)