Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion compiler/rustc_target/src/callconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,9 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
// Only integers have signedness
if let BackendRepr::Scalar(scalar) = self.layout.backend_repr
&& let Primitive::Int(i, signed) = scalar.primitive()
&& i.size().bits() < bits
// bools are i1 but their primitive is i8. Unlike other types,
// bools can be extended to their primitive size.
&& (i.size().bits() < bits || self.layout.backend_repr.is_bool())
&& let PassMode::Direct(ref mut attrs) = self.mode
{
if signed {
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_target/src/callconv/x86_64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,11 @@ where
} else if is_arg || cx.target_spec().is_like_darwin {
arg.extend_integer_width_to(32);
}
// The x86_64 psABI requires bools to be zero-extended to 8-bits, with high bits unspecified.
// zeroext i1 has this behavior in the LLVM X86 backend.
if !is_arg && arg.layout.backend_repr.is_bool() {
arg.extend_integer_width_to(8);
}
}
}
};
Expand Down
62 changes: 41 additions & 21 deletions tests/codegen-llvm/some-abis-do-extend-params-to-32-bits.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
//@ add-minicore
//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0

//@ revisions:x86_64 i686 aarch64-apple aarch64-windows aarch64-linux arm riscv
//@ revisions:x86_64-linux x86_64-uefi i686 aarch64-apple aarch64-windows aarch64-linux arm riscv

//@[x86_64] compile-flags: --target x86_64-unknown-uefi
//@[x86_64] needs-llvm-components: x86
//@[x86_64-uefi] compile-flags: --target x86_64-unknown-uefi
//@[x86_64-uefi] needs-llvm-components: x86
//@[x86_64-linux] compile-flags: --target x86_64-unknown-linux-gnu
//@[x86_64-linux] needs-llvm-components: x86
//@[i686] compile-flags: --target i686-unknown-linux-musl
//@[i686] needs-llvm-components: x86
//@[aarch64-windows] compile-flags: --target aarch64-pc-windows-msvc
Expand Down Expand Up @@ -33,7 +35,8 @@ use minicore::*;
//
// ZERO/SIGN-EXTENDING TO 32 BITS NON-EXTENDING
// ============================== =======================
// x86_64: void @c_arg_bool(i1 zeroext %_a)
Comment on lines 34 to -36

@jieyouxu jieyouxu Oct 9, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also noticed that because of how the test is written, if codegen starts adding a zeroext on a return type where it is wrong to do so, the test will pass anyway.

Yeah, that seems a bit awkward since it defeats the purpose of the return checks...

For the non-extending return check cases, can we instead match via patterns such as

// x86_64-linux:                                    define {{(dso_local )?}}i1 @c_ret_bool()

That way if the return type gets a zeroext this check should fail. Using this pattern against the uefi one (where it does zeroext) indeed fails to match.

(This is not blocking; I think we can also do this as a follow-up, since this is pre-existing.)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up: #164016

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming we have the option to pass FileCheck arguments, you could also use something like --implicit-check-not=zeroext --implicit-check-not=signext.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm yeah. I'm not sure using the implicit flags is much better though, that also seems not very straightforward when looking at the actual diff right?

// x86_64-linux: void @c_arg_bool(i1 zeroext %_a)
// x86_64-uefi: void @c_arg_bool(i1 zeroext %_a)
// i686: void @c_arg_bool(i1 zeroext %_a)
// aarch64-apple: void @c_arg_bool(i1 zeroext %_a)
// aarch64-windows: void @c_arg_bool(i1 %_a)
Expand All @@ -43,7 +46,8 @@ use minicore::*;
#[no_mangle]
pub extern "C" fn c_arg_bool(_a: bool) {}

// x86_64: void @c_arg_u8(i8 zeroext %_a)
// x86_64-linux: void @c_arg_u8(i8 zeroext %_a)
// x86_64-uefi: void @c_arg_u8(i8 zeroext %_a)
// i686: void @c_arg_u8(i8 zeroext %_a)
// aarch64-apple: void @c_arg_u8(i8 zeroext %_a)
// aarch64-windows: void @c_arg_u8(i8 %_a)
Expand All @@ -53,7 +57,8 @@ pub extern "C" fn c_arg_bool(_a: bool) {}
#[no_mangle]
pub extern "C" fn c_arg_u8(_a: u8) {}

// x86_64: void @c_arg_u16(i16 zeroext %_a)
// x86_64-linux: void @c_arg_u16(i16 zeroext %_a)
// x86_64-uefi: void @c_arg_u16(i16 zeroext %_a)
// i686: void @c_arg_u16(i16 zeroext %_a)
// aarch64-apple: void @c_arg_u16(i16 zeroext %_a)
// aarch64-windows: void @c_arg_u16(i16 %_a)
Expand All @@ -63,7 +68,8 @@ pub extern "C" fn c_arg_u8(_a: u8) {}
#[no_mangle]
pub extern "C" fn c_arg_u16(_a: u16) {}

// x86_64: void @c_arg_u32(i32 %_a)
// x86_64-linux: void @c_arg_u32(i32 %_a)
// x86_64-uefi: void @c_arg_u32(i32 %_a)
// i686: void @c_arg_u32(i32 %_a)
// aarch64-apple: void @c_arg_u32(i32 %_a)
// aarch64-windows: void @c_arg_u32(i32 %_a)
Expand All @@ -73,7 +79,8 @@ pub extern "C" fn c_arg_u16(_a: u16) {}
#[no_mangle]
pub extern "C" fn c_arg_u32(_a: u32) {}

// x86_64: void @c_arg_u64(i64 %_a)
// x86_64-linux: void @c_arg_u64(i64 %_a)
// x86_64-uefi: void @c_arg_u64(i64 %_a)
// i686: void @c_arg_u64(i64 %_a)
// aarch64-apple: void @c_arg_u64(i64 %_a)
// aarch64-windows: void @c_arg_u64(i64 %_a)
Expand All @@ -83,7 +90,8 @@ pub extern "C" fn c_arg_u32(_a: u32) {}
#[no_mangle]
pub extern "C" fn c_arg_u64(_a: u64) {}

// x86_64: void @c_arg_i8(i8 signext %_a)
// x86_64-linux: void @c_arg_i8(i8 signext %_a)
// x86_64-uefi: void @c_arg_i8(i8 signext %_a)
// i686: void @c_arg_i8(i8 signext %_a)
// aarch64-apple: void @c_arg_i8(i8 signext %_a)
// aarch64-windows: void @c_arg_i8(i8 %_a)
Expand All @@ -93,7 +101,8 @@ pub extern "C" fn c_arg_u64(_a: u64) {}
#[no_mangle]
pub extern "C" fn c_arg_i8(_a: i8) {}

// x86_64: void @c_arg_i16(i16 signext %_a)
// x86_64-linux: void @c_arg_i16(i16 signext %_a)
// x86_64-uefi: void @c_arg_i16(i16 signext %_a)
// i686: void @c_arg_i16(i16 signext %_a)
// aarch64-apple: void @c_arg_i16(i16 signext %_a)
// aarch64-windows: void @c_arg_i16(i16 %_a)
Expand All @@ -103,7 +112,8 @@ pub extern "C" fn c_arg_i8(_a: i8) {}
#[no_mangle]
pub extern "C" fn c_arg_i16(_a: i16) {}

// x86_64: void @c_arg_i32(i32 %_a)
// x86_64-linux: void @c_arg_i32(i32 %_a)
// x86_64-uefi: void @c_arg_i32(i32 %_a)
// i686: void @c_arg_i32(i32 %_a)
// aarch64-apple: void @c_arg_i32(i32 %_a)
// aarch64-windows: void @c_arg_i32(i32 %_a)
Expand All @@ -113,7 +123,8 @@ pub extern "C" fn c_arg_i16(_a: i16) {}
#[no_mangle]
pub extern "C" fn c_arg_i32(_a: i32) {}

// x86_64: void @c_arg_i64(i64 %_a)
// x86_64-linux: void @c_arg_i64(i64 %_a)
// x86_64-uefi: void @c_arg_i64(i64 %_a)
// i686: void @c_arg_i64(i64 %_a)
// aarch64-apple: void @c_arg_i64(i64 %_a)
// aarch64-windows: void @c_arg_i64(i64 %_a)
Expand All @@ -123,7 +134,8 @@ pub extern "C" fn c_arg_i32(_a: i32) {}
#[no_mangle]
pub extern "C" fn c_arg_i64(_a: i64) {}

// x86_64: zeroext i1 @c_ret_bool()
// x86_64-linux: zeroext i1 @c_ret_bool()
// x86_64-uefi: zeroext i1 @c_ret_bool()
// i686: zeroext i1 @c_ret_bool()
// aarch64-apple: zeroext i1 @c_ret_bool()
// aarch64-windows: i1 @c_ret_bool()
Expand All @@ -135,7 +147,8 @@ pub extern "C" fn c_ret_bool() -> bool {
false
}

// x86_64: zeroext i8 @c_ret_u8()
// x86_64-linux: i8 @c_ret_u8()
// x86_64-uefi: zeroext i8 @c_ret_u8()
// i686: zeroext i8 @c_ret_u8()
// aarch64-apple: zeroext i8 @c_ret_u8()
// aarch64-windows: i8 @c_ret_u8()
Expand All @@ -147,7 +160,8 @@ pub extern "C" fn c_ret_u8() -> u8 {
0
}

// x86_64: zeroext i16 @c_ret_u16()
// x86_64-linux: i16 @c_ret_u16()
// x86_64-uefi: zeroext i16 @c_ret_u16()
// i686: zeroext i16 @c_ret_u16()
// aarch64-apple: zeroext i16 @c_ret_u16()
// aarch64-windows: i16 @c_ret_u16()
Expand All @@ -159,7 +173,8 @@ pub extern "C" fn c_ret_u16() -> u16 {
0
}

// x86_64: i32 @c_ret_u32()
// x86_64-linux: i32 @c_ret_u32()
// x86_64-uefi: i32 @c_ret_u32()
// i686: i32 @c_ret_u32()
// aarch64-apple: i32 @c_ret_u32()
// aarch64-windows: i32 @c_ret_u32()
Expand All @@ -171,7 +186,8 @@ pub extern "C" fn c_ret_u32() -> u32 {
0
}

// x86_64: i64 @c_ret_u64()
// x86_64-linux: i64 @c_ret_u64()
// x86_64-uefi: i64 @c_ret_u64()
// i686: i64 @c_ret_u64()
// aarch64-apple: i64 @c_ret_u64()
// aarch64-windows: i64 @c_ret_u64()
Expand All @@ -183,7 +199,8 @@ pub extern "C" fn c_ret_u64() -> u64 {
0
}

// x86_64: signext i8 @c_ret_i8()
// x86_64-linux: i8 @c_ret_i8()
// x86_64-uefi: signext i8 @c_ret_i8()
// i686: signext i8 @c_ret_i8()
// aarch64-apple: signext i8 @c_ret_i8()
// aarch64-windows: i8 @c_ret_i8()
Expand All @@ -195,7 +212,8 @@ pub extern "C" fn c_ret_i8() -> i8 {
0
}

// x86_64: signext i16 @c_ret_i16()
// x86_64-linux: i16 @c_ret_i16()
// x86_64-uefi: signext i16 @c_ret_i16()
// i686: signext i16 @c_ret_i16()
// aarch64-apple: signext i16 @c_ret_i16()
// aarch64-windows: i16 @c_ret_i16()
Expand All @@ -207,7 +225,8 @@ pub extern "C" fn c_ret_i16() -> i16 {
0
}

// x86_64: i32 @c_ret_i32()
// x86_64-linux: i32 @c_ret_i32()
// x86_64-uefi: i32 @c_ret_i32()
// i686: i32 @c_ret_i32()
// aarch64-apple: i32 @c_ret_i32()
// aarch64-windows: i32 @c_ret_i32()
Expand All @@ -219,7 +238,8 @@ pub extern "C" fn c_ret_i32() -> i32 {
0
}

// x86_64: i64 @c_ret_i64()
// x86_64-linux: i64 @c_ret_i64()
// x86_64-uefi: i64 @c_ret_i64()
// i686: i64 @c_ret_i64()
// aarch64-apple: i64 @c_ret_i64()
// aarch64-windows: i64 @c_ret_i64()
Expand Down
Loading