Skip to content

Commit 007551e

Browse files
committed
Added support for setting fields of structs. Added optimzation, which removed a lot of unused CIL ops, locals, and labels.
1 parent cb70ae8 commit 007551e

File tree

10 files changed

+222
-40
lines changed

10 files changed

+222
-40
lines changed

src/assembly.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ impl Assembly {
6262
last_bb_id += 1;
6363
for statement in &block_data.statements {
6464
ops.extend(crate::statement::handle_statement(statement, mir, tcx, mir));
65-
ops.push(CILOp::Comment(format!("{statement:?}").into()));
65+
// ops.push(CILOp::Comment(format!("{statement:?}").into()));
6666
//println!("ops:{ops:?}\n\n");
6767
}
6868
match &block_data.terminator {
@@ -92,6 +92,10 @@ impl Assembly {
9292
self.types.insert(type_def);
9393
}
9494
}
95+
pub fn opt(&mut self){
96+
let functions:HashSet<_> = self.functions.iter().map(|method|{let mut method = method.clone();crate::opt::opt_method(&mut method);method}).collect();
97+
self.functions = functions;
98+
}
9599
pub fn add_typedef<'ctx>(&mut self, type_def: TypeDef) {
96100
self.types.insert(type_def);
97101
}

src/assembly_exporter/ilasm_exporter.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -379,11 +379,18 @@ fn op_cli(op: &crate::cil_op::CILOp) -> Cow<'static, str> {
379379
}
380380
// Pointer stuff
381381
CILOp::LDIndI8 => "ldind.i1".into(),
382-
CILOp::Pop => "pop".into(),
382+
//OOP
383383
CILOp::Throw => "throw".into(),
384384
CILOp::LdStr(str) => format!("ldstr {str:?}").into(),
385385
CILOp::LDField(descr) => format!(
386-
"ldfld {prefixed_type} {owner}::{field_name}",
386+
"ldfld {prefixed_type} valuetype {owner}::{field_name}",
387+
prefixed_type = prefixed_type_cli(descr.tpe()),
388+
owner = dotnet_type_ref_cli(descr.owner()),
389+
field_name = descr.name()
390+
)
391+
.into(),
392+
CILOp::STField(descr) => format!(
393+
"stfld {prefixed_type} valuetype {owner}::{field_name}",
387394
prefixed_type = prefixed_type_cli(descr.tpe()),
388395
owner = dotnet_type_ref_cli(descr.owner()),
389396
field_name = descr.name()
@@ -421,6 +428,9 @@ fn op_cli(op: &crate::cil_op::CILOp) -> Cow<'static, str> {
421428
.into()
422429
}
423430
}
431+
//Stack
432+
CILOp::Pop => "pop".into(),
433+
CILOp::Dup => "dup".into(),
424434
_ => todo!("Unsuported op {op:?}"),
425435
}
426436
}

src/cil_op.rs

+4
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,12 @@ pub enum CILOp {
148148
Gt,
149149
//Special
150150
Pop,
151+
Dup,
152+
Nop,
151153
//OOP
152154
NewObj(Box<CallSite>),
153155
LDField(Box<FieldDescriptor>),
154156
LDFieldAdress(Box<FieldDescriptor>),
157+
STField(Box<FieldDescriptor>),
158+
LdObj(Box<DotnetTypeRef>),
155159
}

src/compile_test.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ macro_rules! run_test {
107107
let exec_path = concat!("../", stringify!($test_name), ".exe");
108108
test_dotnet_executable(exec_path, test_dir);
109109
}
110-
};
110+
};
111111
}
112112
#[cfg(test)]
113113
fn backend_path() -> &'static str {
@@ -130,9 +130,10 @@ test_lib! {identity}
130130
test_lib! {libc}
131131
test_lib! {nbody}
132132
test_lib! {references}
133-
test_lib! {structs}
133+
//test_lib! {structs}
134134

135135
test_lib! {types}
136136

137137
run_test! {arthm,add}
138138
run_test! {types,enums}
139+
run_test! {types,structs}

src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ mod r#type;
6161
mod type_def;
6262
mod unop;
6363
mod utilis;
64+
mod opt;
6465
use assembly::Assembly;
6566
struct MyBackend;
6667
pub(crate) const ALWAYS_INIT_STRUCTS: bool = false;
@@ -106,7 +107,7 @@ impl CodegenBackend for MyBackend {
106107
let cs = cil_op::CallSite::new(None, symbol.into(), sig, true);
107108
codegen.set_entrypoint(cs);
108109
}
109-
110+
codegen.opt();
110111
let name: IString = cgus.iter().next().unwrap().name().to_string().into();
111112
Box::new((
112113
name,

src/method.rs

+6
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ impl Method {
4040
.iter()
4141
.any(|attr| *attr == Attribute::EntryPoint)
4242
}
43+
pub fn ops_mut(&mut self)->&mut Vec<CILOp>{
44+
&mut self.ops
45+
}
4346
pub fn access(&self) -> AccessModifer {
4447
self.access
4548
}
@@ -61,4 +64,7 @@ impl Method {
6164
pub fn add_attribute(&mut self, attr: Attribute) {
6265
self.attributes.push(attr);
6366
}
67+
pub fn set_locals(&mut self,locals: impl Into<Vec<Type>>){
68+
self.locals = locals.into();
69+
}
6470
}

src/opt/mod.rs

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
use crate::{method::Method, cil_op::CILOp};
2+
const MAX_PASS:u32 = 4;
3+
pub fn opt_method(method:&mut Method){
4+
for _ in 0..MAX_PASS{
5+
op2_combos(method.ops_mut());
6+
remove_zombie_sets(method.ops_mut());
7+
method.ops_mut().retain(|op|*op != CILOp::Nop);
8+
remove_unused_locals(method);
9+
}
10+
}
11+
fn remove_unused_locals(method:&mut Method){
12+
let mut local_map = vec![u32::MAX;method.locals().len()];
13+
let mut new_locals = Vec::with_capacity(method.locals().len());
14+
for (local,tpe) in method.locals().iter().enumerate(){
15+
if local_map[local] == u32::MAX && !is_local_unused(method.get_ops(), local as u32){
16+
local_map[local] = new_locals.len() as u32;
17+
new_locals.push(tpe.clone());
18+
}
19+
}
20+
method.ops_mut().iter_mut().for_each(|op|match op{
21+
CILOp::LDLoc(idx)=>{
22+
let new_loc = local_map[*idx as usize];
23+
*op = CILOp::LDLoc(new_loc);
24+
},
25+
CILOp::LDLocA(idx)=>{
26+
let new_loc = local_map[*idx as usize];
27+
*op = CILOp::LDLocA(new_loc);
28+
},
29+
CILOp::STLoc(idx)=>{
30+
let new_loc = local_map[*idx as usize];
31+
*op = CILOp::STLoc(new_loc);
32+
}
33+
_=>(),
34+
});
35+
method.set_locals(new_locals);
36+
}
37+
fn remove_zombie_sets(ops:&mut Vec<CILOp>){
38+
for idx in 0..ops.len(){
39+
match ops[idx]{
40+
CILOp::STLoc(loc)=>
41+
if is_local_dead(ops,loc){
42+
ops[idx] = CILOp::Pop;
43+
},
44+
CILOp::Label(label)=>
45+
if is_label_unsused(ops,label){
46+
ops[idx] = CILOp::Nop;
47+
},
48+
_=>(),
49+
}
50+
}
51+
}
52+
fn op2_combos(ops:&mut Vec<CILOp>){
53+
if ops.is_empty(){
54+
return;
55+
}
56+
for idx in 0..(ops.len() - 1){
57+
let (op1,op2) = (&ops[idx],&ops[idx + 1]);
58+
match (op1,op2){
59+
(CILOp::LDLoc(a),CILOp::STLoc(b))=> if a == b{
60+
ops[idx] = CILOp::Nop;
61+
ops[idx + 1] = CILOp::Nop;
62+
}
63+
(CILOp::STLoc(a),CILOp::LDLoc(b))=> if a == b{
64+
ops[idx + 1] = CILOp::STLoc(*a);
65+
ops[idx] = CILOp::Dup;
66+
67+
}
68+
(CILOp::Dup,CILOp::Pop)=>{
69+
ops[idx] = CILOp::Nop;
70+
ops[idx + 1] = CILOp::Nop;
71+
}
72+
(CILOp::GoTo(target),CILOp::Label(label))=>if target == label{
73+
ops[idx] = CILOp::Nop;
74+
}
75+
_=>(),
76+
}
77+
}
78+
}
79+
/// A "Dead" local is one that is only written into - never read.
80+
fn is_local_dead(ops:&[CILOp],local:u32)->bool{
81+
!ops.iter().any(|op|{
82+
match op{
83+
CILOp::LDLoc(loc) => *loc == local,
84+
CILOp::LDLocA(loc) => *loc == local,
85+
_=>false,
86+
}
87+
})
88+
}
89+
/// A "Unused" local is one that is never written to or read from.
90+
fn is_local_unused(ops:&[CILOp],local:u32)->bool{
91+
!ops.iter().any(|op|{
92+
match op{
93+
CILOp::LDLoc(loc) => *loc == local,
94+
CILOp::LDLocA(loc) => *loc == local,
95+
CILOp::STLoc(loc) => *loc == local,
96+
_=>false,
97+
}
98+
})
99+
}
100+
/// A "Unused" label is one that is never jumped to
101+
fn is_label_unsused(ops:&[CILOp],label:u32)->bool{
102+
!ops.iter().any(|op|{
103+
match op{
104+
CILOp::GoTo(target) => label == *target,
105+
CILOp::BEq(target) => label == *target,
106+
_=>false,
107+
}
108+
})
109+
}

src/place.rs

+71-27
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ fn slice_head<T>(slice: &[T]) -> (&T, &[T]) {
99
fn pointed_type(ty: Ty) -> Ty {
1010
if let TyKind::Ref(_region, inner, _mut) = ty.kind() {
1111
*inner
12-
} else {
12+
} else if let TyKind::RawPtr(inner_and_mut) = ty.kind() {
13+
inner_and_mut.ty
14+
}else {
1315
panic!("{ty:?} is not a pointer type!");
1416
}
1517
}
@@ -18,6 +20,7 @@ fn body_ty_is_by_adress(last_ty: &Ty) -> bool {
1820
TyKind::Int(_) => false,
1921
TyKind::Adt(_, _) => true,
2022
TyKind::Ref(_region, inner, _mut) => false,
23+
TyKind::RawPtr(_) => false,
2124
_ => todo!("TODO: body_ty_is_by_adress does not support type {last_ty:?}"),
2225
}
2326
}
@@ -56,37 +59,37 @@ fn local_body<'tcx>(local: usize, method: &rustc_middle::mir::Body<'tcx>) -> (CI
5659
(local_get(local, method), ty)
5760
}
5861
}
59-
/// Returns the ops for getting the value of place.
60-
pub fn place_get<'a>(
61-
place: &Place<'a>,
62+
fn place_elem_get<'a>(
63+
place_elem: &PlaceElem<'a>,
64+
curr_type: Ty<'a>,
6265
ctx: TyCtxt<'a>,
63-
method: &rustc_middle::mir::Body<'a>,
6466
) -> Vec<CILOp> {
65-
let mut ops = Vec::with_capacity(place.projection.len());
66-
if place.projection.is_empty() {
67-
ops.push(local_get(place.local.as_usize(), method));
68-
return ops;
69-
} else {
70-
let (op, mut ty) = local_body(place.local.as_usize(), method);
71-
ops.push(op);
72-
let (head, body) = slice_head(place.projection);
73-
for elem in body {
74-
println!("elem:{elem:?} ty:{ty:?}");
75-
let (curr_ty, curr_ops) = place_elem_body(elem, ty, ctx);
76-
ty = curr_ty;
77-
ops.extend(curr_ops);
67+
match place_elem {
68+
PlaceElem::Deref => deref_op(curr_type,ctx),
69+
PlaceElem::Field(index, field_type) => {
70+
let field_name = field_name(curr_type, index.as_u32());
71+
let curr_type = crate::r#type::Type::from_ty(curr_type, ctx);
72+
let curr_type = if let crate::r#type::Type::DotnetType(dotnet_type) = curr_type {
73+
dotnet_type.as_ref().clone()
74+
} else {
75+
panic!();
76+
};
77+
let field_desc = FieldDescriptor::boxed(
78+
curr_type,
79+
crate::r#type::Type::from_ty(*field_type, ctx),
80+
field_name,
81+
);
82+
vec![CILOp::LDField(field_desc)]
7883
}
79-
ops.extend(place_elem_get(head, ty, ctx));
80-
ops
84+
_ => todo!("Can't handle porojection {place_elem:?} in get"),
8185
}
8286
}
83-
fn place_elem_get<'a>(
87+
fn place_elem_set<'a>(
8488
place_elem: &PlaceElem<'a>,
8589
curr_type: Ty<'a>,
8690
ctx: TyCtxt<'a>,
8791
) -> Vec<CILOp> {
8892
match place_elem {
89-
PlaceElem::Deref => deref_op(curr_type),
9093
PlaceElem::Field(index, field_type) => {
9194
let field_name = field_name(curr_type, index.as_u32());
9295
let curr_type = crate::r#type::Type::from_ty(curr_type, ctx);
@@ -100,9 +103,9 @@ fn place_elem_get<'a>(
100103
crate::r#type::Type::from_ty(*field_type, ctx),
101104
field_name,
102105
);
103-
vec![CILOp::LDField(field_desc)]
106+
vec![CILOp::STField(field_desc)]
104107
}
105-
_ => todo!("Can't handle porojection {place_elem:?} in get"),
108+
_ => todo!("Can't handle porojection {place_elem:?} in set"),
106109
}
107110
}
108111
fn field_name(ty: Ty, idx: u32) -> crate::IString {
@@ -128,7 +131,7 @@ fn place_elem_body<'ctx>(
128131
if body_ty_is_by_adress(&pointed) {
129132
(pointed, vec![])
130133
} else {
131-
(pointed, deref_op(curr_type))
134+
(pointed, deref_op(curr_type,tyctx))
132135
}
133136
}
134137
PlaceElem::Field(index, field_type) => {
@@ -153,16 +156,48 @@ fn place_elem_body<'ctx>(
153156
_ => todo!("Can't handle porojection {place_elem:?} in body"),
154157
}
155158
}
156-
fn deref_op(curr_type: Ty) -> Vec<CILOp> {
159+
fn deref_op<'ctx>(curr_type: Ty<'ctx>,tyctx: TyCtxt<'ctx>) -> Vec<CILOp> {
157160
match curr_type.kind() {
158161
TyKind::Int(int_ty) => match int_ty {
159162
IntTy::I8 => vec![CILOp::LDIndI8],
160163
_ => todo!("TODO: can't deref int type {int_ty:?} yet"),
161164
},
165+
TyKind::Adt(_,_)=>{
166+
let curr_type = if let crate::r#type::Type::DotnetType(dotnet_type) = crate::r#type::Type::from_ty(curr_type,tyctx) {
167+
dotnet_type
168+
} else {
169+
panic!();
170+
};
171+
vec![CILOp::LdObj(curr_type)]
172+
}
162173
_ => todo!("TODO: can't deref type {curr_type:?} yet"),
163174
}
164175
}
165176
/// Returns the ops for getting the value of place.
177+
pub fn place_get<'a>(
178+
place: &Place<'a>,
179+
ctx: TyCtxt<'a>,
180+
method: &rustc_middle::mir::Body<'a>,
181+
) -> Vec<CILOp> {
182+
let mut ops = Vec::with_capacity(place.projection.len());
183+
if place.projection.is_empty() {
184+
ops.push(local_get(place.local.as_usize(), method));
185+
return ops;
186+
} else {
187+
let (op, mut ty) = local_body(place.local.as_usize(), method);
188+
ops.push(op);
189+
let (head, body) = slice_head(place.projection);
190+
for elem in body {
191+
println!("elem:{elem:?} ty:{ty:?}");
192+
let (curr_ty, curr_ops) = place_elem_body(elem, ty, ctx);
193+
ty = curr_ty;
194+
ops.extend(curr_ops);
195+
}
196+
ops.extend(place_elem_get(head, ty, ctx));
197+
ops
198+
}
199+
}
200+
/// Returns the ops for getting the value of place.
166201
pub fn place_adress<'a>(
167202
place: &Place<'a>,
168203
ctx: TyCtxt<'a>,
@@ -192,6 +227,15 @@ pub(crate) fn place_set<'a>(
192227
} else {
193228
let (op, mut ty) = local_body(place.local.as_usize(), method);
194229
ops.push(op);
195-
todo!();
230+
let (head, body) = slice_head(place.projection);
231+
for elem in body {
232+
println!("elem:{elem:?} ty:{ty:?}");
233+
let (curr_ty, curr_ops) = place_elem_body(elem, ty, ctx);
234+
ty = curr_ty;
235+
ops.extend(curr_ops);
236+
}
237+
ops.extend(value_calc);
238+
ops.extend(place_elem_set(head, ty, ctx));
239+
ops
196240
}
197241
}

0 commit comments

Comments
 (0)