deferring all null checks after the peepholes
This commit is contained in:
parent
798000c756
commit
44fc9c3e2e
47
f.txt
47
f.txt
|
@ -1,47 +0,0 @@
|
||||||
start: 0
|
|
||||||
46-c65535: +: [0, 38, 45] [47]
|
|
||||||
45-c65535: &: [0, 43, 44] [46]
|
|
||||||
44-c65535: cint: #255 [0] [45]
|
|
||||||
43-c65535: load: [0, 42, 23] [45]
|
|
||||||
42-c65535: +: [0, 22, 18] [43]
|
|
||||||
39-c65535: stre: [0, 0, 36, 37] [47]
|
|
||||||
39-c65535: stre: [0, 0, 36, 37] [47]
|
|
||||||
37-c65535: stre: [0, 35, 36, 3] [38, 39]
|
|
||||||
36-c65535: stck: [0, 3] [37, 38, 39]
|
|
||||||
35-c65535: load: [0, 24, 34] [37]
|
|
||||||
34-c65535: stre: [0, 31, 33, 30] [35, 47]
|
|
||||||
33-c65535: +: [0, 24, 32] [34]
|
|
||||||
32-c65535: cint: #16 [0] [33]
|
|
||||||
31-c65535: cint: #4 [0] [34]
|
|
||||||
30-c65535: stre: [0, 27, 29, 26] [34]
|
|
||||||
29-c65535: +: [0, 24, 28] [30]
|
|
||||||
28-c65535: cint: #8 [0] [29]
|
|
||||||
27-c65535: cint: #2 [0] [30]
|
|
||||||
26-c65535: stre: [0, 25, 24, 3] [30]
|
|
||||||
25-c65535: cint: #1 [0] [26]
|
|
||||||
24-c65535: stck: [0, 3] [26, 29, 33, 35]
|
|
||||||
23-c65535: stre: [0, 21, 22, 3] [43, 47]
|
|
||||||
22-c65535: stck: [0, 3] [23, 42]
|
|
||||||
21-c65535: load: [0, 6, 20] [23]
|
|
||||||
20-c65535: stre: [0, 17, 19, 14] [21, 47]
|
|
||||||
19-c65535: +: [0, 6, 18] [20]
|
|
||||||
18-c65535: cint: #3 [0] [19, 42]
|
|
||||||
17-c65535: cint: #1 [0] [20]
|
|
||||||
14-c65535: stre: [0, 5, 13, 11] [20]
|
|
||||||
13-c65535: +: [0, 6, 12] [14]
|
|
||||||
12-c65535: cint: #2 [0] [13]
|
|
||||||
11-c65535: stre: [0, 7, 10, 8] [14]
|
|
||||||
10-c65535: +: [0, 6, 9] [11]
|
|
||||||
9-c65535: cint: #1 [0] [10]
|
|
||||||
8-c65535: stre: [0, 7, 6, 3] [11]
|
|
||||||
7-c65535: cint: #0 [0] [8, 11]
|
|
||||||
6-c65535: stck: [0, 3] [8, 10, 13, 19, 21]
|
|
||||||
5-c65535: cint: #511 [0] [14]
|
|
||||||
4-c65535: loops: [0] []
|
|
||||||
3-c65535: mem: [0] [6, 8, 22, 23, 24, 26, 36, 37, 47]
|
|
||||||
2-c65535: ctrl: entry [0] [38]
|
|
||||||
b2: 0 0 [38]
|
|
||||||
38-c65535: call: 1 0 [2, 36, 37] [46, 47]
|
|
||||||
47-c65535: ret: [38, 46, 3, 20, 23, 34, 39] [1]
|
|
||||||
|
|
||||||
|
|
38
f1.txt
38
f1.txt
|
@ -1,38 +0,0 @@
|
||||||
|
|
||||||
start: 0
|
|
||||||
34-c65535: stre: [0, 31, 51, 30] [39, 47, 38]
|
|
||||||
51-c65535: +: [0, 36, 32] [34]
|
|
||||||
32-c65535: cint: #16 [0] [51]
|
|
||||||
31-c65535: cint: #4 [0] [34]
|
|
||||||
30-c65535: stre: [0, 27, 50, 26] [34]
|
|
||||||
50-c65535: +: [0, 36, 28] [30]
|
|
||||||
28-c65535: cint: #8 [0] [50]
|
|
||||||
27-c65535: cint: #2 [0] [30]
|
|
||||||
26-c65535: stre: [0, 25, 36, 3] [30]
|
|
||||||
25-c65535: cint: #1 [0] [26, 46]
|
|
||||||
39-c65535: stre: [0, 0, 36, 34] [47]
|
|
||||||
36-c65535: stck: [0, 3] [51, 38, 39, 26, 50]
|
|
||||||
22-c65535: stck: [0, 3] [49, 42, 8, 48]
|
|
||||||
39-c65535: stre: [0, 0, 36, 34] [47]
|
|
||||||
20-c65535: stre: [0, 17, 42, 14] [47, 47]
|
|
||||||
46-c65535: +: [0, 38, 25] [47]
|
|
||||||
18-c65535: cint: #3 [0] [42]
|
|
||||||
17-c65535: cint: #1 [0] [20]
|
|
||||||
14-c65535: stre: [0, 5, 49, 11] [20]
|
|
||||||
49-c65535: +: [0, 22, 12] [14]
|
|
||||||
12-c65535: cint: #2 [0] [49]
|
|
||||||
11-c65535: stre: [0, 7, 48, 8] [14]
|
|
||||||
48-c65535: +: [0, 22, 9] [11]
|
|
||||||
9-c65535: cint: #1 [0] [48]
|
|
||||||
8-c65535: stre: [0, 7, 22, 3] [11]
|
|
||||||
7-c65535: cint: #0 [0] [8, 11]
|
|
||||||
42-c65535: +: [0, 22, 18] [20]
|
|
||||||
5-c65535: cint: #511 [0] [14]
|
|
||||||
4-c65535: loops: [0] []
|
|
||||||
3-c65535: mem: [0] [47, 8, 22, 26, 36]
|
|
||||||
2-c65535: ctrl: entry [0] [38]
|
|
||||||
b2: 0 0 [38]
|
|
||||||
38-c65535: call: 1 0 [2, 36, 34] [46, 47]
|
|
||||||
47-c65535: ret: [38, 46, 3, 20, 20, 34, 39] [1]
|
|
||||||
|
|
||||||
|
|
39
f2.txt
39
f2.txt
|
@ -1,39 +0,0 @@
|
||||||
start: 0
|
|
||||||
42-c65535: +: [0, 22, 18] [43, 20]
|
|
||||||
36-c65535: stck: [0, 3] [51, 38, 39, 26, 50]
|
|
||||||
39-c65535: stre: [0, 0, 36, 34] [47]
|
|
||||||
34-c65535: stre: [0, 31, 51, 30] [39, 47, 38]
|
|
||||||
51-c65535: +: [0, 36, 32] [34]
|
|
||||||
32-c65535: cint: #16 [0] [51]
|
|
||||||
31-c65535: cint: #4 [0] [34]
|
|
||||||
30-c65535: stre: [0, 27, 50, 26] [34]
|
|
||||||
50-c65535: +: [0, 36, 28] [30]
|
|
||||||
28-c65535: cint: #8 [0] [50]
|
|
||||||
27-c65535: cint: #2 [0] [30]
|
|
||||||
26-c65535: stre: [0, 25, 36, 3] [30]
|
|
||||||
25-c65535: cint: #1 [0] [26]
|
|
||||||
39-c65535: stre: [0, 0, 36, 34] [47]
|
|
||||||
45-c65535: &: [0, 43, 44] [46]
|
|
||||||
22-c65535: stck: [0, 3] [49, 42, 8, 48]
|
|
||||||
44-c65535: cint: #255 [0] [45]
|
|
||||||
20-c65535: stre: [0, 17, 42, 14] [47, 47, 43]
|
|
||||||
46-c65535: +: [0, 38, 45] [47]
|
|
||||||
18-c65535: cint: #3 [0] [42]
|
|
||||||
17-c65535: cint: #1 [0] [20]
|
|
||||||
14-c65535: stre: [0, 5, 49, 11] [20]
|
|
||||||
49-c65535: +: [0, 22, 12] [14]
|
|
||||||
12-c65535: cint: #2 [0] [49]
|
|
||||||
11-c65535: stre: [0, 7, 48, 8] [14]
|
|
||||||
48-c65535: +: [0, 22, 9] [11]
|
|
||||||
9-c65535: cint: #1 [0] [48]
|
|
||||||
8-c65535: stre: [0, 7, 22, 3] [11]
|
|
||||||
7-c65535: cint: #0 [0] [8, 11]
|
|
||||||
43-c65535: load: [0, 42, 20] [45]
|
|
||||||
5-c65535: cint: #511 [0] [14]
|
|
||||||
4-c65535: loops: [0] []
|
|
||||||
3-c65535: mem: [0] [47, 8, 22, 26, 36]
|
|
||||||
2-c65535: ctrl: entry [0] [38]
|
|
||||||
b2: 0 0 [38]
|
|
||||||
38-c65535: call: 1 0 [2, 36, 34] [46, 47]
|
|
||||||
47-c65535: ret: [38, 46, 3, 20, 20, 34, 39] [1]
|
|
||||||
|
|
|
@ -1044,6 +1044,28 @@ main := fn(): uint {
|
||||||
|
|
||||||
### Just Testing Optimizations
|
### Just Testing Optimizations
|
||||||
|
|
||||||
|
#### null_check_test
|
||||||
|
```hb
|
||||||
|
get_ptr := fn(): ?^uint {
|
||||||
|
value := 0
|
||||||
|
return &value
|
||||||
|
}
|
||||||
|
|
||||||
|
main := fn(): uint {
|
||||||
|
ptr := get_ptr()
|
||||||
|
|
||||||
|
if ptr == null {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
loop if *ptr != 10 {
|
||||||
|
*ptr += 1
|
||||||
|
} else break
|
||||||
|
|
||||||
|
return *ptr
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
#### const_folding_with_arg
|
#### const_folding_with_arg
|
||||||
```hb
|
```hb
|
||||||
main := fn(arg: uint): uint {
|
main := fn(arg: uint): uint {
|
||||||
|
|
125
lang/src/son.rs
125
lang/src/son.rs
|
@ -879,6 +879,46 @@ impl Nodes {
|
||||||
return Some(self.new_const(ty, op.apply_unop(value, is_float)));
|
return Some(self.new_const(ty, op.apply_unop(value, is_float)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
K::Assert { kind, pos } => {
|
||||||
|
if self[target].ty == ty::Id::VOID {
|
||||||
|
let &[ctrl, cond] = self[target].inputs.as_slice() else { unreachable!() };
|
||||||
|
if let K::CInt { value } = self[cond].kind {
|
||||||
|
let ty = if value != 0 {
|
||||||
|
ty::Id::NEVER
|
||||||
|
} else {
|
||||||
|
return Some(ctrl);
|
||||||
|
};
|
||||||
|
return Some(self.new_node_nop(ty, K::Assert { kind, pos }, [ctrl, cond]));
|
||||||
|
}
|
||||||
|
|
||||||
|
'b: {
|
||||||
|
let mut cursor = ctrl;
|
||||||
|
loop {
|
||||||
|
if cursor == ENTRY {
|
||||||
|
break 'b;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: do more inteligent checks on the condition
|
||||||
|
if self[cursor].kind == Kind::Else
|
||||||
|
&& self[self[cursor].inputs[0]].inputs[1] == cond
|
||||||
|
{
|
||||||
|
return Some(ctrl);
|
||||||
|
}
|
||||||
|
if self[cursor].kind == Kind::Then
|
||||||
|
&& self[self[cursor].inputs[0]].inputs[1] == cond
|
||||||
|
{
|
||||||
|
return Some(self.new_node_nop(
|
||||||
|
ty::Id::NEVER,
|
||||||
|
K::Assert { kind, pos },
|
||||||
|
[ctrl, cond],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor = self.idom(cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
K::If => {
|
K::If => {
|
||||||
if self[target].ty == ty::Id::VOID {
|
if self[target].ty == ty::Id::VOID {
|
||||||
let &[ctrl, cond] = self[target].inputs.as_slice() else { unreachable!() };
|
let &[ctrl, cond] = self[target].inputs.as_slice() else { unreachable!() };
|
||||||
|
@ -1295,7 +1335,7 @@ impl Nodes {
|
||||||
write!(out, " {node:>2}-c{:>2}: ", self[node].ralloc_backref)?;
|
write!(out, " {node:>2}-c{:>2}: ", self[node].ralloc_backref)?;
|
||||||
}
|
}
|
||||||
match self[node].kind {
|
match self[node].kind {
|
||||||
Kind::Start => unreachable!(),
|
Kind::Assert { .. } | Kind::Start => unreachable!(),
|
||||||
Kind::End => return Ok(()),
|
Kind::End => return Ok(()),
|
||||||
Kind::If => write!(out, " if: "),
|
Kind::If => write!(out, " if: "),
|
||||||
Kind::Region | Kind::Loop => writeln!(out, " goto: {node}"),
|
Kind::Region | Kind::Loop => writeln!(out, " goto: {node}"),
|
||||||
|
@ -1561,6 +1601,11 @@ impl ops::IndexMut<Nid> for Nodes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
pub enum AssertKind {
|
||||||
|
NullCheck,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum Kind {
|
pub enum Kind {
|
||||||
|
@ -1586,6 +1631,11 @@ pub enum Kind {
|
||||||
Return,
|
Return,
|
||||||
// [ctrl]
|
// [ctrl]
|
||||||
Die,
|
Die,
|
||||||
|
// [ctrl, cond]
|
||||||
|
Assert {
|
||||||
|
kind: AssertKind,
|
||||||
|
pos: Pos,
|
||||||
|
},
|
||||||
// [ctrl]
|
// [ctrl]
|
||||||
CInt {
|
CInt {
|
||||||
value: i64,
|
value: i64,
|
||||||
|
@ -1634,6 +1684,7 @@ impl Kind {
|
||||||
| Self::Then
|
| Self::Then
|
||||||
| Self::Else
|
| Self::Else
|
||||||
| Self::Call { .. }
|
| Self::Call { .. }
|
||||||
|
| Self::Assert { .. }
|
||||||
| Self::If
|
| Self::If
|
||||||
| Self::Region
|
| Self::Region
|
||||||
| Self::Loop
|
| Self::Loop
|
||||||
|
@ -3981,9 +4032,7 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
self.ci.scope.vars.drain(..).for_each(|v| v.remove_ignore_arg(&mut self.ci.nodes));
|
self.ci.scope.vars.drain(..).for_each(|v| v.remove_ignore_arg(&mut self.ci.nodes));
|
||||||
|
|
||||||
self.ci.finalize(&mut self.pool.nid_stack, self.tys, self.files);
|
if self.finalize(prev_err_len) {
|
||||||
|
|
||||||
if self.errors.borrow().len() == prev_err_len {
|
|
||||||
self.ci.emit_body(self.tys, self.files, sig, self.pool);
|
self.ci.emit_body(self.tys, self.files, sig, self.pool);
|
||||||
self.tys.ins.funcs[id as usize].code.append(&mut self.ci.code);
|
self.tys.ins.funcs[id as usize].code.append(&mut self.ci.code);
|
||||||
self.tys.ins.funcs[id as usize].relocs.append(&mut self.ci.relocs);
|
self.tys.ins.funcs[id as usize].relocs.append(&mut self.ci.relocs);
|
||||||
|
@ -3992,6 +4041,32 @@ impl<'a> Codegen<'a> {
|
||||||
self.pool.pop_ci(&mut self.ci);
|
self.pool.pop_ci(&mut self.ci);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn finalize(&mut self, prev_err_len: usize) -> bool {
|
||||||
|
self.ci.finalize(&mut self.pool.nid_stack, self.tys, self.files);
|
||||||
|
for (_, node) in self.ci.nodes.iter() {
|
||||||
|
if let Kind::Assert { kind: AssertKind::NullCheck, pos } = node.kind {
|
||||||
|
match node.ty {
|
||||||
|
ty::Id::NEVER => {
|
||||||
|
self.report(
|
||||||
|
pos,
|
||||||
|
"the value is always null, some checks might need to be inverted",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.report(
|
||||||
|
pos,
|
||||||
|
"can't prove the value is not 'null', \
|
||||||
|
use '@unwrap(<opt>)' if you believe compiler is stupid, \
|
||||||
|
or explicitly check for null and handle it \
|
||||||
|
('if <opt> == null { /* handle */ } else { /* use opt */ }')",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.errors.borrow().len() == prev_err_len
|
||||||
|
}
|
||||||
|
|
||||||
fn ty(&mut self, expr: &Expr) -> ty::Id {
|
fn ty(&mut self, expr: &Expr) -> ty::Id {
|
||||||
self.parse_ty(self.ci.file, expr, None, self.files)
|
self.parse_ty(self.ci.file, expr, None, self.files)
|
||||||
}
|
}
|
||||||
|
@ -4096,27 +4171,16 @@ impl<'a> Codegen<'a> {
|
||||||
let null_check = self.gen_null_check(*opt, ty, TokenKind::Eq);
|
let null_check = self.gen_null_check(*opt, ty, TokenKind::Eq);
|
||||||
|
|
||||||
// TODO: extract the if check int a fucntion
|
// TODO: extract the if check int a fucntion
|
||||||
let ctrl = self.ci.nodes.new_node(ty::Id::VOID, Kind::If, [self.ci.ctrl.get(), null_check]);
|
self.ci.ctrl.set(
|
||||||
let ctrl_ty = self.ci.nodes[ctrl].ty;
|
self.ci.nodes.new_node(
|
||||||
self.ci.nodes.remove(ctrl);
|
ty::Id::VOID,
|
||||||
let oty = mem::replace(&mut opt.ty, ty);
|
Kind::Assert { kind: AssertKind::NullCheck, pos },
|
||||||
match ctrl_ty {
|
[self.ci.ctrl.get(), null_check],
|
||||||
ty::Id::LEFT_UNREACHABLE => {
|
),
|
||||||
self.unwrap_opt_unchecked(ty, oty, opt);
|
&mut self.ci.nodes,
|
||||||
}
|
|
||||||
ty::Id::RIGHT_UNREACHABLE => {
|
|
||||||
self.report(pos, "the value is always null, some checks might need to be inverted");
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
self.report(
|
|
||||||
pos,
|
|
||||||
"can't prove the value is not 'null', \
|
|
||||||
use '@unwrap(<opt>)' if you believe compiler is stupid, \
|
|
||||||
or explicitly check for null and handle it \
|
|
||||||
('if <opt> == null { /* handle */ } else { /* use opt */ }')",
|
|
||||||
);
|
);
|
||||||
}
|
let oty = mem::replace(&mut opt.ty, ty);
|
||||||
}
|
self.unwrap_opt_unchecked(ty, oty, opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unwrap_opt_unchecked(&mut self, ty: ty::Id, oty: ty::Id, opt: &mut Value) {
|
fn unwrap_opt_unchecked(&mut self, ty: ty::Id, oty: ty::Id, opt: &mut Value) {
|
||||||
|
@ -4247,13 +4311,9 @@ impl TypeParser for Codegen<'_> {
|
||||||
self.expr(&Expr::Return { pos: expr.pos(), val: Some(expr) });
|
self.expr(&Expr::Return { pos: expr.pos(), val: Some(expr) });
|
||||||
|
|
||||||
scope = mem::take(&mut self.ci.scope.vars);
|
scope = mem::take(&mut self.ci.scope.vars);
|
||||||
self.ci.finalize(&mut self.pool.nid_stack, self.tys, self.files);
|
|
||||||
|
|
||||||
let res = if self.errors.borrow().len() == prev_err_len {
|
let res =
|
||||||
self.emit_and_eval(file, ret, &mut [])
|
if self.finalize(prev_err_len) { self.emit_and_eval(file, ret, &mut []) } else { 1 };
|
||||||
} else {
|
|
||||||
1
|
|
||||||
};
|
|
||||||
|
|
||||||
self.pool.pop_ci(&mut self.ci);
|
self.pool.pop_ci(&mut self.ci);
|
||||||
self.ci.scope.vars = scope;
|
self.ci.scope.vars = scope;
|
||||||
|
@ -4291,10 +4351,8 @@ impl TypeParser for Codegen<'_> {
|
||||||
|
|
||||||
self.expr(&(Expr::Return { pos: expr.pos(), val: Some(expr) }));
|
self.expr(&(Expr::Return { pos: expr.pos(), val: Some(expr) }));
|
||||||
|
|
||||||
self.ci.finalize(&mut self.pool.nid_stack, self.tys, self.files);
|
|
||||||
|
|
||||||
let ret = self.ci.ret.expect("for return type to be infered");
|
let ret = self.ci.ret.expect("for return type to be infered");
|
||||||
if self.errors.borrow().len() == prev_err_len {
|
if self.finalize(prev_err_len) {
|
||||||
let mut mem = vec![0u8; self.tys.size_of(ret) as usize];
|
let mut mem = vec![0u8; self.tys.size_of(ret) as usize];
|
||||||
self.emit_and_eval(file, ret, &mut mem);
|
self.emit_and_eval(file, ret, &mut mem);
|
||||||
self.tys.ins.globals[gid as usize].data = mem;
|
self.tys.ins.globals[gid as usize].data = mem;
|
||||||
|
@ -4388,6 +4446,7 @@ mod tests {
|
||||||
fb_driver;
|
fb_driver;
|
||||||
|
|
||||||
// Purely Testing Examples;
|
// Purely Testing Examples;
|
||||||
|
null_check_test;
|
||||||
only_break_loop;
|
only_break_loop;
|
||||||
reading_idk;
|
reading_idk;
|
||||||
nonexistent_ident_import;
|
nonexistent_ident_import;
|
||||||
|
|
|
@ -493,6 +493,7 @@ impl ItemCtx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Kind::Start
|
Kind::Start
|
||||||
|
| Kind::Assert { .. }
|
||||||
| Kind::Entry
|
| Kind::Entry
|
||||||
| Kind::Mem
|
| Kind::Mem
|
||||||
| Kind::End
|
| Kind::End
|
||||||
|
@ -1021,6 +1022,7 @@ impl<'a> Function<'a> {
|
||||||
let ops = vec![self.drg(nid)];
|
let ops = vec![self.drg(nid)];
|
||||||
self.add_instr(nid, ops);
|
self.add_instr(nid, ops);
|
||||||
}
|
}
|
||||||
|
Kind::Assert { .. } => unreachable!(),
|
||||||
Kind::End |
|
Kind::End |
|
||||||
Kind::Phi | Kind::Arg | Kind::Mem | Kind::Loops => {}
|
Kind::Phi | Kind::Arg | Kind::Mem | Kind::Loops => {}
|
||||||
Kind::Load { .. } if node.ty.loc(self.tys) == Loc::Stack => {
|
Kind::Load { .. } if node.ty.loc(self.tys) == Loc::Stack => {
|
||||||
|
|
0
lang/tests/son_tests_inlining_loops.txt
Normal file
0
lang/tests/son_tests_inlining_loops.txt
Normal file
26
lang/tests/son_tests_null_check_test.txt
Normal file
26
lang/tests/son_tests_null_check_test.txt
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
get_ptr:
|
||||||
|
ADDI64 r254, r254, -8d
|
||||||
|
ADDI64 r1, r254, 0d
|
||||||
|
ADDI64 r254, r254, 8d
|
||||||
|
JALA r0, r31, 0a
|
||||||
|
main:
|
||||||
|
ADDI64 r254, r254, -8d
|
||||||
|
ST r31, r254, 0a, 8h
|
||||||
|
JAL r31, r0, :get_ptr
|
||||||
|
LI64 r3, 0d
|
||||||
|
JNE r1, r3, :0
|
||||||
|
LI64 r1, 0d
|
||||||
|
JMP :1
|
||||||
|
0: LI64 r10, 10d
|
||||||
|
CP r2, r1
|
||||||
|
2: LD r1, r2, 0a, 8h
|
||||||
|
JEQ r1, r10, :1
|
||||||
|
ADDI64 r3, r1, 1d
|
||||||
|
ST r3, r2, 0a, 8h
|
||||||
|
JMP :2
|
||||||
|
1: LD r31, r254, 0a, 8h
|
||||||
|
ADDI64 r254, r254, 8d
|
||||||
|
JALA r0, r31, 0a
|
||||||
|
code size: 208
|
||||||
|
ret: 10
|
||||||
|
status: Ok(())
|
Loading…
Reference in a new issue