about summary refs log tree commit diff
diff options
context:
space:
mode:
authormichal kostrubiec <fractalfirdev@gmail.com>2025-05-09 21:22:33 +0200
committermichal kostrubiec <fractalfirdev@gmail.com>2025-05-10 00:34:54 +0200
commit33966ccbb6570c83b9fc1dd0942f83ae2d56f47c (patch)
tree4bc68addcdc6ed0454f68da589c0b7f24b4decef
parentcfe88fa8318ecf6aa2947a6314c0dcdc830e7de0 (diff)
downloadrust-33966ccbb6570c83b9fc1dd0942f83ae2d56f47c.tar.gz
rust-33966ccbb6570c83b9fc1dd0942f83ae2d56f47c.zip
Add a workaround for 128 bit switches
-rw-r--r--example/mini_core.rs54
-rw-r--r--src/builder.rs25
-rw-r--r--tests/run/switchint_128bit.rs37
3 files changed, 96 insertions, 20 deletions
diff --git a/example/mini_core.rs b/example/mini_core.rs
index c554a87b825..d1d8e8fd5bc 100644
--- a/example/mini_core.rs
+++ b/example/mini_core.rs
@@ -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]
@@ -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"]
@@ -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 {}
@@ -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 {}
@@ -336,7 +346,6 @@ impl PartialEq for u32 {
     }
 }
 
-
 impl PartialEq for u64 {
     fn eq(&self, other: &u64) -> bool {
         (*self) == (*other)
@@ -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();
     }
 }
@@ -551,8 +564,7 @@ pub trait Deref {
     fn deref(&self) -> &Self::Target;
 }
 
-pub trait Allocator {
-}
+pub trait Allocator {}
 
 impl Allocator for () {}
 
@@ -635,6 +647,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]
     pub fn size_of<T>() -> usize;
@@ -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;
 
diff --git a/src/builder.rs b/src/builder.rs
index 5c70f4a7df9..557f7da0db8 100644
--- a/src/builder.rs
+++ b/src/builder.rs
@@ -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")]
diff --git a/tests/run/switchint_128bit.rs b/tests/run/switchint_128bit.rs
new file mode 100644
index 00000000000..decae5bfcd7
--- /dev/null
+++ b/tests/run/switchint_128bit.rs
@@ -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
+}