Skip to content

Commit

Permalink
Added new intrinsics, added support for small atomics
Browse files Browse the repository at this point in the history
  • Loading branch information
FractalFir committed Jan 5, 2025
1 parent 075b91a commit 6d807b5
Show file tree
Hide file tree
Showing 14 changed files with 525 additions and 269 deletions.
98 changes: 74 additions & 24 deletions cilly/src/v2/builtins/atomics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,25 @@ pub fn emulate_uint8_cmp_xchng(asm: &mut Assembly, patcher: &mut MissingMethodPa
generate_atomic(
asm,
patcher,
"cmpxchng",
"cmpxchng8",
|asm, prev, arg, _| {
// 1st, mask the previous value
let prev_mask = asm.alloc_node(Const::I32(0x00FF_FFFF));
let prev_mask = asm.alloc_node(Const::I32(0xFFFF_FF00_u32 as i32));
let prev = asm.alloc_node(CILNode::BinOp(prev, prev_mask, BinOp::And));
// 2nd. Shift the byte into the least siginificant position(by 24 bytes)
let shift_ammount = asm.alloc_node(Const::I32(24));
let arg = asm.alloc_node(CILNode::BinOp(arg, shift_ammount, BinOp::Shl));
// Assemble those into a new value for the target memory.

asm.alloc_node(CILNode::BinOp(prev, arg, BinOp::Or))
},
Int::I32,
);
generate_atomic(
asm,
patcher,
"cmpxchng16",
|asm, prev, arg, _| {
// 1st, mask the previous value
let prev_mask = asm.alloc_node(Const::I32(0xFFFF_0000_u32 as i32));
let prev = asm.alloc_node(CILNode::BinOp(prev, prev_mask, BinOp::And));

asm.alloc_node(CILNode::BinOp(prev, arg, BinOp::Or))
},
Int::I32,
Expand Down Expand Up @@ -54,6 +64,58 @@ pub fn emulate_uint8_cmp_xchng(asm: &mut Assembly, patcher: &mut MissingMethodPa
};
patcher.insert(name, Box::new(generator));
}
pub fn compare_exchange(asm:&mut Assembly,int:Int,addr:NodeIdx, value:NodeIdx, comaprand:NodeIdx)->NodeIdx{
match int.size().unwrap_or(8){
// u16 is buggy :(. TODO: fix it.
1 | 2=>{
let compare_exchange = asm.alloc_string("atomic_cmpxchng8_i32");

let i32 = Type::Int(int);
let i32_ref = asm.nref(i32);
let cmpxchng_sig = asm.sig([i32_ref, i32, i32], i32);
let main_mod = asm.main_module();
let mref = asm.alloc_methodref(MethodRef::new(
*main_mod,
compare_exchange,
cmpxchng_sig,
MethodKind::Static,
vec![].into(),
));
let cast_value = asm.alloc_node(CILNode::IntCast { input: value, target: Int::I32, extend: crate::cilnode::ExtendKind::ZeroExtend });
let cast_comparand = asm.alloc_node(CILNode::IntCast { input: comaprand, target: Int::I32, extend: crate::cilnode::ExtendKind::ZeroExtend });
let addr = asm.alloc_node(CILNode::RefToPtr(addr));
let i32_tidx = asm.alloc_type(Type::Int(Int::I32));
let addr = asm.alloc_node(CILNode::PtrCast(addr, Box::new(crate::cilnode::PtrCastRes::Ptr(i32_tidx))));
let res = asm.alloc_node(CILNode::Call(Box::new((
mref,
Box::new([addr, cast_value, cast_comparand]),
))));
asm.alloc_node(CILNode::IntCast { input: res, target: int, extend: crate::cilnode::ExtendKind::ZeroExtend })
}
4..=8 => {
let compare_exchange = asm.alloc_string("CompareExchange");

let tpe = Type::Int(int);
let tref = asm.nref(tpe);
let cmpxchng_sig = asm.sig([tref, tpe, tpe], tpe);
let interlocked = ClassRef::interlocked(asm);
let mref = asm.alloc_methodref(MethodRef::new(
interlocked,
compare_exchange,
cmpxchng_sig,
MethodKind::Static,
vec![].into(),
));

asm.alloc_node(CILNode::Call(Box::new((
mref,
Box::new([addr, value, comaprand]),
))))
}
_=>todo!("Can't cmpxchng {int:?}")
}

}
pub fn generate_atomic(
asm: &mut Assembly,
patcher: &mut MissingMethodPatcher,
Expand All @@ -72,25 +134,9 @@ pub fn generate_atomic(

// The OP of this atomic
let op = op(asm, ldloc_0, ldarg_1, int);
let call = compare_exchange(asm, int, ldarg_0, op, ldloc_0);

let tpe = Type::Int(int);
let tref = asm.nref(tpe);

let cmpxchng_sig = asm.sig([tref, tpe, tpe], tpe);
let interlocked = ClassRef::interlocked(asm);

let compare_exchange = asm.alloc_string("CompareExchange");
let mref = asm.alloc_methodref(MethodRef::new(
interlocked,
compare_exchange,
cmpxchng_sig,
MethodKind::Static,
vec![].into(),
));
let call = asm.alloc_node(CILNode::Call(Box::new((
mref,
Box::new([ldarg_0, op, ldloc_0]),
))));
let zero = asm.alloc_node(int.zero());
let entry_block = vec![
asm.alloc_root(CILRoot::StLoc(1, zero)),
Expand Down Expand Up @@ -124,7 +170,11 @@ pub fn generate_atomic_for_ints(
op_name: &str,
op: impl Fn(&mut Assembly, NodeIdx, NodeIdx, Int) -> NodeIdx + 'static + Clone,
) {
const ATOMIC_INTS: [Int; 6] = [
const ATOMIC_INTS: [Int; 10] = [
Int::U8,
Int::I8,
Int::U16,
Int::I16,
Int::U32,
Int::U64,
Int::USize,
Expand Down
22 changes: 22 additions & 0 deletions cilly/src/v2/cst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,28 @@ impl Const {
Const::Null(tpe) => Type::ClassRef(*tpe),
}
}

pub(crate) fn is_zero(&self) -> bool {
match self {
Const::I8(val) => *val == 0,
Const::I16(val) => *val == 0,
Const::I32(val) => *val == 0,
Const::I64(val) => *val == 0,
Const::I128(val) => *val == 0,
Const::ISize(val) => *val == 0,
Const::U8(val) => *val == 0,
Const::U16(val) => *val == 0,
Const::U32(val) => *val == 0,
Const::U64(val) => *val == 0,
Const::U128(val) => *val == 0,
Const::USize(val) => *val == 0,
Const::PlatformString(_) => false,
Const::Bool(_) => false,
Const::F32(val) => **val == 0.0,
Const::F64(val) => **val == 0.0,
Const::Null(_) => true,
}
}
}

impl From<Const> for CILNode {
Expand Down
25 changes: 20 additions & 5 deletions cilly/src/v2/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ impl MethodDef {
return;
};
// Check if the entry block does not jump anywhere(no targets) and has no handler - if so, only keep it.
if blocks[0].targets(asm).count() == 0 && blocks[0].handler().is_none(){
if blocks[0].targets(asm).count() == 0 && blocks[0].handler().is_none() {
let entry = blocks[0].clone();
*self.implementation_mut().blocks_mut().unwrap() = vec![entry];
return;
Expand All @@ -465,19 +465,34 @@ impl MethodDef {
return;
}
// If handlers jump to normal blocks, do not GC.
if blocks.iter().flat_map(|block|block.handler()).flatten().flat_map(|block|block.roots()).any(|root|matches!(asm[*root],CILRoot::ExitSpecialRegion { target: _, source: _ })){
if blocks
.iter()
.flat_map(|block| block.handler())
.flatten()
.flat_map(|block| block.roots())
.any(|root| {
matches!(
asm[*root],
CILRoot::ExitSpecialRegion {
target: _,
source: _
}
)
})
{
return;
}
//let blocks_copy = blocks.clone();
self.implementation_mut()
.blocks_mut()
.unwrap()
.retain(|block| alive.contains(&block.block_id()));

}

pub(crate) fn locals(&self) -> Option<&[LocalDef]> {
let MethodImpl::MethodBody { blocks:_, locals } = self.implementation() else {return None;};
let MethodImpl::MethodBody { blocks: _, locals } = self.implementation() else {
return None;
};
Some(locals)
}
}
Expand Down
30 changes: 15 additions & 15 deletions cilly/src/v2/opt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,6 @@ impl MethodDef {
cache: &mut SideEffectInfoCache,
fuel: &mut OptFuel,
) {

self.implementation_mut().propagate_locals(asm, cache, fuel);
self.implementation_mut()
.remove_dead_writes(asm, cache, fuel);
Expand All @@ -515,8 +514,6 @@ impl MethodDef {
self.implementation_mut().remove_duplicate_sfi(asm);
}
self.remove_useless_handlers(asm, fuel, cache);


}
fn remove_useless_handlers(
&mut self,
Expand All @@ -534,17 +531,17 @@ impl MethodDef {
.map(|block| (block.block_id(), block.clone()))
.collect();
for block in blocks.iter_mut() {
if let CILRoot::Branch(info) =
/*if let CILRoot::Branch(info) =
&asm[*block.roots().last().expect("Blocks can't be empty")]
{
/*let (target, _, None) = info.as_ref() else {continue;};
let (target, _, None) = info.as_ref() else {continue;};
// Ret or throw
if !has_targets[target] {
if !has_targets[target] && blocks_copy[target].roots().len() < 20 {
let roots = block.roots_mut();
roots.pop();
roots.extend(blocks_copy[target].roots());
}*/
}
}
}*/
let Some(handler) = block.handler() else {
continue;
};
Expand Down Expand Up @@ -637,12 +634,13 @@ impl MethodDef {
cache: &mut SideEffectInfoCache,
asm: &mut Assembly,
) {
if self.implementation().blocks().is_none(){
if self.implementation().blocks().is_none() {
return;
}
// TODO: this is a hack, which makes root inlining optimizations not consume fuel.
let fuel = std::sync::Mutex::new(&mut *fuel);
let locals = self.locals().map(|locs|locs.to_vec()).unwrap();
let locals = self.locals().map(|locs| locs.to_vec()).unwrap();
let mut cache2 = SideEffectInfoCache::default();
self.map_roots(
asm,
&mut |root, asm| {
Expand All @@ -662,11 +660,13 @@ impl MethodDef {
CILRoot::Call(info) => {
inline_trivial_call_root(info.0, &info.1, *root_fuel, asm)
}

CILRoot::StInd(ref info) => match asm.get_node(info.0) {
CILNode::LdLocA(loc) if asm[locals[*loc as usize].1] == info.2 => CILRoot::StLoc(*loc,info.1),
CILNode::LdLocA(loc) if asm[locals[*loc as usize].1] == info.2 => {
CILRoot::StLoc(*loc, info.1)
}
_ => root,
}
},
CILRoot::SetField(info) => {
let (field, mut addr, val) = info.as_ref();
if let CILNode::RefToPtr(inner) = asm[addr] {
Expand Down Expand Up @@ -956,7 +956,7 @@ impl MethodDef {
},
&mut |node, asm| {
let mut fuel = fuel.lock().unwrap();
opt_node::opt_node(node, asm, *fuel)
opt_node::opt_node(node, asm, *fuel, &mut cache2)
},
);
}
Expand Down Expand Up @@ -984,7 +984,7 @@ fn opt_init_obj(
false,
)));
}
Type::Float(float) if fuel.consume(1) && matches!(float.size(),32|64) => {
Type::Float(float) if fuel.consume(1) && matches!(float.size(), 32 | 64) => {
return CILRoot::StInd(Box::new((
addr,
asm.alloc_node(float.zero()),
Expand Down
35 changes: 31 additions & 4 deletions cilly/src/v2/opt/opt_node.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use crate::v2::{cilnode::ExtendKind, Assembly, CILNode, Const, Int, NodeIdx, Type};
use crate::{
v2::{cilnode::ExtendKind, Assembly, CILNode, Const, Int, NodeIdx, Type},
BinOp,
};

use super::{opt_if_fuel, OptFuel};
use super::{opt_if_fuel, OptFuel, SideEffectInfoCache};
/// Optimizes an intiger cast.
fn opt_int_cast(
original: CILNode,
Expand All @@ -11,7 +14,9 @@ fn opt_int_cast(
extend: ExtendKind,
) -> CILNode {
match asm.get_node(input) {
CILNode::LdField { addr, field } if asm[*field].tpe() == Type::Int(target) => asm.get_node(input).clone(),
CILNode::LdField { addr, field } if asm[*field].tpe() == Type::Int(target) => {
asm.get_node(input).clone()
}
CILNode::Const(cst) => match (cst.as_ref(), target) {
(Const::U64(val), Int::USize) => opt_if_fuel(Const::USize(*val).into(), original, fuel),
(Const::I64(val), Int::ISize) => opt_if_fuel(Const::ISize(*val).into(), original, fuel),
Expand Down Expand Up @@ -87,7 +92,12 @@ fn opt_int_cast(
_ => original,
}
}
pub fn opt_node(original: CILNode, asm: &mut Assembly, fuel: &mut OptFuel) -> CILNode {
pub fn opt_node(
original: CILNode,
asm: &mut Assembly,
fuel: &mut OptFuel,
cache: &mut SideEffectInfoCache,
) -> CILNode {
match original {
CILNode::SizeOf(tpe) => match asm[tpe] {
Type::Int(
Expand Down Expand Up @@ -147,6 +157,23 @@ pub fn opt_node(original: CILNode, asm: &mut Assembly, fuel: &mut OptFuel) -> CI
}
_ => original,
},
CILNode::LdFieldAdress { addr, field } => match asm.get_node(addr) {
CILNode::RefToPtr(inner) => CILNode::RefToPtr(asm.alloc_node(CILNode::LdFieldAdress {
addr: *inner,
field,
})),
_ => original,
},
CILNode::BinOp(lhs, rhs, op @ (BinOp::Add | BinOp::Sub)) => {
match (asm.get_node(lhs), asm.get_node(rhs)) {
(CILNode::Const(cst), rhs) if cst.as_ref().is_zero() && op != BinOp::Sub => {
rhs.clone()
}
(lhs, CILNode::Const(cst)) if cst.as_ref().is_zero() => lhs.clone(),
_ => original,
}
}
//CILNode::BinOp(lhs,rhs ,BinOp::And) if lhs == rhs && cache.has_side_effects(lhs, asm)=> asm[lhs].clone(),
CILNode::LdField { addr, field } => match asm.get_node(addr) {
CILNode::RefToPtr(addr) => {
opt_if_fuel(CILNode::LdField { addr: *addr, field }, original, fuel)
Expand Down
10 changes: 10 additions & 0 deletions cilly/src/v2/tpe/int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,16 @@ impl Int {
Int::ISize => todo!(),
}
}

pub fn promoted(&self) -> Option<Self> {
if self.size() == Some(128) {
return None;
}
Some(Self::from_size_sign(
self.size().unwrap_or(8) * 2,
self.is_signed(),
))
}
}
#[test]
fn is_signed() {
Expand Down
Loading

0 comments on commit 6d807b5

Please sign in to comment.