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

View file

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