about summary refs log tree commit diff
path: root/compiler/rustc_codegen_cranelift
diff options
context:
space:
mode:
authorLeón Orell Valerian Liehr <me@fmease.dev>2025-06-15 23:51:56 +0200
committerGitHub <noreply@github.com>2025-06-15 23:51:56 +0200
commit16152661ff82185b43d982b99f080d17bdfb468b (patch)
treea7b968fd26c25ccf4bf3558afe7bde78d6985418 /compiler/rustc_codegen_cranelift
parente06196da5bde7561480048af2c67057aed017b4b (diff)
parenteb472e77cd3eeb154d163c8d3d23afe5666d367e (diff)
downloadrust-16152661ff82185b43d982b99f080d17bdfb468b.tar.gz
rust-16152661ff82185b43d982b99f080d17bdfb468b.zip
Rollup merge of #142389 - beetrees:cranelift-arg-ext, r=bjorn3
Apply ABI attributes on return types in `rustc_codegen_cranelift`

- The [x86-64 System V ABI standard](https://gitlab.com/x86-psABIs/x86-64-ABI/-/jobs/artifacts/master/raw/x86-64-ABI/abi.pdf?job=build) doesn't sign/zero-extend integer arguments or return types.
- But the de-facto standard as implemented by Clang and GCC is to sign/zero-extend arguments to 32 bits (but not return types).
- Additionally, Apple targets [sign/zero-extend both arguments and return values to 32 bits](https://developer.apple.com/documentation/xcode/writing-64-bit-intel-code-for-apple-platforms#Pass-arguments-to-functions-correctly).
- However, the `rustc_target` ABI adjustment code currently [unconditionally extends both arguments and return values to 32 bits](https://github.com/rust-lang/rust/blame/e703dff8fe220b78195c53478e83fb2f68d8499c/compiler/rustc_target/src/callconv/x86_64.rs#L240) on all targets.
- This doesn't cause a miscompilation when compiling with LLVM as LLVM will ignore the `signext`/`zeroext` attribute when applied to return types on non-Apple x86-64 targets.
- Cranelift, however, does not have a similar special case, requiring `rustc` to set the argument extension attribute correctly.
- However, `rustc_codegen_cranelift` doesn't currently apply ABI attributes to return types at all, meaning `rustc_codegen_cranelift` will currently miscompile `i8`/`u8`/`i16`/`u16` returns on x86-64 Apple targets as those targets require sign/zero-extension of return types.

This PR fixes the bug(s) by making the `rustc_target` x86-64 System V ABI only mark return types as sign/zero-extended on Apple platforms, while also making `rustc_codegen_cranelift` apply ABI attributes to return types. The RISC-V and s390x C ABIs also require sign/zero extension of return types, so this will fix those targets when building with `rustc_codegen_cranelift` too.

r? `````@bjorn3`````
Diffstat (limited to 'compiler/rustc_codegen_cranelift')
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs59
1 files changed, 37 insertions, 22 deletions
diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
index 6d8614aca69..9a0a5b51039 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
@@ -1,6 +1,6 @@
 //! Argument passing
 
-use cranelift_codegen::ir::{ArgumentExtension, ArgumentPurpose};
+use cranelift_codegen::ir::ArgumentPurpose;
 use rustc_abi::{Reg, RegKind};
 use rustc_target::callconv::{
     ArgAbi, ArgAttributes, ArgExtension as RustcArgExtension, CastTarget, PassMode,
@@ -32,13 +32,12 @@ fn reg_to_abi_param(reg: Reg) -> AbiParam {
     AbiParam::new(clif_ty)
 }
 
-fn apply_arg_attrs_to_abi_param(mut param: AbiParam, arg_attrs: ArgAttributes) -> AbiParam {
+fn apply_attrs_to_abi_param(param: AbiParam, arg_attrs: ArgAttributes) -> AbiParam {
     match arg_attrs.arg_ext {
-        RustcArgExtension::None => {}
-        RustcArgExtension::Zext => param.extension = ArgumentExtension::Uext,
-        RustcArgExtension::Sext => param.extension = ArgumentExtension::Sext,
+        RustcArgExtension::None => param,
+        RustcArgExtension::Zext => param.uext(),
+        RustcArgExtension::Sext => param.sext(),
     }
-    param
 }
 
 fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[AbiParam; 2]> {
@@ -82,7 +81,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
         match self.mode {
             PassMode::Ignore => smallvec![],
             PassMode::Direct(attrs) => match self.layout.backend_repr {
-                BackendRepr::Scalar(scalar) => smallvec![apply_arg_attrs_to_abi_param(
+                BackendRepr::Scalar(scalar) => smallvec![apply_attrs_to_abi_param(
                     AbiParam::new(scalar_to_clif_type(tcx, scalar)),
                     attrs
                 )],
@@ -97,8 +96,8 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
                     let a = scalar_to_clif_type(tcx, a);
                     let b = scalar_to_clif_type(tcx, b);
                     smallvec![
-                        apply_arg_attrs_to_abi_param(AbiParam::new(a), attrs_a),
-                        apply_arg_attrs_to_abi_param(AbiParam::new(b), attrs_b),
+                        apply_attrs_to_abi_param(AbiParam::new(a), attrs_a),
+                        apply_attrs_to_abi_param(AbiParam::new(b), attrs_b),
                     ]
                 }
                 _ => unreachable!("{:?}", self.layout.backend_repr),
@@ -112,19 +111,19 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
                     // Abi requires aligning struct size to pointer size
                     let size = self.layout.size.align_to(tcx.data_layout.pointer_align.abi);
                     let size = u32::try_from(size.bytes()).unwrap();
-                    smallvec![apply_arg_attrs_to_abi_param(
+                    smallvec![apply_attrs_to_abi_param(
                         AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructArgument(size),),
                         attrs
                     )]
                 } else {
-                    smallvec![apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs)]
+                    smallvec![apply_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs)]
                 }
             }
             PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => {
                 assert!(!on_stack);
                 smallvec![
-                    apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs),
-                    apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), meta_attrs),
+                    apply_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs),
+                    apply_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), meta_attrs),
                 ]
             }
         }
@@ -133,30 +132,46 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
     fn get_abi_return(&self, tcx: TyCtxt<'tcx>) -> (Option<AbiParam>, Vec<AbiParam>) {
         match self.mode {
             PassMode::Ignore => (None, vec![]),
-            PassMode::Direct(_) => match self.layout.backend_repr {
-                BackendRepr::Scalar(scalar) => {
-                    (None, vec![AbiParam::new(scalar_to_clif_type(tcx, scalar))])
-                }
+            PassMode::Direct(attrs) => match self.layout.backend_repr {
+                BackendRepr::Scalar(scalar) => (
+                    None,
+                    vec![apply_attrs_to_abi_param(
+                        AbiParam::new(scalar_to_clif_type(tcx, scalar)),
+                        attrs,
+                    )],
+                ),
                 BackendRepr::SimdVector { .. } => {
                     let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout);
-                    (None, vec![AbiParam::new(vector_ty)])
+                    (None, vec![apply_attrs_to_abi_param(AbiParam::new(vector_ty), attrs)])
                 }
                 _ => unreachable!("{:?}", self.layout.backend_repr),
             },
-            PassMode::Pair(_, _) => match self.layout.backend_repr {
+            PassMode::Pair(attrs_a, attrs_b) => match self.layout.backend_repr {
                 BackendRepr::ScalarPair(a, b) => {
                     let a = scalar_to_clif_type(tcx, a);
                     let b = scalar_to_clif_type(tcx, b);
-                    (None, vec![AbiParam::new(a), AbiParam::new(b)])
+                    (
+                        None,
+                        vec![
+                            apply_attrs_to_abi_param(AbiParam::new(a), attrs_a),
+                            apply_attrs_to_abi_param(AbiParam::new(b), attrs_b),
+                        ],
+                    )
                 }
                 _ => unreachable!("{:?}", self.layout.backend_repr),
             },
             PassMode::Cast { ref cast, .. } => {
                 (None, cast_target_to_abi_params(cast).into_iter().collect())
             }
-            PassMode::Indirect { attrs: _, meta_attrs: None, on_stack } => {
+            PassMode::Indirect { attrs, meta_attrs: None, on_stack } => {
                 assert!(!on_stack);
-                (Some(AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructReturn)), vec![])
+                (
+                    Some(apply_attrs_to_abi_param(
+                        AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructReturn),
+                        attrs,
+                    )),
+                    vec![],
+                )
             }
             PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
                 unreachable!("unsized return value")