diff --git a/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs
index 1995de9dd2d7e..0e0e13fd1d8e0 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs
@@ -20,6 +20,7 @@ pub(crate) fn target() -> Target {
             max_atomic_width: Some(32),
             atomic_cas: false,
             features: "+forced-atomics".into(),
+            llvm_abiname: "ilp32".into(),
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
             emit_debug_gdb_scripts: false,
diff --git a/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs
index bd37cf80b4833..669c1702fda8c 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32im_risc0_zkvm_elf.rs
@@ -29,6 +29,7 @@ pub(crate) fn target() -> Target {
             atomic_cas: true,
 
             features: "+m".into(),
+            llvm_abiname: "ilp32".into(),
             executables: true,
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
diff --git a/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs
index 32df30ddb5e3d..477a6c0e9eb97 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs
@@ -20,6 +20,7 @@ pub(crate) fn target() -> Target {
             max_atomic_width: Some(32),
             atomic_cas: false,
             features: "+m,+forced-atomics".into(),
+            llvm_abiname: "ilp32".into(),
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
             emit_debug_gdb_scripts: false,
diff --git a/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs
index 61c887031bcf2..68146788d2074 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs
@@ -19,6 +19,7 @@ pub(crate) fn target() -> Target {
             cpu: "generic-rv32".into(),
             max_atomic_width: Some(32),
             features: "+m,+a".into(),
+            llvm_abiname: "ilp32".into(),
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
             emit_debug_gdb_scripts: false,
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs
index 9795af5656941..e12c3af6f8f38 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imac_esp_espidf.rs
@@ -27,6 +27,7 @@ pub(crate) fn target() -> Target {
             atomic_cas: true,
 
             features: "+m,+a,+c".into(),
+            llvm_abiname: "ilp32".into(),
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
             emit_debug_gdb_scripts: false,
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs
index cc28198e3ff0a..adc76f3cdb583 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_none_elf.rs
@@ -19,6 +19,7 @@ pub(crate) fn target() -> Target {
             cpu: "generic-rv32".into(),
             max_atomic_width: Some(32),
             features: "+m,+a,+c".into(),
+            llvm_abiname: "ilp32".into(),
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
             emit_debug_gdb_scripts: false,
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs
index 62397dcae9a1b..31c9180c509ce 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_nuttx_elf.rs
@@ -21,6 +21,7 @@ pub(crate) fn target() -> Target {
             cpu: "generic-rv32".into(),
             max_atomic_width: Some(32),
             features: "+m,+a,+c".into(),
+            llvm_abiname: "ilp32".into(),
             panic_strategy: PanicStrategy::Unwind,
             relocation_model: RelocModel::Static,
             ..Default::default()
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs
index 0eaabc60cbcd0..88d112a012d0c 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs
@@ -20,6 +20,7 @@ pub(crate) fn target() -> Target {
             cpu: "generic-rv32".into(),
             max_atomic_width: Some(32),
             features: "+m,+a,+c".into(),
+            llvm_abiname: "ilp32".into(),
             panic_strategy: PanicStrategy::Unwind,
             relocation_model: RelocModel::Static,
             ..Default::default()
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs b/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs
index 9ae84ace457dd..cec97f8653899 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imc_esp_espidf.rs
@@ -30,6 +30,7 @@ pub(crate) fn target() -> Target {
             atomic_cas: true,
 
             features: "+m,+c".into(),
+            llvm_abiname: "ilp32".into(),
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
             emit_debug_gdb_scripts: false,
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs
index 0ae49debc3a38..0e00fc69b41a9 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs
@@ -20,6 +20,7 @@ pub(crate) fn target() -> Target {
             max_atomic_width: Some(32),
             atomic_cas: false,
             features: "+m,+c,+forced-atomics".into(),
+            llvm_abiname: "ilp32".into(),
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
             emit_debug_gdb_scripts: false,
diff --git a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs
index 5f3917edf7019..e86549806ddbf 100644
--- a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_nuttx_elf.rs
@@ -21,6 +21,7 @@ pub(crate) fn target() -> Target {
             cpu: "generic-rv32".into(),
             max_atomic_width: Some(32),
             features: "+m,+c".into(),
+            llvm_abiname: "ilp32".into(),
             panic_strategy: PanicStrategy::Unwind,
             relocation_model: RelocModel::Static,
             ..Default::default()
diff --git a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs
index d514f8efcd08c..d62ecc07a5d4f 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_none_elf.rs
@@ -22,6 +22,7 @@ pub(crate) fn target() -> Target {
             cpu: "generic-rv64".into(),
             max_atomic_width: Some(64),
             features: "+m,+a,+c".into(),
+            llvm_abiname: "lp64".into(),
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
             code_model: Some(CodeModel::Medium),
diff --git a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs
index a737e46de1baa..9c18166558115 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64imac_unknown_nuttx_elf.rs
@@ -24,6 +24,7 @@ pub(crate) fn target() -> Target {
             cpu: "generic-rv64".into(),
             max_atomic_width: Some(64),
             features: "+m,+a,+c".into(),
+            llvm_abiname: "lp64".into(),
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
             code_model: Some(CodeModel::Medium),
diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs
index fc5bd846e0241..7ed21954fba02 100644
--- a/compiler/rustc_target/src/spec/tests/tests_impl.rs
+++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs
@@ -152,6 +152,17 @@ impl Target {
         if self.crt_static_default || self.crt_static_allows_dylibs {
             assert!(self.crt_static_respected);
         }
+
+        // Check that RISC-V targets always specify which ABI they use.
+        match &*self.arch {
+            "riscv32" => {
+                assert_matches!(&*self.llvm_abiname, "ilp32" | "ilp32f" | "ilp32d" | "ilp32e")
+            }
+            "riscv64" => {
+                assert_matches!(&*self.llvm_abiname, "lp64" | "lp64f" | "lp64d" | "lp64q")
+            }
+            _ => {}
+        }
     }
 
     // Add your target to the whitelist if it has `std` library
diff --git a/tests/assembly/riscv-soft-abi-with-float-features.rs b/tests/assembly/riscv-soft-abi-with-float-features.rs
new file mode 100644
index 0000000000000..733137f570093
--- /dev/null
+++ b/tests/assembly/riscv-soft-abi-with-float-features.rs
@@ -0,0 +1,46 @@
+//@ assembly-output: emit-asm
+//@ compile-flags: --target riscv64imac-unknown-none-elf -Ctarget-feature=+f,+d
+//@ needs-llvm-components: riscv
+
+#![feature(no_core, lang_items, f16)]
+#![crate_type = "lib"]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[lang = "copy"]
+trait Copy {}
+
+impl Copy for f16 {}
+impl Copy for f32 {}
+impl Copy for f64 {}
+
+// This test checks that the floats are all returned in `a0` as required by the `lp64` ABI.
+
+// CHECK-LABEL: read_f16
+#[no_mangle]
+pub extern "C" fn read_f16(x: &f16) -> f16 {
+    // CHECK: lh a0, 0(a0)
+    // CHECK-NEXT: lui a1, 1048560
+    // CHECK-NEXT: or a0, a0, a1
+    // CHECK-NEXT: ret
+    *x
+}
+
+// CHECK-LABEL: read_f32
+#[no_mangle]
+pub extern "C" fn read_f32(x: &f32) -> f32 {
+    // CHECK: flw fa5, 0(a0)
+    // CHECK-NEXT: fmv.x.w a0, fa5
+    // CHECK-NEXT: ret
+    *x
+}
+
+// CHECK-LABEL: read_f64
+#[no_mangle]
+pub extern "C" fn read_f64(x: &f64) -> f64 {
+    // CHECK: ld a0, 0(a0)
+    // CHECK-NEXT: ret
+    *x
+}
diff --git a/tests/codegen/riscv-target-abi.rs b/tests/codegen/riscv-target-abi.rs
index 5d545af9c7690..88da4ece7ba31 100644
--- a/tests/codegen/riscv-target-abi.rs
+++ b/tests/codegen/riscv-target-abi.rs
@@ -10,7 +10,7 @@
 
 //@[riscv32imac] compile-flags: --target=riscv32imac-unknown-none-elf
 //@[riscv32imac] needs-llvm-components: riscv
-// riscv32imac-NOT: !"target-abi"
+// riscv32imac: !{i32 1, !"target-abi", !"ilp32"}
 
 #![feature(no_core, lang_items)]
 #![crate_type = "lib"]