Compare commits

..

2 commits

Author SHA1 Message Date
Jakub Doka 97eb985a02
removing specific opts from a fucntion and adding them to the general peepholes 2024-10-29 09:04:49 +01:00
Jakub Doka 7ef1adf7e2
saving 2024-10-28 23:38:57 +01:00
13 changed files with 531 additions and 348 deletions

47
f.txt Normal file
View file

@ -0,0 +1,47 @@
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 Normal file
View file

@ -0,0 +1,38 @@
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 Normal file
View file

@ -0,0 +1,39 @@
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]

View file

@ -45,7 +45,7 @@ impl crate::ctx_map::CtxEntry for Nid {
type Key<'a> = (Kind, &'a [Nid], ty::Id); type Key<'a> = (Kind, &'a [Nid], ty::Id);
fn key<'a>(&self, ctx: &'a Self::Ctx) -> Self::Key<'a> { fn key<'a>(&self, ctx: &'a Self::Ctx) -> Self::Key<'a> {
ctx[*self as usize].as_ref().unwrap().key() ctx[*self as usize].as_ref().unwrap_or_else(|(_, t)| panic!("{t:#?}")).key()
} }
} }
@ -73,6 +73,7 @@ struct Nodes {
visited: BitSet, visited: BitSet,
free: Nid, free: Nid,
lookup: Lookup, lookup: Lookup,
complete: bool,
} }
impl Default for Nodes { impl Default for Nodes {
@ -82,6 +83,7 @@ impl Default for Nodes {
free: Nid::MAX, free: Nid::MAX,
lookup: Default::default(), lookup: Default::default(),
visited: Default::default(), visited: Default::default(),
complete: false,
} }
} }
} }
@ -230,7 +232,7 @@ impl Nodes {
} }
fn push_up(&mut self, rpo: &mut Vec<Nid>) { fn push_up(&mut self, rpo: &mut Vec<Nid>) {
rpo.clear(); debug_assert!(rpo.is_empty());
self.collect_rpo(VOID, rpo); self.collect_rpo(VOID, rpo);
for &node in rpo.iter().rev() { for &node in rpo.iter().rev() {
@ -262,6 +264,8 @@ impl Nodes {
&& !matches!(nod.kind, Kind::Arg | Kind::Mem | Kind::Loops)) && !matches!(nod.kind, Kind::Arg | Kind::Mem | Kind::Loops))
.collect::<Vec<_>>() .collect::<Vec<_>>()
); );
rpo.clear();
} }
fn better(&mut self, is: Nid, then: Nid) -> bool { fn better(&mut self, is: Nid, then: Nid) -> bool {
@ -491,6 +495,7 @@ impl Nodes {
self.values.clear(); self.values.clear();
self.lookup.clear(); self.lookup.clear();
self.free = Nid::MAX; self.free = Nid::MAX;
self.complete = false;
} }
fn new_node_nop(&mut self, ty: ty::Id, kind: Kind, inps: impl Into<Vc>) -> Nid { fn new_node_nop(&mut self, ty: ty::Id, kind: Kind, inps: impl Into<Vc>) -> Nid {
@ -610,13 +615,13 @@ impl Nodes {
fn late_peephole(&mut self, target: Nid) -> Option<Nid> { fn late_peephole(&mut self, target: Nid) -> Option<Nid> {
if let Some(id) = self.peephole(target) { if let Some(id) = self.peephole(target) {
self.replace(target, id); self.replace(target, id);
return Some(id); return None;
} }
None None
} }
fn iter_peeps(&mut self, mut fuel: usize, stack: &mut Vec<Nid>) { fn iter_peeps(&mut self, mut fuel: usize, stack: &mut Vec<Nid>) {
stack.clear(); debug_assert!(stack.is_empty());
self.iter() self.iter()
.filter_map(|(id, node)| node.kind.is_peeped().then_some(id)) .filter_map(|(id, node)| node.kind.is_peeped().then_some(id))
@ -627,19 +632,57 @@ impl Nodes {
&& let Some(node) = stack.pop() && let Some(node) = stack.pop()
{ {
fuel -= 1; fuel -= 1;
if self[node].outputs.is_empty() {
self.push_adjacent_nodes(node, stack);
}
if self.unlock_remove(node) { if self.unlock_remove(node) {
continue; continue;
} }
let new = self.late_peephole(node);
if let Some(new) = new { if let Some(new) = self.peephole(node) {
let prev_len = stack.len(); self.replace(node, new);
for &i in self[new].outputs.iter().chain(self[new].inputs.iter()) { self.push_adjacent_nodes(new, stack);
if self[i].kind.is_peeped() && self[i].lock_rc == 0 {
stack.push(i);
}
}
stack.iter().skip(prev_len).for_each(|&n| self.lock(n));
} }
debug_assert_matches!(
self.iter()
.find(|(i, n)| n.lock_rc != 0 && n.kind.is_peeped() && !stack.contains(i)),
None
);
}
stack.drain(..).for_each(|s| _ = self.unlock_remove(s));
}
fn push_adjacent_nodes(&mut self, of: Nid, stack: &mut Vec<Nid>) {
let prev_len = stack.len();
for &i in self[of]
.outputs
.iter()
.chain(self[of].inputs.iter())
.chain(self[of].peep_triggers.iter())
{
if self.values[i as usize].is_ok() && self[i].kind.is_peeped() && self[i].lock_rc == 0 {
stack.push(i);
}
}
self[of].peep_triggers = Vc::default();
stack.iter().skip(prev_len).for_each(|&n| self.lock(n));
}
pub fn aclass_index(&self, mut region: Nid) -> (usize, Nid) {
loop {
region = match self[region].kind {
Kind::BinOp { op: TokenKind::Add | TokenKind::Sub } => self[region].inputs[1],
Kind::Phi => {
debug_assert_eq!(self[region].inputs[2], 0);
self[region].inputs[1]
}
_ => break (self[region].aclass, region),
};
} }
} }
@ -823,11 +866,47 @@ impl Nodes {
return Some(ctrl); return Some(ctrl);
} }
K::Call { .. } | K::Return => { K::Call { .. } => {
if self[target].inputs[0] == NEVER { if self[target].inputs[0] == NEVER {
return Some(NEVER); return Some(NEVER);
} }
} }
K::Return => {
if self[target].inputs[0] == NEVER {
return Some(NEVER);
}
let mut new_inps = Vc::from(&self[target].inputs[..2]);
'a: for &n in self[target].inputs.clone().iter().skip(2) {
if self[n].kind != Kind::Stre || self[n].inputs.len() != 4 {
new_inps.push(n);
continue;
}
let mut cursor = n;
let class = self.aclass_index(self[cursor].inputs[2]);
if self[class.1].kind != Kind::Stck {
new_inps.push(n);
continue;
}
cursor = self[cursor].inputs[3];
while cursor != MEM {
if self.aclass_index(self[cursor].inputs[2]) != class
|| self[cursor].inputs.len() != 4
{
new_inps.push(n);
continue 'a;
}
cursor = self[cursor].inputs[3];
}
}
if new_inps.as_slice() != self[target].inputs.as_slice() {
return Some(self.new_node_nop(ty::Id::VOID, Kind::Return, new_inps));
}
}
K::Phi => { K::Phi => {
let &[ctrl, lhs, rhs] = self[target].inputs.as_slice() else { unreachable!() }; let &[ctrl, lhs, rhs] = self[target].inputs.as_slice() else { unreachable!() };
@ -857,18 +936,129 @@ impl Nodes {
} }
} }
K::Stre => { K::Stre => {
if self[target].inputs[1] != VOID let &[_, value, region, store, ..] = self[target].inputs.as_slice() else {
unreachable!()
};
'eliminate: {
if self[target].outputs.is_empty() {
break 'eliminate;
}
if self[value].kind != Kind::Load || self[value].outputs.as_slice() != [target]
{
for &ele in self[value].outputs.clone().iter().filter(|&&n| n != target) {
self[ele].peep_triggers.push(target);
}
break 'eliminate;
}
let &[_, stack, last_store] = self[value].inputs.as_slice() else {
unreachable!()
};
if self[stack].ty != self[value].ty || self[stack].kind != Kind::Stck {
break 'eliminate;
}
let mut unidentifed = self[stack].outputs.clone();
let load_idx = unidentifed.iter().position(|&n| n == value).unwrap();
unidentifed.swap_remove(load_idx);
let mut saved = Vc::default();
let mut cursor = last_store;
let mut first_store = last_store;
while cursor != MEM && self[cursor].kind == Kind::Stre {
let mut contact_point = cursor;
let mut region = self[cursor].inputs[2];
if let Kind::BinOp { op } = self[region].kind {
debug_assert_matches!(op, TokenKind::Add | TokenKind::Sub);
contact_point = region;
region = self[region].inputs[1]
}
if region != stack {
break;
}
let Some(index) = unidentifed.iter().position(|&n| n == contact_point)
else {
break 'eliminate;
};
unidentifed.remove(index);
saved.push(contact_point);
first_store = cursor;
cursor = *self[cursor].inputs.get(3).unwrap_or(&MEM);
if unidentifed.is_empty() {
break;
}
}
// TODO: this can be an offset already due to previous peeps so handle that
if let &[mcall] = unidentifed.as_slice()
&& matches!(self[mcall].kind, Kind::Call { .. })
&& self[mcall].inputs.last() == Some(&stack)
{
self.modify_input(mcall, self[mcall].inputs.len() - 1, region);
return Some(last_store);
} else {
debug_assert_matches!(
self[last_store].kind,
Kind::Stre | Kind::Mem,
"{:?}",
self[last_store]
);
debug_assert_matches!(
self[first_store].kind,
Kind::Stre | Kind::Mem,
"{:?}",
self[first_store]
);
if !unidentifed.is_empty() {
break 'eliminate;
}
// FIXME: when the loads and stores become parallel we will need to get saved
// differently
let mut prev_store = store;
for mut oper in saved.into_iter().rev() {
let mut region = region;
if let Kind::BinOp { op } = self[oper].kind {
debug_assert_eq!(self[oper].outputs.len(), 1);
debug_assert_eq!(self[self[oper].outputs[0]].kind, Kind::Stre);
region = self.new_node(self[oper].ty, Kind::BinOp { op }, [
VOID,
region,
self[oper].inputs[2],
]);
oper = self[oper].outputs[0];
}
let mut inps = self[oper].inputs.clone();
debug_assert_eq!(inps.len(), 4);
inps[2] = region;
inps[3] = prev_store;
prev_store = self.new_node(self[oper].ty, Kind::Stre, inps);
}
return Some(prev_store);
}
}
if value != VOID
&& self[target].inputs.len() == 4 && self[target].inputs.len() == 4
&& self[self[target].inputs[1]].kind != Kind::Load && self[value].kind != Kind::Load
&& self[self[target].inputs[3]].kind == Kind::Stre && self[store].kind == Kind::Stre
&& self[self[target].inputs[3]].lock_rc == 0 && self[store].lock_rc == 0
&& self[self[target].inputs[3]].inputs[2] == self[target].inputs[2] && self[store].inputs[2] == region
{ {
return Some(self.modify_input( if self[store].inputs[1] == value {
self[target].inputs[3], return Some(store);
1, }
self[target].inputs[1],
)); return Some(self.modify_input(store, 1, value));
} }
} }
K::Load => { K::Load => {
@ -908,43 +1098,45 @@ impl Nodes {
fn replace(&mut self, target: Nid, with: Nid) { fn replace(&mut self, target: Nid, with: Nid) {
debug_assert_ne!(target, with, "{:?}", self[target]); debug_assert_ne!(target, with, "{:?}", self[target]);
let mut back_press = 0; for out in self[target].outputs.clone() {
for i in 0..self[target].outputs.len() {
let out = self[target].outputs[i - back_press];
let index = self[out].inputs.iter().position(|&p| p == target).unwrap(); let index = self[out].inputs.iter().position(|&p| p == target).unwrap();
self.lock(target);
let prev_len = self[target].outputs.len();
self.modify_input(out, index, with); self.modify_input(out, index, with);
back_press += (self[target].outputs.len() != prev_len) as usize;
self.unlock(target);
} }
self.remove(target);
} }
fn modify_input(&mut self, target: Nid, inp_index: usize, with: Nid) -> Nid { fn modify_input(&mut self, target: Nid, inp_index: usize, with: Nid) -> Nid {
self.remove_node_lookup(target); self.remove_node_lookup(target);
debug_assert_ne!(self[target].inputs[inp_index], with, "{:?}", self[target]); debug_assert_ne!(self[target].inputs[inp_index], with, "{:?}", self[target]);
let prev = self[target].inputs[inp_index]; if self[target].is_not_gvnd() && (self[target].kind != Kind::Phi || with == 0) {
self[target].inputs[inp_index] = with; let prev = self[target].inputs[inp_index];
let (entry, hash) = self.lookup.entry(target.key(&self.values), &self.values); self[target].inputs[inp_index] = with;
match entry { self[with].outputs.push(target);
hash_map::RawEntryMut::Occupied(other) => { let index = self[prev].outputs.iter().position(|&o| o == target).unwrap();
let rpl = other.get_key_value().0.value; self[prev].outputs.swap_remove(index);
self[target].inputs[inp_index] = prev; self.remove(prev);
self.lookup.insert(target.key(&self.values), target, &self.values); target
self.replace(target, rpl); } else {
rpl let prev = self[target].inputs[inp_index];
} self[target].inputs[inp_index] = with;
hash_map::RawEntryMut::Vacant(slot) => { let (entry, hash) = self.lookup.entry(target.key(&self.values), &self.values);
slot.insert(crate::ctx_map::Key { value: target, hash }, ()); match entry {
let index = self[prev].outputs.iter().position(|&o| o == target).unwrap(); hash_map::RawEntryMut::Occupied(other) => {
self[prev].outputs.swap_remove(index); let rpl = other.get_key_value().0.value;
self[with].outputs.push(target); self[target].inputs[inp_index] = prev;
self.remove(prev); self.lookup.insert(target.key(&self.values), target, &self.values);
self.replace(target, rpl);
rpl
}
hash_map::RawEntryMut::Vacant(slot) => {
slot.insert(crate::ctx_map::Key { value: target, hash }, ());
let index = self[prev].outputs.iter().position(|&o| o == target).unwrap();
self[prev].outputs.swap_remove(index);
self[with].outputs.push(target);
self.remove(prev);
target target
}
} }
} }
} }
@ -1121,7 +1313,7 @@ impl Nodes {
if !matches!(node.kind, Kind::End | Kind::Mem | Kind::Arg | Kind::Loops) if !matches!(node.kind, Kind::End | Kind::Mem | Kind::Arg | Kind::Loops)
&& node.outputs.is_empty() && node.outputs.is_empty()
{ {
log::error!("outputs are empry {id} {:?}", node.kind); log::error!("outputs are empry {id} {:?}", node);
failed = true; failed = true;
} }
if node.inputs.first() == Some(&NEVER) && id != NEVER { if node.inputs.first() == Some(&NEVER) && id != NEVER {
@ -1211,124 +1403,6 @@ impl Nodes {
dominated = self.idom(dominated); dominated = self.idom(dominated);
} }
} }
fn eliminate_stack_temporaries(&mut self) {
'o: for stack in self[MEM].outputs.clone() {
if self.values[stack as usize].is_err() || self[stack].kind != Kind::Stck {
continue;
}
let mut full_read_into = None;
let mut unidentifed = Vc::default();
for &o in self[stack].outputs.iter() {
match self[o].kind {
Kind::Load
if self[o].ty == self[stack].ty
&& self[o].outputs.iter().all(|&n| self[n].kind == Kind::Stre)
&& let mut full_stores = self[o].outputs.iter().filter(|&&n| {
self[n].kind == Kind::Stre && self[n].inputs[1] == o
})
&& let Some(&n) = full_stores.next()
&& full_stores.next().is_none() =>
{
if full_read_into.replace((n, self[o].inputs[2])).is_some() {
continue 'o;
}
}
_ => unidentifed.push(o),
}
}
let Some((dst, last_store)) = full_read_into else { continue };
let mut saved = Vc::default();
let mut cursor = last_store;
let mut first_store = last_store;
while cursor != MEM && self[cursor].kind == Kind::Stre {
let mut contact_point = cursor;
let mut region = self[cursor].inputs[2];
if let Kind::BinOp { op } = self[region].kind {
debug_assert_matches!(op, TokenKind::Add | TokenKind::Sub);
contact_point = region;
region = self[region].inputs[1]
}
if region != stack {
break;
}
let Some(index) = unidentifed.iter().position(|&n| n == contact_point) else {
continue 'o;
};
unidentifed.remove(index);
saved.push(contact_point);
first_store = cursor;
cursor = *self[cursor].inputs.get(3).unwrap_or(&MEM);
if unidentifed.is_empty() {
break;
}
}
let region = self[dst].inputs[2];
// TODO: this can be an offset already due to previous peeps so handle that
if let &[mcall] = unidentifed.as_slice()
&& matches!(self[mcall].kind, Kind::Call { .. })
&& self[mcall].inputs.last() == Some(&stack)
{
self.modify_input(mcall, self[mcall].inputs.len() - 1, region);
} else {
debug_assert_matches!(
self[last_store].kind,
Kind::Stre | Kind::Mem,
"{:?}",
self[last_store]
);
debug_assert_matches!(
self[first_store].kind,
Kind::Stre | Kind::Mem,
"{:?}",
self[first_store]
);
if !unidentifed.is_empty() {
continue;
}
// FIXME: when the loads and stores become parallel we will need to get saved
// differently
for mut oper in saved.into_iter().rev() {
let mut region = region;
if let Kind::BinOp { op } = self[oper].kind {
debug_assert_eq!(self[oper].outputs.len(), 1);
debug_assert_eq!(self[self[oper].outputs[0]].kind, Kind::Stre);
region = self.new_node(self[oper].ty, Kind::BinOp { op }, [
VOID,
region,
self[oper].inputs[2],
]);
oper = self[oper].outputs[0];
}
self.modify_input(oper, 2, region);
}
}
// self[first_store].lock_rc = u16::MAX - 1;
// self[last_store].lock_rc = u16::MAX - 1;
let prev_store = self[dst].inputs[3];
if prev_store != MEM && first_store != MEM {
self.modify_input(first_store, 3, prev_store);
}
self.replace(dst, last_store);
if self.values[stack as usize].is_ok() {
self.lock(stack);
}
if self.values[dst as usize].is_ok() {
self.lock(dst);
}
}
}
} }
impl ops::Index<Nid> for Nodes { impl ops::Index<Nid> for Nodes {
@ -1426,7 +1500,7 @@ impl Kind {
} }
fn is_peeped(&self) -> bool { fn is_peeped(&self) -> bool {
!matches!(self, Self::End | Self::Arg) !matches!(self, Self::End | Self::Arg | Self::Mem | Self::Loops)
} }
} }
@ -1449,6 +1523,7 @@ pub struct Node {
kind: Kind, kind: Kind,
inputs: Vc, inputs: Vc,
outputs: Vc, outputs: Vc,
peep_triggers: Vc,
ty: ty::Id, ty: ty::Id,
offset: Offset, offset: Offset,
ralloc_backref: RallocBRef, ralloc_backref: RallocBRef,
@ -1473,7 +1548,8 @@ impl Node {
fn is_not_gvnd(&self) -> bool { fn is_not_gvnd(&self) -> bool {
(self.kind == Kind::Phi && self.inputs[2] == 0) (self.kind == Kind::Phi && self.inputs[2] == 0)
|| matches!(self.kind, Kind::Arg | Kind::Stck | Kind::End) || matches!(self.kind, Kind::Arg | Kind::Stck)
|| self.kind.is_cfg()
} }
fn is_mem(&self) -> bool { fn is_mem(&self) -> bool {
@ -1724,11 +1800,12 @@ impl ItemCtx {
self.scope.aclasses.push(AClass::new(&mut self.nodes)); self.scope.aclasses.push(AClass::new(&mut self.nodes));
} }
fn finalize(&mut self, stack: &mut Vec<Nid>) { fn finalize(&mut self, stack: &mut Vec<Nid>, _tys: &Types, _files: &[parser::Ast]) {
self.scope.clear(&mut self.nodes); self.scope.clear(&mut self.nodes);
mem::take(&mut self.ctrl).soft_remove(&mut self.nodes); mem::take(&mut self.ctrl).soft_remove(&mut self.nodes);
self.nodes.eliminate_stack_temporaries();
self.nodes.iter_peeps(1000, stack); self.nodes.iter_peeps(1000, stack);
self.nodes.unlock(MEM); self.nodes.unlock(MEM);
self.nodes.unlock(NEVER); self.nodes.unlock(NEVER);
self.nodes.unlock(LOOPS); self.nodes.unlock(LOOPS);
@ -1993,7 +2070,7 @@ impl<'a> Codegen<'a> {
); );
debug_assert!(self.ci.nodes[region].kind != Kind::Stre); debug_assert!(self.ci.nodes[region].kind != Kind::Stre);
let (value_index, value_region) = self.aclass_index(value); let (value_index, value_region) = self.ci.nodes.aclass_index(value);
if value_index != 0 { if value_index != 0 {
// simply switch the class to the default one // simply switch the class to the default one
let aclass = &mut self.ci.scope.aclasses[value_index]; let aclass = &mut self.ci.scope.aclasses[value_index];
@ -2018,7 +2095,7 @@ impl<'a> Codegen<'a> {
self.ci.nodes[value_region].aclass = 0; self.ci.nodes[value_region].aclass = 0;
} }
let (index, _) = self.aclass_index(region); let (index, _) = self.ci.nodes.aclass_index(region);
let aclass = &mut self.ci.scope.aclasses[index]; let aclass = &mut self.ci.scope.aclasses[index];
self.ci.nodes.load_loop_aclass(index, aclass, &mut self.ci.loops); self.ci.nodes.load_loop_aclass(index, aclass, &mut self.ci.loops);
let mut vc = Vc::from([VOID, value, region, aclass.last_store.get()]); let mut vc = Vc::from([VOID, value, region, aclass.last_store.get()]);
@ -2031,11 +2108,10 @@ impl<'a> Codegen<'a> {
vc.push(load); vc.push(load);
} }
} }
let store = self.ci.nodes.new_node_nop(ty, Kind::Stre, vc); mem::take(&mut aclass.last_store).soft_remove(&mut self.ci.nodes);
aclass.last_store.set(store, &mut self.ci.nodes); let store = self.ci.nodes.new_node(ty, Kind::Stre, vc);
let opted = self.ci.nodes.late_peephole(store).unwrap_or(store); aclass.last_store = StrongRef::new(store, &mut self.ci.nodes);
aclass.last_store.set_remove(opted, &mut self.ci.nodes); store
opted
} }
fn load_mem(&mut self, region: Nid, ty: ty::Id) -> Nid { fn load_mem(&mut self, region: Nid, ty: ty::Id) -> Nid {
@ -2052,7 +2128,7 @@ impl<'a> Codegen<'a> {
self.ty_display(self.ci.nodes[region].ty) self.ty_display(self.ci.nodes[region].ty)
); );
debug_assert!(self.ci.nodes[region].kind != Kind::Stre); debug_assert!(self.ci.nodes[region].kind != Kind::Stre);
let (index, _) = self.aclass_index(region); let (index, _) = self.ci.nodes.aclass_index(region);
let aclass = &mut self.ci.scope.aclasses[index]; let aclass = &mut self.ci.scope.aclasses[index];
self.ci.nodes.load_loop_aclass(index, aclass, &mut self.ci.loops); self.ci.nodes.load_loop_aclass(index, aclass, &mut self.ci.loops);
let vc = [VOID, region, aclass.last_store.get()]; let vc = [VOID, region, aclass.last_store.get()];
@ -2061,21 +2137,6 @@ impl<'a> Codegen<'a> {
load load
} }
pub fn aclass_index(&mut self, mut region: Nid) -> (usize, Nid) {
loop {
region = match self.ci.nodes[region].kind {
Kind::BinOp { op: TokenKind::Add | TokenKind::Sub } => {
self.ci.nodes[region].inputs[1]
}
Kind::Phi => {
debug_assert_eq!(self.ci.nodes[region].inputs[2], 0);
self.ci.nodes[region].inputs[1]
}
_ => break (self.ci.nodes[region].aclass, region),
};
}
}
pub fn generate(&mut self, entry: FileId) { pub fn generate(&mut self, entry: FileId) {
self.find_type(0, entry, entry, Err("main"), self.files); self.find_type(0, entry, entry, Err("main"), self.files);
if self.tys.ins.funcs.is_empty() { if self.tys.ins.funcs.is_empty() {
@ -2229,7 +2290,7 @@ impl<'a> Codegen<'a> {
} }
self.ci.ctrl.set( self.ci.ctrl.set(
self.ci.nodes.new_node(ty::Id::VOID, Kind::Return, inps), self.ci.nodes.new_node_nop(ty::Id::VOID, Kind::Return, inps),
&mut self.ci.nodes, &mut self.ci.nodes,
); );
@ -2567,7 +2628,7 @@ impl<'a> Codegen<'a> {
for arg in args { for arg in args {
let value = self.expr(arg)?; let value = self.expr(arg)?;
if let Some(base) = self.tys.base_of(value.ty) { if let Some(base) = self.tys.base_of(value.ty) {
clobbered_aliases.push(self.aclass_index(value.id).0); clobbered_aliases.push(self.ci.nodes.aclass_index(value.id).0);
if base.has_pointers(self.tys) { if base.has_pointers(self.tys) {
clobbered_aliases.push(0); clobbered_aliases.push(0);
} }
@ -2674,7 +2735,7 @@ impl<'a> Codegen<'a> {
self.assert_ty(arg.pos(), &mut value, ty, fa!("argument {}", carg.name)); self.assert_ty(arg.pos(), &mut value, ty, fa!("argument {}", carg.name));
if let Some(base) = self.tys.base_of(value.ty) { if let Some(base) = self.tys.base_of(value.ty) {
clobbered_aliases.push(self.aclass_index(value.id).0); clobbered_aliases.push(self.ci.nodes.aclass_index(value.id).0);
if base.has_pointers(self.tys) { if base.has_pointers(self.tys) {
clobbered_aliases.push(0); clobbered_aliases.push(0);
} }
@ -3600,7 +3661,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.ci.finalize(&mut self.pool.nid_stack, self.tys, self.files);
if self.errors.borrow().len() == 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);
@ -3737,7 +3798,7 @@ 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.ci.finalize(&mut self.pool.nid_stack, self.tys, self.files);
let res = if self.errors.borrow().len() == prev_err_len { let res = if self.errors.borrow().len() == prev_err_len {
self.emit_and_eval(file, ret, &mut []) self.emit_and_eval(file, ret, &mut [])
@ -3781,7 +3842,7 @@ 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.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.errors.borrow().len() == prev_err_len {

View file

@ -809,6 +809,7 @@ impl<'a> Function<'a> {
let mut args = self.nodes[VOID].outputs[ARG_START..].to_owned().into_iter(); let mut args = self.nodes[VOID].outputs[ARG_START..].to_owned().into_iter();
while let Some(ty) = typs.next_value(self.tys) { while let Some(ty) = typs.next_value(self.tys) {
let arg = args.next().unwrap(); let arg = args.next().unwrap();
debug_assert_eq!(self.nodes[arg].kind, Kind::Arg);
match parama.next(ty, self.tys) { match parama.next(ty, self.tys) {
None => {} None => {}
Some(PLoc::Reg(r, _) | PLoc::WideReg(r, _) | PLoc::Ref(r, _)) => { Some(PLoc::Reg(r, _) | PLoc::WideReg(r, _) | PLoc::Ref(r, _)) => {

View file

@ -0,0 +1,16 @@
main:
ADDI64 r254, r254, -24d
ADDI64 r2, r254, 16d
ST r2, r254, 0a, 8h
LI64 r5, 0d
LI64 r4, 2d
ST r5, r254, 8a, 8h
ST r4, r254, 16a, 8h
LD r10, r254, 0a, 8h
ST r5, r10, 0a, 8h
LD r1, r254, 16a, 8h
ADDI64 r254, r254, 24d
JALA r0, r31, 0a
code size: 150
ret: 0
status: Ok(())

View file

@ -1,24 +1,17 @@
main: main:
ADDI64 r254, r254, -44d ADDI64 r254, r254, -40d
ST r31, r254, 28a, 16h ST r31, r254, 24a, 16h
LI64 r32, 1d LI64 r32, 1d
ADDI64 r2, r254, 0d ADDI64 r2, r254, 0d
ST r32, r254, 0a, 8h ST r32, r254, 0a, 8h
LI64 r8, 2d LI64 r5, 2d
ST r8, r254, 8a, 8h ST r5, r254, 8a, 8h
LI64 r11, 4d LI64 r8, 4d
ST r11, r254, 16a, 8h ST r8, r254, 16a, 8h
JAL r31, r0, :pass JAL r31, r0, :pass
LI8 r10, 0b
ST r10, r254, 24a, 1h
ST r10, r254, 25a, 1h
LI16 r12, 511h
ST r12, r254, 26a, 1h
LI16 r4, 1h
ST r4, r254, 27a, 1h
ADD64 r1, r1, r32 ADD64 r1, r1, r32
LD r31, r254, 28a, 16h LD r31, r254, 24a, 16h
ADDI64 r254, r254, 44d ADDI64 r254, r254, 40d
JALA r0, r31, 0a JALA r0, r31, 0a
pass: pass:
LD r4, r2, 8a, 8h LD r4, r2, 8a, 8h
@ -29,6 +22,6 @@ pass:
LD r1, r10, 0a, 8h LD r1, r10, 0a, 8h
ADD64 r1, r1, r9 ADD64 r1, r1, r9
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 294 code size: 231
ret: 8 ret: 8
status: Ok(()) status: Ok(())

View file

@ -2,8 +2,8 @@ cond:
LI64 r1, 0d LI64 r1, 0d
JALA r0, r31, 0a JALA r0, r31, 0a
main: main:
ADDI64 r254, r254, -16d ADDI64 r254, r254, -8d
ST r31, r254, 8a, 8h ST r31, r254, 0a, 8h
JAL r31, r0, :cond JAL r31, r0, :cond
LI64 r5, 0d LI64 r5, 0d
CP r7, r5 CP r7, r5
@ -12,10 +12,9 @@ main:
CP r1, r5 CP r1, r5
JMP :1 JMP :1
0: LI64 r1, 2d 0: LI64 r1, 2d
1: ST r1, r254, 0a, 8h 1: LD r31, r254, 0a, 8h
LD r31, r254, 8a, 8h ADDI64 r254, r254, 8d
ADDI64 r254, r254, 16d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 147 code size: 134
ret: 0 ret: 0
status: Ok(()) status: Ok(())

View file

@ -1,23 +1,19 @@
main: main:
ADDI64 r254, r254, -31d ADDI64 r254, r254, -16d
LI64 r1, 10d LI64 r1, 10d
ADDI64 r4, r254, 15d ADDI64 r4, r254, 0d
ST r1, r254, 15a, 8h ST r1, r254, 0a, 8h
LI64 r7, 20d LI64 r7, 20d
ST r7, r254, 23a, 8h ST r7, r254, 8a, 8h
LI64 r6, 6d LI64 r6, 6d
LI64 r5, 5d LI64 r5, 5d
LI64 r2, 1d LI64 r2, 1d
LD r3, r4, 0a, 16h LD r3, r4, 0a, 16h
ECA ECA
LRA r5, r0, :arbitrary text
ADDI64 r7, r254, 0d
BMC r5, r7, 15h
LI64 r1, 0d LI64 r1, 0d
ADDI64 r254, r254, 31d ADDI64 r254, r254, 16d
JALA r0, r31, 0a JALA r0, r31, 0a
ev: Ecall ev: Ecall
code size: 190 code size: 152
ret: 0 ret: 0
status: Ok(()) status: Ok(())

View file

@ -22,22 +22,19 @@ scalar_values:
LI64 r1, 0d LI64 r1, 0d
JALA r0, r31, 0a JALA r0, r31, 0a
structs: structs:
ADDI64 r254, r254, -48d ADDI64 r254, r254, -32d
LI64 r3, 5d LI64 r2, 5d
ST r3, r254, 0a, 8h ST r2, r254, 16a, 8h
ST r3, r254, 8a, 8h ST r2, r254, 24a, 8h
LD r7, r254, 0a, 8h LD r6, r254, 16a, 8h
ADDI64 r9, r7, 15d ADDI64 r8, r6, 15d
ST r9, r254, 24a, 8h ST r8, r254, 0a, 8h
LI64 r8, 20d LI64 r7, 20d
ST r8, r254, 32a, 8h ST r7, r254, 8a, 8h
LI64 r9, 0d LD r1, r254, 0a, 8h
LD r3, r254, 24a, 8h SUB64 r1, r1, r7
ST r8, r254, 16a, 8h ADDI64 r254, r254, 32d
ST r9, r254, 40a, 8h
SUB64 r1, r3, r8
ADDI64 r254, r254, 48d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 346 code size: 310
ret: 0 ret: 0
status: Ok(()) status: Ok(())

View file

@ -2,31 +2,31 @@ main:
ADDI64 r254, r254, -152d ADDI64 r254, r254, -152d
LI8 r1, 0b LI8 r1, 0b
LI8 r3, 1b LI8 r3, 1b
ST r1, r254, 148a, 1h ST r1, r254, 132a, 1h
ST r3, r254, 144a, 1h ST r3, r254, 128a, 1h
ST r1, r254, 149a, 1h ST r1, r254, 133a, 1h
ST r3, r254, 145a, 1h ST r3, r254, 129a, 1h
ST r1, r254, 150a, 1h ST r1, r254, 134a, 1h
ST r3, r254, 146a, 1h ST r3, r254, 130a, 1h
ST r1, r254, 151a, 1h ST r1, r254, 135a, 1h
ST r3, r254, 147a, 1h ST r3, r254, 131a, 1h
LD r1, r254, 148a, 1h LD r1, r254, 132a, 1h
LD r4, r254, 144a, 1h LD r4, r254, 128a, 1h
ADD8 r5, r4, r1 ADD8 r5, r4, r1
LD r8, r254, 145a, 1h LD r8, r254, 129a, 1h
LD r9, r254, 149a, 1h LD r9, r254, 133a, 1h
ST r5, r254, 148a, 1h ST r5, r254, 132a, 1h
ADD8 r12, r9, r8 ADD8 r12, r9, r8
LD r4, r254, 146a, 1h LD r4, r254, 130a, 1h
LD r5, r254, 150a, 1h LD r5, r254, 134a, 1h
ST r12, r254, 149a, 1h ST r12, r254, 133a, 1h
ADD8 r7, r5, r4 ADD8 r7, r5, r4
ST r7, r254, 150a, 1h ST r7, r254, 134a, 1h
ST r3, r254, 151a, 1h ST r3, r254, 135a, 1h
LD r12, r254, 149a, 1h LD r12, r254, 133a, 1h
LD r1, r254, 150a, 1h LD r1, r254, 134a, 1h
ADD8 r4, r1, r12 ADD8 r4, r1, r12
LD r5, r254, 148a, 1h LD r5, r254, 132a, 1h
ADD8 r7, r5, r4 ADD8 r7, r5, r4
LI8 r9, 4b LI8 r9, 4b
ADD8 r1, r7, r3 ADD8 r1, r7, r3
@ -36,61 +36,61 @@ main:
LI64 r1, 1008d LI64 r1, 1008d
JMP :1 JMP :1
0: LI64 r6, 1d 0: LI64 r6, 1d
ADDI64 r5, r254, 112d ADDI64 r5, r254, 80d
ST r6, r254, 112a, 8h ST r6, r254, 80a, 8h
LI64 r9, 2d LI64 r9, 2d
ST r9, r254, 120a, 8h ST r9, r254, 88a, 8h
LI64 r2, 3d LI64 r2, 3d
ADDI64 r1, r254, 96d ADDI64 r1, r254, 64d
ST r2, r254, 64a, 8h ST r2, r254, 48a, 8h
LI64 r6, 4d LI64 r6, 4d
LI64 r2, 0d LI64 r2, 0d
BMC r5, r1, 16h BMC r5, r1, 16h
ST r6, r254, 72a, 8h ST r6, r254, 56a, 8h
ST r2, r254, 80a, 8h ST r2, r254, 0a, 8h
LD r11, r254, 96a, 8h LD r11, r254, 64a, 8h
LD r1, r254, 64a, 8h LD r1, r254, 48a, 8h
ST r2, r254, 88a, 8h ST r2, r254, 8a, 8h
ADD64 r4, r1, r11 ADD64 r4, r1, r11
LD r7, r254, 104a, 8h LD r7, r254, 72a, 8h
LD r2, r254, 80a, 8h LD r2, r254, 0a, 8h
ST r4, r254, 32a, 8h ST r4, r254, 96a, 8h
ADD64 r12, r7, r6 ADD64 r12, r7, r6
SUB64 r3, r2, r1 SUB64 r3, r2, r1
ADDI64 r8, r254, 0d ADDI64 r8, r254, 16d
ST r12, r254, 40a, 8h ST r12, r254, 104a, 8h
SUB64 r2, r1, r11 SUB64 r2, r1, r11
ST r3, r254, 0a, 8h ST r3, r254, 16a, 8h
LI64 r9, -4d LI64 r9, -4d
ST r2, r254, 48a, 8h ST r2, r254, 112a, 8h
SUB64 r7, r6, r7 SUB64 r7, r6, r7
ST r9, r254, 8a, 8h ST r9, r254, 24a, 8h
ADDI64 r8, r8, 16d ADDI64 r8, r8, 16d
ST r7, r254, 56a, 8h ST r7, r254, 120a, 8h
BMC r5, r8, 16h BMC r5, r8, 16h
LD r6, r254, 32a, 8h LD r6, r254, 96a, 8h
LD r8, r254, 0a, 8h
ADD64 r9, r8, r6
LD r11, r254, 8a, 8h
LD r1, r254, 40a, 8h
ST r9, r254, 0a, 8h
ADD64 r4, r1, r11
LD r8, r254, 16a, 8h LD r8, r254, 16a, 8h
LD r9, r254, 48a, 8h ADD64 r9, r8, r6
ST r4, r254, 8a, 8h LD r11, r254, 24a, 8h
LD r1, r254, 104a, 8h
ST r9, r254, 16a, 8h
ADD64 r4, r1, r11
LD r8, r254, 32a, 8h
LD r9, r254, 112a, 8h
ST r4, r254, 24a, 8h
ADD64 r12, r9, r8 ADD64 r12, r9, r8
LD r2, r254, 24a, 8h LD r2, r254, 40a, 8h
ST r12, r254, 16a, 8h ST r12, r254, 32a, 8h
ADD64 r12, r2, r7 ADD64 r12, r2, r7
ST r12, r254, 24a, 8h ST r12, r254, 40a, 8h
LD r7, r254, 0a, 8h LD r7, r254, 16a, 8h
LD r9, r254, 16a, 8h LD r9, r254, 32a, 8h
ADD64 r11, r9, r7 ADD64 r11, r9, r7
LD r1, r254, 8a, 8h LD r1, r254, 24a, 8h
ST r11, r254, 128a, 8h ST r11, r254, 136a, 8h
ADD64 r6, r1, r12 ADD64 r6, r1, r12
ST r6, r254, 136a, 8h ST r6, r254, 144a, 8h
LD r7, r254, 128a, 8h LD r7, r254, 136a, 8h
ADD64 r1, r7, r6 ADD64 r1, r7, r6
1: ADDI64 r254, r254, 152d 1: ADDI64 r254, r254, 152d
JALA r0, r31, 0a JALA r0, r31, 0a

View file

@ -1,25 +1,23 @@
main: main:
ADDI64 r254, r254, -80d ADDI64 r254, r254, -56d
ST r31, r254, 48a, 32h ST r31, r254, 32a, 24h
LI64 r2, 4d LI64 r3, 4d
ADDI64 r32, r254, 32d ADDI64 r2, r254, 16d
ST r2, r254, 32a, 8h ST r3, r254, 16a, 8h
LI64 r33, 3d LI64 r32, 3d
ST r33, r254, 40a, 8h ST r32, r254, 24a, 8h
ADDI64 r34, r254, 0d ADDI64 r33, r254, 0d
LD r3, r32, 0a, 16h LD r3, r2, 0a, 16h
JAL r31, r0, :odher_pass JAL r31, r0, :odher_pass
ST r1, r254, 0a, 16h ST r1, r254, 0a, 16h
ADDI64 r11, r254, 16d LD r2, r254, 8a, 8h
BMC r32, r11, 16h JNE r2, r32, :0
LD r4, r254, 8a, 8h CP r2, r33
JNE r4, r33, :0
CP r2, r34
JAL r31, r0, :pass JAL r31, r0, :pass
JMP :1 JMP :1
0: LI64 r1, 0d 0: LI64 r1, 0d
1: LD r31, r254, 48a, 32h 1: LD r31, r254, 32a, 24h
ADDI64 r254, r254, 80d ADDI64 r254, r254, 56d
JALA r0, r31, 0a JALA r0, r31, 0a
odher_pass: odher_pass:
ADDI64 r254, r254, -16d ADDI64 r254, r254, -16d
@ -31,6 +29,6 @@ odher_pass:
pass: pass:
LD r1, r2, 0a, 8h LD r1, r2, 0a, 8h
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 321 code size: 305
ret: 4 ret: 4
status: Ok(()) status: Ok(())

View file

@ -14,32 +14,30 @@ main:
ADDI64 r254, r254, 24d ADDI64 r254, r254, 24d
JALA r0, r31, 0a JALA r0, r31, 0a
maina: maina:
ADDI64 r254, r254, -44d ADDI64 r254, r254, -36d
ST r31, r254, 36a, 8h ST r31, r254, 28a, 8h
ADDI64 r6, r254, 32d ADDI64 r5, r254, 24d
JAL r31, r0, :small_struct JAL r31, r0, :small_struct
ST r1, r254, 32a, 4h ST r1, r254, 24a, 4h
LI8 r11, 0b LI8 r11, 0b
ADDI64 r10, r254, 24d ADDI64 r10, r254, 0d
ST r11, r254, 24a, 1h ST r11, r254, 0a, 1h
ST r11, r254, 25a, 1h ST r11, r254, 1a, 1h
ST r11, r254, 26a, 1h ST r11, r254, 2a, 1h
LI8 r4, 3b LI8 r4, 3b
ST r4, r254, 27a, 1h ST r4, r254, 3a, 1h
LI8 r7, 1b LI8 r7, 1b
ST r7, r254, 28a, 1h ST r7, r254, 4a, 1h
ST r11, r254, 29a, 1h ST r11, r254, 5a, 1h
ST r11, r254, 30a, 1h ST r11, r254, 6a, 1h
ST r11, r254, 31a, 1h ST r11, r254, 7a, 1h
ADDI64 r2, r254, 0d ADDI64 r1, r254, 8d
BMC r10, r2, 8h BMC r10, r1, 8h
ADDI64 r5, r2, 8d ADDI64 r4, r1, 8d
ADDI64 r4, r254, 16d
BMC r10, r5, 8h
BMC r10, r4, 8h BMC r10, r4, 8h
LD r1, r2, 0a, 16h LD r1, r1, 0a, 16h
LD r31, r254, 36a, 8h LD r31, r254, 28a, 8h
ADDI64 r254, r254, 44d ADDI64 r254, r254, 36d
JALA r0, r31, 0a JALA r0, r31, 0a
small_struct: small_struct:
ADDI64 r254, r254, -4d ADDI64 r254, r254, -4d
@ -50,6 +48,6 @@ small_struct:
LD r1, r3, 0a, 4h LD r1, r3, 0a, 4h
ADDI64 r254, r254, 4d ADDI64 r254, r254, 4d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 514 code size: 498
ret: 2 ret: 2
status: Ok(()) status: Ok(())