handled all the abi passing, now just test it
Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
This commit is contained in:
parent
68186ec0ce
commit
d25540dd52
|
@ -4,7 +4,7 @@ use {
|
||||||
core::panic,
|
core::panic,
|
||||||
cranelift_codegen::{
|
cranelift_codegen::{
|
||||||
CodegenError, Final, FinalizedMachReloc, MachBufferFinalized,
|
CodegenError, Final, FinalizedMachReloc, MachBufferFinalized,
|
||||||
ir::{InstBuilder, MemFlags, UserExternalName},
|
ir::{InstBuilder, MemFlags, TrapCode, UserExternalName},
|
||||||
isa::{LookupError, TargetIsa},
|
isa::{LookupError, TargetIsa},
|
||||||
settings::Configurable,
|
settings::Configurable,
|
||||||
},
|
},
|
||||||
|
@ -15,7 +15,7 @@ use {
|
||||||
nodes::Kind,
|
nodes::Kind,
|
||||||
utils::{Ent, EntVec},
|
utils::{Ent, EntVec},
|
||||||
},
|
},
|
||||||
std::{fmt::Display, ops::Range, usize},
|
std::{fmt::Display, ops::Range},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod x86_64;
|
mod x86_64;
|
||||||
|
@ -220,8 +220,10 @@ impl hblang::backend::Backend for Backend {
|
||||||
tys,
|
tys,
|
||||||
files,
|
files,
|
||||||
values: &mut vec![None; nodes.len()],
|
values: &mut vec![None; nodes.len()],
|
||||||
|
arg_lens: &lens,
|
||||||
|
stack_ret,
|
||||||
}
|
}
|
||||||
.build(tys.ins.funcs[id].sig, &lens, stack_ret);
|
.build(tys.ins.funcs[id].sig);
|
||||||
|
|
||||||
self.ctx.func.name =
|
self.ctx.func.name =
|
||||||
cranelift_codegen::ir::UserFuncName::User(cranelift_codegen::ir::UserExternalName {
|
cranelift_codegen::ir::UserFuncName::User(cranelift_codegen::ir::UserExternalName {
|
||||||
|
@ -242,17 +244,23 @@ fn build_signature(
|
||||||
sig: hblang::ty::Sig,
|
sig: hblang::ty::Sig,
|
||||||
types: &hblang::ty::Types,
|
types: &hblang::ty::Types,
|
||||||
signature: &mut cranelift_codegen::ir::Signature,
|
signature: &mut cranelift_codegen::ir::Signature,
|
||||||
arg_lens: &mut Vec<usize>,
|
arg_meta: &mut Vec<AbiMeta>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
signature.clear(call_conv);
|
signature.clear(call_conv);
|
||||||
match call_conv {
|
match call_conv {
|
||||||
cranelift_codegen::isa::CallConv::SystemV => {
|
cranelift_codegen::isa::CallConv::SystemV => {
|
||||||
x86_64::build_systemv_signature(sig, types, signature, arg_lens)
|
x86_64::build_systemv_signature(sig, types, signature, arg_meta)
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct AbiMeta {
|
||||||
|
trough_mem: bool,
|
||||||
|
arg_count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
struct FuncBuilder<'a, 'b> {
|
struct FuncBuilder<'a, 'b> {
|
||||||
bl: cranelift_frontend::FunctionBuilder<'b>,
|
bl: cranelift_frontend::FunctionBuilder<'b>,
|
||||||
isa: &'a dyn TargetIsa,
|
isa: &'a dyn TargetIsa,
|
||||||
|
@ -260,32 +268,48 @@ struct FuncBuilder<'a, 'b> {
|
||||||
tys: &'a hblang::ty::Types,
|
tys: &'a hblang::ty::Types,
|
||||||
files: &'a hblang::utils::EntSlice<hblang::ty::Module, hblang::parser::Ast>,
|
files: &'a hblang::utils::EntSlice<hblang::ty::Module, hblang::parser::Ast>,
|
||||||
values: &'b mut [Option<Result<cranelift_codegen::ir::Value, cranelift_codegen::ir::Block>>],
|
values: &'b mut [Option<Result<cranelift_codegen::ir::Value, cranelift_codegen::ir::Block>>],
|
||||||
|
arg_lens: &'a [AbiMeta],
|
||||||
|
stack_ret: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FuncBuilder<'_, '_> {
|
impl FuncBuilder<'_, '_> {
|
||||||
pub fn build(mut self, sig: hblang::ty::Sig, arg_lens: &[usize], stack_ret: bool) {
|
pub fn build(mut self, sig: hblang::ty::Sig) {
|
||||||
let entry = self.bl.create_block();
|
let entry = self.bl.create_block();
|
||||||
self.bl.append_block_params_for_function_params(entry);
|
self.bl.append_block_params_for_function_params(entry);
|
||||||
self.bl.switch_to_block(entry);
|
self.bl.switch_to_block(entry);
|
||||||
let mut arg_vals = self.bl.block_params(entry);
|
let mut arg_vals = &self.bl.block_params(entry).to_vec()[..];
|
||||||
|
|
||||||
if stack_ret {
|
if self.stack_ret {
|
||||||
let ret_ptr = *arg_vals.take_first().unwrap();
|
let ret_ptr = *arg_vals.take_first().unwrap();
|
||||||
self.values[hblang::nodes::MEM as usize] = Some(Ok(ret_ptr));
|
self.values[hblang::nodes::MEM as usize] = Some(Ok(ret_ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
let Self { nodes, tys, .. } = self;
|
let Self { nodes, tys, .. } = self;
|
||||||
|
|
||||||
let mut parama_len = arg_lens.iter();
|
let mut parama_len = self.arg_lens[(self.tys.size_of(sig.ret) != 0) as usize..].iter();
|
||||||
let mut typs = sig.args.args();
|
let mut typs = sig.args.args();
|
||||||
let mut args = nodes[hblang::nodes::VOID].outputs[hblang::nodes::ARG_START..].iter();
|
let mut args = nodes[hblang::nodes::VOID].outputs[hblang::nodes::ARG_START..].iter();
|
||||||
while let Some(aty) = typs.next(tys) {
|
while let Some(aty) = typs.next(tys) {
|
||||||
let hblang::ty::Arg::Value(ty) = aty else { continue };
|
let hblang::ty::Arg::Value(ty) = aty else { continue };
|
||||||
let loc = arg_vals.take(..*parama_len.next().unwrap()).unwrap();
|
let abi_meta = parama_len.next().unwrap();
|
||||||
let &arg = args.next().unwrap();
|
let &arg = args.next().unwrap();
|
||||||
if ty.is_aggregate(tys) {
|
if !abi_meta.trough_mem && ty.is_aggregate(tys) {
|
||||||
todo!()
|
let slot = self.bl.create_sized_stack_slot(cranelift_codegen::ir::StackSlotData {
|
||||||
|
kind: cranelift_codegen::ir::StackSlotKind::ExplicitSlot,
|
||||||
|
size: self.tys.size_of(ty),
|
||||||
|
align_shift: self.tys.align_of(ty).ilog2() as _,
|
||||||
|
});
|
||||||
|
let loc = arg_vals.take(..abi_meta.arg_count).unwrap();
|
||||||
|
assert!(loc.len() <= 2, "NEED handling");
|
||||||
|
let align =
|
||||||
|
loc.iter().map(|&p| self.bl.func.dfg.value_type(p).bytes()).max().unwrap();
|
||||||
|
let mut offset = 0i32;
|
||||||
|
for &v in loc {
|
||||||
|
self.bl.ins().stack_store(v, slot, offset);
|
||||||
|
offset += align as i32;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
let loc = arg_vals.take(..abi_meta.arg_count).unwrap();
|
||||||
debug_assert_eq!(loc.len(), 1);
|
debug_assert_eq!(loc.len(), 1);
|
||||||
self.values[arg as usize] = Some(Ok(loc[0]));
|
self.values[arg as usize] = Some(Ok(loc[0]));
|
||||||
}
|
}
|
||||||
|
@ -402,8 +426,42 @@ impl FuncBuilder<'_, '_> {
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Kind::Return { .. } | Kind::Die => {
|
Kind::Die => {
|
||||||
|
self.bl.ins().trap(TrapCode::unwrap_user(1));
|
||||||
|
self.close_block(block);
|
||||||
|
self.emit_node(node.outputs[0], block);
|
||||||
|
Err(self.block_of(block))
|
||||||
|
}
|
||||||
|
Kind::Return { .. } => {
|
||||||
|
let mut ir_args = vec![];
|
||||||
|
if node.inputs[1] == hblang::nodes::VOID {
|
||||||
|
} else {
|
||||||
|
let abi_meta = self.arg_lens[0];
|
||||||
|
let arg = node.inputs[1];
|
||||||
|
if !abi_meta.trough_mem && self.nodes[node.inputs[1]].ty.is_aggregate(self.tys)
|
||||||
|
{
|
||||||
|
let loc = self.bl.func.signature.returns.clone();
|
||||||
|
assert!(loc.len() <= 2, "NEED handling");
|
||||||
|
let align = loc.iter().map(|&p| p.value_type.bytes()).max().unwrap();
|
||||||
|
let mut offset = 0i32;
|
||||||
|
let src = self.value_of(self.nodes[arg].inputs[1]);
|
||||||
|
debug_assert!(self.nodes[arg].kind == Kind::Load);
|
||||||
|
for &v in &loc {
|
||||||
|
ir_args.push(self.bl.ins().load(
|
||||||
|
v.value_type,
|
||||||
|
MemFlags::new(),
|
||||||
|
src,
|
||||||
|
offset,
|
||||||
|
));
|
||||||
|
offset += align as i32;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ir_args.push(self.value_of(arg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let ret = self.value_of(node.inputs[1]);
|
let ret = self.value_of(node.inputs[1]);
|
||||||
|
|
||||||
self.bl.ins().return_(&[ret]);
|
self.bl.ins().return_(&[ret]);
|
||||||
self.close_block(block);
|
self.close_block(block);
|
||||||
self.emit_node(node.outputs[0], block);
|
self.emit_node(node.outputs[0], block);
|
||||||
|
@ -435,7 +493,7 @@ impl FuncBuilder<'_, '_> {
|
||||||
&mut signature,
|
&mut signature,
|
||||||
&mut arg_lens,
|
&mut arg_lens,
|
||||||
);
|
);
|
||||||
assert!(!stack_ret, "TODO");
|
|
||||||
let func_ref = 'b: {
|
let func_ref = 'b: {
|
||||||
let user_name_ref = self.bl.func.declare_imported_user_function(
|
let user_name_ref = self.bl.func.declare_imported_user_function(
|
||||||
cranelift_codegen::ir::UserExternalName {
|
cranelift_codegen::ir::UserExternalName {
|
||||||
|
@ -451,7 +509,7 @@ impl FuncBuilder<'_, '_> {
|
||||||
break 'b id;
|
break 'b id;
|
||||||
}
|
}
|
||||||
|
|
||||||
let signature = self.bl.func.import_signature(signature);
|
let signature = self.bl.func.import_signature(signature.clone());
|
||||||
|
|
||||||
self.bl.func.import_function(cranelift_codegen::ir::ExtFuncData {
|
self.bl.func.import_function(cranelift_codegen::ir::ExtFuncData {
|
||||||
name: cranelift_codegen::ir::ExternalName::user(user_name_ref),
|
name: cranelift_codegen::ir::ExternalName::user(user_name_ref),
|
||||||
|
@ -460,15 +518,66 @@ impl FuncBuilder<'_, '_> {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
let args = node.inputs[1..][..args.len()]
|
let mut ir_args = vec![];
|
||||||
.iter()
|
|
||||||
.map(|&n| self.value_of(n))
|
if stack_ret {
|
||||||
.collect::<Vec<_>>();
|
ir_args.push(self.value_of(*node.inputs.last().unwrap()));
|
||||||
let inst = self.bl.ins().call(func_ref, &args);
|
}
|
||||||
|
|
||||||
|
let mut params = signature.params.as_slice();
|
||||||
|
let mut parama_len =
|
||||||
|
arg_lens[(self.tys.size_of(node.ty) != 0) as usize..].iter();
|
||||||
|
let mut typs = args.args();
|
||||||
|
let mut args = node.inputs[1..].iter();
|
||||||
|
while let Some(aty) = typs.next(self.tys) {
|
||||||
|
let hblang::ty::Arg::Value(ty) = aty else { continue };
|
||||||
|
let abi_meta = parama_len.next().unwrap();
|
||||||
|
let &arg = args.next().unwrap();
|
||||||
|
if !abi_meta.trough_mem && ty.is_aggregate(self.tys) {
|
||||||
|
let loc = params.take(..abi_meta.arg_count).unwrap();
|
||||||
|
assert!(loc.len() <= 2, "NEED handling");
|
||||||
|
let align = loc.iter().map(|&p| p.value_type.bytes()).max().unwrap();
|
||||||
|
let mut offset = 0i32;
|
||||||
|
let src = self.value_of(self.nodes[arg].inputs[1]);
|
||||||
|
debug_assert!(self.nodes[arg].kind == Kind::Load);
|
||||||
|
for &v in loc {
|
||||||
|
ir_args.push(self.bl.ins().load(
|
||||||
|
v.value_type,
|
||||||
|
MemFlags::new(),
|
||||||
|
src,
|
||||||
|
offset,
|
||||||
|
));
|
||||||
|
offset += align as i32;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let loc = params.take(..abi_meta.arg_count).unwrap();
|
||||||
|
debug_assert_eq!(loc.len(), 1);
|
||||||
|
ir_args.push(self.value_of(arg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let inst = self.bl.ins().call(func_ref, &ir_args);
|
||||||
match *self.bl.inst_results(inst) {
|
match *self.bl.inst_results(inst) {
|
||||||
[] => {}
|
[] => {}
|
||||||
[scala] => self.values[nid as usize] = Some(Ok(scala)),
|
[scala] => self.values[nid as usize] = Some(Ok(scala)),
|
||||||
_ => todo!(),
|
[a, b] => {
|
||||||
|
assert!(!stack_ret);
|
||||||
|
let slot = self.value_of(*node.inputs.last().unwrap());
|
||||||
|
|
||||||
|
let loc = [a, b];
|
||||||
|
assert!(loc.len() <= 2, "NEED handling");
|
||||||
|
let align = loc
|
||||||
|
.iter()
|
||||||
|
.map(|&p| self.bl.func.dfg.value_type(p).bytes())
|
||||||
|
.max()
|
||||||
|
.unwrap();
|
||||||
|
let mut offset = 0i32;
|
||||||
|
for v in loc {
|
||||||
|
self.bl.ins().store(MemFlags::new(), v, slot, offset);
|
||||||
|
offset += align as i32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
for &o in node.outputs.iter().rev() {
|
for &o in node.outputs.iter().rev() {
|
||||||
if self.nodes[o].inputs[0] == nid
|
if self.nodes[o].inputs[0] == nid
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
// The classification code for the x86_64 ABI is taken from the clay language
|
// The classification code for the x86_64 ABI is taken from the clay language
|
||||||
// https://github.com/jckarter/clay/blob/db0bd2702ab0b6e48965cd85f8859bbd5f60e48e/compiler/externals.cpp
|
// https://github.com/jckarter/clay/blob/db0bd2702ab0b6e48965cd85f8859bbd5f60e48e/compiler/externals.cpp
|
||||||
|
|
||||||
|
use crate::AbiMeta;
|
||||||
|
|
||||||
pub fn build_systemv_signature(
|
pub fn build_systemv_signature(
|
||||||
sig: hblang::ty::Sig,
|
sig: hblang::ty::Sig,
|
||||||
types: &hblang::ty::Types,
|
types: &hblang::ty::Types,
|
||||||
signature: &mut cranelift_codegen::ir::Signature,
|
signature: &mut cranelift_codegen::ir::Signature,
|
||||||
arg_lens: &mut Vec<usize>,
|
arg_lens: &mut Vec<AbiMeta>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut alloca = Alloca::new();
|
let mut alloca = Alloca::new();
|
||||||
|
|
||||||
|
@ -20,8 +22,8 @@ pub fn build_systemv_signature(
|
||||||
let mut args = sig.args.args();
|
let mut args = sig.args.args();
|
||||||
while let Some(arg) = args.next_value(types) {
|
while let Some(arg) = args.next_value(types) {
|
||||||
let prev = signature.params.len();
|
let prev = signature.params.len();
|
||||||
alloca.next(true, arg, types, &mut signature.params);
|
let trough_mem = alloca.next(true, arg, types, &mut signature.params);
|
||||||
arg_lens.push(signature.params.len() - prev);
|
arg_lens.push(AbiMeta { arg_count: signature.params.len() - prev, trough_mem });
|
||||||
}
|
}
|
||||||
|
|
||||||
stack_ret
|
stack_ret
|
||||||
|
@ -238,7 +240,7 @@ impl Alloca {
|
||||||
arg: hblang::ty::Id,
|
arg: hblang::ty::Id,
|
||||||
cx: &hblang::ty::Types,
|
cx: &hblang::ty::Types,
|
||||||
dest: &mut Vec<cranelift_codegen::ir::AbiParam>,
|
dest: &mut Vec<cranelift_codegen::ir::AbiParam>,
|
||||||
) {
|
) -> bool {
|
||||||
let mut cls_or_mem = classify_arg(cx, arg);
|
let mut cls_or_mem = classify_arg(cx, arg);
|
||||||
|
|
||||||
if is_arg {
|
if is_arg {
|
||||||
|
@ -283,6 +285,7 @@ impl Alloca {
|
||||||
cranelift_codegen::ir::ArgumentPurpose::StructReturn,
|
cranelift_codegen::ir::ArgumentPurpose::StructReturn,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
true
|
||||||
}
|
}
|
||||||
Ok(ref cls) => {
|
Ok(ref cls) => {
|
||||||
// split into sized chunks passed individually
|
// split into sized chunks passed individually
|
||||||
|
@ -293,6 +296,7 @@ impl Alloca {
|
||||||
reg_component(cls, &mut 0, cx.size_of(arg)).unwrap(),
|
reg_component(cls, &mut 0, cx.size_of(arg)).unwrap(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue