forked from AbleOS/holey-bytes
fixing code scheduling bugs
This commit is contained in:
parent
89cc611f7a
commit
6ad0b41759
|
@ -452,6 +452,8 @@ mod ty {
|
||||||
|
|
||||||
builtin_type! {
|
builtin_type! {
|
||||||
UNDECLARED;
|
UNDECLARED;
|
||||||
|
LEFT_UNREACHABLE;
|
||||||
|
RIGHT_UNREACHABLE;
|
||||||
NEVER;
|
NEVER;
|
||||||
VOID;
|
VOID;
|
||||||
TYPE;
|
TYPE;
|
||||||
|
@ -464,8 +466,7 @@ mod ty {
|
||||||
I16;
|
I16;
|
||||||
I32;
|
I32;
|
||||||
INT;
|
INT;
|
||||||
LEFT_UNREACHABLE;
|
|
||||||
RIGHT_UNREACHABLE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! type_kind {
|
macro_rules! type_kind {
|
||||||
|
|
|
@ -210,7 +210,9 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let index = self.ctx.idents.binary_search_by_key(&id, |s| s.ident).expect("fck up");
|
let Ok(index) = self.ctx.idents.binary_search_by_key(&id, |s| s.ident) else {
|
||||||
|
self.report(pos, "the identifier is rezerved for a builtin (proably)");
|
||||||
|
};
|
||||||
if core::mem::replace(&mut self.ctx.idents[index].declared, true) {
|
if core::mem::replace(&mut self.ctx.idents[index].declared, true) {
|
||||||
self.report(
|
self.report(
|
||||||
pos,
|
pos,
|
||||||
|
|
445
lang/src/son.rs
445
lang/src/son.rs
|
@ -9,8 +9,7 @@ use {
|
||||||
idfl::{self},
|
idfl::{self},
|
||||||
Expr, ExprRef, FileId, Pos,
|
Expr, ExprRef, FileId, Pos,
|
||||||
},
|
},
|
||||||
reg, task,
|
reg, task, ty,
|
||||||
ty::{self},
|
|
||||||
vc::{BitSet, Vc},
|
vc::{BitSet, Vc},
|
||||||
Func, HashMap, Offset, OffsetIter, Reloc, Sig, SymKey, TypedReloc, Types,
|
Func, HashMap, Offset, OffsetIter, Reloc, Sig, SymKey, TypedReloc, Types,
|
||||||
},
|
},
|
||||||
|
@ -35,6 +34,16 @@ type Nid = u16;
|
||||||
|
|
||||||
type Lookup = crate::ctx_map::CtxMap<Nid>;
|
type Lookup = crate::ctx_map::CtxMap<Nid>;
|
||||||
|
|
||||||
|
trait StoreId: Sized {
|
||||||
|
fn to_store(self) -> Option<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StoreId for Nid {
|
||||||
|
fn to_store(self) -> Option<Self> {
|
||||||
|
(self != NEVER).then_some(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl crate::ctx_map::CtxEntry for Nid {
|
impl crate::ctx_map::CtxEntry for Nid {
|
||||||
type Ctx = [Result<Node, Nid>];
|
type Ctx = [Result<Node, Nid>];
|
||||||
type Key<'a> = (Kind, &'a [Nid], ty::Id);
|
type Key<'a> = (Kind, &'a [Nid], ty::Id);
|
||||||
|
@ -416,7 +425,7 @@ impl Nodes {
|
||||||
Kind::Stck => write!(out, "stck: "),
|
Kind::Stck => write!(out, "stck: "),
|
||||||
Kind::Load => write!(out, "load: "),
|
Kind::Load => write!(out, "load: "),
|
||||||
Kind::Stre => write!(out, "stre: "),
|
Kind::Stre => write!(out, "stre: "),
|
||||||
_ => unreachable!(),
|
Kind::Mem => write!(out, " mem: "),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
if self[node].kind != Kind::Loop && self[node].kind != Kind::Region {
|
if self[node].kind != Kind::Loop && self[node].kind != Kind::Region {
|
||||||
|
@ -613,26 +622,48 @@ impl Nodes {
|
||||||
target
|
target
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_loop_value(&mut self, index: usize, value: &mut Value, loops: &mut [Loop]) {
|
fn load_loop_var(&mut self, index: usize, value: &mut Nid, loops: &mut [Loop]) {
|
||||||
if value.id != 0 {
|
self.load_loop_value(
|
||||||
debug_assert!(!value.var);
|
&mut |l| {
|
||||||
|
l.scope
|
||||||
|
.vars
|
||||||
|
.get_mut(index)
|
||||||
|
.map_or((ty::Id::VOID, &mut l.scope.store), |v| (v.ty, &mut v.value))
|
||||||
|
},
|
||||||
|
value,
|
||||||
|
loops,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_loop_store(&mut self, value: &mut Nid, loops: &mut [Loop]) {
|
||||||
|
self.load_loop_value(&mut |l| (ty::Id::VOID, &mut l.scope.store), value, loops);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_loop_value(
|
||||||
|
&mut self,
|
||||||
|
get_lvalue: &mut impl FnMut(&mut Loop) -> (ty::Id, &mut Nid),
|
||||||
|
value: &mut Nid,
|
||||||
|
loops: &mut [Loop],
|
||||||
|
) {
|
||||||
|
if *value != VOID {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let [loob, loops @ ..] = loops else { unreachable!() };
|
let [loob, loops @ ..] = loops else { unreachable!() };
|
||||||
let lvalue = &mut loob.scope.vars[index].value;
|
let node = loob.node;
|
||||||
|
let (ty, lvalue) = get_lvalue(loob);
|
||||||
|
|
||||||
self.load_loop_value(index, lvalue, loops);
|
self.load_loop_value(get_lvalue, lvalue, loops);
|
||||||
|
|
||||||
if !self[lvalue.id].is_lazy_phi() {
|
if !self[*lvalue].is_lazy_phi() {
|
||||||
self.unlock(value.id);
|
self.unlock(*value);
|
||||||
let inps = [loob.node, lvalue.id, VOID];
|
let inps = [node, *lvalue, VOID];
|
||||||
self.unlock(lvalue.id);
|
self.unlock(*lvalue);
|
||||||
lvalue.id = self.new_node_nop(lvalue.ty, Kind::Phi, inps);
|
*lvalue = self.new_node_nop(ty, Kind::Phi, inps);
|
||||||
self[lvalue.id].lock_rc += 2;
|
self[*lvalue].lock_rc += 2;
|
||||||
} else {
|
} else {
|
||||||
self.lock(lvalue.id);
|
self.lock(*lvalue);
|
||||||
self.unlock(value.id);
|
self.unlock(*value);
|
||||||
}
|
}
|
||||||
*value = *lvalue;
|
*value = *lvalue;
|
||||||
}
|
}
|
||||||
|
@ -679,26 +710,26 @@ impl Nodes {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lock_scope(&mut self, scope: &Scope) {
|
fn lock_scope(&mut self, scope: &Scope) {
|
||||||
if let Some(str) = scope.store {
|
if let Some(str) = scope.store.to_store() {
|
||||||
self.lock(str);
|
self.lock(str);
|
||||||
}
|
}
|
||||||
for &load in &scope.loads {
|
for &load in &scope.loads {
|
||||||
self.lock(load);
|
self.lock(load);
|
||||||
}
|
}
|
||||||
for var in &scope.vars {
|
for var in &scope.vars {
|
||||||
self.lock(var.value.id);
|
self.lock(var.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unlock_remove_scope(&mut self, scope: &Scope) {
|
fn unlock_remove_scope(&mut self, scope: &Scope) {
|
||||||
if let Some(str) = scope.store {
|
if let Some(str) = scope.store.to_store() {
|
||||||
self.unlock_remove(str);
|
self.unlock_remove(str);
|
||||||
}
|
}
|
||||||
for &load in &scope.loads {
|
for &load in &scope.loads {
|
||||||
self.unlock_remove(load);
|
self.unlock_remove(load);
|
||||||
}
|
}
|
||||||
for var in &scope.vars {
|
for var in &scope.vars {
|
||||||
self.unlock_remove(var.value.id);
|
self.unlock_remove(var.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -768,7 +799,7 @@ pub enum Kind {
|
||||||
|
|
||||||
impl Kind {
|
impl Kind {
|
||||||
fn is_pinned(&self) -> bool {
|
fn is_pinned(&self) -> bool {
|
||||||
self.is_cfg() || matches!(self, Self::Phi | Self::Mem)
|
self.is_cfg() || matches!(self, Self::Phi | Self::Mem | Self::Arg { .. })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_cfg(&self) -> bool {
|
fn is_cfg(&self) -> bool {
|
||||||
|
@ -780,7 +811,6 @@ impl Kind {
|
||||||
| Self::Entry
|
| Self::Entry
|
||||||
| Self::Then
|
| Self::Then
|
||||||
| Self::Else
|
| Self::Else
|
||||||
| Self::Arg { .. }
|
|
||||||
| Self::Call { .. }
|
| Self::Call { .. }
|
||||||
| Self::If
|
| Self::If
|
||||||
| Self::Region
|
| Self::Region
|
||||||
|
@ -850,14 +880,24 @@ struct Loop {
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
struct Variable {
|
struct Variable {
|
||||||
id: Ident,
|
id: Ident,
|
||||||
value: Value,
|
ty: ty::Id,
|
||||||
|
value: Nid,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
struct Scope {
|
struct Scope {
|
||||||
vars: Vec<Variable>,
|
vars: Vec<Variable>,
|
||||||
loads: Vec<Nid>,
|
loads: Vec<Nid>,
|
||||||
store: Option<Nid>,
|
store: Nid,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scope {
|
||||||
|
pub fn iter_elems_mut(&mut self) -> impl Iterator<Item = (ty::Id, &mut Nid)> {
|
||||||
|
self.vars
|
||||||
|
.iter_mut()
|
||||||
|
.map(|v| (v.ty, &mut v.value))
|
||||||
|
.chain(core::iter::once((ty::Id::VOID, &mut self.store)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -943,7 +983,7 @@ impl Default for Regalloc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone, Copy)]
|
#[derive(Default, Clone, Copy, PartialEq, Eq)]
|
||||||
struct Value {
|
struct Value {
|
||||||
ty: ty::Id,
|
ty: ty::Id,
|
||||||
var: bool,
|
var: bool,
|
||||||
|
@ -1025,8 +1065,13 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn store_mem(&mut self, region: Nid, value: Nid) -> Nid {
|
fn store_mem(&mut self, region: Nid, value: Nid) -> Nid {
|
||||||
|
if value == NEVER {
|
||||||
|
return NEVER;
|
||||||
|
}
|
||||||
|
|
||||||
let mut vc = Vc::from([VOID, value, region]);
|
let mut vc = Vc::from([VOID, value, region]);
|
||||||
if let Some(str) = self.ci.scope.store {
|
self.ci.nodes.load_loop_store(&mut self.ci.scope.store, &mut self.ci.loops);
|
||||||
|
if let Some(str) = self.ci.scope.store.to_store() {
|
||||||
self.ci.nodes.unlock(str);
|
self.ci.nodes.unlock(str);
|
||||||
vc.push(str);
|
vc.push(str);
|
||||||
}
|
}
|
||||||
|
@ -1041,13 +1086,15 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
let store = self.ci.nodes.new_node(self.tof(value), Kind::Stre, vc);
|
let store = self.ci.nodes.new_node(self.tof(value), Kind::Stre, vc);
|
||||||
self.ci.nodes.lock(store);
|
self.ci.nodes.lock(store);
|
||||||
self.ci.scope.store = Some(store);
|
self.ci.scope.store = store;
|
||||||
store
|
store
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_mem(&mut self, region: Nid, ty: ty::Id) -> Nid {
|
fn load_mem(&mut self, region: Nid, ty: ty::Id) -> Nid {
|
||||||
|
debug_assert_ne!(region, VOID);
|
||||||
let mut vc = Vc::from([VOID, region]);
|
let mut vc = Vc::from([VOID, region]);
|
||||||
if let Some(str) = self.ci.scope.store {
|
self.ci.nodes.load_loop_store(&mut self.ci.scope.store, &mut self.ci.loops);
|
||||||
|
if let Some(str) = self.ci.scope.store.to_store() {
|
||||||
vc.push(str);
|
vc.push(str);
|
||||||
}
|
}
|
||||||
let load = self.ci.nodes.new_node(ty, Kind::Load, vc);
|
let load = self.ci.nodes.new_node(ty, Kind::Load, vc);
|
||||||
|
@ -1086,14 +1133,13 @@ impl Codegen {
|
||||||
return Value::NEVER;
|
return Value::NEVER;
|
||||||
};
|
};
|
||||||
|
|
||||||
self.ci.nodes.load_loop_value(
|
self.ci.nodes.load_loop_var(
|
||||||
index,
|
index,
|
||||||
&mut self.ci.scope.vars[index].value,
|
&mut self.ci.scope.vars[index].value,
|
||||||
&mut self.ci.loops,
|
&mut self.ci.loops,
|
||||||
);
|
);
|
||||||
debug_assert_ne!(self.ci.scope.vars[index].value.ty, ty::Id::VOID);
|
|
||||||
|
|
||||||
Some(Value::var(index).ty(self.ci.scope.vars[index].value.ty))
|
Some(Value::var(index).ty(self.ci.scope.vars[index].ty))
|
||||||
}
|
}
|
||||||
Expr::Number { value, .. } => Some(self.ci.nodes.new_node_lit(
|
Expr::Number { value, .. } => Some(self.ci.nodes.new_node_lit(
|
||||||
ctx.ty.filter(|ty| ty.is_integer() || ty.is_pointer()).unwrap_or(ty::Id::INT),
|
ctx.ty.filter(|ty| ty.is_integer() || ty.is_pointer()).unwrap_or(ty::Id::INT),
|
||||||
|
@ -1108,8 +1154,9 @@ impl Codegen {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut inps = Vc::from([self.ci.ctrl, value.id]);
|
let mut inps = Vc::from([self.ci.ctrl, value.id]);
|
||||||
for &m in self.ci.scope.store.iter() {
|
self.ci.nodes.load_loop_store(&mut self.ci.scope.store, &mut self.ci.loops);
|
||||||
inps.push(m);
|
if let Some(str) = self.ci.scope.store.to_store() {
|
||||||
|
inps.push(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.ci.ctrl = self.ci.nodes.new_node(ty::Id::VOID, Kind::Return, inps);
|
self.ci.ctrl = self.ci.nodes.new_node(ty::Id::VOID, Kind::Return, inps);
|
||||||
|
@ -1202,7 +1249,7 @@ impl Codegen {
|
||||||
Expr::BinOp { left: &Expr::Ident { id, .. }, op: TokenKind::Decl, right } => {
|
Expr::BinOp { left: &Expr::Ident { id, .. }, op: TokenKind::Decl, right } => {
|
||||||
let value = self.expr(right)?;
|
let value = self.expr(right)?;
|
||||||
self.ci.nodes.lock(value.id);
|
self.ci.nodes.lock(value.id);
|
||||||
self.ci.scope.vars.push(Variable { id, value });
|
self.ci.scope.vars.push(Variable { id, value: value.id, ty: value.ty });
|
||||||
Some(Value::VOID)
|
Some(Value::VOID)
|
||||||
}
|
}
|
||||||
Expr::BinOp { left, op: TokenKind::Assign, right } => {
|
Expr::BinOp { left, op: TokenKind::Assign, right } => {
|
||||||
|
@ -1214,8 +1261,8 @@ impl Codegen {
|
||||||
if dest.var {
|
if dest.var {
|
||||||
self.ci.nodes.lock(value.id);
|
self.ci.nodes.lock(value.id);
|
||||||
let var = &mut self.ci.scope.vars[(u16::MAX - dest.id) as usize];
|
let var = &mut self.ci.scope.vars[(u16::MAX - dest.id) as usize];
|
||||||
let prev = core::mem::replace(&mut var.value, value);
|
let prev = core::mem::replace(&mut var.value, value.id);
|
||||||
self.ci.nodes.unlock_remove(prev.id);
|
self.ci.nodes.unlock_remove(prev);
|
||||||
} else if dest.ptr {
|
} else if dest.ptr {
|
||||||
self.store_mem(dest.id, value.id);
|
self.store_mem(dest.id, value.id);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1242,6 +1289,10 @@ impl Codegen {
|
||||||
[VOID],
|
[VOID],
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
Expr::Directive { name: "as", args: [ty, expr], .. } => {
|
||||||
|
let ctx = Ctx::default().with_ty(self.ty(ty));
|
||||||
|
self.expr_ctx(expr, ctx)
|
||||||
|
}
|
||||||
Expr::Call { func: &Expr::Ident { pos, id, .. }, args, .. } => {
|
Expr::Call { func: &Expr::Ident { pos, id, .. }, args, .. } => {
|
||||||
self.ci.call_count += 1;
|
self.ci.call_count += 1;
|
||||||
let cfile = self.cfile().clone();
|
let cfile = self.cfile().clone();
|
||||||
|
@ -1294,7 +1345,7 @@ impl Codegen {
|
||||||
inps.push(value.id);
|
inps.push(value.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(str) = self.ci.scope.store {
|
if let Some(str) = self.ci.scope.store.to_store() {
|
||||||
inps.push(str);
|
inps.push(str);
|
||||||
}
|
}
|
||||||
for load in self.ci.scope.loads.drain(..) {
|
for load in self.ci.scope.loads.drain(..) {
|
||||||
|
@ -1317,6 +1368,59 @@ impl Codegen {
|
||||||
|
|
||||||
Some(Value::new(self.ci.ctrl).ty(sig.ret))
|
Some(Value::new(self.ci.ctrl).ty(sig.ret))
|
||||||
}
|
}
|
||||||
|
Expr::Tupl { pos, ty, fields, .. } => {
|
||||||
|
let Some(sty) = ty.map(|ty| self.ty(ty)).or(ctx.ty) else {
|
||||||
|
self.report(
|
||||||
|
pos,
|
||||||
|
"the type of struct cannot be inferred from context, \
|
||||||
|
use an explicit type instead: <type>.{ ... }",
|
||||||
|
);
|
||||||
|
return Value::NEVER;
|
||||||
|
};
|
||||||
|
|
||||||
|
let ty::Kind::Struct(s) = sty.expand() else {
|
||||||
|
let inferred = if ty.is_some() { "" } else { "inferred " };
|
||||||
|
self.report(
|
||||||
|
pos,
|
||||||
|
fa!(
|
||||||
|
"the {inferred}type of the constructor is `{}`, \
|
||||||
|
but thats not a struct",
|
||||||
|
self.ty_display(sty)
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return Value::NEVER;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: dont allocate
|
||||||
|
let mut offs = OffsetIter::new(s, &self.tys);
|
||||||
|
let mem = self.ci.nodes.new_node(sty, Kind::Stck, [VOID, MEM]);
|
||||||
|
for field in fields {
|
||||||
|
let Some((ty, offset)) = offs.next_ty(&self.tys) else {
|
||||||
|
self.report(field.pos(), "this init argumen overflows the field count");
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
let value = self.expr_ctx(field, Ctx::default().with_ty(ty))?;
|
||||||
|
let mem = self.offset(mem, ty, offset);
|
||||||
|
self.store_mem(mem, value.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let field_list = offs
|
||||||
|
.into_iter(&self.tys)
|
||||||
|
.map(|(f, ..)| self.tys.names.ident_str(f.name))
|
||||||
|
.intersperse(", ")
|
||||||
|
.collect::<String>();
|
||||||
|
|
||||||
|
if !field_list.is_empty() {
|
||||||
|
self.report(
|
||||||
|
pos,
|
||||||
|
fa!("the struct initializer is missing {field_list} \
|
||||||
|
(append them to the end of the constructor)"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Value::ptr(mem).ty(sty))
|
||||||
|
}
|
||||||
Expr::Ctor { pos, ty, fields, .. } => {
|
Expr::Ctor { pos, ty, fields, .. } => {
|
||||||
let Some(sty) = ty.map(|ty| self.ty(ty)).or(ctx.ty) else {
|
let Some(sty) = ty.map(|ty| self.ty(ty)).or(ctx.ty) else {
|
||||||
self.report(
|
self.report(
|
||||||
|
@ -1400,7 +1504,7 @@ impl Codegen {
|
||||||
|
|
||||||
self.ci.nodes.lock(self.ci.ctrl);
|
self.ci.nodes.lock(self.ci.ctrl);
|
||||||
for var in self.ci.scope.vars.drain(base..) {
|
for var in self.ci.scope.vars.drain(base..) {
|
||||||
self.ci.nodes.unlock_remove(var.value.id);
|
self.ci.nodes.unlock_remove(var.value);
|
||||||
}
|
}
|
||||||
self.ci.nodes.unlock(self.ci.ctrl);
|
self.ci.nodes.unlock(self.ci.ctrl);
|
||||||
|
|
||||||
|
@ -1415,8 +1519,8 @@ impl Codegen {
|
||||||
scope: self.ci.scope.clone(),
|
scope: self.ci.scope.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
for var in &mut self.ci.scope.vars {
|
for (_, var) in &mut self.ci.scope.iter_elems_mut() {
|
||||||
var.value = Value::VOID;
|
*var = VOID;
|
||||||
}
|
}
|
||||||
self.ci.nodes.lock_scope(&self.ci.scope);
|
self.ci.nodes.lock_scope(&self.ci.scope);
|
||||||
|
|
||||||
|
@ -1461,66 +1565,50 @@ impl Codegen {
|
||||||
|
|
||||||
core::mem::swap(&mut self.ci.scope, &mut bres);
|
core::mem::swap(&mut self.ci.scope, &mut bres);
|
||||||
|
|
||||||
for ((dest_var, mut scope_var), loop_var) in
|
for (((_, dest_value), (_, &mut mut scope_value)), (_, &mut loop_value)) in self
|
||||||
self.ci.scope.vars.iter_mut().zip(scope.vars.drain(..)).zip(bres.vars.drain(..))
|
.ci
|
||||||
|
.scope
|
||||||
|
.iter_elems_mut()
|
||||||
|
.zip(scope.iter_elems_mut())
|
||||||
|
.zip(bres.iter_elems_mut())
|
||||||
{
|
{
|
||||||
self.ci.nodes.unlock(loop_var.value.id);
|
self.ci.nodes.unlock(loop_value);
|
||||||
|
|
||||||
if loop_var.value.id != VOID {
|
if loop_value != VOID {
|
||||||
self.ci.nodes.unlock(scope_var.value.id);
|
self.ci.nodes.unlock(scope_value);
|
||||||
if loop_var.value.id != scope_var.value.id {
|
if loop_value != scope_value {
|
||||||
scope_var.value.id = self.ci.nodes.modify_input(
|
scope_value = self.ci.nodes.modify_input(scope_value, 2, loop_value);
|
||||||
scope_var.value.id,
|
self.ci.nodes.lock(scope_value);
|
||||||
2,
|
|
||||||
loop_var.value.id,
|
|
||||||
);
|
|
||||||
self.ci.nodes.lock(scope_var.value.id);
|
|
||||||
} else {
|
} else {
|
||||||
if dest_var.value.id == scope_var.value.id {
|
if *dest_value == scope_value {
|
||||||
self.ci.nodes.unlock(dest_var.value.id);
|
self.ci.nodes.unlock(*dest_value);
|
||||||
dest_var.value.id = VOID;
|
*dest_value = VOID;
|
||||||
self.ci.nodes.lock(dest_var.value.id);
|
self.ci.nodes.lock(*dest_value);
|
||||||
}
|
}
|
||||||
let phi = &self.ci.nodes[scope_var.value.id];
|
let phi = &self.ci.nodes[scope_value];
|
||||||
debug_assert_eq!(phi.kind, Kind::Phi);
|
debug_assert_eq!(phi.kind, Kind::Phi);
|
||||||
debug_assert_eq!(phi.inputs[2], VOID);
|
debug_assert_eq!(phi.inputs[2], VOID);
|
||||||
debug_assert_eq!(phi.ty, scope_var.value.ty);
|
|
||||||
let prev = phi.inputs[1];
|
let prev = phi.inputs[1];
|
||||||
self.ci.nodes.replace(scope_var.value.id, prev);
|
self.ci.nodes.replace(scope_value, prev);
|
||||||
scope_var.value.id = prev;
|
scope_value = prev;
|
||||||
self.ci.nodes.lock(prev);
|
self.ci.nodes.lock(prev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if dest_var.value.id == VOID {
|
if *dest_value == VOID {
|
||||||
self.ci.nodes.unlock(dest_var.value.id);
|
self.ci.nodes.unlock(*dest_value);
|
||||||
dest_var.value = scope_var.value;
|
*dest_value = scope_value;
|
||||||
self.ci.nodes.lock(dest_var.value.id);
|
self.ci.nodes.lock(*dest_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
self.ci.nodes[dest_var.value.id].kind != Kind::Phi
|
self.ci.nodes[*dest_value].kind != Kind::Phi
|
||||||
|| self.ci.nodes[dest_var.value.id].inputs[2] != 0
|
|| self.ci.nodes[*dest_value].inputs[2] != 0
|
||||||
);
|
);
|
||||||
|
|
||||||
self.ci.nodes.unlock_remove(scope_var.value.id);
|
self.ci.nodes.unlock_remove(scope_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if bres.store != scope.store {
|
|
||||||
let (to_store, from_store, prev) =
|
|
||||||
(bres.store.unwrap(), scope.store.unwrap(), self.ci.scope.store.unwrap());
|
|
||||||
self.ci.nodes.unlock_remove(prev);
|
|
||||||
self.ci.scope.store = Some(
|
|
||||||
self.ci
|
|
||||||
.nodes
|
|
||||||
.new_node(ty::Id::VOID, Kind::Phi, [node, from_store, to_store]),
|
|
||||||
);
|
|
||||||
self.ci.nodes.lock(self.ci.scope.store.unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
self.ci.nodes.unlock_remove_scope(&scope);
|
|
||||||
self.ci.nodes.unlock_remove_scope(&bres);
|
|
||||||
|
|
||||||
self.ci.nodes.unlock(self.ci.ctrl);
|
self.ci.nodes.unlock(self.ci.ctrl);
|
||||||
|
|
||||||
Some(Value::VOID)
|
Some(Value::VOID)
|
||||||
|
@ -1551,8 +1639,9 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.ci.nodes.load_loop_store(&mut self.ci.scope.store, &mut self.ci.loops);
|
||||||
let orig_store = self.ci.scope.store;
|
let orig_store = self.ci.scope.store;
|
||||||
if let Some(str) = orig_store {
|
if let Some(str) = orig_store.to_store() {
|
||||||
self.ci.nodes.lock(str);
|
self.ci.nodes.lock(str);
|
||||||
}
|
}
|
||||||
let else_scope = self.ci.scope.clone();
|
let else_scope = self.ci.scope.clone();
|
||||||
|
@ -1569,7 +1658,7 @@ impl Codegen {
|
||||||
self.ci.ctrl
|
self.ci.ctrl
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(str) = orig_store {
|
if let Some(str) = orig_store.to_store() {
|
||||||
self.ci.nodes.unlock_remove(str);
|
self.ci.nodes.unlock_remove(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1628,12 +1717,8 @@ impl Codegen {
|
||||||
fn strip_var(&mut self, n: &mut Value) {
|
fn strip_var(&mut self, n: &mut Value) {
|
||||||
if core::mem::take(&mut n.var) {
|
if core::mem::take(&mut n.var) {
|
||||||
let id = (u16::MAX - n.id) as usize;
|
let id = (u16::MAX - n.id) as usize;
|
||||||
self.ci.nodes.load_loop_value(
|
self.ci.nodes.load_loop_var(id, &mut self.ci.scope.vars[id].value, &mut self.ci.loops);
|
||||||
id,
|
n.id = self.ci.scope.vars[id].value;
|
||||||
&mut self.ci.scope.vars[id].value,
|
|
||||||
&mut self.ci.loops,
|
|
||||||
);
|
|
||||||
*n = self.ci.scope.vars[id].value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1683,32 +1768,26 @@ impl Codegen {
|
||||||
from: &mut Scope,
|
from: &mut Scope,
|
||||||
drop_from: bool,
|
drop_from: bool,
|
||||||
) {
|
) {
|
||||||
for (i, (to_var, from_var)) in to.vars.iter_mut().zip(&mut from.vars).enumerate() {
|
for (i, ((ty, to_value), (_, from_value))) in
|
||||||
if to_var.value.id != from_var.value.id {
|
to.iter_elems_mut().zip(from.iter_elems_mut()).enumerate()
|
||||||
nodes.load_loop_value(i, &mut from_var.value, loops);
|
{
|
||||||
nodes.load_loop_value(i, &mut to_var.value, loops);
|
if to_value != from_value {
|
||||||
if to_var.value.id != from_var.value.id {
|
nodes.load_loop_var(i, from_value, loops);
|
||||||
let ty = nodes[to_var.value.id].ty;
|
nodes.load_loop_var(i, to_value, loops);
|
||||||
debug_assert_eq!(ty, nodes[from_var.value.id].ty, "TODO: typecheck properly");
|
if to_value != from_value {
|
||||||
|
let inps = [ctrl, *from_value, *to_value];
|
||||||
let inps = [ctrl, from_var.value.id, to_var.value.id];
|
nodes.unlock(*to_value);
|
||||||
nodes.unlock(to_var.value.id);
|
*to_value = nodes.new_node(ty, Kind::Phi, inps);
|
||||||
to_var.value.id = nodes.new_node(ty, Kind::Phi, inps);
|
nodes.lock(*to_value);
|
||||||
nodes.lock(to_var.value.id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if to.store != from.store {
|
for load in to.loads.drain(..) {
|
||||||
let (to_store, from_store) = (to.store.unwrap(), from.store.unwrap());
|
nodes.unlock_remove(load);
|
||||||
nodes.unlock(to_store);
|
|
||||||
to.store = Some(nodes.new_node(ty::Id::VOID, Kind::Phi, [ctrl, from_store, to_store]));
|
|
||||||
nodes.lock(to.store.unwrap());
|
|
||||||
}
|
}
|
||||||
|
for load in from.loads.drain(..) {
|
||||||
to.loads.extend(&from.loads);
|
nodes.unlock_remove(load);
|
||||||
for &load in &from.loads {
|
|
||||||
nodes.lock(load);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if drop_from {
|
if drop_from {
|
||||||
|
@ -1756,6 +1835,8 @@ impl Codegen {
|
||||||
let mem = self.ci.nodes.new_node(ty::Id::VOID, Kind::Mem, [VOID]);
|
let mem = self.ci.nodes.new_node(ty::Id::VOID, Kind::Mem, [VOID]);
|
||||||
debug_assert_eq!(mem, MEM);
|
debug_assert_eq!(mem, MEM);
|
||||||
self.ci.nodes.lock(mem);
|
self.ci.nodes.lock(mem);
|
||||||
|
self.ci.nodes.lock(end);
|
||||||
|
self.ci.scope.store = end;
|
||||||
|
|
||||||
let Expr::BinOp {
|
let Expr::BinOp {
|
||||||
left: Expr::Ident { .. },
|
left: Expr::Ident { .. },
|
||||||
|
@ -1773,7 +1854,7 @@ impl Codegen {
|
||||||
self.ci.nodes.lock(value);
|
self.ci.nodes.lock(value);
|
||||||
let sym = parser::find_symbol(&ast.symbols, arg.id);
|
let sym = parser::find_symbol(&ast.symbols, arg.id);
|
||||||
assert!(sym.flags & idfl::COMPTIME == 0, "TODO");
|
assert!(sym.flags & idfl::COMPTIME == 0, "TODO");
|
||||||
self.ci.scope.vars.push(Variable { id: arg.id, value: Value::new(value).ty(ty) });
|
self.ci.scope.vars.push(Variable { id: arg.id, value, ty });
|
||||||
}
|
}
|
||||||
|
|
||||||
let orig_vars = self.ci.scope.vars.clone();
|
let orig_vars = self.ci.scope.vars.clone();
|
||||||
|
@ -1782,6 +1863,7 @@ impl Codegen {
|
||||||
self.report(body.pos(), "expected all paths in the fucntion to return");
|
self.report(body.pos(), "expected all paths in the fucntion to return");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.ci.nodes.unlock(end);
|
||||||
self.ci.nodes.unlock(end);
|
self.ci.nodes.unlock(end);
|
||||||
|
|
||||||
self.ci.nodes.unlock_remove_scope(&core::mem::take(&mut self.ci.scope));
|
self.ci.nodes.unlock_remove_scope(&core::mem::take(&mut self.ci.scope));
|
||||||
|
@ -2207,16 +2289,13 @@ impl Codegen {
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn report(&self, pos: Pos, msg: impl core::fmt::Display) {
|
fn report(&self, pos: Pos, msg: impl core::fmt::Display) {
|
||||||
let mut buf = self.errors.borrow_mut();
|
let mut buf = self.errors.borrow_mut();
|
||||||
writeln!(buf, "{}", self.cfile().report(pos, msg)).unwrap();
|
write!(buf, "{}", self.cfile().report(pos, msg)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn report_unhandled_ast(&self, ast: &Expr, hint: &str) {
|
fn report_unhandled_ast(&self, ast: &Expr, hint: &str) {
|
||||||
log::debug!("{ast:#?}");
|
log::debug!("{ast:#?}");
|
||||||
self.fatal_report(
|
self.fatal_report(ast.pos(), fa!("compiler does not (yet) know how to handle ({hint})"));
|
||||||
ast.pos(),
|
|
||||||
fa!("compiler does not (yet) know how to handle ({hint}):\n{}", self.ast_display(ast)),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cfile(&self) -> &parser::Ast {
|
fn cfile(&self) -> &parser::Ast {
|
||||||
|
@ -2230,7 +2309,7 @@ impl Codegen {
|
||||||
|
|
||||||
fn gcm(&mut self) {
|
fn gcm(&mut self) {
|
||||||
self.ci.nodes.visited.clear(self.ci.nodes.values.len());
|
self.ci.nodes.visited.clear(self.ci.nodes.values.len());
|
||||||
push_up(&mut self.ci.nodes, NEVER);
|
push_up(&mut self.ci.nodes);
|
||||||
// TODO: handle infinte loops
|
// TODO: handle infinte loops
|
||||||
self.ci.nodes.visited.clear(self.ci.nodes.values.len());
|
self.ci.nodes.visited.clear(self.ci.nodes.values.len());
|
||||||
push_down(&mut self.ci.nodes, VOID);
|
push_down(&mut self.ci.nodes, VOID);
|
||||||
|
@ -2586,8 +2665,8 @@ impl<'a> Function<'a> {
|
||||||
self.add_instr(nid, ops);
|
self.add_instr(nid, ops);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Kind::Stre { .. } if node.inputs[2] == VOID => self.nodes.lock(nid),
|
Kind::Stre if node.inputs[2] == VOID => self.nodes.lock(nid),
|
||||||
Kind::Stre { .. } => {
|
Kind::Stre => {
|
||||||
let mut region = node.inputs[2];
|
let mut region = node.inputs[2];
|
||||||
if self.nodes[region].kind == (Kind::BinOp { op: TokenKind::Add })
|
if self.nodes[region].kind == (Kind::BinOp { op: TokenKind::Add })
|
||||||
&& self.nodes.is_const(self.nodes[region].inputs[2])
|
&& self.nodes.is_const(self.nodes[region].inputs[2])
|
||||||
|
@ -2751,18 +2830,12 @@ fn loop_depth(target: Nid, nodes: &mut Nodes) -> LoopDepth {
|
||||||
depth
|
depth
|
||||||
}
|
}
|
||||||
Kind::Start | Kind::End => 1,
|
Kind::Start | Kind::End => 1,
|
||||||
_ => unreachable!(),
|
u => unreachable!("{u:?}"),
|
||||||
};
|
};
|
||||||
|
|
||||||
nodes[target].loop_depth
|
nodes[target].loop_depth
|
||||||
}
|
}
|
||||||
|
|
||||||
fn better(nodes: &mut Nodes, is: Nid, then: Nid) -> bool {
|
|
||||||
loop_depth(is, nodes) < loop_depth(then, nodes)
|
|
||||||
|| idepth(nodes, is) > idepth(nodes, then)
|
|
||||||
|| nodes[then].kind == Kind::If
|
|
||||||
}
|
|
||||||
|
|
||||||
fn idepth(nodes: &mut Nodes, target: Nid) -> IDomDepth {
|
fn idepth(nodes: &mut Nodes, target: Nid) -> IDomDepth {
|
||||||
if target == VOID {
|
if target == VOID {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2779,71 +2852,116 @@ fn idepth(nodes: &mut Nodes, target: Nid) -> IDomDepth {
|
||||||
nodes[target].depth
|
nodes[target].depth
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_up(nodes: &mut Nodes, node: Nid) {
|
fn push_up(nodes: &mut Nodes) {
|
||||||
|
fn collect_rpo(node: Nid, nodes: &mut Nodes, rpo: &mut Vec<Nid>) {
|
||||||
|
if !nodes.is_cfg(node) || !nodes.visited.set(node) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..nodes[node].outputs.len() {
|
||||||
|
collect_rpo(nodes[node].outputs[i], nodes, rpo);
|
||||||
|
}
|
||||||
|
rpo.push(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_up_impl(node: Nid, nodes: &mut Nodes) {
|
||||||
if !nodes.visited.set(node) {
|
if !nodes.visited.set(node) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for i in 0..nodes[node].inputs.len() {
|
||||||
|
let inp = nodes[node].inputs[i];
|
||||||
|
if !nodes[inp].kind.is_pinned() {
|
||||||
|
push_up_impl(inp, nodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if nodes[node].kind.is_pinned() {
|
if nodes[node].kind.is_pinned() {
|
||||||
for i in 0..nodes[node].inputs.len() {
|
return;
|
||||||
let i = nodes[node].inputs[i];
|
|
||||||
push_up(nodes, i);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
let mut max = VOID;
|
let mut deepest = VOID;
|
||||||
for i in 0..nodes[node].inputs.len() {
|
for i in 1..nodes[node].inputs.len() {
|
||||||
let i = nodes[node].inputs[i];
|
let inp = nodes[node].inputs[i];
|
||||||
let is_call = matches!(nodes[i].kind, Kind::Call { .. });
|
if idepth(nodes, inp) > idepth(nodes, deepest) {
|
||||||
if nodes.is_cfg(i) && !is_call {
|
deepest = idom(nodes, inp);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
push_up(nodes, i);
|
|
||||||
if idepth(nodes, i) > idepth(nodes, max) {
|
|
||||||
max = if is_call { i } else { idom(nodes, i) };
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
if deepest == VOID {
|
||||||
{
|
|
||||||
nodes.check_dominance(node, max, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if max == VOID {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let index = nodes[0].outputs.iter().position(|&p| p == node).unwrap();
|
let index = nodes[0].outputs.iter().position(|&p| p == node).unwrap();
|
||||||
nodes[0].outputs.remove(index);
|
nodes[0].outputs.remove(index);
|
||||||
nodes[node].inputs[0] = max;
|
nodes[node].inputs[0] = deepest;
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
!nodes[max].outputs.contains(&node) || matches!(nodes[max].kind, Kind::Call { .. }),
|
!nodes[deepest].outputs.contains(&node)
|
||||||
"{node} {:?} {max} {:?}",
|
|| matches!(nodes[deepest].kind, Kind::Call { .. }),
|
||||||
|
"{node} {:?} {deepest} {:?}",
|
||||||
nodes[node],
|
nodes[node],
|
||||||
nodes[max]
|
nodes[deepest]
|
||||||
);
|
);
|
||||||
nodes[max].outputs.push(node);
|
nodes[deepest].outputs.push(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut rpo = vec![];
|
||||||
|
|
||||||
|
collect_rpo(VOID, nodes, &mut rpo);
|
||||||
|
|
||||||
|
for node in rpo.into_iter().rev() {
|
||||||
|
loop_depth(node, nodes);
|
||||||
|
for i in 0..nodes[node].inputs.len() {
|
||||||
|
push_up_impl(nodes[node].inputs[i], nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches!(nodes[node].kind, Kind::Loop | Kind::Region) {
|
||||||
|
for i in 0..nodes[node].outputs.len() {
|
||||||
|
let usage = nodes[node].outputs[i];
|
||||||
|
if nodes[usage].kind == Kind::Phi {
|
||||||
|
push_up_impl(usage, nodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_down(nodes: &mut Nodes, node: Nid) {
|
fn push_down(nodes: &mut Nodes, node: Nid) {
|
||||||
|
fn is_forward_edge(usage: Nid, def: Nid, nodes: &mut Nodes) -> bool {
|
||||||
|
match nodes[usage].kind {
|
||||||
|
Kind::Phi => {
|
||||||
|
nodes[usage].inputs[2] != def || nodes[nodes[usage].inputs[0]].kind != Kind::Loop
|
||||||
|
}
|
||||||
|
Kind::Loop => nodes[usage].inputs[1] != def,
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn better(nodes: &mut Nodes, is: Nid, then: Nid) -> bool {
|
||||||
|
loop_depth(is, nodes) < loop_depth(then, nodes)
|
||||||
|
|| idepth(nodes, is) > idepth(nodes, then)
|
||||||
|
|| nodes[then].kind == Kind::If
|
||||||
|
}
|
||||||
|
|
||||||
if !nodes.visited.set(node) {
|
if !nodes.visited.set(node) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: handle memory nodes first
|
for usage in nodes[node].outputs.clone() {
|
||||||
|
if is_forward_edge(usage, node, nodes) {
|
||||||
|
push_down(nodes, usage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if nodes[node].kind.is_pinned() {
|
if nodes[node].kind.is_pinned() {
|
||||||
// TODO: use buffer to avoid allocation or better yet queue the location changes
|
return;
|
||||||
for i in nodes[node].outputs.clone() {
|
|
||||||
push_down(nodes, i);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
let mut min = None::<Nid>;
|
let mut min = None::<Nid>;
|
||||||
for i in 0..nodes[node].outputs.len() {
|
for i in 0..nodes[node].outputs.len() {
|
||||||
let i = nodes[node].outputs[i];
|
let usage = nodes[node].outputs[i];
|
||||||
push_down(nodes, i);
|
let ub = use_block(node, usage, nodes);
|
||||||
let i = use_block(node, i, nodes);
|
min = min.map(|m| common_dom(ub, m, nodes)).or(Some(ub));
|
||||||
min = min.map(|m| common_dom(i, m, nodes)).or(Some(i));
|
|
||||||
}
|
}
|
||||||
let mut min = min.unwrap();
|
let mut min = min.unwrap();
|
||||||
|
|
||||||
|
@ -2875,7 +2993,6 @@ fn push_down(nodes: &mut Nodes, node: Nid) {
|
||||||
nodes[prev].outputs.remove(index);
|
nodes[prev].outputs.remove(index);
|
||||||
nodes[node].inputs[0] = min;
|
nodes[node].inputs[0] = min;
|
||||||
nodes[min].outputs.push(node);
|
nodes[min].outputs.push(node);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_block(target: Nid, from: Nid, nodes: &mut Nodes) -> Nid {
|
fn use_block(target: Nid, from: Nid, nodes: &mut Nodes) -> Nid {
|
||||||
|
@ -2966,7 +3083,7 @@ mod tests {
|
||||||
//generic_functions;
|
//generic_functions;
|
||||||
//c_strings;
|
//c_strings;
|
||||||
//struct_patterns;
|
//struct_patterns;
|
||||||
//arrays;
|
arrays;
|
||||||
//struct_return_from_module_function;
|
//struct_return_from_module_function;
|
||||||
////comptime_pointers;
|
////comptime_pointers;
|
||||||
//sort_something_viredly;
|
//sort_something_viredly;
|
||||||
|
|
|
@ -38,16 +38,15 @@ odher_pass:
|
||||||
ADDI64 r254, r254, 40d
|
ADDI64 r254, r254, 40d
|
||||||
JALA r0, r31, 0a
|
JALA r0, r31, 0a
|
||||||
pass:
|
pass:
|
||||||
ADDI64 r254, r254, -40d
|
ADDI64 r254, r254, -32d
|
||||||
ST r31, r254, 0a, 40h
|
ST r31, r254, 0a, 32h
|
||||||
CP r32, r2
|
CP r32, r2
|
||||||
CP r33, r32
|
LD r33, r32, 0a, 8h
|
||||||
LD r34, r33, 0a, 8h
|
LD r34, r32, 8a, 8h
|
||||||
LD r35, r33, 8a, 8h
|
SUB64 r1, r33, r34
|
||||||
SUB64 r1, r34, r35
|
LD r31, r254, 0a, 32h
|
||||||
LD r31, r254, 0a, 40h
|
ADDI64 r254, r254, 32d
|
||||||
ADDI64 r254, r254, 40d
|
|
||||||
JALA r0, r31, 0a
|
JALA r0, r31, 0a
|
||||||
code size: 440
|
code size: 437
|
||||||
ret: 3
|
ret: 3
|
||||||
status: Ok(())
|
status: Ok(())
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
main:
|
||||||
|
ADDI64 r254, r254, -8d
|
||||||
|
LI64 r4, 0d
|
||||||
|
LI64 r2, 10d
|
||||||
|
ADDI64 r5, r254, 0d
|
||||||
|
ST r2, r254, 0a, 8h
|
||||||
|
2: LD r1, r254, 0a, 8h
|
||||||
|
JNE r1, r4, :0
|
||||||
|
JMP :1
|
||||||
|
0: ADDI64 r1, r1, -1d
|
||||||
|
ST r1, r254, 0a, 8h
|
||||||
|
JMP :2
|
||||||
|
1: ADDI64 r254, r254, 8d
|
||||||
|
JALA r0, r31, 0a
|
||||||
|
code size: 137
|
||||||
|
ret: 0
|
||||||
|
status: Ok(())
|
Loading…
Reference in a new issue