From d25540dd528f0cfe276bf51d2d361ee84f0bc290 Mon Sep 17 00:00:00 2001 From: Jakub Doka Date: Sun, 29 Dec 2024 17:37:38 +0100 Subject: [PATCH] handled all the abi passing, now just test it Signed-off-by: Jakub Doka --- cranelift-backend/src/lib.rs | 151 +++++++++++++++++++++++++++----- cranelift-backend/src/x86_64.rs | 12 ++- 2 files changed, 138 insertions(+), 25 deletions(-) diff --git a/cranelift-backend/src/lib.rs b/cranelift-backend/src/lib.rs index 5e961aa..63b63b4 100644 --- a/cranelift-backend/src/lib.rs +++ b/cranelift-backend/src/lib.rs @@ -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, + arg_meta: &mut Vec, ) -> 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, values: &'b mut [Option>], + 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::>(); - 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 diff --git a/cranelift-backend/src/x86_64.rs b/cranelift-backend/src/x86_64.rs index 851d9fb..3c48f0b 100644 --- a/cranelift-backend/src/x86_64.rs +++ b/cranelift-backend/src/x86_64.rs @@ -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, + arg_lens: &mut Vec, ) -> 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, - ) { + ) -> 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 } } }