Skip to content

Commit

Permalink
Added support for calling functiomn pointers
Browse files Browse the repository at this point in the history
  • Loading branch information
FractalFir committed Dec 30, 2023
1 parent b440a7c commit 5946c83
Show file tree
Hide file tree
Showing 13 changed files with 243 additions and 66 deletions.
23 changes: 21 additions & 2 deletions src/assembly_exporter/ilasm_op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,21 @@ pub fn op_cli(op: &crate::cil::CILOp) -> Cow<'static, str> {
.into()
}
}
CILOp::CallI(sig)=>{
let mut inputs_iter = sig.inputs().iter();
let mut input_string = String::new();
if let Some(firts_arg) = inputs_iter.next() {
input_string.push_str(&non_void_type_cil(firts_arg));
}
for arg in inputs_iter {
input_string.push(',');
input_string.push_str(&non_void_type_cil(arg));
}
format!(
"calli {output} ({input_string})",
output = type_cil(sig.output())
).into()
}
CILOp::LDFtn(call_site)=>{
//assert!(sig.inputs.is_empty());
let mut inputs_iter = call_site.explicit_inputs().iter();
Expand Down Expand Up @@ -429,7 +444,7 @@ pub fn non_void_type_cil(tpe: &Type) -> Cow<'static, str> {
}
pub fn type_cil(tpe: &Type) -> Cow<'static, str> {
match tpe {
Type::DelegatePtr(sig)=>{
Type::DelegatePtr(sig) => {
let mut inputs_iter = sig.inputs().iter();
let mut input_string = String::new();
if let Some(firts_arg) = inputs_iter.next() {
Expand All @@ -439,7 +454,11 @@ pub fn type_cil(tpe: &Type) -> Cow<'static, str> {
input_string.push(',');
input_string.push_str(&non_void_type_cil(arg));
}
format!("method {output}*({input_string})",output = type_cil(sig.output())).into()
format!(
"method {output}*({input_string})",
output = type_cil(sig.output())
)
.into()
}
Type::FnDef(name) => format!("valuetype fn_{name}").into(),
Type::Void => "void".into(),
Expand Down
32 changes: 21 additions & 11 deletions src/bin/rustflags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ fn main() {
let build_env = rustc_codegen_clr::compile_test::cargo_build_env();
let print_raw_env = std::env::args().any(|arg| arg == "--print_raw_env");
let setup_command = std::env::args().any(|arg| arg == "--setup_command");
if print_raw_env{
if print_raw_env {
println!("\"{build_env}\"");
return;
}
if setup_command{
if setup_command {
#[cfg(target_family = "unix")]
println!("export RUSTFLAGS=\"{build_env}\"");
#[cfg(target_family = "windows")]
println!("$Env:RUSTFLAGS = '{build_env}'");
return
return;
}
println!("Welcome to the `rustc_codegen_clr` environment setup helper!");
println!("This tool will help you use the codegen to compile Rust projects.");
Expand All @@ -24,32 +24,40 @@ fn main() {
println!("\"{build_env}\"");
println!();
println!();
#[cfg(target_family = "unix")]{
println!("You may use the following command to quickly set the required environment variables:");
#[cfg(target_family = "unix")]
{
println!(
"You may use the following command to quickly set the required environment variables:"
);
println!();
println!();
println!("export RUSTFLAGS=\"{build_env}\"");
println!();
println!();
}
#[cfg(target_family = "windows")]{
println!("You may use the following command to quickly set the required environment variables:");
#[cfg(target_family = "windows")]
{
println!(
"You may use the following command to quickly set the required environment variables:"
);
println!();
println!();
println!("$Env:RUSTFLAGS = '{build_env}'");
println!();
println!();
}
println!("After you are done working with `rustc_codegen_clr` either unset the environment variable OR restart your shell (close the command prompt window).");
#[cfg(target_family = "unix")]{
#[cfg(target_family = "unix")]
{
println!("You may use the following command to quickly unset the required environment variables:");
println!();
println!();
println!("unset RUSTFLAGS");
println!();
println!();
}
#[cfg(target_family = "windows")]{
#[cfg(target_family = "windows")]
{
println!();
}
println!("Please note that those variables may change when the codegen is updated/rebuilt.");
Expand All @@ -58,7 +66,9 @@ fn main() {
println!("If you are using the project, please remember to:");
println!("1. Update BOTH rustc and the project on a regular basis.");
println!("2. Report compiler bugs to the maintainers of `rustc_codegen_clr`, and not the maintainers of the Rust compiler as a whole.");
println!(" In 99.999% of the cases, the bug is within this project and not the Rust compiler.");
println!(
" In 99.999% of the cases, the bug is within this project and not the Rust compiler."
);
println!("");
// std::env::set_var("RUSTFLAGS", build_env);
// std::env::set_var("RUSTFLAGS", build_env);
}
46 changes: 42 additions & 4 deletions src/checked_binop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,42 @@ fn add(tpe: Type) -> Box<[CILOp]> {
)),
)
.into(),
Type::I128 => {
eprintln!("WARING: checked 128 bit arthmetics ARE NOT SUPPOPRTED YET. Using unchecked variants, bugs may occur.");
let tuple = crate::r#type::simple_tuple(&[tpe.clone(), Type::Bool]);
let tuple_ty: Type = tuple.clone().into();
[
CILOp::Call(
CallSite::new(
Some(DotnetTypeRef::uint_128()),
"op_Multiplication".into(),
crate::function_sig::FnSig::new(&[Type::I128, Type::I128], &Type::I128),
true,
)
.into(),
),
CILOp::NewTMPLocal(tpe.clone().into()),
CILOp::SetTMPLocal,
CILOp::NewTMPLocal(tuple_ty.into()),
CILOp::LoadAddresOfTMPLocal,
CILOp::LoadUnderTMPLocal(1),
CILOp::STField(FieldDescriptor::boxed(
tuple.clone(),
Type::I128,
"Item1".into(),
)),
CILOp::LoadAddresOfTMPLocal,
CILOp::LdcI32(0),
CILOp::STField(FieldDescriptor::boxed(
tuple.clone(),
Type::Bool,
"Item2".into(),
)),
CILOp::LoadTMPLocal,
CILOp::FreeTMPLocal,
]
.into()
}
_ => todo!("Can't preform checked add on type {tpe:?} yet!"),
}
}
Expand Down Expand Up @@ -715,7 +751,7 @@ fn sub(tpe: Type) -> Box<[CILOp]> {
true,
)),
CILOp::Call(CallSite::boxed(
Some(DotnetTypeRef::int_128()),
Some(DotnetTypeRef::int_128()),
"op_Implicit".into(),
FnSig::new(&[Type::I32], &Type::I128),
true,
Expand All @@ -732,7 +768,8 @@ fn sub(tpe: Type) -> Box<[CILOp]> {
FnSig::new(&[Type::I128, Type::I128], &Type::Bool),
true,
)),
).into(),
)
.into(),
Type::U128 => checked_sub_128bit(
Type::U128,
CILOp::Call(CallSite::boxed(
Expand All @@ -742,7 +779,7 @@ fn sub(tpe: Type) -> Box<[CILOp]> {
true,
)),
CILOp::Call(CallSite::boxed(
Some(DotnetTypeRef::uint_128()),
Some(DotnetTypeRef::uint_128()),
"op_Implicit".into(),
FnSig::new(&[Type::I32], &Type::U128),
true,
Expand All @@ -759,7 +796,8 @@ fn sub(tpe: Type) -> Box<[CILOp]> {
FnSig::new(&[Type::U128, Type::U128], &Type::Bool),
true,
)),
).into(),
)
.into(),
_ => todo!("Can't preform checked sub on type {tpe:?} yet!"),
}
}
Expand Down
11 changes: 10 additions & 1 deletion src/cil/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ pub enum CILOp {
STStaticField(Box<StaticFieldDescriptor>),
/// Copies to *dst* from *src* *count* bytes.
CpBlk,
/// Calls the variable on top of the stack as a function with signature `sig`.
CallI(Box<FnSig>),
}
impl CILOp {
/// If this op is a branch operation, and its target is `original`, replaces the target with `replacement`
Expand All @@ -260,7 +262,7 @@ impl CILOp {
Self::Call(site) => Some(site),
Self::CallVirt(site) => Some(site),
Self::NewObj(site) => Some(site),
Self::LDFtn(site)=>Some(site),
Self::LDFtn(site) => Some(site),
_ => None,
}
}
Expand Down Expand Up @@ -449,6 +451,13 @@ impl CILOp {
CILOp::SetTMPLocal => -1,
CILOp::LDFtn(_) => 1,
CILOp::LoadGlobalAllocPtr { alloc_id: _ } => 1,
CILOp::CallI(fn_sig) => {
if fn_sig.output() == &crate::r#type::Type::Void {
-(1 + fn_sig.inputs().len() as isize)
} else {
1 - (1 + fn_sig.inputs().len() as isize)
}
}
}
}
/// Flips a conditional, changing the order of its arguments. Eg. BLt(a,b) [a < b] becomes BGt(b,a) [b > a].
Expand Down
28 changes: 20 additions & 8 deletions src/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,22 +195,28 @@ fn create_const_from_slice<'ctx>(
)),
CILOp::ConvUSize(false),
],
IntTy::I128=>{
let value = u128::from_ne_bytes(bytes[..std::mem::size_of::<i128>()].try_into().expect("Invalid slice!"));
IntTy::I128 => {
let value = u128::from_ne_bytes(
bytes[..std::mem::size_of::<i128>()]
.try_into()
.expect("Invalid slice!"),
);
let low = (value & u128::from(u64::MAX)) as u64;
let high = (value << 64) as u64;
let low = i64::from_ne_bytes(low.to_ne_bytes());
let high = i64::from_ne_bytes(high.to_ne_bytes());
let ctor_sig =
crate::function_sig::FnSig::new(&[Type::U64, Type::U64], &Type::Void);
vec![CILOp::LdcI64(high),
vec![
CILOp::LdcI64(high),
CILOp::LdcI64(low),
CILOp::NewObj(CallSite::boxed(
Some(DotnetTypeRef::int_128()),
".ctor".into(),
ctor_sig,
true,
))]
)),
]
}
},
TyKind::Uint(int) => match int {
Expand Down Expand Up @@ -240,22 +246,28 @@ fn create_const_from_slice<'ctx>(
)),
CILOp::ConvUSize(false),
],
UintTy::U128=>{
let value = u128::from_ne_bytes(bytes[..std::mem::size_of::<u128>()].try_into().expect("Invalid slice!"));
UintTy::U128 => {
let value = u128::from_ne_bytes(
bytes[..std::mem::size_of::<u128>()]
.try_into()
.expect("Invalid slice!"),
);
let low = (value & u128::from(u64::MAX)) as u64;
let high = (value << 64) as u64;
let low = i64::from_ne_bytes(low.to_ne_bytes());
let high = i64::from_ne_bytes(high.to_ne_bytes());
let ctor_sig =
crate::function_sig::FnSig::new(&[Type::U64, Type::U64], &Type::Void);
vec![CILOp::LdcI64(high),
vec![
CILOp::LdcI64(high),
CILOp::LdcI64(low),
CILOp::NewObj(CallSite::boxed(
Some(DotnetTypeRef::uint_128()),
".ctor".into(),
ctor_sig,
true,
))]
)),
]
}
},
TyKind::RawPtr(type_and_mut) => match type_and_mut.ty.kind() {
Expand Down
24 changes: 23 additions & 1 deletion src/function_sig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{
codegen_error::CodegenError,
r#type::{TyCache, Type},
};
use rustc_middle::ty::{Instance, List, ParamEnv, ParamEnvAnd, TyCtxt, TyKind};
use rustc_middle::ty::{Instance, List, ParamEnv, ParamEnvAnd, PolyFnSig, TyCtxt, TyKind};
use rustc_target::abi::call::Conv;
use rustc_target::spec::abi::Abi as TargetAbi;
use serde::{Deserialize, Serialize};
Expand All @@ -13,6 +13,28 @@ pub struct FnSig {
output: Type,
}
impl FnSig {
/// Creates a `FnSig` from ``. May not match the result of `sig_from_instance_`!
/// Use ONLY for function pointers!
pub fn from_poly_sig<'tyctx>(
method_instance: Option<Instance<'tyctx>>,
tyctx: TyCtxt<'tyctx>,
tycache: &mut TyCache,
sig: PolyFnSig<'tyctx>,
) -> Self {
let sig = if let Some(method_instance) = method_instance {
crate::utilis::monomorphize(&method_instance, sig, tyctx)
} else {
sig
};
let sig = sig.skip_binder();
let output = tycache.type_from_cache(sig.output(), tyctx, method_instance);
let inputs: Box<[Type]> = sig
.inputs()
.iter()
.map(|input| tycache.type_from_cache(*input, tyctx, method_instance))
.collect();
FnSig::new(&inputs, &output)
}
/// Returns the signature of function behind `function`.
pub fn sig_from_instance_<'tcx>(
function: Instance<'tcx>,
Expand Down
10 changes: 10 additions & 0 deletions src/place/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,16 @@ pub fn deref_op<'ctx>(
type_cache.type_from_cache(derefed_type, tyctx, Some(*method_instance));
vec![CILOp::LdObj(derefed_type.into())]
}
TyKind::FnPtr(_) => {
let derefed_type =
type_cache.type_from_cache(derefed_type, tyctx, Some(*method_instance));
vec![CILOp::LdObj(derefed_type.into())]
}
TyKind::Closure(_,_) => {
let derefed_type =
type_cache.type_from_cache(derefed_type, tyctx, Some(*method_instance));
vec![CILOp::LdObj(derefed_type.into())]
}
_ => todo!("TODO: can't deref type {derefed_type:?} yet"),
}
} else {
Expand Down
Loading

0 comments on commit 5946c83

Please sign in to comment.