Skip to content

Commit 7c5d1e9

Browse files
committed
More optimizations
1 parent 6d807b5 commit 7c5d1e9

File tree

18 files changed

+408
-82
lines changed

18 files changed

+408
-82
lines changed

cilly/src/bin/asmedit.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,21 @@ fn main() {
257257
);
258258
println!("strings:{:?}", encoded_stats(asm.strings()));
259259
}
260+
"top_methods" => {
261+
let mut keys: Vec<_> = asm
262+
.method_refs()
263+
.iter_keys()
264+
.filter_map(|key| asm.method_ref_to_def(key))
265+
.map(|def| (def, asm[def].implementation().root_count()))
266+
.collect();
267+
let avg = keys.iter().map(|(_, len)| *len).sum::<usize>() / keys.len();
268+
keys.retain(|(_, val)| *val > avg);
269+
keys.sort_by(|(_, a), (_, b)| a.cmp(b));
270+
for (def, len) in keys[(keys.len() - body.parse::<usize>().unwrap_or(10))..].iter()
271+
{
272+
eprintln!("({},{len})", &asm[asm[*def].name()])
273+
}
274+
}
260275
"shorten_strings" => {
261276
let size_cap: usize = body.parse().unwrap();
262277
asm.shorten_strings(size_cap)

cilly/src/bin/linker/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ fn main() {
497497
println!("Eliminating dead code");
498498
final_assembly.eliminate_dead_code();
499499
}
500-
let mut fuel = final_assembly.fuel_from_env().fraction(0.5);
500+
let mut fuel = final_assembly.fuel_from_env().fraction(0.25);
501501
final_assembly.opt(&mut fuel);
502502
final_assembly.eliminate_dead_code();
503503
final_assembly.fix_aligement();

cilly/src/v2/asm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ impl Assembly {
147147
}
148148
#[must_use]
149149
pub fn default_fuel(&self) -> OptFuel {
150-
OptFuel::new((self.method_defs.len() * 4 + self.roots.len() * 8) as u32)
150+
OptFuel::new((self.method_defs.len() * 4 + self.roots.len() * 16) as u32)
151151
}
152152
pub(crate) fn borrow_methoddef(&mut self, def_id: MethodDefIdx) -> MethodDef {
153153
self.method_defs.remove(&def_id).unwrap()

cilly/src/v2/basic_block.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use serde::{Deserialize, Serialize};
22

3-
use super::{opt, Assembly, CILNode, CILRoot, RootIdx};
3+
use super::{opt::{self, blockid_from_jump}, Assembly, CILNode, CILRoot, RootIdx};
44
use crate::basic_block::BasicBlock as V1Block;
55
pub type BlockId = u32;
66
#[derive(Hash, PartialEq, Eq, Clone, Debug, Serialize, Deserialize)]
@@ -182,8 +182,12 @@ impl BasicBlock {
182182
/// block.remove_handler();
183183
/// assert!(block.handler().is_none());
184184
/// ```
185-
pub fn remove_handler(&mut self) {
185+
pub fn remove_handler(&mut self,asm:&mut Assembly) {
186186
self.handler = None;
187+
self.roots_mut().iter_mut().for_each(|root|if let CILRoot::ExitSpecialRegion { target, source } = asm[*root] {
188+
let target = blockid_from_jump(target, source);
189+
*root = asm.alloc_root(CILRoot::Branch(Box::new((target,0,None))));
190+
});
187191
}
188192
}
189193
impl BasicBlock {

cilly/src/v2/builtins/atomics.rs

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub fn emulate_uint8_cmp_xchng(asm: &mut Assembly, patcher: &mut MissingMethodPa
1818
// 1st, mask the previous value
1919
let prev_mask = asm.alloc_node(Const::I32(0xFFFF_FF00_u32 as i32));
2020
let prev = asm.alloc_node(CILNode::BinOp(prev, prev_mask, BinOp::And));
21-
21+
2222
asm.alloc_node(CILNode::BinOp(prev, arg, BinOp::Or))
2323
},
2424
Int::I32,
@@ -31,7 +31,7 @@ pub fn emulate_uint8_cmp_xchng(asm: &mut Assembly, patcher: &mut MissingMethodPa
3131
// 1st, mask the previous value
3232
let prev_mask = asm.alloc_node(Const::I32(0xFFFF_0000_u32 as i32));
3333
let prev = asm.alloc_node(CILNode::BinOp(prev, prev_mask, BinOp::And));
34-
34+
3535
asm.alloc_node(CILNode::BinOp(prev, arg, BinOp::Or))
3636
},
3737
Int::I32,
@@ -64,10 +64,16 @@ pub fn emulate_uint8_cmp_xchng(asm: &mut Assembly, patcher: &mut MissingMethodPa
6464
};
6565
patcher.insert(name, Box::new(generator));
6666
}
67-
pub fn compare_exchange(asm:&mut Assembly,int:Int,addr:NodeIdx, value:NodeIdx, comaprand:NodeIdx)->NodeIdx{
68-
match int.size().unwrap_or(8){
67+
pub fn compare_exchange(
68+
asm: &mut Assembly,
69+
int: Int,
70+
addr: NodeIdx,
71+
value: NodeIdx,
72+
comaprand: NodeIdx,
73+
) -> NodeIdx {
74+
match int.size().unwrap_or(8) {
6975
// u16 is buggy :(. TODO: fix it.
70-
1 | 2=>{
76+
1 | 2 => {
7177
let compare_exchange = asm.alloc_string("atomic_cmpxchng8_i32");
7278

7379
let i32 = Type::Int(int);
@@ -81,16 +87,31 @@ pub fn compare_exchange(asm:&mut Assembly,int:Int,addr:NodeIdx, value:NodeIdx, c
8187
MethodKind::Static,
8288
vec![].into(),
8389
));
84-
let cast_value = asm.alloc_node(CILNode::IntCast { input: value, target: Int::I32, extend: crate::cilnode::ExtendKind::ZeroExtend });
85-
let cast_comparand = asm.alloc_node(CILNode::IntCast { input: comaprand, target: Int::I32, extend: crate::cilnode::ExtendKind::ZeroExtend });
90+
let cast_value = asm.alloc_node(CILNode::IntCast {
91+
input: value,
92+
target: Int::I32,
93+
extend: crate::cilnode::ExtendKind::ZeroExtend,
94+
});
95+
let cast_comparand = asm.alloc_node(CILNode::IntCast {
96+
input: comaprand,
97+
target: Int::I32,
98+
extend: crate::cilnode::ExtendKind::ZeroExtend,
99+
});
86100
let addr = asm.alloc_node(CILNode::RefToPtr(addr));
87101
let i32_tidx = asm.alloc_type(Type::Int(Int::I32));
88-
let addr = asm.alloc_node(CILNode::PtrCast(addr, Box::new(crate::cilnode::PtrCastRes::Ptr(i32_tidx))));
102+
let addr = asm.alloc_node(CILNode::PtrCast(
103+
addr,
104+
Box::new(crate::cilnode::PtrCastRes::Ptr(i32_tidx)),
105+
));
89106
let res = asm.alloc_node(CILNode::Call(Box::new((
90107
mref,
91108
Box::new([addr, cast_value, cast_comparand]),
92109
))));
93-
asm.alloc_node(CILNode::IntCast { input: res, target: int, extend: crate::cilnode::ExtendKind::ZeroExtend })
110+
asm.alloc_node(CILNode::IntCast {
111+
input: res,
112+
target: int,
113+
extend: crate::cilnode::ExtendKind::ZeroExtend,
114+
})
94115
}
95116
4..=8 => {
96117
let compare_exchange = asm.alloc_string("CompareExchange");
@@ -106,15 +127,14 @@ pub fn compare_exchange(asm:&mut Assembly,int:Int,addr:NodeIdx, value:NodeIdx, c
106127
MethodKind::Static,
107128
vec![].into(),
108129
));
109-
130+
110131
asm.alloc_node(CILNode::Call(Box::new((
111132
mref,
112133
Box::new([addr, value, comaprand]),
113134
))))
114135
}
115-
_=>todo!("Can't cmpxchng {int:?}")
136+
_ => todo!("Can't cmpxchng {int:?}"),
116137
}
117-
118138
}
119139
pub fn generate_atomic(
120140
asm: &mut Assembly,
@@ -209,7 +229,7 @@ pub fn generate_all_atomics(asm: &mut Assembly, patcher: &mut MissingMethodPatch
209229
generate_atomic_for_ints(asm, patcher, "min", int_min);
210230
// Emulates 1 byte compare exchange
211231
emulate_uint8_cmp_xchng(asm, patcher);
212-
for int in [Int::ISize, Int::USize] {
232+
for int in [Int::ISize, Int::USize, Int::U8, Int::I8] {
213233
generate_atomic(
214234
asm,
215235
patcher,

cilly/src/v2/cst.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,27 @@ impl Const {
6969
Const::Null(_) => true,
7070
}
7171
}
72+
pub(crate) fn is_one(&self) -> bool {
73+
match self {
74+
Const::I8(val) => *val == 1,
75+
Const::I16(val) => *val == 1,
76+
Const::I32(val) => *val == 1,
77+
Const::I64(val) => *val == 1,
78+
Const::I128(val) => *val == 1,
79+
Const::ISize(val) => *val == 1,
80+
Const::U8(val) => *val == 1,
81+
Const::U16(val) => *val == 1,
82+
Const::U32(val) => *val == 1,
83+
Const::U64(val) => *val == 1,
84+
Const::U128(val) => *val == 1,
85+
Const::USize(val) => *val == 1,
86+
Const::PlatformString(_) => false,
87+
Const::Bool(_) => false,
88+
Const::F32(val) => **val == 1.1,
89+
Const::F64(val) => **val == 1.1,
90+
Const::Null(_) => true,
91+
}
92+
}
7293
}
7394

7495
impl From<Const> for CILNode {

cilly/src/v2/method.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,16 @@ pub enum MethodImpl {
511511
Missing,
512512
}
513513
impl MethodImpl {
514+
pub fn root_count(&self) -> usize {
515+
match self {
516+
MethodImpl::MethodBody { blocks, .. } => {
517+
blocks.iter().map(|block| block.roots().len()).sum()
518+
}
519+
MethodImpl::Extern { .. } => 0,
520+
MethodImpl::AliasFor(_) => 0,
521+
MethodImpl::Missing => 3,
522+
}
523+
}
514524
pub fn blocks_mut(&mut self) -> Option<&mut Vec<BasicBlock>> {
515525
match self {
516526
Self::MethodBody { blocks, .. } => Some(blocks),

cilly/src/v2/opt/mod.rs

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -513,11 +513,15 @@ impl MethodDef {
513513
if fuel.consume(1) {
514514
self.implementation_mut().remove_duplicate_sfi(asm);
515515
}
516+
if let MethodImpl::MethodBody { blocks, .. } = self.implementation_mut() {
517+
linearize_blocks(blocks,&asm);
518+
}
519+
516520
self.remove_useless_handlers(asm, fuel, cache);
517521
}
518522
fn remove_useless_handlers(
519523
&mut self,
520-
asm: &Assembly,
524+
asm: &mut Assembly,
521525
fuel: &mut OptFuel,
522526
cache: &mut SideEffectInfoCache,
523527
) {
@@ -536,7 +540,7 @@ impl MethodDef {
536540
{
537541
let (target, _, None) = info.as_ref() else {continue;};
538542
// Ret or throw
539-
if !has_targets[target] && blocks_copy[target].roots().len() < 20 {
543+
if !has_targets[target] && blocks_copy[target].roots().len() < 10 {
540544
let roots = block.roots_mut();
541545
roots.pop();
542546
roots.extend(blocks_copy[target].roots());
@@ -567,7 +571,7 @@ impl MethodDef {
567571
})
568572
}) && fuel.consume(6)
569573
{
570-
block.remove_handler();
574+
block.remove_handler( asm);
571575
}
572576
}
573577
};
@@ -606,6 +610,12 @@ impl MethodDef {
606610
let curr = peekable.next().unwrap();
607611
*curr = asm.alloc_root(CILRoot::Ret(tree));
608612
}
613+
(CILRoot::Branch(info), CILRoot::Branch(_))
614+
if is_branch_unconditional(info) =>
615+
{
616+
let curr = peekable.next().unwrap();
617+
*curr = nop;
618+
}
609619
(CILRoot::Branch(info), CILRoot::Branch(info2))
610620
if is_branch_unconditional(info2) =>
611621
{
@@ -1003,7 +1013,7 @@ fn opt_init_obj(
10031013
pub fn is_branch_unconditional(branch: &(u32, u32, Option<BranchCond>)) -> bool {
10041014
branch.2.is_none()
10051015
}
1006-
fn blockid_from_jump(target: u32, sub_target: u32) -> u32 {
1016+
pub fn blockid_from_jump(target: u32, sub_target: u32) -> u32 {
10071017
if sub_target == 0 {
10081018
target
10091019
} else {
@@ -1152,3 +1162,49 @@ fn remove_nops() {
11521162
mimpl.remove_nops(&mut asm);
11531163
assert_eq!(mimpl.blocks_mut().unwrap()[0].roots().len(), 2);
11541164
}
1165+
/// Replaces a sequence of blocks with unconditional jumps with a single block.
1166+
fn linearize_blocks(blocks: &mut Vec<BasicBlock>, asm: &Assembly) {
1167+
// 1. This optimization *only* works if no handlers present.
1168+
if blocks.iter().any(|block| block.handler().is_some()) {
1169+
return;
1170+
}
1171+
// 2. This optimization only works if all blocks jump unconditionaly.
1172+
if blocks
1173+
.iter()
1174+
.flat_map(|block| block.roots().iter())
1175+
.any(|root| match &asm[*root] {
1176+
CILRoot::Branch(info) => !is_branch_unconditional(info),
1177+
CILRoot::ExitSpecialRegion { .. } => true,
1178+
_ => false,
1179+
})
1180+
{
1181+
return;
1182+
}
1183+
let mut res = Vec::new();
1184+
let mut curr_block = &blocks[0];
1185+
let mut should_countinue = true;
1186+
// Cap the optimization to prevent infinite loops from causing issues
1187+
let mut ic = 0;
1188+
while should_countinue {
1189+
should_countinue = false;
1190+
for root in curr_block.roots() {
1191+
ic += 1;
1192+
if ic > 2000{
1193+
return;
1194+
}
1195+
match &asm[*root] {
1196+
CILRoot::Branch(info) => {
1197+
let Some(block) = block_with_id(blocks, blockid_from_jump(info.0, info.1))
1198+
else {
1199+
return;
1200+
};
1201+
curr_block = block;
1202+
should_countinue = true;
1203+
break;
1204+
}
1205+
_ => res.push(*root),
1206+
}
1207+
}
1208+
}
1209+
*blocks = vec![BasicBlock::new(res, 0, None)];
1210+
}

cilly/src/v2/opt/opt_node.rs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ pub fn opt_node(
116116
original,
117117
fuel,
118118
),
119+
Type::Float(float) => {
120+
opt_if_fuel(Const::I32(float.size() as i32).into(), original, fuel)
121+
}
119122
_ => original,
120123
},
121124
CILNode::IntCast {
@@ -173,7 +176,54 @@ pub fn opt_node(
173176
_ => original,
174177
}
175178
}
176-
//CILNode::BinOp(lhs,rhs ,BinOp::And) if lhs == rhs && cache.has_side_effects(lhs, asm)=> asm[lhs].clone(),
179+
CILNode::BinOp(lhs, rhs, BinOp::Rem | BinOp::RemUn) => {
180+
match (asm.get_node(lhs), asm.get_node(rhs)) {
181+
(CILNode::Const(a), CILNode::Const(b)) if a.get_type() == b.get_type() => {
182+
match (a.as_ref(), b.as_ref()) {
183+
(Const::U8(a), Const::U8(b)) => Const::U8(a.wrapping_rem(*b)).into(),
184+
(Const::U16(a), Const::U16(b)) => Const::U16(a.wrapping_rem(*b)).into(),
185+
(Const::U32(a), Const::U32(b)) => Const::U32(a.wrapping_rem(*b)).into(),
186+
(Const::U64(a), Const::U64(b)) => Const::U64(a.wrapping_rem(*b)).into(),
187+
(Const::U128(a), Const::U128(b)) => Const::U128(a.wrapping_rem(*b)).into(),
188+
(Const::USize(a), Const::USize(b)) => {
189+
Const::USize(a.wrapping_rem(*b)).into()
190+
}
191+
(Const::I8(a), Const::I8(b)) => Const::I8(a.wrapping_rem(*b)).into(),
192+
(Const::I16(a), Const::I16(b)) => Const::I16(a.wrapping_rem(*b)).into(),
193+
(Const::I32(a), Const::I32(b)) => Const::I32(a.wrapping_rem(*b)).into(),
194+
(Const::I64(a), Const::I64(b)) => Const::I64(a.wrapping_rem(*b)).into(),
195+
(Const::I128(a), Const::I128(b)) => Const::I128(a.wrapping_rem(*b)).into(),
196+
(Const::ISize(a), Const::ISize(b)) => {
197+
Const::ISize(a.wrapping_rem(*b)).into()
198+
}
199+
_ => original,
200+
}
201+
}
202+
_ => original,
203+
}
204+
}
205+
CILNode::BinOp(lhs, rhs, BinOp::Mul) => match (asm.get_node(lhs), asm.get_node(rhs)) {
206+
(CILNode::Const(a), CILNode::Const(b)) if a.get_type() == b.get_type() => {
207+
match (a.as_ref(), b.as_ref()) {
208+
(Const::U8(a), Const::U8(b)) => Const::U8(a.wrapping_mul(*b)).into(),
209+
(Const::U16(a), Const::U16(b)) => Const::U16(a.wrapping_mul(*b)).into(),
210+
(Const::U32(a), Const::U32(b)) => Const::U32(a.wrapping_mul(*b)).into(),
211+
(Const::U64(a), Const::U64(b)) => Const::U64(a.wrapping_mul(*b)).into(),
212+
(Const::U128(a), Const::U128(b)) => Const::U128(a.wrapping_mul(*b)).into(),
213+
(Const::USize(a), Const::USize(b)) => Const::USize(a.wrapping_mul(*b)).into(),
214+
(Const::I8(a), Const::I8(b)) => Const::I8(a.wrapping_mul(*b)).into(),
215+
(Const::I16(a), Const::I16(b)) => Const::I16(a.wrapping_mul(*b)).into(),
216+
(Const::I32(a), Const::I32(b)) => Const::I32(a.wrapping_mul(*b)).into(),
217+
(Const::I64(a), Const::I64(b)) => Const::I64(a.wrapping_mul(*b)).into(),
218+
(Const::I128(a), Const::I128(b)) => Const::I128(a.wrapping_mul(*b)).into(),
219+
(Const::ISize(a), Const::ISize(b)) => Const::ISize(a.wrapping_mul(*b)).into(),
220+
_ => original,
221+
}
222+
}
223+
(CILNode::Const(a), b) if a.is_one() => b.clone(),
224+
(a, CILNode::Const(b)) if b.is_one() => a.clone(),
225+
_ => original,
226+
},
177227
CILNode::LdField { addr, field } => match asm.get_node(addr) {
178228
CILNode::RefToPtr(addr) => {
179229
opt_if_fuel(CILNode::LdField { addr: *addr, field }, original, fuel)

src/binop/cmp.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ pub fn eq_unchecked(
5858
TyKind::Bool
5959
| TyKind::Char
6060
| TyKind::Float(FloatTy::F32 | FloatTy::F64)
61-
| TyKind::RawPtr(_, _) | TyKind::FnPtr(_,_)=> {
61+
| TyKind::RawPtr(_, _)
62+
| TyKind::FnPtr(_, _) => {
6263
eq!(operand_a, operand_b)
6364
}
6465
TyKind::Float(FloatTy::F128) => {

0 commit comments

Comments
 (0)