uptimizing a bit more, inline calls
This commit is contained in:
parent
641be15703
commit
ad3fc1190c
|
@ -239,7 +239,7 @@ main := fn(): int {
|
|||
align_of_Type_in_bytes := @alignof(foo.Type)
|
||||
hardcoded_pointer := @as(^u8, @bitcast(10))
|
||||
ecall_that_returns_int := @eca(int, 1, foo.Type.(10, 20), 5, 6)
|
||||
return 0
|
||||
return @inline(foo.foo)
|
||||
}
|
||||
|
||||
// in module: foo.hb
|
||||
|
@ -248,6 +248,8 @@ Type := struct {
|
|||
brah: int,
|
||||
blah: int,
|
||||
}
|
||||
|
||||
foo := fn(): int return 0
|
||||
```
|
||||
|
||||
- `@use(<string>)`: imports a module based of string, the string is passed to a loader that can be customized, default loader uses following syntax:
|
||||
|
@ -257,7 +259,8 @@ Type := struct {
|
|||
- `@intcast(<expr>)`: needs to be used when conversion of `@TypeOf(<expr>)` would loose precision (widening of integers is implicit)
|
||||
- `@sizeof(<ty>), @alignof(<ty>)`: I think explaining this would insult your intelligence
|
||||
- `@bitcast(<expr>)`: tell compiler to assume `@TypeOf(<expr>)` is whatever is inferred, so long as size and alignment did not change
|
||||
- `@eca(<ty>, <expr>...)`: invoke `eca` instruction, where `<ty>` is the type this will return and `<expr>...` are arguments passed to the call
|
||||
- `@eca(<ty>, ...<expr>)`: invoke `eca` instruction, where `<ty>` is the type this will return and `<expr>...` are arguments passed to the call
|
||||
- `@inline(<func>, ...<args>)`: equivalent to `<func>(...<args>)` but function is guaranteed to inline, compiler will otherwise never inline
|
||||
|
||||
#### c_strings
|
||||
```hb
|
||||
|
@ -324,6 +327,17 @@ pass := fn(arr: ^[int; 3]): int {
|
|||
}
|
||||
```
|
||||
|
||||
#### inline
|
||||
```hb
|
||||
main := fn(): int {
|
||||
return @inline(foo, 1, 2, 3) - 6
|
||||
}
|
||||
|
||||
foo := fn(a: int, b: int, c: int): int {
|
||||
return a + b + c
|
||||
}
|
||||
```
|
||||
|
||||
### Incomplete Examples
|
||||
|
||||
#### comptime_pointers
|
||||
|
|
|
@ -8,8 +8,7 @@ use {
|
|||
parser::{self, find_symbol, idfl, CtorField, Expr, ExprRef, FileId, Pos},
|
||||
HashMap,
|
||||
},
|
||||
core::panic,
|
||||
std::{ops::Range, rc::Rc},
|
||||
std::{ops::Range, rc::Rc, usize},
|
||||
};
|
||||
|
||||
type Offset = u32;
|
||||
|
@ -635,6 +634,13 @@ impl Loc {
|
|||
Self::Rt { stack: Some(stack), reg: reg::STACK_PTR.into(), derefed: true, offset: 0 }
|
||||
}
|
||||
|
||||
fn get_reg(&self) -> reg::Id {
|
||||
match self {
|
||||
Self::Rt { reg, .. } => reg.as_ref(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn reg(reg: impl Into<reg::Id>) -> Self {
|
||||
let reg = reg.into();
|
||||
assert!(reg.get() != 0);
|
||||
|
@ -779,6 +785,15 @@ impl ItemCtx {
|
|||
debug_assert!(reloc.offset < len);
|
||||
}
|
||||
|
||||
if let Some(last_ret) = self.ret_relocs.last()
|
||||
&& last_ret.offset as usize == output.code.len() - 5
|
||||
{
|
||||
output.code.truncate(output.code.len() - 5);
|
||||
self.ret_relocs.pop();
|
||||
}
|
||||
|
||||
let len = output.code.len() as Offset;
|
||||
|
||||
self.stack.finalize_leaked();
|
||||
for rel in self.stack_relocs.drain(..) {
|
||||
rel.apply_stack_offset(&mut output.code[base as usize..], &self.stack)
|
||||
|
@ -1046,6 +1061,24 @@ pub struct Snapshot {
|
|||
strings: usize,
|
||||
}
|
||||
|
||||
impl Snapshot {
|
||||
fn _sub(&mut self, other: &Self) {
|
||||
self.code -= other.code;
|
||||
self.string_data -= other.string_data;
|
||||
self.funcs -= other.funcs;
|
||||
self.globals -= other.globals;
|
||||
self.strings -= other.strings;
|
||||
}
|
||||
|
||||
fn _add(&mut self, other: &Self) {
|
||||
self.code += other.code;
|
||||
self.string_data += other.string_data;
|
||||
self.funcs += other.funcs;
|
||||
self.globals += other.globals;
|
||||
self.strings += other.strings;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Output {
|
||||
code: Vec<u8>,
|
||||
|
@ -1348,6 +1381,7 @@ impl Codegen {
|
|||
pub fn generate(&mut self) {
|
||||
self.output.emit_entry_prelude();
|
||||
self.find_or_declare(0, 0, Err("main"), "");
|
||||
self.make_func_reachable(0);
|
||||
self.complete_call_graph_low();
|
||||
self.link();
|
||||
}
|
||||
|
@ -1474,6 +1508,53 @@ impl Codegen {
|
|||
let val = self.ty(val);
|
||||
Some(Value::ty(self.tys.make_ptr(val)))
|
||||
}
|
||||
E::Directive { name: "inline", args: [func_ast, args @ ..], .. } => {
|
||||
let ty::Kind::Func(mut func) = self.ty(func_ast).expand() else {
|
||||
self.report(func_ast.pos(), "first argument of inline needs to be a function");
|
||||
};
|
||||
|
||||
let fuc = self.tys.funcs[func as usize];
|
||||
let fast = self.files[fuc.file as usize].clone();
|
||||
let E::BinOp { right: &E::Closure { args: cargs, body, .. }, .. } =
|
||||
fuc.expr.get(&fast).unwrap()
|
||||
else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
let scope = self.ci.vars.len();
|
||||
let sig = self.compute_signature(&mut func, func_ast.pos(), args)?;
|
||||
|
||||
if scope == self.ci.vars.len() {
|
||||
for ((arg, ty), carg) in
|
||||
args.iter().zip(sig.args.view(&self.tys.args).to_owned()).zip(cargs)
|
||||
{
|
||||
let loc = self.expr_ctx(arg, Ctx::default().with_ty(ty))?.loc;
|
||||
self.ci.vars.push(Variable { id: carg.id, value: Value { ty, loc } });
|
||||
}
|
||||
}
|
||||
|
||||
let ret_reloc_base = self.ci.ret_relocs.len();
|
||||
|
||||
let loc = self.alloc_ret(sig.ret, ctx, false);
|
||||
let prev_ret_reg = std::mem::replace(&mut self.ci.ret_reg, loc.get_reg());
|
||||
self.expr(body);
|
||||
self.ci.ret_reg = prev_ret_reg;
|
||||
|
||||
//if let Some(last_ret) = self.ci.ret_relocs.last()
|
||||
// && last_ret.offset as usize + self.ci.snap.code == self.output.code.len() - 5
|
||||
//{
|
||||
// self.output.code.truncate(self.output.code.len() - 5);
|
||||
// self.ci.ret_relocs.pop();
|
||||
//}
|
||||
let len = self.output.code.len() as u32;
|
||||
for mut rel in self.ci.ret_relocs.drain(ret_reloc_base..) {
|
||||
rel.offset += self.ci.snap.code as u32;
|
||||
rel.shifted = true;
|
||||
rel.apply_jump(&mut self.output.code, len);
|
||||
}
|
||||
|
||||
return Some(Value { ty: sig.ret, loc });
|
||||
}
|
||||
E::Directive { name: "TypeOf", args: [expr], .. } => {
|
||||
let snap = self.output.snap();
|
||||
let value = self.expr(expr).unwrap();
|
||||
|
@ -1495,7 +1576,7 @@ impl Codegen {
|
|||
self.ci.free_loc(value);
|
||||
}
|
||||
|
||||
let loc = self.alloc_ret(ty, ctx);
|
||||
let loc = self.alloc_ret(ty, ctx, false);
|
||||
|
||||
self.output.emit(eca());
|
||||
|
||||
|
@ -1797,72 +1878,27 @@ impl Codegen {
|
|||
self.report(fast.pos(), "can't call this, maybe in the future");
|
||||
};
|
||||
|
||||
// TODO: this will be usefull but not now
|
||||
let scope = self.ci.vars.len();
|
||||
//let mut snap = self.output.snap();
|
||||
//snap.sub(&self.ci.snap);
|
||||
//let prev_stack_rel = self.ci.stack_relocs.len();
|
||||
//let prev_ret_rel = self.ci.ret_relocs.len();
|
||||
let sig = self.compute_signature(&mut func, expr.pos(), args)?;
|
||||
//self.ci.ret_relocs.truncate(prev_ret_rel);
|
||||
//self.ci.stack_relocs.truncate(prev_stack_rel);
|
||||
//snap.add(&self.ci.snap);
|
||||
//self.output.trunc(&snap);
|
||||
self.ci.vars.truncate(scope);
|
||||
|
||||
let fuc = self.tys.funcs[func as usize];
|
||||
let ast = self.files[fuc.file as usize].clone();
|
||||
let E::BinOp { right: &E::Closure { args: cargs, ret, .. }, .. } =
|
||||
let E::BinOp { right: &E::Closure { args: cargs, .. }, .. } =
|
||||
fuc.expr.get(&ast).unwrap()
|
||||
else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
let sig = if let Some(sig) = fuc.sig {
|
||||
sig
|
||||
} else {
|
||||
let scope = self.ci.vars.len();
|
||||
let arg_base = self.tys.args.len();
|
||||
|
||||
for (arg, carg) in args.iter().zip(cargs) {
|
||||
let ty = self.ty(&carg.ty);
|
||||
log::dbg!("arg: {}", self.ty_display(ty));
|
||||
self.tys.args.push(ty);
|
||||
let sym = parser::find_symbol(&ast.symbols, carg.id);
|
||||
let loc = if sym.flags & idfl::COMPTIME == 0 {
|
||||
// FIXME: could fuck us
|
||||
Loc::default()
|
||||
} else {
|
||||
debug_assert_eq!(
|
||||
ty,
|
||||
ty::TYPE.into(),
|
||||
"TODO: we dont support anything except type generics"
|
||||
);
|
||||
let arg = self.expr_ctx(arg, Ctx::default().with_ty(ty))?;
|
||||
self.tys.args.push(arg.loc.to_ty().unwrap());
|
||||
arg.loc
|
||||
};
|
||||
|
||||
self.ci.vars.push(Variable { id: carg.id, value: Value { ty, loc } });
|
||||
}
|
||||
|
||||
let args = self.pack_args(expr.pos(), arg_base);
|
||||
let ret = self.ty(ret);
|
||||
self.ci.vars.truncate(scope);
|
||||
|
||||
let sym = SymKey {
|
||||
file: !args.repr(),
|
||||
ident: ty::Kind::Func(func).compress().repr(),
|
||||
};
|
||||
let ct = || {
|
||||
let func_id = self.tys.funcs.len();
|
||||
self.tys.funcs.push(Func {
|
||||
file: fuc.file,
|
||||
offset: task::id(func_id),
|
||||
sig: Some(Sig { args, ret }),
|
||||
expr: fuc.expr,
|
||||
});
|
||||
|
||||
self.tasks.push(Some(FTask {
|
||||
// FIXME: this will fuck us
|
||||
file: fuc.file,
|
||||
id: func_id as _,
|
||||
}));
|
||||
|
||||
ty::Kind::Func(func_id as _).compress()
|
||||
};
|
||||
func = self.tys.syms.entry(sym).or_insert_with(ct).expand().inner();
|
||||
|
||||
Sig { args, ret }
|
||||
};
|
||||
|
||||
let mut parama = self.tys.parama(sig.ret);
|
||||
let mut values = Vec::with_capacity(args.len());
|
||||
let mut sig_args = sig.args.range();
|
||||
|
@ -1888,7 +1924,7 @@ impl Codegen {
|
|||
|
||||
log::dbg!("call ctx: {ctx:?}");
|
||||
|
||||
let loc = self.alloc_ret(sig.ret, ctx);
|
||||
let loc = self.alloc_ret(sig.ret, ctx, false);
|
||||
|
||||
if should_momize {
|
||||
self.output.write_trap(trap::Trap::MomizedCall(trap::MomizedCall { func }));
|
||||
|
@ -1897,6 +1933,7 @@ impl Codegen {
|
|||
let reloc = Reloc::new(self.local_offset(), 3, 4);
|
||||
self.output.funcs.push((func, reloc));
|
||||
self.output.emit(jal(RET_ADDR, ZERO, 0));
|
||||
self.make_func_reachable(func);
|
||||
|
||||
if should_momize {
|
||||
self.output.emit(tx());
|
||||
|
@ -2177,6 +2214,63 @@ impl Codegen {
|
|||
})
|
||||
}
|
||||
|
||||
fn compute_signature(&mut self, func: &mut ty::Func, pos: Pos, args: &[Expr]) -> Option<Sig> {
|
||||
let fuc = self.tys.funcs[*func as usize];
|
||||
let fast = self.files[fuc.file as usize].clone();
|
||||
let Expr::BinOp { right: &Expr::Closure { args: cargs, ret, .. }, .. } =
|
||||
fuc.expr.get(&fast).unwrap()
|
||||
else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
Some(if let Some(sig) = fuc.sig {
|
||||
sig
|
||||
} else {
|
||||
let arg_base = self.tys.args.len();
|
||||
|
||||
for (arg, carg) in args.iter().zip(cargs) {
|
||||
let ty = self.ty(&carg.ty);
|
||||
log::dbg!("arg: {}", self.ty_display(ty));
|
||||
self.tys.args.push(ty);
|
||||
let sym = parser::find_symbol(&fast.symbols, carg.id);
|
||||
let loc = if sym.flags & idfl::COMPTIME == 0 {
|
||||
// FIXME: could fuck us
|
||||
Loc::default()
|
||||
} else {
|
||||
debug_assert_eq!(
|
||||
ty,
|
||||
ty::TYPE.into(),
|
||||
"TODO: we dont support anything except type generics"
|
||||
);
|
||||
let arg = self.expr_ctx(arg, Ctx::default().with_ty(ty))?;
|
||||
self.tys.args.push(arg.loc.to_ty().unwrap());
|
||||
arg.loc
|
||||
};
|
||||
|
||||
self.ci.vars.push(Variable { id: carg.id, value: Value { ty, loc } });
|
||||
}
|
||||
|
||||
let args = self.pack_args(pos, arg_base);
|
||||
let ret = self.ty(ret);
|
||||
|
||||
let sym = SymKey { file: !args.repr(), ident: ty::Kind::Func(*func).compress().repr() };
|
||||
let ct = || {
|
||||
let func_id = self.tys.funcs.len();
|
||||
self.tys.funcs.push(Func {
|
||||
file: fuc.file,
|
||||
offset: u32::MAX,
|
||||
sig: Some(Sig { args, ret }),
|
||||
expr: fuc.expr,
|
||||
});
|
||||
|
||||
ty::Kind::Func(func_id as _).compress()
|
||||
};
|
||||
*func = self.tys.syms.entry(sym).or_insert_with(ct).expand().inner();
|
||||
|
||||
Sig { args, ret }
|
||||
})
|
||||
}
|
||||
|
||||
fn has_ct(&self, expr: &Expr) -> bool {
|
||||
expr.has_ct(&self.cfile().symbols)
|
||||
}
|
||||
|
@ -2625,7 +2719,7 @@ impl Codegen {
|
|||
Value { ty: ret.into(), loc: Loc::reg(1) }
|
||||
}
|
||||
|
||||
fn alloc_ret(&mut self, ret: ty::Id, ctx: Ctx) -> Loc {
|
||||
fn alloc_ret(&mut self, ret: ty::Id, ctx: Ctx, custom_ret_reg: bool) -> Loc {
|
||||
let size = self.tys.size_of(ret);
|
||||
if size == 0 {
|
||||
debug_assert!(ctx.loc.is_none(), "{}", self.ty_display(ret));
|
||||
|
@ -2638,9 +2732,10 @@ impl Codegen {
|
|||
|
||||
match size {
|
||||
0 => Loc::default(),
|
||||
1..=8 if custom_ret_reg => Loc::reg(self.ci.regs.allocate()),
|
||||
1..=8 => Loc::reg(1),
|
||||
9..=16 => Loc::stack(self.ci.stack.allocate(size)),
|
||||
_ => {
|
||||
17.. => {
|
||||
let loc = ctx.loc.unwrap_or_else(|| Loc::stack(self.ci.stack.allocate(size)));
|
||||
let Loc::Rt { reg, stack, offset, .. } = &loc else {
|
||||
todo!("old man with the beard looks at the sky scared");
|
||||
|
@ -2955,10 +3050,8 @@ impl Codegen {
|
|||
op: TokenKind::Decl,
|
||||
right: &Expr::Closure { pos, args, ret, .. },
|
||||
} => {
|
||||
let mut push_task = false;
|
||||
let func = Func {
|
||||
file,
|
||||
offset: task::id(self.tasks.len()),
|
||||
sig: 'b: {
|
||||
let arg_base = self.tys.args.len();
|
||||
for arg in args {
|
||||
|
@ -2971,8 +3064,6 @@ impl Codegen {
|
|||
self.tys.args.push(ty);
|
||||
}
|
||||
|
||||
push_task = true;
|
||||
|
||||
let args = self.pack_args(pos, arg_base);
|
||||
log::dbg!("eval ret");
|
||||
let ret = self.ty(ret);
|
||||
|
@ -2984,12 +3075,10 @@ impl Codegen {
|
|||
debug_assert!(refr.get(&f).is_some());
|
||||
refr
|
||||
},
|
||||
offset: u32::MAX,
|
||||
};
|
||||
|
||||
let id = self.tys.funcs.len() as _;
|
||||
if push_task {
|
||||
self.tasks.push(Some(FTask { file, id }));
|
||||
}
|
||||
self.tys.funcs.push(func);
|
||||
|
||||
ty::Kind::Func(id)
|
||||
|
@ -3023,6 +3112,14 @@ impl Codegen {
|
|||
sym
|
||||
}
|
||||
|
||||
fn make_func_reachable(&mut self, func: ty::Func) {
|
||||
let fuc = &mut self.tys.funcs[func as usize];
|
||||
if fuc.offset == u32::MAX {
|
||||
fuc.offset = task::id(self.tasks.len() as _);
|
||||
self.tasks.push(Some(FTask { file: fuc.file, id: func }));
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_global(&mut self, expr: &Expr) -> Global {
|
||||
self.output.emit_prelude();
|
||||
|
||||
|
@ -3364,5 +3461,6 @@ mod tests {
|
|||
comptime_min_reg_leak => README;
|
||||
// structs_in_registers => README;
|
||||
comptime_function_from_another_file => README;
|
||||
inline => README;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
code size: 193
|
||||
code size: 188
|
||||
ret: 1
|
||||
status: Ok(())
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
code size: 418
|
||||
code size: 408
|
||||
ret: 7
|
||||
status: Ok(())
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
code size: 313
|
||||
code size: 303
|
||||
ret: 16
|
||||
status: Ok(())
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
code size: 153
|
||||
code size: 143
|
||||
ret: 0
|
||||
status: Ok(())
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
code size: 255
|
||||
code size: 245
|
||||
ret: 50
|
||||
status: Ok(())
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
code size: 231
|
||||
code size: 221
|
||||
ret: 50
|
||||
status: Ok(())
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
code size: 536
|
||||
code size: 531
|
||||
ret: 512
|
||||
status: Ok(())
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
code size: 525
|
||||
code size: 505
|
||||
ret: 0
|
||||
status: Ok(())
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
code size: 281
|
||||
code size: 266
|
||||
ret: 33
|
||||
status: Ok(())
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
code size: 296
|
||||
code size: 281
|
||||
ret: 0
|
||||
status: Ok(())
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
code size: 1504
|
||||
code size: 1469
|
||||
ret: 69
|
||||
status: Ok(())
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
code size: 277
|
||||
code size: 267
|
||||
ret: 50
|
||||
status: Ok(())
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
code size: 210
|
||||
code size: 205
|
||||
ret: 0
|
||||
status: Ok(())
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
code size: 262
|
||||
code size: 252
|
||||
ret: 55
|
||||
status: Ok(())
|
||||
|
|
3
hblang/tests/codegen_tests_inline.txt
Normal file
3
hblang/tests/codegen_tests_inline.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
code size: 124
|
||||
ret: 0
|
||||
status: Ok(())
|
|
@ -1,3 +1,3 @@
|
|||
code size: 268
|
||||
code size: 258
|
||||
ret: 55
|
||||
status: Ok(())
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
code size: 330
|
||||
code size: 315
|
||||
ret: 0
|
||||
status: Ok(())
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
code size: 357
|
||||
code size: 87
|
||||
ret: 0
|
||||
status: Ok(())
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
code size: 786
|
||||
code size: 781
|
||||
ret: 10
|
||||
status: Ok(())
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
code size: 533
|
||||
code size: 518
|
||||
ret: 0
|
||||
status: Ok(())
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
code size: 330
|
||||
code size: 320
|
||||
ret: 0
|
||||
status: Ok(())
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
code size: 460
|
||||
code size: 445
|
||||
ret: 3
|
||||
status: Ok(())
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
code size: 116
|
||||
code size: 111
|
||||
ret: 0
|
||||
status: Ok(())
|
||||
|
|
Loading…
Reference in a new issue