mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-27 07:31:28 +00:00
[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.
This commit is contained in:
parent
14e7dac92a
commit
c053e9f0f4
@ -199,6 +199,8 @@ class RISCVAsmParser : public MCTargetAsmParser {
|
||||
ParseStatus parseInsnDirectiveOpcode(OperandVector &Operands);
|
||||
ParseStatus parseInsnCDirectiveOpcode(OperandVector &Operands);
|
||||
ParseStatus parseGPRAsFPR(OperandVector &Operands);
|
||||
template <bool IsRV64Inst> ParseStatus parseGPRPair(OperandVector &Operands);
|
||||
ParseStatus parseGPRPair(OperandVector &Operands, bool IsRV64Inst);
|
||||
ParseStatus parseFRMArg(OperandVector &Operands);
|
||||
ParseStatus parseFenceArg(OperandVector &Operands);
|
||||
ParseStatus parseReglist(OperandVector &Operands);
|
||||
@ -466,6 +468,12 @@ public:
|
||||
|
||||
bool isGPRAsFPR() const { return isGPR() && Reg.IsGPRAsFPR; }
|
||||
|
||||
bool isGPRPair() const {
|
||||
return Kind == KindTy::Register &&
|
||||
RISCVMCRegisterClasses[RISCV::GPRPairRegClassID].contains(
|
||||
Reg.RegNum);
|
||||
}
|
||||
|
||||
static bool evaluateConstantImm(const MCExpr *Expr, int64_t &Imm,
|
||||
RISCVMCExpr::VariantKind &VK) {
|
||||
if (auto *RE = dyn_cast<RISCVMCExpr>(Expr)) {
|
||||
@ -1300,6 +1308,10 @@ unsigned RISCVAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
|
||||
assert(Op.isReg());
|
||||
|
||||
MCRegister Reg = Op.getReg();
|
||||
if (RISCVMCRegisterClasses[RISCV::GPRPairRegClassID].contains(Reg))
|
||||
continue;
|
||||
|
||||
// FIXME: We should form a paired register during parsing/matching.
|
||||
if (((Reg.id() - RISCV::X0) & 1) != 0)
|
||||
return Match_RequiresEvenGPRs;
|
||||
}
|
||||
@ -2222,6 +2234,48 @@ ParseStatus RISCVAsmParser::parseGPRAsFPR(OperandVector &Operands) {
|
||||
return ParseStatus::Success;
|
||||
}
|
||||
|
||||
template <bool IsRV64>
|
||||
ParseStatus RISCVAsmParser::parseGPRPair(OperandVector &Operands) {
|
||||
return parseGPRPair(Operands, IsRV64);
|
||||
}
|
||||
|
||||
ParseStatus RISCVAsmParser::parseGPRPair(OperandVector &Operands,
|
||||
bool IsRV64Inst) {
|
||||
// If this is not an RV64 GPRPair instruction, don't parse as a GPRPair on
|
||||
// RV64 as it will prevent matching the RV64 version of the same instruction
|
||||
// that doesn't use a GPRPair.
|
||||
// If this is an RV64 GPRPair instruction, there is no RV32 version so we can
|
||||
// still parse as a pair.
|
||||
if (!IsRV64Inst && isRV64())
|
||||
return ParseStatus::NoMatch;
|
||||
|
||||
if (getLexer().isNot(AsmToken::Identifier))
|
||||
return ParseStatus::NoMatch;
|
||||
|
||||
StringRef Name = getLexer().getTok().getIdentifier();
|
||||
MCRegister RegNo = matchRegisterNameHelper(isRVE(), Name);
|
||||
|
||||
if (!RegNo)
|
||||
return ParseStatus::NoMatch;
|
||||
|
||||
if (!RISCVMCRegisterClasses[RISCV::GPRRegClassID].contains(RegNo))
|
||||
return ParseStatus::NoMatch;
|
||||
|
||||
if ((RegNo - RISCV::X0) & 1)
|
||||
return TokError("register must be even");
|
||||
|
||||
SMLoc S = getLoc();
|
||||
SMLoc E = SMLoc::getFromPointer(S.getPointer() + Name.size());
|
||||
getLexer().Lex();
|
||||
|
||||
const MCRegisterInfo *RI = getContext().getRegisterInfo();
|
||||
unsigned Pair = RI->getMatchingSuperReg(
|
||||
RegNo, RISCV::sub_gpr_even,
|
||||
&RISCVMCRegisterClasses[RISCV::GPRPairRegClassID]);
|
||||
Operands.push_back(RISCVOperand::createReg(Pair, S, E));
|
||||
return ParseStatus::Success;
|
||||
}
|
||||
|
||||
ParseStatus RISCVAsmParser::parseFRMArg(OperandVector &Operands) {
|
||||
if (getLexer().isNot(AsmToken::Identifier))
|
||||
return TokError(
|
||||
@ -3335,27 +3389,6 @@ bool RISCVAsmParser::validateInstruction(MCInst &Inst,
|
||||
return Error(Loc, "Operand must be constant 4.");
|
||||
}
|
||||
|
||||
bool IsAMOCAS_D = Opcode == RISCV::AMOCAS_D || Opcode == RISCV::AMOCAS_D_AQ ||
|
||||
Opcode == RISCV::AMOCAS_D_RL ||
|
||||
Opcode == RISCV::AMOCAS_D_AQ_RL;
|
||||
bool IsAMOCAS_Q = Opcode == RISCV::AMOCAS_Q || Opcode == RISCV::AMOCAS_Q_AQ ||
|
||||
Opcode == RISCV::AMOCAS_Q_RL ||
|
||||
Opcode == RISCV::AMOCAS_Q_AQ_RL;
|
||||
if ((!isRV64() && IsAMOCAS_D) || IsAMOCAS_Q) {
|
||||
unsigned Rd = Inst.getOperand(0).getReg();
|
||||
unsigned Rs2 = Inst.getOperand(2).getReg();
|
||||
assert(Rd >= RISCV::X0 && Rd <= RISCV::X31);
|
||||
if ((Rd - RISCV::X0) % 2 != 0) {
|
||||
SMLoc Loc = Operands[1]->getStartLoc();
|
||||
return Error(Loc, "The destination register must be even.");
|
||||
}
|
||||
assert(Rs2 >= RISCV::X0 && Rs2 <= RISCV::X31);
|
||||
if ((Rs2 - RISCV::X0) % 2 != 0) {
|
||||
SMLoc Loc = Operands[2]->getStartLoc();
|
||||
return Error(Loc, "The source register must be even.");
|
||||
}
|
||||
}
|
||||
|
||||
const MCInstrDesc &MCID = MII.get(Opcode);
|
||||
if (!(MCID.TSFlags & RISCVII::ConstraintMask))
|
||||
return false;
|
||||
|
@ -546,6 +546,10 @@ DecodeStatus RISCVDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
|
||||
!STI.hasFeature(RISCV::Feature64Bit),
|
||||
DecoderTableRV32Zdinx32,
|
||||
"RV32Zdinx table (Double in Integer and rv32)");
|
||||
TRY_TO_DECODE(STI.hasFeature(RISCV::FeatureStdExtZacas) &&
|
||||
!STI.hasFeature(RISCV::Feature64Bit),
|
||||
DecoderTableRV32Zacas32,
|
||||
"RV32Zacas table (Compare-And-Swap and rv32)");
|
||||
TRY_TO_DECODE_FEATURE(RISCV::FeatureStdExtZfinx, DecoderTableRVZfinx32,
|
||||
"RVZfinx table (Float in Integer)");
|
||||
TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXVentanaCondOps,
|
||||
|
@ -17,13 +17,54 @@
|
||||
// Zacas (Atomic Compare-and-Swap)
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def GPRPairRV32Operand : AsmOperandClass {
|
||||
let Name = "GPRPairRV32";
|
||||
let ParserMethod = "parseGPRPair<false>";
|
||||
let PredicateMethod = "isGPRPair";
|
||||
let RenderMethod = "addRegOperands";
|
||||
}
|
||||
|
||||
def GPRPairRV64Operand : AsmOperandClass {
|
||||
let Name = "GPRPairRV64";
|
||||
let ParserMethod = "parseGPRPair<true>";
|
||||
let PredicateMethod = "isGPRPair";
|
||||
let RenderMethod = "addRegOperands";
|
||||
}
|
||||
|
||||
def GPRPairRV32 : RegisterOperand<GPRPair> {
|
||||
let ParserMatchClass = GPRPairRV32Operand;
|
||||
}
|
||||
|
||||
def GPRPairRV64 : RegisterOperand<GPRPair> {
|
||||
let ParserMatchClass = GPRPairRV64Operand;
|
||||
}
|
||||
|
||||
let hasSideEffects = 0, mayLoad = 1, mayStore = 1, Constraints = "$rd = $rd_wb" in
|
||||
class AMO_cas<bits<5> funct5, bit aq, bit rl, bits<3> funct3, string opcodestr,
|
||||
DAGOperand RC>
|
||||
: RVInstRAtomic<funct5, aq, rl, funct3, OPC_AMO,
|
||||
(outs RC:$rd_wb), (ins RC:$rd, GPRMemZeroOffset:$rs1, RC:$rs2),
|
||||
opcodestr, "$rd, $rs2, $rs1">;
|
||||
|
||||
multiclass AMO_cas_aq_rl<bits<5> funct5, bits<3> funct3, string opcodestr,
|
||||
DAGOperand RC> {
|
||||
def "" : AMO_cas<funct5, 0, 0, funct3, opcodestr, RC>;
|
||||
def _AQ : AMO_cas<funct5, 1, 0, funct3, opcodestr # ".aq", RC>;
|
||||
def _RL : AMO_cas<funct5, 0, 1, funct3, opcodestr # ".rl", RC>;
|
||||
def _AQ_RL : AMO_cas<funct5, 1, 1, funct3, opcodestr # ".aqrl", RC>;
|
||||
}
|
||||
|
||||
let Predicates = [HasStdExtZacas] in {
|
||||
defm AMOCAS_W : AMO_rr_aq_rl<0b00101, 0b010, "amocas.w">;
|
||||
defm AMOCAS_D : AMO_rr_aq_rl<0b00101, 0b011, "amocas.d">;
|
||||
defm AMOCAS_W : AMO_cas_aq_rl<0b00101, 0b010, "amocas.w", GPR>;
|
||||
} // Predicates = [HasStdExtZacas]
|
||||
|
||||
let Predicates = [HasStdExtZacas, IsRV32], DecoderNamespace = "RV32Zacas" in {
|
||||
defm AMOCAS_D_RV32 : AMO_cas_aq_rl<0b00101, 0b011, "amocas.d", GPRPairRV32>;
|
||||
} // Predicates = [HasStdExtZacas, IsRV32]
|
||||
|
||||
let Predicates = [HasStdExtZacas, IsRV64] in {
|
||||
defm AMOCAS_Q : AMO_rr_aq_rl<0b00101, 0b100, "amocas.q">;
|
||||
defm AMOCAS_D_RV64 : AMO_cas_aq_rl<0b00101, 0b011, "amocas.d", GPR>;
|
||||
defm AMOCAS_Q : AMO_cas_aq_rl<0b00101, 0b100, "amocas.q", GPRPairRV64>;
|
||||
} // Predicates = [HasStdExtZacas, IsRV64]
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -2,17 +2,17 @@
|
||||
|
||||
# Non-zero offsets not supported for the third operand (rs1).
|
||||
amocas.w a1, a3, 1(a5) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0
|
||||
amocas.d a1, a3, 2(a5) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0
|
||||
amocas.d a0, a2, 2(a5) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0
|
||||
|
||||
# First and second operands (rd and rs2) of amocas.d must be even for RV32.
|
||||
amocas.d a1, a2, (a1) # CHECK: :[[@LINE]]:10: error: The destination register must be even.
|
||||
amocas.d a0, a1, (a1) # CHECK: :[[@LINE]]:14: error: The source register must be even.
|
||||
amocas.d.aq a1, a2, (a1) # CHECK: :[[@LINE]]:13: error: The destination register must be even.
|
||||
amocas.d.aq a0, a1, (a1) # CHECK: :[[@LINE]]:17: error: The source register must be even.
|
||||
amocas.d.rl a1, a2, (a1) # CHECK: :[[@LINE]]:13: error: The destination register must be even.
|
||||
amocas.d.rl a0, a1, (a1) # CHECK: :[[@LINE]]:17: error: The source register must be even.
|
||||
amocas.d.aqrl a1, a2, (a1) # CHECK: :[[@LINE]]:15: error: The destination register must be even.
|
||||
amocas.d.aqrl a0, a1, (a1) # CHECK: :[[@LINE]]:19: error: The source register must be even.
|
||||
amocas.d a1, a2, (a1) # CHECK: :[[@LINE]]:10: error: register must be even
|
||||
amocas.d a0, a1, (a1) # CHECK: :[[@LINE]]:14: error: register must be even
|
||||
amocas.d.aq a1, a2, (a1) # CHECK: :[[@LINE]]:13: error: register must be even
|
||||
amocas.d.aq a0, a1, (a1) # CHECK: :[[@LINE]]:17: error: register must be even
|
||||
amocas.d.rl a1, a2, (a1) # CHECK: :[[@LINE]]:13: error: register must be even
|
||||
amocas.d.rl a0, a1, (a1) # CHECK: :[[@LINE]]:17: error: register must be even
|
||||
amocas.d.aqrl a1, a2, (a1) # CHECK: :[[@LINE]]:15: error: register must be even
|
||||
amocas.d.aqrl a0, a1, (a1) # CHECK: :[[@LINE]]:19: error: register must be even
|
||||
|
||||
# amocas.q is not supported for RV32.
|
||||
amocas.q a1, a1, (a1) # CHECK: :[[@LINE]]:1: error: instruction requires the following: RV64I Base Instruction Set{{$}}
|
||||
amocas.q a0, a0, (a1) # CHECK: :[[@LINE]]:1: error: instruction requires the following: RV64I Base Instruction Set{{$}}
|
||||
|
@ -3,14 +3,14 @@
|
||||
# Non-zero offsets not supported for the third operand (rs1).
|
||||
amocas.w a1, a3, 1(a5) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0
|
||||
amocas.d a1, a3, 2(a5) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0
|
||||
amocas.q a1, a3, 3(a5) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0
|
||||
amocas.q a0, a2, 3(a5) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0
|
||||
|
||||
# First and second operands (rd and rs2) of amocas.q must be even.
|
||||
amocas.q a1, a2, (a1) # CHECK: :[[@LINE]]:10: error: The destination register must be even.
|
||||
amocas.q a0, a1, (a1) # CHECK: :[[@LINE]]:14: error: The source register must be even.
|
||||
amocas.q.aq a1, a2, (a1) # CHECK: :[[@LINE]]:13: error: The destination register must be even.
|
||||
amocas.q.aq a0, a1, (a1) # CHECK: :[[@LINE]]:17: error: The source register must be even.
|
||||
amocas.q.rl a1, a2, (a1) # CHECK: :[[@LINE]]:13: error: The destination register must be even.
|
||||
amocas.q.rl a0, a1, (a1) # CHECK: :[[@LINE]]:17: error: The source register must be even.
|
||||
amocas.q.aqrl a1, a2, (a1) # CHECK: :[[@LINE]]:15: error: The destination register must be even.
|
||||
amocas.q.aqrl a0, a1, (a1) # CHECK: :[[@LINE]]:19: error: The source register must be even.
|
||||
amocas.q a1, a2, (a1) # CHECK: :[[@LINE]]:10: error: register must be even
|
||||
amocas.q a0, a1, (a1) # CHECK: :[[@LINE]]:14: error: register must be even
|
||||
amocas.q.aq a1, a2, (a1) # CHECK: :[[@LINE]]:13: error: register must be even
|
||||
amocas.q.aq a0, a1, (a1) # CHECK: :[[@LINE]]:17: error: register must be even
|
||||
amocas.q.rl a1, a2, (a1) # CHECK: :[[@LINE]]:13: error: register must be even
|
||||
amocas.q.rl a0, a1, (a1) # CHECK: :[[@LINE]]:17: error: register must be even
|
||||
amocas.q.aqrl a1, a2, (a1) # CHECK: :[[@LINE]]:15: error: register must be even
|
||||
amocas.q.aqrl a0, a1, (a1) # CHECK: :[[@LINE]]:19: error: register must be even
|
||||
|
Loading…
Reference in New Issue
Block a user