forked from AbleOS/holey-bytes
implementing pointers example
This commit is contained in:
parent
602249a48a
commit
c0d4464097
109
Cargo.lock
generated
109
Cargo.lock
generated
|
@ -2,18 +2,6 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
|
@ -23,6 +11,12 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.15"
|
||||
|
@ -73,10 +67,13 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
name = "bumpalo"
|
||||
version = "3.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
|
@ -112,9 +109,6 @@ name = "hashbrown"
|
|||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hbbytecode"
|
||||
|
@ -188,40 +182,16 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regalloc2"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12908dbeb234370af84d0579b9f68258a0f67e201412dd9a2814e6f45b2fc0f0"
|
||||
source = "git+https://github.com/jakubDoka/regalloc2?branch=reuse-allocations#4100af4e24bc2921c0931c901651a969c898f852"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"bumpalo",
|
||||
"hashbrown",
|
||||
"log",
|
||||
"rustc-hash",
|
||||
"slice-group-by",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
|
@ -260,47 +230,18 @@ version = "2.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
|
||||
|
||||
[[package]]
|
||||
name = "slice-group-by"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
|
@ -377,23 +318,3 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
|||
[[package]]
|
||||
name = "xtask"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
|
|
@ -10,8 +10,7 @@ path = "src/main.rs"
|
|||
[dependencies]
|
||||
hbbytecode = { version = "0.1.0", path = "../hbbytecode" }
|
||||
hbvm = { path = "../hbvm", features = ["nightly"] }
|
||||
regalloc2 = "0.10.2"
|
||||
#regalloc2 = { path = "../../regalloc2/" }#git = "https://github.com/jakubDoka/regalloc2", branch = "reuse-allocations", features = [] }
|
||||
regalloc2 = { git = "https://github.com/jakubDoka/regalloc2", branch = "reuse-allocations", features = [] }
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "0.11.5"
|
||||
|
|
221
hblang/README.md
221
hblang/README.md
|
@ -133,7 +133,6 @@ main := fn(): int {
|
|||
b := &a
|
||||
modify(b)
|
||||
drop(a)
|
||||
stack_reclamation_edge_case := 0
|
||||
return *b - 2
|
||||
}
|
||||
|
||||
|
@ -508,226 +507,6 @@ main := fn(): int {
|
|||
if y == width break
|
||||
}
|
||||
}
|
||||
|
||||
width += 1
|
||||
|
||||
loop {
|
||||
if x < height {
|
||||
//t += set_pixel(x, y, height)
|
||||
x += 1
|
||||
i += 1
|
||||
} else {
|
||||
x = 0
|
||||
y += 1
|
||||
if set_pixel(x, y, height) != i return 0
|
||||
if y == width break
|
||||
}
|
||||
}
|
||||
|
||||
width += 1
|
||||
|
||||
loop {
|
||||
if x < height {
|
||||
//t += set_pixel(x, y, height)
|
||||
x += 1
|
||||
i += 1
|
||||
} else {
|
||||
x = 0
|
||||
y += 1
|
||||
if set_pixel(x, y, height) != i return 0
|
||||
if y == width break
|
||||
}
|
||||
}
|
||||
|
||||
width += 1
|
||||
|
||||
loop {
|
||||
if x < height {
|
||||
//t += set_pixel(x, y, height)
|
||||
x += 1
|
||||
i += 1
|
||||
} else {
|
||||
x = 0
|
||||
y += 1
|
||||
if set_pixel(x, y, height) != i return 0
|
||||
if y == width break
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
if x < height {
|
||||
//t += set_pixel(x, y, height)
|
||||
x += 1
|
||||
i += 1
|
||||
} else {
|
||||
x = 0
|
||||
y += 1
|
||||
if set_pixel(x, y, height) != i return 0
|
||||
if y == width break
|
||||
}
|
||||
}
|
||||
|
||||
width += 1
|
||||
|
||||
loop {
|
||||
if x < height {
|
||||
//t += set_pixel(x, y, height)
|
||||
x += 1
|
||||
i += 1
|
||||
} else {
|
||||
x = 0
|
||||
y += 1
|
||||
if set_pixel(x, y, height) != i return 0
|
||||
if y == width break
|
||||
}
|
||||
}
|
||||
|
||||
width += 1
|
||||
|
||||
loop {
|
||||
if x < height {
|
||||
//t += set_pixel(x, y, height)
|
||||
x += 1
|
||||
i += 1
|
||||
} else {
|
||||
x = 0
|
||||
y += 1
|
||||
if set_pixel(x, y, height) != i return 0
|
||||
if y == width break
|
||||
}
|
||||
}
|
||||
|
||||
width += 1
|
||||
|
||||
loop {
|
||||
if x < height {
|
||||
//t += set_pixel(x, y, height)
|
||||
x += 1
|
||||
i += 1
|
||||
} else {
|
||||
x = 0
|
||||
y += 1
|
||||
if set_pixel(x, y, height) != i return 0
|
||||
if y == width break
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
if x < height {
|
||||
//t += set_pixel(x, y, height)
|
||||
x += 1
|
||||
i += 1
|
||||
} else {
|
||||
x = 0
|
||||
y += 1
|
||||
if set_pixel(x, y, height) != i return 0
|
||||
if y == width break
|
||||
}
|
||||
}
|
||||
|
||||
width += 1
|
||||
|
||||
loop {
|
||||
if x < height {
|
||||
//t += set_pixel(x, y, height)
|
||||
x += 1
|
||||
i += 1
|
||||
} else {
|
||||
x = 0
|
||||
y += 1
|
||||
if set_pixel(x, y, height) != i return 0
|
||||
if y == width break
|
||||
}
|
||||
}
|
||||
|
||||
width += 1
|
||||
|
||||
loop {
|
||||
if x < height {
|
||||
//t += set_pixel(x, y, height)
|
||||
x += 1
|
||||
i += 1
|
||||
} else {
|
||||
x = 0
|
||||
y += 1
|
||||
if set_pixel(x, y, height) != i return 0
|
||||
if y == width break
|
||||
}
|
||||
}
|
||||
|
||||
width += 1
|
||||
|
||||
loop {
|
||||
if x < height {
|
||||
//t += set_pixel(x, y, height)
|
||||
x += 1
|
||||
i += 1
|
||||
} else {
|
||||
x = 0
|
||||
y += 1
|
||||
if set_pixel(x, y, height) != i return 0
|
||||
if y == width break
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
if x < height {
|
||||
//t += set_pixel(x, y, height)
|
||||
x += 1
|
||||
i += 1
|
||||
} else {
|
||||
x = 0
|
||||
y += 1
|
||||
if set_pixel(x, y, height) != i return 0
|
||||
if y == width break
|
||||
}
|
||||
}
|
||||
|
||||
width += 1
|
||||
|
||||
loop {
|
||||
if x < height {
|
||||
//t += set_pixel(x, y, height)
|
||||
x += 1
|
||||
i += 1
|
||||
} else {
|
||||
x = 0
|
||||
y += 1
|
||||
if set_pixel(x, y, height) != i return 0
|
||||
if y == width break
|
||||
}
|
||||
}
|
||||
|
||||
width += 1
|
||||
|
||||
loop {
|
||||
if x < height {
|
||||
//t += set_pixel(x, y, height)
|
||||
x += 1
|
||||
i += 1
|
||||
} else {
|
||||
x = 0
|
||||
y += 1
|
||||
if set_pixel(x, y, height) != i return 0
|
||||
if y == width break
|
||||
}
|
||||
}
|
||||
|
||||
width += 1
|
||||
|
||||
loop {
|
||||
if x < height {
|
||||
//t += set_pixel(x, y, height)
|
||||
x += 1
|
||||
i += 1
|
||||
} else {
|
||||
x = 0
|
||||
y += 1
|
||||
if set_pixel(x, y, height) != i return 0
|
||||
if y == width break
|
||||
}
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
```
|
||||
|
|
|
@ -817,7 +817,7 @@ impl Types {
|
|||
match ty.expand() {
|
||||
ty::Kind::Ptr(_) => 8,
|
||||
ty::Kind::Builtin(ty::VOID) => 0,
|
||||
ty::Kind::Builtin(ty::NEVER) => unreachable!(),
|
||||
ty::Kind::Builtin(ty::NEVER) => 0,
|
||||
ty::Kind::Builtin(ty::INT | ty::UINT) => 8,
|
||||
ty::Kind::Builtin(ty::I32 | ty::U32 | ty::TYPE) => 4,
|
||||
ty::Kind::Builtin(ty::I16 | ty::U16) => 2,
|
||||
|
|
|
@ -12,7 +12,7 @@ use {
|
|||
},
|
||||
task,
|
||||
ty::{self},
|
||||
Field, Func, Offset, Reloc, Sig, Size, Struct, SymKey, TypedReloc, Types,
|
||||
Field, Func, HashMap, Offset, Reloc, Sig, Size, Struct, SymKey, TypedReloc, Types,
|
||||
},
|
||||
core::fmt,
|
||||
regalloc2::VReg,
|
||||
|
@ -20,6 +20,7 @@ use {
|
|||
assert_matches::debug_assert_matches,
|
||||
cell::RefCell,
|
||||
collections::hash_map,
|
||||
convert::identity,
|
||||
fmt::{Debug, Display, Write},
|
||||
hash::{Hash as _, Hasher},
|
||||
mem::{self, MaybeUninit},
|
||||
|
@ -32,6 +33,8 @@ const VC_SIZE: usize = 16;
|
|||
const INLINE_ELEMS: usize = VC_SIZE / 2 - 1;
|
||||
const VOID: Nid = 0;
|
||||
const NEVER: Nid = 1;
|
||||
const ENTRY: Nid = 2;
|
||||
const MEM: Nid = 3;
|
||||
|
||||
union Vc {
|
||||
inline: InlineVc,
|
||||
|
@ -702,12 +705,12 @@ impl Nodes {
|
|||
Kind::Call { func } => {
|
||||
write!(out, "call: {func} {} ", self[node].depth)
|
||||
}
|
||||
Kind::Ctrl { index: u32::MAX } => write!(out, "ctrl: {:<5}", "entry"),
|
||||
Kind::Ctrl { index: 0 } => write!(out, "ctrl: {:<5}", "then"),
|
||||
Kind::Ctrl { index: 1 } => write!(out, "ctrl: {:<5}", "else"),
|
||||
Kind::Stck { size } => write!(out, "stck: {size:<5}"),
|
||||
Kind::Load { offset } => write!(out, "load: {offset:<5}"),
|
||||
Kind::Stre { offset } => write!(out, "stre: {offset:<5}"),
|
||||
Kind::Entry => write!(out, "ctrl: {:<5}", "entry"),
|
||||
Kind::Then => write!(out, "ctrl: {:<5}", "then"),
|
||||
Kind::Else => write!(out, "ctrl: {:<5}", "else"),
|
||||
Kind::Stck => write!(out, "stck: "),
|
||||
Kind::Load => write!(out, "load"),
|
||||
Kind::Stre => write!(out, "stre"),
|
||||
_ => unreachable!(),
|
||||
}?;
|
||||
|
||||
|
@ -776,7 +779,7 @@ impl Nodes {
|
|||
Kind::Return => {
|
||||
node = self[node].outputs[0];
|
||||
}
|
||||
Kind::Ctrl { .. } => {
|
||||
Kind::Then | Kind::Else | Kind::Entry => {
|
||||
writeln!(
|
||||
out,
|
||||
"b{node}: {} {} {:?}",
|
||||
|
@ -806,16 +809,7 @@ impl Nodes {
|
|||
}
|
||||
node = cfg_index;
|
||||
}
|
||||
Kind::Arg { .. }
|
||||
| Kind::Stck { .. }
|
||||
| Kind::Load { .. }
|
||||
| Kind::Stre { .. }
|
||||
| Kind::CInt { .. }
|
||||
| Kind::Phi
|
||||
| Kind::BinOp { .. }
|
||||
| Kind::UnOp { .. } => {
|
||||
unreachable!()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1024,9 +1018,10 @@ pub enum Kind {
|
|||
index: u32,
|
||||
},
|
||||
// [ctrl]
|
||||
Ctrl {
|
||||
index: u32,
|
||||
},
|
||||
Entry,
|
||||
Mem,
|
||||
Then,
|
||||
Else,
|
||||
// [ctrl, oper]
|
||||
UnOp {
|
||||
op: lexer::TokenKind,
|
||||
|
@ -1040,22 +1035,21 @@ pub enum Kind {
|
|||
func: ty::Func,
|
||||
},
|
||||
// [ctrl]
|
||||
Stck {
|
||||
size: Size,
|
||||
},
|
||||
Stck,
|
||||
|
||||
// [ctrl, memory]
|
||||
Load {
|
||||
Offset {
|
||||
offset: Offset,
|
||||
},
|
||||
// [ctrl, memory]
|
||||
Stre {
|
||||
offset: Offset,
|
||||
},
|
||||
Load,
|
||||
// [ctrl, memory]
|
||||
Stre,
|
||||
}
|
||||
|
||||
impl Kind {
|
||||
fn is_pinned(&self) -> bool {
|
||||
self.is_cfg() || matches!(self, Self::Phi)
|
||||
self.is_cfg() || matches!(self, Self::Phi | Self::Mem)
|
||||
}
|
||||
|
||||
fn is_cfg(&self) -> bool {
|
||||
|
@ -1064,7 +1058,9 @@ impl Kind {
|
|||
Self::Start
|
||||
| Self::End
|
||||
| Self::Return
|
||||
| Self::Ctrl { .. }
|
||||
| Self::Entry
|
||||
| Self::Then
|
||||
| Self::Else
|
||||
| Self::Arg { .. }
|
||||
| Self::Call { .. }
|
||||
| Self::If
|
||||
|
@ -1078,7 +1074,16 @@ impl Kind {
|
|||
}
|
||||
|
||||
fn starts_basic_block(&self) -> bool {
|
||||
matches!(self, Self::Start | Self::End | Self::Ctrl { .. } | Self::Region | Self::Loop)
|
||||
matches!(
|
||||
self,
|
||||
Self::Start
|
||||
| Self::End
|
||||
| Self::Entry
|
||||
| Self::Then
|
||||
| Self::Else
|
||||
| Self::Region
|
||||
| Self::Loop
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1086,9 +1091,9 @@ impl fmt::Display for Kind {
|
|||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Kind::CInt { value } => write!(f, "#{value}"),
|
||||
Kind::Ctrl { index: u32::MAX } => write!(f, "ctrl[entry]"),
|
||||
Kind::Ctrl { index: 0 } => write!(f, "ctrl[then]"),
|
||||
Kind::Ctrl { index: 1 } => write!(f, "ctrl[else]"),
|
||||
Kind::Entry => write!(f, "ctrl[entry]"),
|
||||
Kind::Then => write!(f, "ctrl[then]"),
|
||||
Kind::Else => write!(f, "ctrl[else]"),
|
||||
Kind::BinOp { op } => write!(f, "{op}"),
|
||||
Kind::Call { func, .. } => write!(f, "call {func}"),
|
||||
slf => write!(f, "{slf:?}"),
|
||||
|
@ -1099,15 +1104,15 @@ impl fmt::Display for Kind {
|
|||
#[derive(Debug, Default, Clone)]
|
||||
//#[repr(align(64))]
|
||||
struct Node {
|
||||
kind: Kind,
|
||||
inputs: Vc,
|
||||
outputs: Vc,
|
||||
kind: Kind,
|
||||
ty: ty::Id,
|
||||
offset: Offset,
|
||||
ralloc_backref: RallocBRef,
|
||||
depth: IDomDepth,
|
||||
lock_rc: LockRc,
|
||||
ty: ty::Id,
|
||||
loop_depth: LoopDepth,
|
||||
offset: Offset,
|
||||
}
|
||||
|
||||
impl Node {
|
||||
|
@ -1149,6 +1154,13 @@ struct ColorMeta {
|
|||
loc: Loc,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
struct MemKey {
|
||||
region: Nid,
|
||||
offset: u32,
|
||||
node: Nid,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct ItemCtx {
|
||||
file: FileId,
|
||||
|
@ -1165,8 +1177,10 @@ struct ItemCtx {
|
|||
filled: Vec<Nid>,
|
||||
delayed_frees: Vec<RallocBRef>,
|
||||
|
||||
stack_size: Size,
|
||||
loops: Vec<Loop>,
|
||||
vars: Vec<Variable>,
|
||||
memories: Vec<MemKey>,
|
||||
ret_relocs: Vec<Reloc>,
|
||||
relocs: Vec<TypedReloc>,
|
||||
jump_relocs: Vec<(Nid, Reloc)>,
|
||||
|
@ -1221,6 +1235,33 @@ struct Pool {
|
|||
cis: Vec<ItemCtx>,
|
||||
}
|
||||
|
||||
struct Regalloc {
|
||||
env: regalloc2::MachineEnv,
|
||||
ctx: regalloc2::Ctx,
|
||||
}
|
||||
|
||||
impl Default for Regalloc {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
env: regalloc2::MachineEnv {
|
||||
preferred_regs_by_class: [
|
||||
(1..13).map(|i| regalloc2::PReg::new(i, regalloc2::RegClass::Int)).collect(),
|
||||
vec![],
|
||||
vec![],
|
||||
],
|
||||
non_preferred_regs_by_class: [
|
||||
(13..64).map(|i| regalloc2::PReg::new(i, regalloc2::RegClass::Int)).collect(),
|
||||
vec![],
|
||||
vec![],
|
||||
],
|
||||
scratch_by_class: Default::default(),
|
||||
fixed_stack_slots: Default::default(),
|
||||
},
|
||||
ctx: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Codegen {
|
||||
pub files: Vec<parser::Ast>,
|
||||
|
@ -1229,10 +1270,62 @@ pub struct Codegen {
|
|||
tys: Types,
|
||||
ci: ItemCtx,
|
||||
pool: Pool,
|
||||
ralloc: Regalloc,
|
||||
errors: RefCell<String>,
|
||||
}
|
||||
|
||||
impl Codegen {
|
||||
fn mem_op(&mut self, region: Nid, offset: Offset, kind: Kind, ty: ty::Id, mut inps: Vc) -> Nid {
|
||||
let size = self.tys.size_of(ty);
|
||||
let insert_start = self
|
||||
.ci
|
||||
.memories
|
||||
.binary_search_by_key(&(region, offset), |k| (k.region, k.offset))
|
||||
.unwrap_or_else(identity);
|
||||
let insert_end = self
|
||||
.ci
|
||||
.memories
|
||||
.binary_search_by(|k| (k.region, k.offset).cmp(&(region, offset + size)))
|
||||
.unwrap_or_else(identity);
|
||||
|
||||
for mk in &self.ci.memories[insert_start..insert_end] {
|
||||
debug_assert_eq!(mk.region, region);
|
||||
debug_assert!(mk.offset >= offset);
|
||||
debug_assert!(mk.offset < offset + size);
|
||||
if matches!(kind, Kind::Load | Kind::Offset { .. })
|
||||
|| !self.ci.nodes.unlock_remove(mk.node)
|
||||
{
|
||||
inps.push(mk.node);
|
||||
}
|
||||
}
|
||||
|
||||
if insert_start == insert_end {
|
||||
inps.push(region);
|
||||
}
|
||||
|
||||
let new_op = self.ci.nodes.new_node(ty, kind, inps);
|
||||
if !matches!(kind, Kind::Offset { .. }) {
|
||||
self.ci.memories.splice(
|
||||
insert_start..insert_end,
|
||||
std::iter::once(MemKey { node: new_op, region, offset }),
|
||||
);
|
||||
self.ci.nodes.lock(new_op);
|
||||
}
|
||||
new_op
|
||||
}
|
||||
|
||||
fn store_mem(&mut self, region: Nid, offset: Offset, value: Nid) -> Nid {
|
||||
self.mem_op(region, offset, Kind::Stre, self.tof(value), [VOID, value].into())
|
||||
}
|
||||
|
||||
fn load_mem(&mut self, region: Nid, offset: Offset, ty: ty::Id) -> Nid {
|
||||
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) {
|
||||
self.find_or_declare(0, 0, None, "main");
|
||||
self.make_func_reachable(0);
|
||||
|
@ -1303,7 +1396,32 @@ impl Codegen {
|
|||
self.ci.nodes.unlock_remove(prev);
|
||||
Some(VOID)
|
||||
}
|
||||
Expr::BinOp { left, op, right } => {
|
||||
Expr::BinOp {
|
||||
left: &Expr::UnOp { pos, op: TokenKind::Mul, val },
|
||||
op: TokenKind::Assign,
|
||||
right,
|
||||
} => {
|
||||
let ctx = Ctx { ty: ctx.ty.map(|ty| self.tys.make_ptr(ty)) };
|
||||
let val = self.expr_ctx(val, ctx)?;
|
||||
let base = match self.tof(val).expand() {
|
||||
ty::Kind::Ptr(p) => self.tys.ptrs[p as usize].base,
|
||||
_ => {
|
||||
self.report(
|
||||
pos,
|
||||
format_args!(
|
||||
"the '{}' can not be dereferneced",
|
||||
self.ty_display(self.tof(val))
|
||||
),
|
||||
);
|
||||
ty::NEVER.into()
|
||||
}
|
||||
};
|
||||
let value = self.expr(right)?;
|
||||
_ = self.assert_ty(right.pos(), self.tof(value), base, true, "stored value");
|
||||
self.store_mem(val, 0, value);
|
||||
Some(VOID)
|
||||
}
|
||||
Expr::BinOp { left, op, right } if op != TokenKind::Assign => {
|
||||
let lhs = self.expr_ctx(left, ctx)?;
|
||||
self.ci.nodes.lock(lhs);
|
||||
let rhs = self.expr_ctx(right, Ctx::default().with_ty(self.tof(lhs)));
|
||||
|
@ -1319,10 +1437,46 @@ impl Codegen {
|
|||
let inps = [VOID, lhs, rhs];
|
||||
Some(self.ci.nodes.new_node(ty::bin_ret(ty, op), Kind::BinOp { op }, inps))
|
||||
}
|
||||
Expr::UnOp { pos: _, op: TokenKind::Band, val: _ } => {
|
||||
todo!()
|
||||
Expr::UnOp { op: TokenKind::Band, val, .. } => {
|
||||
let ctx = Ctx {
|
||||
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 ty = self.tof(val);
|
||||
if !matches!(self.ci.nodes[val].kind, Kind::Stck | Kind::Offset { .. }) {
|
||||
let stck = self.ci.nodes.new_node_nop(ty, Kind::Stck, [VOID, MEM]);
|
||||
self.ci.nodes[stck].offset = self.ci.stack_size;
|
||||
self.ci.stack_size += self.tys.size_of(ty);
|
||||
self.store_mem(stck, 0, val);
|
||||
val = stck;
|
||||
}
|
||||
|
||||
let ptr = self.tys.make_ptr(ty);
|
||||
Some(self.ref_mem(val, 0, ptr))
|
||||
}
|
||||
Expr::UnOp { pos, op, val } => {
|
||||
Expr::UnOp { op: TokenKind::Mul, val, pos } => {
|
||||
let ctx = Ctx { ty: ctx.ty.map(|ty| self.tys.make_ptr(ty)) };
|
||||
let val = self.expr_ctx(val, ctx)?;
|
||||
let base = match self.tof(val).expand() {
|
||||
ty::Kind::Ptr(p) => self.tys.ptrs[p as usize].base,
|
||||
_ => {
|
||||
self.report(
|
||||
pos,
|
||||
format_args!(
|
||||
"the '{}' can not be dereferneced",
|
||||
self.ty_display(self.tof(val))
|
||||
),
|
||||
);
|
||||
ty::NEVER.into()
|
||||
}
|
||||
};
|
||||
Some(self.load_mem(val, 0, base))
|
||||
}
|
||||
Expr::UnOp { pos, op: op @ TokenKind::Sub, val } => {
|
||||
let val = self.expr_ctx(val, ctx)?;
|
||||
if !self.tof(val).is_integer() {
|
||||
self.report(
|
||||
|
@ -1360,11 +1514,11 @@ impl Codegen {
|
|||
self.ci.nodes.lock(el.value);
|
||||
}
|
||||
|
||||
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Ctrl { index: 0 }, [if_node]);
|
||||
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Then, [if_node]);
|
||||
let lcntrl = self.expr(then).map_or(Nid::MAX, |_| self.ci.ctrl);
|
||||
|
||||
let mut then_scope = std::mem::replace(&mut self.ci.vars, else_scope);
|
||||
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Ctrl { index: 1 }, [if_node]);
|
||||
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Else, [if_node]);
|
||||
let rcntrl = if let Some(else_) = else_ {
|
||||
self.expr(else_).map_or(Nid::MAX, |_| self.ci.ctrl)
|
||||
} else {
|
||||
|
@ -1568,7 +1722,10 @@ impl Codegen {
|
|||
VOID
|
||||
};
|
||||
|
||||
let inps = [self.ci.ctrl, value];
|
||||
let mut inps = Vc::from([self.ci.ctrl, value]);
|
||||
for m in self.ci.memories.iter() {
|
||||
inps.push(m.node);
|
||||
}
|
||||
|
||||
let out = &mut String::new();
|
||||
self.report_log_to(pos, "returning here", out);
|
||||
|
@ -1718,7 +1875,10 @@ impl Codegen {
|
|||
debug_assert_eq!(start, VOID);
|
||||
let end = self.ci.nodes.new_node(ty::NEVER, Kind::End, []);
|
||||
debug_assert_eq!(end, NEVER);
|
||||
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Ctrl { index: u32::MAX }, [VOID]);
|
||||
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Entry, [VOID]);
|
||||
debug_assert_eq!(self.ci.ctrl, ENTRY);
|
||||
let mem = self.ci.nodes.new_node(ty::VOID, Kind::Mem, [VOID]);
|
||||
debug_assert_eq!(mem, MEM);
|
||||
|
||||
let Expr::BinOp {
|
||||
left: Expr::Ident { .. },
|
||||
|
@ -1745,6 +1905,9 @@ impl Codegen {
|
|||
self.report(body.pos(), "expected all paths in the fucntion to return");
|
||||
}
|
||||
|
||||
for mem in self.ci.memories.drain(..) {
|
||||
self.ci.nodes.unlock_remove(mem.node);
|
||||
}
|
||||
for var in self.ci.vars.drain(..) {
|
||||
self.ci.nodes.unlock(var.value);
|
||||
}
|
||||
|
@ -1790,7 +1953,7 @@ impl Codegen {
|
|||
|
||||
'_close_function: {
|
||||
let pushed = (saved as i64 + 1) * 8;
|
||||
let stack = 0;
|
||||
let stack = std::mem::take(&mut self.ci.stack_size) as i64;
|
||||
|
||||
write_reloc(&mut self.ci.code, 3, -(pushed + stack), 8);
|
||||
write_reloc(&mut self.ci.code, 3 + 8 + 3, stack, 8);
|
||||
|
@ -1813,153 +1976,216 @@ impl Codegen {
|
|||
let mut nodes = std::mem::take(&mut self.ci.nodes);
|
||||
|
||||
let func = Function::new(&mut nodes, &self.tys, sig);
|
||||
let mut env = regalloc2::MachineEnv {
|
||||
preferred_regs_by_class: [
|
||||
(1..5).map(|i| regalloc2::PReg::new(i, regalloc2::RegClass::Int)).collect(),
|
||||
vec![],
|
||||
vec![],
|
||||
],
|
||||
non_preferred_regs_by_class: [
|
||||
(12..16).map(|i| regalloc2::PReg::new(i, regalloc2::RegClass::Int)).collect(),
|
||||
vec![],
|
||||
vec![],
|
||||
],
|
||||
scratch_by_class: Default::default(),
|
||||
fixed_stack_slots: Default::default(),
|
||||
};
|
||||
if self.ci.call_count != 0 {
|
||||
std::mem::swap(&mut env.preferred_regs_by_class, &mut env.non_preferred_regs_by_class);
|
||||
std::mem::swap(
|
||||
&mut self.ralloc.env.preferred_regs_by_class,
|
||||
&mut self.ralloc.env.non_preferred_regs_by_class,
|
||||
);
|
||||
};
|
||||
let options = regalloc2::RegallocOptions { verbose_log: false, validate_ssa: false };
|
||||
let iters = std::hint::black_box(10000);
|
||||
|
||||
//let mut ctx = regalloc2::Ctx::default();
|
||||
//regalloc2::run_with_ctx(&func, &env, &options, &mut ctx)
|
||||
// .unwrap_or_else(|err| panic!("{err}"));
|
||||
//let now = std::time::Instant::now();
|
||||
//for _ in 0..iters {
|
||||
// regalloc2::run_with_ctx(&func, &env, &options, &mut ctx)
|
||||
// .unwrap_or_else(|err| panic!("{err}"));
|
||||
//}
|
||||
//eprintln!("took: {:?}", now.elapsed().checked_div(iters).unwrap());
|
||||
let options = regalloc2::RegallocOptions {
|
||||
verbose_log: false,
|
||||
validate_ssa: false,
|
||||
algorithm: regalloc2::Algorithm::Ion,
|
||||
};
|
||||
regalloc2::run_with_ctx(&func, &self.ralloc.env, &options, &mut self.ralloc.ctx)
|
||||
.unwrap_or_else(|err| panic!("{err}"));
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
for _ in 0..iters {
|
||||
regalloc2::run(&func, &env, &options).unwrap_or_else(|err| panic!("{err}"));
|
||||
if self.ci.call_count != 0 {
|
||||
std::mem::swap(
|
||||
&mut self.ralloc.env.preferred_regs_by_class,
|
||||
&mut self.ralloc.env.non_preferred_regs_by_class,
|
||||
);
|
||||
};
|
||||
|
||||
let mut saved_regs = HashMap::<u8, u8>::default();
|
||||
let mut atr = |allc: regalloc2::Allocation| {
|
||||
debug_assert!(allc.is_reg());
|
||||
let hvenc = regalloc2::PReg::from_index(allc.index()).hw_enc() as u8;
|
||||
if hvenc <= 12 {
|
||||
return hvenc;
|
||||
}
|
||||
let would_insert = saved_regs.len() as u8 + reg::RET_ADDR + 1;
|
||||
*saved_regs.entry(hvenc).or_insert(would_insert)
|
||||
};
|
||||
|
||||
for (i, block) in func.blocks.iter().enumerate() {
|
||||
let blk = regalloc2::Block(i as _);
|
||||
func.nodes[block.nid].offset = self.ci.code.len() as _;
|
||||
for instr_or_edit in self.ralloc.ctx.output.block_insts_and_edits(&func, blk) {
|
||||
let inst = match instr_or_edit {
|
||||
regalloc2::InstOrEdit::Inst(inst) => inst,
|
||||
regalloc2::InstOrEdit::Edit(®alloc2::Edit::Move { from, to }) => {
|
||||
self.ci.emit(instrs::cp(atr(to), atr(from)));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let nid = func.instrs[inst.index()].nid;
|
||||
if nid == NEVER {
|
||||
continue;
|
||||
};
|
||||
let allocs = self.ralloc.ctx.output.inst_allocs(inst);
|
||||
let node = &func.nodes[nid];
|
||||
match node.kind {
|
||||
Kind::If => {
|
||||
let &[_, cond] = node.inputs.as_slice() else { unreachable!() };
|
||||
if let Kind::BinOp { op } = func.nodes[cond].kind
|
||||
&& let Some((op, swapped)) = op.cond_op(node.ty.is_signed())
|
||||
{
|
||||
let rel = Reloc::new(self.ci.code.len(), 3, 2);
|
||||
self.ci.jump_relocs.push((node.outputs[!swapped as usize], rel));
|
||||
let &[lhs, rhs] = allocs else { unreachable!() };
|
||||
self.ci.emit(op(atr(lhs), atr(rhs), 0));
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
Kind::Loop | Kind::Region => {
|
||||
if node.ralloc_backref as usize != i + 1 {
|
||||
let rel = Reloc::new(self.ci.code.len(), 1, 4);
|
||||
self.ci.jump_relocs.push((nid, rel));
|
||||
self.ci.emit(instrs::jmp(0));
|
||||
}
|
||||
}
|
||||
Kind::Return => {
|
||||
if i != func.blocks.len() - 1 {
|
||||
let rel = Reloc::new(self.ci.code.len(), 1, 4);
|
||||
self.ci.ret_relocs.push(rel);
|
||||
self.ci.emit(instrs::jmp(0));
|
||||
}
|
||||
}
|
||||
Kind::CInt { value } => {
|
||||
self.ci.emit(instrs::li64(atr(allocs[0]), value as _));
|
||||
}
|
||||
Kind::UnOp { op } => {
|
||||
let op = op.unop().expect("TODO: unary operator not supported");
|
||||
let &[dst, oper] = allocs else { unreachable!() };
|
||||
self.ci.emit(op(atr(dst), atr(oper)));
|
||||
}
|
||||
Kind::BinOp { op } => {
|
||||
let &[.., rhs] = node.inputs.as_slice() else { unreachable!() };
|
||||
|
||||
if let Kind::CInt { value } = func.nodes[rhs].kind
|
||||
&& let Some(op) =
|
||||
op.imm_binop(node.ty.is_signed(), func.tys.size_of(node.ty))
|
||||
{
|
||||
let &[dst, lhs] = allocs else { unreachable!() };
|
||||
self.ci.emit(op(atr(dst), atr(lhs), value as _));
|
||||
} else if let Some(op) =
|
||||
op.binop(node.ty.is_signed(), func.tys.size_of(node.ty))
|
||||
{
|
||||
let &[dst, lhs, rhs] = allocs else { unreachable!() };
|
||||
self.ci.emit(op(atr(dst), atr(lhs), atr(rhs)));
|
||||
} else if op.cond_op(node.ty.is_signed()).is_some() {
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
Kind::Call { func } => {
|
||||
self.ci.relocs.push(TypedReloc {
|
||||
target: ty::Kind::Func(func).compress(),
|
||||
reloc: Reloc::new(self.ci.code.len(), 3, 4),
|
||||
});
|
||||
self.ci.emit(instrs::jal(reg::RET_ADDR, reg::ZERO, 0));
|
||||
}
|
||||
Kind::Stck => todo!(),
|
||||
Kind::Load => {
|
||||
let mut region = node.inputs[1];
|
||||
let mut offset = 0;
|
||||
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::ld(atr(dst), base, offset as _, size as _));
|
||||
}
|
||||
Kind::Stre => {
|
||||
let mut region = node.inputs[2];
|
||||
let mut offset = 0;
|
||||
let size = self.tys.size_of(node.ty);
|
||||
debug_assert_eq!(size, 8, "TODO");
|
||||
let (base, offset, src) = loop {
|
||||
match func.nodes[region].kind {
|
||||
Kind::Stck => {
|
||||
break (
|
||||
reg::STACK_PTR,
|
||||
self.ci.stack_size - func.nodes[region].offset + offset
|
||||
- size,
|
||||
allocs[0],
|
||||
);
|
||||
}
|
||||
Kind::Arg { .. } => {
|
||||
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],
|
||||
k => unreachable!("{k:?}"),
|
||||
};
|
||||
};
|
||||
|
||||
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!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
eprintln!("took: {:?}", now.elapsed().checked_div(iters).unwrap());
|
||||
|
||||
0
|
||||
self.ci.nodes = nodes;
|
||||
|
||||
//let mut saved_regs = HashMap::<u8, u8>::default();
|
||||
//let mut atr = |allc: regalloc2::Allocation| {
|
||||
// debug_assert!(allc.is_reg());
|
||||
// let hvenc = regalloc2::PReg::from_index(allc.index()).hw_enc() as u8;
|
||||
// if hvenc <= 12 {
|
||||
// return hvenc;
|
||||
// }
|
||||
// let would_insert = saved_regs.len() as u8 + reg::RET_ADDR + 1;
|
||||
// *saved_regs.entry(hvenc).or_insert(would_insert)
|
||||
//};
|
||||
|
||||
//for (i, block) in func.blocks.iter().enumerate() {
|
||||
// let blk = regalloc2::Block(i as _);
|
||||
// func.nodes[block.nid].offset = self.ci.code.len() as _;
|
||||
// for instr_or_edit in ctx.output.block_insts_and_edits(&func, blk) {
|
||||
// let inst = match instr_or_edit {
|
||||
// regalloc2::InstOrEdit::Inst(inst) => inst,
|
||||
// regalloc2::InstOrEdit::Edit(®alloc2::Edit::Move { from, to }) => {
|
||||
// self.ci.emit(instrs::cp(atr(to), atr(from)));
|
||||
// continue;
|
||||
// }
|
||||
// };
|
||||
|
||||
// let nid = func.instrs[inst.index()].nid;
|
||||
// if nid == NEVER {
|
||||
// continue;
|
||||
// };
|
||||
// let allocs = ctx.output.inst_allocs(inst);
|
||||
// let node = &func.nodes[nid];
|
||||
// match node.kind {
|
||||
// Kind::If => {
|
||||
// let &[_, cond] = node.inputs.as_slice() else { unreachable!() };
|
||||
// if let Kind::BinOp { op } = func.nodes[cond].kind
|
||||
// && let Some((op, swapped)) = op.cond_op(node.ty.is_signed())
|
||||
// {
|
||||
// let rel = Reloc::new(self.ci.code.len(), 3, 2);
|
||||
// self.ci.jump_relocs.push((node.outputs[!swapped as usize], rel));
|
||||
// let &[lhs, rhs] = allocs else { unreachable!() };
|
||||
// self.ci.emit(op(atr(lhs), atr(rhs), 0));
|
||||
// } else {
|
||||
// todo!()
|
||||
// }
|
||||
// }
|
||||
// Kind::Loop | Kind::Region => {
|
||||
// if node.ralloc_backref as usize != i + 1 {
|
||||
// let rel = Reloc::new(self.ci.code.len(), 1, 4);
|
||||
// self.ci.jump_relocs.push((nid, rel));
|
||||
// self.ci.emit(instrs::jmp(0));
|
||||
// }
|
||||
// }
|
||||
// Kind::Return => {
|
||||
// if i != func.blocks.len() - 1 {
|
||||
// let rel = Reloc::new(self.ci.code.len(), 1, 4);
|
||||
// self.ci.ret_relocs.push(rel);
|
||||
// self.ci.emit(instrs::jmp(0));
|
||||
// }
|
||||
// }
|
||||
// Kind::CInt { value } => {
|
||||
// self.ci.emit(instrs::li64(atr(allocs[0]), value as _));
|
||||
// }
|
||||
// Kind::UnOp { op } => {
|
||||
// let op = op.unop().expect("TODO: unary operator not supported");
|
||||
// let &[dst, oper] = allocs else { unreachable!() };
|
||||
// self.ci.emit(op(atr(dst), atr(oper)));
|
||||
// }
|
||||
// Kind::BinOp { op } => {
|
||||
// let &[.., rhs] = node.inputs.as_slice() else { unreachable!() };
|
||||
|
||||
// if let Kind::CInt { value } = func.nodes[rhs].kind
|
||||
// && let Some(op) =
|
||||
// op.imm_binop(node.ty.is_signed(), func.tys.size_of(node.ty))
|
||||
// {
|
||||
// let &[dst, lhs] = allocs else { unreachable!() };
|
||||
// self.ci.emit(op(atr(dst), atr(lhs), value as _));
|
||||
// } else if let Some(op) =
|
||||
// op.binop(node.ty.is_signed(), func.tys.size_of(node.ty))
|
||||
// {
|
||||
// let &[dst, lhs, rhs] = allocs else { unreachable!() };
|
||||
// self.ci.emit(op(atr(dst), atr(lhs), atr(rhs)));
|
||||
// } else if op.cond_op(node.ty.is_signed()).is_some() {
|
||||
// } else {
|
||||
// todo!()
|
||||
// }
|
||||
// }
|
||||
// Kind::Call { func } => {
|
||||
// self.ci.relocs.push(TypedReloc {
|
||||
// target: ty::Kind::Func(func).compress(),
|
||||
// reloc: Reloc::new(self.ci.code.len(), 3, 4),
|
||||
// });
|
||||
// self.ci.emit(instrs::jal(reg::RET_ADDR, reg::ZERO, 0));
|
||||
// }
|
||||
// Kind::Start | Kind::End | Kind::Phi | Kind::Arg { .. } | Kind::Ctrl { .. } => {
|
||||
// unreachable!()
|
||||
// }
|
||||
// Kind::Stck { .. } => todo!(),
|
||||
// Kind::Load { .. } => todo!(),
|
||||
// Kind::Stre { .. } => todo!(),
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
//self.ci.nodes = nodes;
|
||||
|
||||
//saved_regs.len()
|
||||
saved_regs.len()
|
||||
}
|
||||
|
||||
// TODO: sometimes its better to do this in bulk
|
||||
fn ty(&mut self, expr: &Expr) -> ty::Id {
|
||||
match *expr {
|
||||
Expr::UnOp { op: TokenKind::Xor, val, .. } => {
|
||||
let base = self.ty(val);
|
||||
self.tys.make_ptr(base)
|
||||
}
|
||||
Expr::Ident { id, .. } if ident::is_null(id) => id.into(),
|
||||
ref e => {
|
||||
self.report_unhandled_ast(e, "type");
|
||||
|
@ -2287,9 +2513,7 @@ impl<'a> Function<'a> {
|
|||
let node = self.nodes[nid].clone();
|
||||
match node.kind {
|
||||
Kind::Start => {
|
||||
debug_assert_matches!(self.nodes[node.outputs[0]].kind, Kind::Ctrl {
|
||||
index: u32::MAX
|
||||
});
|
||||
debug_assert_matches!(self.nodes[node.outputs[0]].kind, Kind::Entry);
|
||||
self.emit_node(node.outputs[0], VOID)
|
||||
}
|
||||
Kind::End => {}
|
||||
|
@ -2360,12 +2584,12 @@ impl<'a> Function<'a> {
|
|||
self.add_instr(nid, ops);
|
||||
}
|
||||
}
|
||||
Kind::Ctrl { index: u32::MAX } => {
|
||||
Kind::Entry => {
|
||||
self.nodes[nid].ralloc_backref = self.add_block(nid);
|
||||
|
||||
let mut parama = self.tys.parama(self.sig.ret);
|
||||
for (arg, ti) in
|
||||
self.nodes[VOID].clone().outputs.into_iter().skip(1).zip(self.sig.args.range())
|
||||
self.nodes[VOID].clone().outputs.into_iter().skip(2).zip(self.sig.args.range())
|
||||
{
|
||||
let ty = self.tys.args[ti];
|
||||
match self.tys.size_of(ty) {
|
||||
|
@ -2385,7 +2609,7 @@ impl<'a> Function<'a> {
|
|||
self.emit_node(o, nid);
|
||||
}
|
||||
}
|
||||
Kind::Ctrl { .. } => {
|
||||
Kind::Then | Kind::Else => {
|
||||
self.nodes[nid].ralloc_backref = self.add_block(nid);
|
||||
self.bridge(prev, nid);
|
||||
for o in node.outputs.into_iter().rev() {
|
||||
|
@ -2448,10 +2672,46 @@ impl<'a> Function<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
Kind::Phi | Kind::Arg { .. } => {}
|
||||
Kind::Stck { .. } => todo!(),
|
||||
Kind::Load { .. } => todo!(),
|
||||
Kind::Stre { .. } => todo!(),
|
||||
Kind::Offset { .. } => {
|
||||
let mut region = node.inputs[1];
|
||||
let ops = loop {
|
||||
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);
|
||||
}
|
||||
Kind::Stck | Kind::Phi | Kind::Arg { .. } | Kind::Mem => {}
|
||||
Kind::Load => {
|
||||
let mut region = node.inputs[1];
|
||||
let ops = loop {
|
||||
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);
|
||||
}
|
||||
Kind::Stre => {
|
||||
let mut region = node.inputs[2];
|
||||
let ops = loop {
|
||||
match self.nodes[region].kind {
|
||||
Kind::Stck => break vec![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],
|
||||
k => unreachable!("{k:?}"),
|
||||
};
|
||||
};
|
||||
|
||||
self.add_instr(nid, ops);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2506,7 +2766,7 @@ impl<'a> regalloc2::Function for Function<'a> {
|
|||
fn is_branch(&self, insn: regalloc2::Inst) -> bool {
|
||||
matches!(
|
||||
self.nodes[self.instrs[insn.index()].nid].kind,
|
||||
Kind::If | Kind::Ctrl { .. } | Kind::Loop | Kind::Region
|
||||
Kind::If | Kind::Then | Kind::Else | Kind::Entry | Kind::Loop | Kind::Region
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -2531,7 +2791,7 @@ impl<'a> regalloc2::Function for Function<'a> {
|
|||
fn inst_clobbers(&self, insn: regalloc2::Inst) -> regalloc2::PRegSet {
|
||||
if matches!(self.nodes[self.instrs[insn.index()].nid].kind, Kind::Call { .. }) {
|
||||
let mut set = regalloc2::PRegSet::default();
|
||||
for i in 2..12 {
|
||||
for i in 2..13 {
|
||||
set.add(regalloc2::PReg::new(i, regalloc2::RegClass::Int));
|
||||
}
|
||||
set
|
||||
|
@ -2559,13 +2819,17 @@ fn loop_depth(target: Nid, nodes: &mut Nodes) -> LoopDepth {
|
|||
}
|
||||
|
||||
nodes[target].loop_depth = match nodes[target].kind {
|
||||
Kind::Ctrl { .. } | Kind::Call { .. } | Kind::Return | Kind::If => {
|
||||
loop_depth(nodes[target].inputs[0], nodes)
|
||||
Kind::Entry | Kind::Then | Kind::Else | Kind::Call { .. } | Kind::Return | Kind::If => {
|
||||
let dpth = loop_depth(nodes[target].inputs[0], nodes);
|
||||
if nodes[target].loop_depth != 0 {
|
||||
return nodes[target].loop_depth;
|
||||
}
|
||||
dpth
|
||||
}
|
||||
Kind::Region => {
|
||||
let l = loop_depth(nodes[target].inputs[0], nodes);
|
||||
let r = loop_depth(nodes[target].inputs[1], nodes);
|
||||
debug_assert_eq!(r, l);
|
||||
debug_assert_eq!(l, r);
|
||||
l
|
||||
}
|
||||
Kind::Loop => {
|
||||
|
@ -2581,11 +2845,11 @@ fn loop_depth(target: Nid, nodes: &mut Nodes) -> LoopDepth {
|
|||
idom(nodes, cursor)
|
||||
};
|
||||
debug_assert_ne!(next, VOID);
|
||||
if let Kind::Ctrl { index: index @ ..=1 } = nodes[cursor].kind {
|
||||
if matches!(nodes[cursor].kind, Kind::Then | Kind::Else) {
|
||||
let other = *nodes[next]
|
||||
.outputs
|
||||
.iter()
|
||||
.find(|&&n| nodes[n].kind != Kind::Ctrl { index })
|
||||
.find(|&&n| nodes[n].kind != nodes[cursor].kind)
|
||||
.unwrap();
|
||||
if nodes[other].loop_depth == 0 {
|
||||
nodes[other].loop_depth = depth - 1;
|
||||
|
@ -2599,10 +2863,6 @@ fn loop_depth(target: Nid, nodes: &mut Nodes) -> LoopDepth {
|
|||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
if target == 19 {
|
||||
//panic!("{}", nodes[target].loop_depth);
|
||||
}
|
||||
|
||||
nodes[target].loop_depth
|
||||
}
|
||||
|
||||
|
|
|
@ -20,54 +20,54 @@ continue_and_state_change:
|
|||
ADDI64 r254, r254, 40d
|
||||
JALA r0, r31, 0a
|
||||
main:
|
||||
ADDI64 r254, r254, -72d
|
||||
ST r31, r254, 0a, 72h
|
||||
LI64 r12, 0d
|
||||
CP r2, r12
|
||||
ADDI64 r254, r254, -80d
|
||||
ST r31, r254, 0a, 80h
|
||||
LI64 r32, 0d
|
||||
CP r2, r32
|
||||
JAL r31, r0, :multiple_breaks
|
||||
CP r32, r12
|
||||
CP r33, r1
|
||||
CP r33, r32
|
||||
CP r34, r1
|
||||
LI64 r1, 3d
|
||||
JEQ r33, r1, :0
|
||||
JEQ r34, r1, :0
|
||||
LI64 r1, 1d
|
||||
JMP :1
|
||||
0: CP r34, r1
|
||||
LI64 r35, 4d
|
||||
CP r2, r35
|
||||
0: CP r35, r1
|
||||
LI64 r36, 4d
|
||||
CP r2, r36
|
||||
JAL r31, r0, :multiple_breaks
|
||||
CP r36, r35
|
||||
LI64 r37, 10d
|
||||
JEQ r1, r37, :2
|
||||
CP r37, r36
|
||||
LI64 r38, 10d
|
||||
JEQ r1, r38, :2
|
||||
LI64 r1, 2d
|
||||
JMP :1
|
||||
2: CP r2, r32
|
||||
2: CP r2, r33
|
||||
JAL r31, r0, :state_change_in_break
|
||||
CP r38, r1
|
||||
CP r1, r32
|
||||
JEQ r38, r1, :3
|
||||
CP r1, r34
|
||||
CP r39, r1
|
||||
CP r1, r33
|
||||
JEQ r39, r1, :3
|
||||
CP r1, r35
|
||||
JMP :1
|
||||
3: CP r32, r1
|
||||
CP r2, r36
|
||||
3: CP r33, r1
|
||||
CP r2, r37
|
||||
JAL r31, r0, :state_change_in_break
|
||||
JEQ r1, r37, :4
|
||||
CP r1, r36
|
||||
JEQ r1, r38, :4
|
||||
CP r1, r37
|
||||
JMP :1
|
||||
4: CP r2, r37
|
||||
4: CP r2, r38
|
||||
JAL r31, r0, :continue_and_state_change
|
||||
JEQ r1, r37, :5
|
||||
JEQ r1, r38, :5
|
||||
LI64 r1, 5d
|
||||
JMP :1
|
||||
5: CP r2, r34
|
||||
5: CP r2, r35
|
||||
JAL r31, r0, :continue_and_state_change
|
||||
CP r39, r1
|
||||
CP r1, r32
|
||||
JEQ r39, r1, :6
|
||||
CP r40, r1
|
||||
CP r1, r33
|
||||
JEQ r40, r1, :6
|
||||
LI64 r1, 6d
|
||||
JMP :1
|
||||
6: CP r1, r32
|
||||
1: LD r31, r254, 0a, 72h
|
||||
ADDI64 r254, r254, 72d
|
||||
6: CP r1, r33
|
||||
1: LD r31, r254, 0a, 80h
|
||||
ADDI64 r254, r254, 80d
|
||||
JALA r0, r31, 0a
|
||||
multiple_breaks:
|
||||
ADDI64 r254, r254, -24d
|
||||
|
|
31
hblang/tests/son_tests_pointers.txt
Normal file
31
hblang/tests/son_tests_pointers.txt
Normal file
|
@ -0,0 +1,31 @@
|
|||
drop:
|
||||
ADDI64 r254, r254, -8d
|
||||
ST r31, r254, 0a, 8h
|
||||
LD r31, r254, 0a, 8h
|
||||
ADDI64 r254, r254, 8d
|
||||
JALA r0, r31, 0a
|
||||
main:
|
||||
ADDI64 r254, r254, -32d
|
||||
ST r31, r254, 8a, 24h
|
||||
LI64 r32, 1d
|
||||
ST r32, r254, 0a, 8h
|
||||
ADDI64 r2, r254, 0d
|
||||
JAL r31, r0, :modify
|
||||
CP r2, r32
|
||||
JAL r31, r0, :drop
|
||||
LD r33, r254, 0a, 8h
|
||||
ADDI64 r1, r33, -2d
|
||||
LD r31, r254, 8a, 24h
|
||||
ADDI64 r254, r254, 32d
|
||||
JALA r0, r31, 0a
|
||||
modify:
|
||||
ADDI64 r254, r254, -16d
|
||||
ST r31, r254, 0a, 16h
|
||||
LI64 r32, 2d
|
||||
ST r32, r2, 0a, 8h
|
||||
LD r31, r254, 0a, 16h
|
||||
ADDI64 r254, r254, 16d
|
||||
JALA r0, r31, 0a
|
||||
code size: 283
|
||||
ret: 0
|
||||
status: Ok(())
|
|
@ -1,11 +0,0 @@
|
|||
foo := 0;
|
||||
|
||||
.{global, fib, Structa, create_window, WindowID} := @use("pkg.hb")
|
||||
|
||||
main := fn(a: int): int {
|
||||
g := global
|
||||
|
||||
win := create_window()
|
||||
|
||||
return fib(g + Structa.(0, 0).foo)
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
global := 10
|
||||
|
||||
Structa := struct {
|
||||
foo: int,
|
||||
goo: int,
|
||||
}
|
||||
|
||||
create_window := fn(): WindowID {
|
||||
return WindowID.(1, 2)
|
||||
}
|
||||
|
||||
WindowID := struct {
|
||||
host_id: int,
|
||||
window_id: int,
|
||||
}
|
||||
|
||||
fib := fn(n: int): int {
|
||||
return n + 1
|
||||
}
|
Loading…
Reference in a new issue