Skip to content

Commit 608d542

Browse files
committed
Reimplemented bitreverse intrinsics
1 parent addeecb commit 608d542

File tree

4 files changed

+249
-6
lines changed

4 files changed

+249
-6
lines changed

cilly/src/v2/builtins/math.rs

+239
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,243 @@ pub fn bitreverse_u128(asm: &mut Assembly, patcher: &mut MissingMethodPatcher) {
9292
pub fn math(asm: &mut Assembly, patcher: &mut MissingMethodPatcher) {
9393
ldexp(asm, patcher);
9494
ldexpf(asm, patcher);
95+
bitreverse_u32(asm, patcher);
96+
bitreverse_u64(asm, patcher);
97+
bitreverse_u128(asm, patcher);
9598
}
99+
100+
fn bitreverse_u32(asm: &mut Assembly, patcher: &mut MissingMethodPatcher) {
101+
let name = asm.alloc_string("bitreverse_u32");
102+
let generator = move |_, asm: &mut Assembly| {
103+
let curr = asm.alloc_node(CILNode::LdLoc(0));
104+
let mut shift = 16;
105+
let arg0 = asm.alloc_node(CILNode::LdArg(0));
106+
let mut trees = vec![asm.alloc_root(CILRoot::StLoc(0, arg0))];
107+
let mut i = 0;
108+
let masks = [
109+
0b11111111111111110000000000000000,
110+
0b11111111000000001111111100000000,
111+
0b11110000111100001111000011110000,
112+
0b11001100110011001100110011001100,
113+
0b10101010101010101010101010101010,
114+
];
115+
while shift > 0 {
116+
let mask = asm.alloc_node(Const::U32(masks[i]));
117+
let inv_mask = asm.alloc_node(Const::U32(!masks[i]));
118+
let masked = asm.alloc_node(CILNode::BinOp(curr, mask, BinOp::And));
119+
let inv_masked = asm.alloc_node(CILNode::BinOp(curr, inv_mask, BinOp::And));
120+
let shift_ammount = asm.alloc_node(Const::I32(shift));
121+
let masked_shifted =
122+
asm.alloc_node(CILNode::BinOp(masked, shift_ammount, BinOp::ShrUn));
123+
let inv_masked_shifted =
124+
asm.alloc_node(CILNode::BinOp(inv_masked, shift_ammount, BinOp::Shl));
125+
let curr_val = asm.alloc_node(CILNode::BinOp(
126+
masked_shifted,
127+
inv_masked_shifted,
128+
BinOp::Or,
129+
));
130+
trees.push(asm.alloc_root(CILRoot::StLoc(0, curr_val)));
131+
i += 1;
132+
shift /= 2;
133+
}
134+
trees.push(asm.alloc_root(CILRoot::Ret(curr)));
135+
MethodImpl::MethodBody {
136+
blocks: vec![BasicBlock::new(trees, 0, None)],
137+
locals: vec![(None, asm.alloc_type(Type::Int(Int::U32)))],
138+
}
139+
};
140+
patcher.insert(name, Box::new(generator));
141+
}
142+
fn bitreverse_u64(asm: &mut Assembly, patcher: &mut MissingMethodPatcher) {
143+
let name = asm.alloc_string("bitreverse_u64");
144+
let generator = move |_, asm: &mut Assembly| {
145+
let curr = asm.alloc_node(CILNode::LdLoc(0));
146+
let mut shift = 32;
147+
let arg0 = asm.alloc_node(CILNode::LdArg(0));
148+
let mut trees = vec![asm.alloc_root(CILRoot::StLoc(0, arg0))];
149+
let mut i = 0;
150+
let masks = [
151+
0b1111111111111111111111111111111100000000000000000000000000000000,
152+
0b1111111111111111000000000000000011111111111111110000000000000000,
153+
0b1111111100000000111111110000000011111111000000001111111100000000,
154+
0b1111000011110000111100001111000011110000111100001111000011110000,
155+
0b1100110011001100110011001100110011001100110011001100110011001100,
156+
0b1010101010101010101010101010101010101010101010101010101010101010,
157+
];
158+
while shift > 0 {
159+
let mask = asm.alloc_node(Const::U64(masks[i]));
160+
let inv_mask = asm.alloc_node(Const::U64(!masks[i]));
161+
let masked = asm.alloc_node(CILNode::BinOp(curr, mask, BinOp::And));
162+
let inv_masked = asm.alloc_node(CILNode::BinOp(curr, inv_mask, BinOp::And));
163+
let shift_ammount = asm.alloc_node(Const::I64(shift));
164+
let masked_shifted =
165+
asm.alloc_node(CILNode::BinOp(masked, shift_ammount, BinOp::ShrUn));
166+
let inv_masked_shifted =
167+
asm.alloc_node(CILNode::BinOp(inv_masked, shift_ammount, BinOp::Shl));
168+
let curr_val = asm.alloc_node(CILNode::BinOp(
169+
masked_shifted,
170+
inv_masked_shifted,
171+
BinOp::Or,
172+
));
173+
trees.push(asm.alloc_root(CILRoot::StLoc(0, curr_val)));
174+
i += 1;
175+
shift /= 2;
176+
}
177+
trees.push(asm.alloc_root(CILRoot::Ret(curr)));
178+
MethodImpl::MethodBody {
179+
blocks: vec![BasicBlock::new(trees, 0, None)],
180+
locals: vec![(None, asm.alloc_type(Type::Int(Int::U64)))],
181+
}
182+
};
183+
patcher.insert(name, Box::new(generator));
184+
}
185+
fn bitreverse_u128(asm: &mut Assembly, patcher: &mut MissingMethodPatcher) {
186+
let name = asm.alloc_string("bitreverse_u128");
187+
let generator = move |_, asm: &mut Assembly| {
188+
let u64_max = asm.alloc_node(Const::U64(u64::MAX));
189+
let u64_zero = asm.alloc_node(Const::U64(0));
190+
let u128_class = ClassRef::uint_128(asm);
191+
let u128_class = asm[u128_class].clone();
192+
let u128_ctor = u128_class.ctor(&[Type::Int(Int::U64), Type::Int(Int::U64)], asm);
193+
194+
let mut shift = 64;
195+
//let op_add = asm.alloc_string("op_Addition");
196+
let op_and = asm.alloc_string("op_BitwiseAnd");
197+
let and = u128_class.static_mref(
198+
&[Type::Int(Int::U128), Type::Int(Int::U128)],
199+
Type::Int(Int::U128),
200+
op_and,
201+
asm,
202+
);
203+
let op_or = asm.alloc_string("op_BitwiseOr");
204+
let or = u128_class.static_mref(
205+
&[Type::Int(Int::U128), Type::Int(Int::U128)],
206+
Type::Int(Int::U128),
207+
op_or,
208+
asm,
209+
);
210+
let op_lshift = asm.alloc_string("op_LeftShift");
211+
let lshift = u128_class.static_mref(
212+
&[Type::Int(Int::U128), Type::Int(Int::I32)],
213+
Type::Int(Int::U128),
214+
op_lshift,
215+
asm,
216+
);
217+
let op_rshift = asm.alloc_string("op_RightShift");
218+
let rshift = u128_class.static_mref(
219+
&[Type::Int(Int::U128), Type::Int(Int::I32)],
220+
Type::Int(Int::U128),
221+
op_rshift,
222+
asm,
223+
);
224+
let curr = asm.alloc_node(CILNode::LdLoc(0));
225+
let arg0 = asm.alloc_node(CILNode::LdArg(0));
226+
let mut trees = vec![asm.alloc_root(CILRoot::StLoc(0, arg0))];
227+
let mut i = 0;
228+
let masks = [
229+
0b11111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000,
230+
0b11111111111111111111111111111111000000000000000000000000000000001111111111111111111111111111111100000000000000000000000000000000,
231+
0b11111111111111110000000000000000111111111111111100000000000000001111111111111111000000000000000011111111111111110000000000000000,
232+
0b11111111000000001111111100000000111111110000000011111111000000001111111100000000111111110000000011111111000000001111111100000000,
233+
0b11110000111100001111000011110000111100001111000011110000111100001111000011110000111100001111000011110000111100001111000011110000,
234+
0b11001100110011001100110011001100110011001100110011001100110011001100110011001100110011001100110011001100110011001100110011001100,
235+
0b10101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010_u128,
236+
];
237+
while shift > 0 {
238+
let curr_mask = masks[i];
239+
let mask = CILNode::Call(Box::new((
240+
u128_ctor,
241+
([
242+
asm.alloc_node(Const::U64((curr_mask >> 64) as u64)),
243+
asm.alloc_node(Const::U64(curr_mask as u64)),
244+
])
245+
.into(),
246+
)));
247+
let mask = asm.alloc_node(mask);
248+
let curr_mask = !masks[i];
249+
let inv_mask = CILNode::Call(Box::new((
250+
u128_ctor,
251+
([
252+
asm.alloc_node(Const::U64((curr_mask >> 64) as u64)),
253+
asm.alloc_node(Const::U64(curr_mask as u64)),
254+
])
255+
.into(),
256+
)));
257+
let inv_mask = asm.alloc_node(inv_mask);
258+
let masked = asm.alloc_node(CILNode::Call(Box::new((and, [curr, mask].into()))));
259+
let inv_masked =
260+
asm.alloc_node(CILNode::Call(Box::new((and, [curr, inv_mask].into()))));
261+
let shift_ammount = asm.alloc_node(Const::I64(shift));
262+
let masked_shifted = asm.alloc_node(CILNode::Call(Box::new((
263+
rshift,
264+
[masked, shift_ammount].into(),
265+
))));
266+
let inv_masked_shifted = asm.alloc_node(CILNode::Call(Box::new((
267+
lshift,
268+
[inv_masked, shift_ammount].into(),
269+
))));
270+
271+
let curr_val = asm.alloc_node(CILNode::Call(Box::new((
272+
or,
273+
[masked_shifted, inv_masked_shifted].into(),
274+
))));
275+
trees.push(asm.alloc_root(CILRoot::StLoc(0, curr_val)));
276+
i += 1;
277+
shift /= 2;
278+
}
279+
trees.push(asm.alloc_root(CILRoot::Ret(curr)));
280+
MethodImpl::MethodBody {
281+
blocks: vec![BasicBlock::new(trees, 0, None)],
282+
locals: vec![(None, asm.alloc_type(Type::Int(Int::U128)))],
283+
}
284+
};
285+
patcher.insert(name, Box::new(generator));
286+
}
287+
/*
288+
fn bitreverse_u128(asm: &mut Assembly, patcher: &mut MissingMethodPatcher) {
289+
let name = asm.alloc_string("bitreverse_u64");
290+
let generator = move |_, asm: &mut Assembly| {
291+
let u64_max = asm.alloc_node(Const::U64(u64::MAX));
292+
let u64_zero = asm.alloc_node(Const::U64(0));
293+
let u128_class = ClassRef::uint_128(asm);
294+
let u128_class = asm[u128_class].clone();
295+
let u128_ctor = u128_class.ctor(&[Type::Int(Int::U64), Type::Int(Int::U64)], asm);
296+
let mask = asm.alloc_node(CILNode::Call(Box::new((
297+
u128_ctor,
298+
([u64_max, u64_zero]).into(),
299+
))));
300+
let inv_mask = asm.alloc_node(CILNode::Call(Box::new((
301+
u128_ctor,
302+
([u64_zero, u64_max]).into(),
303+
))));
304+
let mut curr = asm.alloc_node(CILNode::LdArg(0));
305+
let mut shift = 32;
306+
let op_add = asm.alloc_string("op_Addition");
307+
let op_and = asm.alloc_string("op_BitwiseAnd");
308+
let op_or = asm.alloc_string("op_BitwiseOr");
309+
let op_lshift = asm.alloc_string("op_LeftShift");
310+
let op_rshift = asm.alloc_string("op_RightShift");
311+
while shift > 0 {
312+
let masked = asm.alloc_node(CILNode::BinOp(curr, mask, BinOp::And));
313+
let inv_masked = asm.alloc_node(CILNode::BinOp(curr, inv_mask, BinOp::And));
314+
let shift_ammount = asm.alloc_node(Const::I64(shift));
315+
let masked_shifted =
316+
asm.alloc_node(CILNode::BinOp(masked, shift_ammount, BinOp::ShrUn));
317+
let inv_masked_shifted =
318+
asm.alloc_node(CILNode::BinOp(inv_masked, shift_ammount, BinOp::Shl));
319+
curr = asm.alloc_node(CILNode::BinOp(
320+
masked_shifted,
321+
inv_masked_shifted,
322+
BinOp::Or,
323+
));
324+
shift /= 2;
325+
}
326+
let ret = asm.alloc_root(CILRoot::Ret(curr));
327+
MethodImpl::MethodBody {
328+
blocks: vec![BasicBlock::new(vec![ret], 0, None)],
329+
locals: vec![],
330+
}
331+
};
332+
patcher.insert(name, Box::new(generator));
333+
}
334+
*/

cilly/src/v2/opt/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,10 @@ impl BasicBlock {
281281
if cache.has_side_effects(tree, asm) {
282282
break 'm;
283283
}
284+
// Check that the tree is not too big
285+
if CILIter::new(asm.get_node(tree).clone(), asm).count() > 16 {
286+
break 'm;
287+
}
284288
// Check that it does not depend on itself
285289
if CILIter::new(asm.get_node(tree).clone(), asm)
286290
.any(|node| node == CILIterElem::Node(CILNode::LdLoc(loc)))

src/terminator/intrinsics/ints.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ fn bitreverse_u16(ushort: CILNode) -> CILNode {
447447
pub fn bitreverse_int(val: CILNode, int: Int, asm: &mut cilly::v2::Assembly) -> CILNode {
448448
let mref = MethodRef::new(
449449
*asm.main_module(),
450-
asm.alloc_string(format!("bitreverse{}", int.name())),
450+
asm.alloc_string(format!("bitreverse_{}", int.as_unsigned().name())),
451451
asm.sig([Type::Int(int.as_unsigned())], Type::Int(int.as_unsigned())),
452452
MethodKind::Static,
453453
vec![].into(),

test/arthm/num_test.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,6 @@ fn main() {
130130
n = (n >> 16) | (n << 16);
131131
n
132132
}
133-
#[cfg(not(debug_assertions))]
134-
for b in 0..u16::MAX {
135-
let b = b as u128 + b as u128 * (u64::MAX as u128);
136-
test_eq!(bitreverse_u128(b), core::intrinsics::bitreverse(b));
137-
}
138133

139134
for b in 0..u16::MAX {
140135
let b = b as u64 + b as u64 * (u32::MAX as u64);
@@ -145,6 +140,11 @@ fn main() {
145140
test_eq!(bitreverse_u32(b), core::intrinsics::bitreverse(b));
146141
}
147142
#[cfg(not(debug_assertions))]
143+
for b in 0..u16::MAX {
144+
let b = b as u128 + b as u128 * (u64::MAX as u128);
145+
test_eq!(bitreverse_u128(b), core::intrinsics::bitreverse(b));
146+
}
147+
#[cfg(not(debug_assertions))]
148148
for b in 0..u16::MAX {
149149
let b = b as i128 + b as i128 * (u64::MAX as i128);
150150
test_eq!(

0 commit comments

Comments
 (0)