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,
|
||||
cranelift_codegen::{
|
||||
CodegenError, Final, FinalizedMachReloc, MachBufferFinalized,
|
||||
ir::{InstBuilder, MemFlags, UserExternalName},
|
||||
ir::{InstBuilder, MemFlags, TrapCode, UserExternalName},
|
||||
isa::{LookupError, TargetIsa},
|
||||
settings::Configurable,
|
||||
},
|
||||
|
@ -15,7 +15,7 @@ use {
|
|||
nodes::Kind,
|
||||
utils::{Ent, EntVec},
|
||||
},
|
||||
std::{fmt::Display, ops::Range, usize},
|
||||
std::{fmt::Display, ops::Range},
|
||||
};
|
||||
|
||||
mod x86_64;
|
||||
|
@ -220,8 +220,10 @@ impl hblang::backend::Backend for Backend {
|
|||
tys,
|
||||
files,
|
||||
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 =
|
||||
cranelift_codegen::ir::UserFuncName::User(cranelift_codegen::ir::UserExternalName {
|
||||
|
@ -242,17 +244,23 @@ fn build_signature(
|
|||
sig: hblang::ty::Sig,
|
||||
types: &hblang::ty::Types,
|
||||
signature: &mut cranelift_codegen::ir::Signature,
|
||||
arg_lens: &mut Vec<usize>,
|
||||
arg_meta: &mut Vec<AbiMeta>,
|
||||
) -> bool {
|
||||
signature.clear(call_conv);
|
||||
match call_conv {
|
||||
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!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct AbiMeta {
|
||||
trough_mem: bool,
|
||||
arg_count: usize,
|
||||
}
|
||||
|
||||
struct FuncBuilder<'a, 'b> {
|
||||
bl: cranelift_frontend::FunctionBuilder<'b>,
|
||||
isa: &'a dyn TargetIsa,
|
||||
|
@ -260,32 +268,48 @@ struct FuncBuilder<'a, 'b> {
|
|||
tys: &'a hblang::ty::Types,
|
||||
files: &'a hblang::utils::EntSlice<hblang::ty::Module, hblang::parser::Ast>,
|
||||
values: &'b mut [Option<Result<cranelift_codegen::ir::Value, cranelift_codegen::ir::Block>>],
|
||||
arg_lens: &'a [AbiMeta],
|
||||
stack_ret: bool,
|
||||
}
|
||||
|
||||
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();
|
||||
self.bl.append_block_params_for_function_params(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();
|
||||
self.values[hblang::nodes::MEM as usize] = Some(Ok(ret_ptr));
|
||||
}
|
||||
|
||||
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 args = nodes[hblang::nodes::VOID].outputs[hblang::nodes::ARG_START..].iter();
|
||||
while let Some(aty) = typs.next(tys) {
|
||||
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();
|
||||
if ty.is_aggregate(tys) {
|
||||
todo!()
|
||||
if !abi_meta.trough_mem && ty.is_aggregate(tys) {
|
||||
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 {
|
||||
let loc = arg_vals.take(..abi_meta.arg_count).unwrap();
|
||||
debug_assert_eq!(loc.len(), 1);
|
||||
self.values[arg as usize] = Some(Ok(loc[0]));
|
||||
}
|
||||
|
@ -402,8 +426,42 @@ impl FuncBuilder<'_, '_> {
|
|||
}
|
||||
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]);
|
||||
|
||||
self.bl.ins().return_(&[ret]);
|
||||
self.close_block(block);
|
||||
self.emit_node(node.outputs[0], block);
|
||||
|
@ -435,7 +493,7 @@ impl FuncBuilder<'_, '_> {
|
|||
&mut signature,
|
||||
&mut arg_lens,
|
||||
);
|
||||
assert!(!stack_ret, "TODO");
|
||||
|
||||
let func_ref = 'b: {
|
||||
let user_name_ref = self.bl.func.declare_imported_user_function(
|
||||
cranelift_codegen::ir::UserExternalName {
|
||||
|
@ -451,7 +509,7 @@ impl FuncBuilder<'_, '_> {
|
|||
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 {
|
||||
name: cranelift_codegen::ir::ExternalName::user(user_name_ref),
|
||||
|
@ -460,15 +518,66 @@ impl FuncBuilder<'_, '_> {
|
|||
})
|
||||
};
|
||||
|
||||
let args = node.inputs[1..][..args.len()]
|
||||
.iter()
|
||||
.map(|&n| self.value_of(n))
|
||||
.collect::<Vec<_>>();
|
||||
let inst = self.bl.ins().call(func_ref, &args);
|
||||
let mut ir_args = vec![];
|
||||
|
||||
if stack_ret {
|
||||
ir_args.push(self.value_of(*node.inputs.last().unwrap()));
|
||||
}
|
||||
|
||||
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) {
|
||||
[] => {}
|
||||
[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() {
|
||||
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
|
||||
// https://github.com/jckarter/clay/blob/db0bd2702ab0b6e48965cd85f8859bbd5f60e48e/compiler/externals.cpp
|
||||
|
||||
use crate::AbiMeta;
|
||||
|
||||
pub fn build_systemv_signature(
|
||||
sig: hblang::ty::Sig,
|
||||
types: &hblang::ty::Types,
|
||||
signature: &mut cranelift_codegen::ir::Signature,
|
||||
arg_lens: &mut Vec<usize>,
|
||||
arg_lens: &mut Vec<AbiMeta>,
|
||||
) -> bool {
|
||||
let mut alloca = Alloca::new();
|
||||
|
||||
|
@ -20,8 +22,8 @@ pub fn build_systemv_signature(
|
|||
let mut args = sig.args.args();
|
||||
while let Some(arg) = args.next_value(types) {
|
||||
let prev = signature.params.len();
|
||||
alloca.next(true, arg, types, &mut signature.params);
|
||||
arg_lens.push(signature.params.len() - prev);
|
||||
let trough_mem = alloca.next(true, arg, types, &mut signature.params);
|
||||
arg_lens.push(AbiMeta { arg_count: signature.params.len() - prev, trough_mem });
|
||||
}
|
||||
|
||||
stack_ret
|
||||
|
@ -238,7 +240,7 @@ impl Alloca {
|
|||
arg: hblang::ty::Id,
|
||||
cx: &hblang::ty::Types,
|
||||
dest: &mut Vec<cranelift_codegen::ir::AbiParam>,
|
||||
) {
|
||||
) -> bool {
|
||||
let mut cls_or_mem = classify_arg(cx, arg);
|
||||
|
||||
if is_arg {
|
||||
|
@ -283,6 +285,7 @@ impl Alloca {
|
|||
cranelift_codegen::ir::ArgumentPurpose::StructReturn,
|
||||
));
|
||||
}
|
||||
true
|
||||
}
|
||||
Ok(ref cls) => {
|
||||
// split into sized chunks passed individually
|
||||
|
@ -293,6 +296,7 @@ impl Alloca {
|
|||
reg_component(cls, &mut 0, cx.size_of(arg)).unwrap(),
|
||||
));
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue