Skip to content
This repository was archived by the owner on Sep 15, 2025. It is now read-only.

Commit 87f6717

Browse files
authored
[RISCV] Use FLI + FNEG to materialize some negative FP constants (llvm#70825)
Most of the FP constants supported by FLI are positive. For negative FP constants X whose positive values is supported by FLI, we can use `(FNEG (FLI -X))` to materialize X.
1 parent 4fbbb7a commit 87f6717

File tree

6 files changed

+54
-32
lines changed

6 files changed

+54
-32
lines changed

llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -857,26 +857,34 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
857857
}
858858
case ISD::ConstantFP: {
859859
const APFloat &APF = cast<ConstantFPSDNode>(Node)->getValueAPF();
860-
int FPImm = static_cast<const RISCVTargetLowering *>(TLI)->getLegalZfaFPImm(
861-
APF, VT);
860+
auto [FPImm, NeedsFNeg] =
861+
static_cast<const RISCVTargetLowering *>(TLI)->getLegalZfaFPImm(APF,
862+
VT);
862863
if (FPImm >= 0) {
863864
unsigned Opc;
865+
unsigned FNegOpc;
864866
switch (VT.SimpleTy) {
865867
default:
866868
llvm_unreachable("Unexpected size");
867869
case MVT::f16:
868870
Opc = RISCV::FLI_H;
871+
FNegOpc = RISCV::FSGNJN_H;
869872
break;
870873
case MVT::f32:
871874
Opc = RISCV::FLI_S;
875+
FNegOpc = RISCV::FSGNJN_S;
872876
break;
873877
case MVT::f64:
874878
Opc = RISCV::FLI_D;
879+
FNegOpc = RISCV::FSGNJN_D;
875880
break;
876881
}
877-
878882
SDNode *Res = CurDAG->getMachineNode(
879883
Opc, DL, VT, CurDAG->getTargetConstant(FPImm, DL, XLenVT));
884+
if (NeedsFNeg)
885+
Res = CurDAG->getMachineNode(FNegOpc, DL, VT, SDValue(Res, 0),
886+
SDValue(Res, 0));
887+
880888
ReplaceNode(Node, Res);
881889
return;
882890
}
@@ -3200,8 +3208,12 @@ bool RISCVDAGToDAGISel::selectFPImm(SDValue N, SDValue &Imm) {
32003208

32013209
MVT VT = CFP->getSimpleValueType(0);
32023210

3203-
if (static_cast<const RISCVTargetLowering *>(TLI)->getLegalZfaFPImm(APF,
3204-
VT) >= 0)
3211+
// Even if this FPImm requires an additional FNEG (i.e. the second element of
3212+
// the returned pair is true) we still prefer FLI + FNEG over immediate
3213+
// materialization as the latter might generate a longer instruction sequence.
3214+
if (static_cast<const RISCVTargetLowering *>(TLI)
3215+
->getLegalZfaFPImm(APF, VT)
3216+
.first >= 0)
32053217
return false;
32063218

32073219
MVT XLenVT = Subtarget->getXLenVT();

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1978,11 +1978,17 @@ bool RISCVTargetLowering::isOffsetFoldingLegal(
19781978
return false;
19791979
}
19801980

1981-
// Returns 0-31 if the fli instruction is available for the type and this is
1982-
// legal FP immediate for the type. Returns -1 otherwise.
1983-
int RISCVTargetLowering::getLegalZfaFPImm(const APFloat &Imm, EVT VT) const {
1981+
// Return one of the followings:
1982+
// (1) `{0-31 value, false}` if FLI is available for Imm's type and FP value.
1983+
// (2) `{0-31 value, true}` if Imm is negative and FLI is available for its
1984+
// positive counterpart, which will be materialized from the first returned
1985+
// element. The second returned element indicated that there should be a FNEG
1986+
// followed.
1987+
// (3) `{-1, _}` if there is no way FLI can be used to materialize Imm.
1988+
std::pair<int, bool> RISCVTargetLowering::getLegalZfaFPImm(const APFloat &Imm,
1989+
EVT VT) const {
19841990
if (!Subtarget.hasStdExtZfa())
1985-
return -1;
1991+
return std::make_pair(-1, false);
19861992

19871993
bool IsSupportedVT = false;
19881994
if (VT == MVT::f16) {
@@ -1995,9 +2001,14 @@ int RISCVTargetLowering::getLegalZfaFPImm(const APFloat &Imm, EVT VT) const {
19952001
}
19962002

19972003
if (!IsSupportedVT)
1998-
return -1;
2004+
return std::make_pair(-1, false);
19992005

2000-
return RISCVLoadFPImm::getLoadFPImm(Imm);
2006+
int Index = RISCVLoadFPImm::getLoadFPImm(Imm);
2007+
if (Index < 0 && Imm.isNegative())
2008+
// Try the combination of its positive counterpart + FNEG.
2009+
return std::make_pair(RISCVLoadFPImm::getLoadFPImm(-Imm), true);
2010+
else
2011+
return std::make_pair(Index, false);
20012012
}
20022013

20032014
bool RISCVTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
@@ -2015,7 +2026,7 @@ bool RISCVTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
20152026
if (!IsLegalVT)
20162027
return false;
20172028

2018-
if (getLegalZfaFPImm(Imm, VT) >= 0)
2029+
if (getLegalZfaFPImm(Imm, VT).first >= 0)
20192030
return true;
20202031

20212032
// Cannot create a 64 bit floating-point immediate value for rv32.

llvm/lib/Target/RISCV/RISCVISelLowering.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ class RISCVTargetLowering : public TargetLowering {
464464
SmallVectorImpl<Use *> &Ops) const override;
465465
bool shouldScalarizeBinop(SDValue VecOp) const override;
466466
bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override;
467-
int getLegalZfaFPImm(const APFloat &Imm, EVT VT) const;
467+
std::pair<int, bool> getLegalZfaFPImm(const APFloat &Imm, EVT VT) const;
468468
bool isFPImmLegal(const APFloat &Imm, EVT VT,
469469
bool ForCodeSize) const override;
470470
bool isExtractSubvectorCheap(EVT ResVT, EVT SrcVT,

llvm/test/CodeGen/RISCV/double-zfa.ll

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -141,23 +141,23 @@ define double @loadfpimm16() {
141141
ret double -1.0
142142
}
143143

144-
; Ensure fli isn't incorrectly used for negated versions of numbers in the fli
144+
; Ensure fli isn't directly used for negated versions of numbers in the fli
145145
; table.
146146
define double @loadfpimm17() {
147147
; CHECK-LABEL: loadfpimm17:
148148
; CHECK: # %bb.0:
149-
; CHECK-NEXT: lui a0, %hi(.LCPI15_0)
150-
; CHECK-NEXT: fld fa0, %lo(.LCPI15_0)(a0)
149+
; CHECK-NEXT: fli.d fa5, 2.0
150+
; CHECK-NEXT: fneg.d fa0, fa5
151151
; CHECK-NEXT: ret
152152
ret double -2.0
153153
}
154154

155-
; Ensure fli isn't incorrecty used for negative min normal value.
155+
; Ensure fli isn't directly used for negative min normal value.
156156
define double @loadfpimm18() {
157157
; CHECK-LABEL: loadfpimm18:
158158
; CHECK: # %bb.0:
159-
; CHECK-NEXT: lui a0, %hi(.LCPI16_0)
160-
; CHECK-NEXT: fld fa0, %lo(.LCPI16_0)(a0)
159+
; CHECK-NEXT: fli.d fa5, min
160+
; CHECK-NEXT: fneg.d fa0, fa5
161161
; CHECK-NEXT: ret
162162
ret double 0x8010000000000000
163163
}

llvm/test/CodeGen/RISCV/float-zfa.ll

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,23 +95,23 @@ define float @loadfpimm11() {
9595
ret float -1.0
9696
}
9797

98-
; Ensure fli isn't incorrectly used for negated versions of numbers in the fli
98+
; Ensure fli isn't directly used for negated versions of numbers in the fli
9999
; table.
100100
define float @loadfpimm12() {
101101
; CHECK-LABEL: loadfpimm12:
102102
; CHECK: # %bb.0:
103-
; CHECK-NEXT: lui a0, 786432
104-
; CHECK-NEXT: fmv.w.x fa0, a0
103+
; CHECK-NEXT: fli.s fa5, 2.0
104+
; CHECK-NEXT: fneg.s fa0, fa5
105105
; CHECK-NEXT: ret
106106
ret float -2.0
107107
}
108108

109-
; Ensure fli isn't incorrecty used for negative min normal value.
109+
; Ensure fli isn't directly used for negative min normal value.
110110
define float @loadfpimm13() {
111111
; CHECK-LABEL: loadfpimm13:
112112
; CHECK: # %bb.0:
113-
; CHECK-NEXT: lui a0, 526336
114-
; CHECK-NEXT: fmv.w.x fa0, a0
113+
; CHECK-NEXT: fli.s fa5, min
114+
; CHECK-NEXT: fneg.s fa0, fa5
115115
; CHECK-NEXT: ret
116116
ret float 0xb810000000000000
117117
}

llvm/test/CodeGen/RISCV/half-zfa-fli.ll

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -195,13 +195,13 @@ define half @loadfpimm13() {
195195
ret half -1.0
196196
}
197197

198-
; Ensure fli isn't incorrectly used for negated versions of numbers in the fli
198+
; Ensure fli isn't directly used for negated versions of numbers in the fli
199199
; table.
200200
define half @loadfpimm14() {
201201
; CHECK-LABEL: loadfpimm14:
202202
; CHECK: # %bb.0:
203-
; CHECK-NEXT: lui a0, 1048572
204-
; CHECK-NEXT: fmv.h.x fa0, a0
203+
; CHECK-NEXT: fli.h fa5, 2.0
204+
; CHECK-NEXT: fneg.h fa0, fa5
205205
; CHECK-NEXT: ret
206206
;
207207
; ZFHMIN-LABEL: loadfpimm14:
@@ -212,12 +212,12 @@ define half @loadfpimm14() {
212212
ret half -2.0
213213
}
214214

215-
; Ensure fli isn't incorrecty used for negative min normal value.
215+
; Ensure fli isn't directly used for negative min normal value.
216216
define half @loadfpimm15() {
217217
; CHECK-LABEL: loadfpimm15:
218218
; CHECK: # %bb.0:
219-
; CHECK-NEXT: lui a0, %hi(.LCPI14_0)
220-
; CHECK-NEXT: flh fa0, %lo(.LCPI14_0)(a0)
219+
; CHECK-NEXT: fli.h fa5, min
220+
; CHECK-NEXT: fneg.h fa0, fa5
221221
; CHECK-NEXT: ret
222222
;
223223
; ZFHMIN-LABEL: loadfpimm15:
@@ -227,4 +227,3 @@ define half @loadfpimm15() {
227227
; ZFHMIN-NEXT: ret
228228
ret half 0xH8400
229229
}
230-

0 commit comments

Comments
 (0)