From 2999a011f54b95008db9a0bae6aeea2e576fbd30 Mon Sep 17 00:00:00 2001 From: mlokr Date: Thu, 19 Sep 2024 13:40:03 +0200 Subject: [PATCH] implementing ableos executable format --- Cargo.lock | 347 +++++ hblang/Cargo.toml | 3 + hblang/src/lib.rs | 76 +- hblang/src/son.rs | 1194 +++++++---------- hblang/tests/codegen_tests_comments.txt | 12 +- hblang/tests/codegen_tests_functions.txt | 32 +- .../tests/codegen_tests_generic_functions.txt | 34 +- hblang/tests/codegen_tests_generic_types.txt | 82 +- hblang/tests/codegen_tests_if_statements.txt | 16 +- hblang/tests/codegen_tests_inline_test.txt | 126 +- ...codegen_tests_integer_inference_issues.txt | 20 +- hblang/tests/codegen_tests_loops.txt | 16 +- hblang/tests/codegen_tests_pointers.txt | 14 +- hblang/tests/codegen_tests_request_page.txt | 18 +- .../tests/codegen_tests_struct_patterns.txt | 80 +- ...sts_struct_return_from_module_function.txt | 26 +- hblang/tests/codegen_tests_structs.txt | 20 +- .../codegen_tests_writing_into_string.txt | 14 +- 18 files changed, 1188 insertions(+), 942 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 59a7e4e..805b971 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,120 @@ # 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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" + +[[package]] +name = "env_filter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", +] + [[package]] name = "hbbytecode" version = "0.1.0" @@ -14,7 +128,10 @@ version = "0.1.0" name = "hblang" version = "0.1.0" dependencies = [ + "env_logger", "hbvm", + "log", + "regalloc2", ] [[package]] @@ -32,12 +149,36 @@ dependencies = [ "memmap2", ] +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "libc" version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + [[package]] name = "memmap2" version = "0.9.5" @@ -47,6 +188,212 @@ 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" +dependencies = [ + "hashbrown", + "log", + "rustc-hash", + "slice-group-by", + "smallvec", +] + +[[package]] +name = "regex" +version = "1.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "rustc-hash" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +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", +] diff --git a/hblang/Cargo.toml b/hblang/Cargo.toml index ee487b4..5dab6dc 100644 --- a/hblang/Cargo.toml +++ b/hblang/Cargo.toml @@ -8,4 +8,7 @@ name = "hbc" path = "src/main.rs" [dependencies] +env_logger = "0.11.5" hbvm = { path = "../hbvm", features = ["nightly"] } +log = "0.4.22" +regalloc2 = { version = "0.10.2", features = ["trace-log"] } diff --git a/hblang/src/lib.rs b/hblang/src/lib.rs index e65c930..4bc6835 100644 --- a/hblang/src/lib.rs +++ b/hblang/src/lib.rs @@ -601,6 +601,19 @@ impl ParamAlloc { } } +#[repr(packed)] +#[allow(dead_code)] +struct AbleOsExecutableHeader { + magic_number: [u8; 3], + executable_version: u32, + + code_length: u64, + data_length: u64, + debug_length: u64, + config_length: u64, + metadata_length: u64, +} + #[derive(Default)] struct Types { syms: HashMap, @@ -613,15 +626,24 @@ struct Types { arrays: Vec, } +const HEADER_SIZE: usize = std::mem::size_of::(); + impl Types { fn assemble(&mut self, to: &mut Vec) { + to.extend([0u8; HEADER_SIZE]); + emit(to, instrs::jal(reg::RET_ADDR, reg::ZERO, 0)); emit(to, instrs::tx()); - self.dump_reachable(0, to); - Reloc::new(0, 3, 4).apply_jump(to, self.funcs[0].offset, 0); + let exe = self.dump_reachable(0, to); + Reloc::new(HEADER_SIZE, 3, 4).apply_jump(to, self.funcs[0].offset, 0); + + unsafe { *to.as_mut_ptr().cast::() = exe } } - fn dump_reachable(&mut self, from: ty::Func, to: &mut Vec) { + fn dump_reachable(&mut self, from: ty::Func, to: &mut Vec) -> AbleOsExecutableHeader { + let mut used_funcs = vec![]; + let mut used_globals = vec![]; + let mut frontier = vec![ty::Kind::Func(from).compress()]; while let Some(itm) = frontier.pop() { @@ -631,8 +653,8 @@ impl Types { if task::is_done(fuc.offset) { continue; } - fuc.offset = to.len() as _; - to.extend(&fuc.code); + fuc.offset = 0; + used_funcs.push(func); frontier.extend(fuc.relocs.iter().map(|r| r.target)); } ty::Kind::Global(glob) => { @@ -640,18 +662,31 @@ impl Types { if task::is_done(glb.offset) { continue; } - glb.offset = to.len() as _; - to.extend(&glb.data); + glb.offset = 0; + used_globals.push(glob); } _ => unreachable!(), } } - for fuc in &self.funcs { - if !task::is_done(fuc.offset) { - continue; - } + for &func in &used_funcs { + let fuc = &mut self.funcs[func as usize]; + fuc.offset = to.len() as _; + to.extend(&fuc.code); + } + let code_length = to.len(); + + for &global in &used_globals { + let global = &mut self.globals[global as usize]; + global.offset = to.len() as _; + to.extend(&global.data); + } + + let data_length = to.len() - code_length; + + for func in used_funcs { + let fuc = &self.funcs[func as usize]; for rel in &fuc.relocs { let offset = match rel.target.expand() { ty::Kind::Func(fun) => self.funcs[fun as usize].offset, @@ -661,6 +696,16 @@ impl Types { rel.reloc.apply_jump(to, offset, fuc.offset); } } + + AbleOsExecutableHeader { + magic_number: [0x15, 0x91, 0xD2], + executable_version: 0, + code_length: (code_length - HEADER_SIZE) as _, + data_length: data_length as _, + debug_length: 0, + config_length: 0, + metadata_length: 0, + } } pub fn disasm( @@ -892,7 +937,10 @@ fn disasm( *binary = prev; } - '_dump: for (&off, &(name, len, kind)) in functions.iter() { + let mut ordered = functions.iter().collect::>(); + ordered.sort_unstable_by_key(|(_, (name, _, _))| name); + + '_dump: for (&off, &(name, len, kind)) in ordered { if matches!(kind, DisasmItem::Global) { continue; } @@ -1336,7 +1384,7 @@ fn test_run_vm(out: &[u8], output: &mut String) { let mut vm = unsafe { hbvm::Vm::<_, { 1024 * 100 }>::new( LoggedMem::default(), - hbvm::mem::Address::new(out.as_ptr() as u64), + hbvm::mem::Address::new(out.as_ptr() as u64).wrapping_add(HEADER_SIZE), ) }; @@ -1375,7 +1423,7 @@ fn test_run_vm(out: &[u8], output: &mut String) { } }; - writeln!(output, "code size: {}", out.len()).unwrap(); + writeln!(output, "code size: {}", out.len() - HEADER_SIZE).unwrap(); writeln!(output, "ret: {:?}", vm.read_reg(1).0).unwrap(); writeln!(output, "status: {:?}", stat).unwrap(); } diff --git a/hblang/src/son.rs b/hblang/src/son.rs index 938b6a7..c4e7d2a 100644 --- a/hblang/src/son.rs +++ b/hblang/src/son.rs @@ -2,7 +2,7 @@ use { crate::{ ident::{self, Ident}, - instrs::{self, jal}, + instrs::{self}, lexer::{self, TokenKind}, log, parser::{ @@ -10,9 +10,12 @@ use { idfl::{self}, CommentOr, Expr, ExprRef, FileId, Pos, StructField, }, - task, ty, Field, Func, Reloc, Sig, Struct, SymKey, TypedReloc, Types, + task, + ty::{self}, + Field, Func, HashMap, Reloc, Sig, Struct, SymKey, TypedReloc, Types, }, core::fmt, + regalloc2::VReg, std::{ cell::RefCell, collections::hash_map, @@ -24,21 +27,6 @@ use { }, }; -macro_rules! node_loc { - ($self:expr, $value:expr) => { - $self.ci.colors[$self.ci.nodes[$value].color as usize - 1].loc - //$self.ci.colors[dbg!(&$self.ci.nodes[$value]).color as usize - 1].loc - }; -} - -struct Drom(&'static str); - -impl Drop for Drom { - fn drop(&mut self) { - log::inf!("{}", self.0); - } -} - const VC_SIZE: usize = 16; const INLINE_ELEMS: usize = VC_SIZE / 2 - 1; const VOID: Nid = 0; @@ -84,10 +72,6 @@ impl Vc { } } - fn find(&self, needle: Nid) -> usize { - self.iter().position(|&n| n == needle).unwrap() - } - fn len_mut(&mut self) -> &mut Nid { unsafe { if self.is_inline() { @@ -321,20 +305,6 @@ impl BitSet { self.data[data_idx] |= 1 << sub_idx; prev == 0 } - - fn unset(&mut self, idx: Nid) { - let idx = idx as usize; - let data_idx = idx / Self::ELEM_SIZE; - let sub_idx = idx % Self::ELEM_SIZE; - self.data[data_idx] &= !(1 << sub_idx); - } - - fn get(&self, idx: Nid) -> bool { - let idx = idx as usize; - let data_idx = idx / Self::ELEM_SIZE; - let sub_idx = idx % Self::ELEM_SIZE; - self.data[data_idx] & (1 << sub_idx) == 1 - } } type Nid = u16; @@ -346,70 +316,6 @@ pub mod reg { pub const RET_ADDR: Reg = 31; pub type Reg = u8; - - #[derive(Default)] - struct AllocMeta { - rc: u16, - depth: u16, - #[cfg(debug_assertions)] - allocated_at: Option, - } - - struct Metas([AllocMeta; 256]); - - impl Default for Metas { - fn default() -> Self { - Metas(std::array::from_fn(|_| AllocMeta::default())) - } - } - - #[derive(Default)] - pub struct Alloc { - meta: Metas, - free: Vec, - max_used: Reg, - } - - impl Alloc { - pub fn init(&mut self) { - self.free.clear(); - self.free.extend((32..=253).rev()); - self.max_used = RET_ADDR; - } - - pub fn allocate(&mut self, depth: u16) -> Reg { - let reg = self.free.pop().expect("TODO: we need to spill"); - self.max_used = self.max_used.max(reg); - self.meta.0[reg as usize] = AllocMeta { - depth, - rc: 1, - #[cfg(debug_assertions)] - allocated_at: Some(std::backtrace::Backtrace::capture()), - }; - reg - } - - pub fn dup(&mut self, reg: Reg) { - self.meta.0[reg as usize].rc += 1; - } - - pub fn free(&mut self, reg: Reg) { - if self.meta.0[reg as usize].rc == 1 { - self.free.push(reg); - self.meta.0[reg as usize] = Default::default(); - } else { - self.meta.0[reg as usize].rc -= 1; - } - } - - pub fn pushed_size(&self) -> usize { - ((self.max_used as usize).saturating_sub(RET_ADDR as usize) + 1) * 8 - } - - pub fn mark_leaked(&mut self, reg: u8) { - self.meta.0[reg as usize].rc = u16::MAX; - } - } } struct LookupEntry { @@ -480,7 +386,8 @@ impl Nodes { fn new_node_nop(&mut self, ty: impl Into, kind: Kind, inps: impl Into) -> Nid { let ty = ty.into(); - let node = Node { inputs: inps.into(), kind, ty, ..Default::default() }; + let node = + Node { ralloc_backref: u16::MAX, inputs: inps.into(), kind, ty, ..Default::default() }; let mut lookup_meta = None; if !node.is_lazy_phi() { @@ -784,7 +691,7 @@ impl Nodes { #[allow(clippy::format_in_format_args)] fn basic_blocks_instr(&mut self, out: &mut String, node: Nid) -> std::fmt::Result { if self[node].kind != Kind::Loop && self[node].kind != Kind::Region { - write!(out, " {node:>2}-c{:>2}: ", self[node].color)?; + write!(out, " {node:>2}-c{:>2}: ", self[node].ralloc_backref)?; } match self[node].kind { Kind::Start => unreachable!(), @@ -1064,6 +971,10 @@ impl Nodes { dominated = idom(self, dominated); } } + + fn iter_mut(&mut self) -> impl Iterator { + self.values.iter_mut().flat_map(Result::as_mut) + } } impl ops::Index for Nodes { @@ -1110,29 +1021,29 @@ pub enum Kind { impl Kind { fn is_pinned(&self) -> bool { - self.is_cfg() || matches!(self, Kind::Phi) + self.is_cfg() || matches!(self, Self::Phi) } fn is_cfg(&self) -> bool { matches!( self, - Kind::Start - | Kind::End - | Kind::Return - | Kind::Tuple { .. } - | Kind::Call { .. } - | Kind::If - | Kind::Region - | Kind::Loop + Self::Start + | Self::End + | Self::Return + | Self::Tuple { .. } + | Self::Call { .. } + | Self::If + | Self::Region + | Self::Loop ) } fn ends_basic_block(&self) -> bool { - matches!(self, Kind::Return | Kind::If | Kind::End) + matches!(self, Self::Return | Self::If | Self::End) } fn starts_basic_block(&self) -> bool { - matches!(self, Kind::Start | Kind::End | Kind::Tuple { .. } | Kind::Region | Kind::Loop) + matches!(self, Self::Start | Self::End | Self::Tuple { .. } | Self::Region | Self::Loop) } } @@ -1154,7 +1065,7 @@ struct Node { inputs: Vc, outputs: Vc, kind: Kind, - color: Color, + ralloc_backref: RallocBRef, depth: IDomDepth, lock_rc: LockRc, ty: ty::Id, @@ -1178,7 +1089,7 @@ impl Node { type Offset = u32; type Size = u32; -type Color = u16; +type RallocBRef = u16; type LoopDepth = u16; type CallCount = u16; type LockRc = u16; @@ -1215,14 +1126,12 @@ struct ItemCtx { ctrl: Nid, loop_depth: LoopDepth, - colors: Vec, call_count: u16, filled: Vec, - delayed_frees: Vec, + delayed_frees: Vec, loops: Vec, vars: Vec, - regs: reg::Alloc, ret_relocs: Vec, relocs: Vec, jump_relocs: Vec<(Nid, Reloc)>, @@ -1230,81 +1139,9 @@ struct ItemCtx { } impl ItemCtx { - fn next_color(&mut self) -> Color { - self.colors.push(ColorMeta { rc: 0, depth: self.loop_depth, loc: Default::default() }); - self.colors.len() as _ // leave out 0 (sentinel) - } - - fn set_next_color(&mut self, node: Nid) -> Color { - let color = self.next_color(); - self.set_color(node, color); - color - } - - fn set_color(&mut self, node: Nid, color: Color) { - if self.nodes[node].color == color { - return; - } - if self.nodes[node].color != 0 { - self.colors[self.nodes[node].color as usize - 1].rc -= 1; - } - self.nodes[node].color = color; - self.colors[color as usize - 1].rc += 1; - } - - fn recolor(&mut self, node: Nid, from: Color, to: Color) { - if from == to { - return; - } - - if self.nodes[node].color != from { - return; - } - - self.set_color(node, to); - - for i in 0..self.nodes[node].inputs.len() { - self.recolor(self.nodes[node].inputs[i], from, to); - } - } - - fn check_color_integrity(&self) { - let node_count = self - .nodes - .values - .iter() - .filter(|v| { - matches!( - v, - Ok(Node { - kind: Kind::BinOp { .. } - | Kind::Call { .. } - | Kind::Phi - | Kind::CInt { .. }, - color: 1.., - .. - }) - ) || matches!( - v, - Ok(Node { kind: Kind::Tuple { index: 1.. }, - color: 1.., - inputs, .. }) if inputs.first() == Some(&VOID) - ) - }) - .count(); - let color_count = self.colors.iter().map(|c| c.rc).sum::(); - debug_assert_eq!(node_count, color_count as usize); - } - fn emit(&mut self, instr: (usize, [u8; instrs::MAX_SIZE])) { crate::emit(&mut self.code, instr); } - - fn free_loc(&mut self, loc: impl Into>) { - if let Some(loc) = loc.into() { - self.regs.free(loc.reg); - } - } } fn write_reloc(doce: &mut [u8], offset: usize, value: i64, size: u16) { @@ -1364,7 +1201,7 @@ impl Codegen { pub fn generate(&mut self) { self.find_or_declare(0, 0, None, "main"); self.make_func_reachable(0); - self.complete_call_graph_low(); + self.complete_call_graph(); } fn make_func_reachable(&mut self, func: ty::Func) { @@ -1803,10 +1640,6 @@ impl Codegen { } fn complete_call_graph(&mut self) { - self.complete_call_graph_low(); - } - - fn complete_call_graph_low(&mut self) { while self.ci.task_base < self.tasks.len() && let Some(task_slot) = self.tasks.pop() { @@ -1879,53 +1712,13 @@ impl Codegen { self.ci.emit(instrs::st(reg::RET_ADDR, reg::STACK_PTR, 0, 0)); } - self.ci.regs.init(); - self.ci.nodes.basic_blocks(); - self.ci.nodes.visited.clear(self.ci.nodes.values.len()); - self.color_node(NEVER); - - let call_count = self.ci.call_count; - let mut parama = self.tys.parama(sig.ret); - '_color_args: { - for (var, ti) in orig_vars.iter().zip(sig.args.range()) { - let ty = self.tys.args[ti]; - let mut col = self.ci.nodes[var.value].color; - if col == 0 { - col = self.ci.set_next_color(var.value); - } - match self.tys.size_of(ty) { - 0 => continue, - 1..=8 => { - let loc = Loc { reg: parama.next() }; - let slot = &mut self.ci.colors[col as usize - 1].loc; - - if *slot != Loc::default() { - self.emit_pass_low(loc, var.value); - } else if check_no_calls(var.value, &mut self.ci.nodes) { - *slot = loc; - } else { - *slot = Loc { reg: self.ci.regs.allocate(0) }; - self.emit_pass_low(loc, var.value); - } - } - _ => todo!(), - } - } - } - //self.ci.nodes.graphviz(); - #[cfg(debug_assertions)] - { - self.ci.check_color_integrity(); - } - self.ci.vars = orig_vars; - self.ci.call_count = call_count; self.ci.nodes.visited.clear(self.ci.nodes.values.len()); - self.emit_node(VOID, VOID); + let saved = self.emit_body(sig); self.ci.vars.clear(); if let Some(last_ret) = self.ci.ret_relocs.last() @@ -1947,7 +1740,7 @@ impl Codegen { } '_close_function: { - let pushed = self.ci.regs.pushed_size() as i64; + let pushed = (saved as i64 + 1) * 8; let stack = 0; write_reloc(&mut self.ci.code, 3, -(pushed + stack), 8); @@ -1963,356 +1756,539 @@ impl Codegen { self.tys.funcs[id as usize].code.append(&mut self.ci.code); self.tys.funcs[id as usize].relocs.append(&mut self.ci.relocs); self.ci.nodes.clear(); - self.ci.colors.clear(); self.ci.filled.clear(); self.pool.cis.push(std::mem::replace(&mut self.ci, prev_ci)); } - fn color_node(&mut self, ctrl: Nid) -> Option { - if !self.ci.nodes.visited.set(ctrl) { - return None; + fn emit_body(&mut self, sig: Sig) -> usize { + // FIXME: make this more efficient (allocated with arena) + + #[derive(Debug)] + struct Block { + nid: Nid, + preds: Vec, + succs: Vec, + instrs: regalloc2::InstRange, + params: Vec, + branch_blockparams: Vec, } - let node = self.ci.nodes[ctrl].clone(); - match node.kind { - Kind::Start => None, - Kind::End => { - for &i in node.inputs.iter() { - self.color_node(i); - } - None - } - Kind::If => { - let &[pred, _] = node.inputs.as_slice() else { unreachable!() }; - self.color_node(pred); - None - } - Kind::Region => { - for o in node.outputs { - self.color_node(o); - } - self.color_node(node.inputs[0]); - self.color_node(node.inputs[1]); - None - } - Kind::Loop => { - self.color_node(node.inputs[1]); - for o in node.outputs { - self.color_node(o); - } - self.color_node(node.inputs[0]); - None - } - Kind::Return => { - if node.inputs[1] != VOID { - let col = self.ci.set_next_color(node.inputs[1]); - if check_no_calls(node.inputs[1], &mut self.ci.nodes) { - self.ci.colors[col as usize - 1].loc = Loc { reg: 1 }; - } - } + #[derive(Debug)] + struct Instr { + nid: Nid, + ops: Vec, + } - self.color_node(node.inputs[0]); - None - } - Kind::CInt { .. } => { - if node.color == 0 && node.lock_rc as usize != node.outputs.len() { - self.ci.set_next_color(ctrl); - } + struct Function<'a> { + sig: Sig, + nodes: &'a mut Nodes, + tys: &'a Types, + blocks: Vec, + instrs: Vec, + } - None - } - Kind::Phi => { - if node.color == 0 { - self.ci.set_next_color(ctrl); - } + impl Debug for Function<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for (i, block) in self.blocks.iter().enumerate() { + writeln!(f, "sb{i}{:?}-{:?}:", block.params, block.preds)?; - fn is_tangled_phy( - target: Nid, - phi: Nid, - min_idepth: IDomDepth, - nodes: &mut Nodes, - ) -> bool { - for i in nodes[target].inputs.clone() { - if nodes.is_cfg(i) { - continue; - } - - if idepth(nodes, i) < min_idepth { - continue; - } - - if i == phi { - continue; - } - - if nodes[i].kind == Kind::Phi && nodes[i].inputs[0] == nodes[phi].inputs[0] - { - return true; - } - - if is_tangled_phy(i, phi, min_idepth, nodes) { - return true; - } + for inst in block.instrs.iter() { + let instr = &self.instrs[inst.index()]; + writeln!( + f, + "{}: i{:?}:{:?}", + inst.index(), + self.nodes[instr.nid].kind, + instr.ops + )?; } - false + writeln!(f, "eb{i}{:?}-{:?}:", block.branch_blockparams, block.succs)?; } + Ok(()) + } + } - let is_region = self.ci.nodes[node.inputs[0]].kind == Kind::Region; - let is_independent_phy = is_region - || !is_tangled_phy( - ctrl, - ctrl, - idepth(&mut self.ci.nodes, node.inputs[0]), - &mut self.ci.nodes, + impl<'a> Function<'a> { + fn new(nodes: &'a mut Nodes, tys: &'a Types, sig: Sig) -> Self { + let mut s = Self { + nodes, + tys, + sig, + blocks: Default::default(), + instrs: Default::default(), + }; + s.nodes.visited.clear(s.nodes.values.len()); + s.emit_node(VOID, VOID); + s.add_block(0); + s.blocks.pop(); + s + } + + fn add_block(&mut self, nid: Nid) -> RallocBRef { + if let Some(prev) = self.blocks.last_mut() { + prev.instrs = regalloc2::InstRange::new( + prev.instrs.first(), + regalloc2::Inst::new(self.instrs.len()), ); - let &[_, l, r] = node.inputs.as_slice() else { unreachable!() }; - if is_independent_phy && is_last_branch_use(l, ctrl, &mut self.ci.nodes) { - self.ci.set_color(l, self.ci.nodes[ctrl].color); - } - if is_independent_phy && is_last_branch_use(r, ctrl, &mut self.ci.nodes) { - self.ci.set_color(r, self.ci.nodes[ctrl].color); } - None + self.blocks.push(Block { + nid, + preds: Default::default(), + succs: Default::default(), + instrs: regalloc2::InstRange::new( + regalloc2::Inst::new(self.instrs.len()), + regalloc2::Inst::new(self.instrs.len() + 1), + ), + params: Default::default(), + branch_blockparams: Default::default(), + }); + self.blocks.len() as RallocBRef - 1 } - Kind::Tuple { index } => { - if (self.ci.nodes[node.inputs[0]].kind == Kind::Start && index == 0) - || (self.ci.nodes[node.inputs[0]].kind == Kind::If && index < 2) - { - for o in node.outputs { - self.color_node(o); + + fn add_instr(&mut self, nid: Nid, ops: Vec) { + self.instrs.push(Instr { nid, ops }); + } + + fn urg(&mut self, nid: Nid) -> regalloc2::Operand { + regalloc2::Operand::reg_use(self.rg(nid)) + } + + fn def_nid(&mut self, _nid: Nid) {} + + fn drg(&mut self, nid: Nid) -> regalloc2::Operand { + self.def_nid(nid); + regalloc2::Operand::reg_def(self.rg(nid)) + } + + fn rg(&self, nid: Nid) -> VReg { + regalloc2::VReg::new(nid as _, regalloc2::RegClass::Int) + } + + fn emit_node(&mut self, nid: Nid, prev: Nid) { + if matches!(self.nodes[nid].kind, Kind::Region | Kind::Loop) { + let prev_bref = self.nodes[prev].ralloc_backref; + let node = self.nodes[nid].clone(); + + let idx = 1 + node.inputs.iter().position(|&i| i == prev).unwrap(); + + for ph in node.outputs { + if self.nodes[ph].kind != Kind::Phi { + continue; + } + + let rg = self.rg(self.nodes[ph].inputs[idx]); + self.blocks[prev_bref as usize].branch_blockparams.push(rg); } - self.color_node(node.inputs[0]); + + self.add_instr(nid, vec![]); + + match (self.nodes[nid].kind, self.nodes.visited.set(nid)) { + (Kind::Loop, false) => { + for i in node.inputs { + self.bridge(i, nid); + } + return; + } + (Kind::Region, true) => return, + _ => {} + } + } else if !self.nodes.visited.set(nid) { + return; } - None - } - Kind::BinOp { .. } => { - let can_optimize = matches!(node.kind, Kind::BinOp { op } if op.cond_op(false).is_some()) - && matches!(node.outputs.as_slice(), &[stmt] if self.ci.nodes[stmt].kind == Kind::If); + let node = self.nodes[nid].clone(); + match node.kind { + Kind::Start => self.emit_node(node.outputs[0], VOID), + Kind::End => {} + Kind::If => { + self.nodes[nid].ralloc_backref = self.nodes[prev].ralloc_backref; - if node.color == 0 && !can_optimize { - self.ci.set_next_color(ctrl); - } + let &[_, cond] = node.inputs.as_slice() else { unreachable!() }; + let &[mut then, mut else_] = node.outputs.as_slice() else { + unreachable!() + }; - let &[_, lhs, rhs] = node.inputs.as_slice() else { unreachable!() }; + if let Kind::BinOp { op } = self.nodes[cond].kind + && let Some((_, swapped)) = op.cond_op(node.ty.is_signed()) + { + if swapped { + std::mem::swap(&mut then, &mut else_); + } + let &[_, lhs, rhs] = self.nodes[cond].inputs.as_slice() else { + unreachable!() + }; + let ops = vec![self.urg(lhs), self.urg(rhs)]; + self.add_instr(nid, ops); + } else { + todo!() + } - if !self.ci.nodes.is_const(rhs) || can_optimize { - self.color_node(rhs); - } else { - self.ci.nodes[rhs].lock_rc += 1; - } - - self.color_node(lhs); - - None - } - Kind::UnOp { .. } => { - if node.color == 0 { - self.ci.set_next_color(ctrl); - } - self.color_node(node.inputs[1]); - None - } - Kind::Call { func } => { - if node.color == 0 { - self.ci.set_next_color(ctrl); - } - - let func = self.tys.funcs[func as usize].sig.unwrap(); - let mut parama = self.tys.parama(func.ret); - for (&i, ti) in node.inputs[1..].iter().zip(func.args.range()) { - let ty = self.tys.args[ti]; - match self.tys.size_of(ty) { - 0 => continue, - 1..=8 => { - let col = self.ci.set_next_color(i); - let loc = Loc { reg: parama.next() }; - if check_no_calls(i, &mut self.ci.nodes) { - self.ci.colors[col as usize - 1].loc = loc; + self.emit_node(then, nid); + self.emit_node(else_, nid); + } + Kind::Region | Kind::Loop => { + self.nodes[nid].ralloc_backref = self.add_block(nid); + if node.kind == Kind::Region { + for i in node.inputs { + self.bridge(i, nid); + } + } + let mut block = vec![]; + for ph in node.outputs.clone() { + if self.nodes[ph].kind != Kind::Phi { + continue; + } + self.def_nid(ph); + block.push(self.rg(ph)); + } + self.blocks[self.nodes[nid].ralloc_backref as usize].params = block; + for o in node.outputs.into_iter().rev() { + self.emit_node(o, nid); + } + } + Kind::Return => { + let ops = if node.inputs[1] != VOID { + vec![regalloc2::Operand::reg_fixed_use( + self.rg(node.inputs[1]), + regalloc2::PReg::new(1, regalloc2::RegClass::Int), + )] + } else { + vec![] + }; + self.add_instr(nid, ops); + self.emit_node(node.outputs[0], nid); + } + Kind::CInt { .. } => { + let ops = vec![self.drg(nid)]; + self.add_instr(nid, ops); + } + Kind::Phi => {} + Kind::Tuple { index } => { + let is_start = self.nodes[node.inputs[0]].kind == Kind::Start && index == 0; + if is_start || (self.nodes[node.inputs[0]].kind == Kind::If && index < 2) { + self.nodes[nid].ralloc_backref = self.add_block(nid); + self.bridge(prev, nid); + + if is_start { + 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()) + { + let ty = self.tys.args[ti]; + match self.tys.size_of(ty) { + 0 => continue, + 1..=8 => { + self.def_nid(arg); + self.add_instr(NEVER, vec![ + regalloc2::Operand::reg_fixed_def( + self.rg(arg), + regalloc2::PReg::new( + parama.next() as _, + regalloc2::RegClass::Int, + ), + ), + ]); + } + _ => todo!(), + } + } + } + + for o in node.outputs.into_iter().rev() { + self.emit_node(o, nid); + } + } else { + todo!(); + } + } + Kind::BinOp { op } => { + let &[_, lhs, rhs] = node.inputs.as_slice() else { unreachable!() }; + + let ops = if let Kind::CInt { .. } = self.nodes[rhs].kind + && op.imm_binop(node.ty.is_signed(), 8).is_some() + { + vec![self.drg(nid), self.urg(lhs)] + } else if op.binop(node.ty.is_signed(), 8).is_some() { + vec![self.drg(nid), self.urg(lhs), self.urg(rhs)] + } else if op.cond_op(node.ty.is_signed()).is_some() { + return; + } else { + todo!("{op}") + }; + self.add_instr(nid, ops); + } + Kind::UnOp { .. } => { + let ops = vec![self.drg(nid), self.urg(node.inputs[1])]; + self.add_instr(nid, ops); + } + Kind::Call { func } => { + self.nodes[nid].ralloc_backref = self.nodes[prev].ralloc_backref; + let mut ops = vec![]; + + let fuc = self.tys.funcs[func as usize].sig.unwrap(); + if self.tys.size_of(fuc.ret) != 0 { + self.def_nid(nid); + ops.push(regalloc2::Operand::reg_fixed_def( + self.rg(nid), + regalloc2::PReg::new(1, regalloc2::RegClass::Int), + )); + } + + let mut parama = self.tys.parama(fuc.ret); + for (&i, ti) in node.inputs[1..].iter().zip(fuc.args.range()) { + let ty = self.tys.args[ti]; + match self.tys.size_of(ty) { + 0 => continue, + 1..=8 => { + ops.push(regalloc2::Operand::reg_fixed_use( + self.rg(i), + regalloc2::PReg::new( + parama.next() as _, + regalloc2::RegClass::Int, + ), + )); + } + _ => todo!(), + } + } + + self.add_instr(nid, ops); + + for o in node.outputs.into_iter().rev() { + if self.nodes[o].inputs[0] == nid { + self.emit_node(o, nid); } } - _ => todo!(), } } + } - for o in node.outputs { - self.color_node(o); + fn bridge(&mut self, pred: u16, succ: u16) { + if self.nodes[pred].ralloc_backref == u16::MAX + || self.nodes[succ].ralloc_backref == u16::MAX + { + return; } - - self.color_node(node.inputs[0]); - None + self.blocks[self.nodes[pred].ralloc_backref as usize] + .succs + .push(regalloc2::Block::new(self.nodes[succ].ralloc_backref as usize)); + self.blocks[self.nodes[succ].ralloc_backref as usize] + .preds + .push(regalloc2::Block::new(self.nodes[pred].ralloc_backref as usize)); } } - } - fn emit_node(&mut self, ctrl: Nid, prev: Nid) -> Option { - if matches!(self.ci.nodes[ctrl].kind, Kind::Region | Kind::Loop) { - let node = self.ci.nodes[ctrl].clone(); + impl<'a> regalloc2::Function for Function<'a> { + fn num_insts(&self) -> usize { + self.instrs.len() + } - let idx = 1 + node.inputs.iter().position(|&i| i == prev).unwrap(); + fn num_blocks(&self) -> usize { + self.blocks.len() + } - for ph in node.outputs { - if self.ci.nodes[ph].kind != Kind::Phi { + fn entry_block(&self) -> regalloc2::Block { + regalloc2::Block(0) + } + + fn block_insns(&self, block: regalloc2::Block) -> regalloc2::InstRange { + self.blocks[block.index()].instrs + } + + fn block_succs(&self, block: regalloc2::Block) -> &[regalloc2::Block] { + &self.blocks[block.index()].succs + } + + fn block_preds(&self, block: regalloc2::Block) -> &[regalloc2::Block] { + &self.blocks[block.index()].preds + } + + fn block_params(&self, block: regalloc2::Block) -> &[regalloc2::VReg] { + &self.blocks[block.index()].params + } + + fn is_ret(&self, insn: regalloc2::Inst) -> bool { + self.nodes[self.instrs[insn.index()].nid].kind == Kind::Return + } + + fn is_branch(&self, insn: regalloc2::Inst) -> bool { + matches!( + self.nodes[self.instrs[insn.index()].nid].kind, + Kind::If | Kind::Tuple { .. } | Kind::Loop | Kind::Region + ) + } + + fn branch_blockparams( + &self, + block: regalloc2::Block, + _insn: regalloc2::Inst, + _succ_idx: usize, + ) -> &[regalloc2::VReg] { + debug_assert!( + self.blocks[block.index()].succs.len() == 1 + || self.blocks[block.index()].branch_blockparams.is_empty() + ); + + &self.blocks[block.index()].branch_blockparams + } + + fn inst_operands(&self, insn: regalloc2::Inst) -> &[regalloc2::Operand] { + &self.instrs[insn.index()].ops + } + + 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 { + set.add(regalloc2::PReg::new(i, regalloc2::RegClass::Int)); + } + set + } else { + regalloc2::PRegSet::default() + } + } + + fn num_vregs(&self) -> usize { + self.nodes.values.len() + } + + fn spillslot_size(&self, regclass: regalloc2::RegClass) -> usize { + match regclass { + regalloc2::RegClass::Int => 1, + regalloc2::RegClass::Float => unreachable!(), + regalloc2::RegClass::Vector => unreachable!(), + } + } + } + + let mut nodes = std::mem::take(&mut self.ci.nodes); + + let func = Function::new(&mut nodes, &self.tys, sig); + let 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(), + }; + let options = regalloc2::RegallocOptions { verbose_log: false, validate_ssa: true }; + let output = regalloc2::run(&func, &env, &options).unwrap_or_else(|err| panic!("{err}")); + + let mut saved_regs = HashMap::::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 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; - } - - self.emit_pass(self.ci.nodes[ph].inputs[idx], ph); - } - - match (self.ci.nodes[ctrl].kind, self.ci.nodes.visited.set(ctrl)) { - (Kind::Region, true) | (Kind::Loop, false) => { - self.ci.jump_relocs.push((ctrl, Reloc::new(self.ci.code.len(), 1, 4))); - self.ci.emit(instrs::jmp(0)); - return None; - } - _ => {} - } - } else if !self.ci.nodes.visited.set(ctrl) { - return None; - } - - let node = self.ci.nodes[ctrl].clone(); - match node.kind { - Kind::Start => self.emit_node(node.outputs[0], VOID), - Kind::End => None, - Kind::If => { - let &[_, cond] = node.inputs.as_slice() else { unreachable!() }; - let &[mut then, mut else_] = node.outputs.as_slice() else { unreachable!() }; - - if let Kind::BinOp { op } = self.ci.nodes[cond].kind - && let Some((op, swapped)) = op.cond_op(node.ty.is_signed()) - { - self.ci.nodes[cond].offset = self.ci.code.len() as _; - if swapped { - std::mem::swap(&mut then, &mut else_); - } - let &[_, lhs, rhs] = self.ci.nodes[cond].inputs.as_slice() else { - unreachable!() - }; - self.ci.emit(op(node_loc!(self, lhs).reg, node_loc!(self, rhs).reg, 0)); - } else { - todo!() - } - - self.emit_node(then, ctrl); - let jump = self.ci.code.len() as i64 - self.ci.nodes[cond].offset as i64; - self.emit_node(else_, ctrl); - write_reloc(&mut self.ci.code, self.ci.nodes[cond].offset as usize + 3, jump, 2); - - None - } - Kind::Region | Kind::Loop => { - self.ci.nodes[ctrl].offset = self.ci.code.len() as _; - for o in node.outputs.into_iter().rev() { - self.emit_node(o, ctrl); - } - None - } - Kind::Return => { - if node.inputs[1] != VOID { - let loc = Loc { reg: 1 }; - if node_loc!(self, node.inputs[1]) != loc { - self.ci.emit(instrs::cp(loc.reg, node_loc!(self, node.inputs[1]).reg)); - } - } - self.ci.ret_relocs.push(Reloc::new(self.ci.code.len(), 1, 4)); - self.ci.emit(instrs::jmp(0)); - self.emit_node(node.outputs[0], ctrl); - None - } - Kind::CInt { value } => { - if node.color != 0 { - if node_loc!(self, ctrl) == Loc::default() { - node_loc!(self, ctrl) = Loc { reg: self.ci.regs.allocate(0) }; - } - // TODO: respect size - self.ci.emit(instrs::li64(node_loc!(self, ctrl).reg, value as _)); - } - None - } - Kind::Phi => None, - Kind::Tuple { index } => { - if (self.ci.nodes[node.inputs[0]].kind == Kind::Start && index == 0) - || (self.ci.nodes[node.inputs[0]].kind == Kind::If && index < 2) - { - for o in node.outputs.into_iter().rev() { - self.emit_node(o, ctrl); - } - } else { - todo!(); - } - - None - } - Kind::BinOp { op } => { - if node.color != 0 { - let &[_, lhs, rhs] = node.inputs.as_slice() else { unreachable!() }; - - self.lazy_init(ctrl); - if self.ci.nodes[rhs].color == 0 - && let Kind::CInt { value } = self.ci.nodes[rhs].kind - && let Some(op) = - op.imm_binop(node.ty.is_signed(), self.tys.size_of(node.ty)) - { - self.ci.emit(op( - node_loc!(self, ctrl).reg, - node_loc!(self, lhs).reg, - value as _, - )); - } else if let Some(op) = - op.binop(node.ty.is_signed(), self.tys.size_of(node.ty)) - { - self.ci.emit(op( - node_loc!(self, ctrl).reg, - node_loc!(self, lhs).reg, - node_loc!(self, rhs).reg, - )); - } else { - todo!() - } - } - None - } - Kind::UnOp { op } => { - if node.color != 0 { - let op = op.unop().expect("TODO: unsupported unary operator"); - self.lazy_init(ctrl); - self.ci - .emit(op(node_loc!(self, ctrl).reg, node_loc!(self, node.inputs[1]).reg)); - } - None - } - Kind::Call { func } => { - let fuc = self.tys.funcs[func as usize].sig.unwrap(); - let mut parama = self.tys.parama(fuc.ret); - for (&i, ti) in node.inputs[1..].iter().zip(fuc.args.range()) { - let ty = self.tys.args[ti]; - match self.tys.size_of(ty) { - 0 => continue, - 1..=8 => { - let loc = Loc { reg: parama.next() }; - if node_loc!(self, i) != loc { - self.ci.emit(instrs::cp(loc.reg, node_loc!(self, i).reg)); - } + }; + let allocs = output.inst_allocs(inst); + let node = &func.nodes[nid]; + match node.kind { + Kind::Start => todo!(), + Kind::End => todo!(), + 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!() } - _ => 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::Phi => todo!(), + Kind::Tuple { .. } => todo!(), + 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!() }; - let reloc = Reloc::new(self.ci.code.len(), 3, 4); - self.ci.relocs.push(TypedReloc { target: ty::Kind::Func(func).compress(), reloc }); - self.ci.emit(jal(reg::RET_ADDR, reg::ZERO, 0)); - self.emit_pass_low(Loc { reg: 1 }, ctrl); - for o in node.outputs.into_iter().rev() { - if self.ci.nodes[o].inputs[0] == ctrl { - self.emit_node(o, ctrl); + 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)); } } - None } } + + self.ci.nodes = nodes; + + saved_regs.len() } // TODO: sometimes its better to do this in bulk @@ -2501,35 +2477,6 @@ impl Codegen { ty::Tuple::new(sp, len) } - fn emit_pass(&mut self, src: Nid, dst: Nid) { - if self.ci.nodes[src].color == self.ci.nodes[dst].color { - return; - } - self.emit_pass_low(node_loc!(self, src), dst); - } - - fn emit_pass_low(&mut self, src: Loc, dst: Nid) { - let loc = &mut node_loc!(self, dst); - if src != *loc { - if *loc == Loc::default() { - let reg = self.ci.regs.allocate(0); - *loc = Loc { reg }; - } - let inst = instrs::cp(loc.reg, src.reg); - self.ci.emit(inst); - } - } - - fn lazy_init(&mut self, expr: Nid) -> bool { - let loc = &mut node_loc!(self, expr); - if *loc == Loc::default() { - let reg = self.ci.regs.allocate(0); - *loc = Loc { reg }; - return true; - } - false - } - fn fatal_report(&self, pos: Pos, msg: impl Display) -> ! { self.report(pos, msg); eprintln!("{}", self.errors.borrow()); @@ -2777,106 +2724,6 @@ fn common_dom(mut a: Nid, mut b: Nid, nodes: &mut Nodes) -> Nid { a } -fn scan_idom( - nodes: &mut Nodes, - target: Nid, - pred: &mut impl FnMut(&mut Nodes, Nid) -> bool, -) -> Option { - if !pred(nodes, target) { - return None; - } - Some(match nodes[target].kind { - Kind::Start => VOID, - Kind::End => unreachable!(), - Kind::Loop - | Kind::CInt { .. } - | Kind::BinOp { .. } - | Kind::UnOp { .. } - | Kind::Call { .. } - | Kind::Phi - | Kind::Tuple { .. } - | Kind::Return - | Kind::If => nodes[target].inputs[0], - Kind::Region => { - let &[mut a, mut b] = nodes[target].inputs.as_slice() else { unreachable!() }; - while a != b { - let [ldepth, rdepth] = [idepth(nodes, a), idepth(nodes, b)]; - if ldepth >= rdepth { - a = scan_idom(nodes, a, pred)?; - } - if ldepth <= rdepth { - b = scan_idom(nodes, b, pred)?; - } - } - a - } - }) -} - -fn walk_use_doms( - target: Nid, - nodes: &mut Nodes, - mut all: impl FnMut(&mut Nodes, Nid) -> bool, -) -> bool { - let dom = - if matches!(nodes[target].kind, Kind::Call { .. }) { target } else { idom(nodes, target) }; - for mut out in nodes[target].outputs.clone().into_iter().skip(1) { - out = use_block(target, out, nodes); - while out != dom { - debug_assert!(idepth(nodes, out) > idepth(nodes, dom),); - debug_assert_ne!(out, VOID); - out = match scan_idom(nodes, out, &mut all) { - Some(next) => next, - None => return false, - }; - } - } - - true -} - -fn check_no_calls(target: Nid, nodes: &mut Nodes) -> bool { - walk_use_doms(target, nodes, |nd, ud| !matches!(nd[ud].kind, Kind::Call { .. } | Kind::Loop)) -} - -fn is_last_branch_use(target: Nid, us: Nid, nodes: &mut Nodes) -> bool { - if nodes[target].outputs.len() == 1 { - return true; - } - - let usdom = if matches!(nodes[us].kind, Kind::Call { .. }) { us } else { idom(nodes, us) }; - let tadom = - if matches!(nodes[target].kind, Kind::Call { .. }) { target } else { idom(nodes, target) }; - if loop_depth(usdom, nodes) > loop_depth(tadom, nodes) { - return false; - } - - let outputs = nodes[target].outputs.clone(); - 'o: for o in outputs { - if o == us || idepth(nodes, o) < idepth(nodes, us) { - continue; - } - - let mut odom = if matches!(nodes[o].kind, Kind::Call { .. }) { o } else { idom(nodes, o) }; - - if odom == usdom { - return nodes[usdom].outputs.find(us) < nodes[odom].outputs.find(o); - } - - while odom != usdom { - odom = idom(nodes, odom); - if idepth(nodes, odom) < idepth(nodes, us) { - continue 'o; - } - debug_assert_ne!(odom, VOID); - } - - return false; - } - - true -} - #[cfg(test)] mod tests { use std::fmt::Write; @@ -2884,6 +2731,7 @@ mod tests { const README: &str = include_str!("../README.md"); fn generate(ident: &'static str, input: &'static str, output: &mut String) { + _ = env_logger::builder().is_test(true).try_init(); let mut codegen = super::Codegen { files: crate::test_parse_files(ident, input), ..Default::default() }; diff --git a/hblang/tests/codegen_tests_comments.txt b/hblang/tests/codegen_tests_comments.txt index 74809d0..33f3145 100644 --- a/hblang/tests/codegen_tests_comments.txt +++ b/hblang/tests/codegen_tests_comments.txt @@ -1,3 +1,9 @@ +foo: + 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, -8d ST r31, r254, 0a, 8h @@ -6,12 +12,6 @@ main: LD r31, r254, 0a, 8h ADDI64 r254, r254, 8d JALA r0, r31, 0a -foo: - ADDI64 r254, r254, -8d - ST r31, r254, 0a, 8h - LD r31, r254, 0a, 8h - ADDI64 r254, r254, 8d - JALA r0, r31, 0a code size: 143 ret: 0 status: Ok(()) diff --git a/hblang/tests/codegen_tests_functions.txt b/hblang/tests/codegen_tests_functions.txt index 524845d..49b789d 100644 --- a/hblang/tests/codegen_tests_functions.txt +++ b/hblang/tests/codegen_tests_functions.txt @@ -1,3 +1,19 @@ +add_one: + ADDI64 r254, r254, -16d + ST r31, r254, 0a, 16h + CP r32, r2 + ADDI64 r1, r32, 1d + LD r31, r254, 0a, 16h + ADDI64 r254, r254, 16d + JALA r0, r31, 0a +add_two: + ADDI64 r254, r254, -16d + ST r31, r254, 0a, 16h + CP r32, r2 + ADDI64 r1, r32, 2d + LD r31, r254, 0a, 16h + ADDI64 r254, r254, 16d + JALA r0, r31, 0a main: ADDI64 r254, r254, -24d ST r31, r254, 0a, 24h @@ -11,22 +27,6 @@ main: LD r31, r254, 0a, 24h ADDI64 r254, r254, 24d JALA r0, r31, 0a -add_two: - ADDI64 r254, r254, -16d - ST r31, r254, 0a, 16h - CP r32, r2 - ADDI64 r1, r32, 2d - LD r31, r254, 0a, 16h - ADDI64 r254, r254, 16d - JALA r0, r31, 0a -add_one: - ADDI64 r254, r254, -16d - ST r31, r254, 0a, 16h - CP r32, r2 - ADDI64 r1, r32, 1d - LD r31, r254, 0a, 16h - ADDI64 r254, r254, 16d - JALA r0, r31, 0a code size: 257 ret: 33 status: Ok(()) diff --git a/hblang/tests/codegen_tests_generic_functions.txt b/hblang/tests/codegen_tests_generic_functions.txt index 69eb94f..0997f12 100644 --- a/hblang/tests/codegen_tests_generic_functions.txt +++ b/hblang/tests/codegen_tests_generic_functions.txt @@ -1,20 +1,3 @@ -main: - ADDI64 r254, r254, -32d - ST r31, r254, 0a, 32h - LI64 r2, 2d - LI64 r3, 2d - JAL r31, r0, :add - CP r32, r1 - LI64 r2, 1d - LI64 r3, 3d - JAL r31, r0, :add - CP r33, r1 - CP r34, r32 - SXT32 r34, r34 - SUB64 r1, r34, r33 - LD r31, r254, 0a, 32h - ADDI64 r254, r254, 32d - JALA r0, r31, 0a add: ADDI64 r254, r254, -24d ST r31, r254, 0a, 24h @@ -33,6 +16,23 @@ add: LD r31, r254, 0a, 24h ADDI64 r254, r254, 24d JALA r0, r31, 0a +main: + ADDI64 r254, r254, -32d + ST r31, r254, 0a, 32h + LI64 r2, 2d + LI64 r3, 2d + JAL r31, r0, :add + CP r32, r1 + LI64 r2, 1d + LI64 r3, 3d + JAL r31, r0, :add + CP r33, r1 + CP r34, r32 + SXT32 r34, r34 + SUB64 r1, r34, r33 + LD r31, r254, 0a, 32h + ADDI64 r254, r254, 32d + JALA r0, r31, 0a code size: 275 ret: 0 status: Ok(()) diff --git a/hblang/tests/codegen_tests_generic_types.txt b/hblang/tests/codegen_tests_generic_types.txt index 1cec9c8..b15058d 100644 --- a/hblang/tests/codegen_tests_generic_types.txt +++ b/hblang/tests/codegen_tests_generic_types.txt @@ -1,3 +1,33 @@ +deinit: + ADDI64 r254, r254, -24d + ST r31, r254, 0a, 24h + CP r32, r2 + LD r2, r32, 0a, 8h + LD r33, r32, 16a, 8h + MULI64 r33, r33, 8d + CP r3, r33 + LI64 r4, 8d + JAL r31, r0, :free + CP r1, r32 + JAL r31, r0, :new + LD r31, r254, 0a, 24h + ADDI64 r254, r254, 24d + JALA r0, r31, 0a +free: + ADDI64 r254, r254, -40d + ST r31, r254, 0a, 40h + CP r32, r2 + CP r33, r3 + CP r34, r4 + LRA r35, r0, :FREE_SYS_CALL + LD r2, r35, 0a, 8h + CP r3, r32 + CP r4, r33 + CP r5, r34 + ECA + LD r31, r254, 0a, 40h + ADDI64 r254, r254, 40d + JALA r0, r31, 0a main: ADDI64 r254, r254, -48d ST r31, r254, 24a, 24h @@ -17,20 +47,18 @@ main: LD r31, r254, 24a, 24h ADDI64 r254, r254, 48d JALA r0, r31, 0a -deinit: - ADDI64 r254, r254, -24d - ST r31, r254, 0a, 24h +malloc: + ADDI64 r254, r254, -32d + ST r31, r254, 0a, 32h CP r32, r2 - LD r2, r32, 0a, 8h - LD r33, r32, 16a, 8h - MULI64 r33, r33, 8d - CP r3, r33 - LI64 r4, 8d - JAL r31, r0, :free - CP r1, r32 - JAL r31, r0, :new - LD r31, r254, 0a, 24h - ADDI64 r254, r254, 24d + CP r33, r3 + LRA r34, r0, :MALLOC_SYS_CALL + LD r2, r34, 0a, 8h + CP r3, r32 + CP r4, r33 + ECA + LD r31, r254, 0a, 32h + ADDI64 r254, r254, 32d JALA r0, r31, 0a new: ADDI64 r254, r254, -24d @@ -45,21 +73,6 @@ new: LD r31, r254, 0a, 24h ADDI64 r254, r254, 24d JALA r0, r31, 0a -free: - ADDI64 r254, r254, -40d - ST r31, r254, 0a, 40h - CP r32, r2 - CP r33, r3 - CP r34, r4 - LRA r35, r0, :FREE_SYS_CALL - LD r2, r35, 0a, 8h - CP r3, r32 - CP r4, r33 - CP r5, r34 - ECA - LD r31, r254, 0a, 40h - ADDI64 r254, r254, 40d - JALA r0, r31, 0a push: ADDI64 r254, r254, -72d ST r31, r254, 0a, 72h @@ -124,19 +137,6 @@ push: 4: LD r31, r254, 0a, 72h ADDI64 r254, r254, 72d JALA r0, r31, 0a -malloc: - ADDI64 r254, r254, -32d - ST r31, r254, 0a, 32h - CP r32, r2 - CP r33, r3 - LRA r34, r0, :MALLOC_SYS_CALL - LD r2, r34, 0a, 8h - CP r3, r32 - CP r4, r33 - ECA - LD r31, r254, 0a, 32h - ADDI64 r254, r254, 32d - JALA r0, r31, 0a code size: 1201 ret: 69 status: Ok(()) diff --git a/hblang/tests/codegen_tests_if_statements.txt b/hblang/tests/codegen_tests_if_statements.txt index dcdada4..b06c467 100644 --- a/hblang/tests/codegen_tests_if_statements.txt +++ b/hblang/tests/codegen_tests_if_statements.txt @@ -1,11 +1,3 @@ -main: - ADDI64 r254, r254, -8d - ST r31, r254, 0a, 8h - LI64 r2, 10d - JAL r31, r0, :fib - LD r31, r254, 0a, 8h - ADDI64 r254, r254, 8d - JALA r0, r31, 0a fib: ADDI64 r254, r254, -24d ST r31, r254, 0a, 24h @@ -27,6 +19,14 @@ fib: 1: LD r31, r254, 0a, 24h ADDI64 r254, r254, 24d JALA r0, r31, 0a +main: + ADDI64 r254, r254, -8d + ST r31, r254, 0a, 8h + LI64 r2, 10d + JAL r31, r0, :fib + LD r31, r254, 0a, 8h + ADDI64 r254, r254, 8d + JALA r0, r31, 0a code size: 231 ret: 55 status: Ok(()) diff --git a/hblang/tests/codegen_tests_inline_test.txt b/hblang/tests/codegen_tests_inline_test.txt index 7f67cf1..549680e 100644 --- a/hblang/tests/codegen_tests_inline_test.txt +++ b/hblang/tests/codegen_tests_inline_test.txt @@ -1,45 +1,3 @@ -main: - ADDI64 r254, r254, -64d - ST r31, r254, 48a, 16h - LI64 r32, 0d - ST r32, r254, 0a, 8h - LI64 r32, 0d - ST r32, r254, 8a, 8h - LD r2, r254, 0a, 16h - LI64 r32, 0d - ST r32, r254, 16a, 8h - LI64 r32, 0d - ST r32, r254, 24a, 8h - LD r4, r254, 16a, 16h - LI64 r32, 0d - ST r32, r254, 32a, 8h - LI64 r32, 0d - ST r32, r254, 40a, 8h - LD r6, r254, 32a, 16h - LI64 r8, 10d - JAL r31, r0, :line - LI64 r32, 0d - ST r32, r254, 0a, 8h - LI64 r32, 0d - ST r32, r254, 8a, 8h - LD r2, r254, 0a, 16h - LI64 r32, 0d - ST r32, r254, 16a, 8h - LI64 r32, 0d - ST r32, r254, 24a, 8h - LD r4, r254, 16a, 16h - LI64 r32, 0d - ST r32, r254, 32a, 8h - LI64 r32, 0d - ST r32, r254, 40a, 8h - LD r6, r254, 32a, 16h - LI64 r8, 10d - JAL r31, r0, :rect_line - JAL r31, r0, :example - LI64 r1, 0d - LD r31, r254, 48a, 16h - ADDI64 r254, r254, 64d - JALA r0, r31, 0a example: ADDI64 r254, r254, -48d ST r31, r254, 0a, 48h @@ -103,6 +61,69 @@ integer: 1: LD r31, r254, 0a, 56h ADDI64 r254, r254, 56d JALA r0, r31, 0a +line: + ADDI64 r254, r254, -80d + ST r31, r254, 48a, 32h + ST r2, r254, 16a, 16h + ST r4, r254, 0a, 16h + ST r6, r254, 32a, 16h + CP r32, r8 + LI64 r33, 1d + JEQ r33, r0, :0 + LD r33, r254, 16a, 8h + LD r34, r254, 0a, 8h + JGTS r33, r34, :1 + JMP :1 + 1: JMP :2 + 0: LD r34, r254, 24a, 8h + LD r33, r254, 8a, 8h + JGTS r34, r33, :2 + JMP :2 + 2: LD r31, r254, 48a, 32h + ADDI64 r254, r254, 80d + JALA r0, r31, 0a +main: + ADDI64 r254, r254, -64d + ST r31, r254, 48a, 16h + LI64 r32, 0d + ST r32, r254, 0a, 8h + LI64 r32, 0d + ST r32, r254, 8a, 8h + LD r2, r254, 0a, 16h + LI64 r32, 0d + ST r32, r254, 16a, 8h + LI64 r32, 0d + ST r32, r254, 24a, 8h + LD r4, r254, 16a, 16h + LI64 r32, 0d + ST r32, r254, 32a, 8h + LI64 r32, 0d + ST r32, r254, 40a, 8h + LD r6, r254, 32a, 16h + LI64 r8, 10d + JAL r31, r0, :line + LI64 r32, 0d + ST r32, r254, 0a, 8h + LI64 r32, 0d + ST r32, r254, 8a, 8h + LD r2, r254, 0a, 16h + LI64 r32, 0d + ST r32, r254, 16a, 8h + LI64 r32, 0d + ST r32, r254, 24a, 8h + LD r4, r254, 16a, 16h + LI64 r32, 0d + ST r32, r254, 32a, 8h + LI64 r32, 0d + ST r32, r254, 40a, 8h + LD r6, r254, 32a, 16h + LI64 r8, 10d + JAL r31, r0, :rect_line + JAL r31, r0, :example + LI64 r1, 0d + LD r31, r254, 48a, 16h + ADDI64 r254, r254, 64d + JALA r0, r31, 0a rect_line: ADDI64 r254, r254, -112d ST r31, r254, 48a, 64h @@ -135,27 +156,6 @@ rect_line: 1: LD r31, r254, 48a, 64h ADDI64 r254, r254, 112d JALA r0, r31, 0a -line: - ADDI64 r254, r254, -80d - ST r31, r254, 48a, 32h - ST r2, r254, 16a, 16h - ST r4, r254, 0a, 16h - ST r6, r254, 32a, 16h - CP r32, r8 - LI64 r33, 1d - JEQ r33, r0, :0 - LD r33, r254, 16a, 8h - LD r34, r254, 0a, 8h - JGTS r33, r34, :1 - JMP :1 - 1: JMP :2 - 0: LD r34, r254, 24a, 8h - LD r33, r254, 8a, 8h - JGTS r34, r33, :2 - JMP :2 - 2: LD r31, r254, 48a, 32h - ADDI64 r254, r254, 80d - JALA r0, r31, 0a code size: 1400 ret: 0 status: Ok(()) diff --git a/hblang/tests/codegen_tests_integer_inference_issues.txt b/hblang/tests/codegen_tests_integer_inference_issues.txt index 36eb5eb..db30783 100644 --- a/hblang/tests/codegen_tests_integer_inference_issues.txt +++ b/hblang/tests/codegen_tests_integer_inference_issues.txt @@ -1,13 +1,3 @@ -main: - ADDI64 r254, r254, -16d - ST r31, r254, 0a, 16h - LI64 r2, 0d - LI64 r3, 1000d - JAL r31, r0, :integer_range - CP r32, r1 - LD r31, r254, 0a, 16h - ADDI64 r254, r254, 16d - JALA r0, r31, 0a integer_range: ADDI64 r254, r254, -32d ST r31, r254, 0a, 32h @@ -24,6 +14,16 @@ integer_range: LD r31, r254, 0a, 32h ADDI64 r254, r254, 32d JALA r0, r31, 0a +main: + ADDI64 r254, r254, -16d + ST r31, r254, 0a, 16h + LI64 r2, 0d + LI64 r3, 1000d + JAL r31, r0, :integer_range + CP r32, r1 + LD r31, r254, 0a, 16h + ADDI64 r254, r254, 16d + JALA r0, r31, 0a code size: 210 ret: 42 status: Ok(()) diff --git a/hblang/tests/codegen_tests_loops.txt b/hblang/tests/codegen_tests_loops.txt index e82279f..670509a 100644 --- a/hblang/tests/codegen_tests_loops.txt +++ b/hblang/tests/codegen_tests_loops.txt @@ -1,11 +1,3 @@ -main: - ADDI64 r254, r254, -8d - ST r31, r254, 0a, 8h - LI64 r2, 10d - JAL r31, r0, :fib - LD r31, r254, 0a, 8h - ADDI64 r254, r254, 8d - JALA r0, r31, 0a fib: ADDI64 r254, r254, -40d ST r31, r254, 0a, 40h @@ -25,6 +17,14 @@ fib: LD r31, r254, 0a, 40h ADDI64 r254, r254, 40d JALA r0, r31, 0a +main: + ADDI64 r254, r254, -8d + ST r31, r254, 0a, 8h + LI64 r2, 10d + JAL r31, r0, :fib + LD r31, r254, 0a, 8h + ADDI64 r254, r254, 8d + JALA r0, r31, 0a code size: 218 ret: 55 status: Ok(()) diff --git a/hblang/tests/codegen_tests_pointers.txt b/hblang/tests/codegen_tests_pointers.txt index 8ad2d01..8cde225 100644 --- a/hblang/tests/codegen_tests_pointers.txt +++ b/hblang/tests/codegen_tests_pointers.txt @@ -1,3 +1,10 @@ +drop: + ADDI64 r254, r254, -16d + ST r31, r254, 0a, 16h + CP r32, r2 + LD r31, r254, 0a, 16h + ADDI64 r254, r254, 16d + JALA r0, r31, 0a main: ADDI64 r254, r254, -40d ST r31, r254, 8a, 32h @@ -14,13 +21,6 @@ main: LD r31, r254, 8a, 32h ADDI64 r254, r254, 40d JALA r0, r31, 0a -drop: - ADDI64 r254, r254, -16d - ST r31, r254, 0a, 16h - CP r32, r2 - LD r31, r254, 0a, 16h - ADDI64 r254, r254, 16d - JALA r0, r31, 0a modify: ADDI64 r254, r254, -24d ST r31, r254, 0a, 24h diff --git a/hblang/tests/codegen_tests_request_page.txt b/hblang/tests/codegen_tests_request_page.txt index 7a905e5..feb1b75 100644 --- a/hblang/tests/codegen_tests_request_page.txt +++ b/hblang/tests/codegen_tests_request_page.txt @@ -1,12 +1,3 @@ -main: - ADDI64 r254, r254, -16d - ST r31, r254, 0a, 16h - LI64 r2, 400d - JAL r31, r0, :create_back_buffer - CP r32, r1 - LD r31, r254, 0a, 16h - ADDI64 r254, r254, 16d - JALA r0, r31, 0a create_back_buffer: ADDI64 r254, r254, -32d ST r31, r254, 0a, 32h @@ -38,6 +29,15 @@ create_back_buffer: 1: LD r31, r254, 0a, 32h ADDI64 r254, r254, 32d JALA r0, r31, 0a +main: + ADDI64 r254, r254, -16d + ST r31, r254, 0a, 16h + LI64 r2, 400d + JAL r31, r0, :create_back_buffer + CP r32, r1 + LD r31, r254, 0a, 16h + ADDI64 r254, r254, 16d + JALA r0, r31, 0a request_page: ADDI64 r254, r254, -32d ST r31, r254, 0a, 32h diff --git a/hblang/tests/codegen_tests_struct_patterns.txt b/hblang/tests/codegen_tests_struct_patterns.txt index d599dbe..616df10 100644 --- a/hblang/tests/codegen_tests_struct_patterns.txt +++ b/hblang/tests/codegen_tests_struct_patterns.txt @@ -1,43 +1,3 @@ -main: - ADDI64 r254, r254, -26d - ST r31, r254, 2a, 24h - LI64 r32, 10d - ST r32, r254, 0a, 1h - LI64 r32, 10d - ST r32, r254, 1a, 1h - CP r32, r0 - LD r32, r254, 0a, 1h - CP r33, r0 - LD r33, r254, 1a, 1h - CP r2, r32 - JAL r31, r0, :fib - CP r32, r1 - CP r2, r33 - JAL r31, r0, :fib_iter - CP r33, r1 - SUB64 r1, r32, r33 - LD r31, r254, 2a, 24h - ADDI64 r254, r254, 26d - JALA r0, r31, 0a -fib_iter: - ADDI64 r254, r254, -40d - ST r31, r254, 0a, 40h - CP r32, r2 - LI64 r33, 0d - LI64 r34, 1d - 2: LI64 r35, 0d - JNE r32, r35, :0 - JMP :1 - 0: CP r35, r33 - ADD64 r35, r35, r34 - CP r33, r34 - CP r34, r35 - ADDI64 r32, r32, -1d - JMP :2 - 1: CP r1, r33 - LD r31, r254, 0a, 40h - ADDI64 r254, r254, 40d - JALA r0, r31, 0a fib: ADDI64 r254, r254, -32d ST r31, r254, 0a, 32h @@ -60,6 +20,46 @@ fib: 1: LD r31, r254, 0a, 32h ADDI64 r254, r254, 32d JALA r0, r31, 0a +fib_iter: + ADDI64 r254, r254, -40d + ST r31, r254, 0a, 40h + CP r32, r2 + LI64 r33, 0d + LI64 r34, 1d + 2: LI64 r35, 0d + JNE r32, r35, :0 + JMP :1 + 0: CP r35, r33 + ADD64 r35, r35, r34 + CP r33, r34 + CP r34, r35 + ADDI64 r32, r32, -1d + JMP :2 + 1: CP r1, r33 + LD r31, r254, 0a, 40h + ADDI64 r254, r254, 40d + JALA r0, r31, 0a +main: + ADDI64 r254, r254, -26d + ST r31, r254, 2a, 24h + LI64 r32, 10d + ST r32, r254, 0a, 1h + LI64 r32, 10d + ST r32, r254, 1a, 1h + CP r32, r0 + LD r32, r254, 0a, 1h + CP r33, r0 + LD r33, r254, 1a, 1h + CP r2, r32 + JAL r31, r0, :fib + CP r32, r1 + CP r2, r33 + JAL r31, r0, :fib_iter + CP r33, r1 + SUB64 r1, r32, r33 + LD r31, r254, 2a, 24h + ADDI64 r254, r254, 26d + JALA r0, r31, 0a code size: 452 ret: 0 status: Ok(()) diff --git a/hblang/tests/codegen_tests_struct_return_from_module_function.txt b/hblang/tests/codegen_tests_struct_return_from_module_function.txt index 00f9584..db9c72b 100644 --- a/hblang/tests/codegen_tests_struct_return_from_module_function.txt +++ b/hblang/tests/codegen_tests_struct_return_from_module_function.txt @@ -1,3 +1,16 @@ +foo: + ADDI64 r254, r254, -32d + ST r31, r254, 16a, 16h + LI64 r32, 3d + ST r32, r254, 0a, 8h + LI64 r32, 2d + ST r32, r254, 8a, 4h + LI64 r32, 2d + ST r32, r254, 12a, 4h + LD r1, r254, 0a, 16h + LD r31, r254, 16a, 16h + ADDI64 r254, r254, 32d + JALA r0, r31, 0a main: ADDI64 r254, r254, -40d ST r31, r254, 16a, 24h @@ -21,19 +34,6 @@ main: LD r31, r254, 16a, 24h ADDI64 r254, r254, 40d JALA r0, r31, 0a -foo: - ADDI64 r254, r254, -32d - ST r31, r254, 16a, 16h - LI64 r32, 3d - ST r32, r254, 0a, 8h - LI64 r32, 2d - ST r32, r254, 8a, 4h - LI64 r32, 2d - ST r32, r254, 12a, 4h - LD r1, r254, 0a, 16h - LD r31, r254, 16a, 16h - ADDI64 r254, r254, 32d - JALA r0, r31, 0a code size: 341 ret: 0 status: Ok(()) diff --git a/hblang/tests/codegen_tests_structs.txt b/hblang/tests/codegen_tests_structs.txt index cb7be51..b1bbd5e 100644 --- a/hblang/tests/codegen_tests_structs.txt +++ b/hblang/tests/codegen_tests_structs.txt @@ -21,16 +21,6 @@ main: 1: LD r31, r254, 24a, 24h ADDI64 r254, r254, 48d JALA r0, r31, 0a -pass: - ADDI64 r254, r254, -32d - ST r31, r254, 0a, 32h - CP r32, r2 - LD r33, r32, 0a, 8h - LD r34, r32, 8a, 8h - SUB64 r1, r33, r34 - LD r31, r254, 0a, 32h - ADDI64 r254, r254, 32d - JALA r0, r31, 0a odher_pass: ADDI64 r254, r254, -32d ST r31, r254, 0a, 32h @@ -41,6 +31,16 @@ odher_pass: LD r31, r254, 0a, 32h ADDI64 r254, r254, 32d JALA r0, r31, 0a +pass: + ADDI64 r254, r254, -32d + ST r31, r254, 0a, 32h + CP r32, r2 + LD r33, r32, 0a, 8h + LD r34, r32, 8a, 8h + SUB64 r1, r33, r34 + LD r31, r254, 0a, 32h + ADDI64 r254, r254, 32d + JALA r0, r31, 0a code size: 394 ret: 3 status: Ok(()) diff --git a/hblang/tests/codegen_tests_writing_into_string.txt b/hblang/tests/codegen_tests_writing_into_string.txt index 87b8955..44d026c 100644 --- a/hblang/tests/codegen_tests_writing_into_string.txt +++ b/hblang/tests/codegen_tests_writing_into_string.txt @@ -1,3 +1,10 @@ +inl: + ADDI64 r254, r254, -16d + ST r31, r254, 0a, 16h + LRA r32, r0, :"luhahah\0" + LD r31, r254, 0a, 16h + ADDI64 r254, r254, 16d + JALA r0, r31, 0a main: ADDI64 r254, r254, -8d ST r31, r254, 0a, 8h @@ -6,13 +13,6 @@ main: LD r31, r254, 0a, 8h ADDI64 r254, r254, 8d JALA r0, r31, 0a -inl: - ADDI64 r254, r254, -16d - ST r31, r254, 0a, 16h - LRA r32, r0, :"luhahah\0" - LD r31, r254, 0a, 16h - ADDI64 r254, r254, 16d - JALA r0, r31, 0a outl: ADDI64 r254, r254, -16d ST r31, r254, 0a, 16h