simplifing code patterns and sixing argument passing

This commit is contained in:
Jakub Doka 2024-10-21 17:04:29 +02:00
parent ad4aed9c98
commit 73c9ccef6a
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
5 changed files with 169 additions and 158 deletions

View file

@ -8,7 +8,7 @@ use {
},
reg,
ty::{self, TyCheck},
Comptime, Field, Func, Global, OffsetIter, ParamAlloc, Reloc, Sig, Struct, SymKey,
Comptime, Field, Func, Global, OffsetIter, PLoc, ParamAlloc, Reloc, Sig, Struct, SymKey,
TypeParser, TypedReloc, Types,
},
alloc::{string::String, vec::Vec},
@ -1037,7 +1037,7 @@ impl Codegen {
);
};
let mut parama = self.tys.parama(ty);
let (_, mut parama) = self.tys.parama(ty);
let base = self.pool.arg_locs.len();
for arg in args {
let arg = self.expr(arg)?;
@ -1402,7 +1402,7 @@ impl Codegen {
unreachable!();
};
let mut parama = self.tys.parama(sig.ret);
let (_, mut parama) = self.tys.parama(sig.ret);
let base = self.pool.arg_locs.len();
let mut sig_args = sig.args.range();
let mut should_momize = !args.is_empty() && sig.ret == ty::Id::from(ty::TYPE);
@ -2135,7 +2135,7 @@ impl Codegen {
self.ci.emit_prelude();
let mut parama = self.tys.parama(sig.ret);
let (ret, mut parama) = self.tys.parama(sig.ret);
let mut sig_args = sig.args.range();
for arg in args.iter() {
let ty = self.tys.ins.args[sig_args.next().unwrap()];
@ -2147,7 +2147,7 @@ impl Codegen {
self.ci.vars.push(Variable { id: arg.id, value: Value { ty, loc } });
}
if self.tys.size_of(sig.ret) > 16 {
if let PLoc::Ref(..) = ret {
let reg = self.ci.regs.allocate();
self.ci.emit(instrs::cp(reg.get(), 1));
self.ci.ret_reg = reg;
@ -2179,20 +2179,21 @@ impl Codegen {
if size == 0 {
return Loc::default();
}
let (src, dst) = match size {
0 => (Loc::default(), Loc::default()),
..=8 if flags & idfl::REFERENCED == 0 => {
(Loc::reg(parama.next()), Loc::reg(self.ci.regs.allocate()))
let (src, dst) = match parama.next(ty, &self.tys) {
PLoc::None => (Loc::default(), Loc::default()),
PLoc::Reg(r, _) if flags & idfl::REFERENCED == 0 => {
(Loc::reg(r), Loc::reg(self.ci.regs.allocate()))
}
1..=8 => (Loc::reg(parama.next()), Loc::stack(self.ci.stack.allocate(size))),
9..=16 => (Loc::reg(parama.next_wide()), Loc::stack(self.ci.stack.allocate(size))),
_ if flags & (idfl::MUTABLE | idfl::REFERENCED) == 0 => {
let ptr = parama.next();
PLoc::Reg(r, _) => (Loc::reg(r), Loc::stack(self.ci.stack.allocate(size))),
PLoc::WideReg(r, _) => (Loc::reg(r), Loc::stack(self.ci.stack.allocate(size))),
PLoc::Ref(ptr, _) if flags & (idfl::MUTABLE | idfl::REFERENCED) == 0 => {
let reg = self.ci.regs.allocate();
self.ci.emit(instrs::cp(reg.get(), ptr));
return Loc::reg(reg).into_derefed();
}
_ => (Loc::reg(parama.next()).into_derefed(), Loc::stack(self.ci.stack.allocate(size))),
PLoc::Ref(ptr, _) => {
(Loc::reg(ptr).into_derefed(), Loc::stack(self.ci.stack.allocate(size)))
}
};
self.store_sized(src, &dst, size);
@ -2265,23 +2266,16 @@ impl Codegen {
}
fn pass_arg(&mut self, value: &Value, parama: &mut ParamAlloc) {
self.pass_arg_low(&value.loc, self.tys.size_of(value.ty), parama)
match parama.next(value.ty, &self.tys) {
PLoc::None => {}
PLoc::Reg(r, _) | PLoc::WideReg(r, _) => {
self.store_typed(&value.loc, Loc::reg(r), value.ty)
}
PLoc::Ref(ptr, _) => {
let Loc::Rt { reg, stack, offset, .. } = &value.loc else { unreachable!() };
self.stack_offset(ptr, reg.get(), stack.as_ref(), *offset as _);
}
fn pass_arg_low(&mut self, loc: &Loc, size: Size, parama: &mut ParamAlloc) {
if size > 16 {
let Loc::Rt { reg, stack, offset, .. } = loc else { unreachable!() };
self.stack_offset(parama.next(), reg.get(), stack.as_ref(), *offset as _);
return;
}
let dst = match size {
0 => return,
9..=16 => Loc::reg(parama.next_wide()),
_ => Loc::reg(parama.next()),
};
self.store_sized(loc, dst, size);
}
fn store_typed(&mut self, src: impl Into<LocCow>, dst: impl Into<LocCow>, ty: ty::Id) {

View file

@ -21,7 +21,8 @@
str_from_raw_parts,
ptr_sub_ptr,
slice_from_ptr_range,
is_sorted
is_sorted,
iter_next_chunk
)]
#![feature(pointer_is_aligned_to)]
#![warn(clippy::dbg_macro)]
@ -247,7 +248,7 @@ mod ty {
ident,
lexer::TokenKind,
parser::{self, Pos},
Size,
Size, Types,
},
core::{num::NonZeroU32, ops::Range},
};
@ -405,6 +406,21 @@ mod ty {
Self::UINT
}
}
pub fn loc(&self, tys: &Types) -> Loc {
match self.expand() {
Kind::Ptr(_) | Kind::Builtin(_) => Loc::Reg,
Kind::Struct(_) if tys.size_of(*self) == 0 => Loc::Reg,
Kind::Struct(_) | Kind::Slice(_) => Loc::Stack,
Kind::Func(_) | Kind::Global(_) | Kind::Module(_) => unreachable!(),
}
}
}
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum Loc {
Reg,
Stack,
}
#[derive(PartialEq, Eq, Default, Debug, Clone, Copy)]
@ -771,15 +787,23 @@ impl Array {
}
}
enum PLoc {
None,
Reg(u8, u16),
WideReg(u8, u16),
Ref(u8, u32),
}
struct ParamAlloc(Range<u8>);
impl ParamAlloc {
pub fn next(&mut self) -> u8 {
self.0.next().expect("too many paramteters")
pub fn next(&mut self, ty: ty::Id, tys: &Types) -> PLoc {
match tys.size_of(ty) {
0 => PLoc::None,
size @ 1..=8 => PLoc::Reg(self.0.next().unwrap(), size as _),
size @ 9..=16 => PLoc::WideReg(self.0.next_chunk::<2>().unwrap()[0], size as _),
size @ 17.. => PLoc::Ref(self.0.next().unwrap(), size),
}
fn next_wide(&mut self) -> u8 {
(self.next(), self.next()).0
}
}
@ -1202,8 +1226,13 @@ impl Types {
instrs::disasm(&mut sluce, &functions, output, eca_handler)
}
fn parama(&self, ret: impl Into<ty::Id>) -> ParamAlloc {
ParamAlloc(2 + (9..=16).contains(&self.size_of(ret.into())) as u8..12)
fn parama(&self, ret: impl Into<ty::Id>) -> (PLoc, ParamAlloc) {
let mut iter = ParamAlloc(1..12);
let ret = iter.next(ret.into(), self);
if let PLoc::None = ret {
iter.0.start += 1;
}
(ret, iter)
}
fn make_ptr(&mut self, base: ty::Id) -> ty::Id {

View file

@ -10,10 +10,10 @@ use {
CtorField, Expr, ExprRef, FileId, Pos,
},
reg, task,
ty::{self, ArrayLen, Tuple},
ty::{self, ArrayLen, Loc, Tuple},
vc::{BitSet, Vc},
Comptime, Func, Global, HashMap, Offset, OffsetIter, Reloc, Sig, TypeParser, TypedReloc,
Types,
Comptime, Func, Global, HashMap, Offset, OffsetIter, PLoc, Reloc, Sig, TypeParser,
TypedReloc, Types,
},
alloc::{string::String, vec::Vec},
core::{
@ -1093,20 +1093,16 @@ impl ItemCtx {
*saved_regs.entry(hvenc).or_insert(would_insert)
};
let mut parama = tys.parama(sig.ret);
let (retl, mut parama) = tys.parama(sig.ret);
for (ti, &arg) in sig.args.range().zip(fuc.nodes[VOID].outputs.iter().skip(2)) {
let ty = tys.ins.args[ti];
if tys.size_of(ty) == 0 {
continue;
}
if let size @ 9..=16 = tys.size_of(ty) {
let rg = parama.next_wide();
self.emit(instrs::st(rg, reg::STACK_PTR, fuc.nodes[arg].offset as _, size as _));
let (rg, size) = match parama.next(ty, tys) {
PLoc::WideReg(rg, size) => (rg, size),
PLoc::Reg(rg, size) if ty.loc(tys) == Loc::Stack => (rg, size),
PLoc::Reg(..) | PLoc::Ref(..) | PLoc::None => continue,
};
self.emit(instrs::st(rg, reg::STACK_PTR, fuc.nodes[arg].offset as _, size));
self.emit(instrs::addi64(rg, reg::STACK_PTR, fuc.nodes[arg].offset as _));
} else {
parama.next();
}
}
for (i, block) in fuc.blocks.iter().enumerate() {
@ -1177,17 +1173,13 @@ impl ItemCtx {
}
}
Kind::Return => {
match tys.size_of(sig.ret) {
0..=8 => {}
size @ 9..=16 => {
self.emit(instrs::ld(reg::RET, atr(allocs[0]), 0, size as _));
match retl {
PLoc::None | PLoc::Reg(..) => {}
PLoc::WideReg(r, size) => {
self.emit(instrs::ld(r, atr(allocs[0]), 0, size))
}
size @ 17.. => {
self.emit(instrs::bmc(
atr(allocs[0]),
reg::RET,
size.try_into().unwrap(),
));
PLoc::Ref(r, size) => {
self.emit(instrs::bmc(atr(allocs[0]), r, size.try_into().unwrap()));
}
}
@ -1243,14 +1235,29 @@ impl ItemCtx {
}
}
Kind::Call { func } => {
let (ret, mut parama) = tys.parama(node.ty);
let mut allocs = allocs.iter();
for ti in tys.ins.funcs[func as usize].sig.unwrap().args.range() {
let ty = tys.ins.args[ti];
let (rg, size) = match parama.next(ty, tys) {
PLoc::Reg(rg, size) if ty.loc(tys) == Loc::Stack => (rg, size),
PLoc::WideReg(rg, size) => (rg, size),
PLoc::None | PLoc::Ref(..) | PLoc::Reg(..) => continue,
};
let &arg = allocs.next().unwrap();
if size > 8 {
allocs.next().unwrap();
}
self.emit(instrs::ld(rg, atr(arg), 0, size));
}
self.relocs.push(TypedReloc {
target: ty::Kind::Func(func).compress(),
reloc: Reloc::new(self.code.len(), 3, 4),
});
self.emit(instrs::jal(reg::RET_ADDR, reg::ZERO, 0));
if let size @ 9..=16 = tys.size_of(node.ty) {
if let PLoc::WideReg(r, size) = ret {
let stck = fuc.nodes[*node.inputs.last().unwrap()].offset;
self.emit(instrs::st(reg::RET, reg::STACK_PTR, stck as _, size as _));
self.emit(instrs::st(r, reg::STACK_PTR, stck as _, size));
}
}
Kind::Global { global } => {
@ -1589,6 +1596,7 @@ impl TypeParser for Codegen<'_> {
code: core::mem::take(&mut self.ci.code),
..Default::default()
};
self.pool.pop_ci(&mut self.ci);
self.complete_call_graph();
@ -2043,12 +2051,8 @@ impl<'a> Codegen<'a> {
let mut inps = Vc::from([self.ci.ctrl]);
for ((arg, carg), tyx) in args.iter().zip(cargs).zip(sig.args.range()) {
let ty = self.tys.ins.args[tyx];
if self.tys.size_of(ty) == 0 {
continue;
}
let mut value = self.expr_ctx(arg, Ctx::default().with_ty(ty))?;
debug_assert_ne!(self.ci.nodes[value.id].kind, Kind::Stre);
debug_assert_ne!(value.id, 0);
self.assert_ty(arg.pos(), &mut value, ty, fa!("argument {}", carg.name));
self.ci.nodes.lock(value.id);
@ -2074,9 +2078,9 @@ impl<'a> Codegen<'a> {
false
});
let alt_value = match self.tys.size_of(sig.ret) {
0..=8 => None,
9.. => {
let alt_value = match sig.ret.loc(&self.tys) {
Loc::Reg => None,
Loc::Stack => {
let stck = self.ci.nodes.new_node_nop(sig.ret, Kind::Stck, [VOID, MEM]);
inps.push(stck);
Some(Value::ptr(stck).ty(sig.ret))
@ -2692,7 +2696,7 @@ impl<'a> Codegen<'a> {
for arg in args.iter() {
let ty = self.tys.ins.args[sig_args.next().unwrap()];
let mut deps = Vc::from([VOID]);
if matches!(self.tys.size_of(ty), 9..=16) {
if ty.loc(&self.tys) == Loc::Stack {
deps.push(MEM);
}
let value = self.ci.nodes.new_node_nop(ty, Kind::Arg, [VOID]);
@ -2994,18 +2998,15 @@ impl<'a> Function<'a> {
}
}
Kind::Return => {
let ops = match self.tys.size_of(self.sig.ret) {
0 => vec![],
1..=8 => {
let ops = match self.tys.parama(self.sig.ret).0 {
PLoc::None => vec![],
PLoc::Reg(r, ..) => {
vec![regalloc2::Operand::reg_fixed_use(
self.rg(node.inputs[1]),
regalloc2::PReg::new(1, regalloc2::RegClass::Int),
regalloc2::PReg::new(r as _, regalloc2::RegClass::Int),
)]
}
9..=16 => {
vec![self.urg(self.nodes[node.inputs[1]].inputs[1])]
}
17.. => {
PLoc::WideReg(..) | PLoc::Ref(..) => {
vec![self.urg(self.nodes[node.inputs[1]].inputs[1])]
}
};
@ -3035,32 +3036,17 @@ impl<'a> Function<'a> {
Kind::Entry => {
self.nodes[nid].ralloc_backref = self.add_block(nid);
let mut parama = self.tys.parama(self.sig.ret);
let (_, mut parama) = self.tys.parama(self.sig.ret);
for (ti, arg) in
self.sig.args.range().zip(self.nodes[VOID].clone().outputs.into_iter().skip(2))
{
let ty = self.tys.ins.args[ti];
match self.tys.size_of(ty) {
0 => continue,
1..=8 => {
match parama.next(ty, self.tys) {
PLoc::None => {}
PLoc::Reg(r, _) | PLoc::WideReg(r, _) | PLoc::Ref(r, _) => {
self.add_instr(NEVER, vec![regalloc2::Operand::reg_fixed_def(
self.rg(arg),
regalloc2::PReg::new(parama.next() as _, regalloc2::RegClass::Int),
)]);
}
9..=16 => {
self.add_instr(NEVER, vec![regalloc2::Operand::reg_fixed_def(
self.rg(arg),
regalloc2::PReg::new(
parama.next_wide() as _,
regalloc2::RegClass::Int,
),
)]);
}
_ => {
self.add_instr(NEVER, vec![regalloc2::Operand::reg_fixed_def(
self.rg(arg),
regalloc2::PReg::new(parama.next() as _, regalloc2::RegClass::Int),
regalloc2::PReg::new(r as _, regalloc2::RegClass::Int),
)]);
}
}
@ -3120,20 +3106,18 @@ impl<'a> Function<'a> {
));
}
let mut parama = self.tys.parama(fuc.ret);
let mut inps = node.inputs[1..].iter();
for ti in fuc.args.range() {
let (ret, mut parama) = self.tys.parama(fuc.ret);
for (ti, &(mut i)) in fuc.args.range().zip(node.inputs[1..].iter()) {
let ty = self.tys.ins.args[ti];
match self.tys.size_of(ty) {
0 => continue,
1..=8 => {
match parama.next(ty, self.tys) {
PLoc::None => {}
PLoc::Reg(r, _) => {
ops.push(regalloc2::Operand::reg_fixed_use(
self.rg(*inps.next().unwrap()),
regalloc2::PReg::new(parama.next() as _, regalloc2::RegClass::Int),
self.rg(i),
regalloc2::PReg::new(r as _, regalloc2::RegClass::Int),
));
}
9..=16 => {
let mut i = *inps.next().unwrap();
PLoc::WideReg(r, _) => {
loop {
match self.nodes[i].kind {
Kind::Stre { .. } => i = self.nodes[i].inputs[2],
@ -3145,15 +3129,14 @@ impl<'a> Function<'a> {
debug_assert!(i != 0);
ops.push(regalloc2::Operand::reg_fixed_use(
self.rg(i),
regalloc2::PReg::new(parama.next() as _, regalloc2::RegClass::Int),
regalloc2::PReg::new(r as _, regalloc2::RegClass::Int),
));
ops.push(regalloc2::Operand::reg_fixed_use(
self.rg(i),
regalloc2::PReg::new(parama.next() as _, regalloc2::RegClass::Int),
regalloc2::PReg::new(r as usize + 1, regalloc2::RegClass::Int),
));
}
_ => {
let mut i = *inps.next().unwrap();
PLoc::Ref(r, _) => {
loop {
match self.nodes[i].kind {
Kind::Stre { .. } => i = self.nodes[i].inputs[2],
@ -3165,21 +3148,18 @@ impl<'a> Function<'a> {
debug_assert!(i != 0);
ops.push(regalloc2::Operand::reg_fixed_use(
self.rg(i),
regalloc2::PReg::new(parama.next() as _, regalloc2::RegClass::Int),
regalloc2::PReg::new(r as _, regalloc2::RegClass::Int),
));
}
}
}
match self.tys.size_of(fuc.ret) {
0..=16 => {}
17.. => {
if let PLoc::Ref(r, _) = ret {
ops.push(regalloc2::Operand::reg_fixed_use(
self.rg(*node.inputs.last().unwrap()),
regalloc2::PReg::new(1, regalloc2::RegClass::Int),
regalloc2::PReg::new(r as _, regalloc2::RegClass::Int),
));
}
}
self.add_instr(nid, ops);
@ -3203,6 +3183,7 @@ impl<'a> Function<'a> {
// .iter()
// .all(|&n| matches!(self.nodes[n].kind, Kind::Stre | Kind::Load)))
// }) => {}
Kind::Stck if self.tys.size_of(node.ty) == 0 => self.nodes.lock(nid),
Kind::Stck => {
let ops = vec![self.drg(nid)];
self.add_instr(nid, ops);
@ -3212,6 +3193,9 @@ impl<'a> Function<'a> {
self.add_instr(nid, ops);
}
Kind::Phi | Kind::Arg | Kind::Mem => {}
Kind::Load { .. } if matches!(self.tys.size_of(node.ty), 0 | 9..) => {
self.nodes.lock(nid)
}
Kind::Load { .. } => {
let mut region = node.inputs[1];
if self.nodes[region].kind == (Kind::BinOp { op: TokenKind::Add })
@ -3219,14 +3203,12 @@ impl<'a> Function<'a> {
{
region = self.nodes[region].inputs[1]
}
if self.tys.size_of(node.ty) <= 8 {
let ops = match self.nodes[region].kind {
Kind::Stck => vec![self.drg(nid)],
_ => vec![self.drg(nid), self.urg(region)],
};
self.add_instr(nid, ops);
}
}
Kind::Stre if node.inputs[2] == VOID => self.nodes.lock(nid),
Kind::Stre => {
let mut region = node.inputs[2];

View file

@ -47,6 +47,9 @@ main:
CP r2, r3
CP r4, r5
CP r6, r7
LD r2, r2, 0a, 16h
LD r4, r4, 0a, 16h
LD r6, r6, 0a, 16h
JAL r31, r0, :line
ADDI64 r7, r254, 0d
ADDI64 r5, r254, 16d
@ -61,6 +64,9 @@ main:
CP r2, r3
CP r4, r5
CP r6, r7
LD r2, r2, 0a, 16h
LD r4, r4, 0a, 16h
LD r6, r6, 0a, 16h
JAL r31, r0, :rect_line
JAL r31, r0, :example
LD r31, r254, 96a, 16h
@ -86,7 +92,6 @@ rect_line:
2: ADDI64 r9, r9, 1d
JMP :4
1: JALA r0, r31, 0a
timed out
code size: 797
ret: 0
code size: 875
ret: 4
status: Ok(())

View file

@ -14,29 +14,30 @@ main:
ADDI64 r254, r254, 56d
JALA r0, r31, 0a
maina:
ADDI64 r254, r254, -88d
ST r31, r254, 24a, 64h
ADDI64 r254, r254, -100d
ST r31, r254, 28a, 72h
ADDI64 r32, r254, 24d
JAL r31, r0, :small_struct
LI64 r32, 1d
LI64 r33, 3d
LI64 r34, 0d
ADDI64 r35, r254, 0d
ADDI64 r36, r254, 16d
ST r34, r254, 16a, 1h
ST r34, r254, 17a, 1h
ST r34, r254, 18a, 1h
ST r33, r254, 19a, 1h
ST r32, r254, 20a, 1h
ST r34, r254, 21a, 1h
ST r34, r254, 22a, 1h
ST r34, r254, 23a, 1h
LD r37, r254, 16a, 8h
ST r37, r254, 0a, 8h
LI64 r33, 1d
LI64 r34, 3d
LI64 r35, 0d
ADDI64 r36, r254, 0d
ADDI64 r37, r254, 16d
ST r35, r254, 16a, 1h
ST r35, r254, 17a, 1h
ST r35, r254, 18a, 1h
ST r34, r254, 19a, 1h
ST r33, r254, 20a, 1h
ST r35, r254, 21a, 1h
ST r35, r254, 22a, 1h
ST r35, r254, 23a, 1h
LD r38, r254, 16a, 8h
ST r38, r254, 8a, 8h
LD r1, r35, 0a, 16h
LD r31, r254, 24a, 64h
ADDI64 r254, r254, 88d
ST r38, r254, 0a, 8h
LD r39, r254, 16a, 8h
ST r39, r254, 8a, 8h
LD r1, r36, 0a, 16h
LD r31, r254, 28a, 72h
ADDI64 r254, r254, 100d
JALA r0, r31, 0a
small_struct:
ADDI64 r254, r254, -4d
@ -47,6 +48,6 @@ small_struct:
LD r1, r254, 0a, 4h
ADDI64 r254, r254, 4d
JALA r0, r31, 0a
code size: 532
code size: 543
ret: 2
status: Ok(())