Skip to content

Commit e10dd0a

Browse files
authored
Merge pull request #19 from antoyo/fix-ctz
Fix count trailing zeroes intrinsic on 128-bit integers
2 parents a88b648 + 1d5b8be commit e10dd0a

File tree

2 files changed

+87
-44
lines changed

2 files changed

+87
-44
lines changed

gcc-test-backend/src/main.rs

Lines changed: 49 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -131,28 +131,6 @@ fn main() {
131131
);*/
132132
*/
133133

134-
assert_eq!(NonZeroU8::new(1).unwrap().leading_zeros(), 7);
135-
assert_eq!(NonZeroI8::new(1).unwrap().leading_zeros(), 7);
136-
assert_eq!(NonZeroU16::new(1).unwrap().leading_zeros(), 15);
137-
assert_eq!(NonZeroI16::new(1).unwrap().leading_zeros(), 15);
138-
assert_eq!(NonZeroU32::new(1).unwrap().leading_zeros(), 31);
139-
assert_eq!(NonZeroI32::new(1).unwrap().leading_zeros(), 31);
140-
assert_eq!(NonZeroU64::new(1).unwrap().leading_zeros(), 63);
141-
assert_eq!(NonZeroI64::new(1).unwrap().leading_zeros(), 63);
142-
assert_eq!(NonZeroU128::new(1).unwrap().leading_zeros(), 127);
143-
assert_eq!(NonZeroI128::new(1).unwrap().leading_zeros(), 127);
144-
assert_eq!(NonZeroUsize::new(1).unwrap().leading_zeros(), usize::BITS - 1);
145-
assert_eq!(NonZeroIsize::new(1).unwrap().leading_zeros(), usize::BITS - 1);
146-
147-
assert_eq!(NonZeroU8::new(u8::MAX >> 2).unwrap().leading_zeros(), 2);
148-
assert_eq!(NonZeroI8::new((u8::MAX >> 2) as i8).unwrap().leading_zeros(), 2);
149-
assert_eq!(NonZeroU16::new(u16::MAX >> 2).unwrap().leading_zeros(), 2);
150-
assert_eq!(NonZeroI16::new((u16::MAX >> 2) as i16).unwrap().leading_zeros(), 2);
151-
assert_eq!(NonZeroU32::new(u32::MAX >> 2).unwrap().leading_zeros(), 2);
152-
assert_eq!(NonZeroI32::new((u32::MAX >> 2) as i32).unwrap().leading_zeros(), 2);
153-
assert_eq!(NonZeroU64::new(u64::MAX >> 2).unwrap().leading_zeros(), 2);
154-
assert_eq!(NonZeroI64::new((u64::MAX >> 2) as i64).unwrap().leading_zeros(), 2);
155-
156134
/*
157135
//let mut num = u128::MAX >> 20;
158136
//let mut num = u128::MAX;
@@ -177,24 +155,53 @@ fn main() {
177155
}
178156
println!();
179157
*/
180-
assert_eq!(NonZeroU128::new(u128::MAX >> 2).unwrap().leading_zeros(), 2);
181-
assert_eq!(NonZeroI128::new((u128::MAX >> 2) as i128).unwrap().leading_zeros(), 2);
182-
assert_eq!(NonZeroUsize::new(usize::MAX >> 2).unwrap().leading_zeros(), 2);
183-
assert_eq!(NonZeroIsize::new((usize::MAX >> 2) as isize).unwrap().leading_zeros(), 2);
184-
185-
assert_eq!(NonZeroU8::new(u8::MAX).unwrap().leading_zeros(), 0);
186-
assert_eq!(NonZeroI8::new(-1i8).unwrap().leading_zeros(), 0);
187-
assert_eq!(NonZeroU16::new(u16::MAX).unwrap().leading_zeros(), 0);
188-
assert_eq!(NonZeroI16::new(-1i16).unwrap().leading_zeros(), 0);
189-
assert_eq!(NonZeroU32::new(u32::MAX).unwrap().leading_zeros(), 0);
190-
assert_eq!(NonZeroI32::new(-1i32).unwrap().leading_zeros(), 0);
191-
assert_eq!(NonZeroU64::new(u64::MAX).unwrap().leading_zeros(), 0);
192-
assert_eq!(NonZeroI64::new(-1i64).unwrap().leading_zeros(), 0);
193-
assert_eq!(NonZeroU128::new(u128::MAX).unwrap().leading_zeros(), 0);
194-
assert_eq!(NonZeroI128::new(-1i128).unwrap().leading_zeros(), 0);
195-
assert_eq!(NonZeroUsize::new(usize::MAX).unwrap().leading_zeros(), 0);
196-
assert_eq!(NonZeroIsize::new(-1isize).unwrap().leading_zeros(), 0);
197-
198-
const LEADING_ZEROS: u32 = NonZeroU16::new(1).unwrap().leading_zeros();
199-
assert_eq!(LEADING_ZEROS, 15);
158+
159+
assert_eq!(NonZeroU8::new(1).unwrap().trailing_zeros(), 0);
160+
assert_eq!(NonZeroI8::new(1).unwrap().trailing_zeros(), 0);
161+
assert_eq!(NonZeroU16::new(1).unwrap().trailing_zeros(), 0);
162+
assert_eq!(NonZeroI16::new(1).unwrap().trailing_zeros(), 0);
163+
assert_eq!(NonZeroU32::new(1).unwrap().trailing_zeros(), 0);
164+
assert_eq!(NonZeroI32::new(1).unwrap().trailing_zeros(), 0);
165+
assert_eq!(NonZeroU64::new(1).unwrap().trailing_zeros(), 0);
166+
assert_eq!(NonZeroI64::new(1).unwrap().trailing_zeros(), 0);
167+
assert_eq!(NonZeroU128::new(1).unwrap().trailing_zeros(), 0);
168+
assert_eq!(NonZeroI128::new(1).unwrap().trailing_zeros(), 0);
169+
assert_eq!(NonZeroUsize::new(1).unwrap().trailing_zeros(), 0);
170+
assert_eq!(NonZeroIsize::new(1).unwrap().trailing_zeros(), 0);
171+
172+
assert_eq!(NonZeroU8::new(1 << 2).unwrap().trailing_zeros(), 2);
173+
assert_eq!(NonZeroI8::new(1 << 2).unwrap().trailing_zeros(), 2);
174+
assert_eq!(NonZeroU16::new(1 << 2).unwrap().trailing_zeros(), 2);
175+
assert_eq!(NonZeroI16::new(1 << 2).unwrap().trailing_zeros(), 2);
176+
assert_eq!(NonZeroU32::new(1 << 2).unwrap().trailing_zeros(), 2);
177+
assert_eq!(NonZeroI32::new(1 << 2).unwrap().trailing_zeros(), 2);
178+
assert_eq!(NonZeroU64::new(1 << 2).unwrap().trailing_zeros(), 2);
179+
assert_eq!(NonZeroI64::new(1 << 2).unwrap().trailing_zeros(), 2);
180+
assert_eq!(NonZeroU128::new(1 << 2).unwrap().trailing_zeros(), 2);
181+
assert_eq!(NonZeroI128::new(1 << 2).unwrap().trailing_zeros(), 2);
182+
assert_eq!(NonZeroUsize::new(1 << 2).unwrap().trailing_zeros(), 2);
183+
assert_eq!(NonZeroIsize::new(1 << 2).unwrap().trailing_zeros(), 2);
184+
185+
assert_eq!(NonZeroU8::new(1 << 7).unwrap().trailing_zeros(), 7);
186+
assert_eq!(NonZeroI8::new(1 << 7).unwrap().trailing_zeros(), 7);
187+
assert_eq!(NonZeroU16::new(1 << 15).unwrap().trailing_zeros(), 15);
188+
assert_eq!(NonZeroI16::new(1 << 15).unwrap().trailing_zeros(), 15);
189+
assert_eq!(NonZeroU32::new(1 << 31).unwrap().trailing_zeros(), 31);
190+
assert_eq!(NonZeroI32::new(1 << 31).unwrap().trailing_zeros(), 31);
191+
assert_eq!(NonZeroU64::new(1 << 63).unwrap().trailing_zeros(), 63);
192+
assert_eq!(NonZeroI64::new(1 << 63).unwrap().trailing_zeros(), 63);
193+
assert_eq!(NonZeroU128::new(1 << 127).unwrap().trailing_zeros(), 127);
194+
assert_eq!(NonZeroI128::new(1 << 127).unwrap().trailing_zeros(), 127);
195+
196+
assert_eq!(
197+
NonZeroUsize::new(1 << (usize::BITS - 1)).unwrap().trailing_zeros(),
198+
usize::BITS - 1
199+
);
200+
assert_eq!(
201+
NonZeroIsize::new(1 << (usize::BITS - 1)).unwrap().trailing_zeros(),
202+
usize::BITS - 1
203+
);
204+
205+
const TRAILING_ZEROS: u32 = NonZeroU16::new(1 << 2).unwrap().trailing_zeros();
206+
assert_eq!(TRAILING_ZEROS, 2);
200207
}

src/intrinsic.rs

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -817,8 +817,44 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
817817
("__builtin_ctzll", self.cx.ulonglong_type)
818818
}
819819
else if arg_type.is_u128(&self.cx) {
820-
// FIXME: actually implement the real function for u128.
821-
("__builtin_ctzll", self.cx.ulonglong_type)
820+
// Adapted from the algorithm to count leading zeroes from: https://stackoverflow.com/a/28433850/389119
821+
let array_type = self.context.new_array_type(None, arg_type, 3);
822+
let result = self.current_func()
823+
.new_local(None, array_type, "count_loading_zeroes_results");
824+
825+
let sixty_four = self.context.new_rvalue_from_long(arg_type, 64);
826+
let high = self.context.new_cast(None, arg >> sixty_four, self.u64_type);
827+
let low = self.context.new_cast(None, arg, self.u64_type);
828+
829+
let zero = self.context.new_rvalue_zero(self.usize_type);
830+
let one = self.context.new_rvalue_one(self.usize_type);
831+
let two = self.context.new_rvalue_from_long(self.usize_type, 2);
832+
833+
let ctzll = self.context.get_builtin_function("__builtin_ctzll");
834+
835+
let first_elem = self.context.new_array_access(None, result, zero);
836+
let first_value = self.context.new_cast(None, self.context.new_call(None, ctzll, &[low]), arg_type);
837+
self.llbb()
838+
.add_assignment(None, first_elem, first_value);
839+
840+
let second_elem = self.context.new_array_access(None, result, one);
841+
let second_value = self.context.new_cast(None, self.context.new_call(None, ctzll, &[high]), arg_type) + sixty_four;
842+
self.llbb()
843+
.add_assignment(None, second_elem, second_value);
844+
845+
let third_elem = self.context.new_array_access(None, result, two);
846+
let third_value = self.context.new_rvalue_from_long(arg_type, 128);
847+
self.llbb()
848+
.add_assignment(None, third_elem, third_value);
849+
850+
let not_low = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, low);
851+
let not_high = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, high);
852+
let not_low_and_not_high = not_low & not_high;
853+
let index = not_low + not_low_and_not_high;
854+
855+
let res = self.context.new_array_access(None, result, index);
856+
857+
return self.context.new_cast(None, res, arg_type);
822858
}
823859
else {
824860
unimplemented!("count_trailing_zeroes for {:?}", arg_type);

0 commit comments

Comments
 (0)