Skip to content

Commit 4615cc3

Browse files
authored
[RISCV] Inline Assembly Support for GPR Pairs ('R') (#112983)
This patch adds support for getting even-odd general purpose register pairs into and out of inline assembly using the `R` constraint as proposed in riscv-non-isa/riscv-c-api-doc#92 There are a few different pieces to this patch, each of which need their own explanation. - Renames the Register Class used for f64 values on rv32i_zdinx from `GPRPair*` to `GPRF64Pair*`. These register classes are kept broadly unmodified, as their primary value type is used for type inference over selection patterns. This rename affects quite a lot of files. - Adds new `GPRPair*` register classes which will be used for `R` constraints and for instructions that need an even-odd GPR pair. This new type is used for `amocas.d.*`(rv32) and `amocas.q.*`(rv64) in Zacas, instead of the `GPRF64Pair` class being used before. - Marks the new `GPRPair` class legal as for holding a `MVT::Untyped`. Two new RISCVISD node types are added for creating and destructing a pair - `BuildGPRPair` and `SplitGPRPair`, and are introduced when bitcasting to/from the pair type and `untyped`. - Adds functionality to `splitValueIntoRegisterParts` and `joinRegisterPartsIntoValue` to handle changing `i<2*xlen>` MVTs into `untyped` pairs. - Adds an override for `getNumRegisters` to ensure that `i<2*xlen>` values, when going to/from inline assembly, only allocate one (pair) register (they would otherwise allocate two). This is due to a bug in SelectionDAGBuilder.cpp which other backends also work around. - Ensures that Clang understands that `R` is a valid inline assembly constraint. - This also allows `R` to be used for `f64` types on `rv32_zdinx` architectures, where doubles are stored in a GPR pair.
1 parent 9161e6a commit 4615cc3

File tree

11 files changed

+310
-30
lines changed

11 files changed

+310
-30
lines changed

clang/lib/Basic/Targets/RISCV.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ bool RISCVTargetInfo::validateAsmConstraint(
108108
return true;
109109
}
110110
return false;
111+
case 'R':
112+
// An even-odd GPR pair
113+
Info.setAllowsRegister();
114+
return true;
111115
case 'v':
112116
// A vector register.
113117
if (Name[1] == 'r' || Name[1] == 'd' || Name[1] == 'm') {

clang/test/CodeGen/RISCV/riscv-inline-asm.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,19 @@ void test_cf(float f, double d) {
3333
asm volatile("" : "=cf"(cd) : "cf"(d));
3434
}
3535

36+
#if __riscv_xlen == 32
37+
typedef long long double_xlen_t;
38+
#elif __riscv_xlen == 64
39+
typedef __int128_t double_xlen_t;
40+
#endif
41+
double_xlen_t test_R_wide_scalar(double_xlen_t p) {
42+
// CHECK-LABEL: define{{.*}} {{i128|i64}} @test_R_wide_scalar(
43+
// CHECK: call {{i128|i64}} asm sideeffect "", "=R,R"({{i128|i64}} %{{.*}})
44+
double_xlen_t ret;
45+
asm volatile("" : "=R"(ret) : "R"(p));
46+
return ret;
47+
}
48+
3649
void test_I(void) {
3750
// CHECK-LABEL: define{{.*}} void @test_I()
3851
// CHECK: call void asm sideeffect "", "I"(i32 2047)

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

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,12 @@ struct RISCVOperand final : public MCParsedAsmOperand {
481481
RISCVMCRegisterClasses[RISCV::GPRRegClassID].contains(Reg.RegNum);
482482
}
483483

484+
bool isGPRPair() const {
485+
return Kind == KindTy::Register &&
486+
RISCVMCRegisterClasses[RISCV::GPRPairRegClassID].contains(
487+
Reg.RegNum);
488+
}
489+
484490
bool isGPRF16() const {
485491
return Kind == KindTy::Register &&
486492
RISCVMCRegisterClasses[RISCV::GPRF16RegClassID].contains(Reg.RegNum);
@@ -491,17 +497,17 @@ struct RISCVOperand final : public MCParsedAsmOperand {
491497
RISCVMCRegisterClasses[RISCV::GPRF32RegClassID].contains(Reg.RegNum);
492498
}
493499

494-
bool isGPRAsFPR() const { return isGPR() && Reg.IsGPRAsFPR; }
495-
bool isGPRAsFPR16() const { return isGPRF16() && Reg.IsGPRAsFPR; }
496-
bool isGPRAsFPR32() const { return isGPRF32() && Reg.IsGPRAsFPR; }
497-
bool isGPRPairAsFPR() const { return isGPRPair() && Reg.IsGPRAsFPR; }
498-
499-
bool isGPRPair() const {
500+
bool isGPRF64Pair() const {
500501
return Kind == KindTy::Register &&
501-
RISCVMCRegisterClasses[RISCV::GPRPairRegClassID].contains(
502+
RISCVMCRegisterClasses[RISCV::GPRF64PairRegClassID].contains(
502503
Reg.RegNum);
503504
}
504505

506+
bool isGPRAsFPR() const { return isGPR() && Reg.IsGPRAsFPR; }
507+
bool isGPRAsFPR16() const { return isGPRF16() && Reg.IsGPRAsFPR; }
508+
bool isGPRAsFPR32() const { return isGPRF32() && Reg.IsGPRAsFPR; }
509+
bool isGPRPairAsFPR64() const { return isGPRF64Pair() && Reg.IsGPRAsFPR; }
510+
505511
static bool evaluateConstantImm(const MCExpr *Expr, int64_t &Imm,
506512
RISCVMCExpr::VariantKind &VK) {
507513
if (auto *RE = dyn_cast<RISCVMCExpr>(Expr)) {
@@ -2399,7 +2405,7 @@ ParseStatus RISCVAsmParser::parseGPRPairAsFPR64(OperandVector &Operands) {
23992405
const MCRegisterInfo *RI = getContext().getRegisterInfo();
24002406
MCRegister Pair = RI->getMatchingSuperReg(
24012407
Reg, RISCV::sub_gpr_even,
2402-
&RISCVMCRegisterClasses[RISCV::GPRPairRegClassID]);
2408+
&RISCVMCRegisterClasses[RISCV::GPRF64PairRegClassID]);
24032409
Operands.push_back(RISCVOperand::createReg(Pair, S, E, /*isGPRAsFPR=*/true));
24042410
return ParseStatus::Success;
24052411
}

llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -952,27 +952,36 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
952952
ReplaceNode(Node, Res);
953953
return;
954954
}
955+
case RISCVISD::BuildGPRPair:
955956
case RISCVISD::BuildPairF64: {
956-
if (!Subtarget->hasStdExtZdinx())
957+
if (Opcode == RISCVISD::BuildPairF64 && !Subtarget->hasStdExtZdinx())
957958
break;
958959

959-
assert(!Subtarget->is64Bit() && "Unexpected subtarget");
960+
assert((!Subtarget->is64Bit() || Opcode == RISCVISD::BuildGPRPair) &&
961+
"BuildPairF64 only handled here on rv32i_zdinx");
962+
963+
int RegClassID = (Opcode == RISCVISD::BuildGPRPair)
964+
? RISCV::GPRPairRegClassID
965+
: RISCV::GPRF64PairRegClassID;
966+
MVT OutType = (Opcode == RISCVISD::BuildGPRPair) ? MVT::Untyped : MVT::f64;
960967

961968
SDValue Ops[] = {
962-
CurDAG->getTargetConstant(RISCV::GPRPairRegClassID, DL, MVT::i32),
969+
CurDAG->getTargetConstant(RegClassID, DL, MVT::i32),
963970
Node->getOperand(0),
964971
CurDAG->getTargetConstant(RISCV::sub_gpr_even, DL, MVT::i32),
965972
Node->getOperand(1),
966973
CurDAG->getTargetConstant(RISCV::sub_gpr_odd, DL, MVT::i32)};
967974

968975
SDNode *N =
969-
CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, DL, MVT::f64, Ops);
976+
CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, DL, OutType, Ops);
970977
ReplaceNode(Node, N);
971978
return;
972979
}
980+
case RISCVISD::SplitGPRPair:
973981
case RISCVISD::SplitF64: {
974-
if (Subtarget->hasStdExtZdinx()) {
975-
assert(!Subtarget->is64Bit() && "Unexpected subtarget");
982+
if (Subtarget->hasStdExtZdinx() || Opcode != RISCVISD::SplitF64) {
983+
assert((!Subtarget->is64Bit() || Opcode == RISCVISD::SplitGPRPair) &&
984+
"SplitF64 only handled here on rv32i_zdinx");
976985

977986
if (!SDValue(Node, 0).use_empty()) {
978987
SDValue Lo = CurDAG->getTargetExtractSubreg(RISCV::sub_gpr_even, DL, VT,
@@ -990,6 +999,9 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
990999
return;
9911000
}
9921001

1002+
assert(Opcode != RISCVISD::SplitGPRPair &&
1003+
"SplitGPRPair should already be handled");
1004+
9931005
if (!Subtarget->hasStdExtZfa())
9941006
break;
9951007
assert(Subtarget->hasStdExtD() && !Subtarget->is64Bit() &&

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
133133
if (Subtarget.is64Bit())
134134
addRegisterClass(MVT::f64, &RISCV::GPRRegClass);
135135
else
136-
addRegisterClass(MVT::f64, &RISCV::GPRPairRegClass);
136+
addRegisterClass(MVT::f64, &RISCV::GPRF64PairRegClass);
137137
}
138138

139139
static const MVT::SimpleValueType BoolVecVTs[] = {
@@ -2233,6 +2233,17 @@ MVT RISCVTargetLowering::getRegisterTypeForCallingConv(LLVMContext &Context,
22332233
return PartVT;
22342234
}
22352235

2236+
unsigned
2237+
RISCVTargetLowering::getNumRegisters(LLVMContext &Context, EVT VT,
2238+
std::optional<MVT> RegisterVT) const {
2239+
// Pair inline assembly operand
2240+
if (VT == (Subtarget.is64Bit() ? MVT::i128 : MVT::i64) && RegisterVT &&
2241+
*RegisterVT == MVT::Untyped)
2242+
return 1;
2243+
2244+
return TargetLowering::getNumRegisters(Context, VT, RegisterVT);
2245+
}
2246+
22362247
unsigned RISCVTargetLowering::getNumRegistersForCallingConv(LLVMContext &Context,
22372248
CallingConv::ID CC,
22382249
EVT VT) const {
@@ -20196,6 +20207,8 @@ const char *RISCVTargetLowering::getTargetNodeName(unsigned Opcode) const {
2019620207
NODE_NAME_CASE(TAIL)
2019720208
NODE_NAME_CASE(SELECT_CC)
2019820209
NODE_NAME_CASE(BR_CC)
20210+
NODE_NAME_CASE(BuildGPRPair)
20211+
NODE_NAME_CASE(SplitGPRPair)
2019920212
NODE_NAME_CASE(BuildPairF64)
2020020213
NODE_NAME_CASE(SplitF64)
2020120214
NODE_NAME_CASE(ADD_LO)
@@ -20456,6 +20469,7 @@ RISCVTargetLowering::getConstraintType(StringRef Constraint) const {
2045620469
default:
2045720470
break;
2045820471
case 'f':
20472+
case 'R':
2045920473
return C_RegisterClass;
2046020474
case 'I':
2046120475
case 'J':
@@ -20493,7 +20507,7 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
2049320507
if (VT == MVT::f32 && Subtarget.hasStdExtZfinx())
2049420508
return std::make_pair(0U, &RISCV::GPRF32NoX0RegClass);
2049520509
if (VT == MVT::f64 && Subtarget.hasStdExtZdinx() && !Subtarget.is64Bit())
20496-
return std::make_pair(0U, &RISCV::GPRPairNoX0RegClass);
20510+
return std::make_pair(0U, &RISCV::GPRF64PairNoX0RegClass);
2049720511
return std::make_pair(0U, &RISCV::GPRNoX0RegClass);
2049820512
case 'f':
2049920513
if (VT == MVT::f16) {
@@ -20510,11 +20524,15 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
2051020524
if (Subtarget.hasStdExtD())
2051120525
return std::make_pair(0U, &RISCV::FPR64RegClass);
2051220526
if (Subtarget.hasStdExtZdinx() && !Subtarget.is64Bit())
20513-
return std::make_pair(0U, &RISCV::GPRPairNoX0RegClass);
20527+
return std::make_pair(0U, &RISCV::GPRF64PairNoX0RegClass);
2051420528
if (Subtarget.hasStdExtZdinx() && Subtarget.is64Bit())
2051520529
return std::make_pair(0U, &RISCV::GPRNoX0RegClass);
2051620530
}
2051720531
break;
20532+
case 'R':
20533+
if (VT == MVT::f64 && !Subtarget.is64Bit() && Subtarget.hasStdExtZdinx())
20534+
return std::make_pair(0U, &RISCV::GPRF64PairCRegClass);
20535+
return std::make_pair(0U, &RISCV::GPRPairNoX0RegClass);
2051820536
default:
2051920537
break;
2052020538
}
@@ -20552,7 +20570,7 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
2055220570
if (VT == MVT::f32 && Subtarget.hasStdExtZfinx())
2055320571
return std::make_pair(0U, &RISCV::GPRF32CRegClass);
2055420572
if (VT == MVT::f64 && Subtarget.hasStdExtZdinx() && !Subtarget.is64Bit())
20555-
return std::make_pair(0U, &RISCV::GPRPairCRegClass);
20573+
return std::make_pair(0U, &RISCV::GPRF64PairCRegClass);
2055620574
if (!VT.isVector())
2055720575
return std::make_pair(0U, &RISCV::GPRCRegClass);
2055820576
} else if (Constraint == "cf") {
@@ -20570,7 +20588,7 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
2057020588
if (Subtarget.hasStdExtD())
2057120589
return std::make_pair(0U, &RISCV::FPR64CRegClass);
2057220590
if (Subtarget.hasStdExtZdinx() && !Subtarget.is64Bit())
20573-
return std::make_pair(0U, &RISCV::GPRPairCRegClass);
20591+
return std::make_pair(0U, &RISCV::GPRF64PairCRegClass);
2057420592
if (Subtarget.hasStdExtZdinx() && Subtarget.is64Bit())
2057520593
return std::make_pair(0U, &RISCV::GPRCRegClass);
2057620594
}
@@ -20734,7 +20752,7 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
2073420752
// Subtarget into account.
2073520753
if (Res.second == &RISCV::GPRF16RegClass ||
2073620754
Res.second == &RISCV::GPRF32RegClass ||
20737-
Res.second == &RISCV::GPRPairRegClass)
20755+
Res.second == &RISCV::GPRF64PairRegClass)
2073820756
return std::make_pair(Res.first, &RISCV::GPRRegClass);
2073920757

2074020758
return Res;
@@ -21360,6 +21378,16 @@ bool RISCVTargetLowering::splitValueIntoRegisterParts(
2136021378
unsigned NumParts, MVT PartVT, std::optional<CallingConv::ID> CC) const {
2136121379
bool IsABIRegCopy = CC.has_value();
2136221380
EVT ValueVT = Val.getValueType();
21381+
21382+
if (ValueVT == (Subtarget.is64Bit() ? MVT::i128 : MVT::i64) &&
21383+
NumParts == 1 && PartVT == MVT::Untyped) {
21384+
// Pairs in Inline Assembly
21385+
MVT XLenVT = Subtarget.getXLenVT();
21386+
auto [Lo, Hi] = DAG.SplitScalar(Val, DL, XLenVT, XLenVT);
21387+
Parts[0] = DAG.getNode(RISCVISD::BuildGPRPair, DL, MVT::Untyped, Lo, Hi);
21388+
return true;
21389+
}
21390+
2136321391
if (IsABIRegCopy && (ValueVT == MVT::f16 || ValueVT == MVT::bf16) &&
2136421392
PartVT == MVT::f32) {
2136521393
// Cast the [b]f16 to i16, extend to i32, pad with ones to make a float
@@ -21436,6 +21464,17 @@ SDValue RISCVTargetLowering::joinRegisterPartsIntoValue(
2143621464
SelectionDAG &DAG, const SDLoc &DL, const SDValue *Parts, unsigned NumParts,
2143721465
MVT PartVT, EVT ValueVT, std::optional<CallingConv::ID> CC) const {
2143821466
bool IsABIRegCopy = CC.has_value();
21467+
21468+
if (ValueVT == (Subtarget.is64Bit() ? MVT::i128 : MVT::i64) &&
21469+
NumParts == 1 && PartVT == MVT::Untyped) {
21470+
// Pairs in Inline Assembly
21471+
MVT XLenVT = Subtarget.getXLenVT();
21472+
SDValue Res = DAG.getNode(RISCVISD::SplitGPRPair, DL,
21473+
DAG.getVTList(XLenVT, XLenVT), Parts[0]);
21474+
return DAG.getNode(ISD::BUILD_PAIR, DL, ValueVT, Res.getValue(0),
21475+
Res.getValue(1));
21476+
}
21477+
2143921478
if (IsABIRegCopy && (ValueVT == MVT::f16 || ValueVT == MVT::bf16) &&
2144021479
PartVT == MVT::f32) {
2144121480
SDValue Val = Parts[0];

llvm/lib/Target/RISCV/RISCVISelLowering.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ enum NodeType : unsigned {
4444
SELECT_CC,
4545
BR_CC,
4646

47+
/// Turn a pair of `i<xlen>`s into an even-odd register pair (`untyped`).
48+
/// - Output: `untyped` even-odd register pair
49+
/// - Input 0: `i<xlen>` low-order bits, for even register.
50+
/// - Input 1: `i<xlen>` high-order bits, for odd register.
51+
BuildGPRPair,
52+
53+
/// Turn an even-odd register pair (`untyped`) into a pair of `i<xlen>`s.
54+
/// - Output 0: `i<xlen>` low-order bits, from even register.
55+
/// - Output 1: `i<xlen>` high-order bits, from odd register.
56+
/// - Input: `untyped` even-odd register pair
57+
SplitGPRPair,
58+
4759
/// Turns a pair of `i32`s into an `f64`. Needed for rv32d/ilp32.
4860
/// - Output: `f64`.
4961
/// - Input 0: low-order bits (31-0) (as `i32`), for even register.
@@ -547,6 +559,11 @@ class RISCVTargetLowering : public TargetLowering {
547559
MVT getRegisterTypeForCallingConv(LLVMContext &Context, CallingConv::ID CC,
548560
EVT VT) const override;
549561

562+
/// Return the number of registers for a given MVT, for inline assembly
563+
unsigned
564+
getNumRegisters(LLVMContext &Context, EVT VT,
565+
std::optional<MVT> RegisterVT = std::nullopt) const override;
566+
550567
/// Return the number of registers for a given MVT, ensuring vectors are
551568
/// treated as a series of gpr sized integers.
552569
unsigned getNumRegistersForCallingConv(LLVMContext &Context,

llvm/lib/Target/RISCV/RISCVInstrInfoD.td

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def AddrRegImmINX : ComplexPattern<iPTR, 2, "SelectAddrRegImmRV32Zdinx">;
3636
def GPRPairAsFPR : AsmOperandClass {
3737
let Name = "GPRPairAsFPR";
3838
let ParserMethod = "parseGPRPairAsFPR64";
39-
let PredicateMethod = "isGPRPairAsFPR";
39+
let PredicateMethod = "isGPRPairAsFPR64";
4040
let RenderMethod = "addRegOperands";
4141
}
4242

@@ -52,7 +52,7 @@ def FPR64INX : RegisterOperand<GPR> {
5252
let DecoderMethod = "DecodeGPRRegisterClass";
5353
}
5454

55-
def FPR64IN32X : RegisterOperand<GPRPair> {
55+
def FPR64IN32X : RegisterOperand<GPRF64Pair> {
5656
let ParserMatchClass = GPRPairAsFPR;
5757
}
5858

@@ -523,15 +523,15 @@ def PseudoFROUND_D_IN32X : PseudoFROUND<FPR64IN32X, f64>;
523523

524524
/// Loads
525525
let isCall = 0, mayLoad = 1, mayStore = 0, Size = 8, isCodeGenOnly = 1 in
526-
def PseudoRV32ZdinxLD : Pseudo<(outs GPRPair:$dst), (ins GPR:$rs1, simm12:$imm12), []>;
526+
def PseudoRV32ZdinxLD : Pseudo<(outs GPRF64Pair:$dst), (ins GPR:$rs1, simm12:$imm12), []>;
527527
def : Pat<(f64 (load (AddrRegImmINX (XLenVT GPR:$rs1), simm12:$imm12))),
528528
(PseudoRV32ZdinxLD GPR:$rs1, simm12:$imm12)>;
529529

530530
/// Stores
531531
let isCall = 0, mayLoad = 0, mayStore = 1, Size = 8, isCodeGenOnly = 1 in
532-
def PseudoRV32ZdinxSD : Pseudo<(outs), (ins GPRPair:$rs2, GPRNoX0:$rs1, simm12:$imm12), []>;
533-
def : Pat<(store (f64 GPRPair:$rs2), (AddrRegImmINX (XLenVT GPR:$rs1), simm12:$imm12)),
534-
(PseudoRV32ZdinxSD GPRPair:$rs2, GPR:$rs1, simm12:$imm12)>;
532+
def PseudoRV32ZdinxSD : Pseudo<(outs), (ins GPRF64Pair:$rs2, GPRNoX0:$rs1, simm12:$imm12), []>;
533+
def : Pat<(store (f64 GPRF64Pair:$rs2), (AddrRegImmINX (XLenVT GPR:$rs1), simm12:$imm12)),
534+
(PseudoRV32ZdinxSD GPRF64Pair:$rs2, GPR:$rs1, simm12:$imm12)>;
535535
} // Predicates = [HasStdExtZdinx, IsRV32]
536536

537537
let Predicates = [HasStdExtD, IsRV32] in {

llvm/lib/Target/RISCV/RISCVRegisterInfo.td

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,8 @@ let RegAltNameIndices = [ABIRegAltName] in {
208208

209209
def XLenVT : ValueTypeByHwMode<[RV32, RV64],
210210
[i32, i64]>;
211+
defvar XLenPairVT = untyped;
212+
211213
// Allow f64 in GPR for ZDINX on RV64.
212214
def XLenFVT : ValueTypeByHwMode<[RV64],
213215
[f64]>;
@@ -323,7 +325,7 @@ let RegAltNameIndices = [ABIRegAltName] in {
323325

324326
let RegInfos = XLenPairRI,
325327
DecoderMethod = "DecodeGPRPairRegisterClass" in {
326-
def GPRPair : RISCVRegisterClass<[XLenPairFVT], 64, (add
328+
def GPRPair : RISCVRegisterClass<[XLenPairVT], 64, (add
327329
X10_X11, X12_X13, X14_X15, X16_X17,
328330
X6_X7,
329331
X28_X29, X30_X31,
@@ -332,11 +334,11 @@ def GPRPair : RISCVRegisterClass<[XLenPairFVT], 64, (add
332334
X0_Pair, X2_X3, X4_X5
333335
)>;
334336

335-
def GPRPairNoX0 : RISCVRegisterClass<[XLenPairFVT], 64, (sub GPRPair, X0_Pair)>;
337+
def GPRPairNoX0 : RISCVRegisterClass<[XLenPairVT], 64, (sub GPRPair, X0_Pair)>;
336338
} // let RegInfos = XLenPairRI, DecoderMethod = "DecodeGPRPairRegisterClass"
337339

338340
let RegInfos = XLenPairRI in
339-
def GPRPairC : RISCVRegisterClass<[XLenPairFVT], 64, (add
341+
def GPRPairC : RISCVRegisterClass<[XLenPairVT], 64, (add
340342
X10_X11, X12_X13, X14_X15, X8_X9
341343
)>;
342344

@@ -462,6 +464,21 @@ def GPRF32C : RISCVRegisterClass<[f32], 32, (add (sequence "X%u_W", 10, 15),
462464
(sequence "X%u_W", 8, 9))>;
463465
def GPRF32NoX0 : RISCVRegisterClass<[f32], 32, (sub GPRF32, X0_W)>;
464466

467+
let DecoderMethod = "DecodeGPRPairRegisterClass" in
468+
def GPRF64Pair : RISCVRegisterClass<[XLenPairFVT], 64, (add
469+
X10_X11, X12_X13, X14_X15, X16_X17,
470+
X6_X7,
471+
X28_X29, X30_X31,
472+
X8_X9,
473+
X18_X19, X20_X21, X22_X23, X24_X25, X26_X27,
474+
X0_Pair, X2_X3, X4_X5
475+
)>;
476+
477+
def GPRF64PairC : RISCVRegisterClass<[XLenPairFVT], 64, (add
478+
X10_X11, X12_X13, X14_X15, X8_X9
479+
)>;
480+
481+
def GPRF64PairNoX0 : RISCVRegisterClass<[XLenPairFVT], 64, (sub GPRF64Pair, X0_Pair)>;
465482

466483
//===----------------------------------------------------------------------===//
467484
// Vector type mapping to LLVM types.

0 commit comments

Comments
 (0)