Skip to content

[RISCV] Re-implement Zacas MC layer support to make it usable for CodeGen. #77418

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 54 additions & 21 deletions llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -466,6 +468,12 @@ struct RISCVOperand final : public MCParsedAsmOperand {

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)) {
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like it always evaluates to false.

Copy link
Collaborator Author

@topperc topperc Jan 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an RV32 entry for amocas.d in the table used by MatchOperandParserImpl. The features are not checked before ParseGPRPair is called because we pass ParseForAllFeatures to MatchOperandParserImpl. The IsRV64Inst flag is false when MatchOperandParserImpl/ParseGPRPair is called for amocas.d and true for amocas.q. We need to disable this custom parser for amocas.d on RV64 so that the regular GPR parsing will happen.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I originally wrote amocas.w above but I meant amocas.d. I've fixed it

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allows amocas.w to be parsed correcty in both modes.

Did you mean amocas.d?

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(
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
47 changes: 44 additions & 3 deletions llvm/lib/Target/RISCV/RISCVInstrInfoZa.td
Original file line number Diff line number Diff line change
Expand Up @@ -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]

//===----------------------------------------------------------------------===//
Expand Down
20 changes: 10 additions & 10 deletions llvm/test/MC/RISCV/rv32zacas-invalid.s
Original file line number Diff line number Diff line change
Expand Up @@ -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{{$}}
18 changes: 9 additions & 9 deletions llvm/test/MC/RISCV/rv64zacas-invalid.s
Original file line number Diff line number Diff line change
Expand Up @@ -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