Skip to content

Commit b28d83e

Browse files
authored
[RISCV][MC] Recognise that fcvt.d.s with frm != 0b000 is valid (llvm#67555)
This seems to be an issue common to both GCC and LLVM. There are various RISC-V FCVT instructions where the frm field makes no difference to the output as the result is always exact (e.g. fcvt.d.s, fcvt.s.h, fcvt.d.h). As with GCC, we always generate a form of these fcvt instructions where frm=0b000. However, the ISA manual _doesn't_ state that frm values are invalid, and we should ensure we can accept them. This patch does so by adding the frm field to fcvt.d.s and adding an InstAlias so that if no frm is specified, it defaults to rne (0b000). This patch just corrects fcvt.d.s in order to allow the approach to be reviewed, before applying it to the other affected instructions. I haven't added tests to llvm/test/MC/Disassembler/RISCV, because it doesn't seem necessary to test there in addition to our usual round-trip tests in llvm/test/MC/RISCV. But feedback is welcome. Recently added tests ensure that the default `rne` rounding mode is printed as desired.
1 parent a5686c2 commit b28d83e

File tree

9 files changed

+85
-10
lines changed

9 files changed

+85
-10
lines changed

llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ class RISCVAsmParser : public MCTargetAsmParser {
259259

260260
std::unique_ptr<RISCVOperand> defaultMaskRegOp() const;
261261
std::unique_ptr<RISCVOperand> defaultFRMArgOp() const;
262+
std::unique_ptr<RISCVOperand> defaultFRMArgLegacyOp() const;
262263

263264
public:
264265
enum RISCVMatchResultTy {
@@ -563,6 +564,7 @@ struct RISCVOperand final : public MCParsedAsmOperand {
563564

564565
/// Return true if the operand is a valid floating point rounding mode.
565566
bool isFRMArg() const { return Kind == KindTy::FRM; }
567+
bool isFRMArgLegacy() const { return Kind == KindTy::FRM; }
566568
bool isRTZArg() const { return isFRMArg() && FRM.FRM == RISCVFPRndMode::RTZ; }
567569

568570
/// Return true if the operand is a valid fli.s floating-point immediate.
@@ -3257,6 +3259,11 @@ std::unique_ptr<RISCVOperand> RISCVAsmParser::defaultFRMArgOp() const {
32573259
llvm::SMLoc());
32583260
}
32593261

3262+
std::unique_ptr<RISCVOperand> RISCVAsmParser::defaultFRMArgLegacyOp() const {
3263+
return RISCVOperand::createFRMArg(RISCVFPRndMode::RoundingMode::RNE,
3264+
llvm::SMLoc());
3265+
}
3266+
32603267
bool RISCVAsmParser::validateInstruction(MCInst &Inst,
32613268
OperandVector &Operands) {
32623269
unsigned Opcode = Inst.getOpcode();

llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,19 @@ void RISCVInstPrinter::printFRMArg(const MCInst *MI, unsigned OpNo,
158158
O << ", " << RISCVFPRndMode::roundingModeToString(FRMArg);
159159
}
160160

161+
void RISCVInstPrinter::printFRMArgLegacy(const MCInst *MI, unsigned OpNo,
162+
const MCSubtargetInfo &STI,
163+
raw_ostream &O) {
164+
auto FRMArg =
165+
static_cast<RISCVFPRndMode::RoundingMode>(MI->getOperand(OpNo).getImm());
166+
// Never print rounding mode if it's the default 'rne'. This ensures the
167+
// output can still be parsed by older tools that erroneously failed to
168+
// accept a rounding mode.
169+
if (FRMArg == RISCVFPRndMode::RoundingMode::RNE)
170+
return;
171+
O << ", " << RISCVFPRndMode::roundingModeToString(FRMArg);
172+
}
173+
161174
void RISCVInstPrinter::printFPImmOperand(const MCInst *MI, unsigned OpNo,
162175
const MCSubtargetInfo &STI,
163176
raw_ostream &O) {

llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ class RISCVInstPrinter : public MCInstPrinter {
4040
const MCSubtargetInfo &STI, raw_ostream &O);
4141
void printFRMArg(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
4242
raw_ostream &O);
43+
void printFRMArgLegacy(const MCInst *MI, unsigned OpNo,
44+
const MCSubtargetInfo &STI, raw_ostream &O);
4345
void printFPImmOperand(const MCInst *MI, unsigned OpNo,
4446
const MCSubtargetInfo &STI, raw_ostream &O);
4547
void printZeroOffsetMemOp(const MCInst *MI, unsigned OpNo,

llvm/lib/Target/RISCV/RISCVInstrInfoD.td

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ foreach Ext = DExts in {
115115
Ext.PrimaryTy, "fcvt.s.d">,
116116
Sched<[WriteFCvtF64ToF32, ReadFCvtF64ToF32]>;
117117

118-
defm FCVT_D_S : FPUnaryOp_r_m<0b0100001, 0b00000, 0b000, Ext, Ext.PrimaryTy,
119-
Ext.F32Ty, "fcvt.d.s">,
118+
defm FCVT_D_S : FPUnaryOp_r_frmlegacy_m<0b0100001, 0b00000, Ext, Ext.PrimaryTy,
119+
Ext.F32Ty, "fcvt.d.s">,
120120
Sched<[WriteFCvtF32ToF64, ReadFCvtF32ToF64]>;
121121

122122
let SchedRW = [WriteFCmp64, ReadFCmp64, ReadFCmp64] in {
@@ -240,23 +240,23 @@ let Predicates = [HasStdExtD] in {
240240

241241
// f64 -> f32, f32 -> f64
242242
def : Pat<(any_fpround FPR64:$rs1), (FCVT_S_D FPR64:$rs1, FRM_DYN)>;
243-
def : Pat<(any_fpextend FPR32:$rs1), (FCVT_D_S FPR32:$rs1)>;
243+
def : Pat<(any_fpextend FPR32:$rs1), (FCVT_D_S FPR32:$rs1, FRM_RNE)>;
244244
} // Predicates = [HasStdExtD]
245245

246246
let Predicates = [HasStdExtZdinx, IsRV64] in {
247247
/// Float conversion operations
248248

249249
// f64 -> f32, f32 -> f64
250250
def : Pat<(any_fpround FPR64INX:$rs1), (FCVT_S_D_INX FPR64INX:$rs1, FRM_DYN)>;
251-
def : Pat<(any_fpextend FPR32INX:$rs1), (FCVT_D_S_INX FPR32INX:$rs1)>;
251+
def : Pat<(any_fpextend FPR32INX:$rs1), (FCVT_D_S_INX FPR32INX:$rs1, FRM_RNE)>;
252252
} // Predicates = [HasStdExtZdinx, IsRV64]
253253

254254
let Predicates = [HasStdExtZdinx, IsRV32] in {
255255
/// Float conversion operations
256256

257257
// f64 -> f32, f32 -> f64
258258
def : Pat<(any_fpround FPR64IN32X:$rs1), (FCVT_S_D_IN32X FPR64IN32X:$rs1, FRM_DYN)>;
259-
def : Pat<(any_fpextend FPR32INX:$rs1), (FCVT_D_S_IN32X FPR32INX:$rs1)>;
259+
def : Pat<(any_fpextend FPR32INX:$rs1), (FCVT_D_S_IN32X FPR32INX:$rs1, FRM_RNE)>;
260260
} // Predicates = [HasStdExtZdinx, IsRV32]
261261

262262
// [u]int<->double conversion patterns must be gated on IsRV32 or IsRV64, so
@@ -281,7 +281,8 @@ def : Pat<(riscv_fpclass FPR64:$rs1), (FCLASS_D $rs1)>;
281281

282282
def : PatFprFpr<fcopysign, FSGNJ_D, FPR64, f64>;
283283
def : Pat<(fcopysign FPR64:$rs1, (fneg FPR64:$rs2)), (FSGNJN_D $rs1, $rs2)>;
284-
def : Pat<(fcopysign FPR64:$rs1, FPR32:$rs2), (FSGNJ_D $rs1, (FCVT_D_S $rs2))>;
284+
def : Pat<(fcopysign FPR64:$rs1, FPR32:$rs2), (FSGNJ_D $rs1, (FCVT_D_S $rs2,
285+
FRM_RNE))>;
285286
def : Pat<(fcopysign FPR32:$rs1, FPR64:$rs2), (FSGNJ_S $rs1, (FCVT_S_D $rs2,
286287
FRM_DYN))>;
287288

@@ -318,7 +319,7 @@ def : PatFprFpr<fcopysign, FSGNJ_D_INX, FPR64INX, f64>;
318319
def : Pat<(fcopysign FPR64INX:$rs1, (fneg FPR64INX:$rs2)),
319320
(FSGNJN_D_INX $rs1, $rs2)>;
320321
def : Pat<(fcopysign FPR64INX:$rs1, FPR32INX:$rs2),
321-
(FSGNJ_D_INX $rs1, (FCVT_D_S_INX $rs2))>;
322+
(FSGNJ_D_INX $rs1, (FCVT_D_S_INX $rs2, FRM_RNE))>;
322323
def : Pat<(fcopysign FPR32INX:$rs1, FPR64INX:$rs2),
323324
(FSGNJ_S_INX $rs1, (FCVT_S_D_INX $rs2, FRM_DYN))>;
324325

@@ -355,7 +356,7 @@ def : PatFprFpr<fcopysign, FSGNJ_D_IN32X, FPR64IN32X, f64>;
355356
def : Pat<(fcopysign FPR64IN32X:$rs1, (fneg FPR64IN32X:$rs2)),
356357
(FSGNJN_D_IN32X $rs1, $rs2)>;
357358
def : Pat<(fcopysign FPR64IN32X:$rs1, FPR32INX:$rs2),
358-
(FSGNJ_D_IN32X $rs1, (FCVT_D_S_INX $rs2))>;
359+
(FSGNJ_D_IN32X $rs1, (FCVT_D_S_INX $rs2, FRM_RNE))>;
359360
def : Pat<(fcopysign FPR32INX:$rs1, FPR64IN32X:$rs2),
360361
(FSGNJ_S_INX $rs1, (FCVT_S_D_IN32X $rs2, FRM_DYN))>;
361362

llvm/lib/Target/RISCV/RISCVInstrInfoF.td

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,26 @@ def frmarg : Operand<XLenVT> {
132132
let DecoderMethod = "decodeFRMArg";
133133
}
134134

135+
// Variants of the rounding mode operand that default to 'rne'. This is used
136+
// for historical/legacy reasons. fcvt functions where the rounding mode
137+
// doesn't affect the output originally always set it to 0b000 ('rne'). As old
138+
// versions of LLVM and GCC will fail to decode versions of these instructions
139+
// with the rounding mode set to something other than 'rne', we retain this
140+
// default.
141+
def FRMArgLegacy : AsmOperandClass {
142+
let Name = "FRMArgLegacy";
143+
let RenderMethod = "addFRMArgOperands";
144+
let ParserMethod = "parseFRMArg";
145+
let IsOptional = 1;
146+
let DefaultMethod = "defaultFRMArgLegacyOp";
147+
}
148+
149+
def frmarglegacy : Operand<XLenVT> {
150+
let ParserMatchClass = FRMArgLegacy;
151+
let PrintMethod = "printFRMArgLegacy";
152+
let DecoderMethod = "decodeFRMArg";
153+
}
154+
135155
//===----------------------------------------------------------------------===//
136156
// Instruction class templates
137157
//===----------------------------------------------------------------------===//
@@ -226,6 +246,24 @@ multiclass FPUnaryOp_r_frm_m<bits<7> funct7, bits<5> rs2val,
226246
opcodestr>;
227247
}
228248

249+
let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1,
250+
UseNamedOperandTable = 1, hasPostISelHook = 1 in
251+
class FPUnaryOp_r_frmlegacy<bits<7> funct7, bits<5> rs2val, DAGOperand rdty,
252+
DAGOperand rs1ty, string opcodestr>
253+
: RVInstRFrm<funct7, OPC_OP_FP, (outs rdty:$rd),
254+
(ins rs1ty:$rs1, frmarglegacy:$frm), opcodestr,
255+
"$rd, $rs1$frm"> {
256+
let rs2 = rs2val;
257+
}
258+
multiclass FPUnaryOp_r_frmlegacy_m<bits<7> funct7, bits<5> rs2val,
259+
ExtInfo Ext, DAGOperand rdty, DAGOperand rs1ty,
260+
string opcodestr, list<Predicate> ExtraPreds = []> {
261+
let Predicates = !listconcat(Ext.Predicates, ExtraPreds),
262+
DecoderNamespace = Ext.Space in
263+
def Ext.Suffix : FPUnaryOp_r_frmlegacy<funct7, rs2val, rdty, rs1ty,
264+
opcodestr>;
265+
}
266+
229267
let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1,
230268
IsSignExtendingOpW = 1 in
231269
class FPCmp_rr<bits<7> funct7, bits<3> funct3, string opcodestr,

llvm/test/MC/RISCV/fp-default-rounding-mode.s

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,14 @@ fadd.d fa0, fa1, fa2
7272
# CHECK-ALIAS: fcvt.s.d fa0, fa0{{$}}
7373
fcvt.s.d fa0, fa0
7474

75-
# FIXME: fcvt.d.s should have a default rounding mode.
75+
# For historical reasons defaults to frm==0b000 (rne) but doesn't print this
76+
# default rounding mode.
7677
# CHECK-INST: fcvt.d.s fa0, fa0{{$}}
7778
# CHECK-ALIAS: fcvt.d.s fa0, fa0{{$}}
7879
fcvt.d.s fa0, fa0
80+
# CHECK-INST: fcvt.d.s fa0, fa0{{$}}
81+
# CHECK-ALIAS: fcvt.d.s fa0, fa0{{$}}
82+
fcvt.d.s fa0, fa0, rne
7983

8084
# CHECK-INST: fcvt.w.d a0, fa0, dyn{{$}}
8185
# CHECK-ALIAS: fcvt.w.d a0, fa0{{$}}

llvm/test/MC/RISCV/fp-inx-default-rounding-mode.s

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,14 @@ fadd.d a0, a1, a2
7575
# CHECK-ALIAS: fcvt.s.d a0, a0{{$}}
7676
fcvt.s.d a0, a0
7777

78-
# FIXME: fcvt.d.s should have a default rounding mode.
78+
# For historical reasons defaults to frm==0b000 (rne) but doesn't print this
79+
# default rounding mode.
7980
# CHECK-INST: fcvt.d.s a0, a0{{$}}
8081
# CHECK-ALIAS: fcvt.d.s a0, a0{{$}}
8182
fcvt.d.s a0, a0
83+
# CHECK-INST: fcvt.d.s a0, a0{{$}}
84+
# CHECK-ALIAS: fcvt.d.s a0, a0{{$}}
85+
fcvt.d.s a0, a0, rne
8286

8387
# CHECK-INST: fcvt.w.d a0, a0, dyn{{$}}
8488
# CHECK-ALIAS: fcvt.w.d a0, a0{{$}}

llvm/test/MC/RISCV/rv32d-valid.s

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ fcvt.s.d fs5, fs6, dyn
9696
# CHECK-ASM-AND-OBJ: fcvt.d.s fs7, fs8
9797
# CHECK-ASM: encoding: [0xd3,0x0b,0x0c,0x42]
9898
fcvt.d.s fs7, fs8
99+
# CHECK-ASM-AND-OBJ: fcvt.d.s fs7, fs8, rup
100+
# CHECK-ASM: encoding: [0xd3,0x3b,0x0c,0x42]
101+
fcvt.d.s fs7, fs8, rup
99102
# CHECK-ASM-AND-OBJ: feq.d a1, fs8, fs9
100103
# CHECK-ASM: encoding: [0xd3,0x25,0x9c,0xa3]
101104
feq.d a1, fs8, fs9

llvm/test/MC/RISCV/rv32zdinx-valid.s

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ fcvt.s.d x26, x28, dyn
5959
# CHECK-ASM-AND-OBJ: fcvt.d.s s10, t3
6060
# CHECK-ASM: encoding: [0x53,0x0d,0x0e,0x42]
6161
fcvt.d.s x26, x28
62+
# CHECK-ASM-AND-OBJ: fcvt.d.s s10, t3, rup
63+
# CHECK-ASM: encoding: [0x53,0x3d,0x0e,0x42]
64+
fcvt.d.s x26, x28, rup
6265
# CHECK-ASM-AND-OBJ: feq.d s10, t3, t5
6366
# CHECK-ASM: encoding: [0x53,0x2d,0xee,0xa3]
6467
feq.d x26, x28, x30

0 commit comments

Comments
 (0)