handled all the abi passing, now just test it

Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
This commit is contained in:
Jakub Doka 2024-12-29 17:37:38 +01:00
parent 68186ec0ce
commit d25540dd52
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
2 changed files with 138 additions and 25 deletions

View file

@ -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

View file

@ -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
}
}
}