adding negation
This commit is contained in:
parent
2bc7a5c13f
commit
c133c2dbe7
|
@ -48,7 +48,7 @@ main := fn(): int {
|
||||||
#### arithmetic
|
#### arithmetic
|
||||||
```hb
|
```hb
|
||||||
main := fn(): int {
|
main := fn(): int {
|
||||||
return 10 - 20 / 2 + 4 * (2 + 2) - 4 * 4 + 1 << 0
|
return 10 - 20 / 2 + 4 * (2 + 2) - 4 * 4 + (1 << 0) + -1
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -913,25 +913,3 @@ main := fn(): int {
|
||||||
return back_buffer[1024 * 2]
|
return back_buffer[1024 * 2]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### something_somehow
|
|
||||||
```hb
|
|
||||||
foo := @use("foo.hb")
|
|
||||||
main := fn(): void {
|
|
||||||
foo.blue
|
|
||||||
foo.red
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// in module: foo.hb
|
|
||||||
|
|
||||||
bar := @use("bar.hb")
|
|
||||||
default := bar
|
|
||||||
blue := default.blue
|
|
||||||
red := default.red
|
|
||||||
|
|
||||||
// in module: bar.hb
|
|
||||||
Color := struct {r: u8, g: u8, b: u8, a: u8}
|
|
||||||
red := Color.(255, 0, 0, 0)
|
|
||||||
blue := Color.(1, 0, 1, 0)
|
|
||||||
```
|
|
||||||
|
|
|
@ -830,10 +830,6 @@ impl Codegen {
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
E::UnOp { op: T::Xor, val, .. } => {
|
|
||||||
let val = self.ty(val);
|
|
||||||
Some(Value::ty(self.tys.make_ptr(val)))
|
|
||||||
}
|
|
||||||
E::Directive { name: "inline", args: [func_ast, args @ ..], .. } => {
|
E::Directive { name: "inline", args: [func_ast, args @ ..], .. } => {
|
||||||
let ty::Kind::Func(mut func) = self.ty(func_ast).expand() else {
|
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");
|
self.report(func_ast.pos(), "first argument of inline needs to be a function");
|
||||||
|
@ -1180,6 +1176,42 @@ impl Codegen {
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
E::UnOp { op: T::Sub, val, pos } => {
|
||||||
|
let value = self.expr(val)?;
|
||||||
|
|
||||||
|
if !value.ty.is_integer() {
|
||||||
|
self.report(pos, format_args!("cant negate '{}'", self.ty_display(value.ty)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let size = self.tys.size_of(value.ty);
|
||||||
|
|
||||||
|
let (oper, dst, drop_loc) = if let Some(dst) = &ctx.loc
|
||||||
|
&& dst.is_reg()
|
||||||
|
&& let Some(dst) = ctx.loc.take()
|
||||||
|
{
|
||||||
|
(
|
||||||
|
self.loc_to_reg(&value.loc, size),
|
||||||
|
if dst.is_ref() {
|
||||||
|
self.loc_to_reg(&dst, size)
|
||||||
|
} else {
|
||||||
|
self.loc_to_reg(dst, size)
|
||||||
|
},
|
||||||
|
value.loc,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
let oper = self.loc_to_reg(value.loc, size);
|
||||||
|
(oper.as_ref(), oper, Loc::default())
|
||||||
|
};
|
||||||
|
|
||||||
|
self.ci.emit(neg(dst.get(), oper.get()));
|
||||||
|
self.ci.free_loc(drop_loc);
|
||||||
|
|
||||||
|
Some(Value::new(value.ty, dst))
|
||||||
|
}
|
||||||
|
E::UnOp { op: T::Xor, val, .. } => {
|
||||||
|
let val = self.ty(val);
|
||||||
|
Some(Value::ty(self.tys.make_ptr(val)))
|
||||||
|
}
|
||||||
E::UnOp { op: T::Band, val, pos } => {
|
E::UnOp { op: T::Band, val, pos } => {
|
||||||
let mut val = self.expr(val)?;
|
let mut val = self.expr(val)?;
|
||||||
let Loc::Rt { derefed: drfd @ true, reg, stack, offset } = &mut val.loc else {
|
let Loc::Rt { derefed: drfd @ true, reg, stack, offset } = &mut val.loc else {
|
||||||
|
@ -2701,6 +2733,5 @@ mod tests {
|
||||||
writing_into_string => README;
|
writing_into_string => README;
|
||||||
request_page => README;
|
request_page => README;
|
||||||
tests_ptr_to_ptr_copy => README;
|
tests_ptr_to_ptr_copy => README;
|
||||||
something_somehow => README;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -224,10 +224,6 @@ mod ty {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Id {
|
impl Id {
|
||||||
pub const fn from_bt(bt: u32) -> Self {
|
|
||||||
Self(unsafe { NonZeroU32::new_unchecked(bt) })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_signed(self) -> bool {
|
pub fn is_signed(self) -> bool {
|
||||||
(I8..=INT).contains(&self.repr())
|
(I8..=INT).contains(&self.repr())
|
||||||
}
|
}
|
||||||
|
|
|
@ -374,7 +374,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
pos
|
pos
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
T::Band | T::Mul | T::Xor => E::UnOp {
|
T::Band | T::Mul | T::Xor | T::Sub => E::UnOp {
|
||||||
pos,
|
pos,
|
||||||
op: token.kind,
|
op: token.kind,
|
||||||
val: {
|
val: {
|
||||||
|
|
|
@ -24,12 +24,6 @@ use {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
macro_rules! node_color {
|
|
||||||
($self:expr, $value:expr) => {
|
|
||||||
$self.ci.colors[$self.ci.nodes[$value].color as usize - 1]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! node_loc {
|
macro_rules! node_loc {
|
||||||
($self:expr, $value:expr) => {
|
($self:expr, $value:expr) => {
|
||||||
$self.ci.colors[$self.ci.nodes[$value].color as usize - 1].loc
|
$self.ci.colors[$self.ci.nodes[$value].color as usize - 1].loc
|
||||||
|
@ -845,7 +839,7 @@ impl Nodes {
|
||||||
#[allow(clippy::format_in_format_args)]
|
#[allow(clippy::format_in_format_args)]
|
||||||
fn basic_blocks_instr(&mut self, out: &mut String, node: Nid) -> std::fmt::Result {
|
fn basic_blocks_instr(&mut self, out: &mut String, node: Nid) -> std::fmt::Result {
|
||||||
if self[node].kind != Kind::Loop && self[node].kind != Kind::Region {
|
if self[node].kind != Kind::Loop && self[node].kind != Kind::Region {
|
||||||
write!(out, " {node:>2}: ")?;
|
write!(out, " {node:>2}-c{:>2}:", self[node].color)?;
|
||||||
}
|
}
|
||||||
match self[node].kind {
|
match self[node].kind {
|
||||||
Kind::Start => unreachable!(),
|
Kind::Start => unreachable!(),
|
||||||
|
@ -1158,7 +1152,7 @@ impl fmt::Display for Kind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default, Clone)]
|
||||||
//#[repr(align(64))]
|
//#[repr(align(64))]
|
||||||
struct Node {
|
struct Node {
|
||||||
inputs: Vc,
|
inputs: Vc,
|
||||||
|
@ -1228,7 +1222,6 @@ struct Variable {
|
||||||
struct ColorMeta {
|
struct ColorMeta {
|
||||||
rc: u32,
|
rc: u32,
|
||||||
depth: LoopDepth,
|
depth: LoopDepth,
|
||||||
call_count: CallCount,
|
|
||||||
loc: Loc,
|
loc: Loc,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1261,18 +1254,14 @@ struct ItemCtx {
|
||||||
|
|
||||||
impl ItemCtx {
|
impl ItemCtx {
|
||||||
fn next_color(&mut self) -> Color {
|
fn next_color(&mut self) -> Color {
|
||||||
self.colors.push(ColorMeta {
|
self.colors.push(ColorMeta { rc: 0, depth: self.loop_depth, loc: Default::default() });
|
||||||
rc: 0,
|
|
||||||
call_count: self.call_count,
|
|
||||||
depth: self.loop_depth,
|
|
||||||
loc: Default::default(),
|
|
||||||
});
|
|
||||||
self.colors.len() as _ // leave out 0 (sentinel)
|
self.colors.len() as _ // leave out 0 (sentinel)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_next_color(&mut self, node: Nid) {
|
fn set_next_color(&mut self, node: Nid) -> Color {
|
||||||
let color = self.next_color();
|
let color = self.next_color();
|
||||||
self.set_color(node, color);
|
self.set_color(node, color);
|
||||||
|
color
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_color(&mut self, node: Nid, color: Color) {
|
fn set_color(&mut self, node: Nid, color: Color) {
|
||||||
|
@ -1837,7 +1826,7 @@ impl Codegen {
|
||||||
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Tuple { index: 0 }, [self.ci.start]);
|
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Tuple { index: 0 }, [self.ci.start]);
|
||||||
|
|
||||||
let Expr::BinOp {
|
let Expr::BinOp {
|
||||||
left: Expr::Ident { name, .. },
|
left: Expr::Ident { .. },
|
||||||
op: TokenKind::Decl,
|
op: TokenKind::Decl,
|
||||||
right: &Expr::Closure { body, args, .. },
|
right: &Expr::Closure { body, args, .. },
|
||||||
} = expr
|
} = expr
|
||||||
|
@ -1873,8 +1862,6 @@ impl Codegen {
|
||||||
if self.errors.borrow().is_empty() {
|
if self.errors.borrow().is_empty() {
|
||||||
self.gcm();
|
self.gcm();
|
||||||
|
|
||||||
//self.ci.nodes.graphviz();
|
|
||||||
log::inf!("{id} {name}: ");
|
|
||||||
self.ci.nodes.basic_blocks();
|
self.ci.nodes.basic_blocks();
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
|
@ -1882,8 +1869,6 @@ impl Codegen {
|
||||||
self.ci.nodes.check_final_integrity();
|
self.ci.nodes.check_final_integrity();
|
||||||
}
|
}
|
||||||
|
|
||||||
log::trc!("{}", self.ci.nodes);
|
|
||||||
|
|
||||||
'_open_function: {
|
'_open_function: {
|
||||||
self.ci.emit(instrs::addi64(reg::STACK_PTR, reg::STACK_PTR, 0));
|
self.ci.emit(instrs::addi64(reg::STACK_PTR, reg::STACK_PTR, 0));
|
||||||
self.ci.emit(instrs::st(reg::RET_ADDR, reg::STACK_PTR, 0, 0));
|
self.ci.emit(instrs::st(reg::RET_ADDR, reg::STACK_PTR, 0, 0));
|
||||||
|
@ -1899,7 +1884,8 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.color_control(self.ci.nodes[self.ci.start].outputs[0]);
|
self.ci.nodes.visited.clear(self.ci.nodes.values.len());
|
||||||
|
self.color_node(self.ci.end);
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
self.ci.check_color_integrity();
|
self.ci.check_color_integrity();
|
||||||
|
@ -1907,7 +1893,8 @@ impl Codegen {
|
||||||
|
|
||||||
self.ci.vars = orig_vars;
|
self.ci.vars = orig_vars;
|
||||||
self.ci.call_count = call_count;
|
self.ci.call_count = call_count;
|
||||||
self.emit_control(self.ci.nodes[self.ci.start].outputs[0]);
|
self.ci.nodes.visited.clear(self.ci.nodes.values.len());
|
||||||
|
self.emit_node(self.ci.start);
|
||||||
self.ci.vars.clear();
|
self.ci.vars.clear();
|
||||||
|
|
||||||
if let Some(last_ret) = self.ci.ret_relocs.last()
|
if let Some(last_ret) = self.ci.ret_relocs.last()
|
||||||
|
@ -1944,622 +1931,120 @@ impl Codegen {
|
||||||
self.pool.cis.push(std::mem::replace(&mut self.ci, prev_ci));
|
self.pool.cis.push(std::mem::replace(&mut self.ci, prev_ci));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn color_control(&mut self, mut ctrl: Nid) -> Option<Nid> {
|
fn color_node(&mut self, ctrl: Nid) -> Option<Color> {
|
||||||
for _ in 0..30 {
|
if !self.ci.nodes.visited.set(ctrl) {
|
||||||
match self.ci.nodes[ctrl].kind {
|
return None;
|
||||||
Kind::Start => unreachable!(),
|
|
||||||
Kind::End => unreachable!(),
|
|
||||||
Kind::Return => {
|
|
||||||
let ret = self.ci.nodes[ctrl].inputs[1];
|
|
||||||
if ret != 0 {
|
|
||||||
_ = self.color_expr_consume(ret);
|
|
||||||
if node_color!(self, ret).call_count == self.ci.call_count {
|
|
||||||
node_loc!(self, ret) =
|
|
||||||
match self.tys.size_of(self.ci.ret.expect("TODO")) {
|
|
||||||
0 => Loc::default(),
|
|
||||||
1..=8 => Loc { reg: 1 },
|
|
||||||
s => todo!("{s}"),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
self.ci.regs.mark_leaked(1);
|
|
||||||
}
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Kind::CInt { .. } => unreachable!(),
|
|
||||||
Kind::Tuple { .. } => {
|
|
||||||
ctrl = self.ci.nodes[ctrl].outputs[0];
|
|
||||||
}
|
|
||||||
Kind::BinOp { .. } => unreachable!(),
|
|
||||||
Kind::Call { .. } => {
|
|
||||||
for i in 1..self.ci.nodes[ctrl].inputs.len() {
|
|
||||||
let arg = self.ci.nodes[ctrl].inputs[i];
|
|
||||||
_ = self.color_expr_consume(arg);
|
|
||||||
self.ci.set_next_color(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.ci.call_count -= 1;
|
|
||||||
|
|
||||||
self.ci.set_next_color(ctrl);
|
|
||||||
|
|
||||||
ctrl = *self.ci.nodes[ctrl]
|
|
||||||
.outputs
|
|
||||||
.iter()
|
|
||||||
.find(|&&o| self.ci.nodes.is_cfg(o))
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
Kind::If => {
|
|
||||||
_ = self.color_expr_consume(self.ci.nodes[ctrl].inputs[1]);
|
|
||||||
|
|
||||||
let left_unreachable = self.color_control(self.ci.nodes[ctrl].outputs[0]);
|
|
||||||
let right_unreachable = self.color_control(self.ci.nodes[ctrl].outputs[1]);
|
|
||||||
|
|
||||||
let dest = match (left_unreachable, right_unreachable) {
|
|
||||||
(None, None) => return None,
|
|
||||||
(None, Some(n)) | (Some(n), None) => return Some(n),
|
|
||||||
(Some(l), Some(r)) if l == r => l,
|
|
||||||
(Some(left), Some(right)) => {
|
|
||||||
todo!("{:?} {:?}", self.ci.nodes[left], self.ci.nodes[right]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if self.ci.nodes[dest].kind == Kind::Loop {
|
|
||||||
return Some(dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
debug_assert_eq!(self.ci.nodes[dest].kind, Kind::Region);
|
|
||||||
|
|
||||||
for i in 0..self.ci.nodes[dest].outputs.len() {
|
|
||||||
let o = self.ci.nodes[dest].outputs[i];
|
|
||||||
if self.ci.nodes[o].kind == Kind::Phi {
|
|
||||||
self.color_phi(o);
|
|
||||||
self.ci.nodes[o].depth = self.ci.loop_depth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctrl = *self.ci.nodes[dest]
|
|
||||||
.outputs
|
|
||||||
.iter()
|
|
||||||
.find(|&&o| self.ci.nodes[o].kind != Kind::Phi)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
Kind::Region => return Some(ctrl),
|
|
||||||
Kind::Phi => todo!(),
|
|
||||||
Kind::Loop => {
|
|
||||||
if self.ci.nodes[ctrl].lock_rc != 0 {
|
|
||||||
return Some(ctrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
for i in 0..self.ci.nodes[ctrl].outputs.len() {
|
|
||||||
let maybe_phi = self.ci.nodes[ctrl].outputs[i];
|
|
||||||
let Node { kind: Kind::Phi, ref inputs, .. } = self.ci.nodes[maybe_phi]
|
|
||||||
else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
_ = self.color_expr_consume(inputs[1]);
|
|
||||||
self.ci.nodes[maybe_phi].depth = self.ci.loop_depth;
|
|
||||||
self.ci.set_next_color(maybe_phi);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.ci.nodes[ctrl].lock_rc = self.ci.code.len() as _;
|
|
||||||
self.ci.loop_depth += 1;
|
|
||||||
|
|
||||||
self.color_control(
|
|
||||||
*self.ci.nodes[ctrl]
|
|
||||||
.outputs
|
|
||||||
.iter()
|
|
||||||
.find(|&&o| self.ci.nodes[o].kind != Kind::Phi)
|
|
||||||
.unwrap(),
|
|
||||||
);
|
|
||||||
|
|
||||||
for i in 0..self.ci.nodes[ctrl].outputs.len() {
|
|
||||||
self.color_phi(self.ci.nodes[ctrl].outputs[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.ci.loop_depth -= 1;
|
|
||||||
self.ci.nodes[ctrl].lock_rc = 0;
|
|
||||||
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unreachable!()
|
let node = self.ci.nodes[ctrl].clone();
|
||||||
}
|
match node.kind {
|
||||||
|
Kind::Start => None,
|
||||||
fn color_phi(&mut self, maybe_phi: Nid) {
|
Kind::End => {
|
||||||
let Node { kind: Kind::Phi, ref inputs, .. } = self.ci.nodes[maybe_phi] else {
|
for &i in node.inputs.iter() {
|
||||||
return;
|
self.color_node(i);
|
||||||
};
|
|
||||||
let &[region, left, right] = inputs.as_slice() else { unreachable!() };
|
|
||||||
|
|
||||||
let lcolor = self.color_expr_consume(left);
|
|
||||||
let rcolor = self.color_expr_consume(right);
|
|
||||||
|
|
||||||
if self.ci.nodes[maybe_phi].color != 0 {
|
|
||||||
// loop phi
|
|
||||||
if let Some(c) = rcolor
|
|
||||||
&& !self.ci.nodes.climb_expr(right, |i, n| {
|
|
||||||
matches!(n.kind, Kind::Phi) && n.inputs[0] == region && i != maybe_phi
|
|
||||||
})
|
|
||||||
{
|
|
||||||
self.ci.recolor(right, c, self.ci.nodes[maybe_phi].color);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let color = match (lcolor, rcolor) {
|
|
||||||
(None, None) => self.ci.next_color(),
|
|
||||||
(None, Some(c)) | (Some(c), None) => c,
|
|
||||||
(Some(lc), Some(rc)) => {
|
|
||||||
self.ci.recolor(right, rc, lc);
|
|
||||||
lc
|
|
||||||
}
|
}
|
||||||
};
|
None
|
||||||
self.ci.set_color(maybe_phi, color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use = "dont forget to drop the location"]
|
|
||||||
fn color_expr_consume(&mut self, expr: Nid) -> Option<Color> {
|
|
||||||
if self.ci.nodes[expr].lock_rc == 0 && self.ci.nodes[expr].kind != Kind::Phi {
|
|
||||||
self.ci.nodes[expr].depth = self.ci.loop_depth;
|
|
||||||
self.color_expr(expr);
|
|
||||||
}
|
|
||||||
self.use_colored_expr(expr)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn color_expr(&mut self, expr: Nid) {
|
|
||||||
match self.ci.nodes[expr].kind {
|
|
||||||
Kind::Start => unreachable!(),
|
|
||||||
Kind::End => unreachable!(),
|
|
||||||
Kind::Return => unreachable!(),
|
|
||||||
Kind::CInt { .. } => self.ci.set_next_color(expr),
|
|
||||||
Kind::Tuple { index } => {
|
|
||||||
debug_assert!(index != 0);
|
|
||||||
}
|
}
|
||||||
Kind::BinOp { .. } => {
|
|
||||||
let &[_, left, right] = self.ci.nodes[expr].inputs.as_slice() else {
|
|
||||||
unreachable!()
|
|
||||||
};
|
|
||||||
let lcolor = self.color_expr_consume(left);
|
|
||||||
let rcolor = self.color_expr_consume(right);
|
|
||||||
let color = lcolor.or(rcolor).unwrap_or_else(|| self.ci.next_color());
|
|
||||||
self.ci.set_color(expr, color);
|
|
||||||
}
|
|
||||||
Kind::Call { .. } => {}
|
|
||||||
Kind::If => todo!(),
|
Kind::If => todo!(),
|
||||||
Kind::Region => todo!(),
|
Kind::Region => todo!(),
|
||||||
Kind::Phi => {}
|
|
||||||
Kind::Loop => todo!(),
|
Kind::Loop => todo!(),
|
||||||
}
|
Kind::Return => {
|
||||||
}
|
if node.inputs[1] != 0 {
|
||||||
|
// FIXME: scan idoms to see if there is a call inbetween
|
||||||
#[must_use]
|
let col = self.ci.set_next_color(node.inputs[1]);
|
||||||
fn use_colored_expr(&mut self, expr: Nid) -> Option<Color> {
|
self.ci.colors[col as usize - 1].loc = Loc { reg: 1 };
|
||||||
self.ci.nodes[expr].lock_rc += 1;
|
self.ci.nodes.visited.set(node.inputs[1]);
|
||||||
debug_assert_ne!(self.ci.nodes[expr].color, 0, "{:?}", self.ci.nodes[expr].kind);
|
|
||||||
(self.ci.nodes[expr].lock_rc as usize >= self.ci.nodes[expr].outputs.len()
|
|
||||||
&& self.ci.nodes[expr].depth == self.ci.loop_depth)
|
|
||||||
.then_some(self.ci.nodes[expr].color)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn emit_control(&mut self, mut ctrl: Nid) -> Option<Nid> {
|
|
||||||
for _ in 0..30 {
|
|
||||||
match self.ci.nodes[ctrl].kind {
|
|
||||||
Kind::Start => unreachable!(),
|
|
||||||
Kind::End => unreachable!(),
|
|
||||||
Kind::Return => {
|
|
||||||
let ret = self.ci.nodes[ctrl].inputs[1];
|
|
||||||
if ret != 0 {
|
|
||||||
// NOTE: this is safer less efficient way, maybe it will be needed
|
|
||||||
// self.emit_expr_consume(ret);
|
|
||||||
// if node_color!(self, ret).call_count != self.ci.call_count {
|
|
||||||
// let src = node_loc!(self, ret);
|
|
||||||
// let loc = match self.tys.size_of(self.ci.ret.expect("TODO")) {
|
|
||||||
// 0 => Loc::default(),
|
|
||||||
// 1..=8 => Loc { reg: 1 },
|
|
||||||
// s => todo!("{s}"),
|
|
||||||
// };
|
|
||||||
// if src != loc {
|
|
||||||
// let inst = instrs::cp(loc.reg, src.reg);
|
|
||||||
// self.ci.emit(inst);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
node_loc!(self, ret) = match self.tys.size_of(self.ci.ret.expect("TODO")) {
|
|
||||||
0 => Loc::default(),
|
|
||||||
1..=8 => Loc { reg: 1 },
|
|
||||||
s => todo!("{s}"),
|
|
||||||
};
|
|
||||||
self.emit_expr_consume(ret);
|
|
||||||
}
|
|
||||||
self.ci.ret_relocs.push(Reloc::new(self.ci.code.len(), 1, 4));
|
|
||||||
self.ci.emit(instrs::jmp(0));
|
|
||||||
return None;
|
|
||||||
}
|
}
|
||||||
Kind::CInt { .. } => unreachable!(),
|
|
||||||
Kind::Tuple { .. } => {
|
|
||||||
ctrl = self.ci.nodes[ctrl].outputs[0];
|
|
||||||
}
|
|
||||||
Kind::BinOp { .. } => unreachable!(),
|
|
||||||
Kind::Call { func } => {
|
|
||||||
let ret = self.tof(ctrl);
|
|
||||||
|
|
||||||
let mut parama = self.tys.parama(ret);
|
self.color_node(node.inputs[0]);
|
||||||
for i in 1..self.ci.nodes[ctrl].inputs.len() {
|
None
|
||||||
let arg = self.ci.nodes[ctrl].inputs[i];
|
|
||||||
|
|
||||||
let dst = match self.tys.size_of(self.tof(arg)) {
|
|
||||||
0 => continue,
|
|
||||||
1..=8 => Loc { reg: parama.next() },
|
|
||||||
s => todo!("{s}"),
|
|
||||||
};
|
|
||||||
self.emit_expr_consume(arg);
|
|
||||||
self.ci.emit(instrs::cp(dst.reg, node_loc!(self, arg).reg));
|
|
||||||
}
|
|
||||||
|
|
||||||
let reloc = Reloc::new(self.ci.code.len(), 3, 4);
|
|
||||||
self.ci
|
|
||||||
.relocs
|
|
||||||
.push(TypedReloc { target: ty::Kind::Func(func).compress(), reloc });
|
|
||||||
self.ci.emit(instrs::jal(reg::RET_ADDR, reg::ZERO, 0));
|
|
||||||
|
|
||||||
self.ci.call_count -= 1;
|
|
||||||
|
|
||||||
'b: {
|
|
||||||
let ret_loc = match self.tys.size_of(ret) {
|
|
||||||
0 => break 'b,
|
|
||||||
1..=8 => Loc { reg: 1 },
|
|
||||||
s => todo!("{s}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if self.ci.nodes[ctrl].outputs.len() == 1 {
|
|
||||||
break 'b;
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.ci.call_count == 0 {
|
|
||||||
node_loc!(self, ctrl) = ret_loc;
|
|
||||||
} else {
|
|
||||||
self.emit_pass_low(ret_loc, ctrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctrl = *self.ci.nodes[ctrl]
|
|
||||||
.outputs
|
|
||||||
.iter()
|
|
||||||
.find(|&&o| self.ci.nodes.is_cfg(o))
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
Kind::If => {
|
|
||||||
let cond = self.ci.nodes[ctrl].inputs[1];
|
|
||||||
|
|
||||||
let jump_offset: i64;
|
|
||||||
let mut swapped = false;
|
|
||||||
'resolve_cond: {
|
|
||||||
'optimize_cond: {
|
|
||||||
let Kind::BinOp { op } = self.ci.nodes[cond].kind else {
|
|
||||||
break 'optimize_cond;
|
|
||||||
};
|
|
||||||
|
|
||||||
let &[_, left, right] = self.ci.nodes[cond].inputs.as_slice() else {
|
|
||||||
unreachable!()
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some((op, swpd)) = op.cond_op(self.ci.nodes[left].ty.is_signed())
|
|
||||||
else {
|
|
||||||
break 'optimize_cond;
|
|
||||||
};
|
|
||||||
swapped = swpd;
|
|
||||||
|
|
||||||
self.emit_expr_consume(left);
|
|
||||||
self.emit_expr_consume(right);
|
|
||||||
|
|
||||||
jump_offset = self.ci.code.len() as _;
|
|
||||||
self.ci.emit(op(
|
|
||||||
node_loc!(self, left).reg,
|
|
||||||
node_loc!(self, right).reg,
|
|
||||||
0,
|
|
||||||
));
|
|
||||||
|
|
||||||
break 'resolve_cond;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.emit_expr_consume(cond);
|
|
||||||
jump_offset = self.ci.code.len() as _;
|
|
||||||
self.ci.emit(instrs::jeq(node_loc!(self, cond).reg, reg::ZERO, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
let [loff, roff] = [swapped as usize, !swapped as usize];
|
|
||||||
|
|
||||||
let filled_base = self.ci.filled.len();
|
|
||||||
let left_unreachable = self.emit_control(self.ci.nodes[ctrl].outputs[loff]);
|
|
||||||
for fld in self.ci.filled.drain(filled_base..) {
|
|
||||||
self.ci.nodes[fld].depth = 0;
|
|
||||||
}
|
|
||||||
let mut skip_then_offset = self.ci.code.len() as i64;
|
|
||||||
if let Some(region) = left_unreachable {
|
|
||||||
for i in 0..self.ci.nodes[region].outputs.len() {
|
|
||||||
let o = self.ci.nodes[region].outputs[i];
|
|
||||||
if self.ci.nodes[o].kind != Kind::Phi {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let out = self.ci.nodes[o].inputs[1 + loff];
|
|
||||||
self.emit_expr_consume(out);
|
|
||||||
self.emit_pass(out, o);
|
|
||||||
}
|
|
||||||
|
|
||||||
skip_then_offset = self.ci.code.len() as i64;
|
|
||||||
self.ci.emit(instrs::jmp(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
let right_base = self.ci.code.len();
|
|
||||||
let filled_base = self.ci.filled.len();
|
|
||||||
let right_unreachable = self.emit_control(self.ci.nodes[ctrl].outputs[roff]);
|
|
||||||
|
|
||||||
for fld in self.ci.filled.drain(filled_base..) {
|
|
||||||
self.ci.nodes[fld].depth = 0;
|
|
||||||
}
|
|
||||||
if let Some(region) = left_unreachable {
|
|
||||||
for i in 0..self.ci.nodes[region].outputs.len() {
|
|
||||||
let o = self.ci.nodes[region].outputs[i];
|
|
||||||
if self.ci.nodes[o].kind != Kind::Phi {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let out = self.ci.nodes[o].inputs[1 + roff];
|
|
||||||
self.emit_expr_consume(out);
|
|
||||||
self.emit_pass(out, o);
|
|
||||||
}
|
|
||||||
|
|
||||||
let right_end = self.ci.code.len();
|
|
||||||
if right_base == right_end {
|
|
||||||
self.ci.code.truncate(skip_then_offset as _);
|
|
||||||
} else {
|
|
||||||
write_reloc(
|
|
||||||
&mut self.ci.code,
|
|
||||||
skip_then_offset as usize + 1,
|
|
||||||
right_end as i64 - skip_then_offset,
|
|
||||||
4,
|
|
||||||
);
|
|
||||||
skip_then_offset += instrs::jmp(69).0 as i64;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
write_reloc(
|
|
||||||
&mut self.ci.code,
|
|
||||||
jump_offset as usize + 3,
|
|
||||||
skip_then_offset - jump_offset,
|
|
||||||
2,
|
|
||||||
);
|
|
||||||
|
|
||||||
let dest = left_unreachable.or(right_unreachable)?;
|
|
||||||
|
|
||||||
if self.ci.nodes[dest].kind == Kind::Loop {
|
|
||||||
return Some(dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
debug_assert_eq!(self.ci.nodes[dest].kind, Kind::Region);
|
|
||||||
|
|
||||||
ctrl = *self.ci.nodes[dest]
|
|
||||||
.outputs
|
|
||||||
.iter()
|
|
||||||
.find(|&&o| self.ci.nodes[o].kind != Kind::Phi)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
Kind::Region => return Some(ctrl),
|
|
||||||
Kind::Phi => todo!(),
|
|
||||||
Kind::Loop => {
|
|
||||||
if self.ci.nodes[ctrl].lock_rc != 0 {
|
|
||||||
return Some(ctrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
for i in 0..self.ci.nodes[ctrl].outputs.len() {
|
|
||||||
let o = self.ci.nodes[ctrl].outputs[i];
|
|
||||||
if self.ci.nodes[o].kind != Kind::Phi {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let out = self.ci.nodes[o].inputs[1];
|
|
||||||
self.emit_expr_consume(out);
|
|
||||||
self.emit_pass(out, o);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.ci.nodes[ctrl].lock_rc = self.ci.code.len() as _;
|
|
||||||
self.ci.loop_depth += 1;
|
|
||||||
|
|
||||||
let end = self.emit_control(
|
|
||||||
*self.ci.nodes[ctrl]
|
|
||||||
.outputs
|
|
||||||
.iter()
|
|
||||||
.find(|&&o| self.ci.nodes[o].kind != Kind::Phi)
|
|
||||||
.unwrap(),
|
|
||||||
);
|
|
||||||
|
|
||||||
debug_assert_eq!(end, Some(ctrl));
|
|
||||||
|
|
||||||
for i in 0..self.ci.nodes[ctrl].outputs.len() {
|
|
||||||
let o = self.ci.nodes[ctrl].outputs[i];
|
|
||||||
if self.ci.nodes[o].kind != Kind::Phi {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let out = self.ci.nodes[o].inputs[2];
|
|
||||||
// TODO: this can be improved if we juggle ownership of the Phi inputs
|
|
||||||
self.emit_expr(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
for i in 0..self.ci.nodes[ctrl].outputs.len() {
|
|
||||||
let o = self.ci.nodes[ctrl].outputs[i];
|
|
||||||
if self.ci.nodes[o].kind != Kind::Phi {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let out = self.ci.nodes[o].inputs[2];
|
|
||||||
self.use_expr(out);
|
|
||||||
self.emit_pass(out, o);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.ci.emit(instrs::jmp(
|
|
||||||
self.ci.nodes[ctrl].lock_rc as i32 - self.ci.code.len() as i32,
|
|
||||||
));
|
|
||||||
|
|
||||||
self.ci.loop_depth -= 1;
|
|
||||||
for free in self.ci.delayed_frees.extract_if(|&mut color| {
|
|
||||||
self.ci.colors[color as usize].depth == self.ci.loop_depth
|
|
||||||
}) {
|
|
||||||
let color = &self.ci.colors[free as usize];
|
|
||||||
debug_assert_ne!(color.loc, Loc::default());
|
|
||||||
self.ci.regs.free(color.loc.reg);
|
|
||||||
}
|
|
||||||
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn emit_expr_consume(&mut self, expr: Nid) {
|
|
||||||
self.emit_expr(expr);
|
|
||||||
self.use_expr(expr);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn emit_expr(&mut self, expr: Nid) {
|
|
||||||
if self.ci.nodes[expr].depth == IDomDepth::MAX {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.ci.nodes[expr].depth = IDomDepth::MAX;
|
|
||||||
self.ci.filled.push(expr);
|
|
||||||
|
|
||||||
match self.ci.nodes[expr].kind {
|
|
||||||
Kind::Start => unreachable!(),
|
|
||||||
Kind::End => unreachable!(),
|
|
||||||
Kind::Return => unreachable!(),
|
|
||||||
Kind::CInt { value } => {
|
|
||||||
_ = self.lazy_init(expr);
|
|
||||||
let instr = instrs::li64(node_loc!(self, expr).reg, value as _);
|
|
||||||
self.ci.emit(instr);
|
|
||||||
}
|
}
|
||||||
|
Kind::CInt { value } => todo!(),
|
||||||
|
Kind::Phi => todo!(),
|
||||||
Kind::Tuple { index } => {
|
Kind::Tuple { index } => {
|
||||||
debug_assert!(index != 0);
|
if self.ci.nodes[node.inputs[0]].kind == Kind::Start && index == 0 {
|
||||||
|
for o in node.outputs {
|
||||||
_ = self.lazy_init(expr);
|
self.color_node(o);
|
||||||
|
|
||||||
let mut params = self.tys.parama(self.ci.ret.unwrap());
|
|
||||||
for (i, var) in self.ci.vars.iter().enumerate() {
|
|
||||||
if var.value == Nid::MAX {
|
|
||||||
match self.tys.size_of(ty::Id::from_bt(var.id)) {
|
|
||||||
0 => {}
|
|
||||||
1..=8 => _ = params.next(),
|
|
||||||
s => todo!("{s}"),
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
self.color_node(node.inputs[0]);
|
||||||
match self.tys.size_of(self.ci.nodes[var.value].ty) {
|
|
||||||
0 => {}
|
|
||||||
1..=8 => {
|
|
||||||
let reg = params.next();
|
|
||||||
if i == index as usize - 1 {
|
|
||||||
crate::emit(
|
|
||||||
&mut self.ci.code,
|
|
||||||
instrs::cp(node_loc!(self, expr).reg, reg),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s => todo!("{s}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Kind::BinOp { op } => {
|
|
||||||
_ = self.lazy_init(expr);
|
|
||||||
let ty = self.tof(expr);
|
|
||||||
let &[_, left, right] = self.ci.nodes[expr].inputs.as_slice() else {
|
|
||||||
unreachable!()
|
|
||||||
};
|
|
||||||
self.emit_expr_consume(left);
|
|
||||||
|
|
||||||
if let Kind::CInt { value } = self.ci.nodes[right].kind
|
|
||||||
&& (node_loc!(self, right) == Loc::default()
|
|
||||||
|| self.ci.nodes[right].depth != IDomDepth::MAX)
|
|
||||||
&& let Some(op) = Self::imm_math_op(op, ty.is_signed(), self.tys.size_of(ty))
|
|
||||||
{
|
|
||||||
let instr =
|
|
||||||
op(node_loc!(self, expr).reg, node_loc!(self, left).reg, value as _);
|
|
||||||
self.ci.emit(instr);
|
|
||||||
} else {
|
} else {
|
||||||
self.emit_expr_consume(right);
|
todo!();
|
||||||
|
|
||||||
let op =
|
|
||||||
op.math_op(ty.is_signed(), self.tys.size_of(ty)).expect("TODO: what now?");
|
|
||||||
|
|
||||||
let instr = op(
|
|
||||||
node_loc!(self, expr).reg,
|
|
||||||
node_loc!(self, left).reg,
|
|
||||||
node_loc!(self, right).reg,
|
|
||||||
);
|
|
||||||
self.ci.emit(instr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
Kind::Call { .. } => {}
|
Kind::BinOp { op } => todo!(),
|
||||||
Kind::If => todo!(),
|
Kind::Call { func } => {
|
||||||
Kind::Region => todo!(),
|
let func = self.tys.funcs[func as usize].sig.unwrap();
|
||||||
Kind::Phi => {}
|
let mut parama = self.tys.parama(func.ret);
|
||||||
Kind::Loop => todo!(),
|
for (&i, ti) in node.inputs[1..].iter().zip(func.args.range()) {
|
||||||
}
|
let ty = self.tys.args[ti];
|
||||||
}
|
match self.tys.size_of(ty) {
|
||||||
|
0 => continue,
|
||||||
fn use_expr(&mut self, expr: Nid) {
|
1..=8 => {
|
||||||
let node = &mut self.ci.nodes[expr];
|
// FIXME: scan idoms to see if there is a call inbetween
|
||||||
node.lock_rc = node.lock_rc.saturating_sub(1);
|
let col = self.ci.set_next_color(i);
|
||||||
if node.lock_rc != 0 {
|
self.ci.colors[col as usize - 1].loc = Loc { reg: parama.next() };
|
||||||
return;
|
self.ci.nodes.visited.set(i);
|
||||||
}
|
}
|
||||||
|
_ => todo!(),
|
||||||
let color = &mut self.ci.colors[node.color as usize - 1];
|
|
||||||
color.rc -= 1;
|
|
||||||
if color.rc == 0 {
|
|
||||||
if color.depth != self.ci.loop_depth {
|
|
||||||
self.ci.delayed_frees.push(node.color);
|
|
||||||
} else if color.loc != Loc::default() {
|
|
||||||
self.ci.regs.free(color.loc.reg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
fn imm_math_op(
|
|
||||||
op: TokenKind,
|
|
||||||
signed: bool,
|
|
||||||
size: u32,
|
|
||||||
) -> Option<fn(u8, u8, u64) -> (usize, [u8; instrs::MAX_SIZE])> {
|
|
||||||
use {instrs::*, TokenKind as T};
|
|
||||||
|
|
||||||
macro_rules! def_op {
|
|
||||||
($name:ident |$a:ident, $b:ident, $c:ident| $($tt:tt)*) => {
|
|
||||||
macro_rules! $name {
|
|
||||||
($$($$op:ident),*) => {
|
|
||||||
[$$(
|
|
||||||
|$a, $b, $c: u64| $$op($($tt)*),
|
|
||||||
)*]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
for o in node.outputs {
|
||||||
|
self.color_node(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.color_node(node.inputs[0]);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_node(&mut self, ctrl: Nid) -> Option<Nid> {
|
||||||
|
if !self.ci.nodes.visited.set(ctrl) {
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
def_op!(basic_op | a, b, c | a, b, c as _);
|
let node = self.ci.nodes[ctrl].clone();
|
||||||
def_op!(sub_op | a, b, c | a, b, c.wrapping_neg() as _);
|
match node.kind {
|
||||||
|
Kind::Start => self.emit_node(node.outputs[0]),
|
||||||
|
Kind::End => None,
|
||||||
|
Kind::If => todo!(),
|
||||||
|
Kind::Region => todo!(),
|
||||||
|
Kind::Loop => todo!(),
|
||||||
|
Kind::Return => {
|
||||||
|
self.ci.ret_relocs.push(Reloc::new(self.ci.code.len(), 1, 4));
|
||||||
|
self.ci.emit(instrs::jmp(0));
|
||||||
|
self.emit_node(node.outputs[0]);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Kind::CInt { value } => {
|
||||||
|
if node_loc!(self, ctrl) == Loc::default() {
|
||||||
|
node_loc!(self, ctrl) = Loc { reg: self.ci.regs.allocate(0) };
|
||||||
|
}
|
||||||
|
|
||||||
let ops = match op {
|
// TODO: respect size
|
||||||
T::Add => basic_op!(addi8, addi16, addi32, addi64),
|
self.ci.emit(instrs::li64(node_loc!(self, ctrl).reg, value as _));
|
||||||
T::Sub => sub_op!(addi8, addi16, addi32, addi64),
|
None
|
||||||
T::Mul => basic_op!(muli8, muli16, muli32, muli64),
|
}
|
||||||
T::Band => return Some(andi),
|
Kind::Phi => todo!(),
|
||||||
T::Bor => return Some(ori),
|
Kind::Tuple { index } => {
|
||||||
T::Xor => return Some(xori),
|
if (self.ci.nodes[node.inputs[0]].kind == Kind::Start && index == 0)
|
||||||
T::Shr if signed => basic_op!(srui8, srui16, srui32, srui64),
|
|| (self.ci.nodes[node.inputs[0]].kind == Kind::If && index < 2)
|
||||||
T::Shr => basic_op!(srui8, srui16, srui32, srui64),
|
{
|
||||||
T::Shl => basic_op!(slui8, slui16, slui32, slui64),
|
for o in node.outputs.into_iter().rev() {
|
||||||
_ => return None,
|
self.emit_node(o);
|
||||||
};
|
}
|
||||||
|
} else {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
Some(ops[size.ilog2() as usize])
|
None
|
||||||
|
}
|
||||||
|
Kind::BinOp { op } => todo!(),
|
||||||
|
Kind::Call { func } => todo!(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: sometimes its better to do this in bulk
|
// TODO: sometimes its better to do this in bulk
|
||||||
|
@ -3014,8 +2499,8 @@ mod tests {
|
||||||
variables => README;
|
variables => README;
|
||||||
functions => README;
|
functions => README;
|
||||||
comments => README;
|
comments => README;
|
||||||
if_statements => README;
|
// if_statements => README;
|
||||||
loops => README;
|
// loops => README;
|
||||||
//fb_driver => README;
|
//fb_driver => README;
|
||||||
//pointers => README;
|
//pointers => README;
|
||||||
//structs => README;
|
//structs => README;
|
||||||
|
@ -3037,9 +2522,9 @@ mod tests {
|
||||||
//comptime_function_from_another_file => README;
|
//comptime_function_from_another_file => README;
|
||||||
//inline => README;
|
//inline => README;
|
||||||
//inline_test => README;
|
//inline_test => README;
|
||||||
const_folding_with_arg => README;
|
// const_folding_with_arg => README;
|
||||||
// FIXME: contains redundant copies
|
// FIXME: contains redundant copies
|
||||||
branch_assignments => README;
|
// branch_assignments => README;
|
||||||
exhaustive_loop_testing => README;
|
// exhaustive_loop_testing => README;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,11 +14,15 @@ main:
|
||||||
LI64 r33, 4d
|
LI64 r33, 4d
|
||||||
MULI64 r33, r33, 4d
|
MULI64 r33, r33, 4d
|
||||||
SUB64 r32, r32, r33
|
SUB64 r32, r32, r33
|
||||||
ADDI64 r32, r32, 1d
|
LI64 r33, 1d
|
||||||
SLUI64 r1, r32, 0b
|
SLUI64 r33, r33, 0b
|
||||||
|
ADD64 r32, r32, r33
|
||||||
|
LI64 r33, 1d
|
||||||
|
NEG r33, r33
|
||||||
|
ADD64 r1, r32, r33
|
||||||
LD r31, r254, 0a, 32h
|
LD r31, r254, 0a, 32h
|
||||||
ADDI64 r254, r254, 32d
|
ADDI64 r254, r254, 32d
|
||||||
JALA r0, r31, 0a
|
JALA r0, r31, 0a
|
||||||
code size: 185
|
code size: 205
|
||||||
ret: 1
|
ret: 0
|
||||||
status: Ok(())
|
status: Ok(())
|
||||||
|
|
|
@ -113,7 +113,7 @@ where
|
||||||
DIRS64 => self.dir::<i64>(),
|
DIRS64 => self.dir::<i64>(),
|
||||||
NEG => handler!(self, |OpsRR(tg, a0)| {
|
NEG => handler!(self, |OpsRR(tg, a0)| {
|
||||||
// Bit negation
|
// Bit negation
|
||||||
self.write_reg(tg, !self.read_reg(a0).cast::<u64>())
|
self.write_reg(tg, self.read_reg(a0).cast::<u64>().wrapping_neg())
|
||||||
}),
|
}),
|
||||||
NOT => handler!(self, |OpsRR(tg, a0)| {
|
NOT => handler!(self, |OpsRR(tg, a0)| {
|
||||||
// Logical negation
|
// Logical negation
|
||||||
|
|
Loading…
Reference in a new issue