Skip to content

Commit acfa294

Browse files
author
Thorsten Schütt
authored
[GlobalIsel] Canonicalize G_FCMP (#108891)
As a side-effect, we start constant folding fcmps.
1 parent 942e872 commit acfa294

File tree

11 files changed

+412
-173
lines changed

11 files changed

+412
-173
lines changed

llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,7 @@ class CombinerHelper {
911911
const MachineInstr &BVMI, BuildFnTy &MatchInfo);
912912

913913
bool matchCanonicalizeICmp(const MachineInstr &MI, BuildFnTy &MatchInfo);
914+
bool matchCanonicalizeFCmp(const MachineInstr &MI, BuildFnTy &MatchInfo);
914915

915916
private:
916917
/// Checks for legality of an indexed variant of \p LdSt.
@@ -1029,6 +1030,8 @@ class CombinerHelper {
10291030

10301031
bool constantFoldICmp(const GICmp &ICmp, const GIConstant &LHSCst,
10311032
const GIConstant &RHSCst, BuildFnTy &MatchInfo);
1033+
bool constantFoldFCmp(const GFCmp &FCmp, const GFConstant &LHSCst,
1034+
const GFConstant &RHSCst, BuildFnTy &MatchInfo);
10321035
};
10331036
} // namespace llvm
10341037

llvm/include/llvm/CodeGen/GlobalISel/Utils.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,5 +632,44 @@ class GIConstant {
632632
const MachineRegisterInfo &MRI);
633633
};
634634

635+
/// An floating-point-like constant.
636+
///
637+
/// It abstracts over scalar, fixed-length vectors, and scalable vectors.
638+
/// In the common case, it provides a common API and feels like an APFloat,
639+
/// while still providing low-level access.
640+
/// It can be used for constant-folding.
641+
///
642+
/// bool isZero()
643+
/// abstracts over the kind.
644+
///
645+
/// switch(const.getKind())
646+
/// {
647+
/// }
648+
/// provides low-level access.
649+
class GFConstant {
650+
public:
651+
enum class GFConstantKind { Scalar, FixedVector, ScalableVector };
652+
653+
private:
654+
GFConstantKind Kind;
655+
SmallVector<APFloat> Values;
656+
657+
public:
658+
GFConstant(ArrayRef<APFloat> Values)
659+
: Kind(GFConstantKind::FixedVector), Values(Values) {};
660+
GFConstant(const APFloat &Value, GFConstantKind Kind) : Kind(Kind) {
661+
Values.push_back(Value);
662+
}
663+
664+
/// Returns the kind of of this constant, e.g, Scalar.
665+
GFConstantKind getKind() const { return Kind; }
666+
667+
/// Returns the value, if this constant is a scalar.
668+
APFloat getScalarValue() const;
669+
670+
static std::optional<GFConstant> getConstant(Register Const,
671+
const MachineRegisterInfo &MRI);
672+
};
673+
635674
} // End namespace llvm.
636675
#endif

llvm/include/llvm/Target/GlobalISel/Combine.td

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1921,8 +1921,15 @@ def canonicalize_icmp : GICombineRule<
19211921
[{ return Helper.matchCanonicalizeICmp(*${cmp}, ${matchinfo}); }]),
19221922
(apply [{ Helper.applyBuildFn(*${cmp}, ${matchinfo}); }])>;
19231923

1924-
def icmp_combines: GICombineGroup<[
1924+
def canonicalize_fcmp : GICombineRule<
1925+
(defs root:$root, build_fn_matchinfo:$matchinfo),
1926+
(match (G_FCMP $root, $pred, $lhs, $rhs):$cmp,
1927+
[{ return Helper.matchCanonicalizeFCmp(*${cmp}, ${matchinfo}); }]),
1928+
(apply [{ Helper.applyBuildFn(*${cmp}, ${matchinfo}); }])>;
1929+
1930+
def cmp_combines: GICombineGroup<[
19251931
canonicalize_icmp,
1932+
canonicalize_fcmp,
19261933
icmp_to_true_false_known_bits,
19271934
icmp_to_lhs_known_bits,
19281935
double_icmp_zero_and_combine,
@@ -1995,7 +2002,7 @@ def all_combines : GICombineGroup<[integer_reassoc_combines, trivial_combines,
19952002
combine_extracted_vector_load,
19962003
undef_combines, identity_combines, phi_combines,
19972004
simplify_add_to_sub, hoist_logic_op_with_same_opcode_hands, shifts_too_big,
1998-
reassocs, ptr_add_immed_chain, icmp_combines,
2005+
reassocs, ptr_add_immed_chain, cmp_combines,
19992006
shl_ashr_to_sext_inreg, sext_inreg_of_load,
20002007
width_reduction_combines, select_combines,
20012008
known_bits_simplifications,

llvm/lib/CodeGen/GlobalISel/CombinerHelperCompares.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,37 @@ bool CombinerHelper::constantFoldICmp(const GICmp &ICmp,
6060
return true;
6161
}
6262

63+
bool CombinerHelper::constantFoldFCmp(const GFCmp &FCmp,
64+
const GFConstant &LHSCst,
65+
const GFConstant &RHSCst,
66+
BuildFnTy &MatchInfo) {
67+
if (LHSCst.getKind() != GFConstant::GFConstantKind::Scalar)
68+
return false;
69+
70+
Register Dst = FCmp.getReg(0);
71+
LLT DstTy = MRI.getType(Dst);
72+
73+
if (!isConstantLegalOrBeforeLegalizer(DstTy))
74+
return false;
75+
76+
CmpInst::Predicate Pred = FCmp.getCond();
77+
APFloat LHS = LHSCst.getScalarValue();
78+
APFloat RHS = RHSCst.getScalarValue();
79+
80+
bool Result = FCmpInst::compare(LHS, RHS, Pred);
81+
82+
MatchInfo = [=](MachineIRBuilder &B) {
83+
if (Result)
84+
B.buildConstant(Dst, getICmpTrueVal(getTargetLowering(),
85+
/*IsVector=*/DstTy.isVector(),
86+
/*IsFP=*/true));
87+
else
88+
B.buildConstant(Dst, 0);
89+
};
90+
91+
return true;
92+
}
93+
6394
bool CombinerHelper::matchCanonicalizeICmp(const MachineInstr &MI,
6495
BuildFnTy &MatchInfo) {
6596
const GICmp *Cmp = cast<GICmp>(&MI);
@@ -84,3 +115,31 @@ bool CombinerHelper::matchCanonicalizeICmp(const MachineInstr &MI,
84115

85116
return false;
86117
}
118+
119+
bool CombinerHelper::matchCanonicalizeFCmp(const MachineInstr &MI,
120+
BuildFnTy &MatchInfo) {
121+
const GFCmp *Cmp = cast<GFCmp>(&MI);
122+
123+
Register Dst = Cmp->getReg(0);
124+
Register LHS = Cmp->getLHSReg();
125+
Register RHS = Cmp->getRHSReg();
126+
127+
CmpInst::Predicate Pred = Cmp->getCond();
128+
assert(CmpInst::isFPPredicate(Pred) && "Not an FP compare!");
129+
130+
if (auto CLHS = GFConstant::getConstant(LHS, MRI)) {
131+
if (auto CRHS = GFConstant::getConstant(RHS, MRI))
132+
return constantFoldFCmp(*Cmp, *CLHS, *CRHS, MatchInfo);
133+
134+
// If we have a constant, make sure it is on the RHS.
135+
std::swap(LHS, RHS);
136+
Pred = CmpInst::getSwappedPredicate(Pred);
137+
138+
MatchInfo = [=](MachineIRBuilder &B) {
139+
B.buildFCmp(Pred, Dst, LHS, RHS, Cmp->getFlags());
140+
};
141+
return true;
142+
}
143+
144+
return false;
145+
}

llvm/lib/CodeGen/GlobalISel/Utils.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2008,3 +2008,43 @@ llvm::GIConstant::getConstant(Register Const, const MachineRegisterInfo &MRI) {
20082008

20092009
return GIConstant(MayBeConstant->Value, GIConstantKind::Scalar);
20102010
}
2011+
2012+
APFloat llvm::GFConstant::getScalarValue() const {
2013+
assert(Kind == GFConstantKind::Scalar && "Expected scalar constant");
2014+
2015+
return Values[0];
2016+
}
2017+
2018+
std::optional<GFConstant>
2019+
llvm::GFConstant::getConstant(Register Const, const MachineRegisterInfo &MRI) {
2020+
MachineInstr *Constant = getDefIgnoringCopies(Const, MRI);
2021+
2022+
if (GSplatVector *Splat = dyn_cast<GSplatVector>(Constant)) {
2023+
std::optional<FPValueAndVReg> MayBeConstant =
2024+
getFConstantVRegValWithLookThrough(Splat->getScalarReg(), MRI);
2025+
if (!MayBeConstant)
2026+
return std::nullopt;
2027+
return GFConstant(MayBeConstant->Value, GFConstantKind::ScalableVector);
2028+
}
2029+
2030+
if (GBuildVector *Build = dyn_cast<GBuildVector>(Constant)) {
2031+
SmallVector<APFloat> Values;
2032+
unsigned NumSources = Build->getNumSources();
2033+
for (unsigned I = 0; I < NumSources; ++I) {
2034+
Register SrcReg = Build->getSourceReg(I);
2035+
std::optional<FPValueAndVReg> MayBeConstant =
2036+
getFConstantVRegValWithLookThrough(SrcReg, MRI);
2037+
if (!MayBeConstant)
2038+
return std::nullopt;
2039+
Values.push_back(MayBeConstant->Value);
2040+
}
2041+
return GFConstant(Values);
2042+
}
2043+
2044+
std::optional<FPValueAndVReg> MayBeConstant =
2045+
getFConstantVRegValWithLookThrough(Const, MRI);
2046+
if (!MayBeConstant)
2047+
return std::nullopt;
2048+
2049+
return GFConstant(MayBeConstant->Value, GFConstantKind::Scalar);
2050+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
2+
# RUN: llc -o - -mtriple=aarch64-unknown-unknown -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs %s | FileCheck %s --check-prefixes=CHECK
3+
4+
---
5+
name: test_fcmp_canon
6+
body: |
7+
bb.1:
8+
; CHECK-LABEL: name: test_fcmp_canon
9+
; CHECK: %lhs:_(s64) = G_FCONSTANT double 1.000000e+00
10+
; CHECK-NEXT: %rhs:_(s64) = COPY $x0
11+
; CHECK-NEXT: %res:_(s32) = afn G_FCMP floatpred(ole), %rhs(s64), %lhs
12+
; CHECK-NEXT: $w0 = COPY %res(s32)
13+
%lhs:_(s64) = G_FCONSTANT double 1.0
14+
%rhs:_(s64) = COPY $x0
15+
%res:_(s32) = afn G_FCMP floatpred(oge), %lhs(s64), %rhs
16+
$w0 = COPY %res(s32)
17+
...
18+
---
19+
name: test_fcmp_no_canon
20+
body: |
21+
bb.1:
22+
; CHECK-LABEL: name: test_fcmp_no_canon
23+
; CHECK: %lhs:_(s64) = COPY $x0
24+
; CHECK-NEXT: %rhs:_(s64) = G_FCONSTANT double 1.000000e+00
25+
; CHECK-NEXT: %res:_(s32) = afn G_FCMP floatpred(oge), %lhs(s64), %rhs
26+
; CHECK-NEXT: $w0 = COPY %res(s32)
27+
%lhs:_(s64) = COPY $x0
28+
%rhs:_(s64) = G_FCONSTANT double 1.0
29+
%res:_(s32) = afn G_FCMP floatpred(oge), %lhs(s64), %rhs
30+
$w0 = COPY %res(s32)
31+
...
32+
---
33+
name: test_fcmp_no_canon_bv
34+
body: |
35+
bb.1:
36+
; CHECK-LABEL: name: test_fcmp_no_canon_bv
37+
; CHECK: %opaque1:_(s64) = COPY $x0
38+
; CHECK-NEXT: %opaque2:_(s64) = COPY $x0
39+
; CHECK-NEXT: %const1:_(s64) = G_FCONSTANT double 1.000000e+00
40+
; CHECK-NEXT: %const2:_(s64) = G_FCONSTANT double 2.000000e+00
41+
; CHECK-NEXT: %lhs:_(<2 x s64>) = G_BUILD_VECTOR %const1(s64), %opaque2(s64)
42+
; CHECK-NEXT: %rhs:_(<2 x s64>) = G_BUILD_VECTOR %opaque1(s64), %const2(s64)
43+
; CHECK-NEXT: %res:_(<2 x s32>) = afn G_FCMP floatpred(oge), %lhs(<2 x s64>), %rhs
44+
; CHECK-NEXT: $x0 = COPY %res(<2 x s32>)
45+
%opaque1:_(s64) = COPY $x0
46+
%opaque2:_(s64) = COPY $x0
47+
%const1:_(s64) = G_FCONSTANT double 1.0
48+
%const2:_(s64) = G_FCONSTANT double 2.0
49+
%lhs:_(<2 x s64>) = G_BUILD_VECTOR %const1(s64), %opaque2(s64)
50+
%rhs:_(<2 x s64>) = G_BUILD_VECTOR %opaque1(s64), %const2(s64)
51+
%res:_(<2 x s32>) = afn G_FCMP floatpred(oge), %lhs(<2 x s64>), %rhs
52+
$x0 = COPY %res(<2 x s32>)
53+
...
54+
---
55+
name: test_fcmp_canon_bv
56+
body: |
57+
bb.1:
58+
; CHECK-LABEL: name: test_fcmp_canon_bv
59+
; CHECK: %opaque1:_(s64) = COPY $x0
60+
; CHECK-NEXT: %opaque2:_(s64) = COPY $x0
61+
; CHECK-NEXT: %const1:_(s64) = G_FCONSTANT double 1.000000e+00
62+
; CHECK-NEXT: %const2:_(s64) = G_FCONSTANT double 2.000000e+00
63+
; CHECK-NEXT: %lhs:_(<2 x s64>) = G_BUILD_VECTOR %const1(s64), %const2(s64)
64+
; CHECK-NEXT: %rhs:_(<2 x s64>) = G_BUILD_VECTOR %opaque1(s64), %opaque2(s64)
65+
; CHECK-NEXT: %res:_(<2 x s32>) = afn G_FCMP floatpred(ole), %rhs(<2 x s64>), %lhs
66+
; CHECK-NEXT: $x0 = COPY %res(<2 x s32>)
67+
%opaque1:_(s64) = COPY $x0
68+
%opaque2:_(s64) = COPY $x0
69+
%const1:_(s64) = G_FCONSTANT double 1.0
70+
%const2:_(s64) = G_FCONSTANT double 2.0
71+
%lhs:_(<2 x s64>) = G_BUILD_VECTOR %const1(s64), %const2(s64)
72+
%rhs:_(<2 x s64>) = G_BUILD_VECTOR %opaque1(s64), %opaque2(s64)
73+
%res:_(<2 x s32>) = afn G_FCMP floatpred(oge), %lhs(<2 x s64>), %rhs
74+
$x0 = COPY %res(<2 x s32>)
75+
...
76+
---
77+
name: test_fcmp_canon_splat
78+
body: |
79+
bb.1:
80+
; CHECK-LABEL: name: test_fcmp_canon_splat
81+
; CHECK: %const:_(s64) = G_FCONSTANT double 1.000000e+00
82+
; CHECK-NEXT: %lhs:_(<vscale x 2 x s64>) = G_SPLAT_VECTOR %const(s64)
83+
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x1
84+
; CHECK-NEXT: %rhs:_(<vscale x 2 x s64>) = G_SPLAT_VECTOR [[COPY]](s64)
85+
; CHECK-NEXT: %res:_(<vscale x 2 x s32>) = afn G_FCMP floatpred(ole), %rhs(<vscale x 2 x s64>), %lhs
86+
; CHECK-NEXT: %z:_(<vscale x 2 x s64>) = G_ZEXT %res(<vscale x 2 x s32>)
87+
; CHECK-NEXT: $z0 = COPY %z(<vscale x 2 x s64>)
88+
%const:_(s64) = G_FCONSTANT double 1.0
89+
%lhs:_(<vscale x 2 x s64>) = G_SPLAT_VECTOR %const:_(s64)
90+
%1:_(s64) = COPY $x1
91+
%rhs:_(<vscale x 2 x s64>) = G_SPLAT_VECTOR %1:_(s64)
92+
%res:_(<vscale x 2 x s32>) = afn G_FCMP floatpred(oge), %lhs(<vscale x 2 x s64>), %rhs
93+
%z:_(<vscale x 2 x s64>) = G_ZEXT %res
94+
$z0 = COPY %z(<vscale x 2 x s64>)
95+
...
96+
---
97+
name: test_fcmp_const
98+
body: |
99+
bb.1:
100+
; CHECK-LABEL: name: test_fcmp_const
101+
; CHECK: %res:_(s32) = G_CONSTANT i32 0
102+
; CHECK-NEXT: $w0 = COPY %res(s32)
103+
%lhs:_(s64) = G_FCONSTANT double 1.0
104+
%rhs:_(s64) = G_FCONSTANT double 2.0
105+
%res:_(s32) = afn G_FCMP floatpred(oge), %lhs(s64), %rhs
106+
$w0 = COPY %res(s32)
107+
...
108+
---
109+
name: test_fcmp_const_other
110+
body: |
111+
bb.1:
112+
; CHECK-LABEL: name: test_fcmp_const_other
113+
; CHECK: %res:_(s32) = G_CONSTANT i32 1
114+
; CHECK-NEXT: $w0 = COPY %res(s32)
115+
%lhs:_(s64) = G_FCONSTANT double 2.0
116+
%rhs:_(s64) = G_FCONSTANT double 1.0
117+
%res:_(s32) = afn G_FCMP floatpred(oge), %lhs(s64), %rhs
118+
$w0 = COPY %res(s32)
119+
...

0 commit comments

Comments
 (0)