Skip to content

Commit c053e9f

Browse files
authored
[RISCV] Re-implement Zacas MC layer support to make it usable for CodeGen. (#77418)
This changes the register class to GPRPair and adds the destination register as a source with a tied operand constraint. Parsing for the paired register is done with a custom parser that checks for even register and converts it to its pair version. A bit of care needs to be taken so that we only parse as a pair register based on which instruction we're parsing and the mode in the subtarget. This allows amocas.w to be parsed correcty in both modes. I've added a FIXME to note that we should be creating pair registers for Zdinx on RV32 to match the instructions CodeGen generates.
1 parent 14e7dac commit c053e9f

File tree

5 files changed

+121
-43
lines changed

5 files changed

+121
-43
lines changed

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

Lines changed: 54 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ class RISCVAsmParser : public MCTargetAsmParser {
199199
ParseStatus parseInsnDirectiveOpcode(OperandVector &Operands);
200200
ParseStatus parseInsnCDirectiveOpcode(OperandVector &Operands);
201201
ParseStatus parseGPRAsFPR(OperandVector &Operands);
202+
template <bool IsRV64Inst> ParseStatus parseGPRPair(OperandVector &Operands);
203+
ParseStatus parseGPRPair(OperandVector &Operands, bool IsRV64Inst);
202204
ParseStatus parseFRMArg(OperandVector &Operands);
203205
ParseStatus parseFenceArg(OperandVector &Operands);
204206
ParseStatus parseReglist(OperandVector &Operands);
@@ -466,6 +468,12 @@ struct RISCVOperand final : public MCParsedAsmOperand {
466468

467469
bool isGPRAsFPR() const { return isGPR() && Reg.IsGPRAsFPR; }
468470

471+
bool isGPRPair() const {
472+
return Kind == KindTy::Register &&
473+
RISCVMCRegisterClasses[RISCV::GPRPairRegClassID].contains(
474+
Reg.RegNum);
475+
}
476+
469477
static bool evaluateConstantImm(const MCExpr *Expr, int64_t &Imm,
470478
RISCVMCExpr::VariantKind &VK) {
471479
if (auto *RE = dyn_cast<RISCVMCExpr>(Expr)) {
@@ -1300,6 +1308,10 @@ unsigned RISCVAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
13001308
assert(Op.isReg());
13011309

13021310
MCRegister Reg = Op.getReg();
1311+
if (RISCVMCRegisterClasses[RISCV::GPRPairRegClassID].contains(Reg))
1312+
continue;
1313+
1314+
// FIXME: We should form a paired register during parsing/matching.
13031315
if (((Reg.id() - RISCV::X0) & 1) != 0)
13041316
return Match_RequiresEvenGPRs;
13051317
}
@@ -2222,6 +2234,48 @@ ParseStatus RISCVAsmParser::parseGPRAsFPR(OperandVector &Operands) {
22222234
return ParseStatus::Success;
22232235
}
22242236

2237+
template <bool IsRV64>
2238+
ParseStatus RISCVAsmParser::parseGPRPair(OperandVector &Operands) {
2239+
return parseGPRPair(Operands, IsRV64);
2240+
}
2241+
2242+
ParseStatus RISCVAsmParser::parseGPRPair(OperandVector &Operands,
2243+
bool IsRV64Inst) {
2244+
// If this is not an RV64 GPRPair instruction, don't parse as a GPRPair on
2245+
// RV64 as it will prevent matching the RV64 version of the same instruction
2246+
// that doesn't use a GPRPair.
2247+
// If this is an RV64 GPRPair instruction, there is no RV32 version so we can
2248+
// still parse as a pair.
2249+
if (!IsRV64Inst && isRV64())
2250+
return ParseStatus::NoMatch;
2251+
2252+
if (getLexer().isNot(AsmToken::Identifier))
2253+
return ParseStatus::NoMatch;
2254+
2255+
StringRef Name = getLexer().getTok().getIdentifier();
2256+
MCRegister RegNo = matchRegisterNameHelper(isRVE(), Name);
2257+
2258+
if (!RegNo)
2259+
return ParseStatus::NoMatch;
2260+
2261+
if (!RISCVMCRegisterClasses[RISCV::GPRRegClassID].contains(RegNo))
2262+
return ParseStatus::NoMatch;
2263+
2264+
if ((RegNo - RISCV::X0) & 1)
2265+
return TokError("register must be even");
2266+
2267+
SMLoc S = getLoc();
2268+
SMLoc E = SMLoc::getFromPointer(S.getPointer() + Name.size());
2269+
getLexer().Lex();
2270+
2271+
const MCRegisterInfo *RI = getContext().getRegisterInfo();
2272+
unsigned Pair = RI->getMatchingSuperReg(
2273+
RegNo, RISCV::sub_gpr_even,
2274+
&RISCVMCRegisterClasses[RISCV::GPRPairRegClassID]);
2275+
Operands.push_back(RISCVOperand::createReg(Pair, S, E));
2276+
return ParseStatus::Success;
2277+
}
2278+
22252279
ParseStatus RISCVAsmParser::parseFRMArg(OperandVector &Operands) {
22262280
if (getLexer().isNot(AsmToken::Identifier))
22272281
return TokError(
@@ -3335,27 +3389,6 @@ bool RISCVAsmParser::validateInstruction(MCInst &Inst,
33353389
return Error(Loc, "Operand must be constant 4.");
33363390
}
33373391

3338-
bool IsAMOCAS_D = Opcode == RISCV::AMOCAS_D || Opcode == RISCV::AMOCAS_D_AQ ||
3339-
Opcode == RISCV::AMOCAS_D_RL ||
3340-
Opcode == RISCV::AMOCAS_D_AQ_RL;
3341-
bool IsAMOCAS_Q = Opcode == RISCV::AMOCAS_Q || Opcode == RISCV::AMOCAS_Q_AQ ||
3342-
Opcode == RISCV::AMOCAS_Q_RL ||
3343-
Opcode == RISCV::AMOCAS_Q_AQ_RL;
3344-
if ((!isRV64() && IsAMOCAS_D) || IsAMOCAS_Q) {
3345-
unsigned Rd = Inst.getOperand(0).getReg();
3346-
unsigned Rs2 = Inst.getOperand(2).getReg();
3347-
assert(Rd >= RISCV::X0 && Rd <= RISCV::X31);
3348-
if ((Rd - RISCV::X0) % 2 != 0) {
3349-
SMLoc Loc = Operands[1]->getStartLoc();
3350-
return Error(Loc, "The destination register must be even.");
3351-
}
3352-
assert(Rs2 >= RISCV::X0 && Rs2 <= RISCV::X31);
3353-
if ((Rs2 - RISCV::X0) % 2 != 0) {
3354-
SMLoc Loc = Operands[2]->getStartLoc();
3355-
return Error(Loc, "The source register must be even.");
3356-
}
3357-
}
3358-
33593392
const MCInstrDesc &MCID = MII.get(Opcode);
33603393
if (!(MCID.TSFlags & RISCVII::ConstraintMask))
33613394
return false;

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,10 @@ DecodeStatus RISCVDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
546546
!STI.hasFeature(RISCV::Feature64Bit),
547547
DecoderTableRV32Zdinx32,
548548
"RV32Zdinx table (Double in Integer and rv32)");
549+
TRY_TO_DECODE(STI.hasFeature(RISCV::FeatureStdExtZacas) &&
550+
!STI.hasFeature(RISCV::Feature64Bit),
551+
DecoderTableRV32Zacas32,
552+
"RV32Zacas table (Compare-And-Swap and rv32)");
549553
TRY_TO_DECODE_FEATURE(RISCV::FeatureStdExtZfinx, DecoderTableRVZfinx32,
550554
"RVZfinx table (Float in Integer)");
551555
TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXVentanaCondOps,

llvm/lib/Target/RISCV/RISCVInstrInfoZa.td

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,54 @@
1717
// Zacas (Atomic Compare-and-Swap)
1818
//===----------------------------------------------------------------------===//
1919

20+
def GPRPairRV32Operand : AsmOperandClass {
21+
let Name = "GPRPairRV32";
22+
let ParserMethod = "parseGPRPair<false>";
23+
let PredicateMethod = "isGPRPair";
24+
let RenderMethod = "addRegOperands";
25+
}
26+
27+
def GPRPairRV64Operand : AsmOperandClass {
28+
let Name = "GPRPairRV64";
29+
let ParserMethod = "parseGPRPair<true>";
30+
let PredicateMethod = "isGPRPair";
31+
let RenderMethod = "addRegOperands";
32+
}
33+
34+
def GPRPairRV32 : RegisterOperand<GPRPair> {
35+
let ParserMatchClass = GPRPairRV32Operand;
36+
}
37+
38+
def GPRPairRV64 : RegisterOperand<GPRPair> {
39+
let ParserMatchClass = GPRPairRV64Operand;
40+
}
41+
42+
let hasSideEffects = 0, mayLoad = 1, mayStore = 1, Constraints = "$rd = $rd_wb" in
43+
class AMO_cas<bits<5> funct5, bit aq, bit rl, bits<3> funct3, string opcodestr,
44+
DAGOperand RC>
45+
: RVInstRAtomic<funct5, aq, rl, funct3, OPC_AMO,
46+
(outs RC:$rd_wb), (ins RC:$rd, GPRMemZeroOffset:$rs1, RC:$rs2),
47+
opcodestr, "$rd, $rs2, $rs1">;
48+
49+
multiclass AMO_cas_aq_rl<bits<5> funct5, bits<3> funct3, string opcodestr,
50+
DAGOperand RC> {
51+
def "" : AMO_cas<funct5, 0, 0, funct3, opcodestr, RC>;
52+
def _AQ : AMO_cas<funct5, 1, 0, funct3, opcodestr # ".aq", RC>;
53+
def _RL : AMO_cas<funct5, 0, 1, funct3, opcodestr # ".rl", RC>;
54+
def _AQ_RL : AMO_cas<funct5, 1, 1, funct3, opcodestr # ".aqrl", RC>;
55+
}
56+
2057
let Predicates = [HasStdExtZacas] in {
21-
defm AMOCAS_W : AMO_rr_aq_rl<0b00101, 0b010, "amocas.w">;
22-
defm AMOCAS_D : AMO_rr_aq_rl<0b00101, 0b011, "amocas.d">;
58+
defm AMOCAS_W : AMO_cas_aq_rl<0b00101, 0b010, "amocas.w", GPR>;
2359
} // Predicates = [HasStdExtZacas]
2460

61+
let Predicates = [HasStdExtZacas, IsRV32], DecoderNamespace = "RV32Zacas" in {
62+
defm AMOCAS_D_RV32 : AMO_cas_aq_rl<0b00101, 0b011, "amocas.d", GPRPairRV32>;
63+
} // Predicates = [HasStdExtZacas, IsRV32]
64+
2565
let Predicates = [HasStdExtZacas, IsRV64] in {
26-
defm AMOCAS_Q : AMO_rr_aq_rl<0b00101, 0b100, "amocas.q">;
66+
defm AMOCAS_D_RV64 : AMO_cas_aq_rl<0b00101, 0b011, "amocas.d", GPR>;
67+
defm AMOCAS_Q : AMO_cas_aq_rl<0b00101, 0b100, "amocas.q", GPRPairRV64>;
2768
} // Predicates = [HasStdExtZacas, IsRV64]
2869

2970
//===----------------------------------------------------------------------===//

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@
22

33
# Non-zero offsets not supported for the third operand (rs1).
44
amocas.w a1, a3, 1(a5) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0
5-
amocas.d a1, a3, 2(a5) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0
5+
amocas.d a0, a2, 2(a5) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0
66

77
# First and second operands (rd and rs2) of amocas.d must be even for RV32.
8-
amocas.d a1, a2, (a1) # CHECK: :[[@LINE]]:10: error: The destination register must be even.
9-
amocas.d a0, a1, (a1) # CHECK: :[[@LINE]]:14: error: The source register must be even.
10-
amocas.d.aq a1, a2, (a1) # CHECK: :[[@LINE]]:13: error: The destination register must be even.
11-
amocas.d.aq a0, a1, (a1) # CHECK: :[[@LINE]]:17: error: The source register must be even.
12-
amocas.d.rl a1, a2, (a1) # CHECK: :[[@LINE]]:13: error: The destination register must be even.
13-
amocas.d.rl a0, a1, (a1) # CHECK: :[[@LINE]]:17: error: The source register must be even.
14-
amocas.d.aqrl a1, a2, (a1) # CHECK: :[[@LINE]]:15: error: The destination register must be even.
15-
amocas.d.aqrl a0, a1, (a1) # CHECK: :[[@LINE]]:19: error: The source register must be even.
8+
amocas.d a1, a2, (a1) # CHECK: :[[@LINE]]:10: error: register must be even
9+
amocas.d a0, a1, (a1) # CHECK: :[[@LINE]]:14: error: register must be even
10+
amocas.d.aq a1, a2, (a1) # CHECK: :[[@LINE]]:13: error: register must be even
11+
amocas.d.aq a0, a1, (a1) # CHECK: :[[@LINE]]:17: error: register must be even
12+
amocas.d.rl a1, a2, (a1) # CHECK: :[[@LINE]]:13: error: register must be even
13+
amocas.d.rl a0, a1, (a1) # CHECK: :[[@LINE]]:17: error: register must be even
14+
amocas.d.aqrl a1, a2, (a1) # CHECK: :[[@LINE]]:15: error: register must be even
15+
amocas.d.aqrl a0, a1, (a1) # CHECK: :[[@LINE]]:19: error: register must be even
1616

1717
# amocas.q is not supported for RV32.
18-
amocas.q a1, a1, (a1) # CHECK: :[[@LINE]]:1: error: instruction requires the following: RV64I Base Instruction Set{{$}}
18+
amocas.q a0, a0, (a1) # CHECK: :[[@LINE]]:1: error: instruction requires the following: RV64I Base Instruction Set{{$}}

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

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
# Non-zero offsets not supported for the third operand (rs1).
44
amocas.w a1, a3, 1(a5) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0
55
amocas.d a1, a3, 2(a5) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0
6-
amocas.q a1, a3, 3(a5) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0
6+
amocas.q a0, a2, 3(a5) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0
77

88
# First and second operands (rd and rs2) of amocas.q must be even.
9-
amocas.q a1, a2, (a1) # CHECK: :[[@LINE]]:10: error: The destination register must be even.
10-
amocas.q a0, a1, (a1) # CHECK: :[[@LINE]]:14: error: The source register must be even.
11-
amocas.q.aq a1, a2, (a1) # CHECK: :[[@LINE]]:13: error: The destination register must be even.
12-
amocas.q.aq a0, a1, (a1) # CHECK: :[[@LINE]]:17: error: The source register must be even.
13-
amocas.q.rl a1, a2, (a1) # CHECK: :[[@LINE]]:13: error: The destination register must be even.
14-
amocas.q.rl a0, a1, (a1) # CHECK: :[[@LINE]]:17: error: The source register must be even.
15-
amocas.q.aqrl a1, a2, (a1) # CHECK: :[[@LINE]]:15: error: The destination register must be even.
16-
amocas.q.aqrl a0, a1, (a1) # CHECK: :[[@LINE]]:19: error: The source register must be even.
9+
amocas.q a1, a2, (a1) # CHECK: :[[@LINE]]:10: error: register must be even
10+
amocas.q a0, a1, (a1) # CHECK: :[[@LINE]]:14: error: register must be even
11+
amocas.q.aq a1, a2, (a1) # CHECK: :[[@LINE]]:13: error: register must be even
12+
amocas.q.aq a0, a1, (a1) # CHECK: :[[@LINE]]:17: error: register must be even
13+
amocas.q.rl a1, a2, (a1) # CHECK: :[[@LINE]]:13: error: register must be even
14+
amocas.q.rl a0, a1, (a1) # CHECK: :[[@LINE]]:17: error: register must be even
15+
amocas.q.aqrl a1, a2, (a1) # CHECK: :[[@LINE]]:15: error: register must be even
16+
amocas.q.aqrl a0, a1, (a1) # CHECK: :[[@LINE]]:19: error: register must be even

0 commit comments

Comments
 (0)