Skip to content
Draft
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
6 changes: 6 additions & 0 deletions compiler/rustc_target/src/callconv/x86.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,12 @@ where
Ty: TyAbiInterface<'a, C> + Copy,
C: HasDataLayout + HasTargetSpec,
{
// Perform some sign/arg extension on integers to mirror our C ABI
for arg in fn_abi.args.iter_mut() {
arg.extend_integer_width_to(8);
}
fn_abi.ret.extend_integer_width_to(8);

// Avoid returning floats in x87 registers on x86 as loading and storing from x87
// registers will quiet signalling NaNs. Also avoid using SSE registers since they
// are not always available (depending on target features).
Expand Down
11 changes: 1 addition & 10 deletions compiler/rustc_ty_utils/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ use rustc_middle::ty::layout::{
use rustc_middle::ty::{self, InstanceKind, ShimKind, Ty, TyCtxt, Unnormalized};
use rustc_span::DUMMY_SP;
use rustc_span::def_id::DefId;
use rustc_target::callconv::{
AbiMap, ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, FnAbi, PassMode,
};
use rustc_target::callconv::{AbiMap, ArgAbi, ArgAttribute, ArgAttributes, FnAbi, PassMode};
use tracing::debug;

pub(crate) fn provide(providers: &mut Providers) {
Expand Down Expand Up @@ -331,13 +329,6 @@ fn arg_attrs_for_rust_scalar<'tcx>(
) -> ArgAttributes {
let mut attrs = ArgAttributes::new();

// Booleans are always a noundef i1 that needs to be zero-extended.
if scalar.is_bool() {
attrs.ext(ArgExtension::Zext);
attrs.set(ArgAttribute::NoUndef);
return attrs;
}

if !scalar.is_uninit_valid() {
attrs.set(ArgAttribute::NoUndef);
}
Expand Down
41 changes: 41 additions & 0 deletions tests/assembly-llvm/aarch64/mask-bool-ffi-return.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//@ add-minicore
//@ assembly-output: emit-asm
//@ needs-llvm-components: aarch64
//@ compile-flags: -Copt-level=3 --target=aarch64-unknown-linux-gnu

// Previously, Rust used to assume omnipresent zero-extension on bool in FFI returns
// which resulted in LLVM assuming that a register did not require explicit masking (e.g. `and`)
// and could be correctly handled via `cmp w0, #0`.
// `cmp` looks at the full register, but only the 8 bits that contain the bool are specified,
// and this is particularly glaring in the event of a branch or csel based on this.
// Thus we are looking for explicit handling like `tst w0, #0x1` or `and w0, #0xFF`

// NOTE: simplifying this further is risky as `tbnz x0, #0, ...` only examines 1 bit,
// so LLVM will optimize it all away if there's an immediate jump to another function

#![crate_type = "lib"]
#![feature(no_core)]
#![no_core]

extern crate minicore;

#[repr(C)]
struct Bools {
a: bool,
b: bool,
}

#[link(name = "rust_test_helpers")]
unsafe extern "C" {
safe fn bools_get_first_bool(bools: Bools) -> bool;
}

// CHECK-LABEL: broken
pub fn broken() -> i32 {
let bools = Bools { a: false, b: true };
// CHECK: bl bools_get_first_bool
// CHECK-NOT: cmp
// CHECK: tst w0, #0x1
// CHECK-NOT: cmp
if bools_get_first_bool(bools) { 123 } else { 321 }
}
2 changes: 1 addition & 1 deletion tests/codegen-llvm/enum/enum-aggregate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::ptr::NonNull;

#[no_mangle]
fn make_some_bool(x: bool) -> Option<bool> {
// CHECK-LABEL: i8 @make_some_bool(i1 zeroext %x)
// CHECK-LABEL: i8 @make_some_bool(i1{{( zeroext)?}} %x)
// CHECK-NEXT: start:
// CHECK-NEXT: %[[WIDER:.+]] = zext i1 %x to i8
// CHECK-NEXT: ret i8 %[[WIDER]]
Expand Down
8 changes: 4 additions & 4 deletions tests/codegen-llvm/function-arguments-noopt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub struct S {
_field: [i32; 8],
}

// CHECK: zeroext i1 @boolean(i1 zeroext %x)
// CHECK: {{(zeroext)?}} i1 @boolean(i1{{( zeroext)?}} %x)
#[no_mangle]
pub fn boolean(x: bool) -> bool {
x
Expand All @@ -19,7 +19,7 @@ pub fn boolean(x: bool) -> bool {
// CHECK-LABEL: @boolean_call
#[no_mangle]
pub fn boolean_call(x: bool, f: fn(bool) -> bool) -> bool {
// CHECK: call zeroext i1 %f(i1 zeroext %x)
// CHECK: call{{( zeroext)?}} i1 %f(i1{{( zeroext)?}} %x)
f(x)
}

Expand Down Expand Up @@ -55,7 +55,7 @@ pub fn struct_call(x: S, f: fn(S) -> S) -> S {
f(x)
}

// CHECK: { i1, i8 } @enum_(i1 zeroext %x.0, i8 %x.1)
// CHECK: { i1, i8 } @enum_(i1{{( zeroext)?}} %x.0, i8 %x.1)
#[no_mangle]
pub fn enum_(x: Option<u8>) -> Option<u8> {
x
Expand All @@ -64,6 +64,6 @@ pub fn enum_(x: Option<u8>) -> Option<u8> {
// CHECK-LABEL: @enum_call
#[no_mangle]
pub fn enum_call(x: Option<u8>, f: fn(Option<u8>) -> Option<u8>) -> Option<u8> {
// CHECK: call { i1, i8 } %f(i1 zeroext %x.0, i8 %x.1)
// CHECK: call { i1, i8 } %f(i1{{( zeroext)?}} %x.0, i8 %x.1)
f(x)
}
6 changes: 3 additions & 3 deletions tests/codegen-llvm/function-arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub enum MyBool {
False,
}

// CHECK: noundef zeroext i1 @boolean(i1 noundef zeroext %x)
// CHECK: noundef{{( zeroext)?}} i1 @boolean(i1 noundef{{( zeroext)?}} %x)
#[no_mangle]
pub fn boolean(x: bool) -> bool {
x
Expand All @@ -38,7 +38,7 @@ pub fn maybeuninit_boolean(x: MaybeUninit<bool>) -> MaybeUninit<bool> {
x
}

// CHECK: noundef zeroext i1 @enum_bool(i1 noundef zeroext %x)
// CHECK: noundef{{( zeroext)?}} i1 @enum_bool(i1 noundef{{( zeroext)?}} %x)
#[no_mangle]
pub fn enum_bool(x: MyBool) -> MyBool {
x
Expand Down Expand Up @@ -271,7 +271,7 @@ pub fn enum_id_1(x: Option<Result<u16, u16>>) -> Option<Result<u16, u16>> {
x
}

// CHECK: { i1, i8 } @enum_id_2(i1 noundef zeroext %x.0, i8 %x.1)
// CHECK: { i1, i8 } @enum_id_2(i1 noundef{{( zeroext)?}} %x.0, i8 %x.1)
#[no_mangle]
pub fn enum_id_2(x: Option<u8>) -> Option<u8> {
x
Expand Down
6 changes: 3 additions & 3 deletions tests/codegen-llvm/mir-aggregate-no-alloca.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,15 @@ pub fn make_2_tuple(x: u32) -> (u32, u32) {
pair
}

// CHECK-LABEL: i8 @make_cell_of_bool(i1 noundef zeroext %b)
// CHECK-LABEL: i8 @make_cell_of_bool(i1 noundef{{( zeroext)?}} %b)
#[no_mangle]
pub fn make_cell_of_bool(b: bool) -> std::cell::Cell<bool> {
// CHECK: %[[BYTE:.+]] = zext i1 %b to i8
// CHECK: ret i8 %[[BYTE]]
std::cell::Cell::new(b)
}

// CHECK-LABEL: { i8, i16 } @make_cell_of_bool_and_short(i1 noundef zeroext %b, i16{{.*}} %s)
// CHECK-LABEL: { i8, i16 } @make_cell_of_bool_and_short(i1 noundef{{( zeroext)?}} %b, i16{{.*}} %s)
#[no_mangle]
pub fn make_cell_of_bool_and_short(b: bool, s: u16) -> std::cell::Cell<(bool, u16)> {
// CHECK-NOT: alloca
Expand All @@ -70,7 +70,7 @@ pub fn make_cell_of_bool_and_short(b: bool, s: u16) -> std::cell::Cell<(bool, u1
std::cell::Cell::new((b, s))
}

// CHECK-LABEL: { i1, i1 } @make_tuple_of_bools(i1 noundef zeroext %a, i1 noundef zeroext %b)
// CHECK-LABEL: { i1, i1 } @make_tuple_of_bools(i1 noundef{{( zeroext)?}} %a, i1 noundef{{( zeroext)?}} %b)
#[no_mangle]
pub fn make_tuple_of_bools(a: bool, b: bool) -> (bool, bool) {
// CHECK-NOT: alloca
Expand Down
4 changes: 2 additions & 2 deletions tests/codegen-llvm/rust-abi-arch-specific-adjustment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ pub fn arg_attr_i128(x: i128) -> i128 {
}

#[no_mangle]
// riscv64: define noundef zeroext i1 @arg_attr_bool(i1 noundef zeroext %x)
// loongarch64: define noundef zeroext i1 @arg_attr_bool(i1 noundef zeroext %x)
// riscv64: define noundef i1 @arg_attr_bool(i1 noundef zeroext %x)
// loongarch64: define noundef i1 @arg_attr_bool(i1 noundef zeroext %x)
pub fn arg_attr_bool(x: bool) -> bool {
x
}
Expand Down
10 changes: 5 additions & 5 deletions tests/codegen-llvm/scalar-pair-bool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,25 @@

#![crate_type = "lib"]

// CHECK: define{{.*}}{ i1, i1 } @pair_bool_bool(i1 noundef zeroext %pair.0, i1 noundef zeroext %pair.1)
// CHECK: define{{.*}}{ i1, i1 } @pair_bool_bool(i1 noundef{{( zeroext)?}} %pair.0, i1 noundef{{( zeroext)?}} %pair.1)
#[no_mangle]
pub fn pair_bool_bool(pair: (bool, bool)) -> (bool, bool) {
pair
}

// CHECK: define{{.*}}{ i1, i32 } @pair_bool_i32(i1 noundef zeroext %pair.0, i32 noundef %pair.1)
// CHECK: define{{.*}}{ i1, i32 } @pair_bool_i32(i1 noundef{{( zeroext)?}} %pair.0, i32 noundef %pair.1)
#[no_mangle]
pub fn pair_bool_i32(pair: (bool, i32)) -> (bool, i32) {
pair
}

// CHECK: define{{.*}}{ i32, i1 } @pair_i32_bool(i32 noundef %pair.0, i1 noundef zeroext %pair.1)
// CHECK: define{{.*}}{ i32, i1 } @pair_i32_bool(i32 noundef %pair.0, i1 noundef{{( zeroext)?}} %pair.1)
#[no_mangle]
pub fn pair_i32_bool(pair: (i32, bool)) -> (i32, bool) {
pair
}

// CHECK: define{{.*}}{ i1, i1 } @pair_and_or(i1 noundef zeroext %_1.0, i1 noundef zeroext %_1.1)
// CHECK: define{{.*}}{ i1, i1 } @pair_and_or(i1 noundef{{( zeroext)?}} %_1.0, i1 noundef{{( zeroext)?}} %_1.1)
#[no_mangle]
pub fn pair_and_or((a, b): (bool, bool)) -> (bool, bool) {
// Make sure it can operate directly on the unpacked args
Expand All @@ -30,7 +30,7 @@ pub fn pair_and_or((a, b): (bool, bool)) -> (bool, bool) {
(a && b, a || b)
}

// CHECK: define{{.*}}void @pair_branches(i1 noundef zeroext %_1.0, i1 noundef zeroext %_1.1)
// CHECK: define{{.*}}void @pair_branches(i1 noundef{{( zeroext)?}} %_1.0, i1 noundef{{( zeroext)?}} %_1.1)
#[no_mangle]
pub fn pair_branches((a, b): (bool, bool)) {
// Make sure it can branch directly on the unpacked bool args
Expand Down
27 changes: 27 additions & 0 deletions tests/codegen-llvm/some-abis-do-extend-params-to-32-bits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ use minicore::*;
//
// ZERO/SIGN-EXTENDING TO 32 BITS NON-EXTENDING
// ============================== =======================
// x86_64: 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)
// aarch64-linux: void @c_arg_bool(i1 %_a)
// arm: void @c_arg_bool(i1 zeroext %_a)
// riscv: void @c_arg_bool(i1 zeroext %_a)
#[no_mangle]
pub extern "C" fn c_arg_bool(_a: bool) {}

// x86_64: void @c_arg_u8(i8 zeroext %_a)
// i686: void @c_arg_u8(i8 zeroext %_a)
// aarch64-apple: void @c_arg_u8(i8 zeroext %_a)
Expand Down Expand Up @@ -113,6 +123,18 @@ 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()
// i686: zeroext i1 @c_ret_bool()
// aarch64-apple: zeroext i1 @c_ret_bool()
// aarch64-windows: i1 @c_ret_bool()
// aarch64-linux: i1 @c_ret_bool()
// arm: zeroext i1 @c_ret_bool()
// riscv: zeroext i1 @c_ret_bool()
#[no_mangle]
pub extern "C" fn c_ret_bool() -> bool {
false
}

// x86_64: zeroext i8 @c_ret_u8()
// i686: zeroext i8 @c_ret_u8()
// aarch64-apple: zeroext i8 @c_ret_u8()
Expand Down Expand Up @@ -210,10 +232,13 @@ pub extern "C" fn c_ret_i64() -> i64 {
}

const C_SOURCE_FILE: &'static str = r##"
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>

void c_arg_bool(bool _a) { }

void c_arg_u8(uint8_t _a) { }
void c_arg_u16(uint16_t _a) { }
void c_arg_u32(uint32_t _a) { }
Expand All @@ -224,6 +249,8 @@ void c_arg_i16(int16_t _a) { }
void c_arg_i32(int32_t _a) { }
void c_arg_i64(int64_t _a) { }

bool c_ret_bool() { return false; }

uint8_t c_ret_u8() { return 0; }
uint16_t c_ret_u16() { return 0; }
uint32_t c_ret_u32() { return 0; }
Expand Down
10 changes: 5 additions & 5 deletions tests/codegen-llvm/transmute-scalar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ pub fn f32_to_bits(x: f32) -> u32 {
unsafe { mem::transmute(x) }
}

// CHECK-LABEL: define{{.*}}i8 @bool_to_byte(i1 zeroext %b)
// CHECK-LABEL: define{{.*}}i8 @bool_to_byte(i1{{( zeroext)?}} %b)
// CHECK: %_0 = zext i1 %b to i8
// CHECK-NEXT: ret i8 %_0
#[no_mangle]
pub fn bool_to_byte(b: bool) -> u8 {
unsafe { mem::transmute(b) }
}

// CHECK-LABEL: define{{.*}}zeroext i1 @byte_to_bool(i8{{.*}} %byte)
// CHECK-LABEL: define{{.*}} i1 @byte_to_bool(i8{{.*}} %byte)
// CHECK: %_0 = trunc{{( nuw)?}} i8 %byte to i1
// CHECK-NEXT: ret i1 %_0
#[no_mangle]
Expand Down Expand Up @@ -72,7 +72,7 @@ pub enum FakeBoolSigned {
True = 1,
}

// CHECK-LABEL: define{{.*}}i8 @bool_to_fake_bool_signed(i1 zeroext %b)
// CHECK-LABEL: define{{.*}}i8 @bool_to_fake_bool_signed(i1{{( zeroext)?}} %b)
// CHECK: %_0 = zext i1 %b to i8
// CHECK-NEXT: ret i8 %_0
#[no_mangle]
Expand All @@ -94,14 +94,14 @@ pub enum FakeBoolUnsigned {
True = 1,
}

// CHECK-LABEL: define{{.*}}i1 @bool_to_fake_bool_unsigned(i1 zeroext %b)
// CHECK-LABEL: define{{.*}}i1 @bool_to_fake_bool_unsigned(i1{{( zeroext)?}} %b)
// CHECK: ret i1 %b
#[no_mangle]
pub fn bool_to_fake_bool_unsigned(b: bool) -> FakeBoolUnsigned {
unsafe { mem::transmute(b) }
}

// CHECK-LABEL: define{{.*}}i1 @fake_bool_unsigned_to_bool(i1 zeroext %b)
// CHECK-LABEL: define{{.*}}i1 @fake_bool_unsigned_to_bool(i1{{( zeroext)?}} %b)
// CHECK: ret i1 %b
#[no_mangle]
pub fn fake_bool_unsigned_to_bool(b: FakeBoolUnsigned) -> bool {
Expand Down
2 changes: 1 addition & 1 deletion tests/codegen-llvm/union-abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ pub fn test_CUnionU128(_: CUnionU128) {
pub union UnionBool {
b: bool,
}
// CHECK: define {{(dso_local )?}}noundef zeroext i1 @test_UnionBool(i8{{.*}} %b)
// CHECK: define {{(dso_local )?}}noundef{{( zeroext)?}} i1 @test_UnionBool(i8{{.*}} %b)
#[no_mangle]
pub fn test_UnionBool(b: UnionBool) -> bool {
unsafe { b.b }
Expand Down
2 changes: 1 addition & 1 deletion tests/codegen-llvm/union-aggregate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use std::ptr::NonNull;

#[no_mangle]
fn make_mu_bool(x: bool) -> MU<bool> {
// CHECK-LABEL: i8 @make_mu_bool(i1 zeroext %x)
// CHECK-LABEL: i8 @make_mu_bool(i1{{( zeroext)?}} %x)
// CHECK-NEXT: start:
// CHECK-NEXT: %[[WIDER:.+]] = zext i1 %x to i8
// CHECK-NEXT: ret i8 %[[WIDER]]
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/abi/debug.generic.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ error: fn_abi_of(test) = FnAbi {
mode: Direct(
ArgAttributes {
regular: NoUndef,
arg_ext: Zext,
arg_ext: None,
pointee_size: Size(0 bytes),
pointee_align: None,
},
Expand Down Expand Up @@ -169,7 +169,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi {
mode: Direct(
ArgAttributes {
regular: NoUndef,
arg_ext: Zext,
arg_ext: None,
pointee_size: Size(0 bytes),
pointee_align: None,
},
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/abi/debug.loongarch64.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ error: fn_abi_of(test) = FnAbi {
mode: Direct(
ArgAttributes {
regular: NoUndef,
arg_ext: Zext,
arg_ext: None,
pointee_size: Size(0 bytes),
pointee_align: None,
},
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/abi/debug.riscv64.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ error: fn_abi_of(test) = FnAbi {
mode: Direct(
ArgAttributes {
regular: NoUndef,
arg_ext: Zext,
arg_ext: None,
pointee_size: Size(0 bytes),
pointee_align: None,
},
Expand Down
Loading