Skip to content

Commit 9de913a

Browse files
committed
Refactoring, can now emmit assembly for very simple functions
1 parent 3612d55 commit 9de913a

File tree

5 files changed

+386
-221
lines changed

5 files changed

+386
-221
lines changed

src/assembly.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
use crate::{FunctionSignature,CLRMethod};
2+
use crate::IString;
3+
use rustc_middle::{
4+
mir::mono::MonoItem,
5+
ty::{Instance, ParamEnv, TyCtxt},
6+
};
7+
pub(crate) struct Assembly {
8+
methods: Vec<CLRMethod>,
9+
name: IString,
10+
}
11+
impl Assembly {
12+
pub(crate) fn into_il_ir(&self) -> IString {
13+
let mut methods = String::new();
14+
for method in &self.methods{
15+
methods.push_str(&method.into_il_ir());
16+
}
17+
let methods = format!(".class {name} {{{methods}}}", name = self.name);
18+
format!(".assembly {name}{{}}\n{methods}", name = self.name).into()
19+
}
20+
}
21+
impl Assembly {
22+
pub(crate) fn new(name: &str) -> Self {
23+
let name: String = name.chars().take_while(|c| *c != '.').collect();
24+
let name = name.replace("-", "_");
25+
Self {
26+
methods: Vec::with_capacity(0x100),
27+
name: name.into(),
28+
}
29+
}
30+
pub(crate) fn add_fn<'tcx>(&mut self, instance: Instance<'tcx>, tcx: TyCtxt<'tcx>,name:&str) {
31+
// TODO: figure out: What should it be???
32+
let param_env = ParamEnv::empty();
33+
34+
let def_id = instance.def_id();
35+
let mir = tcx.optimized_mir(def_id);
36+
let blocks = &(*mir.basic_blocks);
37+
let sig = instance.ty(tcx, param_env).fn_sig(tcx);
38+
let mut clr_method = CLRMethod::new(FunctionSignature::from_poly_sig(sig).expect("Could not resolve the function signature"),name);
39+
for block_data in blocks {
40+
for statement in &block_data.statements {
41+
clr_method.add_statement(statement);
42+
}
43+
match &block_data.terminator {
44+
Some(term) => clr_method.add_terminator(term),
45+
None => (),
46+
}
47+
}
48+
clr_method.opt();
49+
clr_method.typecheck();
50+
println!("clr_method:{clr_method:?}");
51+
println!("instance:{instance:?}\n");
52+
self.methods.push(clr_method);
53+
}
54+
pub(crate) fn add_item<'tcx>(&mut self, item: MonoItem<'tcx>, tcx: TyCtxt<'tcx>) {
55+
println!("adding item:{}", item.symbol_name(tcx));
56+
57+
match item {
58+
MonoItem::Fn(instance) => self.add_fn(instance, tcx,&format!("{}",item.symbol_name(tcx))),
59+
_ => todo!("Unsupported item:\"{item:?}\"!"),
60+
}
61+
}
62+
}

src/base_ir.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
use crate::{IString,VariableType,CLRMethod};
2+
#[derive(Debug, Clone)]
3+
pub(crate) enum BaseIR {
4+
LDConstI32(i32),
5+
STArg(u32),
6+
LDArg(u32),
7+
STLoc(u32),
8+
LDLoc(u32),
9+
Add,
10+
Mul,
11+
Shl,
12+
Return,
13+
}
14+
impl BaseIR{
15+
pub(crate) fn get_trivial_type(&self,parrent_method:&CLRMethod)->Option<VariableType>{
16+
match self{
17+
Self::LDConstI32(_)=>Some(VariableType::I32),
18+
Self::LDArg(arg_id)=>Some(parrent_method.get_arg_type(*arg_id).clone()),
19+
_=>None,
20+
}
21+
}
22+
pub(crate) fn clr_ir(&self)->IString{
23+
match self{
24+
Self::LDArg(arg)=>format!("\tldarg.{arg}\n"),
25+
Self::LDLoc(arg)=>format!("\tldloc.{arg}\n"),
26+
Self::STLoc(arg)=>format!("\tstloc.{arg}\n"),
27+
Self::Return=>"\tret\n".into(),
28+
Self::Add=>"\tadd\n".into(),
29+
Self::Mul=>"\tmul\n".into(),
30+
Self::Shl=>"\tshl\n".into(),
31+
Self::LDConstI32(i32const)=>format!("ldc.i4 {i32const}\t\n"),
32+
_=>format!("\t//Comment!\n"),
33+
}.into()
34+
}
35+
}

src/clr_method.rs

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
use crate::BaseIR;
2+
use crate::IString;
3+
use crate::FunctionSignature;
4+
use crate::VariableType;
5+
use rustc_middle::{
6+
mir::{
7+
interpret::ConstValue, AggregateKind, BinOp, ConstantKind, Operand, Rvalue, Statement,
8+
StatementKind, Terminator, TerminatorKind,
9+
},
10+
ty::{IntTy, TyKind},
11+
};
12+
#[derive(Debug)]
13+
pub(crate) struct CLRMethod {
14+
ops: Vec<BaseIR>,
15+
locals: Vec<Option<VariableType>>,
16+
op_types:Vec<Option<VariableType>>,
17+
sig: FunctionSignature,
18+
name:IString,
19+
}
20+
enum LocalPlacement {
21+
Arg(u32),
22+
Var(u32),
23+
}
24+
impl CLRMethod {
25+
fn name(&self)->&str{&self.name}
26+
pub(crate) fn get_arg_type(&self,arg:u32)->&VariableType{
27+
&self.sig.inputs()[arg as usize]
28+
}
29+
fn set_trivial_types(&mut self){
30+
for index in 0..(self.op_types.len()){
31+
if let None = self.op_types[index]{
32+
self.op_types[index] = self.ops[index].get_trivial_type(self);
33+
}
34+
}
35+
}
36+
pub(crate) fn typecheck(&mut self){
37+
while self.op_types.len() < self.ops.len(){
38+
self.op_types.push(None);
39+
}
40+
41+
self.set_trivial_types();
42+
println!("op_types:{:?}",self.op_types);
43+
}
44+
pub(crate) fn into_il_ir(&self)->String{
45+
let output = self.sig.output().il_name();
46+
let mut arg_list = String::new();
47+
let mut arg_iter = self.sig.inputs.iter();
48+
match arg_iter.next(){
49+
Some(start)=>arg_list.push_str(&start.il_name()),
50+
None=>(),
51+
}
52+
for arg in arg_iter{
53+
arg_list.push(',');
54+
arg_list.push_str(&arg.il_name());
55+
}
56+
let mut ops_ir = String::new();
57+
for op in &self.ops{
58+
ops_ir.push_str(&op.clr_ir());
59+
}
60+
format!(".method public static {output} {name}({arg_list}){{\n{ops_ir}}}\n",name = self.name())
61+
}
62+
fn argc(&self) -> u32 {
63+
self.sig.inputs().len() as u32
64+
}
65+
fn remove_sl(&mut self) -> usize {
66+
let mut opt_ops: Vec<BaseIR> = Vec::with_capacity(self.ops.len());
67+
let mut ops_peek = self.ops.iter().peekable();
68+
while let Some(op) = ops_peek.next() {
69+
match op {
70+
BaseIR::STLoc(local_id) => {
71+
if let Some(BaseIR::LDLoc(other_id)) = ops_peek.peek() {
72+
//Ops store and the load the same value, being effectively a NOP.
73+
if local_id == other_id {
74+
ops_peek.next();
75+
continue;
76+
}
77+
}
78+
}
79+
_ => (),
80+
}
81+
opt_ops.push(op.clone());
82+
}
83+
self.ops = opt_ops;
84+
self.ops.len()
85+
}
86+
pub(crate) fn opt(&mut self) {
87+
const MAX_OPT_PASS: usize = 8;
88+
for _ in 0..MAX_OPT_PASS {
89+
let prev_length = self.ops.len();
90+
if !(self.remove_sl() < prev_length) {
91+
continue;
92+
}
93+
}
94+
}
95+
fn has_return(&self) -> bool {
96+
true
97+
}
98+
pub(crate) fn new(sig: FunctionSignature,name:&str) -> Self {
99+
Self {
100+
locals: Vec::new(),
101+
op_types: Vec::with_capacity(0x100),
102+
sig,
103+
name:name.into(),
104+
ops: Vec::with_capacity(0x100),
105+
}
106+
}
107+
fn var_live(&mut self, _local: u32) {
108+
//TODO: use variable lifetimes!
109+
}
110+
fn var_dead(&mut self, _local: u32) {
111+
//TODO: use variable lifetimes!
112+
}
113+
fn local_id_placement(&self, local: u32) -> LocalPlacement {
114+
// I assume local 0 is supposed to be the return value. TODO: check if this is always the case.
115+
if self.has_return() {
116+
if local == 0 {
117+
LocalPlacement::Var(0)
118+
} else if local - 1 < self.argc() {
119+
LocalPlacement::Arg(local - 1)
120+
} else {
121+
LocalPlacement::Var(local - self.argc())
122+
}
123+
} else {
124+
panic!("Can't handle void functions yet. Diagnose MIR to determine what happens to the return var(0)!");
125+
}
126+
}
127+
fn load(&mut self, local: u32) {
128+
self.ops.push(match self.local_id_placement(local) {
129+
LocalPlacement::Arg(arg_id) => BaseIR::LDArg(arg_id),
130+
LocalPlacement::Var(var_id) => BaseIR::LDLoc(var_id),
131+
})
132+
}
133+
fn store(&mut self, local: u32) {
134+
self.ops.push(match self.local_id_placement(local) {
135+
LocalPlacement::Arg(arg_id) => BaseIR::STArg(arg_id),
136+
LocalPlacement::Var(var_id) => BaseIR::STLoc(var_id),
137+
})
138+
}
139+
fn process_constant(&mut self, constant: ConstantKind) {
140+
self.ops.push(match constant {
141+
ConstantKind::Val(value, r#type) => match value {
142+
ConstValue::Scalar(scalar) => match r#type.kind() {
143+
TyKind::Int(IntTy::I32) => BaseIR::LDConstI32(
144+
scalar
145+
.to_i32()
146+
.expect("Type is i32, but odes not fit in i32."),
147+
),
148+
_ => todo!("Unhandled type kind {:?}", r#type.kind()),
149+
},
150+
_ => todo!("Unhanled constant value {value:?}"),
151+
},
152+
_ => todo!("Unhanled constant {constant:?}"),
153+
});
154+
}
155+
// Makes so the top of the stack is the value of RValue
156+
fn process_operand(&mut self, operand: &Operand) {
157+
match operand {
158+
Operand::Copy(place) => self.load(place.local.into()),
159+
//TODO:Do moves need to be treated any diffrently forom copies in the context of CLR?
160+
Operand::Move(place) => self.load(place.local.into()),
161+
Operand::Constant(const_val) => {
162+
self.process_constant(const_val.literal);
163+
}
164+
_ => todo!("Unhanled operand {operand:?}"),
165+
}
166+
}
167+
// Makes so the top of the stack is the value of RValue
168+
fn process_rvalue(&mut self, rvalue: &Rvalue) {
169+
match rvalue {
170+
Rvalue::Use(operand) => self.process_operand(operand),
171+
Rvalue::BinaryOp(binop, operands) => {
172+
let (a, b): (_, _) = (&operands.0, &operands.1);
173+
self.process_operand(a);
174+
self.process_operand(b);
175+
self.ops.push(match binop {
176+
BinOp::Add => BaseIR::Add,
177+
BinOp::Mul => BaseIR::Mul,
178+
BinOp::Shl => BaseIR::Shl,
179+
_ => todo!("Unknown binop:{binop:?}"),
180+
});
181+
}
182+
Rvalue::Aggregate(kind, operands) => {
183+
match kind.as_ref() {
184+
AggregateKind::Adt(def_id, variant_idx, subst_ref, utai, fidx) => {
185+
//let (def_id,variant_idx,subst_ref,utai,fidx) = *adt;
186+
panic!("def_id:{def_id:?},variant_idx:{variant_idx:?},subst_ref:{subst_ref:?},utai:{utai:?},fidx:{fidx:?}");
187+
}
188+
_ => todo!(
189+
"Can't yet handle the aggregate of kind {kind:?} and operands:{operands:?}"
190+
),
191+
}
192+
}
193+
_ => todo!("Can't yet handle a rvalue of type {rvalue:?}"),
194+
}
195+
}
196+
pub(crate) fn add_statement(&mut self, statement: &Statement) {
197+
println!("statement:{statement:?}");
198+
match &statement.kind {
199+
StatementKind::Assign(asign_box) => {
200+
let (place, rvalue) = (asign_box.0, &asign_box.1);
201+
self.process_rvalue(rvalue);
202+
self.store(place.local.into());
203+
//panic!("place:{place:?},rvalue:{rvalue:?}");
204+
}
205+
StatementKind::StorageLive(local) => {
206+
self.var_live((*local).into());
207+
}
208+
StatementKind::StorageDead(local) => {
209+
self.var_dead((*local).into());
210+
}
211+
_ => todo!("Unhanded statement:{:?}", statement.kind),
212+
}
213+
}
214+
pub(crate) fn add_terminator(&mut self, terminator: &Terminator) {
215+
match terminator.kind {
216+
TerminatorKind::Return => {
217+
if self.has_return() {
218+
self.load(0);
219+
self.ops.push(BaseIR::Return);
220+
} else {
221+
todo!("Can't yet return from a void method!");
222+
}
223+
}
224+
_ => todo!("Unknown terminator type {terminator:?}"),
225+
}
226+
}
227+
}

0 commit comments

Comments
 (0)