1
Fork 0

Fix/count trailing zeroes (#95)

* Fix count trailing zeroes
* Fix pop count
* Fix bit reverse
This commit is contained in:
antoyo 2021-09-27 20:35:45 -04:00 committed by GitHub
parent 63608ac6b3
commit 11c2023ef5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 196 additions and 142 deletions

View file

@ -302,6 +302,7 @@ pub trait SignType<'gcc, 'tcx> {
fn is_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; fn is_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
fn is_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; fn is_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
fn to_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; fn to_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
fn to_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
} }
impl<'gcc, 'tcx> SignType<'gcc, 'tcx> for Type<'gcc> { impl<'gcc, 'tcx> SignType<'gcc, 'tcx> for Type<'gcc> {
@ -333,6 +334,27 @@ impl<'gcc, 'tcx> SignType<'gcc, 'tcx> for Type<'gcc> {
self.clone() self.clone()
} }
} }
fn to_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
if self.is_i8(cx) {
cx.u8_type
}
else if self.is_i16(cx) {
cx.u16_type
}
else if self.is_i32(cx) {
cx.u32_type
}
else if self.is_i64(cx) {
cx.u64_type
}
else if self.is_i128(cx) {
cx.u128_type
}
else {
self.clone()
}
}
} }
pub trait TypeReflection<'gcc, 'tcx> { pub trait TypeReflection<'gcc, 'tcx> {

View file

@ -18,7 +18,7 @@ use rustc_target::spec::PanicStrategy;
use crate::abi::GccType; use crate::abi::GccType;
use crate::builder::Builder; use crate::builder::Builder;
use crate::common::TypeReflection; use crate::common::{SignType, TypeReflection};
use crate::context::CodegenCx; use crate::context::CodegenCx;
use crate::type_of::LayoutGccExt; use crate::type_of::LayoutGccExt;
use crate::intrinsic::simd::generic_simd_intrinsic; use crate::intrinsic::simd::generic_simd_intrinsic;
@ -520,8 +520,19 @@ fn int_type_width_signed<'gcc, 'tcx>(ty: Ty<'tcx>, cx: &CodegenCx<'gcc, 'tcx>) -
impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
fn bit_reverse(&mut self, width: u64, value: RValue<'gcc>) -> RValue<'gcc> { fn bit_reverse(&mut self, width: u64, value: RValue<'gcc>) -> RValue<'gcc> {
let typ = value.get_type(); let result_type = value.get_type();
let typ = result_type.to_unsigned(self.cx);
let value =
if result_type.is_signed(self.cx) {
self.context.new_bitcast(None, value, typ)
}
else {
value
};
let context = &self.cx.context; let context = &self.cx.context;
let result =
match width { match width {
8 => { 8 => {
// First step. // First step.
@ -676,7 +687,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
_ => { _ => {
panic!("cannot bit reverse with width = {}", width); panic!("cannot bit reverse with width = {}", width);
}, },
} };
self.context.new_bitcast(None, result, result_type)
} }
fn count_leading_zeroes(&self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { fn count_leading_zeroes(&self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> {
@ -746,6 +759,15 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
} }
fn count_trailing_zeroes(&self, _width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { fn count_trailing_zeroes(&self, _width: u64, arg: RValue<'gcc>) -> RValue<'gcc> {
let result_type = arg.get_type();
let arg =
if result_type.is_signed(self.cx) {
let new_type = result_type.to_unsigned(self.cx);
self.context.new_bitcast(None, arg, new_type)
}
else {
arg
};
let arg_type = arg.get_type(); let arg_type = arg.get_type();
let (count_trailing_zeroes, expected_type) = let (count_trailing_zeroes, expected_type) =
if arg_type.is_uchar(&self.cx) || arg_type.is_ushort(&self.cx) || arg_type.is_uint(&self.cx) { if arg_type.is_uchar(&self.cx) || arg_type.is_ushort(&self.cx) || arg_type.is_uint(&self.cx) {
@ -796,7 +818,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
let res = self.context.new_array_access(None, result, index); let res = self.context.new_array_access(None, result, index);
return self.context.new_cast(None, res, arg_type); return self.context.new_bitcast(None, res, result_type);
} }
else { else {
unimplemented!("count_trailing_zeroes for {:?}", arg_type); unimplemented!("count_trailing_zeroes for {:?}", arg_type);
@ -810,7 +832,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
arg arg
}; };
let res = self.context.new_call(None, count_trailing_zeroes, &[arg]); let res = self.context.new_call(None, count_trailing_zeroes, &[arg]);
self.context.new_cast(None, res, arg_type) self.context.new_bitcast(None, res, result_type)
} }
fn int_width(&self, typ: Type<'gcc>) -> i64 { fn int_width(&self, typ: Type<'gcc>) -> i64 {
@ -819,7 +841,16 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
fn pop_count(&self, value: RValue<'gcc>) -> RValue<'gcc> { fn pop_count(&self, value: RValue<'gcc>) -> RValue<'gcc> {
// TODO(antoyo): use the optimized version with fewer operations. // TODO(antoyo): use the optimized version with fewer operations.
let value_type = value.get_type(); let result_type = value.get_type();
let value_type = result_type.to_unsigned(self.cx);
let value =
if result_type.is_signed(self.cx) {
self.context.new_bitcast(None, value, value_type)
}
else {
value
};
if value_type.is_u128(&self.cx) { if value_type.is_u128(&self.cx) {
// TODO(antoyo): implement in the normal algorithm below to have a more efficient // TODO(antoyo): implement in the normal algorithm below to have a more efficient
@ -830,7 +861,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
let high = self.context.new_call(None, popcount, &[high]); let high = self.context.new_call(None, popcount, &[high]);
let low = self.context.new_cast(None, value, self.cx.ulonglong_type); let low = self.context.new_cast(None, value, self.cx.ulonglong_type);
let low = self.context.new_call(None, popcount, &[low]); let low = self.context.new_call(None, popcount, &[low]);
return high + low; let res = high + low;
return self.context.new_bitcast(None, res, result_type);
} }
// First step. // First step.
@ -855,7 +887,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
let value = left + right; let value = left + right;
if value_type.is_u8(&self.cx) { if value_type.is_u8(&self.cx) {
return value; return self.context.new_bitcast(None, value, result_type);
} }
// Fourth step. // Fourth step.
@ -866,7 +898,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
let value = left + right; let value = left + right;
if value_type.is_u16(&self.cx) { if value_type.is_u16(&self.cx) {
return value; return self.context.new_bitcast(None, value, result_type);
} }
// Fifth step. // Fifth step.
@ -877,7 +909,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
let value = left + right; let value = left + right;
if value_type.is_u32(&self.cx) { if value_type.is_u32(&self.cx) {
return value; return self.context.new_bitcast(None, value, result_type);
} }
// Sixth step. // Sixth step.
@ -887,7 +919,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
let right = shifted & mask; let right = shifted & mask;
let value = left + right; let value = left + right;
value self.context.new_bitcast(None, value, result_type)
} }
// Algorithm from: https://blog.regehr.org/archives/1063 // Algorithm from: https://blog.regehr.org/archives/1063