diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp index db23b0c22833..8167d7603b0e 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -102,7 +102,7 @@ bool RISCVTargetInfo::validateAsmConstraint( return true; case 'c': // A RVC register - GPR or FPR - if (Name[1] == 'r' || Name[1] == 'f') { + if (Name[1] == 'r' || Name[1] == 'R' || Name[1] == 'f') { Info.setAllowsRegister(); Name += 1; return true; diff --git a/clang/test/CodeGen/RISCV/riscv-inline-asm.c b/clang/test/CodeGen/RISCV/riscv-inline-asm.c index 9da306807ed0..f2031e0adcbc 100644 --- a/clang/test/CodeGen/RISCV/riscv-inline-asm.c +++ b/clang/test/CodeGen/RISCV/riscv-inline-asm.c @@ -46,6 +46,14 @@ double_xlen_t test_R_wide_scalar(double_xlen_t p) { return ret; } +double_xlen_t test_cR_wide_scalar(double_xlen_t p) { +// CHECK-LABEL: define{{.*}} {{i128|i64}} @test_cR_wide_scalar( +// CHECK: call {{i128|i64}} asm sideeffect "", "=^cR,^cR"({{i128|i64}} %{{.*}}) + double_xlen_t ret; + asm volatile("" : "=cR"(ret) : "cR"(p)); + return ret; +} + void test_I(void) { // CHECK-LABEL: define{{.*}} void @test_I() // CHECK: call void asm sideeffect "", "I"(i32 2047) diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index 295fd315c56d..324b13ab164d 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -21087,7 +21087,7 @@ RISCVTargetLowering::getConstraintType(StringRef Constraint) const { } else { if (Constraint == "vr" || Constraint == "vd" || Constraint == "vm") return C_RegisterClass; - if (Constraint == "cr" || Constraint == "cf") + if (Constraint == "cr" || Constraint == "cR" || Constraint == "cf") return C_RegisterClass; } return TargetLowering::getConstraintType(Constraint); @@ -21176,6 +21176,8 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, return std::make_pair(0U, &RISCV::GPRPairCRegClass); if (!VT.isVector()) return std::make_pair(0U, &RISCV::GPRCRegClass); + } else if (Constraint == "cR") { + return std::make_pair(0U, &RISCV::GPRPairCRegClass); } else if (Constraint == "cf") { if (VT == MVT::f16) { if (Subtarget.hasStdExtZfhmin()) diff --git a/llvm/test/CodeGen/RISCV/rv32-inline-asm-pairs.ll b/llvm/test/CodeGen/RISCV/rv32-inline-asm-pairs.ll index 04a5d268aebf..f14fe2665835 100644 --- a/llvm/test/CodeGen/RISCV/rv32-inline-asm-pairs.ll +++ b/llvm/test/CodeGen/RISCV/rv32-inline-asm-pairs.ll @@ -71,3 +71,73 @@ entry: %9 = load i64, ptr %3, align 8 ret i64 %9 } + +define i64 @test_cR_wide_scalar_simple(i64 noundef %0) nounwind { +; CHECK-LABEL: test_cR_wide_scalar_simple: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: # a2 <- a0 +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: mv a0, a2 +; CHECK-NEXT: mv a1, a3 +; CHECK-NEXT: ret +entry: + %1 = call i64 asm sideeffect "/* $0 <- $1 */", "=&^cR,^cR"(i64 %0) + ret i64 %1 +} + +define i32 @test_cR_wide_scalar_with_ops(i32 noundef %0) nounwind { +; CHECK-LABEL: test_cR_wide_scalar_with_ops: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mv a1, a0 +; CHECK-NEXT: #APP +; CHECK-NEXT: # a2 <- a0 +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: or a0, a2, a3 +; CHECK-NEXT: ret +entry: + %1 = zext i32 %0 to i64 + %2 = shl i64 %1, 32 + %3 = or i64 %1, %2 + %4 = call i64 asm sideeffect "/* $0 <- $1 */", "=&^cR,^cR"(i64 %3) + %5 = trunc i64 %4 to i32 + %6 = lshr i64 %4, 32 + %7 = trunc i64 %6 to i32 + %8 = or i32 %5, %7 + ret i32 %8 +} + +define i64 @test_cR_wide_scalar_inout(ptr %0, i64 noundef %1) nounwind { +; CHECK-LABEL: test_cR_wide_scalar_inout: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: addi sp, sp, -16 +; CHECK-NEXT: mv a3, a2 +; CHECK-NEXT: sw a0, 12(sp) +; CHECK-NEXT: mv a2, a1 +; CHECK-NEXT: sw a1, 0(sp) +; CHECK-NEXT: sw a3, 4(sp) +; CHECK-NEXT: #APP +; CHECK-NEXT: # a0; a2 +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: sw a0, 12(sp) +; CHECK-NEXT: sw a2, 0(sp) +; CHECK-NEXT: sw a3, 4(sp) +; CHECK-NEXT: mv a0, a2 +; CHECK-NEXT: mv a1, a3 +; CHECK-NEXT: addi sp, sp, 16 +; CHECK-NEXT: ret +entry: + %2 = alloca ptr, align 4 + %3 = alloca i64, align 8 + store ptr %0, ptr %2, align 4 + store i64 %1, ptr %3, align 8 + %4 = load ptr, ptr %2, align 4 + %5 = load i64, ptr %3, align 8 + %6 = call { ptr, i64 } asm sideeffect "/* $0; $1 */", "=r,=^cR,0,1"(ptr %4, i64 %5) + %7 = extractvalue { ptr, i64} %6, 0 + %8 = extractvalue { ptr, i64 } %6, 1 + store ptr %7, ptr %2, align 4 + store i64 %8, ptr %3, align 8 + %9 = load i64, ptr %3, align 8 + ret i64 %9 +} diff --git a/llvm/test/CodeGen/RISCV/rv64-inline-asm-pairs.ll b/llvm/test/CodeGen/RISCV/rv64-inline-asm-pairs.ll index 41f353d0781a..ac455b7fac88 100644 --- a/llvm/test/CodeGen/RISCV/rv64-inline-asm-pairs.ll +++ b/llvm/test/CodeGen/RISCV/rv64-inline-asm-pairs.ll @@ -71,3 +71,73 @@ entry: %9 = load i128, ptr %3, align 16 ret i128 %9 } + +define i128 @test_cR_wide_scalar_simple(i128 noundef %0) nounwind { +; CHECK-LABEL: test_cR_wide_scalar_simple: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: # a2 <- a0 +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: mv a0, a2 +; CHECK-NEXT: mv a1, a3 +; CHECK-NEXT: ret +entry: + %1 = call i128 asm sideeffect "/* $0 <- $1 */", "=&^cR,^cR"(i128 %0) + ret i128 %1 +} + +define i64 @test_cR_wide_scalar_with_ops(i64 noundef %0) nounwind { +; CHECK-LABEL: test_cR_wide_scalar_with_ops: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mv a1, a0 +; CHECK-NEXT: #APP +; CHECK-NEXT: # a2 <- a0 +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: or a0, a2, a3 +; CHECK-NEXT: ret +entry: + %1 = zext i64 %0 to i128 + %2 = shl i128 %1, 64 + %3 = or i128 %1, %2 + %4 = call i128 asm sideeffect "/* $0 <- $1 */", "=&^cR,^cR"(i128 %3) + %5 = trunc i128 %4 to i64 + %6 = lshr i128 %4, 64 + %7 = trunc i128 %6 to i64 + %8 = or i64 %5, %7 + ret i64 %8 +} + +define i128 @test_cR_wide_scalar_inout(ptr %0, i128 noundef %1) nounwind { +; CHECK-LABEL: test_cR_wide_scalar_inout: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: addi sp, sp, -32 +; CHECK-NEXT: mv a3, a2 +; CHECK-NEXT: sd a0, 24(sp) +; CHECK-NEXT: mv a2, a1 +; CHECK-NEXT: sd a1, 0(sp) +; CHECK-NEXT: sd a3, 8(sp) +; CHECK-NEXT: #APP +; CHECK-NEXT: # a0; a2 +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: sd a0, 24(sp) +; CHECK-NEXT: sd a2, 0(sp) +; CHECK-NEXT: sd a3, 8(sp) +; CHECK-NEXT: mv a0, a2 +; CHECK-NEXT: mv a1, a3 +; CHECK-NEXT: addi sp, sp, 32 +; CHECK-NEXT: ret +entry: + %2 = alloca ptr, align 8 + %3 = alloca i128, align 16 + store ptr %0, ptr %2, align 8 + store i128 %1, ptr %3, align 16 + %4 = load ptr, ptr %2, align 8 + %5 = load i128, ptr %3, align 16 + %6 = call { ptr, i128 } asm sideeffect "/* $0; $1 */", "=r,=^cR,0,1"(ptr %4, i128 %5) + %7 = extractvalue { ptr, i128} %6, 0 + %8 = extractvalue { ptr, i128 } %6, 1 + store ptr %7, ptr %2, align 8 + store i128 %8, ptr %3, align 16 + %9 = load i128, ptr %3, align 16 + ret i128 %9 +} diff --git a/llvm/test/CodeGen/RISCV/zdinx-asm-constraint.ll b/llvm/test/CodeGen/RISCV/zdinx-asm-constraint.ll index 81a8a8065e6b..b7d7d4c0945b 100644 --- a/llvm/test/CodeGen/RISCV/zdinx-asm-constraint.ll +++ b/llvm/test/CodeGen/RISCV/zdinx-asm-constraint.ll @@ -82,6 +82,24 @@ entry: ret void } +define dso_local void @zdinx_asm_cR_inout(ptr nocapture noundef writeonly %a, double noundef %b) nounwind { +; CHECK-LABEL: zdinx_asm_cR_inout: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mv a3, a2 +; CHECK-NEXT: mv a2, a1 +; CHECK-NEXT: #APP +; CHECK-NEXT: fabs.d a2, a2 +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: sw a2, 8(a0) +; CHECK-NEXT: sw a3, 12(a0) +; CHECK-NEXT: ret +entry: + %arrayidx = getelementptr inbounds double, ptr %a, i32 1 + %0 = tail call double asm "fsgnjx.d $0, $1, $1", "=^cR,0"(double %b) + store double %0, ptr %arrayidx, align 8 + ret void +} + define dso_local void @zfinx_asm(ptr nocapture noundef writeonly %a, float noundef %b, float noundef %c) nounwind { ; CHECK-LABEL: zfinx_asm: ; CHECK: # %bb.0: # %entry @@ -167,3 +185,29 @@ entry: store half %0, ptr %arrayidx, align 8 ret void } + +define dso_local void @zdinx_asm_cR(ptr nocapture noundef writeonly %a, double noundef %b, double noundef %c) nounwind { +; CHECK-LABEL: zdinx_asm_cR: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: addi sp, sp, -16 +; CHECK-NEXT: sw s0, 12(sp) # 4-byte Folded Spill +; CHECK-NEXT: sw s1, 8(sp) # 4-byte Folded Spill +; CHECK-NEXT: mv a5, a4 +; CHECK-NEXT: mv s1, a2 +; CHECK-NEXT: mv a4, a3 +; CHECK-NEXT: mv s0, a1 +; CHECK-NEXT: #APP +; CHECK-NEXT: fsgnjx.d a2, s0, a4 +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: sw a2, 8(a0) +; CHECK-NEXT: sw a3, 12(a0) +; CHECK-NEXT: lw s0, 12(sp) # 4-byte Folded Reload +; CHECK-NEXT: lw s1, 8(sp) # 4-byte Folded Reload +; CHECK-NEXT: addi sp, sp, 16 +; CHECK-NEXT: ret +entry: + %arrayidx = getelementptr inbounds double, ptr %a, i32 1 + %0 = tail call double asm "fsgnjx.d $0, $1, $2", "=^cR,^cR,^cR"(double %b, double %c) + store double %0, ptr %arrayidx, align 8 + ret void +}