[llvm] r368303 - [RISCV] Allow ABI Names in Inline Assembly Constraints

Sam Elliott via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 8 07:59:16 PDT 2019


Author: lenary
Date: Thu Aug  8 07:59:16 2019
New Revision: 368303

URL: http://llvm.org/viewvc/llvm-project?rev=368303&view=rev
Log:
[RISCV] Allow ABI Names in Inline Assembly Constraints

Summary:
Clang will replace references to registers using ABI names in inline
assembly constraints with references to architecture names, but other
frontends do not. LLVM uses the regular assembly parser to parse inline asm,
so inline assembly strings can contain references to registers using their
ABI names.

This patch adds support for parsing constraints using either the ABI name or
the architectural register name. This means we do not need to implement the
ABI name replacement code in every single frontend, especially those like
Rust which are a very thin shim on top of LLVM IR's inline asm, and that
constraints can more closely match the assembly strings they refer to.

Reviewers: asb, simoncook

Reviewed By: simoncook

Subscribers: hiraditya, rbar, johnrusso, JDevlieghere, apazos, sabuasal, niosHD, kito-cheng, shiva0217, jrtc27, MaskRay, zzheng, edward-jones, rogfer01, MartinMosbeck, brucehoult, the_o, rkruppe, PkmX, jocewei, psnobl, benna, Jim, s.egerton, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D65947

Added:
    llvm/trunk/test/CodeGen/RISCV/inline-asm-abi-names.ll
    llvm/trunk/test/CodeGen/RISCV/inline-asm-d-abi-names.ll
    llvm/trunk/test/CodeGen/RISCV/inline-asm-f-abi-names.ll
Modified:
    llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp
    llvm/trunk/test/CodeGen/RISCV/inline-asm-d-constraint-f.ll
    llvm/trunk/test/CodeGen/RISCV/inline-asm-f-constraint-f.ll

Modified: llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp?rev=368303&r1=368302&r2=368303&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp Thu Aug  8 07:59:16 2019
@@ -2461,47 +2461,91 @@ RISCVTargetLowering::getRegForInlineAsmC
     }
   }
 
+  // Clang will correctly decode the usage of register name aliases into their
+  // official names. However, other frontends like `rustc` do not. This allows
+  // users of these frontends to use the ABI names for registers in LLVM-style
+  // register constraints.
+  unsigned XRegFromAlias = StringSwitch<unsigned>(Constraint.lower())
+                               .Case("{zero}", RISCV::X0)
+                               .Case("{ra}", RISCV::X1)
+                               .Case("{sp}", RISCV::X2)
+                               .Case("{gp}", RISCV::X3)
+                               .Case("{tp}", RISCV::X4)
+                               .Case("{t0}", RISCV::X5)
+                               .Case("{t1}", RISCV::X6)
+                               .Case("{t2}", RISCV::X7)
+                               .Cases("{s0}", "{fp}", RISCV::X8)
+                               .Case("{s1}", RISCV::X9)
+                               .Case("{a0}", RISCV::X10)
+                               .Case("{a1}", RISCV::X11)
+                               .Case("{a2}", RISCV::X12)
+                               .Case("{a3}", RISCV::X13)
+                               .Case("{a4}", RISCV::X14)
+                               .Case("{a5}", RISCV::X15)
+                               .Case("{a6}", RISCV::X16)
+                               .Case("{a7}", RISCV::X17)
+                               .Case("{s2}", RISCV::X18)
+                               .Case("{s3}", RISCV::X19)
+                               .Case("{s4}", RISCV::X20)
+                               .Case("{s5}", RISCV::X21)
+                               .Case("{s6}", RISCV::X22)
+                               .Case("{s7}", RISCV::X23)
+                               .Case("{s8}", RISCV::X24)
+                               .Case("{s9}", RISCV::X25)
+                               .Case("{s10}", RISCV::X26)
+                               .Case("{s11}", RISCV::X27)
+                               .Case("{t3}", RISCV::X28)
+                               .Case("{t4}", RISCV::X29)
+                               .Case("{t5}", RISCV::X30)
+                               .Case("{t6}", RISCV::X31)
+                               .Default(RISCV::NoRegister);
+  if (XRegFromAlias != RISCV::NoRegister)
+    return std::make_pair(XRegFromAlias, &RISCV::GPRRegClass);
+
   // Since TargetLowering::getRegForInlineAsmConstraint uses the name of the
   // TableGen record rather than the AsmName to choose registers for InlineAsm
   // constraints, plus we want to match those names to the widest floating point
   // register type available, manually select floating point registers here.
+  //
+  // The second case is the ABI name of the register, so that frontends can also
+  // use the ABI names in register constraint lists.
   if (Subtarget.hasStdExtF() || Subtarget.hasStdExtD()) {
     std::pair<unsigned, unsigned> FReg =
         StringSwitch<std::pair<unsigned, unsigned>>(Constraint.lower())
-            .Case("{f0}", {RISCV::F0_32, RISCV::F0_64})
-            .Case("{f1}", {RISCV::F1_32, RISCV::F1_64})
-            .Case("{f2}", {RISCV::F2_32, RISCV::F2_64})
-            .Case("{f3}", {RISCV::F3_32, RISCV::F3_64})
-            .Case("{f4}", {RISCV::F4_32, RISCV::F4_64})
-            .Case("{f5}", {RISCV::F5_32, RISCV::F5_64})
-            .Case("{f6}", {RISCV::F6_32, RISCV::F6_64})
-            .Case("{f7}", {RISCV::F7_32, RISCV::F7_64})
-            .Case("{f8}", {RISCV::F8_32, RISCV::F8_64})
-            .Case("{f9}", {RISCV::F9_32, RISCV::F9_64})
-            .Case("{f10}", {RISCV::F10_32, RISCV::F10_64})
-            .Case("{f11}", {RISCV::F11_32, RISCV::F11_64})
-            .Case("{f12}", {RISCV::F12_32, RISCV::F12_64})
-            .Case("{f13}", {RISCV::F13_32, RISCV::F13_64})
-            .Case("{f14}", {RISCV::F14_32, RISCV::F14_64})
-            .Case("{f15}", {RISCV::F15_32, RISCV::F15_64})
-            .Case("{f16}", {RISCV::F16_32, RISCV::F16_64})
-            .Case("{f17}", {RISCV::F17_32, RISCV::F17_64})
-            .Case("{f18}", {RISCV::F18_32, RISCV::F18_64})
-            .Case("{f19}", {RISCV::F19_32, RISCV::F19_64})
-            .Case("{f20}", {RISCV::F20_32, RISCV::F20_64})
-            .Case("{f21}", {RISCV::F21_32, RISCV::F21_64})
-            .Case("{f22}", {RISCV::F22_32, RISCV::F22_64})
-            .Case("{f23}", {RISCV::F23_32, RISCV::F23_64})
-            .Case("{f24}", {RISCV::F24_32, RISCV::F24_64})
-            .Case("{f25}", {RISCV::F25_32, RISCV::F25_64})
-            .Case("{f26}", {RISCV::F26_32, RISCV::F26_64})
-            .Case("{f27}", {RISCV::F27_32, RISCV::F27_64})
-            .Case("{f28}", {RISCV::F28_32, RISCV::F28_64})
-            .Case("{f29}", {RISCV::F29_32, RISCV::F29_64})
-            .Case("{f30}", {RISCV::F30_32, RISCV::F30_64})
-            .Case("{f31}", {RISCV::F31_32, RISCV::F31_64})
-            .Default({-1U, -1U});
-    if (FReg.first != -1U)
+            .Cases("{f0}", "{ft0}", {RISCV::F0_32, RISCV::F0_64})
+            .Cases("{f1}", "{ft1}", {RISCV::F1_32, RISCV::F1_64})
+            .Cases("{f2}", "{ft2}", {RISCV::F2_32, RISCV::F2_64})
+            .Cases("{f3}", "{ft3}", {RISCV::F3_32, RISCV::F3_64})
+            .Cases("{f4}", "{ft4}", {RISCV::F4_32, RISCV::F4_64})
+            .Cases("{f5}", "{ft5}", {RISCV::F5_32, RISCV::F5_64})
+            .Cases("{f6}", "{ft6}", {RISCV::F6_32, RISCV::F6_64})
+            .Cases("{f7}", "{ft7}", {RISCV::F7_32, RISCV::F7_64})
+            .Cases("{f8}", "{fs0}", {RISCV::F8_32, RISCV::F8_64})
+            .Cases("{f9}", "{fs1}", {RISCV::F9_32, RISCV::F9_64})
+            .Cases("{f10}", "{fa0}", {RISCV::F10_32, RISCV::F10_64})
+            .Cases("{f11}", "{fa1}", {RISCV::F11_32, RISCV::F11_64})
+            .Cases("{f12}", "{fa2}", {RISCV::F12_32, RISCV::F12_64})
+            .Cases("{f13}", "{fa3}", {RISCV::F13_32, RISCV::F13_64})
+            .Cases("{f14}", "{fa4}", {RISCV::F14_32, RISCV::F14_64})
+            .Cases("{f15}", "{fa5}", {RISCV::F15_32, RISCV::F15_64})
+            .Cases("{f16}", "{fa6}", {RISCV::F16_32, RISCV::F16_64})
+            .Cases("{f17}", "{fa7}", {RISCV::F17_32, RISCV::F17_64})
+            .Cases("{f18}", "{fs2}", {RISCV::F18_32, RISCV::F18_64})
+            .Cases("{f19}", "{fs3}", {RISCV::F19_32, RISCV::F19_64})
+            .Cases("{f20}", "{fs4}", {RISCV::F20_32, RISCV::F20_64})
+            .Cases("{f21}", "{fs5}", {RISCV::F21_32, RISCV::F21_64})
+            .Cases("{f22}", "{fs6}", {RISCV::F22_32, RISCV::F22_64})
+            .Cases("{f23}", "{fs7}", {RISCV::F23_32, RISCV::F23_64})
+            .Cases("{f24}", "{fs8}", {RISCV::F24_32, RISCV::F24_64})
+            .Cases("{f25}", "{fs9}", {RISCV::F25_32, RISCV::F25_64})
+            .Cases("{f26}", "{fs10}", {RISCV::F26_32, RISCV::F26_64})
+            .Cases("{f27}", "{fs11}", {RISCV::F27_32, RISCV::F27_64})
+            .Cases("{f28}", "{ft8}", {RISCV::F28_32, RISCV::F28_64})
+            .Cases("{f29}", "{ft9}", {RISCV::F29_32, RISCV::F29_64})
+            .Cases("{f30}", "{ft10}", {RISCV::F30_32, RISCV::F30_64})
+            .Cases("{f31}", "{ft11}", {RISCV::F31_32, RISCV::F31_64})
+            .Default({RISCV::NoRegister, RISCV::NoRegister});
+    if (FReg.first != RISCV::NoRegister)
       return Subtarget.hasStdExtD()
                  ? std::make_pair(FReg.second, &RISCV::FPR64RegClass)
                  : std::make_pair(FReg.first, &RISCV::FPR32RegClass);

Added: llvm/trunk/test/CodeGen/RISCV/inline-asm-abi-names.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/RISCV/inline-asm-abi-names.ll?rev=368303&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/RISCV/inline-asm-abi-names.ll (added)
+++ llvm/trunk/test/CodeGen/RISCV/inline-asm-abi-names.ll Thu Aug  8 07:59:16 2019
@@ -0,0 +1,1590 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV32I %s
+; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV64I %s
+
+; These test that we can use both the architectural names (x*) and the ABI names
+; (a*, s*, t* etc) to refer to registers in inline asm constraint lists. In each
+; case, the named register should be used for the source register of the `addi`.
+; It is very likely that `a0` will be chosen as the designation register, but
+; this is left to the compiler to choose.
+;
+; The inline assembly will, by default, contain the ABI names for the registers.
+;
+; Parenthesised registers in comments are the other aliases for this register.
+
+; NOTE: This test has to pass in 0 to the inline asm, because that's the only
+; value `x0` (`zero`) can take.
+define i32 @explicit_register_x0() nounwind {
+; RV32I-LABEL: explicit_register_x0:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, zero, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x0:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, zero, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x0}"(i32 0)
+  ret i32 %1
+}
+
+; NOTE: This test has to pass in 0 to the inline asm, because that's the only
+; value that `zero` (`x0`) can take.
+define i32 @explicit_register_zero() nounwind {
+; RV32I-LABEL: explicit_register_zero:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, zero, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_zero:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, zero, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{zero}"(i32 0)
+  ret i32 %1
+}
+
+; NOTE: This test uses `x1` (`ra`) as an input, so it should be saved.
+define i32 @explicit_register_x1(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x1:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw ra, 12(sp)
+; RV32I-NEXT:    mv ra, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, ra, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw ra, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x1:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd ra, 8(sp)
+; RV64I-NEXT:    mv ra, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, ra, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld ra, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x1}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `ra` (`x1`) as an input, so it should be saved.
+define i32 @explicit_register_ra(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_ra:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw ra, 12(sp)
+; RV32I-NEXT:    mv ra, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, ra, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw ra, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_ra:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd ra, 8(sp)
+; RV64I-NEXT:    mv ra, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, ra, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld ra, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{ra}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_x2(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x2:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv sp, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, sp, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x2:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv sp, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, sp, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x2}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_sp(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_sp:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv sp, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, sp, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_sp:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv sp, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, sp, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{sp}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `x3` (`gp`) as an input, so it should be saved.
+define i32 @explicit_register_x3(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x3:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw gp, 12(sp)
+; RV32I-NEXT:    mv gp, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, gp, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw gp, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x3:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd gp, 8(sp)
+; RV64I-NEXT:    mv gp, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, gp, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld gp, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x3}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `gp` (`x3`) as an input, so it should be saved.
+define i32 @explicit_register_gp(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_gp:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw gp, 12(sp)
+; RV32I-NEXT:    mv gp, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, gp, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw gp, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_gp:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd gp, 8(sp)
+; RV64I-NEXT:    mv gp, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, gp, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld gp, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{gp}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `x4` (`tp`) as an input, so it should be saved.
+define i32 @explicit_register_x4(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x4:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw tp, 12(sp)
+; RV32I-NEXT:    mv tp, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, tp, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw tp, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x4:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd tp, 8(sp)
+; RV64I-NEXT:    mv tp, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, tp, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld tp, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x4}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `tp` (`x4`) as an input, so it should be saved.
+define i32 @explicit_register_tp(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_tp:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw tp, 12(sp)
+; RV32I-NEXT:    mv tp, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, tp, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw tp, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_tp:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd tp, 8(sp)
+; RV64I-NEXT:    mv tp, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, tp, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld tp, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{tp}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_x5(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x5:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv t0, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, t0, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x5:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv t0, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, t0, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x5}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_t0(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_t0:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv t0, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, t0, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_t0:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv t0, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, t0, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{t0}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_x6(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x6:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv t1, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, t1, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x6:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv t1, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, t1, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x6}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_t1(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_t1:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv t1, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, t1, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_t1:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv t1, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, t1, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{t1}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_x7(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x7:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv t2, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, t2, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x7:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv t2, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, t2, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x7}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_t2(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_t2:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv t2, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, t2, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_t2:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv t2, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, t2, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{t2}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `x8` (`s0`, `fp`) as an input, so it should be saved.
+define i32 @explicit_register_x8(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x8:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s0, 12(sp)
+; RV32I-NEXT:    mv s0, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s0, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s0, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x8:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s0, 8(sp)
+; RV64I-NEXT:    mv s0, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s0, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s0, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x8}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `s0` (`x8`, `fp`) as an input, so it should be saved.
+define i32 @explicit_register_s0(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_s0:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s0, 12(sp)
+; RV32I-NEXT:    mv s0, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s0, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s0, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_s0:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s0, 8(sp)
+; RV64I-NEXT:    mv s0, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s0, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s0, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{s0}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fp` (`x8`, `s0`) as an input, so it should be saved.
+define i32 @explicit_register_fp(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_fp:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s0, 12(sp)
+; RV32I-NEXT:    mv s0, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s0, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s0, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_fp:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s0, 8(sp)
+; RV64I-NEXT:    mv s0, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s0, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s0, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{fp}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `x9` (`s1`) as an input, so it should be saved.
+define i32 @explicit_register_x9(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x9:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s1, 12(sp)
+; RV32I-NEXT:    mv s1, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s1, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s1, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x9:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s1, 8(sp)
+; RV64I-NEXT:    mv s1, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s1, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s1, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x9}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `s1` (`x9`) as an input, so it should be saved.
+define i32 @explicit_register_s1(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_s1:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s1, 12(sp)
+; RV32I-NEXT:    mv s1, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s1, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s1, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_s1:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s1, 8(sp)
+; RV64I-NEXT:    mv s1, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s1, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s1, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{s1}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_x10(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x10:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, a0, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x10:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, a0, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x10}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_a0(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_a0:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, a0, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_a0:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, a0, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{a0}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_x11(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x11:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv a1, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, a1, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x11:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv a1, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, a1, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x11}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_a1(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_a1:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv a1, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, a1, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_a1:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv a1, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, a1, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{a1}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_x12(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x12:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv a2, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, a2, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x12:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv a2, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, a2, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x12}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_a2(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_a2:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv a2, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, a2, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_a2:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv a2, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, a2, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{a2}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_x13(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x13:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv a3, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, a3, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x13:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv a3, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, a3, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x13}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_a3(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_a3:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv a3, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, a3, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_a3:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv a3, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, a3, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{a3}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_x14(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x14:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv a4, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, a4, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x14:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv a4, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, a4, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x14}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_a4(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_a4:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv a4, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, a4, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_a4:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv a4, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, a4, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{a4}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_x15(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x15:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv a5, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, a5, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x15:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv a5, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, a5, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x15}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_a5(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_a5:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv a5, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, a5, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_a5:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv a5, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, a5, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{a5}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_x16(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x16:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv a6, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, a6, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x16:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv a6, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, a6, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x16}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_a6(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_a6:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv a6, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, a6, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_a6:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv a6, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, a6, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{a6}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_x17(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x17:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv a7, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, a7, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x17:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv a7, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, a7, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x17}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_a7(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_a7:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv a7, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, a7, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_a7:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv a7, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, a7, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{a7}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `x18` (`s2`) as an input, so it should be saved.
+define i32 @explicit_register_x18(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x18:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s2, 12(sp)
+; RV32I-NEXT:    mv s2, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s2, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s2, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x18:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s2, 8(sp)
+; RV64I-NEXT:    mv s2, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s2, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s2, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x18}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `s2` (`x18`) as an input, so it should be saved.
+define i32 @explicit_register_s2(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_s2:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s2, 12(sp)
+; RV32I-NEXT:    mv s2, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s2, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s2, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_s2:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s2, 8(sp)
+; RV64I-NEXT:    mv s2, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s2, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s2, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{s2}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `x19` (`s3`) as an input, so it should be saved.
+define i32 @explicit_register_x19(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x19:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s3, 12(sp)
+; RV32I-NEXT:    mv s3, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s3, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s3, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x19:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s3, 8(sp)
+; RV64I-NEXT:    mv s3, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s3, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s3, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x19}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `s3` (`x19`) as an input, so it should be saved.
+define i32 @explicit_register_s3(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_s3:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s3, 12(sp)
+; RV32I-NEXT:    mv s3, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s3, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s3, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_s3:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s3, 8(sp)
+; RV64I-NEXT:    mv s3, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s3, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s3, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{s3}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `x20` (`s4`) as an input, so it should be saved.
+define i32 @explicit_register_x20(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x20:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s4, 12(sp)
+; RV32I-NEXT:    mv s4, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s4, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s4, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x20:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s4, 8(sp)
+; RV64I-NEXT:    mv s4, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s4, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s4, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x20}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `s4` (`x20`) as an input, so it should be saved.
+define i32 @explicit_register_s4(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_s4:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s4, 12(sp)
+; RV32I-NEXT:    mv s4, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s4, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s4, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_s4:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s4, 8(sp)
+; RV64I-NEXT:    mv s4, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s4, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s4, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{s4}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `x21` (`s5`) as an input, so it should be saved.
+define i32 @explicit_register_x21(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x21:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s5, 12(sp)
+; RV32I-NEXT:    mv s5, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s5, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s5, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x21:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s5, 8(sp)
+; RV64I-NEXT:    mv s5, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s5, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s5, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x21}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `s5` (`x21`) as an input, so it should be saved.
+define i32 @explicit_register_s5(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_s5:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s5, 12(sp)
+; RV32I-NEXT:    mv s5, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s5, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s5, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_s5:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s5, 8(sp)
+; RV64I-NEXT:    mv s5, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s5, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s5, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{s5}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `x22` (`s6`) as an input, so it should be saved.
+define i32 @explicit_register_x22(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x22:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s6, 12(sp)
+; RV32I-NEXT:    mv s6, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s6, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s6, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x22:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s6, 8(sp)
+; RV64I-NEXT:    mv s6, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s6, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s6, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x22}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `s6` (`x22`) as an input, so it should be saved.
+define i32 @explicit_register_s6(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_s6:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s6, 12(sp)
+; RV32I-NEXT:    mv s6, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s6, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s6, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_s6:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s6, 8(sp)
+; RV64I-NEXT:    mv s6, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s6, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s6, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{s6}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `x23` (`s7`) as an input, so it should be saved.
+define i32 @explicit_register_x23(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x23:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s7, 12(sp)
+; RV32I-NEXT:    mv s7, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s7, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s7, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x23:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s7, 8(sp)
+; RV64I-NEXT:    mv s7, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s7, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s7, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x23}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `s7` (`x23`) as an input, so it should be saved.
+define i32 @explicit_register_s7(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_s7:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s7, 12(sp)
+; RV32I-NEXT:    mv s7, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s7, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s7, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_s7:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s7, 8(sp)
+; RV64I-NEXT:    mv s7, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s7, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s7, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{s7}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `x24` (`s8`) as an input, so it should be saved.
+define i32 @explicit_register_x24(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x24:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s8, 12(sp)
+; RV32I-NEXT:    mv s8, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s8, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s8, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x24:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s8, 8(sp)
+; RV64I-NEXT:    mv s8, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s8, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s8, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x24}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `s8` (`x24`) as an input, so it should be saved.
+define i32 @explicit_register_s8(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_s8:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s8, 12(sp)
+; RV32I-NEXT:    mv s8, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s8, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s8, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_s8:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s8, 8(sp)
+; RV64I-NEXT:    mv s8, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s8, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s8, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{s8}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `x25` (`s9`) as an input, so it should be saved.
+define i32 @explicit_register_x25(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x25:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s9, 12(sp)
+; RV32I-NEXT:    mv s9, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s9, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s9, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x25:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s9, 8(sp)
+; RV64I-NEXT:    mv s9, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s9, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s9, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x25}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `s9` (`x25`) as an input, so it should be saved.
+define i32 @explicit_register_s9(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_s9:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s9, 12(sp)
+; RV32I-NEXT:    mv s9, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s9, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s9, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_s9:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s9, 8(sp)
+; RV64I-NEXT:    mv s9, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s9, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s9, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{s9}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `x26` (`s10`) as an input, so it should be saved.
+define i32 @explicit_register_x26(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x26:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s10, 12(sp)
+; RV32I-NEXT:    mv s10, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s10, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s10, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x26:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s10, 8(sp)
+; RV64I-NEXT:    mv s10, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s10, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s10, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x26}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `s10` (`x28`) as an input, so it should be saved.
+define i32 @explicit_register_s10(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_s10:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s10, 12(sp)
+; RV32I-NEXT:    mv s10, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s10, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s10, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_s10:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s10, 8(sp)
+; RV64I-NEXT:    mv s10, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s10, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s10, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{s10}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `x27` (`s11`) as an input, so it should be saved.
+define i32 @explicit_register_x27(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x27:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s11, 12(sp)
+; RV32I-NEXT:    mv s11, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s11, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s11, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x27:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s11, 8(sp)
+; RV64I-NEXT:    mv s11, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s11, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s11, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x27}"(i32 %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `s11` (`x27`) as an input, so it should be saved.
+define i32 @explicit_register_s11(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_s11:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    addi sp, sp, -16
+; RV32I-NEXT:    sw s11, 12(sp)
+; RV32I-NEXT:    mv s11, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, s11, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    lw s11, 12(sp)
+; RV32I-NEXT:    addi sp, sp, 16
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_s11:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd s11, 8(sp)
+; RV64I-NEXT:    mv s11, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, s11, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ld s11, 8(sp)
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{s11}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_x28(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x28:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv t3, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, t3, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x28:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv t3, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, t3, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x28}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_t3(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_t3:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv t3, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, t3, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_t3:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv t3, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, t3, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{t3}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_x29(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x29:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv t4, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, t4, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x29:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv t4, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, t4, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x29}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_t4(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_t4:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv t4, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, t4, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_t4:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv t4, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, t4, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{t4}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_x30(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x30:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv t5, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, t5, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x30:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv t5, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, t5, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x30}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_t5(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_t5:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv t5, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, t5, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_t5:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv t5, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, t5, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{t5}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_x31(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_x31:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv t6, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, t6, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_x31:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv t6, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, t6, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{x31}"(i32 %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_t6(i32 %a) nounwind {
+; RV32I-LABEL: explicit_register_t6:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    mv t6, a0
+; RV32I-NEXT:    #APP
+; RV32I-NEXT:    addi a0, t6, 0
+; RV32I-NEXT:    #NO_APP
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: explicit_register_t6:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    mv t6, a0
+; RV64I-NEXT:    #APP
+; RV64I-NEXT:    addi a0, t6, 0
+; RV64I-NEXT:    #NO_APP
+; RV64I-NEXT:    ret
+  %1 = tail call i32 asm "addi $0, $1, 0", "=r,{t6}"(i32 %a)
+  ret i32 %1
+}

Added: llvm/trunk/test/CodeGen/RISCV/inline-asm-d-abi-names.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/RISCV/inline-asm-d-abi-names.ll?rev=368303&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/RISCV/inline-asm-d-abi-names.ll (added)
+++ llvm/trunk/test/CodeGen/RISCV/inline-asm-d-abi-names.ll Thu Aug  8 07:59:16 2019
@@ -0,0 +1,1509 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -mattr=+f,+d -target-abi ilp32d -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV32IFD %s
+; RUN: llc -mtriple=riscv64 -mattr=+f,+d -target-abi lp64d -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV64IFD %s
+
+; These test that we can use both the architectural names (x*) and the ABI names
+; (a*, s*, t* etc) to refer to registers in inline asm constraint lists. In each
+; case, the named register should be used for the source register of the `addi`.
+; It is very likely that `a0` will be chosen as the designation register, but
+; this is left to the compiler to choose.
+;
+; The inline assembly will, by default, contain the ABI names for the registers.
+;
+; Parenthesised registers in comments are the other aliases for this register.
+
+
+define i32 @explicit_register_f0(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f0:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d ft0, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, ft0
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f0:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d ft0, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, ft0
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f0}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_ft0(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_ft0:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d ft0, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, ft0
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_ft0:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d ft0, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, ft0
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{ft0}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f1(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f1:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d ft1, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, ft1
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f1:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d ft1, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, ft1
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f1}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_ft1(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_ft1:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d ft1, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, ft1
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_ft1:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d ft1, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, ft1
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{ft1}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f2(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f2:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d ft2, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, ft2
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f2:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d ft2, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, ft2
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f2}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_ft2(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_ft2:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d ft2, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, ft2
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_ft2:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d ft2, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, ft2
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{ft2}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f3(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f3:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d ft3, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, ft3
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f3:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d ft3, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, ft3
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f3}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_ft3(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_ft3:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d ft3, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, ft3
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_ft3:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d ft3, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, ft3
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{ft3}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f4(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f4:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d ft4, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, ft4
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f4:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d ft4, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, ft4
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f4}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_ft4(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_ft4:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d ft4, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, ft4
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_ft4:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d ft4, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, ft4
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{ft4}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f5(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f5:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d ft5, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, ft5
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f5:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d ft5, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, ft5
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f5}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_ft5(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_ft5:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d ft5, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, ft5
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_ft5:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d ft5, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, ft5
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{ft5}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f6(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f6:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d ft6, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, ft6
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f6:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d ft6, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, ft6
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f6}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_ft6(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_ft6:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d ft6, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, ft6
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_ft6:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d ft6, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, ft6
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{ft6}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f7(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f7:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d ft7, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, ft7
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f7:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d ft7, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, ft7
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f7}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_ft7(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_ft7:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d ft7, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, ft7
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_ft7:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d ft7, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, ft7
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{ft7}"(double %a)
+  ret i32 %1
+}
+
+
+; NOTE: This test uses `f8` (`fs0`) as an input, so it should be saved.
+define i32 @explicit_register_f8(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f8:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    addi sp, sp, -16
+; RV32IFD-NEXT:    fsd fs0, 8(sp)
+; RV32IFD-NEXT:    fmv.d fs0, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fs0
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    fld fs0, 8(sp)
+; RV32IFD-NEXT:    addi sp, sp, 16
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f8:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    addi sp, sp, -16
+; RV64IFD-NEXT:    fsd fs0, 8(sp)
+; RV64IFD-NEXT:    fmv.d fs0, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fs0
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    fld fs0, 8(sp)
+; RV64IFD-NEXT:    addi sp, sp, 16
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f8}"(double %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fs0` (`f8`) as an input, so it should be saved.
+define i32 @explicit_register_fs0(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_fs0:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    addi sp, sp, -16
+; RV32IFD-NEXT:    fsd fs0, 8(sp)
+; RV32IFD-NEXT:    fmv.d fs0, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fs0
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    fld fs0, 8(sp)
+; RV32IFD-NEXT:    addi sp, sp, 16
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_fs0:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    addi sp, sp, -16
+; RV64IFD-NEXT:    fsd fs0, 8(sp)
+; RV64IFD-NEXT:    fmv.d fs0, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fs0
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    fld fs0, 8(sp)
+; RV64IFD-NEXT:    addi sp, sp, 16
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{fs0}"(double %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `f9` (`fs1`) as an input, so it should be saved.
+define i32 @explicit_register_f9(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f9:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    addi sp, sp, -16
+; RV32IFD-NEXT:    fsd fs1, 8(sp)
+; RV32IFD-NEXT:    fmv.d fs1, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fs1
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    fld fs1, 8(sp)
+; RV32IFD-NEXT:    addi sp, sp, 16
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f9:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    addi sp, sp, -16
+; RV64IFD-NEXT:    fsd fs1, 8(sp)
+; RV64IFD-NEXT:    fmv.d fs1, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fs1
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    fld fs1, 8(sp)
+; RV64IFD-NEXT:    addi sp, sp, 16
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f9}"(double %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fs1` (`f9`) as an input, so it should be saved.
+define i32 @explicit_register_fs1(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_fs1:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    addi sp, sp, -16
+; RV32IFD-NEXT:    fsd fs1, 8(sp)
+; RV32IFD-NEXT:    fmv.d fs1, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fs1
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    fld fs1, 8(sp)
+; RV32IFD-NEXT:    addi sp, sp, 16
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_fs1:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    addi sp, sp, -16
+; RV64IFD-NEXT:    fsd fs1, 8(sp)
+; RV64IFD-NEXT:    fmv.d fs1, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fs1
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    fld fs1, 8(sp)
+; RV64IFD-NEXT:    addi sp, sp, 16
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{fs1}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f10(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f10:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fa0
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f10:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fa0
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f10}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_fa0(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_fa0:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fa0
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_fa0:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fa0
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{fa0}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f11(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f11:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d fa1, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fa1
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f11:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d fa1, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fa1
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f11}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_fa1(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_fa1:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d fa1, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fa1
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_fa1:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d fa1, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fa1
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{fa1}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f12(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f12:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d fa2, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fa2
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f12:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d fa2, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fa2
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f12}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_fa2(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_fa2:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d fa2, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fa2
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_fa2:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d fa2, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fa2
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{fa2}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f13(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f13:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d fa3, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fa3
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f13:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d fa3, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fa3
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f13}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_fa3(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_fa3:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d fa3, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fa3
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_fa3:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d fa3, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fa3
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{fa3}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f14(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f14:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d fa4, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fa4
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f14:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d fa4, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fa4
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f14}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_fa4(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_fa4:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d fa4, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fa4
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_fa4:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d fa4, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fa4
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{fa4}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f15(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f15:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d fa5, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fa5
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f15:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d fa5, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fa5
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f15}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_fa5(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_fa5:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d fa5, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fa5
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_fa5:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d fa5, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fa5
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{fa5}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f16(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f16:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d fa6, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fa6
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f16:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d fa6, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fa6
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f16}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_fa6(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_fa6:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d fa6, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fa6
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_fa6:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d fa6, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fa6
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{fa6}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f17(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f17:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d fa7, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fa7
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f17:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d fa7, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fa7
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f17}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_fa7(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_fa7:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d fa7, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fa7
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_fa7:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d fa7, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fa7
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{fa7}"(double %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `f18` (`fs2`) as an input, so it should be saved.
+define i32 @explicit_register_f18(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f18:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    addi sp, sp, -16
+; RV32IFD-NEXT:    fsd fs2, 8(sp)
+; RV32IFD-NEXT:    fmv.d fs2, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fs2
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    fld fs2, 8(sp)
+; RV32IFD-NEXT:    addi sp, sp, 16
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f18:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    addi sp, sp, -16
+; RV64IFD-NEXT:    fsd fs2, 8(sp)
+; RV64IFD-NEXT:    fmv.d fs2, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fs2
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    fld fs2, 8(sp)
+; RV64IFD-NEXT:    addi sp, sp, 16
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f18}"(double %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fs2` (`f18`) as an input, so it should be saved.
+define i32 @explicit_register_fs2(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_fs2:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    addi sp, sp, -16
+; RV32IFD-NEXT:    fsd fs2, 8(sp)
+; RV32IFD-NEXT:    fmv.d fs2, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fs2
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    fld fs2, 8(sp)
+; RV32IFD-NEXT:    addi sp, sp, 16
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_fs2:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    addi sp, sp, -16
+; RV64IFD-NEXT:    fsd fs2, 8(sp)
+; RV64IFD-NEXT:    fmv.d fs2, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fs2
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    fld fs2, 8(sp)
+; RV64IFD-NEXT:    addi sp, sp, 16
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{fs2}"(double %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `f19` (`fs3`) as an input, so it should be saved.
+define i32 @explicit_register_f19(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f19:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    addi sp, sp, -16
+; RV32IFD-NEXT:    fsd fs3, 8(sp)
+; RV32IFD-NEXT:    fmv.d fs3, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fs3
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    fld fs3, 8(sp)
+; RV32IFD-NEXT:    addi sp, sp, 16
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f19:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    addi sp, sp, -16
+; RV64IFD-NEXT:    fsd fs3, 8(sp)
+; RV64IFD-NEXT:    fmv.d fs3, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fs3
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    fld fs3, 8(sp)
+; RV64IFD-NEXT:    addi sp, sp, 16
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f19}"(double %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fs3` (`f19`) as an input, so it should be saved.
+define i32 @explicit_register_fs3(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_fs3:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    addi sp, sp, -16
+; RV32IFD-NEXT:    fsd fs3, 8(sp)
+; RV32IFD-NEXT:    fmv.d fs3, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fs3
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    fld fs3, 8(sp)
+; RV32IFD-NEXT:    addi sp, sp, 16
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_fs3:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    addi sp, sp, -16
+; RV64IFD-NEXT:    fsd fs3, 8(sp)
+; RV64IFD-NEXT:    fmv.d fs3, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fs3
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    fld fs3, 8(sp)
+; RV64IFD-NEXT:    addi sp, sp, 16
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{fs3}"(double %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `f20` (`fs4`) as an input, so it should be saved.
+define i32 @explicit_register_f20(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f20:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    addi sp, sp, -16
+; RV32IFD-NEXT:    fsd fs4, 8(sp)
+; RV32IFD-NEXT:    fmv.d fs4, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fs4
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    fld fs4, 8(sp)
+; RV32IFD-NEXT:    addi sp, sp, 16
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f20:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    addi sp, sp, -16
+; RV64IFD-NEXT:    fsd fs4, 8(sp)
+; RV64IFD-NEXT:    fmv.d fs4, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fs4
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    fld fs4, 8(sp)
+; RV64IFD-NEXT:    addi sp, sp, 16
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f20}"(double %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fs4` (`f20`) as an input, so it should be saved.
+define i32 @explicit_register_fs4(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_fs4:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    addi sp, sp, -16
+; RV32IFD-NEXT:    fsd fs4, 8(sp)
+; RV32IFD-NEXT:    fmv.d fs4, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fs4
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    fld fs4, 8(sp)
+; RV32IFD-NEXT:    addi sp, sp, 16
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_fs4:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    addi sp, sp, -16
+; RV64IFD-NEXT:    fsd fs4, 8(sp)
+; RV64IFD-NEXT:    fmv.d fs4, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fs4
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    fld fs4, 8(sp)
+; RV64IFD-NEXT:    addi sp, sp, 16
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{fs4}"(double %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `f21` (`fs5`) as an input, so it should be saved.
+define i32 @explicit_register_f21(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f21:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    addi sp, sp, -16
+; RV32IFD-NEXT:    fsd fs5, 8(sp)
+; RV32IFD-NEXT:    fmv.d fs5, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fs5
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    fld fs5, 8(sp)
+; RV32IFD-NEXT:    addi sp, sp, 16
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f21:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    addi sp, sp, -16
+; RV64IFD-NEXT:    fsd fs5, 8(sp)
+; RV64IFD-NEXT:    fmv.d fs5, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fs5
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    fld fs5, 8(sp)
+; RV64IFD-NEXT:    addi sp, sp, 16
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f21}"(double %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fs5` (`f21`) as an input, so it should be saved.
+define i32 @explicit_register_fs5(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_fs5:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    addi sp, sp, -16
+; RV32IFD-NEXT:    fsd fs5, 8(sp)
+; RV32IFD-NEXT:    fmv.d fs5, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fs5
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    fld fs5, 8(sp)
+; RV32IFD-NEXT:    addi sp, sp, 16
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_fs5:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    addi sp, sp, -16
+; RV64IFD-NEXT:    fsd fs5, 8(sp)
+; RV64IFD-NEXT:    fmv.d fs5, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fs5
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    fld fs5, 8(sp)
+; RV64IFD-NEXT:    addi sp, sp, 16
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{fs5}"(double %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `f22` (`fs6`) as an input, so it should be saved.
+define i32 @explicit_register_f22(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f22:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    addi sp, sp, -16
+; RV32IFD-NEXT:    fsd fs6, 8(sp)
+; RV32IFD-NEXT:    fmv.d fs6, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fs6
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    fld fs6, 8(sp)
+; RV32IFD-NEXT:    addi sp, sp, 16
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f22:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    addi sp, sp, -16
+; RV64IFD-NEXT:    fsd fs6, 8(sp)
+; RV64IFD-NEXT:    fmv.d fs6, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fs6
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    fld fs6, 8(sp)
+; RV64IFD-NEXT:    addi sp, sp, 16
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f22}"(double %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fs6` (`f22`) as an input, so it should be saved.
+define i32 @explicit_register_fs6(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_fs6:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    addi sp, sp, -16
+; RV32IFD-NEXT:    fsd fs6, 8(sp)
+; RV32IFD-NEXT:    fmv.d fs6, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fs6
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    fld fs6, 8(sp)
+; RV32IFD-NEXT:    addi sp, sp, 16
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_fs6:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    addi sp, sp, -16
+; RV64IFD-NEXT:    fsd fs6, 8(sp)
+; RV64IFD-NEXT:    fmv.d fs6, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fs6
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    fld fs6, 8(sp)
+; RV64IFD-NEXT:    addi sp, sp, 16
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{fs6}"(double %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `f23` (`fs7`) as an input, so it should be saved.
+define i32 @explicit_register_f23(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f23:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    addi sp, sp, -16
+; RV32IFD-NEXT:    fsd fs7, 8(sp)
+; RV32IFD-NEXT:    fmv.d fs7, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fs7
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    fld fs7, 8(sp)
+; RV32IFD-NEXT:    addi sp, sp, 16
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f23:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    addi sp, sp, -16
+; RV64IFD-NEXT:    fsd fs7, 8(sp)
+; RV64IFD-NEXT:    fmv.d fs7, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fs7
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    fld fs7, 8(sp)
+; RV64IFD-NEXT:    addi sp, sp, 16
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f23}"(double %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fs7` (`f23`) as an input, so it should be saved.
+define i32 @explicit_register_fs7(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_fs7:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    addi sp, sp, -16
+; RV32IFD-NEXT:    fsd fs7, 8(sp)
+; RV32IFD-NEXT:    fmv.d fs7, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fs7
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    fld fs7, 8(sp)
+; RV32IFD-NEXT:    addi sp, sp, 16
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_fs7:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    addi sp, sp, -16
+; RV64IFD-NEXT:    fsd fs7, 8(sp)
+; RV64IFD-NEXT:    fmv.d fs7, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fs7
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    fld fs7, 8(sp)
+; RV64IFD-NEXT:    addi sp, sp, 16
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{fs7}"(double %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `f24` (`fs8`) as an input, so it should be saved.
+define i32 @explicit_register_f24(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f24:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    addi sp, sp, -16
+; RV32IFD-NEXT:    fsd fs8, 8(sp)
+; RV32IFD-NEXT:    fmv.d fs8, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fs8
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    fld fs8, 8(sp)
+; RV32IFD-NEXT:    addi sp, sp, 16
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f24:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    addi sp, sp, -16
+; RV64IFD-NEXT:    fsd fs8, 8(sp)
+; RV64IFD-NEXT:    fmv.d fs8, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fs8
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    fld fs8, 8(sp)
+; RV64IFD-NEXT:    addi sp, sp, 16
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f24}"(double %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fs8` (`f24`) as an input, so it should be saved.
+define i32 @explicit_register_fs8(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_fs8:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    addi sp, sp, -16
+; RV32IFD-NEXT:    fsd fs8, 8(sp)
+; RV32IFD-NEXT:    fmv.d fs8, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fs8
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    fld fs8, 8(sp)
+; RV32IFD-NEXT:    addi sp, sp, 16
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_fs8:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    addi sp, sp, -16
+; RV64IFD-NEXT:    fsd fs8, 8(sp)
+; RV64IFD-NEXT:    fmv.d fs8, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fs8
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    fld fs8, 8(sp)
+; RV64IFD-NEXT:    addi sp, sp, 16
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{fs8}"(double %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `f25` (`fs9`) as an input, so it should be saved.
+define i32 @explicit_register_f25(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f25:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    addi sp, sp, -16
+; RV32IFD-NEXT:    fsd fs9, 8(sp)
+; RV32IFD-NEXT:    fmv.d fs9, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fs9
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    fld fs9, 8(sp)
+; RV32IFD-NEXT:    addi sp, sp, 16
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f25:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    addi sp, sp, -16
+; RV64IFD-NEXT:    fsd fs9, 8(sp)
+; RV64IFD-NEXT:    fmv.d fs9, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fs9
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    fld fs9, 8(sp)
+; RV64IFD-NEXT:    addi sp, sp, 16
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f25}"(double %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fs9` (`f25`) as an input, so it should be saved.
+define i32 @explicit_register_fs9(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_fs9:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    addi sp, sp, -16
+; RV32IFD-NEXT:    fsd fs9, 8(sp)
+; RV32IFD-NEXT:    fmv.d fs9, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fs9
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    fld fs9, 8(sp)
+; RV32IFD-NEXT:    addi sp, sp, 16
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_fs9:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    addi sp, sp, -16
+; RV64IFD-NEXT:    fsd fs9, 8(sp)
+; RV64IFD-NEXT:    fmv.d fs9, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fs9
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    fld fs9, 8(sp)
+; RV64IFD-NEXT:    addi sp, sp, 16
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{fs9}"(double %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `f26` (`fs10`) as an input, so it should be saved.
+define i32 @explicit_register_f26(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f26:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    addi sp, sp, -16
+; RV32IFD-NEXT:    fsd fs10, 8(sp)
+; RV32IFD-NEXT:    fmv.d fs10, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fs10
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    fld fs10, 8(sp)
+; RV32IFD-NEXT:    addi sp, sp, 16
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f26:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    addi sp, sp, -16
+; RV64IFD-NEXT:    fsd fs10, 8(sp)
+; RV64IFD-NEXT:    fmv.d fs10, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fs10
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    fld fs10, 8(sp)
+; RV64IFD-NEXT:    addi sp, sp, 16
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f26}"(double %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fs10` (`f26`) as an input, so it should be saved.
+define i32 @explicit_register_fs10(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_fs10:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    addi sp, sp, -16
+; RV32IFD-NEXT:    fsd fs10, 8(sp)
+; RV32IFD-NEXT:    fmv.d fs10, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fs10
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    fld fs10, 8(sp)
+; RV32IFD-NEXT:    addi sp, sp, 16
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_fs10:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    addi sp, sp, -16
+; RV64IFD-NEXT:    fsd fs10, 8(sp)
+; RV64IFD-NEXT:    fmv.d fs10, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fs10
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    fld fs10, 8(sp)
+; RV64IFD-NEXT:    addi sp, sp, 16
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{fs10}"(double %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `f27` (`fs11`) as an input, so it should be saved.
+define i32 @explicit_register_f27(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f27:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    addi sp, sp, -16
+; RV32IFD-NEXT:    fsd fs11, 8(sp)
+; RV32IFD-NEXT:    fmv.d fs11, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fs11
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    fld fs11, 8(sp)
+; RV32IFD-NEXT:    addi sp, sp, 16
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f27:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    addi sp, sp, -16
+; RV64IFD-NEXT:    fsd fs11, 8(sp)
+; RV64IFD-NEXT:    fmv.d fs11, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fs11
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    fld fs11, 8(sp)
+; RV64IFD-NEXT:    addi sp, sp, 16
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f27}"(double %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fs11` (`f27`) as an input, so it should be saved.
+define i32 @explicit_register_fs11(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_fs11:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    addi sp, sp, -16
+; RV32IFD-NEXT:    fsd fs11, 8(sp)
+; RV32IFD-NEXT:    fmv.d fs11, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, fs11
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    fld fs11, 8(sp)
+; RV32IFD-NEXT:    addi sp, sp, 16
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_fs11:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    addi sp, sp, -16
+; RV64IFD-NEXT:    fsd fs11, 8(sp)
+; RV64IFD-NEXT:    fmv.d fs11, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, fs11
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    fld fs11, 8(sp)
+; RV64IFD-NEXT:    addi sp, sp, 16
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{fs11}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f28(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f28:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d ft8, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, ft8
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f28:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d ft8, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, ft8
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f28}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_ft8(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_ft8:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d ft8, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, ft8
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_ft8:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d ft8, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, ft8
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{ft8}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f29(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f29:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d ft9, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, ft9
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f29:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d ft9, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, ft9
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f29}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_ft9(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_ft9:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d ft9, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, ft9
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_ft9:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d ft9, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, ft9
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{ft9}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f30(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f30:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d ft10, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, ft10
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f30:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d ft10, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, ft10
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f30}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_ft10(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_ft10:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d ft10, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, ft10
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_ft10:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d ft10, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, ft10
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{ft10}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f31(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_f31:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d ft11, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, ft11
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_f31:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d ft11, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, ft11
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{f31}"(double %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_ft11(double %a) nounwind {
+; RV32IFD-LABEL: explicit_register_ft11:
+; RV32IFD:       # %bb.0:
+; RV32IFD-NEXT:    fmv.d ft11, fa0
+; RV32IFD-NEXT:    #APP
+; RV32IFD-NEXT:    fcvt.w.d a0, ft11
+; RV32IFD-NEXT:    #NO_APP
+; RV32IFD-NEXT:    ret
+;
+; RV64IFD-LABEL: explicit_register_ft11:
+; RV64IFD:       # %bb.0:
+; RV64IFD-NEXT:    fmv.d ft11, fa0
+; RV64IFD-NEXT:    #APP
+; RV64IFD-NEXT:    fcvt.w.d a0, ft11
+; RV64IFD-NEXT:    #NO_APP
+; RV64IFD-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.d $0, $1", "=r,{ft11}"(double %a)
+  ret i32 %1
+}

Modified: llvm/trunk/test/CodeGen/RISCV/inline-asm-d-constraint-f.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/RISCV/inline-asm-d-constraint-f.ll?rev=368303&r1=368302&r2=368303&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/RISCV/inline-asm-d-constraint-f.ll (original)
+++ llvm/trunk/test/CodeGen/RISCV/inline-asm-d-constraint-f.ll Thu Aug  8 07:59:16 2019
@@ -38,3 +38,36 @@ define double @constraint_f_double(doubl
   %2 = tail call double asm "fadd.d $0, $1, $2", "=f,f,f"(double %a, double %1)
   ret double %2
 }
+
+define double @constraint_f_double_abi_name(double %a) nounwind {
+; RV32F-LABEL: constraint_f_double_abi_name:
+; RV32F:       # %bb.0:
+; RV32F-NEXT:    addi sp, sp, -16
+; RV32F-NEXT:    sw a0, 8(sp)
+; RV32F-NEXT:    sw a1, 12(sp)
+; RV32F-NEXT:    fld fa1, 8(sp)
+; RV32F-NEXT:    lui a0, %hi(gd)
+; RV32F-NEXT:    fld fs0, %lo(gd)(a0)
+; RV32F-NEXT:    #APP
+; RV32F-NEXT:    fadd.d ft0, fa1, fs0
+; RV32F-NEXT:    #NO_APP
+; RV32F-NEXT:    fsd ft0, 8(sp)
+; RV32F-NEXT:    lw a0, 8(sp)
+; RV32F-NEXT:    lw a1, 12(sp)
+; RV32F-NEXT:    addi sp, sp, 16
+; RV32F-NEXT:    ret
+;
+; RV64F-LABEL: constraint_f_double_abi_name:
+; RV64F:       # %bb.0:
+; RV64F-NEXT:    fmv.d.x fa1, a0
+; RV64F-NEXT:    lui a0, %hi(gd)
+; RV64F-NEXT:    fld fs0, %lo(gd)(a0)
+; RV64F-NEXT:    #APP
+; RV64F-NEXT:    fadd.d ft0, fa1, fs0
+; RV64F-NEXT:    #NO_APP
+; RV64F-NEXT:    fmv.x.d a0, ft0
+; RV64F-NEXT:    ret
+  %1 = load double, double* @gd
+  %2 = tail call double asm "fadd.d $0, $1, $2", "={ft0},{fa1},{fs0}"(double %a, double %1)
+  ret double %2
+}

Added: llvm/trunk/test/CodeGen/RISCV/inline-asm-f-abi-names.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/RISCV/inline-asm-f-abi-names.ll?rev=368303&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/RISCV/inline-asm-f-abi-names.ll (added)
+++ llvm/trunk/test/CodeGen/RISCV/inline-asm-f-abi-names.ll Thu Aug  8 07:59:16 2019
@@ -0,0 +1,1509 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -mattr=+f -target-abi ilp32f -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV32IF %s
+; RUN: llc -mtriple=riscv64 -mattr=+f -target-abi lp64f -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=RV64IF %s
+
+; These test that we can use both the architectural names (x*) and the ABI names
+; (a*, s*, t* etc) to refer to registers in inline asm constraint lists. In each
+; case, the named register should be used for the source register of the `addi`.
+; It is very likely that `a0` will be chosen as the designation register, but
+; this is left to the compiler to choose.
+;
+; The inline assembly will, by default, contain the ABI names for the registers.
+;
+; Parenthesised registers in comments are the other aliases for this register.
+
+
+define i32 @explicit_register_f0(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f0:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s ft0, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, ft0
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f0:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s ft0, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, ft0
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f0}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_ft0(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_ft0:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s ft0, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, ft0
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_ft0:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s ft0, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, ft0
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{ft0}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f1(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f1:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s ft1, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, ft1
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f1:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s ft1, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, ft1
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f1}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_ft1(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_ft1:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s ft1, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, ft1
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_ft1:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s ft1, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, ft1
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{ft1}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f2(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f2:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s ft2, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, ft2
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f2:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s ft2, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, ft2
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f2}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_ft2(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_ft2:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s ft2, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, ft2
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_ft2:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s ft2, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, ft2
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{ft2}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f3(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f3:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s ft3, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, ft3
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f3:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s ft3, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, ft3
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f3}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_ft3(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_ft3:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s ft3, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, ft3
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_ft3:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s ft3, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, ft3
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{ft3}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f4(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f4:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s ft4, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, ft4
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f4:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s ft4, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, ft4
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f4}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_ft4(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_ft4:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s ft4, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, ft4
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_ft4:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s ft4, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, ft4
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{ft4}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f5(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f5:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s ft5, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, ft5
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f5:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s ft5, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, ft5
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f5}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_ft5(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_ft5:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s ft5, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, ft5
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_ft5:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s ft5, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, ft5
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{ft5}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f6(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f6:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s ft6, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, ft6
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f6:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s ft6, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, ft6
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f6}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_ft6(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_ft6:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s ft6, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, ft6
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_ft6:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s ft6, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, ft6
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{ft6}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f7(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f7:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s ft7, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, ft7
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f7:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s ft7, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, ft7
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f7}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_ft7(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_ft7:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s ft7, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, ft7
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_ft7:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s ft7, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, ft7
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{ft7}"(float %a)
+  ret i32 %1
+}
+
+
+; NOTE: This test uses `f8` (`fs0`) as an input, so it should be saved.
+define i32 @explicit_register_f8(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f8:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    addi sp, sp, -16
+; RV32IF-NEXT:    fsw fs0, 12(sp)
+; RV32IF-NEXT:    fmv.s fs0, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fs0
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    flw fs0, 12(sp)
+; RV32IF-NEXT:    addi sp, sp, 16
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f8:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    addi sp, sp, -16
+; RV64IF-NEXT:    fsw fs0, 12(sp)
+; RV64IF-NEXT:    fmv.s fs0, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fs0
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    flw fs0, 12(sp)
+; RV64IF-NEXT:    addi sp, sp, 16
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f8}"(float %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fs0` (`f8`) as an input, so it should be saved.
+define i32 @explicit_register_fs0(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_fs0:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    addi sp, sp, -16
+; RV32IF-NEXT:    fsw fs0, 12(sp)
+; RV32IF-NEXT:    fmv.s fs0, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fs0
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    flw fs0, 12(sp)
+; RV32IF-NEXT:    addi sp, sp, 16
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_fs0:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    addi sp, sp, -16
+; RV64IF-NEXT:    fsw fs0, 12(sp)
+; RV64IF-NEXT:    fmv.s fs0, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fs0
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    flw fs0, 12(sp)
+; RV64IF-NEXT:    addi sp, sp, 16
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{fs0}"(float %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `f9` (`fs1`) as an input, so it should be saved.
+define i32 @explicit_register_f9(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f9:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    addi sp, sp, -16
+; RV32IF-NEXT:    fsw fs1, 12(sp)
+; RV32IF-NEXT:    fmv.s fs1, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fs1
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    flw fs1, 12(sp)
+; RV32IF-NEXT:    addi sp, sp, 16
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f9:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    addi sp, sp, -16
+; RV64IF-NEXT:    fsw fs1, 12(sp)
+; RV64IF-NEXT:    fmv.s fs1, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fs1
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    flw fs1, 12(sp)
+; RV64IF-NEXT:    addi sp, sp, 16
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f9}"(float %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fs1` (`f9`) as an input, so it should be saved.
+define i32 @explicit_register_fs1(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_fs1:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    addi sp, sp, -16
+; RV32IF-NEXT:    fsw fs1, 12(sp)
+; RV32IF-NEXT:    fmv.s fs1, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fs1
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    flw fs1, 12(sp)
+; RV32IF-NEXT:    addi sp, sp, 16
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_fs1:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    addi sp, sp, -16
+; RV64IF-NEXT:    fsw fs1, 12(sp)
+; RV64IF-NEXT:    fmv.s fs1, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fs1
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    flw fs1, 12(sp)
+; RV64IF-NEXT:    addi sp, sp, 16
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{fs1}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f10(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f10:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fa0
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f10:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fa0
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f10}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_fa0(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_fa0:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fa0
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_fa0:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fa0
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{fa0}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f11(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f11:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s fa1, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fa1
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f11:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s fa1, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fa1
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f11}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_fa1(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_fa1:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s fa1, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fa1
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_fa1:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s fa1, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fa1
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{fa1}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f12(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f12:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s fa2, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fa2
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f12:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s fa2, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fa2
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f12}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_fa2(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_fa2:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s fa2, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fa2
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_fa2:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s fa2, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fa2
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{fa2}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f13(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f13:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s fa3, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fa3
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f13:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s fa3, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fa3
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f13}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_fa3(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_fa3:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s fa3, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fa3
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_fa3:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s fa3, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fa3
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{fa3}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f14(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f14:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s fa4, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fa4
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f14:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s fa4, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fa4
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f14}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_fa4(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_fa4:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s fa4, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fa4
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_fa4:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s fa4, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fa4
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{fa4}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f15(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f15:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s fa5, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fa5
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f15:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s fa5, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fa5
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f15}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_fa5(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_fa5:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s fa5, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fa5
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_fa5:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s fa5, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fa5
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{fa5}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f16(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f16:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s fa6, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fa6
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f16:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s fa6, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fa6
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f16}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_fa6(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_fa6:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s fa6, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fa6
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_fa6:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s fa6, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fa6
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{fa6}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f17(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f17:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s fa7, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fa7
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f17:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s fa7, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fa7
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f17}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_fa7(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_fa7:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s fa7, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fa7
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_fa7:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s fa7, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fa7
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{fa7}"(float %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `f18` (`fs2`) as an input, so it should be saved.
+define i32 @explicit_register_f18(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f18:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    addi sp, sp, -16
+; RV32IF-NEXT:    fsw fs2, 12(sp)
+; RV32IF-NEXT:    fmv.s fs2, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fs2
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    flw fs2, 12(sp)
+; RV32IF-NEXT:    addi sp, sp, 16
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f18:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    addi sp, sp, -16
+; RV64IF-NEXT:    fsw fs2, 12(sp)
+; RV64IF-NEXT:    fmv.s fs2, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fs2
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    flw fs2, 12(sp)
+; RV64IF-NEXT:    addi sp, sp, 16
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f18}"(float %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fs2` (`f18`) as an input, so it should be saved.
+define i32 @explicit_register_fs2(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_fs2:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    addi sp, sp, -16
+; RV32IF-NEXT:    fsw fs2, 12(sp)
+; RV32IF-NEXT:    fmv.s fs2, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fs2
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    flw fs2, 12(sp)
+; RV32IF-NEXT:    addi sp, sp, 16
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_fs2:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    addi sp, sp, -16
+; RV64IF-NEXT:    fsw fs2, 12(sp)
+; RV64IF-NEXT:    fmv.s fs2, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fs2
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    flw fs2, 12(sp)
+; RV64IF-NEXT:    addi sp, sp, 16
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{fs2}"(float %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `f19` (`fs3`) as an input, so it should be saved.
+define i32 @explicit_register_f19(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f19:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    addi sp, sp, -16
+; RV32IF-NEXT:    fsw fs3, 12(sp)
+; RV32IF-NEXT:    fmv.s fs3, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fs3
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    flw fs3, 12(sp)
+; RV32IF-NEXT:    addi sp, sp, 16
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f19:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    addi sp, sp, -16
+; RV64IF-NEXT:    fsw fs3, 12(sp)
+; RV64IF-NEXT:    fmv.s fs3, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fs3
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    flw fs3, 12(sp)
+; RV64IF-NEXT:    addi sp, sp, 16
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f19}"(float %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fs3` (`f19`) as an input, so it should be saved.
+define i32 @explicit_register_fs3(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_fs3:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    addi sp, sp, -16
+; RV32IF-NEXT:    fsw fs3, 12(sp)
+; RV32IF-NEXT:    fmv.s fs3, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fs3
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    flw fs3, 12(sp)
+; RV32IF-NEXT:    addi sp, sp, 16
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_fs3:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    addi sp, sp, -16
+; RV64IF-NEXT:    fsw fs3, 12(sp)
+; RV64IF-NEXT:    fmv.s fs3, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fs3
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    flw fs3, 12(sp)
+; RV64IF-NEXT:    addi sp, sp, 16
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{fs3}"(float %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `f20` (`fs4`) as an input, so it should be saved.
+define i32 @explicit_register_f20(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f20:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    addi sp, sp, -16
+; RV32IF-NEXT:    fsw fs4, 12(sp)
+; RV32IF-NEXT:    fmv.s fs4, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fs4
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    flw fs4, 12(sp)
+; RV32IF-NEXT:    addi sp, sp, 16
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f20:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    addi sp, sp, -16
+; RV64IF-NEXT:    fsw fs4, 12(sp)
+; RV64IF-NEXT:    fmv.s fs4, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fs4
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    flw fs4, 12(sp)
+; RV64IF-NEXT:    addi sp, sp, 16
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f20}"(float %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fs4` (`f20`) as an input, so it should be saved.
+define i32 @explicit_register_fs4(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_fs4:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    addi sp, sp, -16
+; RV32IF-NEXT:    fsw fs4, 12(sp)
+; RV32IF-NEXT:    fmv.s fs4, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fs4
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    flw fs4, 12(sp)
+; RV32IF-NEXT:    addi sp, sp, 16
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_fs4:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    addi sp, sp, -16
+; RV64IF-NEXT:    fsw fs4, 12(sp)
+; RV64IF-NEXT:    fmv.s fs4, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fs4
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    flw fs4, 12(sp)
+; RV64IF-NEXT:    addi sp, sp, 16
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{fs4}"(float %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `f21` (`fs5`) as an input, so it should be saved.
+define i32 @explicit_register_f21(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f21:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    addi sp, sp, -16
+; RV32IF-NEXT:    fsw fs5, 12(sp)
+; RV32IF-NEXT:    fmv.s fs5, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fs5
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    flw fs5, 12(sp)
+; RV32IF-NEXT:    addi sp, sp, 16
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f21:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    addi sp, sp, -16
+; RV64IF-NEXT:    fsw fs5, 12(sp)
+; RV64IF-NEXT:    fmv.s fs5, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fs5
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    flw fs5, 12(sp)
+; RV64IF-NEXT:    addi sp, sp, 16
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f21}"(float %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fs5` (`f21`) as an input, so it should be saved.
+define i32 @explicit_register_fs5(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_fs5:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    addi sp, sp, -16
+; RV32IF-NEXT:    fsw fs5, 12(sp)
+; RV32IF-NEXT:    fmv.s fs5, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fs5
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    flw fs5, 12(sp)
+; RV32IF-NEXT:    addi sp, sp, 16
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_fs5:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    addi sp, sp, -16
+; RV64IF-NEXT:    fsw fs5, 12(sp)
+; RV64IF-NEXT:    fmv.s fs5, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fs5
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    flw fs5, 12(sp)
+; RV64IF-NEXT:    addi sp, sp, 16
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{fs5}"(float %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `f22` (`fs6`) as an input, so it should be saved.
+define i32 @explicit_register_f22(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f22:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    addi sp, sp, -16
+; RV32IF-NEXT:    fsw fs6, 12(sp)
+; RV32IF-NEXT:    fmv.s fs6, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fs6
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    flw fs6, 12(sp)
+; RV32IF-NEXT:    addi sp, sp, 16
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f22:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    addi sp, sp, -16
+; RV64IF-NEXT:    fsw fs6, 12(sp)
+; RV64IF-NEXT:    fmv.s fs6, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fs6
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    flw fs6, 12(sp)
+; RV64IF-NEXT:    addi sp, sp, 16
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f22}"(float %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fs6` (`f22`) as an input, so it should be saved.
+define i32 @explicit_register_fs6(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_fs6:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    addi sp, sp, -16
+; RV32IF-NEXT:    fsw fs6, 12(sp)
+; RV32IF-NEXT:    fmv.s fs6, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fs6
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    flw fs6, 12(sp)
+; RV32IF-NEXT:    addi sp, sp, 16
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_fs6:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    addi sp, sp, -16
+; RV64IF-NEXT:    fsw fs6, 12(sp)
+; RV64IF-NEXT:    fmv.s fs6, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fs6
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    flw fs6, 12(sp)
+; RV64IF-NEXT:    addi sp, sp, 16
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{fs6}"(float %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `f23` (`fs7`) as an input, so it should be saved.
+define i32 @explicit_register_f23(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f23:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    addi sp, sp, -16
+; RV32IF-NEXT:    fsw fs7, 12(sp)
+; RV32IF-NEXT:    fmv.s fs7, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fs7
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    flw fs7, 12(sp)
+; RV32IF-NEXT:    addi sp, sp, 16
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f23:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    addi sp, sp, -16
+; RV64IF-NEXT:    fsw fs7, 12(sp)
+; RV64IF-NEXT:    fmv.s fs7, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fs7
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    flw fs7, 12(sp)
+; RV64IF-NEXT:    addi sp, sp, 16
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f23}"(float %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fs7` (`f23`) as an input, so it should be saved.
+define i32 @explicit_register_fs7(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_fs7:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    addi sp, sp, -16
+; RV32IF-NEXT:    fsw fs7, 12(sp)
+; RV32IF-NEXT:    fmv.s fs7, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fs7
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    flw fs7, 12(sp)
+; RV32IF-NEXT:    addi sp, sp, 16
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_fs7:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    addi sp, sp, -16
+; RV64IF-NEXT:    fsw fs7, 12(sp)
+; RV64IF-NEXT:    fmv.s fs7, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fs7
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    flw fs7, 12(sp)
+; RV64IF-NEXT:    addi sp, sp, 16
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{fs7}"(float %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `f24` (`fs8`) as an input, so it should be saved.
+define i32 @explicit_register_f24(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f24:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    addi sp, sp, -16
+; RV32IF-NEXT:    fsw fs8, 12(sp)
+; RV32IF-NEXT:    fmv.s fs8, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fs8
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    flw fs8, 12(sp)
+; RV32IF-NEXT:    addi sp, sp, 16
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f24:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    addi sp, sp, -16
+; RV64IF-NEXT:    fsw fs8, 12(sp)
+; RV64IF-NEXT:    fmv.s fs8, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fs8
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    flw fs8, 12(sp)
+; RV64IF-NEXT:    addi sp, sp, 16
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f24}"(float %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fs8` (`f24`) as an input, so it should be saved.
+define i32 @explicit_register_fs8(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_fs8:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    addi sp, sp, -16
+; RV32IF-NEXT:    fsw fs8, 12(sp)
+; RV32IF-NEXT:    fmv.s fs8, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fs8
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    flw fs8, 12(sp)
+; RV32IF-NEXT:    addi sp, sp, 16
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_fs8:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    addi sp, sp, -16
+; RV64IF-NEXT:    fsw fs8, 12(sp)
+; RV64IF-NEXT:    fmv.s fs8, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fs8
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    flw fs8, 12(sp)
+; RV64IF-NEXT:    addi sp, sp, 16
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{fs8}"(float %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `f25` (`fs9`) as an input, so it should be saved.
+define i32 @explicit_register_f25(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f25:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    addi sp, sp, -16
+; RV32IF-NEXT:    fsw fs9, 12(sp)
+; RV32IF-NEXT:    fmv.s fs9, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fs9
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    flw fs9, 12(sp)
+; RV32IF-NEXT:    addi sp, sp, 16
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f25:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    addi sp, sp, -16
+; RV64IF-NEXT:    fsw fs9, 12(sp)
+; RV64IF-NEXT:    fmv.s fs9, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fs9
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    flw fs9, 12(sp)
+; RV64IF-NEXT:    addi sp, sp, 16
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f25}"(float %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fs9` (`f25`) as an input, so it should be saved.
+define i32 @explicit_register_fs9(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_fs9:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    addi sp, sp, -16
+; RV32IF-NEXT:    fsw fs9, 12(sp)
+; RV32IF-NEXT:    fmv.s fs9, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fs9
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    flw fs9, 12(sp)
+; RV32IF-NEXT:    addi sp, sp, 16
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_fs9:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    addi sp, sp, -16
+; RV64IF-NEXT:    fsw fs9, 12(sp)
+; RV64IF-NEXT:    fmv.s fs9, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fs9
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    flw fs9, 12(sp)
+; RV64IF-NEXT:    addi sp, sp, 16
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{fs9}"(float %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `f26` (`fs10`) as an input, so it should be saved.
+define i32 @explicit_register_f26(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f26:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    addi sp, sp, -16
+; RV32IF-NEXT:    fsw fs10, 12(sp)
+; RV32IF-NEXT:    fmv.s fs10, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fs10
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    flw fs10, 12(sp)
+; RV32IF-NEXT:    addi sp, sp, 16
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f26:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    addi sp, sp, -16
+; RV64IF-NEXT:    fsw fs10, 12(sp)
+; RV64IF-NEXT:    fmv.s fs10, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fs10
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    flw fs10, 12(sp)
+; RV64IF-NEXT:    addi sp, sp, 16
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f26}"(float %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fs10` (`f26`) as an input, so it should be saved.
+define i32 @explicit_register_fs10(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_fs10:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    addi sp, sp, -16
+; RV32IF-NEXT:    fsw fs10, 12(sp)
+; RV32IF-NEXT:    fmv.s fs10, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fs10
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    flw fs10, 12(sp)
+; RV32IF-NEXT:    addi sp, sp, 16
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_fs10:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    addi sp, sp, -16
+; RV64IF-NEXT:    fsw fs10, 12(sp)
+; RV64IF-NEXT:    fmv.s fs10, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fs10
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    flw fs10, 12(sp)
+; RV64IF-NEXT:    addi sp, sp, 16
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{fs10}"(float %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `f27` (`fs11`) as an input, so it should be saved.
+define i32 @explicit_register_f27(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f27:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    addi sp, sp, -16
+; RV32IF-NEXT:    fsw fs11, 12(sp)
+; RV32IF-NEXT:    fmv.s fs11, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fs11
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    flw fs11, 12(sp)
+; RV32IF-NEXT:    addi sp, sp, 16
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f27:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    addi sp, sp, -16
+; RV64IF-NEXT:    fsw fs11, 12(sp)
+; RV64IF-NEXT:    fmv.s fs11, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fs11
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    flw fs11, 12(sp)
+; RV64IF-NEXT:    addi sp, sp, 16
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f27}"(float %a)
+  ret i32 %1
+}
+
+; NOTE: This test uses `fs11` (`f27`) as an input, so it should be saved.
+define i32 @explicit_register_fs11(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_fs11:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    addi sp, sp, -16
+; RV32IF-NEXT:    fsw fs11, 12(sp)
+; RV32IF-NEXT:    fmv.s fs11, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, fs11
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    flw fs11, 12(sp)
+; RV32IF-NEXT:    addi sp, sp, 16
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_fs11:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    addi sp, sp, -16
+; RV64IF-NEXT:    fsw fs11, 12(sp)
+; RV64IF-NEXT:    fmv.s fs11, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, fs11
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    flw fs11, 12(sp)
+; RV64IF-NEXT:    addi sp, sp, 16
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{fs11}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f28(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f28:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s ft8, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, ft8
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f28:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s ft8, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, ft8
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f28}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_ft8(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_ft8:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s ft8, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, ft8
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_ft8:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s ft8, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, ft8
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{ft8}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f29(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f29:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s ft9, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, ft9
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f29:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s ft9, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, ft9
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f29}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_ft9(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_ft9:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s ft9, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, ft9
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_ft9:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s ft9, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, ft9
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{ft9}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f30(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f30:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s ft10, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, ft10
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f30:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s ft10, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, ft10
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f30}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_ft10(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_ft10:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s ft10, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, ft10
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_ft10:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s ft10, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, ft10
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{ft10}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_f31(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_f31:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s ft11, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, ft11
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_f31:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s ft11, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, ft11
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{f31}"(float %a)
+  ret i32 %1
+}
+
+define i32 @explicit_register_ft11(float %a) nounwind {
+; RV32IF-LABEL: explicit_register_ft11:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    fmv.s ft11, fa0
+; RV32IF-NEXT:    #APP
+; RV32IF-NEXT:    fcvt.w.s a0, ft11
+; RV32IF-NEXT:    #NO_APP
+; RV32IF-NEXT:    ret
+;
+; RV64IF-LABEL: explicit_register_ft11:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    fmv.s ft11, fa0
+; RV64IF-NEXT:    #APP
+; RV64IF-NEXT:    fcvt.w.s a0, ft11
+; RV64IF-NEXT:    #NO_APP
+; RV64IF-NEXT:    ret
+  %1 = tail call i32 asm "fcvt.w.s $0, $1", "=r,{ft11}"(float %a)
+  ret i32 %1
+}

Modified: llvm/trunk/test/CodeGen/RISCV/inline-asm-f-constraint-f.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/RISCV/inline-asm-f-constraint-f.ll?rev=368303&r1=368302&r2=368303&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/RISCV/inline-asm-f-constraint-f.ll (original)
+++ llvm/trunk/test/CodeGen/RISCV/inline-asm-f-constraint-f.ll Thu Aug  8 07:59:16 2019
@@ -32,3 +32,30 @@ define float @constraint_f_float(float %
   %2 = tail call float asm "fadd.s $0, $1, $2", "=f,f,f"(float %a, float %1)
   ret float %2
 }
+
+define float @constraint_f_float_abi_name(float %a) nounwind {
+; RV32F-LABEL: constraint_f_float_abi_name:
+; RV32F:       # %bb.0:
+; RV32F-NEXT:    fmv.w.x fa0, a0
+; RV32F-NEXT:    lui a0, %hi(gf)
+; RV32F-NEXT:    flw fs0, %lo(gf)(a0)
+; RV32F-NEXT:    #APP
+; RV32F-NEXT:    fadd.s ft0, fa0, fs0
+; RV32F-NEXT:    #NO_APP
+; RV32F-NEXT:    fmv.x.w a0, ft0
+; RV32F-NEXT:    ret
+;
+; RV64F-LABEL: constraint_f_float_abi_name:
+; RV64F:       # %bb.0:
+; RV64F-NEXT:    fmv.w.x fa0, a0
+; RV64F-NEXT:    lui a0, %hi(gf)
+; RV64F-NEXT:    flw fs0, %lo(gf)(a0)
+; RV64F-NEXT:    #APP
+; RV64F-NEXT:    fadd.s ft0, fa0, fs0
+; RV64F-NEXT:    #NO_APP
+; RV64F-NEXT:    fmv.x.w a0, ft0
+; RV64F-NEXT:    ret
+  %1 = load float, float* @gf
+  %2 = tail call float asm "fadd.s $0, $1, $2", "={ft0},{fa0},{fs0}"(float %a, float %1)
+  ret float %2
+}




More information about the llvm-commits mailing list