Page MenuHomePhabricator

[RISCV] add the MC layer support of Zfinx extension
ClosedPublic

Authored by achieveartificialintelligence on Dec 15 2020, 6:53 AM.

Details

Summary

This patch added the MC layer support of Zfinx extension.

Authored-by: StephenFan
Co-Authored-by: Shao-Ce Sun

Diff Detail

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes

Ping. Any other suggestions?

craig.topper added inline comments.Jan 19 2022, 11:30 PM
llvm/lib/Target/RISCV/RISCVRegisterInfo.td
135

Does putting this back the way it was and using "(add GPR)" in GPRF16, GPRF32, and GPRF64 work?

asb added a comment.EditedJan 24 2022, 7:01 AM

Thanks for your work on this. The way you've managed to use multiclasses to handle this with the 'ExtInfo' definitions takes a bit of unpicking to follow, but it does a really good job of keeping the instruction definitions largely unmodified. Nice!

I've got a few requests/questions on the test coverage:

  • I'm not sure the inclusion of the load/store instructions in the z[d,f,h]inx test cases has much value, given those instructions are unmodified?
  • Given that the set of F/D/Zfh instructions that _aren't_ supported under z[d,f,h]inx is relatively short, it's probably worth being exhaustive in the *-invalid.s test cases. It's only 8 instructions for Zfinx for instance.
  • The *-invalid.s test cases should have coverage for using a floating point register with an operation that is supported by Z[d,f,h]inx
  • The zdinx test cases don't include any coverage for when odd registers are used, but I think it should
asb added a comment.Jan 24 2022, 7:10 AM

Not an issue for this MC-layer patch, but I've created https://github.com/riscv/riscv-zfinx/issues/14 to point out what seems to be an incorrect statement about the status quo on the ABI for 32-bit floating point types on RV64 in the Zfinx spec.

achieveartificialintelligence marked an inline comment as done.

@asb Thank you very much! Could you please take a look at what needs to be modified now?

Separate the Zhinxmin and Zhinx extensions. Inspired by D118581

Assuming this will be merged soon, do you want to submit a backport request for the 14.0 branch?

Assuming this will be merged soon, do you want to submit a backport request for the 14.0 branch?

Yes.

Jim added inline comments.Feb 8 2022, 7:34 PM
llvm/lib/Target/RISCV/RISCVRegisterInfo.td
555

Is XLenRI correct for GPRPF64? RV32 has size 32.

craig.topper added inline comments.Feb 9 2022, 7:31 PM
llvm/lib/Target/RISCV/RISCVRegisterInfo.td
555

I'm not sure the RegInfos are correct for the other classes either. The RegInfos override the register size, the spill size, and spill alignment. I think those should all be based on the FP type.

So I don't think any of these should have a RegInfos.

achieveartificialintelligence marked 2 inline comments as done.

Address comments.

llvm/lib/Target/RISCV/RISCVRegisterInfo.td
555

Without RegInfo, it would cause spill size to be changed for a large number of other tests.

Jim added inline comments.Feb 10 2022, 9:29 PM
llvm/lib/Target/RISCV/RISCVRegisterInfo.td
557

Is register pair only on RV32 for used as f64?

achieveartificialintelligence marked an inline comment as done.Feb 11 2022, 5:34 AM
achieveartificialintelligence added inline comments.
llvm/lib/Target/RISCV/RISCVRegisterInfo.td
557

Yes.

asb added a comment.Feb 16 2022, 6:50 AM

I think all my comments have been addressed. @craig.topper - are you happy your RegInfo question is addressed?

In D93298#3326230, @asb wrote:

I think all my comments have been addressed. @craig.topper - are you happy your RegInfo question is addressed?

I'm happy.

asb accepted this revision.Feb 17 2022, 5:36 AM

In that case, LGTM (needs a rebase though). Thanks for your patience on this @achieveartificialintelligence.

This revision is now accepted and ready to land.Feb 17 2022, 5:36 AM
This revision was landed with ongoing or failed builds.Feb 17 2022, 5:54 AM
This revision was automatically updated to reflect the committed changes.
achieveartificialintelligence marked an inline comment as done.

It appears that this is causing an assertion segfault in a rustc test over at our experimental rust + llvm@head bot:
https://buildkite.com/llvm-project/rust-llvm-integrate-prototype/builds/8430#167e6de5-2dd5-41c3-87d7-b6e3f3908371/262-706
The test is https://github.com/rust-lang/rust/blob/master/src/test/assembly/asm/riscv-types.rs. These two lines appear to cause it (code compiles fine when removed):

The assertion:

Impossible reg-to-reg copy
UNREACHABLE executed at [...]/rust/src/llvm-project/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp:350

The IR for riscv-types.rs:

; ModuleID = 'riscv_types.4cedf4b7-cgu.0'
source_filename = "riscv_types.4cedf4b7-cgu.0"
target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n64-S128"
target triple = "riscv64"

@extern_static = external dso_local global i8
@alloc55 = private unnamed_addr constant <{ [6 x i8] }> <{ [6 x i8] c"reg_i8" }>, align 1
@alloc56 = private unnamed_addr constant <{ [7 x i8] }> <{ [7 x i8] c"reg_i16" }>, align 1
@alloc57 = private unnamed_addr constant <{ [7 x i8] }> <{ [7 x i8] c"reg_i32" }>, align 1
@alloc58 = private unnamed_addr constant <{ [7 x i8] }> <{ [7 x i8] c"reg_f32" }>, align 1
@alloc59 = private unnamed_addr constant <{ [7 x i8] }> <{ [7 x i8] c"reg_i64" }>, align 1
@alloc60 = private unnamed_addr constant <{ [7 x i8] }> <{ [7 x i8] c"reg_f64" }>, align 1
@alloc61 = private unnamed_addr constant <{ [7 x i8] }> <{ [7 x i8] c"reg_ptr" }>, align 1
@alloc62 = private unnamed_addr constant <{ [8 x i8] }> <{ [8 x i8] c"freg_f32" }>, align 1
@alloc63 = private unnamed_addr constant <{ [8 x i8] }> <{ [8 x i8] c"freg_f64" }>, align 1
@alloc64 = private unnamed_addr constant <{ [5 x i8] }> <{ [5 x i8] c"a0_i8" }>, align 1
@alloc65 = private unnamed_addr constant <{ [6 x i8] }> <{ [6 x i8] c"a0_i16" }>, align 1
@alloc66 = private unnamed_addr constant <{ [6 x i8] }> <{ [6 x i8] c"a0_i32" }>, align 1
@alloc67 = private unnamed_addr constant <{ [6 x i8] }> <{ [6 x i8] c"a0_f32" }>, align 1
@alloc68 = private unnamed_addr constant <{ [6 x i8] }> <{ [6 x i8] c"a0_i64" }>, align 1
@alloc69 = private unnamed_addr constant <{ [6 x i8] }> <{ [6 x i8] c"a0_f64" }>, align 1
@alloc70 = private unnamed_addr constant <{ [6 x i8] }> <{ [6 x i8] c"a0_ptr" }>, align 1
@alloc71 = private unnamed_addr constant <{ [7 x i8] }> <{ [7 x i8] c"fa0_f32" }>, align 1
@alloc72 = private unnamed_addr constant <{ [7 x i8] }> <{ [7 x i8] c"fa0_f64" }>, align 1

; Function Attrs: nounwind
define dso_local void @sym_fn() unnamed_addr #0 {
start:
  tail call void asm sideeffect alignstack "call ${0:c}", "s,~{vtype},~{vl},~{vxsat},~{vxrm},~{memory}"(void ()* nonnull @extern_func) #1, !srcloc !1
  ret void
}

; Function Attrs: nounwind
define dso_local void @sym_static() unnamed_addr #0 {
start:
  tail call void asm sideeffect alignstack "lb t0, ${0:c}", "s,~{vtype},~{vl},~{vxsat},~{vxrm},~{memory}"(i8* nonnull @extern_static) #1, !srcloc !2
  ret void
}

; Function Attrs: nounwind
define dso_local i8 @reg_i8(i8 %x) unnamed_addr #0 {
start:
  tail call void @dont_merge([0 x i8]* noalias noundef nonnull readonly align 1 bitcast (<{ [6 x i8] }>* @alloc55 to [0 x i8]*), i64 6) #1
  %0 = tail call i8 asm sideeffect alignstack "mv ${0}, ${1}", "=&r,r,~{vtype},~{vl},~{vxsat},~{vxrm},~{memory}"(i8 %x) #1, !srcloc !3
  ret i8 %0
}

; Function Attrs: nounwind
define dso_local i16 @reg_i16(i16 %x) unnamed_addr #0 {
start:
  tail call void @dont_merge([0 x i8]* noalias noundef nonnull readonly align 1 bitcast (<{ [7 x i8] }>* @alloc56 to [0 x i8]*), i64 7) #1
  %0 = tail call i16 asm sideeffect alignstack "mv ${0}, ${1}", "=&r,r,~{vtype},~{vl},~{vxsat},~{vxrm},~{memory}"(i16 %x) #1, !srcloc !3
  ret i16 %0
}

; Function Attrs: nounwind
define dso_local i32 @reg_i32(i32 %x) unnamed_addr #0 {
start:
  tail call void @dont_merge([0 x i8]* noalias noundef nonnull readonly align 1 bitcast (<{ [7 x i8] }>* @alloc57 to [0 x i8]*), i64 7) #1
  %0 = tail call i32 asm sideeffect alignstack "mv ${0}, ${1}", "=&r,r,~{vtype},~{vl},~{vxsat},~{vxrm},~{memory}"(i32 %x) #1, !srcloc !3
  ret i32 %0
}

; Function Attrs: nounwind
define dso_local float @reg_f32(float %x) unnamed_addr #0 {
start:
  tail call void @dont_merge([0 x i8]* noalias noundef nonnull readonly align 1 bitcast (<{ [7 x i8] }>* @alloc58 to [0 x i8]*), i64 7) #1
  %0 = tail call float asm sideeffect alignstack "mv ${0}, ${1}", "=&r,r,~{vtype},~{vl},~{vxsat},~{vxrm},~{memory}"(float %x) #1, !srcloc !3
  ret float %0
}

; Function Attrs: nounwind
define dso_local i64 @reg_i64(i64 %x) unnamed_addr #0 {
start:
  tail call void @dont_merge([0 x i8]* noalias noundef nonnull readonly align 1 bitcast (<{ [7 x i8] }>* @alloc59 to [0 x i8]*), i64 7) #1
  %0 = tail call i64 asm sideeffect alignstack "mv ${0}, ${1}", "=&r,r,~{vtype},~{vl},~{vxsat},~{vxrm},~{memory}"(i64 %x) #1, !srcloc !3
  ret i64 %0
}

; Function Attrs: nounwind
define dso_local double @reg_f64(double %x) unnamed_addr #0 {
start:
  tail call void @dont_merge([0 x i8]* noalias noundef nonnull readonly align 1 bitcast (<{ [7 x i8] }>* @alloc60 to [0 x i8]*), i64 7) #1
  %0 = tail call double asm sideeffect alignstack "mv ${0}, ${1}", "=&r,r,~{vtype},~{vl},~{vxsat},~{vxrm},~{memory}"(double %x) #1, !srcloc !3
  ret double %0
}

; Function Attrs: nounwind
define dso_local i8* @reg_ptr(i8* %x) unnamed_addr #0 {
start:
  tail call void @dont_merge([0 x i8]* noalias noundef nonnull readonly align 1 bitcast (<{ [7 x i8] }>* @alloc61 to [0 x i8]*), i64 7) #1
  %0 = tail call i8* asm sideeffect alignstack "mv ${0}, ${1}", "=&r,r,~{vtype},~{vl},~{vxsat},~{vxrm},~{memory}"(i8* %x) #1, !srcloc !3
  ret i8* %0
}

; Function Attrs: nounwind
define dso_local float @freg_f32(float %x) unnamed_addr #0 {
start:
  tail call void @dont_merge([0 x i8]* noalias noundef nonnull readonly align 1 bitcast (<{ [8 x i8] }>* @alloc62 to [0 x i8]*), i64 8) #1
  %0 = tail call float asm sideeffect alignstack "fmv.s ${0}, ${1}", "=&f,f,~{vtype},~{vl},~{vxsat},~{vxrm},~{memory}"(float %x) #1, !srcloc !3
  ret float %0
}

; Function Attrs: nounwind
define dso_local double @freg_f64(double %x) unnamed_addr #0 {
start:
  tail call void @dont_merge([0 x i8]* noalias noundef nonnull readonly align 1 bitcast (<{ [8 x i8] }>* @alloc63 to [0 x i8]*), i64 8) #1
  %0 = tail call double asm sideeffect alignstack "fmv.d ${0}, ${1}", "=&f,f,~{vtype},~{vl},~{vxsat},~{vxrm},~{memory}"(double %x) #1, !srcloc !3
  ret double %0
}

; Function Attrs: nounwind
define dso_local i8 @a0_i8(i8 %x) unnamed_addr #0 {
start:
  tail call void @dont_merge([0 x i8]* noalias noundef nonnull readonly align 1 bitcast (<{ [5 x i8] }>* @alloc64 to [0 x i8]*), i64 5) #1
  %0 = tail call i8 asm sideeffect alignstack "mv a0, a0", "={x10},{x10},~{vtype},~{vl},~{vxsat},~{vxrm},~{memory}"(i8 %x) #1, !srcloc !4
  ret i8 %0
}

; Function Attrs: nounwind
define dso_local i16 @a0_i16(i16 %x) unnamed_addr #0 {
start:
  tail call void @dont_merge([0 x i8]* noalias noundef nonnull readonly align 1 bitcast (<{ [6 x i8] }>* @alloc65 to [0 x i8]*), i64 6) #1
  %0 = tail call i16 asm sideeffect alignstack "mv a0, a0", "={x10},{x10},~{vtype},~{vl},~{vxsat},~{vxrm},~{memory}"(i16 %x) #1, !srcloc !4
  ret i16 %0
}

; Function Attrs: nounwind
define dso_local i32 @a0_i32(i32 %x) unnamed_addr #0 {
start:
  tail call void @dont_merge([0 x i8]* noalias noundef nonnull readonly align 1 bitcast (<{ [6 x i8] }>* @alloc66 to [0 x i8]*), i64 6) #1
  %0 = tail call i32 asm sideeffect alignstack "mv a0, a0", "={x10},{x10},~{vtype},~{vl},~{vxsat},~{vxrm},~{memory}"(i32 %x) #1, !srcloc !4
  ret i32 %0
}

; Function Attrs: nounwind
define dso_local float @a0_f32(float %x) unnamed_addr #0 {
start:
  tail call void @dont_merge([0 x i8]* noalias noundef nonnull readonly align 1 bitcast (<{ [6 x i8] }>* @alloc67 to [0 x i8]*), i64 6) #1
  %0 = tail call float asm sideeffect alignstack "mv a0, a0", "={x10},{x10},~{vtype},~{vl},~{vxsat},~{vxrm},~{memory}"(float %x) #1, !srcloc !4
  ret float %0
}

; Function Attrs: nounwind
define dso_local i64 @a0_i64(i64 %x) unnamed_addr #0 {
start:
  tail call void @dont_merge([0 x i8]* noalias noundef nonnull readonly align 1 bitcast (<{ [6 x i8] }>* @alloc68 to [0 x i8]*), i64 6) #1
  %0 = tail call i64 asm sideeffect alignstack "mv a0, a0", "={x10},{x10},~{vtype},~{vl},~{vxsat},~{vxrm},~{memory}"(i64 %x) #1, !srcloc !4
  ret i64 %0
}

; Function Attrs: nounwind
define dso_local double @a0_f64(double %x) unnamed_addr #0 {
start:
  tail call void @dont_merge([0 x i8]* noalias noundef nonnull readonly align 1 bitcast (<{ [6 x i8] }>* @alloc69 to [0 x i8]*), i64 6) #1
  %0 = tail call double asm sideeffect alignstack "mv a0, a0", "={x10},{x10},~{vtype},~{vl},~{vxsat},~{vxrm},~{memory}"(double %x) #1, !srcloc !4
  ret double %0
}

; Function Attrs: nounwind
define dso_local i8* @a0_ptr(i8* %x) unnamed_addr #0 {
start:
  tail call void @dont_merge([0 x i8]* noalias noundef nonnull readonly align 1 bitcast (<{ [6 x i8] }>* @alloc70 to [0 x i8]*), i64 6) #1
  %0 = tail call i8* asm sideeffect alignstack "mv a0, a0", "={x10},{x10},~{vtype},~{vl},~{vxsat},~{vxrm},~{memory}"(i8* %x) #1, !srcloc !4
  ret i8* %0
}

; Function Attrs: nounwind
define dso_local float @fa0_f32(float %x) unnamed_addr #0 {
start:
  tail call void @dont_merge([0 x i8]* noalias noundef nonnull readonly align 1 bitcast (<{ [7 x i8] }>* @alloc71 to [0 x i8]*), i64 7) #1
  %0 = tail call float asm sideeffect alignstack "fmv.s fa0, fa0", "={f10},{f10},~{vtype},~{vl},~{vxsat},~{vxrm},~{memory}"(float %x) #1, !srcloc !4
  ret float %0
}

; Function Attrs: nounwind
define dso_local double @fa0_f64(double %x) unnamed_addr #0 {
start:
  tail call void @dont_merge([0 x i8]* noalias noundef nonnull readonly align 1 bitcast (<{ [7 x i8] }>* @alloc72 to [0 x i8]*), i64 7) #1
  %0 = tail call double asm sideeffect alignstack "fmv.d fa0, fa0", "={f10},{f10},~{vtype},~{vl},~{vxsat},~{vxrm},~{memory}"(double %x) #1, !srcloc !4
  ret double %0
}

; Function Attrs: nounwind
declare dso_local void @extern_func() unnamed_addr #0

; Function Attrs: nounwind
declare dso_local void @dont_merge([0 x i8]* noalias noundef nonnull readonly align 1, i64) unnamed_addr #0

attributes #0 = { nounwind "target-cpu"="generic-rv64" }
attributes #1 = { nounwind }

!llvm.module.flags = !{!0}

!0 = !{i32 1, !"Code Model", i32 3}
!1 = !{i32 1048}
!2 = !{i32 1281}
!3 = !{i32 1670}
!4 = !{i32 2113}

@achieveartificialintelligence could you please take a look? Any ideas what's going wrong here?

It appears that this is causing an assertion segfault in a rustc test over at our experimental rust + llvm@head bot:
https://buildkite.com/llvm-project/rust-llvm-integrate-prototype/builds/8430#167e6de5-2dd5-41c3-87d7-b6e3f3908371/262-706
The test is https://github.com/rust-lang/rust/blob/master/src/test/assembly/asm/riscv-types.rs. These two lines appear to cause it (code compiles fine when removed):

The assertion:

Impossible reg-to-reg copy
UNREACHABLE executed at [...]/rust/src/llvm-project/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp:350

...

This is just MC layer support. Inline assembly interacts with CodeGen; I assume the register classes/constraints still need updating to support Zfinx.

llvm/test/MC/RISCV/rv32i-invalid.s
1

This is an unrelated change

@krasimir Since I don't have a rust environment, can you help me to test if D120130 works?

@krasimir Since I don't have a rust environment, can you help me to test if D120130 works?

Hm, actually, looking at the log, it doesn't appear to be trying to use Zfinx? My guess is that putting a float in a GPR has broken as that's now legal but should only be legal for Zfinx?

It appears that this is causing an assertion segfault in a rustc test over at our experimental rust + llvm@head bot:

I dont think that patch author is required to debug this issue for "experimental rust + llvm@head" - downstream.

Since I don't have a rust environment

There is no requirement, indeed. LLVM devs are not responsible to keep ""experimental rust + llvm@head" working.

It appears that this is causing an assertion segfault in a rustc test over at our experimental rust + llvm@head bot:

I dont think that patch author is required to debug this issue for "experimental rust + llvm@head" - downstream.

Since I don't have a rust environment

There is no requirement, indeed. LLVM devs are not responsible to keep ""experimental rust + llvm@head" working.

They're required to assist with fixing regressions that show when compiling legitimate IR. An IR reproducer was given, so no Rust toolchain knowledge should be needed, at that point it's the LLVM dev's responsibility, and if they can't fix it in a timely manner then it should be backed out.

It appears that this is causing an assertion segfault in a rustc test over at our experimental rust + llvm@head bot:

I dont think that patch author is required to debug this issue for "experimental rust + llvm@head" - downstream.

Since I don't have a rust environment

There is no requirement, indeed. LLVM devs are not responsible to keep ""experimental rust + llvm@head" working.

They're required to assist with fixing regressions that show when compiling legitimate IR. An IR reproducer was given, so no Rust toolchain knowledge should be needed, at that point it's the LLVM dev's responsibility, and if they can't fix it in a timely manner then it should be backed out.

Then yeah, if IR is provided and is standard one, this is okay. Consider to add that IR as testcase for the fix.

nikic added a subscriber: nikic.Feb 21 2022, 2:45 AM

Because I happened to also run into this, reduced IR for -mtriple=riscv32 -mattr=+d is:

define float @test(float %x) {
  %1 = tail call float asm sideeffect alignstack "mv a0, a0", "={x10},{x10}"(float 0.000000e+00)
  ret float 0.000000e+00
}

@achieveartificialintelligence any progress with the problematic IR? Have you been able to reproduce using nikic's reduced example?

@achieveartificialintelligence any progress with the problematic IR? Have you been able to reproduce using nikic's reduced example?

Sorry, I don't have a solution right now.

@achieveartificialintelligence any progress with the problematic IR? Have you been able to reproduce using nikic's reduced example?

Sorry, I don't have a solution right now.

Could we revert this until then?

This revision is now accepted and ready to land.Feb 24 2022, 3:51 AM

Here's a fix that I tested on the original repreoduce. It detects that we picked one of the new register classes and tries to redirect back to the normal GPR register class if the GPR register class has the same width. I also checked for MVT::Other to use the GPR class if there was no type.

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 3daf2d03de03..4984872139c5 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -10893,7 +10893,28 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
     }
   }
 
-  return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
+  std::pair<Register, const TargetRegisterClass*> Res;
+  Res = TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
+
+  if (Res.second == &RISCV::GPRF32RegClass) {
+    if (!Subtarget.is64Bit() || VT == MVT::Other)
+      return std::make_pair(Res.first, &RISCV::GPRRegClass);
+    return std::make_pair(0, nullptr);
+  }
+
+  if (Res.second == &RISCV::GPRF64RegClass) {
+    if (Subtarget.is64Bit() || VT == MVT::Other)
+      return std::make_pair(Res.first, &RISCV::GPRRegClass);
+    return std::make_pair(0, nullptr);
+  }
+
+  if (Res.second == &RISCV::GPRF16RegClass) {
+    if (VT == MVT::Other)
+      return std::make_pair(Res.first, &RISCV::GPRRegClass);
+    return std::make_pair(0, nullptr);
+  }
+
+  return Res;
 }

Can you help test if this patch works fine now? @krasimir

jrtc27 added inline comments.Feb 27 2022, 7:51 PM
llvm/lib/Target/RISCV/RISCVISelLowering.cpp
11015–11038
achieveartificialintelligence marked an inline comment as done.

Address @jrtc27's comments

craig.topper added inline comments.Feb 28 2022, 7:29 PM
llvm/test/CodeGen/RISCV/zfinx-types.ll
6

I'm not sure the Zfh or D RUN lines are really doing anything. Especially the Zfh.

The same bug did happen with double, D extension and RV64 so should probably test that.

achieveartificialintelligence marked an inline comment as done.

Address @craig.topper's comment

This revision was landed with ongoing or failed builds.Mar 1 2022, 10:25 PM
This revision was automatically updated to reflect the committed changes.
Herald added a project: Restricted Project. · View Herald TranscriptMar 1 2022, 10:25 PM
craig.topper added inline comments.Mar 1 2022, 10:48 PM
llvm/test/CodeGen/RISCV/zfinx-types.ll
6

I see you added rv64, but didn't add a test case that uses double instead of float.

@achieveartificialintelligence thank you for looking into this, sorry for the late reply!

It looks like the latest version addresses @nikic's IR reproducer with -mtriple=riscv32.

There seems to be an error trying this out with -mtriple=riscv64:

% cat test.ll
define float @test(float %x) {
  %1 = tail call float asm sideeffect alignstack "mv a0, a0", "={x10},{x10}"(float 0.000000e+00)
  ret float 0.000000e+00
}
% llc -mtriple=riscv32 -mattr=+d test.ll
% llc -mtriple=riscv64 -mattr=+d test.ll
error: couldn't allocate output register for constraint '{x10}'

I'm not sure if this is intended to work -mtriple=riscv64, but judging by the newly added test RUN: llc -mtriple=riscv64 ... line it seems like it should?

@achieveartificialintelligence thank you for looking into this, sorry for the late reply!

It looks like the latest version addresses @nikic's IR reproducer with -mtriple=riscv32.

There seems to be an error trying this out with -mtriple=riscv64:

% cat test.ll
define float @test(float %x) {
  %1 = tail call float asm sideeffect alignstack "mv a0, a0", "={x10},{x10}"(float 0.000000e+00)
  ret float 0.000000e+00
}
% llc -mtriple=riscv32 -mattr=+d test.ll
% llc -mtriple=riscv64 -mattr=+d test.ll
error: couldn't allocate output register for constraint '{x10}'

I'm not sure if this is intended to work -mtriple=riscv64, but judging by the newly added test RUN: llc -mtriple=riscv64 ... line it seems like it should?

My patch was only partially correct. I'll fix it

@achieveartificialintelligence thank you for looking into this, sorry for the late reply!

It looks like the latest version addresses @nikic's IR reproducer with -mtriple=riscv32.

There seems to be an error trying this out with -mtriple=riscv64:

% cat test.ll
define float @test(float %x) {
  %1 = tail call float asm sideeffect alignstack "mv a0, a0", "={x10},{x10}"(float 0.000000e+00)
  ret float 0.000000e+00
}
% llc -mtriple=riscv32 -mattr=+d test.ll
% llc -mtriple=riscv64 -mattr=+d test.ll
error: couldn't allocate output register for constraint '{x10}'

I'm not sure if this is intended to work -mtriple=riscv64, but judging by the newly added test RUN: llc -mtriple=riscv64 ... line it seems like it should?

My patch was only partially correct. I'll fix it

I just pushed 6cb42cd6669785f3b611106e1b6b38bbe65733a9 to hopefully fix this.

Does a double with r for RV32 work with that fix? That's supposed to give the low half of the register. You might need to also deal with the register pair class?

Never mind, I see you added a test for that case

I just pushed 6cb42cd6669785f3b611106e1b6b38bbe65733a9 to hopefully fix this.

Thank you Craig! That fixed it.