Skip to content

Commit 2e939b6

Browse files
committed
[RISCV] GPR Pairs for Inline Asm
1 parent daac613 commit 2e939b6

File tree

13 files changed

+351
-111
lines changed

13 files changed

+351
-111
lines changed

clang/lib/Basic/Targets/RISCV.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,14 @@ bool RISCVTargetInfo::validateAsmConstraint(
108108
return true;
109109
}
110110
return false;
111+
case 'P':
112+
// An even-odd register pair - GPR
113+
if (Name[1] == 'r') {
114+
Info.setAllowsRegister();
115+
Name += 1;
116+
return true;
117+
}
118+
return false;
111119
case 'v':
112120
// A vector register.
113121
if (Name[1] == 'r' || Name[1] == 'd' || Name[1] == 'm') {
@@ -122,8 +130,9 @@ bool RISCVTargetInfo::validateAsmConstraint(
122130
std::string RISCVTargetInfo::convertConstraint(const char *&Constraint) const {
123131
std::string R;
124132
switch (*Constraint) {
125-
// c* and v* are two-letter constraints on RISC-V.
133+
// c*, P*, and v* are all two-letter constraints on RISC-V.
126134
case 'c':
135+
case 'P':
127136
case 'v':
128137
R = std::string("^") + std::string(Constraint, 2);
129138
Constraint += 1;

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_Pr_wide_scalar(double_xlen_t p) {
42+
// CHECK-LABEL: define{{.*}} {{i128|i64}} @test_Pr_wide_scalar(
43+
// CHECK: call {{i128|i64}} asm sideeffect "", "=^Pr,^Pr"({{i128|i64}} %{{.*}})
44+
double_xlen_t ret;
45+
asm volatile("" : "=Pr"(ret) : "Pr"(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/include/llvm/CodeGen/ValueTypes.td

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -317,20 +317,23 @@ def riscv_nxv16i8x3 : VTVecTup<384, 3, i8, 220>; // RISCV vector tuple(min_num_
317317
def riscv_nxv16i8x4 : VTVecTup<512, 4, i8, 221>; // RISCV vector tuple(min_num_elts=16, nf=4)
318318
def riscv_nxv32i8x2 : VTVecTup<512, 2, i8, 222>; // RISCV vector tuple(min_num_elts=32, nf=2)
319319

320-
def x86mmx : ValueType<64, 223>; // X86 MMX value
321-
def Glue : ValueType<0, 224>; // Pre-RA sched glue
322-
def isVoid : ValueType<0, 225>; // Produces no value
323-
def untyped : ValueType<8, 226> { // Produces an untyped value
320+
def riscv_i32_pair : ValueType<64, 223>; // RISCV pair of RV32 GPRs
321+
def riscv_i64_pair : ValueType<128, 224>; // RISCV pair of RV64 GPRs
322+
323+
def x86mmx : ValueType<64, 225>; // X86 MMX value
324+
def Glue : ValueType<0, 226>; // Pre-RA sched glue
325+
def isVoid : ValueType<0, 227>; // Produces no value
326+
def untyped : ValueType<8, 228> { // Produces an untyped value
324327
let LLVMName = "Untyped";
325328
}
326-
def funcref : ValueType<0, 227>; // WebAssembly's funcref type
327-
def externref : ValueType<0, 228>; // WebAssembly's externref type
328-
def exnref : ValueType<0, 229>; // WebAssembly's exnref type
329-
def x86amx : ValueType<8192, 230>; // X86 AMX value
330-
def i64x8 : ValueType<512, 231>; // 8 Consecutive GPRs (AArch64)
329+
def funcref : ValueType<0, 229>; // WebAssembly's funcref type
330+
def externref : ValueType<0, 230>; // WebAssembly's externref type
331+
def exnref : ValueType<0, 231>; // WebAssembly's exnref type
332+
def x86amx : ValueType<8192, 232>; // X86 AMX value
333+
def i64x8 : ValueType<512, 233>; // 8 Consecutive GPRs (AArch64)
331334
def aarch64svcount
332-
: ValueType<16, 232>; // AArch64 predicate-as-counter
333-
def spirvbuiltin : ValueType<0, 233>; // SPIR-V's builtin type
335+
: ValueType<16, 234>; // AArch64 predicate-as-counter
336+
def spirvbuiltin : ValueType<0, 235>; // SPIR-V's builtin type
334337

335338
let isNormalValueType = false in {
336339
def token : ValueType<0, 504>; // TokenTy

llvm/lib/CodeGen/ValueTypes.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,10 @@ std::string EVT::getEVTString() const {
177177
if (isFloatingPoint())
178178
return "f" + utostr(getSizeInBits());
179179
llvm_unreachable("Invalid EVT!");
180+
case MVT::riscv_i32_pair:
181+
return "riscv_i32_pair";
182+
case MVT::riscv_i64_pair:
183+
return "riscv_i64_pair";
180184
case MVT::bf16: return "bf16";
181185
case MVT::ppcf128: return "ppcf128";
182186
case MVT::isVoid: return "isVoid";
@@ -214,6 +218,8 @@ Type *EVT::getTypeForEVT(LLVMContext &Context) const {
214218
assert(isExtended() && "Type is not extended!");
215219
return LLVMTy;
216220
case MVT::isVoid: return Type::getVoidTy(Context);
221+
case MVT::riscv_i32_pair: return IntegerType::get(Context, 64);
222+
case MVT::riscv_i64_pair: return IntegerType::get(Context, 128);
217223
case MVT::x86mmx: return llvm::FixedVectorType::get(llvm::IntegerType::get(Context, 64), 1);
218224
case MVT::aarch64svcount:
219225
return TargetExtType::get(Context, "aarch64.svcount");

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)) {
@@ -2383,7 +2389,7 @@ ParseStatus RISCVAsmParser::parseGPRPairAsFPR64(OperandVector &Operands) {
23832389
const MCRegisterInfo *RI = getContext().getRegisterInfo();
23842390
MCRegister Pair = RI->getMatchingSuperReg(
23852391
Reg, RISCV::sub_gpr_even,
2386-
&RISCVMCRegisterClasses[RISCV::GPRPairRegClassID]);
2392+
&RISCVMCRegisterClasses[RISCV::GPRF64PairRegClassID]);
23872393
Operands.push_back(RISCVOperand::createReg(Pair, S, E, /*isGPRAsFPR=*/true));
23882394
return ParseStatus::Success;
23892395
}

llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -953,14 +953,43 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
953953
ReplaceNode(Node, Res);
954954
return;
955955
}
956+
case RISCVISD::BuildGPRPair: {
957+
SDValue Ops[] = {
958+
CurDAG->getTargetConstant(RISCV::GPRPairRegClassID, DL, MVT::i32),
959+
Node->getOperand(0),
960+
CurDAG->getTargetConstant(RISCV::sub_gpr_even, DL, MVT::i32),
961+
Node->getOperand(1),
962+
CurDAG->getTargetConstant(RISCV::sub_gpr_odd, DL, MVT::i32)};
963+
964+
SDNode *N = CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, DL,
965+
Subtarget->getXLenPairVT(), Ops);
966+
ReplaceNode(Node, N);
967+
return;
968+
}
969+
case RISCVISD::SplitGPRPair: {
970+
if (!SDValue(Node, 0).use_empty()) {
971+
SDValue Lo = CurDAG->getTargetExtractSubreg(RISCV::sub_gpr_even, DL, VT,
972+
Node->getOperand(0));
973+
ReplaceUses(SDValue(Node, 0), Lo);
974+
}
975+
976+
if (!SDValue(Node, 1).use_empty()) {
977+
SDValue Hi = CurDAG->getTargetExtractSubreg(RISCV::sub_gpr_odd, DL, VT,
978+
Node->getOperand(0));
979+
ReplaceUses(SDValue(Node, 1), Hi);
980+
}
981+
982+
CurDAG->RemoveDeadNode(Node);
983+
return;
984+
}
956985
case RISCVISD::BuildPairF64: {
957986
if (!Subtarget->hasStdExtZdinx())
958987
break;
959988

960989
assert(!Subtarget->is64Bit() && "Unexpected subtarget");
961990

962991
SDValue Ops[] = {
963-
CurDAG->getTargetConstant(RISCV::GPRPairRegClassID, DL, MVT::i32),
992+
CurDAG->getTargetConstant(RISCV::GPRF64PairRegClassID, DL, MVT::i32),
964993
Node->getOperand(0),
965994
CurDAG->getTargetConstant(RISCV::sub_gpr_even, DL, MVT::i32),
966995
Node->getOperand(1),

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,11 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
114114
}
115115

116116
MVT XLenVT = Subtarget.getXLenVT();
117+
MVT XLenPairVT = Subtarget.getXLenPairVT();
117118

118119
// Set up the register classes.
119120
addRegisterClass(XLenVT, &RISCV::GPRRegClass);
121+
addRegisterClass(XLenPairVT, &RISCV::GPRPairRegClass);
120122

121123
if (Subtarget.hasStdExtZfhmin())
122124
addRegisterClass(MVT::f16, &RISCV::FPR16RegClass);
@@ -134,7 +136,7 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
134136
if (Subtarget.is64Bit())
135137
addRegisterClass(MVT::f64, &RISCV::GPRRegClass);
136138
else
137-
addRegisterClass(MVT::f64, &RISCV::GPRPairRegClass);
139+
addRegisterClass(MVT::f64, &RISCV::GPRF64PairRegClass);
138140
}
139141

140142
static const MVT::SimpleValueType BoolVecVTs[] = {
@@ -296,6 +298,11 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
296298
setCondCodeAction(ISD::SETLE, XLenVT, Expand);
297299
}
298300

301+
if (Subtarget.isRV64())
302+
setOperationAction(ISD::BITCAST, MVT::i128, Custom);
303+
else if (Subtarget.isRV32())
304+
setOperationAction(ISD::BITCAST, MVT::i64, Custom);
305+
299306
setOperationAction({ISD::STACKSAVE, ISD::STACKRESTORE}, MVT::Other, Expand);
300307

301308
setOperationAction(ISD::VASTART, MVT::Other, Custom);
@@ -2216,6 +2223,17 @@ bool RISCVTargetLowering::isExtractSubvectorCheap(EVT ResVT, EVT SrcVT,
22162223
return Index == 0 || Index == ResElts;
22172224
}
22182225

2226+
EVT RISCVTargetLowering::getAsmOperandValueType(const DataLayout &DL, Type *Ty,
2227+
bool AllowUnknown) const {
2228+
if (Subtarget.isRV32() && Ty->isIntegerTy(64))
2229+
return MVT::riscv_i32_pair;
2230+
2231+
if (Subtarget.isRV64() && Ty->isIntegerTy(128))
2232+
return MVT::riscv_i64_pair;
2233+
2234+
return TargetLowering::getAsmOperandValueType(DL, Ty, AllowUnknown);
2235+
}
2236+
22192237
MVT RISCVTargetLowering::getRegisterTypeForCallingConv(LLVMContext &Context,
22202238
CallingConv::ID CC,
22212239
EVT VT) const {
@@ -6405,6 +6423,13 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op,
64056423
std::tie(Lo, Hi) = DAG.SplitScalar(Op0, DL, MVT::i32, MVT::i32);
64066424
return DAG.getNode(RISCVISD::BuildPairF64, DL, MVT::f64, Lo, Hi);
64076425
}
6426+
if (VT == Subtarget.getXLenPairVT() && Op0VT.isScalarInteger() &&
6427+
Op0VT.getSizeInBits() == 2 * Subtarget.getXLen()) {
6428+
SDValue Lo, Hi;
6429+
std::tie(Lo, Hi) = DAG.SplitScalar(Op0, DL, XLenVT, XLenVT);
6430+
return DAG.getNode(RISCVISD::BuildGPRPair, DL, Subtarget.getXLenPairVT(),
6431+
Lo, Hi);
6432+
}
64086433

64096434
// Consider other scalar<->scalar casts as legal if the types are legal.
64106435
// Otherwise expand them.
@@ -12846,6 +12871,14 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
1284612871
SDValue RetReg = DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64,
1284712872
NewReg.getValue(0), NewReg.getValue(1));
1284812873
Results.push_back(RetReg);
12874+
} else if (VT.isInteger() &&
12875+
VT.getSizeInBits() == 2 * Subtarget.getXLen() &&
12876+
Op0VT == Subtarget.getXLenPairVT()) {
12877+
SDValue NewReg = DAG.getNode(RISCVISD::SplitGPRPair, DL,
12878+
DAG.getVTList(XLenVT, XLenVT), Op0);
12879+
SDValue RetReg = DAG.getNode(ISD::BUILD_PAIR, DL, VT, NewReg.getValue(0),
12880+
NewReg.getValue(1));
12881+
Results.push_back(RetReg);
1284912882
} else if (!VT.isVector() && Op0VT.isFixedLengthVector() &&
1285012883
isTypeLegal(Op0VT)) {
1285112884
// Custom-legalize bitcasts from fixed-length vector types to illegal
@@ -20090,6 +20123,8 @@ const char *RISCVTargetLowering::getTargetNodeName(unsigned Opcode) const {
2009020123
NODE_NAME_CASE(TAIL)
2009120124
NODE_NAME_CASE(SELECT_CC)
2009220125
NODE_NAME_CASE(BR_CC)
20126+
NODE_NAME_CASE(BuildGPRPair)
20127+
NODE_NAME_CASE(SplitGPRPair)
2009320128
NODE_NAME_CASE(BuildPairF64)
2009420129
NODE_NAME_CASE(SplitF64)
2009520130
NODE_NAME_CASE(ADD_LO)
@@ -20368,6 +20403,8 @@ RISCVTargetLowering::getConstraintType(StringRef Constraint) const {
2036820403
return C_RegisterClass;
2036920404
if (Constraint == "cr" || Constraint == "cf")
2037020405
return C_RegisterClass;
20406+
if (Constraint == "Pr")
20407+
return C_RegisterClass;
2037120408
}
2037220409
return TargetLowering::getConstraintType(Constraint);
2037320410
}
@@ -20389,7 +20426,7 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
2038920426
if (VT == MVT::f32 && Subtarget.hasStdExtZfinx())
2039020427
return std::make_pair(0U, &RISCV::GPRF32NoX0RegClass);
2039120428
if (VT == MVT::f64 && Subtarget.hasStdExtZdinx() && !Subtarget.is64Bit())
20392-
return std::make_pair(0U, &RISCV::GPRPairNoX0RegClass);
20429+
return std::make_pair(0U, &RISCV::GPRF64PairNoX0RegClass);
2039320430
return std::make_pair(0U, &RISCV::GPRNoX0RegClass);
2039420431
case 'f':
2039520432
if (VT == MVT::f16) {
@@ -20406,7 +20443,7 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
2040620443
if (Subtarget.hasStdExtD())
2040720444
return std::make_pair(0U, &RISCV::FPR64RegClass);
2040820445
if (Subtarget.hasStdExtZdinx() && !Subtarget.is64Bit())
20409-
return std::make_pair(0U, &RISCV::GPRPairNoX0RegClass);
20446+
return std::make_pair(0U, &RISCV::GPRF64PairNoX0RegClass);
2041020447
if (Subtarget.hasStdExtZdinx() && Subtarget.is64Bit())
2041120448
return std::make_pair(0U, &RISCV::GPRNoX0RegClass);
2041220449
}
@@ -20448,7 +20485,7 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
2044820485
if (VT == MVT::f32 && Subtarget.hasStdExtZfinx())
2044920486
return std::make_pair(0U, &RISCV::GPRF32CRegClass);
2045020487
if (VT == MVT::f64 && Subtarget.hasStdExtZdinx() && !Subtarget.is64Bit())
20451-
return std::make_pair(0U, &RISCV::GPRPairCRegClass);
20488+
return std::make_pair(0U, &RISCV::GPRF64PairCRegClass);
2045220489
if (!VT.isVector())
2045320490
return std::make_pair(0U, &RISCV::GPRCRegClass);
2045420491
} else if (Constraint == "cf") {
@@ -20466,10 +20503,12 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
2046620503
if (Subtarget.hasStdExtD())
2046720504
return std::make_pair(0U, &RISCV::FPR64CRegClass);
2046820505
if (Subtarget.hasStdExtZdinx() && !Subtarget.is64Bit())
20469-
return std::make_pair(0U, &RISCV::GPRPairCRegClass);
20506+
return std::make_pair(0U, &RISCV::GPRF64PairCRegClass);
2047020507
if (Subtarget.hasStdExtZdinx() && Subtarget.is64Bit())
2047120508
return std::make_pair(0U, &RISCV::GPRCRegClass);
2047220509
}
20510+
} else if (Constraint == "Pr") {
20511+
return std::make_pair(0U, &RISCV::GPRPairNoX0RegClass);
2047320512
}
2047420513

2047520514
// Clang will correctly decode the usage of register name aliases into their
@@ -20630,7 +20669,7 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
2063020669
// Subtarget into account.
2063120670
if (Res.second == &RISCV::GPRF16RegClass ||
2063220671
Res.second == &RISCV::GPRF32RegClass ||
20633-
Res.second == &RISCV::GPRPairRegClass)
20672+
Res.second == &RISCV::GPRF64PairRegClass)
2063420673
return std::make_pair(Res.first, &RISCV::GPRRegClass);
2063520674

2063620675
return Res;

llvm/lib/Target/RISCV/RISCVISelLowering.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ enum NodeType : unsigned {
3535
MRET_GLUE,
3636
CALL,
3737
TAIL,
38+
3839
/// Select with condition operator - This selects between a true value and
3940
/// a false value (ops #3 and #4) based on the boolean result of comparing
4041
/// the lhs and rhs (ops #0 and #1) of a conditional expression with the
@@ -44,6 +45,18 @@ enum NodeType : unsigned {
4445
SELECT_CC,
4546
BR_CC,
4647

48+
/// Turn a pair of `i<xlen>`s into a `riscv_i<xlen>_pair`.
49+
/// - Output: `riscv_i<xlen>_pair`
50+
/// - Input 0: `i<xlen>` low-order bits, for even register.
51+
/// - Input 1: `i<xlen>` high-order bits, for odd register.
52+
BuildGPRPair,
53+
54+
/// Turn a `riscv_i<xlen>_pair` into a pair of `i<xlen>`s.
55+
/// - Output 0: `i<xlen>` low-order bits, from even register.
56+
/// - Output 1: `i<xlen>` high-order bits, from odd register.
57+
/// - Input: `riscv_i<xlen>_pair`
58+
SplitGPRPair,
59+
4760
/// Turns a pair of `i32`s into an `f64`. Needed for rv32d/ilp32.
4861
/// - Output: `f64`.
4962
/// - Input 0: low-order bits (31-0) (as `i32`), for even register.
@@ -544,6 +557,9 @@ class RISCVTargetLowering : public TargetLowering {
544557

545558
bool softPromoteHalfType() const override { return true; }
546559

560+
EVT getAsmOperandValueType(const DataLayout &DL, Type *Ty,
561+
bool AllowUnknown = false) const override;
562+
547563
/// Return the register type for a given MVT, ensuring vectors are treated
548564
/// as a series of gpr sized integers.
549565
MVT getRegisterTypeForCallingConv(LLVMContext &Context, CallingConv::ID CC,

0 commit comments

Comments
 (0)