From 93ba9886b4c733c9b1b7832380b618d9b50a37b0 Mon Sep 17 00:00:00 2001 From: FractalFir Date: Tue, 12 Aug 2025 13:49:00 +0200 Subject: [PATCH 1/2] Made the logical shift / artihmetic shift not relly on signs of intigers --- src/builder.rs | 10 +++++-- src/int.rs | 70 ++++++++++++++++++++++++++++++-------------- src/intrinsic/mod.rs | 14 ++++----- 3 files changed, 62 insertions(+), 32 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 34ade3d025f..4dbd4f392aa 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -40,7 +40,11 @@ use crate::type_of::LayoutGccExt; // TODO(antoyo) type Funclet = (); - +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ShiftKind { + Logical, + Arithmetic, +} enum ExtremumOperation { Max, Min, @@ -827,13 +831,13 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn lshr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - self.gcc_lshr(a, b) + self.gcc_shr(a, b, ShiftKind::Logical) } fn ashr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { // TODO(antoyo): check whether behavior is an arithmetic shift for >> . // It seems to be if the value is signed. - self.gcc_lshr(a, b) + self.gcc_shr(a, b, ShiftKind::Arithmetic) } fn and(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { diff --git a/src/int.rs b/src/int.rs index 9fb7f6bad68..41abdae2df7 100644 --- a/src/int.rs +++ b/src/int.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_target::callconv::{ArgAbi, ArgAttributes, FnAbi, PassMode}; use rustc_type_ir::{Interner, TyKind}; -use crate::builder::{Builder, ToGccComp}; +use crate::builder::{Builder, ShiftKind, ToGccComp}; use crate::common::{SignType, TypeReflection}; use crate::context::CodegenCx; @@ -68,36 +68,59 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { self.cx.bitwise_operation(BinaryOp::BitwiseAnd, a, b, self.location) } - pub fn gcc_lshr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + pub fn gcc_shr( + &mut self, + a: RValue<'gcc>, + b: RValue<'gcc>, + shift_kind: ShiftKind, + ) -> RValue<'gcc> { let a_type = a.get_type(); let b_type = b.get_type(); let a_native = self.is_native_int_type(a_type); let b_native = self.is_native_int_type(b_type); if a_native && b_native { - // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by a signed number. - // TODO(antoyo): cast to unsigned to do a logical shift if that does not work. - if a_type.is_signed(self) != b_type.is_signed(self) { - let b = self.context.new_cast(self.location, b, a_type); - a >> b - } else { - let a_size = a_type.get_size(); - let b_size = b_type.get_size(); - match a_size.cmp(&b_size) { - std::cmp::Ordering::Less => { - let a = self.context.new_cast(self.location, a, b_type); - a >> b - } - std::cmp::Ordering::Equal => a >> b, - std::cmp::Ordering::Greater => { - let b = self.context.new_cast(self.location, b, a_type); - a >> b - } + let (a, a_type) = match (shift_kind, a_type.is_signed(self.cx)) { + (ShiftKind::Logical, true) => { + let a_type = a_type.to_unsigned(self.cx); + (self.gcc_int_cast(a, a_type), a_type) + } + (ShiftKind::Logical, false) => (a, a_type), + (ShiftKind::Arithmetic, true) => (a, a_type), + (ShiftKind::Arithmetic, false) => { + let a_type = a_type.to_signed(self.cx); + (self.gcc_int_cast(a, a_type), a_type) + } + }; + let (b, b_type) = match (shift_kind, b_type.is_signed(self.cx)) { + (ShiftKind::Logical, true) => { + let b_type = b_type.to_unsigned(self.cx); + (self.gcc_int_cast(b, b_type), b_type) + } + (ShiftKind::Logical, false) => (b, b_type), + (ShiftKind::Arithmetic, true) => (b, b_type), + (ShiftKind::Arithmetic, false) => { + let b_type = b_type.to_signed(self.cx); + (self.gcc_int_cast(b, b_type), b_type) + } + }; + + let a_size = a_type.get_size(); + let b_size = b_type.get_size(); + match a_size.cmp(&b_size) { + std::cmp::Ordering::Less => { + let a = self.context.new_cast(self.location, a, b_type); + a >> b + } + std::cmp::Ordering::Equal => a >> b, + std::cmp::Ordering::Greater => { + let b = self.context.new_cast(self.location, b, a_type); + a >> b } } } else if a_type.is_vector() && b_type.is_vector() { a >> b } else if a_native && !b_native { - self.gcc_lshr(a, self.gcc_int_cast(b, a_type)) + self.gcc_shr(a, self.gcc_int_cast(b, a_type), shift_kind) } else { // NOTE: we cannot use the lshr builtin because it's calling hi() (to get the most // significant half of the number) which uses lshr. @@ -122,7 +145,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let shift_value = self.gcc_sub(b, sixty_four); let high = self.high(a); - let sign = if a_type.is_signed(self) { high >> sixty_three } else { zero }; + let sign = match shift_kind { + ShiftKind::Logical => zero, + ShiftKind::Arithmetic => high >> sixty_three, + }; let array_value = self.concat_low_high_rvalues(a_type, high >> shift_value, sign); then_block.add_assignment(self.location, result, array_value); then_block.end_with_jump(self.location, after_block); diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index 57bdbad5e53..b69ea6cd195 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -865,7 +865,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { 128 => { // TODO(antoyo): find a more efficient implementation? let sixty_four = self.gcc_int(typ, 64); - let right_shift = self.gcc_lshr(value, sixty_four); + let right_shift = self.lshr(value, sixty_four); let high = self.gcc_int_cast(right_shift, self.u64_type); let low = self.gcc_int_cast(value, self.u64_type); @@ -998,7 +998,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { .new_local(None, array_type, "count_loading_zeroes_results"); let sixty_four = self.gcc_int(arg_type, 64); - let shift = self.gcc_lshr(arg, sixty_four); + let shift = self.lshr(arg, sixty_four); let high = self.gcc_int_cast(shift, self.u64_type); let low = self.gcc_int_cast(arg, self.u64_type); @@ -1073,7 +1073,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // TODO(antoyo): remove this if/when native 128-bit integers land in libgccjit if value_type.is_u128(self.cx) && !self.cx.supports_128bit_integers { let sixty_four = self.gcc_int(value_type, 64); - let right_shift = self.gcc_lshr(value, sixty_four); + let right_shift = self.lshr(value, sixty_four); let high = self.gcc_int_cast(right_shift, self.cx.ulonglong_type); let high = self.pop_count(high); let low = self.gcc_int_cast(value, self.cx.ulonglong_type); @@ -1196,12 +1196,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // Return `result_type`'s maximum or minimum value on overflow // NOTE: convert the type to unsigned to have an unsigned shift. let unsigned_type = result_type.to_unsigned(self.cx); - let shifted = self.gcc_lshr( + let shifted = self.lshr( self.gcc_int_cast(lhs, unsigned_type), self.gcc_int(unsigned_type, width as i64 - 1), ); let uint_max = self.gcc_not(self.gcc_int(unsigned_type, 0)); - let int_max = self.gcc_lshr(uint_max, self.gcc_int(unsigned_type, 1)); + let int_max = self.lshr(uint_max, self.gcc_int(unsigned_type, 1)); then_block.add_assignment( self.location, res, @@ -1267,12 +1267,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // Return `result_type`'s maximum or minimum value on overflow // NOTE: convert the type to unsigned to have an unsigned shift. let unsigned_type = result_type.to_unsigned(self.cx); - let shifted = self.gcc_lshr( + let shifted = self.lshr( self.gcc_int_cast(lhs, unsigned_type), self.gcc_int(unsigned_type, width as i64 - 1), ); let uint_max = self.gcc_not(self.gcc_int(unsigned_type, 0)); - let int_max = self.gcc_lshr(uint_max, self.gcc_int(unsigned_type, 1)); + let int_max = self.lshr(uint_max, self.gcc_int(unsigned_type, 1)); then_block.add_assignment( self.location, res, From f2c00cfb3196bdbeacfe5bc4ebbdae393faad4d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fractal=20Fir=28Micha=C5=82=20Kostrubiec=29?= Date: Thu, 14 Aug 2025 23:00:45 +0200 Subject: [PATCH 2/2] Update src/builder.rs Co-authored-by: antoyo --- src/builder.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/builder.rs b/src/builder.rs index 4dbd4f392aa..de0e39d5be5 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -40,11 +40,13 @@ use crate::type_of::LayoutGccExt; // TODO(antoyo) type Funclet = (); + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ShiftKind { Logical, Arithmetic, } + enum ExtremumOperation { Max, Min,