Skip to content

Commit 5537ae8

Browse files
committed
[RISCV] Fix fneg.d/fabs.d aliasing handling for Zdinx. Add missing fmv.s/d aliases.
We were missing test coverage for fneg.d/fabs.d for Zdinx. When I added it revealed it only worked on RV64. The assembler was not creating a GPRPair register class on RV32 so the alias couldn't match. The disassembler was also not using GPRPair registers preventing the aliases from printing in disassembly too. I've fixed the assembler by adding new parsing methods in an attempt to get decent diagnostics. This is hard since the mnemonics are ambiguous between D and Zdinx. Tests have been adjusted for some differences in what errors are reported first.
1 parent feeb6aa commit 5537ae8

File tree

9 files changed

+106
-38
lines changed

9 files changed

+106
-38
lines changed

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

Lines changed: 57 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ class RISCVAsmParser : public MCTargetAsmParser {
9797

9898
unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
9999
unsigned Kind) override;
100-
unsigned checkTargetMatchPredicate(MCInst &Inst) override;
101100

102101
bool generateImmOutOfRangeError(OperandVector &Operands, uint64_t ErrorInfo,
103102
int64_t Lower, int64_t Upper,
@@ -209,6 +208,8 @@ class RISCVAsmParser : public MCTargetAsmParser {
209208
ParseStatus parseInsnDirectiveOpcode(OperandVector &Operands);
210209
ParseStatus parseInsnCDirectiveOpcode(OperandVector &Operands);
211210
ParseStatus parseGPRAsFPR(OperandVector &Operands);
211+
ParseStatus parseGPRAsFPR64(OperandVector &Operands);
212+
ParseStatus parseGPRPairAsFPR64(OperandVector &Operands);
212213
template <bool IsRV64Inst> ParseStatus parseGPRPair(OperandVector &Operands);
213214
ParseStatus parseGPRPair(OperandVector &Operands, bool IsRV64Inst);
214215
ParseStatus parseFRMArg(OperandVector &Operands);
@@ -280,7 +281,6 @@ class RISCVAsmParser : public MCTargetAsmParser {
280281
public:
281282
enum RISCVMatchResultTy {
282283
Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY,
283-
Match_RequiresEvenGPRs,
284284
#define GET_OPERAND_DIAGNOSTIC_TYPES
285285
#include "RISCVGenAsmMatcher.inc"
286286
#undef GET_OPERAND_DIAGNOSTIC_TYPES
@@ -481,6 +481,7 @@ struct RISCVOperand final : public MCParsedAsmOperand {
481481
}
482482

483483
bool isGPRAsFPR() const { return isGPR() && Reg.IsGPRAsFPR; }
484+
bool isGPRPairAsFPR() const { return isGPRPair() && Reg.IsGPRAsFPR; }
484485

485486
bool isGPRPair() const {
486487
return Kind == KindTy::Register &&
@@ -1341,6 +1342,16 @@ unsigned RISCVAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
13411342
Op.Reg.RegNum = convertFPR64ToFPR16(Reg);
13421343
return Match_Success;
13431344
}
1345+
1346+
// There are some GPRF64AsFPR instructions that have no RV32 equivalent. We
1347+
// reject them at parsing thinking we should match as GPRPairAsFPR for RV32.
1348+
// So we explicitly accept them here for RV32 to allow the generic code to
1349+
// report that the instruction requires RV64.
1350+
if (RISCVMCRegisterClasses[RISCV::GPRRegClassID].contains(Reg) &&
1351+
Kind == MCK_GPRF64AsFPR && STI->hasFeature(RISCV::FeatureStdExtZdinx) &&
1352+
!isRV64())
1353+
return Match_Success;
1354+
13441355
// As the parser couldn't differentiate an VRM2/VRM4/VRM8 from an VR, coerce
13451356
// the register from VR to VRM2/VRM4/VRM8 if necessary.
13461357
if (IsRegVR && (Kind == MCK_VRM2 || Kind == MCK_VRM4 || Kind == MCK_VRM8)) {
@@ -1352,27 +1363,6 @@ unsigned RISCVAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
13521363
return Match_InvalidOperand;
13531364
}
13541365

1355-
unsigned RISCVAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
1356-
const MCInstrDesc &MCID = MII.get(Inst.getOpcode());
1357-
1358-
for (unsigned I = 0; I < MCID.NumOperands; ++I) {
1359-
if (MCID.operands()[I].RegClass == RISCV::GPRPairRegClassID) {
1360-
const auto &Op = Inst.getOperand(I);
1361-
assert(Op.isReg());
1362-
1363-
MCRegister Reg = Op.getReg();
1364-
if (RISCVMCRegisterClasses[RISCV::GPRPairRegClassID].contains(Reg))
1365-
continue;
1366-
1367-
// FIXME: We should form a paired register during parsing/matching.
1368-
if (((Reg.id() - RISCV::X0) & 1) != 0)
1369-
return Match_RequiresEvenGPRs;
1370-
}
1371-
}
1372-
1373-
return Match_Success;
1374-
}
1375-
13761366
bool RISCVAsmParser::generateImmOutOfRangeError(
13771367
SMLoc ErrorLoc, int64_t Lower, int64_t Upper,
13781368
const Twine &Msg = "immediate must be an integer in the range") {
@@ -1448,10 +1438,6 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
14481438
switch (Result) {
14491439
default:
14501440
break;
1451-
case Match_RequiresEvenGPRs:
1452-
return Error(IDLoc,
1453-
"double precision floating point operands must use even "
1454-
"numbered X register");
14551441
case Match_InvalidImmXLenLI:
14561442
if (isRV64()) {
14571443
SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
@@ -2318,6 +2304,13 @@ ParseStatus RISCVAsmParser::parseMaskReg(OperandVector &Operands) {
23182304
return ParseStatus::Success;
23192305
}
23202306

2307+
ParseStatus RISCVAsmParser::parseGPRAsFPR64(OperandVector &Operands) {
2308+
if (!isRV64() || getSTI().hasFeature(RISCV::FeatureStdExtF))
2309+
return ParseStatus::NoMatch;
2310+
2311+
return parseGPRAsFPR(Operands);
2312+
}
2313+
23212314
ParseStatus RISCVAsmParser::parseGPRAsFPR(OperandVector &Operands) {
23222315
if (getLexer().isNot(AsmToken::Identifier))
23232316
return ParseStatus::NoMatch;
@@ -2335,6 +2328,43 @@ ParseStatus RISCVAsmParser::parseGPRAsFPR(OperandVector &Operands) {
23352328
return ParseStatus::Success;
23362329
}
23372330

2331+
ParseStatus RISCVAsmParser::parseGPRPairAsFPR64(OperandVector &Operands) {
2332+
if (isRV64() || getSTI().hasFeature(RISCV::FeatureStdExtF))
2333+
return ParseStatus::NoMatch;
2334+
2335+
if (getLexer().isNot(AsmToken::Identifier))
2336+
return ParseStatus::NoMatch;
2337+
2338+
StringRef Name = getLexer().getTok().getIdentifier();
2339+
MCRegister Reg = matchRegisterNameHelper(Name);
2340+
2341+
if (!Reg)
2342+
return ParseStatus::NoMatch;
2343+
2344+
if (!RISCVMCRegisterClasses[RISCV::GPRRegClassID].contains(Reg))
2345+
return ParseStatus::NoMatch;
2346+
2347+
if ((Reg - RISCV::X0) & 1) {
2348+
// Only report the even register error if we have at least Zfinx so we know
2349+
// some FP is enabled. We already checked F earlier.
2350+
if (getSTI().hasFeature(RISCV::FeatureStdExtZfinx))
2351+
return TokError("double precision floating point operands must use even "
2352+
"numbered X register");
2353+
return ParseStatus::NoMatch;
2354+
}
2355+
2356+
SMLoc S = getLoc();
2357+
SMLoc E = SMLoc::getFromPointer(S.getPointer() + Name.size());
2358+
getLexer().Lex();
2359+
2360+
const MCRegisterInfo *RI = getContext().getRegisterInfo();
2361+
MCRegister Pair = RI->getMatchingSuperReg(
2362+
Reg, RISCV::sub_gpr_even,
2363+
&RISCVMCRegisterClasses[RISCV::GPRPairRegClassID]);
2364+
Operands.push_back(RISCVOperand::createReg(Pair, S, E, /*isGPRAsFPR=*/true));
2365+
return ParseStatus::Success;
2366+
}
2367+
23382368
template <bool IsRV64>
23392369
ParseStatus RISCVAsmParser::parseGPRPair(OperandVector &Operands) {
23402370
return parseGPRPair(Operands, IsRV64);

llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,10 +181,15 @@ static DecodeStatus DecodeGPRCRegisterClass(MCInst &Inst, uint32_t RegNo,
181181
static DecodeStatus DecodeGPRPairRegisterClass(MCInst &Inst, uint32_t RegNo,
182182
uint64_t Address,
183183
const MCDisassembler *Decoder) {
184-
if (RegNo >= 32 || RegNo & 1)
184+
if (RegNo >= 32 || RegNo % 2)
185185
return MCDisassembler::Fail;
186186

187-
MCRegister Reg = RISCV::X0 + RegNo;
187+
const RISCVDisassembler *Dis =
188+
static_cast<const RISCVDisassembler *>(Decoder);
189+
const MCRegisterInfo *RI = Dis->getContext().getRegisterInfo();
190+
MCRegister Reg = RI->getMatchingSuperReg(
191+
RISCV::X0 + RegNo, RISCV::sub_gpr_even,
192+
&RISCVMCRegisterClasses[RISCV::GPRPairRegClassID]);
188193
Inst.addOperand(MCOperand::createReg(Reg));
189194
return MCDisassembler::Success;
190195
}

llvm/lib/Target/RISCV/RISCVInstrInfoD.td

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,15 @@ def AddrRegImmINX : ComplexPattern<iPTR, 2, "SelectAddrRegImmRV32Zdinx">;
3535

3636
def GPRPairAsFPR : AsmOperandClass {
3737
let Name = "GPRPairAsFPR";
38-
let ParserMethod = "parseGPRAsFPR";
39-
let PredicateMethod = "isGPRAsFPR";
38+
let ParserMethod = "parseGPRPairAsFPR64";
39+
let PredicateMethod = "isGPRPairAsFPR";
4040
let RenderMethod = "addRegOperands";
4141
}
4242

4343
def GPRF64AsFPR : AsmOperandClass {
4444
let Name = "GPRF64AsFPR";
4545
let PredicateMethod = "isGPRAsFPR";
46-
let ParserMethod = "parseGPRAsFPR";
46+
let ParserMethod = "parseGPRAsFPR64";
4747
let RenderMethod = "addRegOperands";
4848
}
4949

@@ -205,6 +205,7 @@ def PseudoQuietFLT_D : PseudoQuietFCMP<FPR64>;
205205
} // Predicates = [HasStdExtD]
206206

207207
let Predicates = [HasStdExtZdinx, IsRV64] in {
208+
def : InstAlias<"fmv.d $rd, $rs", (FSGNJ_D_INX FPR64INX:$rd, FPR64INX:$rs, FPR64INX:$rs)>;
208209
def : InstAlias<"fabs.d $rd, $rs", (FSGNJX_D_INX FPR64INX:$rd, FPR64INX:$rs, FPR64INX:$rs)>;
209210
def : InstAlias<"fneg.d $rd, $rs", (FSGNJN_D_INX FPR64INX:$rd, FPR64INX:$rs, FPR64INX:$rs)>;
210211

@@ -219,6 +220,7 @@ def PseudoQuietFLT_D_INX : PseudoQuietFCMP<FPR64INX>;
219220
} // Predicates = [HasStdExtZdinx, IsRV64]
220221

221222
let Predicates = [HasStdExtZdinx, IsRV32] in {
223+
def : InstAlias<"fmv.d $rd, $rs", (FSGNJ_D_IN32X FPR64IN32X:$rd, FPR64IN32X:$rs, FPR64IN32X:$rs)>;
222224
def : InstAlias<"fabs.d $rd, $rs", (FSGNJX_D_IN32X FPR64IN32X:$rd, FPR64IN32X:$rs, FPR64IN32X:$rs)>;
223225
def : InstAlias<"fneg.d $rd, $rs", (FSGNJN_D_IN32X FPR64IN32X:$rd, FPR64IN32X:$rs, FPR64IN32X:$rs)>;
224226

llvm/lib/Target/RISCV/RISCVInstrInfoF.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,7 @@ def PseudoQuietFLT_S : PseudoQuietFCMP<FPR32>;
454454
} // Predicates = [HasStdExtF]
455455

456456
let Predicates = [HasStdExtZfinx] in {
457+
def : InstAlias<"fmv.s $rd, $rs", (FSGNJ_S_INX FPR32INX:$rd, FPR32INX:$rs, FPR32INX:$rs)>;
457458
def : InstAlias<"fabs.s $rd, $rs", (FSGNJX_S_INX FPR32INX:$rd, FPR32INX:$rs, FPR32INX:$rs)>;
458459
def : InstAlias<"fneg.s $rd, $rs", (FSGNJN_S_INX FPR32INX:$rd, FPR32INX:$rs, FPR32INX:$rs)>;
459460

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# RUN: not llvm-mc -triple riscv32 -mattr=+zdinx %s 2>&1 | FileCheck %s
22

33
# Unsupport Odd Registers in RV32
4-
fadd.d a0, a1, a2 # CHECK: :[[@LINE]]:1: error: double precision floating point operands must use even numbered X register
4+
fadd.d a0, a1, a2 # CHECK: :[[@LINE]]:12: error: double precision floating point operands must use even numbered X register
55

66
# Not support float registers
77
flw fa4, 12(sp) # CHECK: :[[@LINE]]:1: error: instruction requires the following: 'F' (Single-Precision Floating-Point){{$}}
@@ -12,8 +12,8 @@ fsw a5, 12(sp) # CHECK: :[[@LINE]]:5: error: invalid operand for instruction
1212
fmv.x.w s0, s1 # CHECK: :[[@LINE]]:13: error: invalid operand for instruction
1313

1414
# Invalid register names
15-
fadd.d a100, a2, a3 # CHECK: :[[@LINE]]:8: error: invalid operand for instruction
16-
fsgnjn.d a100, a2, a3 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
15+
fadd.d a100, a2, a4 # CHECK: :[[@LINE]]:8: error: invalid operand for instruction
16+
fsgnjn.d a100, a2, a4 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
1717

1818
# Rounding mode when a register is expected
1919
fmadd.d x10, x12, x14, ree # CHECK: :[[@LINE]]:24: error: invalid operand for instruction
@@ -24,4 +24,4 @@ fmsub.d x10, x12, x14, x16, 0 # CHECK: :[[@LINE]]:29: error: operand must be a v
2424
fnmsub.d x10, x12, x14, x16, 0b111 # CHECK: :[[@LINE]]:30: error: operand must be a valid floating point rounding mode mnemonic
2525

2626
# FP registers where integer regs are expected
27-
fcvt.wu.d ft2, a1 # CHECK: :[[@LINE]]:11: error: invalid operand for instruction
27+
fcvt.wu.d ft2, a2 # CHECK: :[[@LINE]]:11: error: invalid operand for instruction

llvm/test/MC/RISCV/rv32zfinx-invalid.s

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ fmv.x.w s0, s1 # CHECK: :[[@LINE]]:13: error: invalid operand for instruction
1010
fadd.d t1, t3, t5 # CHECK: :[[@LINE]]:1: error: instruction requires the following: 'Zdinx' (Double in Integer){{$}}
1111

1212
# Invalid register names
13-
fadd.d a100, a2, a3 # CHECK: :[[@LINE]]:8: error: invalid operand for instruction
13+
fadd.s a100, a2, a3 # CHECK: :[[@LINE]]:8: error: invalid operand for instruction
1414
fsgnjn.s a100, a2, a3 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
1515

1616
# Rounding mode when a register is expected
@@ -22,4 +22,7 @@ fmsub.s x14, x15, x16, x17, 0 # CHECK: :[[@LINE]]:29: error: operand must be a v
2222
fnmsub.s x18, x19, x20, x21, 0b111 # CHECK: :[[@LINE]]:30: error: operand must be a valid floating point rounding mode mnemonic
2323

2424
# Using 'Zdinx' instructions for an 'Zfinx'-only target
25-
fadd.d t0, t1, t2 # CHECK: :[[@LINE]]:1: error: instruction requires the following: 'Zdinx' (Double in Integer){{$}}
25+
# odd registers report incorrect registers
26+
fadd.d t0, t1, t2 # CHECK: :[[@LINE]]:8: error: double precision floating point operands must use even numbered X register
27+
# even registers report the required extension
28+
fadd.d t3, t1, t5 # CHECK: :[[@LINE]]:1: error: instruction requires the following: 'Zdinx' (Double in Integer){{$}}

llvm/test/MC/RISCV/rvzdinx-aliases-valid.s

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,27 @@
1919
# RUN: | llvm-objdump -d --mattr=+zdinx - \
2020
# RUN: | FileCheck -check-prefix=CHECK-ALIAS %s
2121

22+
##===----------------------------------------------------------------------===##
23+
## Assembler Pseudo Instructions (User-Level ISA, Version 2.2, Chapter 20)
24+
##===----------------------------------------------------------------------===##
25+
26+
# CHECK-INST: fsgnj.d a0, a2, a2
27+
# CHECK-ALIAS: fmv.d a0, a2
28+
fmv.d a0, a2
29+
# CHECK-INST: fsgnjx.d a2, a4, a4
30+
# CHECK-ALIAS: fabs.d a2, a4
31+
fabs.d a2, a4
32+
# CHECK-INST: fsgnjn.d a4, a6, a6
33+
# CHECK-ALIAS: fneg.d a4, a6
34+
fneg.d a4, a6
35+
36+
# CHECK-INST: flt.d tp, s2, a6
37+
# CHECK-ALIAS: flt.d tp, s2, a6
38+
fgt.d x4, a6, s2
39+
# CHECK-INST: fle.d t2, s4, s2
40+
# CHECK-ALIAS: fle.d t2, s4, s2
41+
fge.d x7, s2, s4
42+
2243
##===----------------------------------------------------------------------===##
2344
## Aliases which omit the rounding mode.
2445
##===----------------------------------------------------------------------===##

llvm/test/MC/RISCV/rvzfinx-aliases-valid.s

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
## Assembler Pseudo Instructions (User-Level ISA, Version 2.2, Chapter 20)
2424
##===----------------------------------------------------------------------===##
2525

26+
# CHECK-INST: fsgnj.s s1, s2, s2
27+
# CHECK-ALIAS: fmv.s s1, s2
28+
fmv.s s1, s2
2629
# CHECK-INST: fsgnjx.s s1, s2, s2
2730
# CHECK-ALIAS: fabs.s s1, s2
2831
fabs.s s1, s2

llvm/test/MC/RISCV/rvzhinx-aliases-valid.s

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
## Assembler Pseudo Instructions (User-Level ISA, Version 2.2, Chapter 20)
2424
##===----------------------------------------------------------------------===##
2525

26+
# CHECK-INST: fsgnj.h s1, s2, s2
27+
# CHECK-ALIAS: fmv.h s1, s2
28+
fmv.h s1, s2
2629
# CHECK-INST: fsgnjx.h s1, s2, s2
2730
# CHECK-ALIAS: fabs.h s1, s2
2831
fabs.h s1, s2

0 commit comments

Comments
 (0)