Skip to content

Commit a7dd519

Browse files
committed
amend! [RISCV] GPR Pairs for Inline Asm using Pr
[RISCV] GPR Pairs for Inline Asm using `R` 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. - Adds Conditions to the GPRF64Pair-related changes to `LowerOperation` and `ReplaceNodeResults` which match when BITCAST for the relevant types should be handled in a custom manner. - This also allows `R` to be used for `f64` types on `rv32_zdinx` architectures, where doubles are stored in a GPR pair.
1 parent a3f95db commit a7dd519

File tree

6 files changed

+30
-36
lines changed

6 files changed

+30
-36
lines changed

clang/lib/Basic/Targets/RISCV.cpp

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -108,14 +108,10 @@ 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;
111+
case 'R':
112+
// An even-odd GPR pair
113+
Info.setAllowsRegister();
114+
return true;
119115
case 'v':
120116
// A vector register.
121117
if (Name[1] == 'r' || Name[1] == 'd' || Name[1] == 'm') {
@@ -130,9 +126,8 @@ bool RISCVTargetInfo::validateAsmConstraint(
130126
std::string RISCVTargetInfo::convertConstraint(const char *&Constraint) const {
131127
std::string R;
132128
switch (*Constraint) {
133-
// c*, P*, and v* are all two-letter constraints on RISC-V.
129+
// c* and v* are two-letter constraints on RISC-V.
134130
case 'c':
135-
case 'P':
136131
case 'v':
137132
R = std::string("^") + std::string(Constraint, 2);
138133
Constraint += 1;

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ typedef long long double_xlen_t;
3838
#elif __riscv_xlen == 64
3939
typedef __int128_t double_xlen_t;
4040
#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}} %{{.*}})
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}} %{{.*}})
4444
double_xlen_t ret;
45-
asm volatile("" : "=Pr"(ret) : "Pr"(p));
45+
asm volatile("" : "=R"(ret) : "R"(p));
4646
return ret;
4747
}
4848

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20458,6 +20458,7 @@ RISCVTargetLowering::getConstraintType(StringRef Constraint) const {
2045820458
default:
2045920459
break;
2046020460
case 'f':
20461+
case 'R':
2046120462
return C_RegisterClass;
2046220463
case 'I':
2046320464
case 'J':
@@ -20474,8 +20475,6 @@ RISCVTargetLowering::getConstraintType(StringRef Constraint) const {
2047420475
return C_RegisterClass;
2047520476
if (Constraint == "cr" || Constraint == "cf")
2047620477
return C_RegisterClass;
20477-
if (Constraint == "Pr")
20478-
return C_RegisterClass;
2047920478
}
2048020479
return TargetLowering::getConstraintType(Constraint);
2048120480
}
@@ -20519,6 +20518,10 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
2051920518
return std::make_pair(0U, &RISCV::GPRNoX0RegClass);
2052020519
}
2052120520
break;
20521+
case 'R':
20522+
if (VT == MVT::f64 && !Subtarget.is64Bit() && Subtarget.hasStdExtZdinx())
20523+
return std::make_pair(0U, &RISCV::GPRF64PairCRegClass);
20524+
return std::make_pair(0U, &RISCV::GPRPairNoX0RegClass);
2052220525
default:
2052320526
break;
2052420527
}
@@ -20578,10 +20581,6 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
2057820581
if (Subtarget.hasStdExtZdinx() && Subtarget.is64Bit())
2057920582
return std::make_pair(0U, &RISCV::GPRCRegClass);
2058020583
}
20581-
} else if (Constraint == "Pr") {
20582-
if (VT == MVT::f64 && !Subtarget.is64Bit() && Subtarget.hasStdExtZdinx())
20583-
return std::make_pair(0U, &RISCV::GPRF64PairCRegClass);
20584-
return std::make_pair(0U, &RISCV::GPRPairNoX0RegClass);
2058520584
}
2058620585

2058720586
// Clang will correctly decode the usage of register name aliases into their

llvm/test/CodeGen/RISCV/rv32-inline-asm-pairs.ll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ define i64 @test_Pr_wide_scalar_simple(i64 noundef %0) nounwind {
1212
; CHECK-NEXT: mv a1, a3
1313
; CHECK-NEXT: ret
1414
entry:
15-
%1 = call i64 asm sideeffect "/* $0 <- $1 */", "=&^Pr,^Pr"(i64 %0)
15+
%1 = call i64 asm sideeffect "/* $0 <- $1 */", "=&R,R"(i64 %0)
1616
ret i64 %1
1717
}
1818

@@ -29,7 +29,7 @@ entry:
2929
%1 = zext i32 %0 to i64
3030
%2 = shl i64 %1, 32
3131
%3 = or i64 %1, %2
32-
%4 = call i64 asm sideeffect "/* $0 <- $1 */", "=&^Pr,^Pr"(i64 %3)
32+
%4 = call i64 asm sideeffect "/* $0 <- $1 */", "=&R,R"(i64 %3)
3333
%5 = trunc i64 %4 to i32
3434
%6 = lshr i64 %4, 32
3535
%7 = trunc i64 %6 to i32
@@ -63,7 +63,7 @@ entry:
6363
store i64 %1, ptr %3, align 8
6464
%4 = load ptr, ptr %2, align 4
6565
%5 = load i64, ptr %3, align 8
66-
%6 = call { ptr, i64 } asm sideeffect "/* $0; $1 */", "=r,=^Pr,0,1"(ptr %4, i64 %5)
66+
%6 = call { ptr, i64 } asm sideeffect "/* $0; $1 */", "=r,=R,0,1"(ptr %4, i64 %5)
6767
%7 = extractvalue { ptr, i64} %6, 0
6868
%8 = extractvalue { ptr, i64 } %6, 1
6969
store ptr %7, ptr %2, align 4

llvm/test/CodeGen/RISCV/rv64-inline-asm-pairs.ll

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \
33
; RUN: | FileCheck %s
44

5-
define i128 @test_Pr_wide_scalar_simple(i128 noundef %0) nounwind {
6-
; CHECK-LABEL: test_Pr_wide_scalar_simple:
5+
define i128 @test_R_wide_scalar_simple(i128 noundef %0) nounwind {
6+
; CHECK-LABEL: test_R_wide_scalar_simple:
77
; CHECK: # %bb.0: # %entry
88
; CHECK-NEXT: #APP
99
; CHECK-NEXT: # a2 <- a0
@@ -12,12 +12,12 @@ define i128 @test_Pr_wide_scalar_simple(i128 noundef %0) nounwind {
1212
; CHECK-NEXT: mv a1, a3
1313
; CHECK-NEXT: ret
1414
entry:
15-
%1 = call i128 asm sideeffect "/* $0 <- $1 */", "=&^Pr,^Pr"(i128 %0)
15+
%1 = call i128 asm sideeffect "/* $0 <- $1 */", "=&R,R"(i128 %0)
1616
ret i128 %1
1717
}
1818

19-
define i64 @test_Pr_wide_scalar_with_ops(i64 noundef %0) nounwind {
20-
; CHECK-LABEL: test_Pr_wide_scalar_with_ops:
19+
define i64 @test_R_wide_scalar_with_ops(i64 noundef %0) nounwind {
20+
; CHECK-LABEL: test_R_wide_scalar_with_ops:
2121
; CHECK: # %bb.0: # %entry
2222
; CHECK-NEXT: mv a1, a0
2323
; CHECK-NEXT: #APP
@@ -29,16 +29,16 @@ entry:
2929
%1 = zext i64 %0 to i128
3030
%2 = shl i128 %1, 64
3131
%3 = or i128 %1, %2
32-
%4 = call i128 asm sideeffect "/* $0 <- $1 */", "=&^Pr,^Pr"(i128 %3)
32+
%4 = call i128 asm sideeffect "/* $0 <- $1 */", "=&R,R"(i128 %3)
3333
%5 = trunc i128 %4 to i64
3434
%6 = lshr i128 %4, 64
3535
%7 = trunc i128 %6 to i64
3636
%8 = or i64 %5, %7
3737
ret i64 %8
3838
}
3939

40-
define i128 @test_Pr_wide_scalar_inout(ptr %0, i128 noundef %1) nounwind {
41-
; CHECK-LABEL: test_Pr_wide_scalar_inout:
40+
define i128 @test_R_wide_scalar_inout(ptr %0, i128 noundef %1) nounwind {
41+
; CHECK-LABEL: test_R_wide_scalar_inout:
4242
; CHECK: # %bb.0: # %entry
4343
; CHECK-NEXT: addi sp, sp, -32
4444
; CHECK-NEXT: mv a3, a2
@@ -63,7 +63,7 @@ entry:
6363
store i128 %1, ptr %3, align 16
6464
%4 = load ptr, ptr %2, align 8
6565
%5 = load i128, ptr %3, align 16
66-
%6 = call { ptr, i128 } asm sideeffect "/* $0; $1 */", "=r,=^Pr,0,1"(ptr %4, i128 %5)
66+
%6 = call { ptr, i128 } asm sideeffect "/* $0; $1 */", "=r,=R,0,1"(ptr %4, i128 %5)
6767
%7 = extractvalue { ptr, i128} %6, 0
6868
%8 = extractvalue { ptr, i128 } %6, 1
6969
store ptr %7, ptr %2, align 8

llvm/test/CodeGen/RISCV/zdinx-asm-constraint.ll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
; RUN: llc -mtriple=riscv32 -mattr=+zdinx -verify-machineinstrs < %s \
33
; RUN: -target-abi=ilp32 -mattr=+zhinx | FileCheck %s
44

5-
;; These tests cover the use of `r` and `cr` constraints for floating point values on rv32.
5+
;; These tests cover the use of `r`, `R`, and `cr` constraints for floating point values on rv32.
66
;;
77
;; In particular, there is significant complexity around using paired GPRs for double values on rv32.
88

@@ -26,8 +26,8 @@ entry:
2626
ret void
2727
}
2828

29-
define dso_local void @zdinx_asm_Pr(ptr nocapture noundef writeonly %a, double noundef %b, double noundef %c) nounwind {
30-
; CHECK-LABEL: zdinx_asm_Pr:
29+
define dso_local void @zdinx_asm_R(ptr nocapture noundef writeonly %a, double noundef %b, double noundef %c) nounwind {
30+
; CHECK-LABEL: zdinx_asm_R:
3131
; CHECK: # %bb.0: # %entry
3232
; CHECK-NEXT: addi sp, sp, -16
3333
; CHECK-NEXT: sw s0, 12(sp) # 4-byte Folded Spill
@@ -47,7 +47,7 @@ define dso_local void @zdinx_asm_Pr(ptr nocapture noundef writeonly %a, double n
4747
; CHECK-NEXT: ret
4848
entry:
4949
%arrayidx = getelementptr inbounds double, ptr %a, i32 1
50-
%0 = tail call double asm "fsgnjx.d $0, $1, $2", "=^Pr,^Pr,^Pr"(double %b, double %c)
50+
%0 = tail call double asm "fsgnjx.d $0, $1, $2", "=R,R,R"(double %b, double %c)
5151
store double %0, ptr %arrayidx, align 8
5252
ret void
5353
}

0 commit comments

Comments
 (0)