making some pointer peepholes
This commit is contained in:
parent
c0d4464097
commit
02c74a181d
|
@ -947,3 +947,23 @@ main := fn(): int {
|
||||||
return back_buffer[1024 * 2]
|
return back_buffer[1024 * 2]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### pointer_opts
|
||||||
|
```hb
|
||||||
|
main := fn(): int {
|
||||||
|
mem := &0;
|
||||||
|
*mem = 1;
|
||||||
|
*mem = 2
|
||||||
|
|
||||||
|
b := *mem + *mem
|
||||||
|
clobber(mem)
|
||||||
|
|
||||||
|
b -= *mem
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
clobber := fn(cb: ^int): void {
|
||||||
|
*cb = 4
|
||||||
|
return
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
--fmt - format all source files
|
--fmt - format all source files
|
||||||
--fmt-current - format mentioned file
|
--fmt-current - format mentioned file
|
||||||
--fmt-stdout - dont write the formatted file but print it
|
--fmt-stdout - dont write the formatted file but print it
|
||||||
|
--dump-asm - output assembly instead of raw code, (the assembly is more for debugging the compiler)
|
||||||
--threads <1...> - number of threads compiler can use [default: 1]
|
--threads <1...> - number of threads compiler can use [default: 1]
|
||||||
|
|
|
@ -866,6 +866,13 @@ impl Types {
|
||||||
_ => self.size_of(ty).max(1),
|
_ => self.size_of(ty).max(1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn base_of(&self, ty: ty::Id) -> Option<ty::Id> {
|
||||||
|
match ty.expand() {
|
||||||
|
ty::Kind::Ptr(p) => Some(self.ptrs[p as usize].base),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TaskQueue<T> {
|
struct TaskQueue<T> {
|
||||||
|
|
|
@ -455,19 +455,28 @@ impl Nodes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_node(&mut self, ty: impl Into<ty::Id>, kind: Kind, inps: impl Into<Vc>) -> Nid {
|
fn new_node_low(
|
||||||
|
&mut self,
|
||||||
|
ty: impl Into<ty::Id>,
|
||||||
|
kind: Kind,
|
||||||
|
inps: impl Into<Vc>,
|
||||||
|
) -> (Nid, bool) {
|
||||||
let id = self.new_node_nop(ty, kind, inps);
|
let id = self.new_node_nop(ty, kind, inps);
|
||||||
if let Some(opt) = self.peephole(id) {
|
if let Some(opt) = self.peephole(id) {
|
||||||
debug_assert_ne!(opt, id);
|
debug_assert_ne!(opt, id);
|
||||||
self.lock(opt);
|
self.lock(opt);
|
||||||
self.remove(id);
|
self.remove(id);
|
||||||
self.unlock(opt);
|
self.unlock(opt);
|
||||||
opt
|
(opt, true)
|
||||||
} else {
|
} else {
|
||||||
id
|
(id, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_node(&mut self, ty: impl Into<ty::Id>, kind: Kind, inps: impl Into<Vc>) -> Nid {
|
||||||
|
self.new_node_low(ty, kind, inps).0
|
||||||
|
}
|
||||||
|
|
||||||
fn lock(&mut self, target: Nid) {
|
fn lock(&mut self, target: Nid) {
|
||||||
self[target].lock_rc += 1;
|
self[target].lock_rc += 1;
|
||||||
}
|
}
|
||||||
|
@ -496,119 +505,145 @@ impl Nodes {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peephole(&mut self, target: Nid) -> Option<Nid> {
|
fn peephole(&mut self, target: Nid) -> Option<Nid> {
|
||||||
|
use {Kind as K, TokenKind as T};
|
||||||
match self[target].kind {
|
match self[target].kind {
|
||||||
Kind::BinOp { op } => return self.peephole_binop(target, op),
|
K::BinOp { op } => {
|
||||||
Kind::UnOp { op } => return self.peephole_unop(target, op),
|
let &[ctrl, mut lhs, mut rhs] = self[target].inputs.as_slice() else {
|
||||||
Kind::If => return self.peephole_if(target),
|
unreachable!()
|
||||||
Kind::Phi => return self.peephole_phi(target),
|
};
|
||||||
|
let ty = self[target].ty;
|
||||||
|
|
||||||
|
if let (&K::CInt { value: a }, &K::CInt { value: b }) =
|
||||||
|
(&self[lhs].kind, &self[rhs].kind)
|
||||||
|
{
|
||||||
|
return Some(
|
||||||
|
self.new_node(ty, K::CInt { value: op.apply_binop(a, b) }, [ctrl]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if lhs == rhs {
|
||||||
|
match op {
|
||||||
|
T::Sub => return Some(self.new_node(ty, K::CInt { value: 0 }, [ctrl])),
|
||||||
|
T::Add => {
|
||||||
|
let rhs = self.new_node_nop(ty, K::CInt { value: 2 }, [ctrl]);
|
||||||
|
return Some(
|
||||||
|
self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, lhs, rhs]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is more general the pushing constants to left to help deduplicate expressions more
|
||||||
|
let mut changed = false;
|
||||||
|
if op.is_comutative() && self[lhs].key() < self[rhs].key() {
|
||||||
|
std::mem::swap(&mut lhs, &mut rhs);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let K::CInt { value } = self[lhs].kind
|
||||||
|
&& op == T::Sub
|
||||||
|
{
|
||||||
|
let lhs = self.new_node_nop(ty, K::CInt { value: -value }, [ctrl]);
|
||||||
|
return Some(self.new_node(ty, K::BinOp { op: T::Add }, [ctrl, rhs, lhs]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let K::CInt { value } = self[rhs].kind {
|
||||||
|
match (op, value) {
|
||||||
|
(T::Add | T::Sub | T::Shl, 0) | (T::Mul | T::Div, 1) => return Some(lhs),
|
||||||
|
(T::Mul, 0) => return Some(rhs),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if op.is_comutative() && self[lhs].kind == (K::BinOp { op }) {
|
||||||
|
let &[_, a, b] = self[lhs].inputs.as_slice() else { unreachable!() };
|
||||||
|
if let K::CInt { value: av } = self[b].kind
|
||||||
|
&& let K::CInt { value: bv } = self[rhs].kind
|
||||||
|
{
|
||||||
|
// (a op #b) op #c => a op (#b op #c)
|
||||||
|
let new_rhs =
|
||||||
|
self.new_node_nop(ty, K::CInt { value: op.apply_binop(av, bv) }, [
|
||||||
|
ctrl,
|
||||||
|
]);
|
||||||
|
return Some(self.new_node(ty, K::BinOp { op }, [ctrl, a, new_rhs]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.is_const(b) {
|
||||||
|
// (a op #b) op c => (a op c) op #b
|
||||||
|
let new_lhs = self.new_node(ty, K::BinOp { op }, [ctrl, a, rhs]);
|
||||||
|
return Some(self.new_node(ty, K::BinOp { op }, [ctrl, new_lhs, b]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if op == T::Add
|
||||||
|
&& self[lhs].kind == (K::BinOp { op: T::Mul })
|
||||||
|
&& self[lhs].inputs[1] == rhs
|
||||||
|
&& let K::CInt { value } = self[self[lhs].inputs[2]].kind
|
||||||
|
{
|
||||||
|
// a * #n + a => a * (#n + 1)
|
||||||
|
let new_rhs = self.new_node_nop(ty, K::CInt { value: value + 1 }, [ctrl]);
|
||||||
|
return Some(self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, rhs, new_rhs]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if op == T::Sub && self[lhs].kind == (K::BinOp { op }) {
|
||||||
|
// (a - b) - c => a - (b + c)
|
||||||
|
let &[_, a, b] = self[lhs].inputs.as_slice() else { unreachable!() };
|
||||||
|
let c = rhs;
|
||||||
|
let new_rhs = self.new_node(ty, K::BinOp { op: T::Add }, [ctrl, b, c]);
|
||||||
|
return Some(self.new_node(ty, K::BinOp { op }, [ctrl, a, new_rhs]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if changed {
|
||||||
|
return Some(self.new_node(ty, self[target].kind, [ctrl, lhs, rhs]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
K::UnOp { op } => {
|
||||||
|
let &[ctrl, oper] = self[target].inputs.as_slice() else { unreachable!() };
|
||||||
|
let ty = self[target].ty;
|
||||||
|
|
||||||
|
if let K::CInt { value } = self[oper].kind {
|
||||||
|
return Some(
|
||||||
|
self.new_node(ty, K::CInt { value: op.apply_unop(value) }, [ctrl]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
K::If => {
|
||||||
|
let cond = self[target].inputs[1];
|
||||||
|
if let K::CInt { value } = self[cond].kind {
|
||||||
|
let ty = if value == 0 { ty::LEFT_UNREACHABLE } else { ty::RIGHT_UNREACHABLE };
|
||||||
|
return Some(self.new_node_nop(ty, K::If, [self[target].inputs[0], cond]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
K::Phi => {
|
||||||
|
if self[target].inputs[1] == self[target].inputs[2] {
|
||||||
|
return Some(self[target].inputs[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
K::Stre => {
|
||||||
|
let parent = self[target].inputs[2];
|
||||||
|
if self[parent].kind == K::Stre && self[parent].outputs.len() == 1 {
|
||||||
|
return Some(self.modify_input(parent, 1, self[target].inputs[1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
K::Load => {
|
||||||
|
let parent = self[target].inputs[1];
|
||||||
|
|
||||||
|
if self[parent].kind == K::Stre && self[parent].offset != u32::MAX {
|
||||||
|
debug_assert_eq!(self[target].ty, self[parent].ty, "TODO");
|
||||||
|
return Some(self[parent].inputs[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self[parent].kind == K::Load && self[parent].offset != u32::MAX {
|
||||||
|
return Some(parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn peephole_phi(&mut self, target: Nid) -> Option<Nid> {
|
|
||||||
if self[target].inputs[1] == self[target].inputs[2] {
|
|
||||||
return Some(self[target].inputs[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peephole_if(&mut self, target: Nid) -> Option<Nid> {
|
|
||||||
let cond = self[target].inputs[1];
|
|
||||||
if let Kind::CInt { value } = self[cond].kind {
|
|
||||||
let ty = if value == 0 { ty::LEFT_UNREACHABLE } else { ty::RIGHT_UNREACHABLE };
|
|
||||||
return Some(self.new_node_nop(ty, Kind::If, [self[target].inputs[0], cond]));
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn peephole_unop(&mut self, target: Nid, op: TokenKind) -> Option<Nid> {
|
|
||||||
let &[ctrl, oper] = self[target].inputs.as_slice() else { unreachable!() };
|
|
||||||
let ty = self[target].ty;
|
|
||||||
|
|
||||||
if let Kind::CInt { value } = self[oper].kind {
|
|
||||||
return Some(self.new_node(ty, Kind::CInt { value: op.apply_unop(value) }, [ctrl]));
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn peephole_binop(&mut self, target: Nid, op: TokenKind) -> Option<Nid> {
|
|
||||||
use {Kind as K, TokenKind as T};
|
|
||||||
let &[ctrl, mut lhs, mut rhs] = self[target].inputs.as_slice() else { unreachable!() };
|
|
||||||
let ty = self[target].ty;
|
|
||||||
|
|
||||||
if let (&K::CInt { value: a }, &K::CInt { value: b }) = (&self[lhs].kind, &self[rhs].kind) {
|
|
||||||
return Some(self.new_node(ty, K::CInt { value: op.apply_binop(a, b) }, [ctrl]));
|
|
||||||
}
|
|
||||||
|
|
||||||
if lhs == rhs {
|
|
||||||
match op {
|
|
||||||
T::Sub => return Some(self.new_node(ty, K::CInt { value: 0 }, [ctrl])),
|
|
||||||
T::Add => {
|
|
||||||
let rhs = self.new_node_nop(ty, K::CInt { value: 2 }, [ctrl]);
|
|
||||||
return Some(self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, lhs, rhs]));
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is more general the pushing constants to left to help deduplicate expressions more
|
|
||||||
let mut changed = false;
|
|
||||||
if op.is_comutative() && self[lhs].key() < self[rhs].key() {
|
|
||||||
std::mem::swap(&mut lhs, &mut rhs);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let K::CInt { value } = self[rhs].kind {
|
|
||||||
match (op, value) {
|
|
||||||
(T::Add | T::Sub | T::Shl, 0) | (T::Mul | T::Div, 1) => return Some(lhs),
|
|
||||||
(T::Mul, 0) => return Some(rhs),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if op.is_comutative() && self[lhs].kind == (K::BinOp { op }) {
|
|
||||||
let &[_, a, b] = self[lhs].inputs.as_slice() else { unreachable!() };
|
|
||||||
if let K::CInt { value: av } = self[b].kind
|
|
||||||
&& let K::CInt { value: bv } = self[rhs].kind
|
|
||||||
{
|
|
||||||
// (a op #b) op #c => a op (#b op #c)
|
|
||||||
let new_rhs =
|
|
||||||
self.new_node_nop(ty, K::CInt { value: op.apply_binop(av, bv) }, [ctrl]);
|
|
||||||
return Some(self.new_node(ty, K::BinOp { op }, [ctrl, a, new_rhs]));
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.is_const(b) {
|
|
||||||
// (a op #b) op c => (a op c) op #b
|
|
||||||
let new_lhs = self.new_node(ty, K::BinOp { op }, [ctrl, a, rhs]);
|
|
||||||
return Some(self.new_node(ty, K::BinOp { op }, [ctrl, new_lhs, b]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if op == T::Add
|
|
||||||
&& self[lhs].kind == (K::BinOp { op: T::Mul })
|
|
||||||
&& self[lhs].inputs[1] == rhs
|
|
||||||
&& let K::CInt { value } = self[self[lhs].inputs[2]].kind
|
|
||||||
{
|
|
||||||
// a * #n + a => a * (#n + 1)
|
|
||||||
let new_rhs = self.new_node_nop(ty, K::CInt { value: value + 1 }, [ctrl]);
|
|
||||||
return Some(self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, rhs, new_rhs]));
|
|
||||||
}
|
|
||||||
|
|
||||||
if op == T::Sub && self[lhs].kind == (K::BinOp { op }) {
|
|
||||||
// (a - b) - c => a - (b + c)
|
|
||||||
let &[_, a, b] = self[lhs].inputs.as_slice() else { unreachable!() };
|
|
||||||
let c = rhs;
|
|
||||||
let new_rhs = self.new_node(ty, K::BinOp { op: T::Add }, [ctrl, b, c]);
|
|
||||||
return Some(self.new_node(ty, K::BinOp { op }, [ctrl, a, new_rhs]));
|
|
||||||
}
|
|
||||||
|
|
||||||
changed.then(|| self.new_node(ty, self[target].kind, [ctrl, lhs, rhs]))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_const(&self, id: Nid) -> bool {
|
fn is_const(&self, id: Nid) -> bool {
|
||||||
matches!(self[id].kind, Kind::CInt { .. })
|
matches!(self[id].kind, Kind::CInt { .. })
|
||||||
}
|
}
|
||||||
|
@ -618,9 +653,11 @@ impl Nodes {
|
||||||
for i in 0..self[target].outputs.len() {
|
for i in 0..self[target].outputs.len() {
|
||||||
let out = self[target].outputs[i - back_press];
|
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();
|
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;
|
back_press += (self[target].outputs.len() != prev_len) as usize;
|
||||||
|
self.unlock(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.remove(target);
|
self.remove(target);
|
||||||
|
@ -649,6 +686,7 @@ impl Nodes {
|
||||||
let index = self[prev].outputs.iter().position(|&o| o == target).unwrap();
|
let index = self[prev].outputs.iter().position(|&o| o == target).unwrap();
|
||||||
self[prev].outputs.swap_remove(index);
|
self[prev].outputs.swap_remove(index);
|
||||||
self[with].outputs.push(target);
|
self[with].outputs.push(target);
|
||||||
|
self.remove(prev);
|
||||||
|
|
||||||
target
|
target
|
||||||
}
|
}
|
||||||
|
@ -1037,10 +1075,6 @@ pub enum Kind {
|
||||||
// [ctrl]
|
// [ctrl]
|
||||||
Stck,
|
Stck,
|
||||||
|
|
||||||
// [ctrl, memory]
|
|
||||||
Offset {
|
|
||||||
offset: Offset,
|
|
||||||
},
|
|
||||||
// [ctrl, memory]
|
// [ctrl, memory]
|
||||||
Load,
|
Load,
|
||||||
// [ctrl, memory]
|
// [ctrl, memory]
|
||||||
|
@ -1275,7 +1309,22 @@ pub struct Codegen {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Codegen {
|
impl Codegen {
|
||||||
fn mem_op(&mut self, region: Nid, offset: Offset, kind: Kind, ty: ty::Id, mut inps: Vc) -> Nid {
|
fn mem_op(
|
||||||
|
&mut self,
|
||||||
|
mut region: Nid,
|
||||||
|
offset: Offset,
|
||||||
|
kind: Kind,
|
||||||
|
ty: ty::Id,
|
||||||
|
mut inps: Vc,
|
||||||
|
) -> Nid {
|
||||||
|
loop {
|
||||||
|
match self.ci.nodes[region].kind {
|
||||||
|
Kind::Arg { .. } | Kind::Stck => break,
|
||||||
|
Kind::Stre => region = self.ci.nodes[region].inputs[2],
|
||||||
|
k => unreachable!("{k:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let size = self.tys.size_of(ty);
|
let size = self.tys.size_of(ty);
|
||||||
let insert_start = self
|
let insert_start = self
|
||||||
.ci
|
.ci
|
||||||
|
@ -1292,19 +1341,19 @@ impl Codegen {
|
||||||
debug_assert_eq!(mk.region, region);
|
debug_assert_eq!(mk.region, region);
|
||||||
debug_assert!(mk.offset >= offset);
|
debug_assert!(mk.offset >= offset);
|
||||||
debug_assert!(mk.offset < offset + size);
|
debug_assert!(mk.offset < offset + size);
|
||||||
if matches!(kind, Kind::Load | Kind::Offset { .. })
|
inps.push(mk.node);
|
||||||
|| !self.ci.nodes.unlock_remove(mk.node)
|
|
||||||
{
|
|
||||||
inps.push(mk.node);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if insert_start == insert_end {
|
if insert_start == insert_end {
|
||||||
inps.push(region);
|
inps.push(region);
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_op = self.ci.nodes.new_node(ty, kind, inps);
|
let (new_op, peeped) = self.ci.nodes.new_node_low(ty, kind, inps);
|
||||||
if !matches!(kind, Kind::Offset { .. }) {
|
if !peeped {
|
||||||
|
for mk in &self.ci.memories[insert_start..insert_end] {
|
||||||
|
self.ci.nodes.unlock(mk.node);
|
||||||
|
}
|
||||||
|
|
||||||
self.ci.memories.splice(
|
self.ci.memories.splice(
|
||||||
insert_start..insert_end,
|
insert_start..insert_end,
|
||||||
std::iter::once(MemKey { node: new_op, region, offset }),
|
std::iter::once(MemKey { node: new_op, region, offset }),
|
||||||
|
@ -1322,10 +1371,6 @@ impl Codegen {
|
||||||
self.mem_op(region, offset, Kind::Load, ty, [VOID].into())
|
self.mem_op(region, offset, Kind::Load, ty, [VOID].into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ref_mem(&mut self, region: Nid, offset: Offset, ty: ty::Id) -> Nid {
|
|
||||||
self.mem_op(region, offset, Kind::Offset { offset }, ty, [VOID].into())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generate(&mut self) {
|
pub fn generate(&mut self) {
|
||||||
self.find_or_declare(0, 0, None, "main");
|
self.find_or_declare(0, 0, None, "main");
|
||||||
self.make_func_reachable(0);
|
self.make_func_reachable(0);
|
||||||
|
@ -1403,20 +1448,17 @@ impl Codegen {
|
||||||
} => {
|
} => {
|
||||||
let ctx = Ctx { ty: ctx.ty.map(|ty| self.tys.make_ptr(ty)) };
|
let ctx = Ctx { ty: ctx.ty.map(|ty| self.tys.make_ptr(ty)) };
|
||||||
let val = self.expr_ctx(val, ctx)?;
|
let val = self.expr_ctx(val, ctx)?;
|
||||||
let base = match self.tof(val).expand() {
|
let base = self.get_load_type(val).unwrap_or_else(|| {
|
||||||
ty::Kind::Ptr(p) => self.tys.ptrs[p as usize].base,
|
self.report(
|
||||||
_ => {
|
pos,
|
||||||
self.report(
|
format_args!(
|
||||||
pos,
|
"the '{}' can not be dereferneced",
|
||||||
format_args!(
|
self.ty_display(self.tof(val))
|
||||||
"the '{}' can not be dereferneced",
|
),
|
||||||
self.ty_display(self.tof(val))
|
);
|
||||||
),
|
ty::NEVER.into()
|
||||||
);
|
});
|
||||||
ty::NEVER.into()
|
let value = self.expr_ctx(right, Ctx::default().with_ty(base))?;
|
||||||
}
|
|
||||||
};
|
|
||||||
let value = self.expr(right)?;
|
|
||||||
_ = self.assert_ty(right.pos(), self.tof(value), base, true, "stored value");
|
_ = self.assert_ty(right.pos(), self.tof(value), base, true, "stored value");
|
||||||
self.store_mem(val, 0, value);
|
self.store_mem(val, 0, value);
|
||||||
Some(VOID)
|
Some(VOID)
|
||||||
|
@ -1438,41 +1480,33 @@ impl Codegen {
|
||||||
Some(self.ci.nodes.new_node(ty::bin_ret(ty, op), Kind::BinOp { op }, inps))
|
Some(self.ci.nodes.new_node(ty::bin_ret(ty, op), Kind::BinOp { op }, inps))
|
||||||
}
|
}
|
||||||
Expr::UnOp { op: TokenKind::Band, val, .. } => {
|
Expr::UnOp { op: TokenKind::Band, val, .. } => {
|
||||||
let ctx = Ctx {
|
let ctx = Ctx { ty: ctx.ty.and_then(|ty| self.tys.base_of(ty)) };
|
||||||
ty: ctx.ty.and_then(|ty| match ty.expand() {
|
|
||||||
ty::Kind::Ptr(p) => Some(self.tys.ptrs[p as usize].base),
|
|
||||||
_ => None,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut val = self.expr_ctx(val, ctx)?;
|
let mut val = self.expr_ctx(val, ctx)?;
|
||||||
let ty = self.tof(val);
|
let ty = self.tof(val);
|
||||||
if !matches!(self.ci.nodes[val].kind, Kind::Stck | Kind::Offset { .. }) {
|
if !matches!(self.ci.nodes[val].kind, Kind::Stck) {
|
||||||
let stck = self.ci.nodes.new_node_nop(ty, Kind::Stck, [VOID, MEM]);
|
let ptr = self.tys.make_ptr(ty);
|
||||||
|
let stck = self.ci.nodes.new_node_nop(ptr, Kind::Stck, [VOID, MEM]);
|
||||||
self.ci.nodes[stck].offset = self.ci.stack_size;
|
self.ci.nodes[stck].offset = self.ci.stack_size;
|
||||||
self.ci.stack_size += self.tys.size_of(ty);
|
self.ci.stack_size += self.tys.size_of(ty);
|
||||||
self.store_mem(stck, 0, val);
|
self.store_mem(stck, 0, val);
|
||||||
val = stck;
|
val = stck;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ptr = self.tys.make_ptr(ty);
|
Some(val)
|
||||||
Some(self.ref_mem(val, 0, ptr))
|
|
||||||
}
|
}
|
||||||
Expr::UnOp { op: TokenKind::Mul, val, pos } => {
|
Expr::UnOp { op: TokenKind::Mul, val, pos } => {
|
||||||
let ctx = Ctx { ty: ctx.ty.map(|ty| self.tys.make_ptr(ty)) };
|
let ctx = Ctx { ty: ctx.ty.map(|ty| self.tys.make_ptr(ty)) };
|
||||||
let val = self.expr_ctx(val, ctx)?;
|
let val = self.expr_ctx(val, ctx)?;
|
||||||
let base = match self.tof(val).expand() {
|
let Some(base) = self.get_load_type(val) else {
|
||||||
ty::Kind::Ptr(p) => self.tys.ptrs[p as usize].base,
|
self.report(
|
||||||
_ => {
|
pos,
|
||||||
self.report(
|
format_args!(
|
||||||
pos,
|
"the '{}' can not be dereferneced",
|
||||||
format_args!(
|
self.ty_display(self.tof(val))
|
||||||
"the '{}' can not be dereferneced",
|
),
|
||||||
self.ty_display(self.tof(val))
|
);
|
||||||
),
|
return Some(NEVER);
|
||||||
);
|
|
||||||
ty::NEVER.into()
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
Some(self.load_mem(val, 0, base))
|
Some(self.load_mem(val, 0, base))
|
||||||
}
|
}
|
||||||
|
@ -1701,7 +1735,7 @@ impl Codegen {
|
||||||
if self.tys.size_of(ty) == 0 {
|
if self.tys.size_of(ty) == 0 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let value = self.expr_ctx(arg, Ctx::default().with_ty(ty))?;
|
let mut value = self.expr_ctx(arg, Ctx::default().with_ty(ty))?;
|
||||||
_ = self.assert_ty(
|
_ = self.assert_ty(
|
||||||
arg.pos(),
|
arg.pos(),
|
||||||
self.tof(value),
|
self.tof(value),
|
||||||
|
@ -1709,6 +1743,15 @@ impl Codegen {
|
||||||
true,
|
true,
|
||||||
format_args!("argument {}", carg.name),
|
format_args!("argument {}", carg.name),
|
||||||
);
|
);
|
||||||
|
if ty.is_pointer() {
|
||||||
|
value = self
|
||||||
|
.ci
|
||||||
|
.memories
|
||||||
|
.binary_search_by_key(&(value, 0), |k| (k.region, k.offset))
|
||||||
|
.map_or(value, |i| self.ci.memories[i].node);
|
||||||
|
// mark the read as clobbed since function can store
|
||||||
|
self.ci.nodes[value].offset = u32::MAX;
|
||||||
|
}
|
||||||
inps.push(value);
|
inps.push(value);
|
||||||
}
|
}
|
||||||
self.ci.ctrl = self.ci.nodes.new_node(sig.ret, Kind::Call { func }, inps);
|
self.ci.ctrl = self.ci.nodes.new_node(sig.ret, Kind::Call { func }, inps);
|
||||||
|
@ -2089,10 +2132,15 @@ impl Codegen {
|
||||||
});
|
});
|
||||||
self.ci.emit(instrs::jal(reg::RET_ADDR, reg::ZERO, 0));
|
self.ci.emit(instrs::jal(reg::RET_ADDR, reg::ZERO, 0));
|
||||||
}
|
}
|
||||||
Kind::Stck => todo!(),
|
Kind::Stck => {
|
||||||
|
let size = self.tys.size_of(self.tys.base_of(node.ty).unwrap());
|
||||||
|
let base = reg::STACK_PTR;
|
||||||
|
let offset = self.ci.stack_size - func.nodes[nid].offset - size;
|
||||||
|
self.ci.emit(instrs::addi64(atr(allocs[0]), base, offset as _));
|
||||||
|
}
|
||||||
Kind::Load => {
|
Kind::Load => {
|
||||||
let mut region = node.inputs[1];
|
let mut region = node.inputs[1];
|
||||||
let mut offset = 0;
|
let offset = 0;
|
||||||
let size = self.tys.size_of(node.ty);
|
let size = self.tys.size_of(node.ty);
|
||||||
debug_assert_eq!(size, 8, "TODO");
|
debug_assert_eq!(size, 8, "TODO");
|
||||||
let (base, offset) = loop {
|
let (base, offset) = loop {
|
||||||
|
@ -2104,11 +2152,8 @@ impl Codegen {
|
||||||
- size,
|
- size,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Kind::Offset { offset: o } => {
|
|
||||||
offset = o;
|
|
||||||
region = func.nodes[region].inputs[1]
|
|
||||||
}
|
|
||||||
Kind::Stre => region = func.nodes[region].inputs[2],
|
Kind::Stre => region = func.nodes[region].inputs[2],
|
||||||
|
Kind::Load => region = func.nodes[region].inputs[1],
|
||||||
k => unreachable!("{k:?}"),
|
k => unreachable!("{k:?}"),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -2118,7 +2163,7 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
Kind::Stre => {
|
Kind::Stre => {
|
||||||
let mut region = node.inputs[2];
|
let mut region = node.inputs[2];
|
||||||
let mut offset = 0;
|
let offset = 0;
|
||||||
let size = self.tys.size_of(node.ty);
|
let size = self.tys.size_of(node.ty);
|
||||||
debug_assert_eq!(size, 8, "TODO");
|
debug_assert_eq!(size, 8, "TODO");
|
||||||
let (base, offset, src) = loop {
|
let (base, offset, src) = loop {
|
||||||
|
@ -2134,41 +2179,14 @@ impl Codegen {
|
||||||
Kind::Arg { .. } => {
|
Kind::Arg { .. } => {
|
||||||
break (atr(allocs[0]), 0, allocs[1]);
|
break (atr(allocs[0]), 0, allocs[1]);
|
||||||
}
|
}
|
||||||
Kind::Offset { offset: o } => {
|
|
||||||
offset = o;
|
|
||||||
region = func.nodes[region].inputs[1]
|
|
||||||
}
|
|
||||||
Kind::Stre => region = func.nodes[region].inputs[2],
|
Kind::Stre => region = func.nodes[region].inputs[2],
|
||||||
|
Kind::Load => region = func.nodes[region].inputs[1],
|
||||||
k => unreachable!("{k:?}"),
|
k => unreachable!("{k:?}"),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
self.ci.emit(instrs::st(atr(src), base, offset as _, size as _));
|
self.ci.emit(instrs::st(atr(src), base, offset as _, size as _));
|
||||||
}
|
}
|
||||||
Kind::Offset { mut offset } => {
|
|
||||||
let mut region = node.inputs[1];
|
|
||||||
let size = self.tys.size_of(node.ty);
|
|
||||||
debug_assert_eq!(size, 8, "TODO");
|
|
||||||
let (base, offset) = loop {
|
|
||||||
match func.nodes[region].kind {
|
|
||||||
Kind::Stck => {
|
|
||||||
break (
|
|
||||||
reg::STACK_PTR,
|
|
||||||
self.ci.stack_size - func.nodes[region].offset + offset
|
|
||||||
- size,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Kind::Offset { offset: o } => {
|
|
||||||
offset = o;
|
|
||||||
region = func.nodes[region].inputs[1]
|
|
||||||
}
|
|
||||||
Kind::Stre => region = func.nodes[region].inputs[2],
|
|
||||||
k => unreachable!("{k:?}"),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
let &[dst] = allocs else { unreachable!() };
|
|
||||||
self.ci.emit(instrs::addi64(atr(dst), base, offset as _));
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2382,6 +2400,16 @@ impl Codegen {
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_load_type(&self, val: Nid) -> Option<ty::Id> {
|
||||||
|
Some(match self.ci.nodes[val].kind {
|
||||||
|
Kind::Stre | Kind::Load => self.ci.nodes[val].ty,
|
||||||
|
Kind::Stck | Kind::Arg { .. } => {
|
||||||
|
self.tys.base_of(self.ci.nodes[val].ty).expect("stack has pointer type, laways")
|
||||||
|
}
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: make this more efficient (allocated with arena)
|
// FIXME: make this more efficient (allocated with arena)
|
||||||
|
@ -2576,6 +2604,7 @@ impl<'a> Function<'a> {
|
||||||
let ond = &self.nodes[o];
|
let ond = &self.nodes[o];
|
||||||
matches!(ond.kind, Kind::BinOp { op }
|
matches!(ond.kind, Kind::BinOp { op }
|
||||||
if op.imm_binop(ond.ty.is_signed(), 8).is_some()
|
if op.imm_binop(ond.ty.is_signed(), 8).is_some()
|
||||||
|
&& self.nodes.is_const(ond.inputs[2])
|
||||||
&& op.cond_op(ond.ty.is_signed()).is_none())
|
&& op.cond_op(ond.ty.is_signed()).is_none())
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2650,8 +2679,15 @@ impl<'a> Function<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut parama = self.tys.parama(fuc.ret);
|
let mut parama = self.tys.parama(fuc.ret);
|
||||||
for (&i, ti) in node.inputs[1..].iter().zip(fuc.args.range()) {
|
for (&(mut i), ti) in node.inputs[1..].iter().zip(fuc.args.range()) {
|
||||||
let ty = self.tys.args[ti];
|
let ty = self.tys.args[ti];
|
||||||
|
loop {
|
||||||
|
match self.nodes[i].kind {
|
||||||
|
Kind::Stre => i = self.nodes[i].inputs[2],
|
||||||
|
Kind::Load => i = self.nodes[i].inputs[1],
|
||||||
|
_ => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
match self.tys.size_of(ty) {
|
match self.tys.size_of(ty) {
|
||||||
0 => continue,
|
0 => continue,
|
||||||
1..=8 => {
|
1..=8 => {
|
||||||
|
@ -2672,26 +2708,18 @@ impl<'a> Function<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Kind::Offset { .. } => {
|
Kind::Phi | Kind::Arg { .. } | Kind::Mem => {}
|
||||||
let mut region = node.inputs[1];
|
Kind::Stck => {
|
||||||
let ops = loop {
|
let ops = vec![self.drg(nid)];
|
||||||
match self.nodes[region].kind {
|
|
||||||
Kind::Stck => break vec![self.drg(nid)],
|
|
||||||
Kind::Offset { .. } => region = self.nodes[region].inputs[1],
|
|
||||||
Kind::Stre => region = self.nodes[region].inputs[2],
|
|
||||||
k => unreachable!("{k:?}"),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
self.add_instr(nid, ops);
|
self.add_instr(nid, ops);
|
||||||
}
|
}
|
||||||
Kind::Stck | Kind::Phi | Kind::Arg { .. } | Kind::Mem => {}
|
|
||||||
Kind::Load => {
|
Kind::Load => {
|
||||||
let mut region = node.inputs[1];
|
let mut region = node.inputs[1];
|
||||||
let ops = loop {
|
let ops = loop {
|
||||||
match self.nodes[region].kind {
|
match self.nodes[region].kind {
|
||||||
Kind::Stck => break vec![self.drg(nid)],
|
Kind::Stck => break vec![self.drg(nid)],
|
||||||
Kind::Offset { .. } => region = self.nodes[region].inputs[1],
|
|
||||||
Kind::Stre => region = self.nodes[region].inputs[2],
|
Kind::Stre => region = self.nodes[region].inputs[2],
|
||||||
|
Kind::Load => region = self.nodes[region].inputs[1],
|
||||||
k => unreachable!("{k:?}"),
|
k => unreachable!("{k:?}"),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -2704,8 +2732,8 @@ impl<'a> Function<'a> {
|
||||||
match self.nodes[region].kind {
|
match self.nodes[region].kind {
|
||||||
Kind::Stck => break vec![self.urg(node.inputs[1])],
|
Kind::Stck => break vec![self.urg(node.inputs[1])],
|
||||||
Kind::Arg { .. } => break vec![self.urg(region), self.urg(node.inputs[1])],
|
Kind::Arg { .. } => break vec![self.urg(region), self.urg(node.inputs[1])],
|
||||||
Kind::Offset { .. } => region = self.nodes[region].inputs[1],
|
|
||||||
Kind::Stre => region = self.nodes[region].inputs[2],
|
Kind::Stre => region = self.nodes[region].inputs[2],
|
||||||
|
Kind::Load => region = self.nodes[region].inputs[1],
|
||||||
k => unreachable!("{k:?}"),
|
k => unreachable!("{k:?}"),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -3100,5 +3128,6 @@ mod tests {
|
||||||
//request_page => README;
|
//request_page => README;
|
||||||
//tests_ptr_to_ptr_copy => README;
|
//tests_ptr_to_ptr_copy => README;
|
||||||
//wide_ret => README;
|
//wide_ret => README;
|
||||||
|
pointer_opts => README;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
0
hblang/tests/son_tests_pointer_opts.txt
Normal file
0
hblang/tests/son_tests_pointer_opts.txt
Normal file
|
@ -8,8 +8,8 @@ main:
|
||||||
ADDI64 r254, r254, -32d
|
ADDI64 r254, r254, -32d
|
||||||
ST r31, r254, 8a, 24h
|
ST r31, r254, 8a, 24h
|
||||||
LI64 r32, 1d
|
LI64 r32, 1d
|
||||||
ST r32, r254, 0a, 8h
|
|
||||||
ADDI64 r2, r254, 0d
|
ADDI64 r2, r254, 0d
|
||||||
|
ST r32, r254, 0a, 8h
|
||||||
JAL r31, r0, :modify
|
JAL r31, r0, :modify
|
||||||
CP r2, r32
|
CP r2, r32
|
||||||
JAL r31, r0, :drop
|
JAL r31, r0, :drop
|
||||||
|
|
Loading…
Reference in a new issue