Skip to content

Commit d28a3fa

Browse files
committed
Drop functions are now detected. Array type can now be constructed, but lacks associated methods required to index into.
1 parent 684e8cb commit d28a3fa

18 files changed

+274
-46
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
*.rlib
33
*.il
44
*.o
5+
*.d
6+
*.rmeta
7+
*.lock
58
test/out
69
/target
710
/Cargo.lock

src/aggregate.rs

+28-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::cil_op::{CILOp, FieldDescriptor};
2-
use crate::r#type::Type;
2+
use crate::r#type::{DotnetTypeRef, Type};
33
use crate::utilis::field_name;
44
use rustc_index::IndexVec;
55
use rustc_middle::mir::{AggregateKind, Operand, Place};
@@ -48,6 +48,33 @@ pub fn handle_aggregate<'tcx>(
4848
active_field,
4949
)
5050
}
51+
AggregateKind::Array(element) => {
52+
let element = Type::from_ty(*element, tcx);
53+
let array_type = DotnetTypeRef::array(element.clone(), field_index.len());
54+
let mut ops: Vec<CILOp> = Vec::with_capacity(fields.len() * 2);
55+
let array_getter =
56+
super::place::place_adress(&target_location, tcx, method, method_instance);
57+
let sig = crate::function_sig::FnSig::new(
58+
&[array_type.clone().into(), element, Type::USize],
59+
&Type::Void,
60+
);
61+
let call_site =
62+
crate::cil_op::CallSite::boxed(Some(array_type), "set_Item".into(), sig, false);
63+
for field in fields {
64+
ops.extend(array_getter.iter().cloned());
65+
ops.extend(field.1);
66+
ops.push(CILOp::LdcI64(field.0 as u64 as i64));
67+
ops.push(CILOp::ConvISize(false));
68+
ops.push(CILOp::Call(call_site.clone()));
69+
}
70+
ops.extend(super::place::place_get(
71+
&target_location,
72+
tcx,
73+
method,
74+
method_instance,
75+
));
76+
ops
77+
}
5178
_ => todo!("Unsuported aggregate kind {aggregate_kind:?}"),
5279
}
5380
}

src/assembly_exporter/ilasm_exporter.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
r#type::{DotnetTypeRef, Type},
77
type_def::TypeDef,
88
};
9-
use std::{borrow::Cow, io::Write};
9+
use std::{borrow::Cow, io::Write, ops::Deref};
1010
#[must_use]
1111
pub(crate) struct ILASMExporter {
1212
encoded_asm: Vec<u8>,
@@ -196,7 +196,7 @@ fn op_cli(op: &crate::cil_op::CILOp) -> Cow<'static, str> {
196196
"".into()
197197
} else {
198198
//assert!(sig.inputs.is_empty());
199-
let mut inputs_iter = call_site.signature().inputs().iter();
199+
let mut inputs_iter = call_site.explicit_inputs().iter();
200200
let mut input_string = String::new();
201201
if let Some(firts_arg) = inputs_iter.next() {
202202
input_string.push_str(&arg_type_cli(firts_arg));
@@ -211,7 +211,9 @@ fn op_cli(op: &crate::cil_op::CILOp) -> Cow<'static, str> {
211211
"instance"
212212
};
213213
let owner_name = match &call_site.class() {
214-
Some(owner) => format!("{}::", dotnet_type_ref_cli(owner)),
214+
Some(owner) => {
215+
format!("{}::", prefixed_type_cli(&owner.deref().clone().into()))
216+
}
215217
None => String::new(),
216218
};
217219
//println!("inputs:{inputs:?} input_string: {input_string}",inputs = call_site.signature.inputs);
@@ -455,7 +457,7 @@ fn op_cli(op: &crate::cil_op::CILOp) -> Cow<'static, str> {
455457
"".into()
456458
} else {
457459
//assert!(sig.inputs.is_empty());
458-
let mut inputs_iter = call_site.signature().inputs().iter();
460+
let mut inputs_iter = call_site.explicit_inputs().iter();
459461
let mut input_string = String::new();
460462
if let Some(firts_arg) = inputs_iter.next() {
461463
input_string.push_str(&arg_type_cli(firts_arg));

src/cil_op.rs

+12
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,18 @@ impl CallSite {
110110
};
111111
true
112112
}
113+
/// All inputs. Includes impilcit `this` argument for instance functions.
114+
pub fn inputs(&self) -> &[crate::r#type::Type] {
115+
&self.signature.inputs()
116+
}
117+
/// Inputs, with the implicit `this` skipped if needed.
118+
pub fn explicit_inputs(&self) -> &[crate::r#type::Type] {
119+
if self.is_static || self.inputs().is_empty() {
120+
&self.signature.inputs()
121+
} else {
122+
&self.signature.inputs()[1..]
123+
}
124+
}
113125
}
114126
use serde::{Deserialize, Serialize};
115127
/// Represenation of a CIL opcode.

src/compile_test.rs

+9-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
fn test_dotnet_executable(file_path: &str, test_dir: &str) {
32
use std::io::Write;
43

@@ -36,7 +35,7 @@ fn test_dotnet_executable(file_path: &str, test_dir: &str) {
3635
"Test program failed with message {stderr:}"
3736
);
3837
}
39-
if !(*IS_DOTNET_PRESENT || *IS_MONO_PRESENT){
38+
if !(*IS_DOTNET_PRESENT || *IS_MONO_PRESENT) {
4039
panic!("You must have either mono or dotnet runtime installed to run tests.");
4140
}
4241
}
@@ -115,10 +114,11 @@ macro_rules! run_test {
115114
};
116115
}
117116
#[cfg(debug_assertions)]
118-
fn build_backend() ->Result<(),String>{
117+
fn build_backend() -> Result<(), String> {
119118
let out = std::process::Command::new("cargo")
120119
.args(["build"])
121-
.output().map_err(|err| err.to_string())?;
120+
.output()
121+
.map_err(|err| err.to_string())?;
122122
/*
123123
if out.stderr.len() > 0{
124124
return Err(String::from_utf8(out.stderr).expect("Non UTF8 error message!"));
@@ -170,14 +170,15 @@ test_lib! {calls}
170170
test_lib! {casts}
171171
test_lib! {identity}
172172
test_lib! {libc}
173-
test_lib! {nbody}
173+
174174
test_lib! {references}
175175
//test_lib! {structs}
176176

177177
test_lib! {types}
178178

179179
run_test! {arthm,add}
180180
run_test! {types,enums}
181+
run_test! {types,nbody}
181182
run_test! {types,structs}
182183
run_test! {types,vec}
183184
run_test! {std,main}
@@ -213,7 +214,7 @@ lazy_static! {
213214
}}"
214215
)
215216
};
216-
static ref IS_MONO_PRESENT: bool = std::process::Command::new("mono").output().is_ok() ;
217-
static ref IS_DOTNET_PRESENT: bool = std::process::Command::new("dotnet").output().is_ok() ;
218-
static ref RUSTC_BUILD_STATUS: Result<(),String> = build_backend();
217+
static ref IS_MONO_PRESENT: bool = std::process::Command::new("mono").output().is_ok();
218+
static ref IS_DOTNET_PRESENT: bool = std::process::Command::new("dotnet").output().is_ok();
219+
static ref RUSTC_BUILD_STATUS: Result<(), String> = build_backend();
219220
}

src/function_sig.rs

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ impl FnSig {
2525
pub fn output(&self) -> &Type {
2626
&self.output
2727
}
28+
/// Creates a new function signature. For non-static functions, this must include the hidden first `this` argument!
2829
pub fn new(inputs: &[Type], output: &Type) -> Self {
2930
Self {
3031
inputs: inputs.into(),

src/place.rs

+80-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// This file contains many unnecesary morphize calls.
22
use crate::cil_op::{CILOp, FieldDescriptor};
3-
use crate::r#type::DotnetTypeRef;
3+
use crate::r#type::{DotnetTypeRef, Type};
44
use crate::utilis::field_name;
55
use rustc_middle::mir::{Place, PlaceElem};
66
use rustc_middle::ty::{Instance, IntTy, Ty, TyCtxt, TyKind, UintTy};
@@ -25,11 +25,22 @@ fn pointed_type(ty: PlaceTy) -> Ty {
2525
fn body_ty_is_by_adress(last_ty: &Ty) -> bool {
2626
match *last_ty.kind() {
2727
TyKind::Int(_) => false,
28+
TyKind::Float(_) => false,
2829
TyKind::Uint(_) => false,
2930
TyKind::Adt(_, _) => true,
31+
TyKind::Array(_, _) => true,
32+
3033
TyKind::Ref(_region, _inner, _mut) => false,
3134
TyKind::RawPtr(_) => false,
32-
_ => todo!("TODO: body_ty_is_by_adress does not support type {last_ty:?}"),
35+
TyKind::Bool => false,
36+
TyKind::Char => false,
37+
//TODO: check if slices are handled propely
38+
TyKind::Slice(_) => true,
39+
TyKind::Str => true,
40+
_ => todo!(
41+
"TODO: body_ty_is_by_adress does not support type {last_ty:?} kind:{kind:?}",
42+
kind = last_ty.kind()
43+
),
3344
}
3445
}
3546
fn local_get(local: usize, method: &rustc_middle::mir::Body) -> CILOp {
@@ -119,6 +130,33 @@ fn place_elem_get<'a>(
119130
//todo!("Can't get fields of enum variants yet!");
120131
}
121132
},
133+
PlaceElem::Index(index) => {
134+
let mut ops = vec![crate::place::local_adress(
135+
index.as_usize(),
136+
ctx.optimized_mir(method_instance.def_id()),
137+
)];
138+
let curr_ty = curr_type.as_ty().expect("Can't index into enum!");
139+
let tpe = Type::from_ty(curr_ty, ctx);
140+
let class = if let Type::DotnetType(dotnet) = &tpe {
141+
dotnet
142+
} else {
143+
panic!("Can't index into type {tpe:?}");
144+
};
145+
let index_ty = Type::USize;
146+
let element_ty = crate::r#type::element_type(curr_ty);
147+
148+
let signature = crate::function_sig::FnSig::new(
149+
&[tpe.clone(), index_ty],
150+
&Type::from_ty(element_ty, ctx),
151+
);
152+
ops.push(CILOp::Call(crate::cil_op::CallSite::boxed(
153+
Some(class.as_ref().clone()),
154+
"get_Item".into(),
155+
signature,
156+
false,
157+
)));
158+
ops
159+
}
122160
_ => todo!("Can't handle porojection {place_elem:?} in get"),
123161
}
124162
}
@@ -228,6 +266,46 @@ fn place_elem_body<'ctx>(
228266
let variant_type = PlaceTy::EnumVariant(curr_type, variant.as_u32());
229267
(variant_type, vec![CILOp::LDFieldAdress(field_desc)])
230268
}
269+
PlaceElem::Index(index) => {
270+
let mut ops = vec![crate::place::local_adress(
271+
index.as_usize(),
272+
tyctx.optimized_mir(method_instance.def_id()),
273+
)];
274+
let curr_ty = curr_type.as_ty().expect("Can't index into enum!");
275+
let tpe = Type::from_ty(curr_ty, tyctx);
276+
let class = if let Type::DotnetType(dotnet) = &tpe {
277+
dotnet
278+
} else {
279+
panic!("Can't index into type {tpe:?}");
280+
};
281+
let index_ty = Type::USize;
282+
let element_ty = crate::r#type::element_type(curr_ty);
283+
if body_ty_is_by_adress(&element_ty) {
284+
let signature = crate::function_sig::FnSig::new(
285+
&[tpe.clone(), index_ty],
286+
&Type::Ptr(Box::new(Type::from_ty(element_ty, tyctx))),
287+
);
288+
ops.push(CILOp::Call(crate::cil_op::CallSite::boxed(
289+
Some(class.as_ref().clone()),
290+
"get_Adress".into(),
291+
signature,
292+
false,
293+
)));
294+
(element_ty.into(), ops)
295+
} else {
296+
let signature = crate::function_sig::FnSig::new(
297+
&[tpe.clone(), index_ty],
298+
&Type::from_ty(element_ty, tyctx),
299+
);
300+
ops.push(CILOp::Call(crate::cil_op::CallSite::boxed(
301+
Some(class.as_ref().clone()),
302+
"get_Item".into(),
303+
signature,
304+
false,
305+
)));
306+
(element_ty.into(), ops)
307+
}
308+
}
231309
_ => todo!("Can't handle porojection {place_elem:?} in body"),
232310
}
233311
}

src/rvalue.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::cil_op::CILOp;
1+
use crate::cil_op::{CILOp, CallSite};
22
use rustc_middle::mir::{CastKind, NullOp};
33
use rustc_middle::{
44
mir::{Place, Rvalue},
@@ -117,6 +117,25 @@ pub fn handle_rvalue<'tcx>(
117117
)));
118118
ops
119119
}
120+
Rvalue::Len(operand) => {
121+
let mut ops = crate::place::place_adress(operand, tcx, method, method_instance);
122+
let tpe = operand.ty(method, tcx);
123+
let class = crate::r#type::Type::from_ty(tpe.ty, tcx)
124+
.as_dotnet()
125+
.expect("Can't get the dotnet type!");
126+
let signature = crate::function_sig::FnSig::new(
127+
&[class.clone().into()],
128+
&crate::r#type::Type::USize,
129+
);
130+
ops.push(CILOp::Call(CallSite::boxed(
131+
Some(class),
132+
"GetLength".into(),
133+
signature,
134+
false,
135+
)));
136+
ops
137+
//todo!("Can't get the length of {operand:?}");
138+
}
120139
_ => todo!("Unhandled RValue {rvalue:?}"),
121140
};
122141
res

src/terminator.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -132,12 +132,14 @@ pub fn handle_terminator<'ctx>(
132132
)]
133133
}
134134
TerminatorKind::Drop {
135-
place: _,
135+
place,
136136
target,
137137
unwind: _,
138138
replace: _,
139139
} => {
140-
eprintln!("WARNING: drop is not supported yet in rustc_codegen_clr!");
140+
let ty = monomorphize(&method_instance, place.ty(method, tyctx).ty, tyctx);
141+
let drop_instance = Instance::resolve_drop_in_place(tyctx, ty).polymorphize(tyctx);
142+
eprintln!("WARNING: drop is not supported yet in rustc_codegen_clr! drop_instance:{drop_instance:?}");
141143
vec![
142144
CILOp::Comment("WARNING: drop is not supported yet in rustc_codegen_clr!".into()),
143145
CILOp::GoTo(target.as_u32()),

src/type.rs

+31-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::IString;
22
use rustc_middle::ty::{
3-
AdtDef, FloatTy, GenericArg, Instance, IntTy, ParamEnv, Ty, TyCtxt, TyKind, UintTy,
3+
AdtDef, ClosureKind, FloatTy, GenericArg, Instance, IntTy, ParamEnv, Ty, TyCtxt, TyKind, UintTy,
44
};
55
/// This struct represetnts either a primitive .NET type (F32,F64), or stores information on how to lookup a more complex type (struct,class,array)
66
use serde::{Deserialize, Serialize};
@@ -51,6 +51,12 @@ impl DotnetTypeRef {
5151
generics: Vec::new(),
5252
}
5353
}
54+
pub fn array(element: Type, length: usize) -> Self {
55+
let name = format!("Arr{length}");
56+
let mut array = DotnetTypeRef::new(None, &name);
57+
array.set_generics([element]);
58+
array
59+
}
5460
pub fn append_path(&mut self, append: &str) {
5561
let mut name_path = self.name_path.to_string();
5662
name_path.push_str(append);
@@ -150,7 +156,19 @@ impl Type {
150156
TyKind::FnPtr(_) => Type::USize,
151157
TyKind::Param(param_ty) => Type::GenericArg(param_ty.index),
152158
TyKind::Alias(_, alias_ty) => Self::from_ty(alias_ty.self_ty(), tyctx),
153-
//TyKind::Closure(def_id,subst)=>Self::from_ty(Instance::resolve(tyctx,ParamEnv::empty(),*def_id,subst).unwrap().unwrap().ty(tyctx,ParamEnv::empty()),tyctx),
159+
TyKind::Closure(def_id, subst) => {
160+
// this is wrong.
161+
let kind = ClosureKind::FnOnce;
162+
let closure = Instance::resolve_closure(tyctx, *def_id, subst, kind)
163+
.expect("Could not resolve closure!");
164+
Self::from_ty(closure.ty(tyctx, ParamEnv::empty()), tyctx)
165+
}
166+
TyKind::Array(element, length) => {
167+
let length = crate::utilis::try_resolve_const_size(length).unwrap();
168+
169+
let element = Type::from_ty(*element, tyctx);
170+
DotnetTypeRef::array(element, length).into()
171+
}
154172
_ => todo!("Unsupported type{rust_tpe:?}!"),
155173
}
156174
}
@@ -187,3 +205,14 @@ impl From<&FloatTy> for Type {
187205
}
188206
}
189207
}
208+
pub fn element_type<'tyctx>(src: Ty<'tyctx>) -> Ty<'tyctx> {
209+
match src.kind() {
210+
TyKind::Array(element, _) => *element,
211+
_ => panic!("Can't get element type of {src:?}"),
212+
}
213+
}
214+
impl From<DotnetTypeRef> for Type {
215+
fn from(value: DotnetTypeRef) -> Self {
216+
Self::DotnetType(Box::new(value))
217+
}
218+
}

0 commit comments

Comments
 (0)