Skip to content

Add a workaround for 128 bit switches #668

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 10, 2025
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
54 changes: 38 additions & 16 deletions example/mini_core.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
#![feature(
no_core, lang_items, intrinsics, unboxed_closures, extern_types,
decl_macro, rustc_attrs, transparent_unions, auto_traits, freeze_impls,
no_core,
lang_items,
intrinsics,
unboxed_closures,
extern_types,
decl_macro,
rustc_attrs,
transparent_unions,
auto_traits,
freeze_impls,
thread_local
)]
#![no_core]
Expand Down Expand Up @@ -35,13 +43,13 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
pub trait DispatchFromDyn<T> {}

// &T -> &U
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
// &mut T -> &mut U
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
// *const T -> *const U
impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
// *mut T -> *mut U
impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U, ()>> for Box<T, ()> {}

#[lang = "legacy_receiver"]
Expand All @@ -52,8 +60,7 @@ impl<T: ?Sized> LegacyReceiver for &mut T {}
impl<T: ?Sized, A: Allocator> LegacyReceiver for Box<T, A> {}

#[lang = "receiver"]
trait Receiver {
}
trait Receiver {}

#[lang = "copy"]
pub trait Copy {}
Expand All @@ -67,10 +74,13 @@ impl Copy for u16 {}
impl Copy for u32 {}
impl Copy for u64 {}
impl Copy for usize {}
impl Copy for u128 {}
impl Copy for i8 {}
impl Copy for i16 {}
impl Copy for i32 {}
impl Copy for i64 {}
impl Copy for isize {}
impl Copy for i128 {}
impl Copy for f32 {}
impl Copy for f64 {}
impl Copy for char {}
Expand Down Expand Up @@ -336,7 +346,6 @@ impl PartialEq for u32 {
}
}


impl PartialEq for u64 {
fn eq(&self, other: &u64) -> bool {
(*self) == (*other)
Expand Down Expand Up @@ -523,7 +532,11 @@ fn panic_in_cleanup() -> ! {
#[track_caller]
fn panic_bounds_check(index: usize, len: usize) -> ! {
unsafe {
libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
libc::printf(
"index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8,
len,
index,
);
intrinsics::abort();
}
}
Expand Down Expand Up @@ -551,8 +564,7 @@ pub trait Deref {
fn deref(&self) -> &Self::Target;
}

pub trait Allocator {
}
pub trait Allocator {}

impl Allocator for () {}

Expand Down Expand Up @@ -634,6 +646,8 @@ pub union MaybeUninit<T> {
}

pub mod intrinsics {
#[rustc_intrinsic]
pub const fn black_box<T>(_dummy: T) -> T;
#[rustc_intrinsic]
pub fn abort() -> !;
#[rustc_intrinsic]
Expand Down Expand Up @@ -711,19 +725,27 @@ pub struct VaList<'a>(&'a mut VaListImpl);

#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
pub macro stringify($($t:tt)*) { /* compiler built-in */ }
pub macro stringify($($t:tt)*) {
/* compiler built-in */
}

#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
pub macro file() { /* compiler built-in */ }
pub macro file() {
/* compiler built-in */
}

#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
pub macro line() { /* compiler built-in */ }
pub macro line() {
/* compiler built-in */
}

#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
pub macro cfg() { /* compiler built-in */ }
pub macro cfg() {
/* compiler built-in */
}

pub static A_STATIC: u8 = 42;

Expand Down
25 changes: 21 additions & 4 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -568,11 +568,28 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
) {
let mut gcc_cases = vec![];
let typ = self.val_ty(value);
for (on_val, dest) in cases {
let on_val = self.const_uint_big(typ, on_val);
gcc_cases.push(self.context.new_case(on_val, on_val, dest));
// FIXME(FractalFir): This is a workaround for a libgccjit limitation.
// Currently, libgccjit can't directly create 128 bit integers.
// Since switch cases must be values, and casts are not constant, we can't use 128 bit switch cases.
// In such a case, we will simply fall back to an if-ladder.
// This *may* be slower than a native switch, but a slow working solution is better than none at all.
if typ.is_i128(self) || typ.is_u128(self) {
for (on_val, dest) in cases {
let on_val = self.const_uint_big(typ, on_val);
let is_case =
self.context.new_comparison(self.location, ComparisonOp::Equals, value, on_val);
let next_block = self.current_func().new_block("case");
self.block.end_with_conditional(self.location, is_case, dest, next_block);
self.block = next_block;
}
self.block.end_with_jump(self.location, default_block);
} else {
for (on_val, dest) in cases {
let on_val = self.const_uint_big(typ, on_val);
gcc_cases.push(self.context.new_case(on_val, on_val, dest));
}
self.block.end_with_switch(self.location, value, default_block, &gcc_cases);
}
self.block.end_with_switch(self.location, value, default_block, &gcc_cases);
}

#[cfg(feature = "master")]
Expand Down
37 changes: 37 additions & 0 deletions tests/run/switchint_128bit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Compiler:
//
// Run-time:
// status: 0

#![feature(no_core)]
#![no_std]
#![no_core]
#![no_main]

extern crate mini_core;
use intrinsics::black_box;
use mini_core::*;

#[no_mangle]
extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
// 1st. Check that small 128 bit values work.
let val = black_box(64_u128);
match val {
0 => return 1,
1 => return 2,
64 => (),
_ => return 3,
}
// 2nd check that *large* values work.
const BIG: u128 = 0xDEAD_C0FE_BEEF_DECAF_BADD_DECAF_BEEF_u128;
let val = black_box(BIG);
match val {
0 => return 4,
1 => return 5,
// Check that we will not match on the lower u64, if the upper qword is different!
0xcafbadddecafbeef => return 6,
0xDEAD_C0FE_BEEF_DECAF_BADD_DECAF_BEEF_u128 => (),
_ => return 7,
}
0
}