parent
74130b0dfa
commit
3cd1241271
@ -0,0 +1,454 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ascii-canvas"
|
||||
version = "4.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef1e3e699d84ab1b0911a1010c5c106aa34ae89aeac103be5ce0c3859db1e891"
|
||||
dependencies = [
|
||||
"term",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
|
||||
dependencies = [
|
||||
"bit-vec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-vec"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||
|
||||
[[package]]
|
||||
name = "ena"
|
||||
version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eabffdaee24bd1bf95c5ef7cec31260444317e72ea56c4c91750e8b7ee58d5f1"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "fixedbitset"
|
||||
version = "0.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "keccak"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653"
|
||||
dependencies = [
|
||||
"cpufeatures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lalrpop"
|
||||
version = "0.22.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba4ebbd48ce411c1d10fb35185f5a51a7bfa3d8b24b4e330d30c9e3a34129501"
|
||||
dependencies = [
|
||||
"ascii-canvas",
|
||||
"bit-set",
|
||||
"ena",
|
||||
"itertools",
|
||||
"lalrpop-util 0.22.2",
|
||||
"petgraph",
|
||||
"pico-args",
|
||||
"regex",
|
||||
"regex-syntax",
|
||||
"sha3",
|
||||
"string_cache",
|
||||
"term",
|
||||
"unicode-xid",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lalrpop-util"
|
||||
version = "0.22.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5baa5e9ff84f1aefd264e6869907646538a52147a755d494517a8007fb48733"
|
||||
dependencies = [
|
||||
"regex-automata",
|
||||
"rustversion",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lalrpop-util"
|
||||
version = "0.23.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "884f3e747ed2dcee867cda1b0c31a048f9e20de2d916a248949319921a2e666e"
|
||||
dependencies = [
|
||||
"regex-automata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.183"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
|
||||
dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
||||
|
||||
[[package]]
|
||||
name = "new_debug_unreachable"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
||||
|
||||
[[package]]
|
||||
name = "nudt-compiler-rust"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"lalrpop",
|
||||
"lalrpop-util 0.23.1",
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "petgraph"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772"
|
||||
dependencies = [
|
||||
"fixedbitset",
|
||||
"indexmap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
|
||||
dependencies = [
|
||||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pico-args"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
|
||||
|
||||
[[package]]
|
||||
name = "precomputed-hash"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "sha3"
|
||||
version = "0.10.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"keccak",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
|
||||
[[package]]
|
||||
name = "string_cache"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f"
|
||||
dependencies = [
|
||||
"new_debug_unreachable",
|
||||
"parking_lot",
|
||||
"phf_shared",
|
||||
"precomputed-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "term"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8c27177b12a6399ffc08b98f76f7c9a1f4fe9fc967c784c5a071fa8d93cf7e1"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "nudt-compiler-rust"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[[bin]]
|
||||
name = "compiler"
|
||||
path = "src/main.rs"
|
||||
|
||||
[build-dependencies]
|
||||
lalrpop = "0.22.1"
|
||||
|
||||
[dependencies]
|
||||
lalrpop = "0.22.1"
|
||||
lalrpop-util = "0.23.1"
|
||||
rustc-hash = "2.1.1"
|
||||
@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
lalrpop::process_src().unwrap();
|
||||
}
|
||||
@ -0,0 +1,274 @@
|
||||
use super::mir::{
|
||||
regs::{ PReg, Reg, RegKind, VReg},
|
||||
mir_operand::MemLoc,
|
||||
mir_block::MirBlock,
|
||||
mir_function::MirFunction,
|
||||
mir_label::MirLabel,
|
||||
mir_inst::{MirInst, MirInstKind},
|
||||
mir_context::{MirContext, RawData},
|
||||
};
|
||||
use crate::utils::{linked_list::LinkedListContainer,
|
||||
storage::ArenaPtr};
|
||||
|
||||
|
||||
pub trait Display {
|
||||
fn display(self, mctx: &MirContext) -> String;
|
||||
}
|
||||
|
||||
impl Display for MirLabel {
|
||||
fn display(self, _mctx: &MirContext) -> String { self.0 }
|
||||
}
|
||||
|
||||
impl Display for MirBlock {
|
||||
fn display(self, mctx: &MirContext) -> String {
|
||||
self.label(mctx).clone().display(mctx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for MirFunction {
|
||||
fn display(self, mctx: &MirContext) -> String {
|
||||
self.label(mctx).clone().display(mctx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for PReg {
|
||||
fn display(self, _mctx: &MirContext) -> String {
|
||||
let mut asm = String::new();
|
||||
let str = match self.kind() {
|
||||
RegKind::Address => match self.num() {
|
||||
0 => "x0",
|
||||
1 => "x1",
|
||||
2 => "x2",
|
||||
3 => "x3",
|
||||
4 => "x4",
|
||||
5 => "x5",
|
||||
6 => "x6",
|
||||
7 => "x7",
|
||||
8 => "x8",
|
||||
9 => "x9",
|
||||
10 => "x10",
|
||||
11 => "x11",
|
||||
12 => "x12",
|
||||
13 => "x13",
|
||||
14 => "x14",
|
||||
15 => "x15",
|
||||
16 => "x16",
|
||||
17 => "x17",
|
||||
18 => "x18",
|
||||
19 => "x19",
|
||||
20 => "x20",
|
||||
21 => "x21",
|
||||
22 => "x22",
|
||||
23 => "x23",
|
||||
24 => "x24",
|
||||
25 => "x25",
|
||||
26 => "x26",
|
||||
27 => "x27",
|
||||
28 => "x28",
|
||||
29 => "fp",
|
||||
30 => "x30",
|
||||
31 => "sp",
|
||||
32 => "xzr",
|
||||
_ => "<invalid>",
|
||||
},
|
||||
RegKind::Integer => match self.num() {
|
||||
0 => "w0",
|
||||
1 => "w1",
|
||||
2 => "w2",
|
||||
3 => "w3",
|
||||
4 => "w4",
|
||||
5 => "w5",
|
||||
6 => "w6",
|
||||
7 => "w7",
|
||||
8 => "w8",
|
||||
9 => "w9",
|
||||
10 => "w10",
|
||||
11 => "w11",
|
||||
12 => "w12",
|
||||
13 => "w13",
|
||||
14 => "w14",
|
||||
15 => "w15",
|
||||
16 => "w16",
|
||||
17 => "w17",
|
||||
18 => "w18",
|
||||
19 => "w19",
|
||||
20 => "w20",
|
||||
21 => "w21",
|
||||
22 => "w22",
|
||||
23 => "w23",
|
||||
24 => "w24",
|
||||
25 => "w25",
|
||||
26 => "w26",
|
||||
27 => "w27",
|
||||
28 => "w28",
|
||||
29 => "fp",
|
||||
30 => "w30",
|
||||
31 => "sp",
|
||||
32 => "wzr",
|
||||
_ => "invalid",
|
||||
}
|
||||
_ => "invalid"
|
||||
};
|
||||
asm += str.to_string().as_str();
|
||||
asm
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for VReg {
|
||||
fn display(self, _mctx: &MirContext) -> String {
|
||||
let mut asm = String::new();
|
||||
let str = match self.1 {
|
||||
RegKind::Integer => "vw",
|
||||
_ => "invalid",
|
||||
};
|
||||
asm += str.to_string().as_str();
|
||||
asm += &self.0.to_string();
|
||||
asm
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Reg {
|
||||
fn display(self, mctx: &MirContext) -> String {
|
||||
let mut asm = String::new();
|
||||
match self {
|
||||
Reg::P(preg) => asm += format!("{}", preg.display(mctx)).as_str(),
|
||||
Reg::V(vreg) => asm += format!("{}", vreg.display(mctx)).as_str(),
|
||||
}
|
||||
asm
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for MirInst {
|
||||
fn display(self, mctx: &MirContext) -> String {
|
||||
let mut asm = String::new();
|
||||
match &self.deref(mctx).unwrap().kind {
|
||||
MirInstKind::Str { rm, mem } => {
|
||||
asm += format!("str {}, {}", rm.display(mctx), mem.display(mctx)).as_str()
|
||||
}
|
||||
MirInstKind::Ldr { rd, mem } => {
|
||||
asm += format!("ldr {}, {}", rd.display(mctx), mem.display(mctx)).as_str()
|
||||
}
|
||||
MirInstKind::Movz{ rd, imm } => {
|
||||
asm += format!("movz {}, #{}", rd.display(mctx), imm).as_str();
|
||||
}
|
||||
MirInstKind::Movk{ rd, imm } => {
|
||||
asm += format!("movk {}, #{}, lsl #16", rd.display(mctx),imm).as_str();
|
||||
}
|
||||
MirInstKind::MovReg { rd, rn } => {
|
||||
asm += format!("mov {}, {}", rd.display(mctx), rn.display(mctx)).as_str()
|
||||
}
|
||||
MirInstKind::B { target } => {
|
||||
asm += format!("b {}", target.clone().display(mctx)).as_str()
|
||||
}
|
||||
MirInstKind::Ret => {
|
||||
asm += format!("ret").as_str()
|
||||
}
|
||||
MirInstKind::Add { rd, rn, rm } => {
|
||||
asm += format!("add {}, {}, {}", rd.display(mctx), rn.display(mctx), rm.display(mctx)).as_str();
|
||||
}
|
||||
MirInstKind::Addi {rd,rn,imm} => {
|
||||
asm += format!("add {}, {}, #{}", rd.display(mctx), rn.display(mctx), imm).as_str();
|
||||
}
|
||||
MirInstKind::Subi {rd,rn,imm} => {
|
||||
asm += format!("sub {}, {}, #{}", rd.display(mctx), rn.display(mctx), imm).as_str();
|
||||
}
|
||||
MirInstKind::Adrp { rd, label } => {
|
||||
asm += format!("adrp {}, {}", rd.display(mctx), label.clone().display(mctx)).as_str();
|
||||
}
|
||||
MirInstKind::AddLabel { rd, rn, label } => {
|
||||
asm += format!("add {}, {}, :lo12:{}",rd.display(mctx), rn.display(mctx), label.clone().display(mctx)).as_str()
|
||||
}
|
||||
}
|
||||
asm
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for MemLoc {
|
||||
fn display(self, mctx: &MirContext) -> String {
|
||||
let mut asm = String::new();
|
||||
match self {
|
||||
MemLoc::Reg { address } => {
|
||||
asm += format!("[{}]", address.display(mctx)).as_str()
|
||||
}
|
||||
MemLoc::RegOffset { base, offset } => {
|
||||
if offset == 0 {
|
||||
asm += format!("[{}]", base.display(mctx)).as_str()
|
||||
}
|
||||
else{
|
||||
asm += format!("[{}, #{}]", base.display(mctx), offset).as_str()
|
||||
}
|
||||
}
|
||||
MemLoc::Reg2Offset { base, offset } => {
|
||||
if offset.is_address() {
|
||||
asm += format!("[{}, {}]", base.display(mctx), offset.display(mctx)).as_str()
|
||||
} else {
|
||||
asm += format!("[{}, {}, SXTW]", base.display(mctx), offset.display(mctx)).as_str()
|
||||
}
|
||||
}
|
||||
}
|
||||
asm
|
||||
}
|
||||
}
|
||||
|
||||
impl MirContext {
|
||||
pub fn get_asm(&self) -> String {
|
||||
let mut asm = String::new();
|
||||
asm += "\t.arch armv8-a\n\t.text\n";
|
||||
for func_data in self.funcs.iter() {
|
||||
let func = func_data.self_ptr();
|
||||
if func.is_external(self) {
|
||||
continue;
|
||||
}
|
||||
asm += format!("\t.global {}\n", func.label(self).clone().display(self)).as_str();
|
||||
asm += format!("\t.type {}, %function\n", func.label(self).clone().display(self)).as_str();
|
||||
asm += format!("\t.p2align 3\n").as_str();
|
||||
asm += format!("{}:\n", func.label(self).clone().display(self)).as_str();
|
||||
|
||||
for block in func.iter(self) {
|
||||
let block_label = block.label(self).clone().display(self);
|
||||
let clean_label = block_label.trim_start_matches('.');
|
||||
if block != func.head(self).unwrap() {
|
||||
asm += format!("{}:\n", clean_label).as_str();
|
||||
}
|
||||
for inst in block.iter(self) {
|
||||
asm += format!("\t{}\n", inst.display(self)).as_str();
|
||||
}
|
||||
}
|
||||
asm += "\n";
|
||||
}
|
||||
asm += "\n";
|
||||
if !self.raw_data.is_empty() {
|
||||
for (label, raw_data) in self.raw_data.iter() {
|
||||
let label_name = label.clone().display(self);
|
||||
// 全局变量声明
|
||||
match raw_data {
|
||||
RawData::Bytes(bytes,size) => {
|
||||
asm += "\t.section .data\n";
|
||||
asm += "\t.p2align 3\n";
|
||||
asm += format!("\t.global {}\n", label_name).as_str();
|
||||
asm += format!("\t.type {}, %object\n", label_name).as_str();
|
||||
asm += format!("{}:\n", label_name).as_str();
|
||||
// 按4字节分组输出.word
|
||||
for chunk in bytes {
|
||||
asm += format!("\t.word {}\n", chunk).as_str();
|
||||
}
|
||||
// 没有赋值的填zeros
|
||||
if *size > 32 * bytes.len() {
|
||||
asm += format!("\t.zero {}\n", size - 32 * bytes.len()).as_str();
|
||||
}
|
||||
}
|
||||
RawData::Bss(size) => {
|
||||
asm += "\t.section .bss\n";
|
||||
asm += "\t.p2align 3\n";
|
||||
asm += format!("\t.global {}\n", label_name).as_str();
|
||||
asm += format!("\t.type {}, %object\n", label_name).as_str();
|
||||
asm += format!("{}:\n", label_name).as_str();
|
||||
asm += format!("\t.zero {}\n", size).as_str();
|
||||
}
|
||||
}
|
||||
asm += "\n";
|
||||
}
|
||||
}
|
||||
asm
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,128 @@
|
||||
use std::hash::Hash;
|
||||
|
||||
use super::{mir_label::MirLabel,
|
||||
mir_inst::MirInst,
|
||||
mir_function::MirFunction,
|
||||
mir_context::MirContext};
|
||||
use crate::{ utils::{linked_list::{LinkedListContainer, LinkedListNode},
|
||||
storage::{Arena, ArenaPtr, GenericPtr}}};
|
||||
|
||||
pub struct MirBlockData {
|
||||
label: MirLabel,
|
||||
start: Option<MirInst>,
|
||||
end: Option<MirInst>,
|
||||
succ: Option<MirBlock>,
|
||||
pre: Option<MirBlock>,
|
||||
parent: Option<MirFunction>,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct MirBlock(pub GenericPtr<MirBlockData>);
|
||||
|
||||
impl MirBlock {
|
||||
pub fn new(ctx: &mut MirContext, label: impl Into<MirLabel>) -> Self {
|
||||
ctx.alloc(MirBlockData {
|
||||
label: label.into(),
|
||||
start: None,
|
||||
end: None,
|
||||
succ: None,
|
||||
pre: None,
|
||||
parent: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_name(&self, ctx: &MirContext) -> String{
|
||||
self.deref(ctx).expect("Invalid block").label.0.clone()
|
||||
}
|
||||
|
||||
pub fn size(self, arena: &MirContext) -> usize {
|
||||
let mut size = 0;
|
||||
for _ in self.iter(arena) {
|
||||
size += 1;
|
||||
}
|
||||
size
|
||||
}
|
||||
|
||||
pub fn label(self, arena: &MirContext) -> &MirLabel {
|
||||
&self.deref(arena).expect("Invalid block").label
|
||||
}
|
||||
|
||||
pub fn remove(self, arena: &mut MirContext) {
|
||||
self.unlink(arena);
|
||||
arena.dealloc(self).unwrap();
|
||||
}
|
||||
|
||||
pub fn get_head(self, ctx: &MirContext) -> Option<MirInst> {
|
||||
self.deref(ctx).expect("Invalid block").start
|
||||
}
|
||||
|
||||
pub fn get_tail(self, ctx: &MirContext) -> Option<MirInst> {
|
||||
self.deref(ctx).expect("Invalid block").end
|
||||
}
|
||||
|
||||
pub fn is_ret(self, ctx: &MirContext) -> bool {
|
||||
if let Some(inst) = self.get_tail(ctx) {
|
||||
inst.is_ret(ctx);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Hash for MirBlock {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.0.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaPtr for MirBlock {
|
||||
type Arena = MirContext;
|
||||
type Data = MirBlockData;
|
||||
}
|
||||
|
||||
impl LinkedListContainer<MirInst> for MirBlock {
|
||||
type Ctx = MirContext;
|
||||
fn head(self, ctx: &MirContext) -> Option<MirInst> {
|
||||
self.deref(ctx).expect("Invalid Inst").start
|
||||
}
|
||||
fn tail(self, ctx: &MirContext) -> Option<MirInst> {
|
||||
self.deref(ctx).expect("Invalid Inst").end
|
||||
}
|
||||
|
||||
fn set_head(self, ctx: &mut MirContext, start: Option<MirInst>) {
|
||||
self.deref_mut(ctx).expect("Invalid Inst").start = start;
|
||||
}
|
||||
|
||||
fn set_tail(self, ctx: &mut MirContext, end: Option<MirInst>) {
|
||||
self.deref_mut(ctx).expect("Invalid Inst").end = end;
|
||||
}
|
||||
}
|
||||
|
||||
impl LinkedListNode for MirBlock {
|
||||
type Container = MirFunction;
|
||||
type Ctx = MirContext;
|
||||
fn succ(self, ctx: &MirContext) -> Option<Self> {
|
||||
self.deref(ctx).expect("Invaliid Block").succ
|
||||
}
|
||||
|
||||
fn pre(self, ctx: &MirContext) -> Option<Self> {
|
||||
self.deref(ctx).expect("Invaliid Block").pre
|
||||
}
|
||||
|
||||
fn set_succ(self, ctx: &mut MirContext, succ: Option<Self>) {
|
||||
self.deref_mut(ctx).expect("Invaliid Block").succ = succ;
|
||||
}
|
||||
|
||||
fn set_pre(self, ctx: &mut MirContext, pre: Option<Self>) {
|
||||
self.deref_mut(ctx).expect("Invaliid Block").pre = pre;
|
||||
}
|
||||
|
||||
fn container(self, ctx: &MirContext) -> Option<MirFunction> {
|
||||
self.deref(ctx).expect("Invaliid Block").parent
|
||||
}
|
||||
|
||||
fn set_container(self, ctx: &mut MirContext, parent: Option<MirFunction>) {
|
||||
self.deref_mut(ctx).expect("Invaliid Block").parent = parent;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,103 @@
|
||||
use super::{mir_label::MirLabel,
|
||||
mir_block::{MirBlock, MirBlockData},
|
||||
mir_function::{MirFunction, MirFunctionData},
|
||||
mir_inst::{MirInst, MirInstData},
|
||||
regs::{RegKind, VReg},
|
||||
};
|
||||
|
||||
use crate::utils::{storage::{Arena, ArenaPtr, GenericArena}};
|
||||
|
||||
pub enum RawData {
|
||||
Bytes(Vec<i32>, usize),
|
||||
Bss(usize),
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MirContext {
|
||||
pub insts: GenericArena<MirInstData>,
|
||||
pub blocks: GenericArena<MirBlockData>,
|
||||
pub funcs: GenericArena<MirFunctionData>,
|
||||
|
||||
pub raw_data: Vec<(MirLabel, RawData)>,
|
||||
pub vreg_counter: u32,
|
||||
pub arch: String,
|
||||
}
|
||||
|
||||
impl MirContext {
|
||||
pub fn new() -> Self { Self::default() }
|
||||
|
||||
pub fn generate_vreg(&mut self, kind: RegKind) -> VReg {
|
||||
let vreg = VReg::new(self.vreg_counter, kind);
|
||||
self.vreg_counter += 1;
|
||||
vreg
|
||||
}
|
||||
|
||||
pub fn add_raw_data(&mut self, label: impl Into<MirLabel>, data: RawData) {
|
||||
self.raw_data.push((label.into(), data));
|
||||
}
|
||||
|
||||
pub fn get_functions(&self) -> impl Iterator<Item = MirFunction> + '_ {
|
||||
self.funcs.iter().map(|data| data.self_ptr() )
|
||||
}
|
||||
}
|
||||
|
||||
impl Arena<MirBlock> for MirContext {
|
||||
fn alloc_with<F>(&mut self, f: F) -> MirBlock
|
||||
where
|
||||
F: FnOnce(MirBlock) -> MirBlockData,
|
||||
{
|
||||
MirBlock(self.blocks.alloc_with(|p| f(MirBlock(p))))
|
||||
}
|
||||
|
||||
fn deref(&self, ptr: MirBlock) -> Option<&MirBlockData> {
|
||||
self.blocks.deref(ptr.0)
|
||||
}
|
||||
|
||||
fn deref_mut(&mut self, ptr: MirBlock) -> Option<&mut MirBlockData> {
|
||||
self.blocks.deref_mut(ptr.0)
|
||||
}
|
||||
|
||||
fn dealloc(&mut self, ptr: MirBlock) -> Option<MirBlockData> {
|
||||
self.blocks.dealloc(ptr.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Arena<MirFunction> for MirContext {
|
||||
fn alloc_with<F>(&mut self, f: F) -> MirFunction
|
||||
where
|
||||
F: FnOnce(MirFunction) -> MirFunctionData,
|
||||
{
|
||||
MirFunction(self.funcs.alloc_with(|p| f(MirFunction(p))))
|
||||
}
|
||||
|
||||
fn deref(&self, ptr: MirFunction) -> Option<&MirFunctionData> { self.funcs.deref(ptr.0) }
|
||||
|
||||
fn deref_mut(&mut self, ptr: MirFunction) -> Option<&mut MirFunctionData> {
|
||||
self.funcs.deref_mut(ptr.0)
|
||||
}
|
||||
|
||||
fn dealloc(&mut self, ptr: MirFunction) -> Option<<MirFunction as ArenaPtr>::Data> {
|
||||
self.funcs.dealloc(ptr.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Arena<MirInst> for MirContext {
|
||||
fn alloc_with<F>(&mut self, f: F) -> MirInst
|
||||
where
|
||||
F: FnOnce(MirInst) -> MirInstData,
|
||||
{
|
||||
MirInst(self.insts.alloc_with(|p| f(MirInst(p))))
|
||||
}
|
||||
|
||||
fn deref(&self, ptr: MirInst) -> Option<&MirInstData> {
|
||||
self.insts.deref(ptr.0)
|
||||
}
|
||||
|
||||
fn deref_mut(&mut self, ptr: MirInst) -> Option<&mut MirInstData> {
|
||||
self.insts.deref_mut(ptr.0)
|
||||
}
|
||||
|
||||
fn dealloc(&mut self, ptr: MirInst) -> Option<MirInstData> {
|
||||
self.insts.dealloc(ptr.0)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,142 @@
|
||||
use std::collections::BTreeSet;
|
||||
use std::hash::Hash;
|
||||
|
||||
use super::{mir_label::MirLabel,
|
||||
mir_block::MirBlock,
|
||||
mir_context::MirContext,
|
||||
regs::PReg};
|
||||
use crate::utils::{linked_list::LinkedListContainer,
|
||||
storage::{Arena, ArenaPtr, GenericPtr}};
|
||||
|
||||
pub struct MirFunctionData {
|
||||
self_ptr: MirFunction,
|
||||
label: MirLabel,
|
||||
storage_stack_size: i32,
|
||||
current_stack_size: i32,
|
||||
calleeargs_stack_size: i32,
|
||||
callee_regs: BTreeSet<PReg>,
|
||||
is_external: bool,
|
||||
start: Option<MirBlock>,
|
||||
end: Option<MirBlock>,
|
||||
}
|
||||
|
||||
impl MirFunctionData {
|
||||
pub fn self_ptr(&self) -> MirFunction { self.self_ptr }
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct MirFunction(pub GenericPtr<MirFunctionData>);
|
||||
|
||||
impl MirFunction {
|
||||
pub fn new(ctx: &mut MirContext, label: impl Into<MirLabel>, is_external: bool) -> Self {
|
||||
ctx.alloc_with(|self_ptr| MirFunctionData {
|
||||
self_ptr,
|
||||
label: label.into(),
|
||||
storage_stack_size: 0,
|
||||
current_stack_size: 0,
|
||||
calleeargs_stack_size: 0,
|
||||
callee_regs: BTreeSet::default(),
|
||||
is_external,
|
||||
start: None,
|
||||
end: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn label(self, arena: &MirContext) -> &MirLabel {
|
||||
&self.deref(arena).expect("Invalid Function Pointer").label
|
||||
}
|
||||
|
||||
pub fn get_id(self, ctx: &MirContext) -> String {
|
||||
self.label(ctx).0.clone()
|
||||
}
|
||||
|
||||
pub fn get_head(self, ctx: &MirContext) -> Option<MirBlock> {
|
||||
self.deref(ctx).expect("Invalid Function Pointer").start
|
||||
}
|
||||
|
||||
pub fn get_tail(self, ctx: &MirContext) -> Option<MirBlock> {
|
||||
self.deref(ctx).expect("Invalid Function Pointer").end
|
||||
}
|
||||
|
||||
pub fn is_external(self, ctx: &MirContext) -> bool {
|
||||
self.deref(ctx).expect("Invalid Function Pointer").is_external
|
||||
}
|
||||
|
||||
pub fn current_stack_size(self, ctx: &MirContext) -> i32 {
|
||||
self.deref(ctx).expect("Invalid Function Pointer").current_stack_size
|
||||
}
|
||||
|
||||
pub fn add_current_stack_size(self, ctx: &mut MirContext, size: i32) {
|
||||
self.deref_mut(ctx).expect("Invalid Function Pointer").current_stack_size += size;
|
||||
}
|
||||
|
||||
pub fn storage_stack_size(self, ctx: &MirContext) -> i32 {
|
||||
self.deref(ctx).expect("Invalid Function Pointer").storage_stack_size
|
||||
}
|
||||
|
||||
|
||||
pub fn add_storage_stack_size(self, ctx: &mut MirContext, size: i32) {
|
||||
self.deref_mut(ctx).expect("Invalid Function Pointer").storage_stack_size += size;
|
||||
}
|
||||
|
||||
pub fn add_calleeargs_stack_size(self, ctx: &mut MirContext, size: i32) {
|
||||
self.deref_mut(ctx).expect("Invalid Function Pointer").calleeargs_stack_size += size;
|
||||
}
|
||||
|
||||
pub fn calleeargs_stack_size(self, ctx: &MirContext) -> i32 {
|
||||
self.deref(ctx).expect("Invalid Function Pointer").calleeargs_stack_size
|
||||
}
|
||||
|
||||
pub fn callee_regs(self, ctx: &MirContext) -> Vec<PReg> {
|
||||
let mut regs: Vec<PReg> = self.deref(ctx).expect("Invalid Function Pointer").callee_regs.iter().copied().collect();
|
||||
regs.sort();
|
||||
regs
|
||||
}
|
||||
|
||||
pub fn add_callee_reg(self, ctx: &mut MirContext, reg: PReg) {
|
||||
self.deref_mut(ctx).expect("Invalid Function Pointer").callee_regs.insert(reg);
|
||||
}
|
||||
|
||||
pub fn callee_stack_size(self, ctx: &MirContext) -> i32 {
|
||||
let mut size = 0;
|
||||
for _reg in self.callee_regs(ctx) {
|
||||
size += 8;
|
||||
}
|
||||
if size % 8 != 0 {
|
||||
size += 4;
|
||||
}
|
||||
size
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaPtr for MirFunction {
|
||||
type Arena = MirContext;
|
||||
type Data = MirFunctionData;
|
||||
}
|
||||
|
||||
impl LinkedListContainer<MirBlock> for MirFunction {
|
||||
type Ctx = MirContext;
|
||||
fn head(self, ctx: &Self::Ctx) -> Option<MirBlock> { self.deref(ctx).expect("Invalid Function Pointer").start }
|
||||
|
||||
fn tail(self, ctx: &Self::Ctx) -> Option<MirBlock> { self.deref(ctx).expect("Invalid Function Pointer").end }
|
||||
|
||||
fn set_head(self, ctx: &mut Self::Ctx, start: Option<MirBlock>) {
|
||||
self.deref_mut(ctx).expect("Invalid Function Pointer").start = start;
|
||||
}
|
||||
|
||||
fn set_tail(self, ctx: &mut Self::Ctx, end: Option<MirBlock>) {
|
||||
self.deref_mut(ctx).expect("Invalid Function Pointer").end = end;
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for MirFunction {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
|
||||
impl Copy for MirFunction {}
|
||||
|
||||
impl Hash for MirFunction {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.0.hash(state)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,503 @@
|
||||
|
||||
use super::{
|
||||
mir_block::MirBlock,
|
||||
mir_context::MirContext,
|
||||
mir_operand::MemLoc,
|
||||
regs::Reg,
|
||||
};
|
||||
use crate::{ backend::mir::mir_label::MirLabel, utils::{
|
||||
linked_list::{LinkedListContainer, LinkedListError, LinkedListNode},
|
||||
storage::{Arena, ArenaPtr, GenericPtr},
|
||||
}};
|
||||
|
||||
pub enum MirInstKind {
|
||||
// 二元指令
|
||||
Add { rd: Reg, rn: Reg, rm: Reg }, // 加法
|
||||
Addi { rd: Reg, rn: Reg, imm: i32 },
|
||||
Subi {rd: Reg, rn: Reg, imm: i32},
|
||||
|
||||
// 内存操作指令
|
||||
Str { rm: Reg, mem: MemLoc }, // 存储到内存
|
||||
Ldr { rd: Reg, mem: MemLoc }, // 从内存加载
|
||||
|
||||
// 移动指令
|
||||
Movz { rd: Reg, imm: i32},
|
||||
Movk { rd: Reg, imm: i32},
|
||||
MovReg {rd: Reg, rn: Reg}, // 寄存器移动
|
||||
|
||||
// 分支指令
|
||||
B { target: MirBlock }, // 无条件分支
|
||||
Ret, // 函数返回
|
||||
|
||||
Adrp {rd: Reg, label: MirLabel}, // 加载全局变量标签
|
||||
AddLabel {rd: Reg, rn: Reg, label: MirLabel},
|
||||
}
|
||||
|
||||
pub struct MirInstData {
|
||||
pub kind: MirInstKind,
|
||||
pub succ: Option<MirInst>,
|
||||
pub pre: Option<MirInst>,
|
||||
pub parent: Option<MirBlock>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct MirInst(pub GenericPtr<MirInstData>);
|
||||
|
||||
impl MirInst {
|
||||
pub fn add(ctx: &mut MirContext, rd: Reg, rn: Reg, rm: Reg) -> Self {
|
||||
let kind = MirInstKind::Add { rd, rn, rm };
|
||||
let data = MirInstData {
|
||||
kind,
|
||||
succ: None,
|
||||
pre: None,
|
||||
parent: None,
|
||||
};
|
||||
ctx.alloc(data)
|
||||
}
|
||||
|
||||
pub fn addi(ctx: &mut MirContext, rd: Reg, rn: Reg, imm: i32) -> Self {
|
||||
let kind = MirInstKind::Addi { rd, rn, imm };
|
||||
let data = MirInstData {
|
||||
kind,
|
||||
succ: None,
|
||||
pre: None,
|
||||
parent: None,
|
||||
};
|
||||
ctx.alloc(data)
|
||||
}
|
||||
|
||||
pub fn subi(ctx: &mut MirContext, rd: Reg, rn: Reg, imm: i32) -> Self {
|
||||
let kind = MirInstKind::Subi { rd, rn, imm };
|
||||
let data = MirInstData {
|
||||
kind,
|
||||
succ: None,
|
||||
pre: None,
|
||||
parent: None,
|
||||
};
|
||||
ctx.alloc(data)
|
||||
}
|
||||
|
||||
pub fn str(ctx: &mut MirContext, rm: Reg, mem: MemLoc) -> Self {
|
||||
let kind = MirInstKind::Str { rm, mem};
|
||||
let data = MirInstData {
|
||||
kind,
|
||||
succ: None,
|
||||
pre: None,
|
||||
parent: None,
|
||||
};
|
||||
ctx.alloc(data)
|
||||
}
|
||||
|
||||
pub fn ldr(ctx: &mut MirContext, rd: Reg, mem: MemLoc) -> Self {
|
||||
let kind = MirInstKind::Ldr { rd, mem };
|
||||
let data = MirInstData {
|
||||
kind,
|
||||
succ: None,
|
||||
pre: None,
|
||||
parent: None,
|
||||
};
|
||||
ctx.alloc(data)
|
||||
}
|
||||
|
||||
pub fn movz(ctx: &mut MirContext, rd: Reg, imm: i32) -> Self {
|
||||
let kind = MirInstKind::Movz { rd, imm};
|
||||
let data = MirInstData {
|
||||
kind,
|
||||
succ: None,
|
||||
pre: None,
|
||||
parent: None,
|
||||
};
|
||||
ctx.alloc(data)
|
||||
}
|
||||
|
||||
pub fn movk(ctx: &mut MirContext, rd: Reg, imm: i32) -> Self {
|
||||
let kind = MirInstKind::Movk { rd, imm};
|
||||
let data = MirInstData {
|
||||
kind,
|
||||
succ: None,
|
||||
pre: None,
|
||||
parent: None,
|
||||
};
|
||||
ctx.alloc(data)
|
||||
}
|
||||
|
||||
pub fn b(ctx: &mut MirContext, target: MirBlock) -> Self {
|
||||
let kind = MirInstKind::B { target };
|
||||
let data = MirInstData {
|
||||
kind,
|
||||
succ: None,
|
||||
pre: None,
|
||||
parent: None,
|
||||
};
|
||||
ctx.alloc(data)
|
||||
}
|
||||
|
||||
pub fn ret(ctx: &mut MirContext) -> Self {
|
||||
let kind = MirInstKind::Ret;
|
||||
let data = MirInstData {
|
||||
kind,
|
||||
succ: None,
|
||||
pre: None,
|
||||
parent: None,
|
||||
};
|
||||
ctx.alloc(data)
|
||||
}
|
||||
|
||||
pub fn adrp(ctx: &mut MirContext, rd: Reg, label: MirLabel) -> Self {
|
||||
let kind = MirInstKind::Adrp { rd, label };
|
||||
let data = MirInstData {
|
||||
kind,
|
||||
succ: None,
|
||||
pre: None,
|
||||
parent: None,
|
||||
};
|
||||
ctx.alloc(data)
|
||||
}
|
||||
|
||||
pub fn add_label(ctx: &mut MirContext, rd: Reg, rn: Reg, label: MirLabel) -> Self {
|
||||
let kind = MirInstKind::AddLabel { rd, rn, label };
|
||||
let data = MirInstData {
|
||||
kind,
|
||||
succ: None,
|
||||
pre: None,
|
||||
parent: None,
|
||||
};
|
||||
ctx.alloc(data)
|
||||
}
|
||||
|
||||
pub fn mov_reg(ctx: &mut MirContext, rd: Reg, rn: Reg) -> Self {
|
||||
let kind = MirInstKind::MovReg { rd, rn };
|
||||
let data = MirInstData {
|
||||
kind,
|
||||
succ: None,
|
||||
pre: None,
|
||||
parent: None,
|
||||
};
|
||||
ctx.alloc(data)
|
||||
}
|
||||
|
||||
pub fn uses(self, mctx: &MirContext) -> Vec<Reg> {
|
||||
match &self.deref(mctx).unwrap().kind {
|
||||
MirInstKind::Add { rd:_, rn, rm } => vec![*rn, *rm],
|
||||
MirInstKind::Addi {rd:_, rn, imm:_} | MirInstKind::Subi {rd:_, rn, imm:_} => vec![*rn],
|
||||
MirInstKind::Ldr { mem, .. } => match mem {
|
||||
MemLoc::Reg { address} => vec![*address],
|
||||
MemLoc::RegOffset { base, .. } => vec![*base],
|
||||
MemLoc::Reg2Offset { base, offset } => vec![*base, *offset],
|
||||
}
|
||||
MirInstKind::Str { rm, mem, .. } => {
|
||||
let mut uses = vec![*rm];
|
||||
match mem {
|
||||
MemLoc::Reg { address} => uses.push(*address),
|
||||
MemLoc::RegOffset { base, .. } => uses.push(*base),
|
||||
MemLoc::Reg2Offset { base, offset } => {
|
||||
uses.push(*base);
|
||||
uses.push(*offset);
|
||||
},
|
||||
}
|
||||
uses
|
||||
}
|
||||
MirInstKind::Movk { rd, imm:_ } => vec![*rd],
|
||||
MirInstKind::MovReg { rd:_, rn } => vec![*rn],
|
||||
MirInstKind::Movz { .. } => vec![],
|
||||
MirInstKind::B { .. } => vec![],
|
||||
MirInstKind::Ret => vec![],
|
||||
MirInstKind::Adrp { .. } => vec![],
|
||||
MirInstKind::AddLabel { rn, ..} => vec![*rn],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn def(self, mctx: &MirContext) -> Vec<Reg> {
|
||||
match &self.deref(mctx).unwrap().kind {
|
||||
MirInstKind::Add { rd, rn:_, rm:_ } => vec![*rd],
|
||||
MirInstKind::Addi {rd, rn:_, imm:_} | MirInstKind::Subi {rd, rn:_, imm:_} => vec![*rd],
|
||||
MirInstKind::Ldr { rd, .. } => vec![*rd],
|
||||
MirInstKind::Str { .. } => vec![],
|
||||
MirInstKind::Movz { rd, imm:_ } => vec![*rd],
|
||||
MirInstKind::Movk { rd, imm:_ } => vec![*rd],
|
||||
MirInstKind::MovReg { rd, rn:_ } => vec![*rd],
|
||||
MirInstKind::B { ..} => vec![],
|
||||
MirInstKind::Ret => vec![],
|
||||
MirInstKind::Adrp { rd, .. } => vec![*rd],
|
||||
MirInstKind::AddLabel{ rd, .. } => vec![*rd],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_regs(self, mctx: &MirContext) -> Vec<Reg> {
|
||||
match &self.deref(mctx).unwrap().kind {
|
||||
MirInstKind::Add { rd, rn, rm } => vec![*rd, *rn, *rm],
|
||||
MirInstKind::Addi {rd, rn, imm:_} | MirInstKind::Subi {rd, rn, imm:_}=> vec![*rd,*rn],
|
||||
MirInstKind::Ldr { rd, mem } => match mem {
|
||||
MemLoc::Reg { address } => vec![*rd, *address],
|
||||
MemLoc::RegOffset { base, .. } => vec![*rd, *base],
|
||||
MemLoc::Reg2Offset { base, offset } => vec![*rd, *base, *offset],
|
||||
}
|
||||
MirInstKind::Str { rm, mem } => {
|
||||
let mut regs = vec![*rm];
|
||||
match mem {
|
||||
MemLoc::Reg { address } => regs.push(*address),
|
||||
MemLoc::RegOffset { base, .. } => regs.push(*base),
|
||||
MemLoc::Reg2Offset { base, offset } => {
|
||||
regs.push(*base);
|
||||
regs.push(*offset);
|
||||
},
|
||||
}
|
||||
regs
|
||||
}
|
||||
MirInstKind::Movz { rd, .. } => vec![*rd],
|
||||
MirInstKind::Movk { rd, .. } => vec![*rd],
|
||||
MirInstKind::MovReg { rd, rn } => vec![*rd, *rn],
|
||||
MirInstKind::B { .. } => vec![],
|
||||
MirInstKind::Ret => vec![],
|
||||
MirInstKind::Adrp { rd, .. } => vec![*rd],
|
||||
MirInstKind::AddLabel { rd, rn, .. } => vec![*rd, *rn],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn replace_regs(self, mctx: &mut MirContext, from: Reg, to: Reg) {
|
||||
match &mut self.deref_mut(mctx).unwrap().kind {
|
||||
MirInstKind::Ldr { rd, mem } => {
|
||||
if *rd == from {
|
||||
*rd = to;
|
||||
}
|
||||
match mem {
|
||||
MemLoc::Reg { address } => {
|
||||
if *address == from {
|
||||
*address = to;
|
||||
}
|
||||
}
|
||||
MemLoc::RegOffset { base, .. } => {
|
||||
if *base == from {
|
||||
*base = to;
|
||||
}
|
||||
}
|
||||
MemLoc::Reg2Offset { base, offset } => {
|
||||
if *base == from {
|
||||
*base = to;
|
||||
}
|
||||
if *offset == from {
|
||||
*offset = to;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MirInstKind::Str { rm, mem } => {
|
||||
if *rm == from {
|
||||
*rm = to;
|
||||
}
|
||||
match mem {
|
||||
MemLoc::Reg { address } => {
|
||||
if *address == from {
|
||||
*address = to;
|
||||
}
|
||||
}
|
||||
MemLoc::RegOffset { base, .. } => {
|
||||
if *base == from {
|
||||
*base = to;
|
||||
}
|
||||
}
|
||||
MemLoc::Reg2Offset { base, offset } => {
|
||||
if *base == from {
|
||||
*base = to;
|
||||
}
|
||||
if *offset == from {
|
||||
*offset = to;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MirInstKind::Movz { rd, .. } => {
|
||||
if *rd == from {
|
||||
*rd = to;
|
||||
}
|
||||
}
|
||||
MirInstKind::Movk { rd, .. } => {
|
||||
if *rd == from {
|
||||
*rd = to;
|
||||
}
|
||||
}
|
||||
MirInstKind::MovReg { rd, rn } => {
|
||||
if *rd == from {
|
||||
*rd = to;
|
||||
}
|
||||
if *rn == from {
|
||||
*rn = to;
|
||||
}
|
||||
}
|
||||
MirInstKind::Add { rd, rn, rm } => {
|
||||
if *rd == from {
|
||||
*rd = to;
|
||||
}
|
||||
if *rn == from {
|
||||
*rn = to;
|
||||
}
|
||||
if *rm == from {
|
||||
*rm = to;
|
||||
}
|
||||
}
|
||||
MirInstKind::Addi {rd, rn, imm:_} | MirInstKind::Subi {rd, rn, imm:_}=> {
|
||||
if *rd == from {
|
||||
*rd = to;
|
||||
}
|
||||
if *rn == from {
|
||||
*rn = to;
|
||||
}
|
||||
}
|
||||
MirInstKind::B { .. } => {},
|
||||
MirInstKind::Ret => {},
|
||||
MirInstKind::Adrp { rd, .. } => {
|
||||
if *rd == from {
|
||||
*rd = to;
|
||||
}
|
||||
}
|
||||
MirInstKind::AddLabel { rd, rn, ..} => {
|
||||
if *rd == from {
|
||||
*rd = to;
|
||||
}
|
||||
if *rn == from {
|
||||
*rn = to;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MirInst {
|
||||
pub fn kind(self, ctx: &MirContext) -> &MirInstKind {
|
||||
&self.deref(ctx).expect("Invalid Inst").kind
|
||||
}
|
||||
|
||||
pub fn kind_mut(self, ctx: &mut MirContext) -> &mut MirInstKind {
|
||||
&mut self.deref_mut(ctx).expect("Invalid Inst").kind
|
||||
}
|
||||
|
||||
pub fn is_br(self, ctx: &MirContext) -> bool {
|
||||
match self.kind(ctx) {
|
||||
MirInstKind::B { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_ret(self, ctx: &MirContext) -> bool {
|
||||
match self.kind(ctx) {
|
||||
MirInstKind::Ret { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_branch(self, ctx: &MirContext) -> bool {
|
||||
match self.kind(ctx) {
|
||||
MirInstKind::B { .. } | // 无条件分支
|
||||
MirInstKind::Ret { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_load(self, ctx: &MirContext) -> bool {
|
||||
match self.kind(ctx) {
|
||||
MirInstKind::Ldr { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_store(self, ctx: &MirContext) -> bool {
|
||||
match self.kind(ctx) {
|
||||
MirInstKind::Str { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_memory(self, ctx: &MirContext) -> bool {
|
||||
return self.is_load(ctx) || self.is_store(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaPtr for MirInst {
|
||||
type Arena = MirContext;
|
||||
type Data = MirInstData;
|
||||
}
|
||||
|
||||
impl LinkedListNode for MirInst {
|
||||
type Container = MirBlock;
|
||||
type Ctx = MirContext;
|
||||
fn succ(self, ctx: &Self::Ctx) -> Option<Self> { self.deref(ctx).expect("Invalid Inst").succ }
|
||||
|
||||
fn pre(self, ctx: &Self::Ctx) -> Option<Self> { self.deref(ctx).expect("Invalid Inst").pre }
|
||||
|
||||
fn set_succ(self, arena: &mut Self::Ctx, succ: Option<Self>) {
|
||||
self.deref_mut(arena).expect("Invalid Inst").succ = succ;
|
||||
}
|
||||
|
||||
fn set_pre(self, arena: &mut Self::Ctx, pre: Option<Self>) {
|
||||
self.deref_mut(arena).expect("Invalid Inst").pre = pre;
|
||||
}
|
||||
|
||||
fn container(self, ctx: &Self::Ctx) -> Option<Self::Container> { self.deref(ctx).expect("Invalid Inst").parent }
|
||||
|
||||
fn set_container(self, arena: &mut Self::Ctx, parent: Option<Self::Container>) {
|
||||
self.deref_mut(arena).expect("Invalid Inst").parent = parent;
|
||||
}
|
||||
|
||||
fn insert_after(self, ctx: &mut Self::Ctx, node: Self) -> Result<(), LinkedListError<Self>> {
|
||||
if self.container(ctx).is_none() {
|
||||
return Err(LinkedListError::CurrentNodeNotLinked(self));
|
||||
}
|
||||
|
||||
if node.container(ctx).is_some() {
|
||||
return Err(LinkedListError::NodeAlreadyInContainer(node));
|
||||
}
|
||||
|
||||
if let Some(succ) = self.succ(ctx) {
|
||||
succ.set_pre(ctx, Some(node));
|
||||
node.set_succ(ctx, Some(succ));
|
||||
}
|
||||
|
||||
node.set_pre(ctx, Some(self));
|
||||
self.set_succ(ctx, Some(node));
|
||||
|
||||
match self.container(ctx) {
|
||||
Some(container) => {
|
||||
if container.tail(ctx) == Some(self) {
|
||||
container.set_tail(ctx, Some(node));
|
||||
}
|
||||
}
|
||||
None => unreachable!(),
|
||||
}
|
||||
node.set_container(ctx, self.container(ctx));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn insert_before(self, ctx: &mut Self::Ctx, node: Self) -> Result<(), LinkedListError<Self>> {
|
||||
if self.container(ctx).is_none() {
|
||||
return Err(LinkedListError::CurrentNodeNotLinked(self));
|
||||
}
|
||||
|
||||
if node.container(ctx).is_some() {
|
||||
return Err(LinkedListError::NodeAlreadyInContainer(node));
|
||||
}
|
||||
|
||||
if let Some(pre) = self.pre(ctx) {
|
||||
pre.set_succ(ctx, Some(node));
|
||||
node.set_pre(ctx, Some(pre));
|
||||
}
|
||||
|
||||
node.set_succ(ctx, Some(self));
|
||||
self.set_pre(ctx, Some(node));
|
||||
|
||||
match self.container(ctx) {
|
||||
Some(container) => {
|
||||
if container.head(ctx) == Some(self) {
|
||||
container.set_head(ctx, Some(node));
|
||||
}
|
||||
}
|
||||
None => unreachable!(),
|
||||
}
|
||||
|
||||
node.set_container(ctx, self.container(ctx));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
use std::hash::Hash;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MirLabel( pub String);
|
||||
|
||||
impl MirLabel {
|
||||
pub fn new(name: String) -> Self { Self(name) }
|
||||
}
|
||||
|
||||
impl PartialEq for MirLabel {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for MirLabel {}
|
||||
|
||||
impl Hash for MirLabel {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.0.hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for MirLabel
|
||||
where
|
||||
T: AsRef<str>,
|
||||
{
|
||||
fn from(value: T) -> Self { Self(value.as_ref().to_string()) }
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
use super::regs::Reg;
|
||||
use crate::frontend::ir;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum MirOperandKind {
|
||||
Mem(MemLoc),
|
||||
Reg(Reg),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct MirOperand {
|
||||
pub(crate) typ: ir::typ::Typ,
|
||||
pub(crate) kind: MirOperandKind,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum MemLoc {
|
||||
/// 地址在寄存器
|
||||
Reg { address: Reg },
|
||||
/// 基地址在寄存器,偏移位立即数
|
||||
RegOffset { base: Reg, offset: i32 },
|
||||
/// 基地址和偏移位都在寄存器(全局数组)
|
||||
Reg2Offset { base: Reg, offset: Reg },
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
pub mod regs;
|
||||
pub mod mir_operand;
|
||||
pub mod mir_block;
|
||||
pub mod mir_context;
|
||||
pub mod mir_label;
|
||||
pub mod mir_function;
|
||||
pub mod mir_inst;
|
||||
@ -0,0 +1,12 @@
|
||||
pub mod mir;
|
||||
pub mod mirgen;
|
||||
pub mod asm2string;
|
||||
pub mod regalloc;
|
||||
|
||||
pub fn mirgen( ir: &mut crate::frontend::ir::context::Context ) -> mir::mir_context::MirContext{
|
||||
let mut mirgen_context = mirgen::MirgenContext::new(&ir);
|
||||
mirgen_context.mirgen();
|
||||
let mut mctx = mirgen_context.mircontext();
|
||||
regalloc::naive_alloc::regalloc(&mut mctx);
|
||||
mctx
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
pub mod naive_alloc;
|
||||
@ -0,0 +1,228 @@
|
||||
use std::{array, collections::{HashMap, HashSet}};
|
||||
|
||||
use crate::{backend::mir::{
|
||||
mir_context::MirContext,
|
||||
mir_function::MirFunction,
|
||||
mir_inst::MirInst,
|
||||
mir_operand::MemLoc,
|
||||
regs::{self, Reg},
|
||||
}, utils::linked_list::{LinkedListContainer, LinkedListNode}};
|
||||
|
||||
pub fn allocate_reg(_mctx: &mut MirContext, _vreg: regs::VReg, candidates: &[regs::PReg], hw_reg_used: &mut [bool]) -> Option<regs::PReg> {
|
||||
for &preg in candidates {
|
||||
let index = preg.hw_index() as usize;
|
||||
if !hw_reg_used[index] {
|
||||
hw_reg_used[index] = true;
|
||||
return Some(preg);
|
||||
}
|
||||
}
|
||||
None
|
||||
|
||||
}
|
||||
|
||||
pub fn regalloc(mctx: &mut MirContext) {
|
||||
// 硬件寄存器状态(9-15和19-28可以用来分配)
|
||||
let hw_reg_used: [bool; 29] = array::from_fn(|i| {
|
||||
!((9..=14).contains(&i) || (19..=28).contains(&i))
|
||||
});
|
||||
let integer_candidates = vec![
|
||||
regs::w19(), regs::w20(), regs::w21(), regs::w22(), regs::w23(), regs::w24(), regs::w25(), regs::w26(), regs::w27(), regs::w28(),
|
||||
regs::w9(), regs::w10(), regs::w11(), regs::w12(), regs::w13(), regs::w14(), regs::w15(), regs::w16(), regs::w17(),
|
||||
];
|
||||
let address_candidates = vec![
|
||||
regs::x19(), regs::x20(), regs::x21(), regs::x22(), regs::x23(), regs::x24(), regs::x25(), regs::x26(), regs::x27(), regs::x28(),
|
||||
regs::x9(), regs::x10(), regs::x11(), regs::x12(), regs::x13(), regs::x14(), regs::x15(), regs::x16(), regs::x17(),
|
||||
];
|
||||
// 预先收集所有函数的信息
|
||||
let mut func_info = Vec::new();
|
||||
for func_data in mctx.funcs.iter() {
|
||||
let function = func_data.self_ptr();
|
||||
if function.is_external(mctx) {
|
||||
continue;
|
||||
}
|
||||
let mut all_vregs = HashSet::new();
|
||||
|
||||
// 使用不可变借用收集虚拟寄存器
|
||||
{
|
||||
for block in function.iter(&mctx) {
|
||||
for inst in block.iter(&mctx) {
|
||||
let mut collect_reg = |reg: Reg| {
|
||||
if let Reg::V(vreg) = reg {
|
||||
all_vregs.insert(vreg);
|
||||
}
|
||||
};
|
||||
let cur_regs = inst.all_regs(&mctx);
|
||||
for reg in cur_regs {
|
||||
collect_reg(reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
func_info.push((function, all_vregs));
|
||||
}
|
||||
// 现在使用可变借用来处理每个函数
|
||||
for (function, all_vregs) in func_info {
|
||||
let curr_func = Some(function);
|
||||
let mut reg_map = HashMap::new();
|
||||
let mut spill_map = HashMap::new();
|
||||
let mut available_regs = hw_reg_used.clone();
|
||||
let mut spilled_registers = HashSet::new();
|
||||
|
||||
let mut use_count = HashMap::new();
|
||||
for block in function.iter(mctx) {
|
||||
for inst in block.iter(mctx) {
|
||||
for reg in inst.uses(mctx) {
|
||||
if let Reg::V(vreg) = reg {
|
||||
*use_count.entry(vreg).or_insert(0) += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut sorted_vregs: Vec<_> = all_vregs.iter().collect();
|
||||
// 使用频率降序排除
|
||||
sorted_vregs.sort_by(|a,b| use_count.get(b).cmp(&use_count.get(a)));
|
||||
|
||||
// 分配物理寄存器
|
||||
for &vreg in &sorted_vregs {
|
||||
let preg = match vreg.kind() {
|
||||
regs::RegKind::Integer => allocate_reg(mctx, *vreg, &integer_candidates, &mut available_regs),
|
||||
regs::RegKind::Address => allocate_reg(mctx, *vreg, &address_candidates, &mut available_regs),
|
||||
};
|
||||
if let Some(preg) = preg {
|
||||
reg_map.insert(vreg, preg);
|
||||
} else {
|
||||
spilled_registers.insert(vreg);
|
||||
}
|
||||
}
|
||||
for ® in &spilled_registers {
|
||||
let e = match reg.kind() {
|
||||
regs::RegKind::Integer => 4,
|
||||
_ => 8
|
||||
};
|
||||
let cur_stack = curr_func.unwrap().storage_stack_size(mctx) + curr_func.unwrap().calleeargs_stack_size(mctx);
|
||||
spill_map.insert(reg, cur_stack);
|
||||
curr_func.unwrap().add_storage_stack_size(mctx, e);
|
||||
}
|
||||
// 处理每条指令的溢出
|
||||
curr_func.unwrap().add_storage_stack_size(mctx, 19*8+24*4);
|
||||
let mut curr_block = function.head(mctx);
|
||||
while let Some(block) = curr_block {
|
||||
let mut curr_inst = block.head(mctx);
|
||||
while let Some(inst) = curr_inst {
|
||||
let next_inst = inst.succ(mctx);
|
||||
// 处理源操作数(uses)
|
||||
let mut spill_reg_index = 0;
|
||||
for reg in inst.uses(mctx) {
|
||||
if let Reg::V(vreg) = reg {
|
||||
if let Some(spill_slot) = spill_map.get(&vreg) {
|
||||
let spill_reg = if spill_reg_index == 0 {
|
||||
match vreg.kind() {
|
||||
regs::RegKind::Address => regs::x15().into(),
|
||||
regs::RegKind::Integer => regs::w15().into(),
|
||||
}
|
||||
} else if spill_reg_index == 1{
|
||||
match vreg.kind() {
|
||||
regs::RegKind::Address => regs::x16().into(),
|
||||
regs::RegKind::Integer => regs::w16().into(),
|
||||
_ => todo!(),
|
||||
}
|
||||
} else {
|
||||
match vreg.kind() {
|
||||
regs::RegKind::Address => regs::x17().into(),
|
||||
regs::RegKind::Integer => regs::w17().into(),
|
||||
_ => todo!(),
|
||||
}
|
||||
};
|
||||
spill_reg_index += 1;
|
||||
|
||||
let spill_offset = *spill_slot;
|
||||
generate_spill_load(
|
||||
mctx,
|
||||
spill_reg,
|
||||
MemLoc::RegOffset { base: regs::sp().into(), offset: spill_offset },
|
||||
inst
|
||||
);
|
||||
// 即使目的操作数也是源操作数
|
||||
let flag = if inst.def(mctx).contains(®) {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
inst.replace_regs(mctx, Reg::V(vreg), spill_reg);
|
||||
if flag {
|
||||
generate_spill_store(
|
||||
mctx,
|
||||
spill_reg,
|
||||
MemLoc::RegOffset { base: regs::sp().into(), offset: spill_offset },
|
||||
inst
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 处理目标操作数(defs)
|
||||
for reg in inst.def(mctx) {
|
||||
if let Reg::V(vreg) = reg {
|
||||
if let Some(spill_slot) = spill_map.get(&vreg) {
|
||||
let spill_reg = match vreg.kind() {
|
||||
regs::RegKind::Address => regs::x15().into(),
|
||||
regs::RegKind::Integer => regs::w15().into(),
|
||||
};
|
||||
let spill_offset = *spill_slot;
|
||||
inst.replace_regs(mctx, Reg::V(vreg), spill_reg);
|
||||
generate_spill_store(
|
||||
mctx,
|
||||
spill_reg,
|
||||
MemLoc::RegOffset { base: regs::sp().into(), offset: spill_offset },
|
||||
inst
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 替换非溢出的虚拟寄存器和调整偏移
|
||||
for reg in inst.all_regs(mctx) {
|
||||
if let Reg::V(vreg) = reg {
|
||||
if let Some(allocated_reg) = reg_map.get(&vreg) {
|
||||
inst.replace_regs(mctx,Reg::V(vreg),(*allocated_reg).into());
|
||||
}
|
||||
}
|
||||
}
|
||||
curr_inst = next_inst;
|
||||
}
|
||||
curr_block = block.succ(mctx);
|
||||
}
|
||||
generate_prologue(mctx,curr_func.unwrap());
|
||||
generate_epilogue(mctx, curr_func.unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_spill_load(mctx: &mut MirContext, reg: Reg, mem_loc: MemLoc, inst: MirInst) {
|
||||
let load = MirInst::ldr(mctx, reg.into(), mem_loc);
|
||||
let _ = inst.insert_before(mctx, load);
|
||||
}
|
||||
|
||||
pub fn generate_spill_store(mctx: &mut MirContext, reg: Reg, mem_loc: MemLoc, inst: MirInst) {
|
||||
let store = MirInst::str(mctx, reg.into(), mem_loc);
|
||||
let _ = inst.insert_after(mctx, store);
|
||||
}
|
||||
|
||||
|
||||
pub fn generate_prologue(mctx: &mut MirContext, function: MirFunction) {
|
||||
function.add_callee_reg(mctx, regs::fp().into());
|
||||
function.add_callee_reg(mctx, regs::x30().into());
|
||||
let mut stack_size = function.storage_stack_size(mctx) + function.calleeargs_stack_size(mctx) + function.callee_regs(mctx).len() as i32 * 8;
|
||||
stack_size = (stack_size + 15) & !15;
|
||||
let sub = MirInst::subi(mctx, regs::sp().into(), regs::sp().into(), stack_size);
|
||||
function.head(mctx).unwrap().push_front(mctx, sub).unwrap();
|
||||
}
|
||||
|
||||
pub fn generate_epilogue(mctx: &mut MirContext, function: MirFunction) {
|
||||
let mut stack_size = function.storage_stack_size(mctx) + function.calleeargs_stack_size(mctx) + function.callee_regs(mctx).len() as i32 * 8;
|
||||
stack_size = (stack_size + 15) & !15;
|
||||
// let ldp = MirInst::ldp(mctx, regs::fp().into(), regs::x30().into(), MemLoc::RegOffset{base: regs::sp().into(), offset: (stack_size - 16) });
|
||||
let addi = MirInst::addi(mctx, regs::sp().into(), regs::sp().into(), stack_size );
|
||||
let ret = MirInst::ret(mctx);
|
||||
function.tail(mctx).unwrap().push_back(mctx, addi).unwrap();
|
||||
function.tail(mctx).unwrap().push_back(mctx, ret).unwrap();
|
||||
}
|
||||
|
||||
@ -0,0 +1,111 @@
|
||||
use super::basicblock::BasicBlock;
|
||||
use super::value::Value;
|
||||
use super::{context::Context, typ::Typ};
|
||||
use crate::utils::linked_list::LinkedListContainer;
|
||||
use crate::utils::storage::{Arena, ArenaPtr, GenericPtr};
|
||||
|
||||
pub struct FunctionData {
|
||||
self_ptr: Function,
|
||||
id: String,
|
||||
parameters: Vec<Value>,
|
||||
return_type: Typ,
|
||||
head: Option<BasicBlock>,
|
||||
tail: Option<BasicBlock>,
|
||||
}
|
||||
|
||||
impl FunctionData {
|
||||
pub fn get_self_ptr(&self) -> Function {
|
||||
*(&self.self_ptr)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
|
||||
pub struct Function(pub GenericPtr<FunctionData>);
|
||||
|
||||
impl Function {
|
||||
/// 创建一个新的函数
|
||||
pub fn new(ctx: &mut Context, id: String, return_type: Typ) -> Self {
|
||||
ctx.alloc_with(|self_ptr| FunctionData {
|
||||
self_ptr,
|
||||
id,
|
||||
parameters: vec![],
|
||||
return_type,
|
||||
head: None,
|
||||
tail: None,
|
||||
})
|
||||
}
|
||||
|
||||
/// 获取函数名
|
||||
pub fn get_id(self, ctx: &Context) -> String {
|
||||
self.deref(ctx)
|
||||
.expect("Failed to deref `functions` in struct Context")
|
||||
.id
|
||||
.clone()
|
||||
}
|
||||
|
||||
/// 获取函数的返回类型
|
||||
pub fn get_return_type(self, ctx: &Context) -> Typ {
|
||||
self.deref(ctx)
|
||||
.expect("Failed to deref `functions` in struct Context")
|
||||
.return_type
|
||||
}
|
||||
|
||||
/// 获取函数的参数列表
|
||||
pub fn get_parameters(self, ctx: &Context) -> Vec<Value> {
|
||||
self.deref(ctx)
|
||||
.expect("Failed to deref `functions` in struct Context")
|
||||
.parameters
|
||||
.clone()
|
||||
}
|
||||
|
||||
/// 添加一个参数到函数参数列表中
|
||||
pub fn add_parameter(self, ctx: &mut Context, typ: Typ) -> Value {
|
||||
let parameter = Value::parameter(
|
||||
ctx,
|
||||
self,
|
||||
self.deref(ctx)
|
||||
.expect("Failed to deref `functions` in struct Context")
|
||||
.parameters
|
||||
.len() as u32,
|
||||
typ,
|
||||
);
|
||||
let function = self
|
||||
.deref_mut(ctx)
|
||||
.expect("Failed to deref `functions` in struct Context");
|
||||
function.parameters.push(parameter);
|
||||
parameter
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaPtr for Function {
|
||||
type Data = FunctionData;
|
||||
type Arena = Context;
|
||||
}
|
||||
|
||||
impl LinkedListContainer<BasicBlock> for Function {
|
||||
type Ctx = Context;
|
||||
|
||||
fn head(self, ctx: &Self::Ctx) -> Option<BasicBlock> {
|
||||
self.deref(ctx)
|
||||
.expect("Failed to deref `functions` in struct Context")
|
||||
.head
|
||||
}
|
||||
|
||||
fn tail(self, ctx: &Self::Ctx) -> Option<BasicBlock> {
|
||||
self.deref(ctx)
|
||||
.expect("Failed to deref `functions` in struct Context")
|
||||
.tail
|
||||
}
|
||||
|
||||
fn set_head(self, ctx: &mut Self::Ctx, head: Option<BasicBlock>) {
|
||||
self.deref_mut(ctx)
|
||||
.expect("Failed to deref `functions` in struct Context")
|
||||
.head = head;
|
||||
}
|
||||
|
||||
fn set_tail(self, ctx: &mut Self::Ctx, tail: Option<BasicBlock>) {
|
||||
self.deref_mut(ctx)
|
||||
.expect("Failed to deref `functions` in struct Context")
|
||||
.tail = tail;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
use super::context::Context;
|
||||
use super::typ::Typ;
|
||||
use super::value::ConstantValue;
|
||||
use crate::utils::storage::{Arena, ArenaPtr, GenericPtr};
|
||||
|
||||
pub struct GlobalData {
|
||||
pub self_ptr: Global,
|
||||
name: String,
|
||||
value: ConstantValue,
|
||||
}
|
||||
|
||||
impl GlobalData {
|
||||
pub fn get_self_ptr(&self) -> Global {
|
||||
self.self_ptr
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, Copy)]
|
||||
pub struct Global(pub GenericPtr<GlobalData>);
|
||||
|
||||
impl ArenaPtr for Global {
|
||||
type Arena = Context;
|
||||
type Data = GlobalData;
|
||||
}
|
||||
|
||||
impl Global {
|
||||
/// 创建一个全局变量
|
||||
pub fn new(ctx: &mut Context, name: String, value: ConstantValue) -> Self {
|
||||
ctx.alloc_with(|self_ptr| GlobalData {
|
||||
self_ptr,
|
||||
name,
|
||||
value,
|
||||
})
|
||||
}
|
||||
|
||||
/// 获取全局变量的名称
|
||||
pub fn name(self, ctx: &Context) -> &str {
|
||||
&self
|
||||
.deref(ctx)
|
||||
.expect("Failed to deref `name` of struct Global")
|
||||
.name
|
||||
}
|
||||
|
||||
/// 获取全局变量的值
|
||||
pub fn value(self, ctx: &Context) -> &ConstantValue {
|
||||
&self
|
||||
.deref(ctx)
|
||||
.expect("Failed to deref `value` of struct Global")
|
||||
.value
|
||||
}
|
||||
|
||||
/// 获取全局变量的类型
|
||||
pub fn typ(self, ctx: &Context) -> Typ {
|
||||
self.value(ctx).typ()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,435 @@
|
||||
use std::vec;
|
||||
|
||||
use crate::{
|
||||
frontend::{
|
||||
ir::{
|
||||
defuse::{Useable, User},
|
||||
},
|
||||
},
|
||||
utils::{
|
||||
linked_list::{LinkedListContainer, LinkedListNode},
|
||||
storage::{Arena, ArenaPtr, GenericPtr},
|
||||
},
|
||||
};
|
||||
|
||||
use super::{basicblock::BasicBlock, context::Context, typ::Typ, value::Value};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum TerminatorOp {
|
||||
// ret <type> <value> ; Return a value from a non-void function
|
||||
// ret void ; Return from void function
|
||||
Ret,
|
||||
// br label <dest> ;无条件跳转
|
||||
Br,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum BinaryOp {
|
||||
// <result> = add <Typ> <op1>, <op2> ; yields Typ:result
|
||||
Add,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum MemAccessOp {
|
||||
// <result> = alloca <type>
|
||||
Alloca { typ: Typ },
|
||||
// store <Typ> <value>, <Typ>* <pointer>
|
||||
Store,
|
||||
// <<result> = load <Typ>, <Typ>* <pointer>
|
||||
Load,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum InstructionKind {
|
||||
// Terminator instructions
|
||||
Terminator { op: TerminatorOp },
|
||||
|
||||
// Binary instructions
|
||||
Binary { op: BinaryOp },
|
||||
|
||||
// Memory access instructions
|
||||
MemAccess { op: MemAccessOp },
|
||||
}
|
||||
|
||||
impl PartialEq for InstructionKind {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(InstructionKind::Terminator { op: op1 }, InstructionKind::Terminator { op: op2 }) => {
|
||||
op1 == op2
|
||||
}
|
||||
(InstructionKind::Binary { op: op1 }, InstructionKind::Binary { op: op2 }) => {
|
||||
op1 == op2
|
||||
}
|
||||
(InstructionKind::MemAccess { op: op1 }, InstructionKind::MemAccess { op: op2 }) => {
|
||||
op1 == op2
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct InstructionData {
|
||||
self_ptr: Instruction,
|
||||
kind: InstructionKind,
|
||||
operands: Vec<(Value, bool)>,
|
||||
operands_bbk: Vec<(BasicBlock, bool)>,
|
||||
result: Option<Value>,
|
||||
succ: Option<Instruction>,
|
||||
pre: Option<Instruction>,
|
||||
basicblock: Option<BasicBlock>,
|
||||
}
|
||||
|
||||
impl InstructionData {
|
||||
pub fn get_self_ptr(&self) -> Instruction {
|
||||
self.self_ptr
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
|
||||
pub struct Instruction(pub GenericPtr<InstructionData>);
|
||||
|
||||
impl Instruction {
|
||||
/// 创建一个还未指定操作数的指令
|
||||
fn new_without_operands(ctx: &mut Context, kind: InstructionKind, typ: Typ) -> Self {
|
||||
let instruction = ctx.alloc_with(|self_ptr| InstructionData {
|
||||
self_ptr: self_ptr,
|
||||
kind,
|
||||
operands: vec![],
|
||||
operands_bbk: vec![],
|
||||
result: None,
|
||||
succ: None,
|
||||
pre: None,
|
||||
basicblock: None,
|
||||
});
|
||||
|
||||
if !typ.is_void(ctx) {
|
||||
let result = Value::inst_result(ctx, instruction, typ);
|
||||
instruction
|
||||
.deref_mut(ctx)
|
||||
.expect("Failed to deref `instructions` in struct `Context`")
|
||||
.result = Some(result);
|
||||
result.insert(ctx, User::new(instruction, 0)); // 默认插入到第0个位置
|
||||
instruction
|
||||
} else {
|
||||
instruction
|
||||
}
|
||||
}
|
||||
|
||||
/// 创建一个指定操作数的指令
|
||||
pub fn new_with_operands(
|
||||
ctx: &mut Context,
|
||||
kind: InstructionKind,
|
||||
typ: Typ,
|
||||
operands: Vec<Value>,
|
||||
) -> Self {
|
||||
let instruction = Self::new_without_operands(ctx, kind, typ);
|
||||
let instruction_data = instruction
|
||||
.deref_mut(ctx)
|
||||
.expect("Failed to deref `instructions` in struct `Context`");
|
||||
instruction_data.operands = operands.into_iter().map(|op| (op, true)).collect();
|
||||
instruction
|
||||
}
|
||||
|
||||
/// 获取指定index位置的操作数
|
||||
pub fn get_operand(self, ctx: &Context, index: usize) -> Option<Value> {
|
||||
if index
|
||||
>= self
|
||||
.deref(ctx)
|
||||
.expect("Failed to deref `operands` in struct `Instruction`")
|
||||
.operands
|
||||
.len()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
self.deref(ctx)
|
||||
.expect("Failed to deref `operands` in struct `Instruction`")
|
||||
.operands
|
||||
.get(index)
|
||||
.map(|(value, _)| *value)
|
||||
}
|
||||
|
||||
/// 获取所有操作数
|
||||
pub fn get_operands(self, ctx: &Context) -> Vec<Value> {
|
||||
self.deref(ctx)
|
||||
.expect("Failed to deref `operands` in struct `Instruction`")
|
||||
.operands
|
||||
.iter()
|
||||
.map(|(value, _)| *value)
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// 获取指令操作数个数
|
||||
pub fn operand_count(self, ctx: &Context) -> usize {
|
||||
self.deref(ctx)
|
||||
.expect("Failed to deref `operands` in struct `Instruction`")
|
||||
.operands
|
||||
.len()
|
||||
}
|
||||
|
||||
/// 获取指令类型
|
||||
pub fn get_kind(&self, ctx: &Context) -> InstructionKind {
|
||||
self.deref(ctx)
|
||||
.expect("Failed to deref `kind` in struct `Instruction`")
|
||||
.kind
|
||||
}
|
||||
|
||||
/// 获取指令的运算结果
|
||||
pub fn get_result(&self, ctx: &Context) -> Option<Value> {
|
||||
self.deref(ctx)
|
||||
.expect("Failed to deref `result` in struct `Instruction`")
|
||||
.result
|
||||
}
|
||||
|
||||
/// 获取指令结果的类型
|
||||
pub fn result_typ(&self, ctx: &Context) -> Typ {
|
||||
self.get_result(ctx)
|
||||
.expect("Failed to get result from instruction")
|
||||
.kind(ctx)
|
||||
}
|
||||
|
||||
/// 获取指令所在的基本块
|
||||
pub fn get_basicblock(&self, ctx: &Context) -> Option<BasicBlock> {
|
||||
self.deref(ctx)
|
||||
.expect("Failed to deref `basic_block` in struct `Instruction`")
|
||||
.basicblock
|
||||
}
|
||||
|
||||
/// 创建ret指令
|
||||
pub fn ret(ctx: &mut Context, value: Option<Value>) -> Self {
|
||||
let typ = Typ::void(ctx);
|
||||
if value.is_none() {
|
||||
return Self::new_without_operands(
|
||||
ctx,
|
||||
InstructionKind::Terminator {
|
||||
op: TerminatorOp::Ret,
|
||||
},
|
||||
typ,
|
||||
);
|
||||
}
|
||||
let instruction = Self::new_with_operands(
|
||||
ctx,
|
||||
InstructionKind::Terminator {
|
||||
op: TerminatorOp::Ret,
|
||||
},
|
||||
typ,
|
||||
vec![value.unwrap()],
|
||||
);
|
||||
value.unwrap().insert(ctx, User::new(instruction, 1));
|
||||
instruction
|
||||
}
|
||||
|
||||
/// 判断是否是ret指令
|
||||
pub fn is_ret(&self, ctx: &Context) -> bool {
|
||||
matches!(
|
||||
self.get_kind(ctx),
|
||||
InstructionKind::Terminator {
|
||||
op: TerminatorOp::Ret
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// 为分支指令增加一个基本块
|
||||
fn add_operand_bbk(self, ctx: &mut Context, block: BasicBlock) {
|
||||
self.deref_mut(ctx)
|
||||
.expect("Failed to deref_mut `operand_bbk` in struct `Instruction`")
|
||||
.operands_bbk
|
||||
.push((block, true));
|
||||
}
|
||||
|
||||
/// 获取跳转指令指定index的基本块
|
||||
pub fn get_operand_bbk(self, ctx: &Context, index: usize) -> Option<BasicBlock> {
|
||||
if index
|
||||
>= self
|
||||
.deref(ctx)
|
||||
.expect("Failed to deref `operands_bbk` in struct `Instruction`")
|
||||
.operands_bbk
|
||||
.len()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
self.deref(ctx)
|
||||
.expect("Failed to deref `operands_bbk` in struct `Instruction`")
|
||||
.operands_bbk
|
||||
.get(index)
|
||||
.map(|(value, _)| *value)
|
||||
}
|
||||
|
||||
/// 创建无条件跳转指令
|
||||
pub fn br(ctx: &mut Context, dest: BasicBlock) -> Self {
|
||||
let typ = Typ::void(ctx);
|
||||
let instruction = Self::new_with_operands(
|
||||
ctx,
|
||||
InstructionKind::Terminator {
|
||||
op: TerminatorOp::Br,
|
||||
},
|
||||
typ,
|
||||
vec![],
|
||||
);
|
||||
instruction.add_operand_bbk(ctx, dest);
|
||||
dest.insert(ctx, User::new(instruction, 1));
|
||||
instruction
|
||||
}
|
||||
|
||||
/// 判断是否是分支指令
|
||||
pub fn is_br(&self, ctx: &Context) -> bool {
|
||||
matches!(
|
||||
self.get_kind(ctx),
|
||||
InstructionKind::Terminator {
|
||||
op: TerminatorOp::Br
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// 判断指令是否是terminator指令
|
||||
pub fn is_terminater(&self, ctx: &Context) -> bool {
|
||||
matches!(self.get_kind(ctx), InstructionKind::Terminator { .. })
|
||||
}
|
||||
|
||||
/// 创建双目运算符
|
||||
pub fn binary(ctx: &mut Context, op: BinaryOp, typ: Typ, op1: Value, op2: Value) -> Self {
|
||||
let instruction =
|
||||
Self::new_with_operands(ctx, InstructionKind::Binary { op }, typ, vec![op1, op2]);
|
||||
op1.insert(ctx, User::new(instruction, 1));
|
||||
op2.insert(ctx, User::new(instruction, 2));
|
||||
instruction
|
||||
}
|
||||
|
||||
/// 创建访存指令
|
||||
pub fn memaccess(ctx: &mut Context, op: MemAccessOp, typ: Typ, ops: Vec<Value>) -> Self {
|
||||
match op {
|
||||
MemAccessOp::Store => {
|
||||
let void = Typ::void(ctx);
|
||||
let instruction = Self::new_with_operands(
|
||||
ctx,
|
||||
InstructionKind::MemAccess { op },
|
||||
void,
|
||||
ops.clone(),
|
||||
);
|
||||
for (i, op) in ops.iter().enumerate() {
|
||||
op.insert(ctx, User::new(instruction, i + 1));
|
||||
}
|
||||
instruction
|
||||
}
|
||||
_ => {
|
||||
let instruction = Self::new_with_operands(
|
||||
ctx,
|
||||
InstructionKind::MemAccess { op },
|
||||
typ,
|
||||
ops.clone(),
|
||||
);
|
||||
for (i, op) in ops.iter().enumerate() {
|
||||
op.insert(ctx, User::new(instruction, i + 1));
|
||||
}
|
||||
instruction
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 判断是否是store指令
|
||||
pub fn is_store(&self, ctx: &Context) -> bool {
|
||||
matches!(
|
||||
self.get_kind(ctx),
|
||||
InstructionKind::MemAccess {
|
||||
op: MemAccessOp::Store
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// 判断是否是load指令
|
||||
pub fn is_load(&self, ctx: &Context) -> bool {
|
||||
matches!(
|
||||
self.get_kind(ctx),
|
||||
InstructionKind::MemAccess {
|
||||
op: MemAccessOp::Load
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// 判断是否是alloca指令
|
||||
pub fn is_alloca(&self, ctx: &Context) -> bool {
|
||||
matches!(
|
||||
self.get_kind(ctx),
|
||||
InstructionKind::MemAccess {
|
||||
op: MemAccessOp::Alloca { .. }
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaPtr for Instruction {
|
||||
type Arena = Context;
|
||||
type Data = InstructionData;
|
||||
}
|
||||
|
||||
impl LinkedListNode for Instruction {
|
||||
type Container = BasicBlock;
|
||||
type Ctx = Context;
|
||||
|
||||
fn succ(self, ctx: &Self::Ctx) -> Option<Self> {
|
||||
self.deref(ctx)
|
||||
.expect("Failed to deref `succ` in struct `Instruction`")
|
||||
.succ
|
||||
}
|
||||
|
||||
fn pre(self, ctx: &Self::Ctx) -> Option<Self> {
|
||||
self.deref(ctx)
|
||||
.expect("Failed to deref `pre` in struct `Instruction`")
|
||||
.pre
|
||||
}
|
||||
|
||||
fn container(self, ctx: &Self::Ctx) -> Option<Self::Container> {
|
||||
self.deref(ctx)
|
||||
.expect("Failed to deref `container` in struct `Instruction")
|
||||
.basicblock
|
||||
}
|
||||
|
||||
fn set_succ(self, ctx: &mut Self::Ctx, succ: Option<Self>) {
|
||||
self.deref_mut(ctx)
|
||||
.expect("Failed to deref `succ` in struct `Instruction`")
|
||||
.succ = succ;
|
||||
}
|
||||
|
||||
fn set_pre(self, ctx: &mut Self::Ctx, pre: Option<Self>) {
|
||||
self.deref_mut(ctx)
|
||||
.expect("Failed to deref `pre` in struct `Instruction`")
|
||||
.pre = pre;
|
||||
}
|
||||
|
||||
fn set_container(self, ctx: &mut Self::Ctx, container: Option<Self::Container>) {
|
||||
self.deref_mut(ctx)
|
||||
.expect("Failed to deref `container` in struct `Instruction`")
|
||||
.basicblock = container;
|
||||
}
|
||||
|
||||
fn unlink(self, ctx: &mut Self::Ctx) {
|
||||
let pre = self.pre(ctx);
|
||||
let succ = self.succ(ctx);
|
||||
|
||||
if let Some(pre) = pre {
|
||||
pre.set_succ(ctx, succ);
|
||||
}
|
||||
|
||||
if let Some(succ) = succ {
|
||||
succ.set_pre(ctx, pre);
|
||||
}
|
||||
|
||||
if let Some(container) = self.container(ctx) {
|
||||
if container.get_head(ctx) == Some(self) {
|
||||
container.set_head(ctx, succ);
|
||||
}
|
||||
|
||||
if container.get_tail(ctx) == Some(self) {
|
||||
container.set_tail(ctx, pre);
|
||||
}
|
||||
}
|
||||
|
||||
self.set_pre(ctx, None);
|
||||
|
||||
self.set_succ(ctx, None);
|
||||
|
||||
self.set_container(ctx, None);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
pub mod context;
|
||||
pub mod typ;
|
||||
pub mod global;
|
||||
pub mod value;
|
||||
pub mod function;
|
||||
pub mod basicblock;
|
||||
pub mod instruction;
|
||||
pub mod defuse;
|
||||
@ -0,0 +1,60 @@
|
||||
use super::context::Context;
|
||||
use crate::{
|
||||
utils::storage::{Arena, ArenaPtr, UniqueArenaPtr},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum TypeData {
|
||||
Void,
|
||||
Int32,
|
||||
Ptr { typ_of_ptr: Typ },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, Copy, PartialOrd)]
|
||||
pub struct Typ(pub UniqueArenaPtr<TypeData>);
|
||||
|
||||
impl ArenaPtr for Typ {
|
||||
type Arena = Context;
|
||||
type Data = TypeData;
|
||||
}
|
||||
|
||||
impl Typ {
|
||||
|
||||
pub fn void(ctx: &mut Context) -> Self{
|
||||
ctx.alloc(TypeData::Void)
|
||||
}
|
||||
|
||||
pub fn is_void(&self, ctx: &Context) -> bool{
|
||||
matches!(self.deref(ctx).unwrap(), TypeData::Void)
|
||||
}
|
||||
|
||||
pub fn int32(ctx: &mut Context) -> Self {
|
||||
ctx.alloc(TypeData::Int32)
|
||||
}
|
||||
|
||||
pub fn is_int32(&self, ctx: &Context) -> bool {
|
||||
matches!(self.deref(ctx).unwrap(), TypeData::Int32)
|
||||
}
|
||||
|
||||
pub fn ptr(ctx: &mut Context, typ_of_ptr: Typ) -> Self {
|
||||
ctx.alloc(TypeData::Ptr { typ_of_ptr })
|
||||
}
|
||||
|
||||
pub fn is_ptr(&self, ctx: &Context) -> bool {
|
||||
matches!(self.deref(ctx).unwrap(), TypeData::Ptr { .. })
|
||||
}
|
||||
|
||||
/// 类型所占位数
|
||||
pub fn bitwidth(&self, ctx: &Context) -> usize {
|
||||
match self.deref(ctx).unwrap() {
|
||||
TypeData::Void => 0,
|
||||
TypeData::Int32 => 32,
|
||||
TypeData::Ptr { .. } => ctx.target as usize * 8,
|
||||
}
|
||||
}
|
||||
|
||||
/// 类型所占字节数
|
||||
pub fn bytewidth(&self, ctx: &Context) -> usize {
|
||||
(self.bitwidth(ctx) + 7) / 8
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,243 @@
|
||||
use super::context::Context;
|
||||
use super::defuse::{Useable, User};
|
||||
use super::function::Function;
|
||||
use super::instruction::Instruction;
|
||||
use super::typ::Typ;
|
||||
use crate::utils::storage::{Arena, ArenaPtr, GenericPtr};
|
||||
use rustc_hash::FxHashSet as HashSet;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ConstantValue {
|
||||
Undef {
|
||||
typ: Typ,
|
||||
},
|
||||
Zero {
|
||||
typ: Typ,
|
||||
},
|
||||
Int32 {
|
||||
typ: Typ,
|
||||
value: i32,
|
||||
},
|
||||
GlobalPtr {
|
||||
typ: Typ, // 全局指针类型
|
||||
name: String, // 全局变量的名
|
||||
value_type: Typ, // 指针指向数据的类型
|
||||
},
|
||||
}
|
||||
|
||||
impl ConstantValue {
|
||||
//常量值的类型
|
||||
pub fn typ(&self) -> Typ {
|
||||
match self {
|
||||
ConstantValue::Undef { typ } => *typ,
|
||||
ConstantValue::Zero { typ, .. } => *typ,
|
||||
ConstantValue::Int32 { typ, .. } => *typ,
|
||||
ConstantValue::GlobalPtr { value_type, .. } => *value_type,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn undef(typ: Typ) -> ConstantValue {
|
||||
ConstantValue::Undef { typ }
|
||||
}
|
||||
|
||||
pub fn is_undef(&self) -> bool {
|
||||
matches!(self, ConstantValue::Undef { .. })
|
||||
}
|
||||
|
||||
/// 创建zero类型
|
||||
pub fn zero(typ: Typ) -> ConstantValue {
|
||||
ConstantValue::Zero { typ }
|
||||
}
|
||||
|
||||
/// 判断是不是zero类型
|
||||
pub fn is_zero(&self) -> bool {
|
||||
matches!(self, ConstantValue::Zero { .. })
|
||||
}
|
||||
|
||||
pub fn int32(ctx: &mut Context, value: i32) -> ConstantValue {
|
||||
let int32 = Typ::int32(ctx);
|
||||
ConstantValue::Int32 { typ: int32, value }
|
||||
}
|
||||
|
||||
pub fn global_ptr(ctx: &mut Context, name: String, value_type: Typ) -> ConstantValue {
|
||||
let global_ptr = Typ::ptr(ctx, value_type.clone());
|
||||
ConstantValue::GlobalPtr {
|
||||
typ: global_ptr,
|
||||
name,
|
||||
value_type,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_string(&self, _ctx: &Context) -> String {
|
||||
let mut str = String::new();
|
||||
|
||||
match self {
|
||||
ConstantValue::Undef { typ: _ } => str.push_str("undef"),
|
||||
ConstantValue::Zero {..} => {
|
||||
str.push_str("0")
|
||||
}
|
||||
ConstantValue::Int32 { value, .. } => str.push_str(&value.to_string()),
|
||||
ConstantValue::GlobalPtr { name, .. } => {
|
||||
str.push_str("@");
|
||||
str.push_str(name);
|
||||
}
|
||||
}
|
||||
str
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ValueKind {
|
||||
// 指令的运算结果
|
||||
InstResult {
|
||||
instruction: Instruction,
|
||||
typ: Typ,
|
||||
},
|
||||
// 函数参数
|
||||
Parameter {
|
||||
function: Function,
|
||||
index: u32,
|
||||
typ: Typ,
|
||||
},
|
||||
// 常量值
|
||||
Constant {
|
||||
value: ConstantValue,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ValueData {
|
||||
// 值类型的种类
|
||||
pub kind: ValueKind,
|
||||
pub users: HashSet<User<Value>>,
|
||||
self_ptr: Value,
|
||||
}
|
||||
|
||||
impl ValueData {
|
||||
pub fn get_self_ptr(&self) -> Value {
|
||||
self.self_ptr
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, Copy, PartialOrd)]
|
||||
pub struct Value(pub GenericPtr<ValueData>);
|
||||
|
||||
impl ArenaPtr for Value {
|
||||
type Arena = Context;
|
||||
type Data = ValueData;
|
||||
}
|
||||
|
||||
impl Value {
|
||||
pub fn new(ctx: &mut Context, kind: ValueKind) -> Self {
|
||||
ctx.alloc_with(|self_ptr| ValueData {
|
||||
self_ptr: self_ptr,
|
||||
kind,
|
||||
users: HashSet::default(),
|
||||
})
|
||||
}
|
||||
|
||||
// InstResult类型的值获取指令
|
||||
pub fn get_instruction(self, ctx: &Context) -> Option<Instruction> {
|
||||
match self.deref(ctx).unwrap().kind {
|
||||
ValueKind::InstResult { instruction, .. } => Some(instruction),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
// 获取值类型
|
||||
pub fn kind(&self, ctx: &Context) -> Typ {
|
||||
match self
|
||||
.deref(ctx)
|
||||
.expect("Failed to deref `Value` in Value::kind()")
|
||||
.kind
|
||||
{
|
||||
ValueKind::InstResult { typ, .. } => typ,
|
||||
ValueKind::Parameter { typ, .. } => typ,
|
||||
ValueKind::Constant { ref value, .. } => value.typ(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parameter(ctx: &mut Context, function: Function, index: u32, typ: Typ) -> Self {
|
||||
Self::new(
|
||||
ctx,
|
||||
ValueKind::Parameter {
|
||||
function: function,
|
||||
index,
|
||||
typ,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn is_parameter(&self, ctx: &Context) -> bool {
|
||||
matches!(
|
||||
self.deref(ctx)
|
||||
.expect("Failed to deref `is_parameter` in Value")
|
||||
.kind,
|
||||
ValueKind::Parameter { .. }
|
||||
)
|
||||
}
|
||||
|
||||
pub fn inst_result(ctx: &mut Context, instruction: Instruction, typ: Typ) -> Self {
|
||||
let value = Self::new(
|
||||
ctx,
|
||||
ValueKind::InstResult {
|
||||
instruction: instruction,
|
||||
typ,
|
||||
},
|
||||
);
|
||||
value
|
||||
}
|
||||
|
||||
pub fn constant(ctx: &mut Context, value: ConstantValue) -> Self {
|
||||
Self::new(ctx, ValueKind::Constant { value })
|
||||
}
|
||||
|
||||
pub fn is_constant(&self, ctx: &Context) -> bool {
|
||||
matches!(
|
||||
self.deref(ctx)
|
||||
.expect("Failed to deref `is_constant` in Value")
|
||||
.kind,
|
||||
ValueKind::Constant { .. }
|
||||
)
|
||||
}
|
||||
|
||||
pub fn global_ptr(ctx: &mut Context, name: String, value_type: Typ) -> Self {
|
||||
let t = ConstantValue::global_ptr(ctx, name, value_type);
|
||||
let t = Self::new(ctx, ValueKind::Constant { value: t });
|
||||
t
|
||||
}
|
||||
|
||||
pub fn is_global_ptr(&self, ctx: &Context) -> bool {
|
||||
matches!(
|
||||
self.deref(ctx)
|
||||
.expect("Failed to deref `is_global_ptr` in Value")
|
||||
.kind,
|
||||
ValueKind::Constant {
|
||||
value: ConstantValue::GlobalPtr { .. }
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Useable for Value {
|
||||
fn users(self, arena: &Self::Arena) -> impl IntoIterator<Item = User<Self>> {
|
||||
self.deref(arena)
|
||||
.expect("Failed to deref `users` in struct Context")
|
||||
.users
|
||||
.iter()
|
||||
.copied()
|
||||
}
|
||||
|
||||
fn insert(self, arena: &mut Self::Arena, user: User<Self>) {
|
||||
self.deref_mut(arena)
|
||||
.expect("Failed to deref mut `users` in struct Context")
|
||||
.users
|
||||
.insert(user);
|
||||
}
|
||||
|
||||
fn remove(self, arena: &mut Self::Arena, user: User<Self>) {
|
||||
self.deref_mut(arena)
|
||||
.expect("Failed to deref mut `users` in struct Context")
|
||||
.users
|
||||
.remove(&user);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,221 @@
|
||||
use super::ir::{
|
||||
basicblock::BasicBlock,
|
||||
context::Context,
|
||||
function::Function,
|
||||
global::{Global, GlobalData},
|
||||
instruction::{
|
||||
BinaryOp as IBinaryOp,InstructionKind,
|
||||
MemAccessOp, TerminatorOp
|
||||
},
|
||||
typ::{Typ, TypeData},
|
||||
value::{Value, ValueKind},
|
||||
};
|
||||
use crate::{
|
||||
frontend::ir::instruction::Instruction,
|
||||
utils::{
|
||||
linked_list::LinkedListContainer,
|
||||
storage::{ArenaPtr, Idx},
|
||||
},
|
||||
};
|
||||
|
||||
pub trait Display {
|
||||
fn display(self, ctx: &Context) -> String;
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn get_ir_string(&self) -> String {
|
||||
let mut ir = String::new();
|
||||
for GlobalData {
|
||||
self_ptr: global, ..
|
||||
} in self.globals.iter()
|
||||
{
|
||||
ir += &format!("{}\n", global.display(self));
|
||||
}
|
||||
|
||||
for func in self.get_functions() {
|
||||
ir += &format!("{}\n", func.display(self));
|
||||
}
|
||||
ir
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Global {
|
||||
fn display(self, ctx: &Context) -> String {
|
||||
let mut ir = String::new();
|
||||
let typ = self.value(ctx).typ().display(ctx);
|
||||
if self.value(ctx).is_undef() || self.value(ctx).is_zero() {
|
||||
ir += &format!("@{} = global {} zeroinitializer\n", self.name(ctx), typ);
|
||||
} else {
|
||||
ir += &format!(
|
||||
"@{} = global {} {}\n",
|
||||
self.name(ctx),
|
||||
typ,
|
||||
self.value(ctx).to_string(ctx)
|
||||
);
|
||||
}
|
||||
ir
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Function {
|
||||
fn display(self, ctx: &Context) -> String {
|
||||
let mut ir = String::new();
|
||||
ir += &format!(
|
||||
"define {} @{}(",
|
||||
self.get_return_type(ctx).display(ctx),
|
||||
self.get_id(ctx)
|
||||
);
|
||||
|
||||
for (i, param) in self.get_parameters(ctx).iter().enumerate() {
|
||||
if i != 0 {
|
||||
ir += ", ";
|
||||
}
|
||||
ir += &format!("{} {}", param.kind(ctx).display(ctx), param.display(ctx));
|
||||
}
|
||||
|
||||
ir += ") {\n";
|
||||
|
||||
for bbk in self.iter(ctx) {
|
||||
ir += &format!("{}\n", bbk.display(ctx));
|
||||
}
|
||||
|
||||
ir += "}";
|
||||
|
||||
ir
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Typ {
|
||||
fn display(self, ctx: &Context) -> String {
|
||||
let mut ir = String::new();
|
||||
match self.deref(ctx).unwrap() {
|
||||
TypeData::Void => {
|
||||
ir += "void";
|
||||
}
|
||||
TypeData::Int32 => {
|
||||
ir += "i32";
|
||||
}
|
||||
TypeData::Ptr { typ_of_ptr: typ } => {
|
||||
if typ.is_void(ctx) {
|
||||
ir += &format!("i8*")
|
||||
} else {
|
||||
ir += &format!("{}*", typ.display(ctx));
|
||||
}
|
||||
}
|
||||
}
|
||||
ir
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for BasicBlock {
|
||||
fn display(self, ctx: &Context) -> String {
|
||||
let mut ir = String::new();
|
||||
ir += &format!("{}:", self.get_name());
|
||||
for inst in self.iter(ctx) {
|
||||
ir += &format!("\n\t{}", inst.display(ctx));
|
||||
}
|
||||
ir
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Instruction {
|
||||
fn display(self, ctx: &Context) -> String {
|
||||
let mut ir = String::new();
|
||||
if let Some(result) = self.get_result(ctx) {
|
||||
ir += &format!("{} = ", result.display(ctx));
|
||||
}
|
||||
|
||||
match self.get_kind(ctx) {
|
||||
InstructionKind::Terminator { op } => match op {
|
||||
TerminatorOp::Ret => {
|
||||
if let Some(ret_val) = self.get_operand(ctx, 0) {
|
||||
ir += &format!(
|
||||
"ret {} {}",
|
||||
ret_val.kind(ctx).display(ctx),
|
||||
ret_val.display(ctx)
|
||||
);
|
||||
} else {
|
||||
ir += "ret void";
|
||||
}
|
||||
|
||||
}
|
||||
TerminatorOp::Br => {
|
||||
ir += &format!(
|
||||
"br label %{}",
|
||||
self.get_operand_bbk(ctx, 0)
|
||||
.expect("Failed to get the first operand of the br instruction")
|
||||
.get_name()
|
||||
);
|
||||
}
|
||||
},
|
||||
InstructionKind::Binary { op } => match op {
|
||||
IBinaryOp::Add => {
|
||||
let op1 = self.get_operand(ctx, 0).unwrap();
|
||||
let op2 = self.get_operand(ctx, 1).unwrap();
|
||||
let typ = op1.kind(ctx);
|
||||
ir += &format!(
|
||||
"add {} {}, {}",
|
||||
typ.display(ctx),
|
||||
op1.display(ctx),
|
||||
op2.display(ctx)
|
||||
);
|
||||
}
|
||||
},
|
||||
InstructionKind::MemAccess { op } => {
|
||||
match op {
|
||||
MemAccessOp::Alloca { typ } => {
|
||||
ir += &format!("alloca {}", typ.display(ctx));
|
||||
}
|
||||
MemAccessOp::Load => {
|
||||
let typ = self.result_typ(ctx);
|
||||
let op1 = self.get_operand(ctx, 0).unwrap();
|
||||
let typ_of_op1 = op1.kind(ctx);
|
||||
ir += &format!(
|
||||
"load {}, {}* {}",
|
||||
typ.display(ctx),
|
||||
typ_of_op1.display(ctx),
|
||||
op1.display(ctx)
|
||||
);
|
||||
}
|
||||
MemAccessOp::Store => {
|
||||
let op1 = self.get_operand(ctx, 0).unwrap();
|
||||
let typ_of_op1 = op1.kind(ctx);
|
||||
let op2 = self.get_operand(ctx, 1).unwrap();
|
||||
let typ_of_op2 = op2.kind(ctx);
|
||||
ir += &format!(
|
||||
"store {} {}, {}* {}",
|
||||
typ_of_op1.display(ctx),
|
||||
op1.display(ctx),
|
||||
typ_of_op2.display(ctx),
|
||||
op2.display(ctx)
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
ir
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Value {
|
||||
fn display(self, ctx: &Context) -> String {
|
||||
let mut ir = String::new();
|
||||
match &self.deref(ctx).unwrap().kind {
|
||||
ValueKind::InstResult {
|
||||
instruction: _,
|
||||
typ: _,
|
||||
}
|
||||
| ValueKind::Parameter {
|
||||
function: _,
|
||||
index: _,
|
||||
typ: _,
|
||||
} => {
|
||||
ir += &format!("%v{}", self.0.index());
|
||||
}
|
||||
ValueKind::Constant { value } => {
|
||||
ir += &format!("{}", value.to_string(ctx));
|
||||
}
|
||||
};
|
||||
ir
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
pub mod ast;
|
||||
@ -0,0 +1,134 @@
|
||||
use crate::frontend::lalrpop::ast::*;
|
||||
|
||||
grammar;
|
||||
|
||||
match {
|
||||
r"\s*" => {},
|
||||
r"//[^\n\r]*[\n\r]*" => {},
|
||||
r"/\*[^*]*\*+(?:[^/*][^*]*\*+)*/" => {},
|
||||
_
|
||||
}
|
||||
|
||||
// Terminal symbols definition
|
||||
Ident: String = r"[_a-zA-Z][_a-zA-Z0-9]*" => <>.to_string();
|
||||
|
||||
Int: i32 = {
|
||||
r"[1-9][0-9]*" => i32::from_str_radix(<>, 10).unwrap(),
|
||||
r"0[0-7]*" => i32::from_str_radix(<>, 8).unwrap(),
|
||||
r"0[xX][0-9a-fA-F]+" => i32::from_str_radix(&<>[2..], 16).unwrap(),
|
||||
}
|
||||
|
||||
// Number -> IntConst
|
||||
pub Number: ComptimeValue = {
|
||||
<n: Int> => ComptimeValue::int(n),
|
||||
}
|
||||
|
||||
// Nonterminal symbols definition
|
||||
// CompUnit -> [CompUnit](Decl|FuncDef)
|
||||
pub CompUnit: CompUnit = <items: (GlobalItem)*> => CompUnit{ <> };
|
||||
|
||||
GlobalItem: GlobalItem = {
|
||||
Decl => GlobalItem::Decl(<>),
|
||||
FuncDef => GlobalItem::FuncDef(<>),
|
||||
}
|
||||
|
||||
// Decl -> VarDecl
|
||||
Decl: Decl = {
|
||||
VarDecl => Decl::VarDecl(<>),
|
||||
}
|
||||
|
||||
// BType -> "int" | "void"
|
||||
pub BType: Type = {
|
||||
"int" => Type::int(),
|
||||
"void" => Type::void(),
|
||||
}
|
||||
|
||||
// VarDecl -> BType VarDef { ',' VarDef } ';'
|
||||
VarDecl: VarDecl = {
|
||||
<typ: BType> <def: VarDef> <mut defs: ("," <VarDef>)*> ";" => {
|
||||
defs.insert(0, def);
|
||||
VarDecl { typ, defs }
|
||||
}
|
||||
}
|
||||
|
||||
// VarDef -> Ident { '[' ConstExp ']' }
|
||||
// | Ident { '[' ConstExp ']' } '=' InitVal
|
||||
VarDef: VarDef = {
|
||||
<id: Ident> <init: ("=" <InitVal>)?> => VarDef { id, init }
|
||||
}
|
||||
|
||||
// InitVal -> Exp
|
||||
InitVal: InitVal = {
|
||||
Exp => InitVal::Exp(<>),
|
||||
}
|
||||
|
||||
// FuncDef -> FuncType Ident '(' FuncFParams ')' Block
|
||||
pub FuncDef: FuncDef = {
|
||||
<typ: BType> <id: Ident> "(" ")" <block: Block> => FuncDef { typ, id, params: vec![], block },
|
||||
<typ: BType> <id: Ident> "(" <params: FuncFParams> ")" <block: Block> => {
|
||||
FuncDef { typ, id, params, block }
|
||||
}
|
||||
}
|
||||
|
||||
// FuncFParams -> FuncFParam { ',' FuncFParam }
|
||||
FuncFParams: Vec<FuncFParam> = {
|
||||
<param: FuncFParam> <mut params: ("," <FuncFParam>)*> => {
|
||||
params.insert(0, param);
|
||||
params
|
||||
}
|
||||
}
|
||||
|
||||
// FuncFParam -> BType Ident [ '[' ']' { '[' Exp ']' } ]
|
||||
FuncFParam: FuncFParam = {
|
||||
<typ: BType> <id: Ident> => {
|
||||
FuncFParam { typ, id }
|
||||
},
|
||||
}
|
||||
|
||||
// Block -> '{' { BlockItem } '}'
|
||||
Block: Block = {
|
||||
"{" <items: (BlockItem)*> "}" => Block { items }
|
||||
}
|
||||
|
||||
// BlockItem -> Decl|Stmt
|
||||
BlockItem: BlockItem = {
|
||||
Decl => BlockItem::Decl(<>),
|
||||
Stmt => BlockItem::Stmt(<>),
|
||||
}
|
||||
|
||||
Stmt: Stmt = {
|
||||
<lval: LVal> "=" <exp: Exp> ";" => Stmt::Assign(Assign { <> }),
|
||||
<exp: (Exp)?> ";" => Stmt::ExpStmt(ExpStmt { <> }),
|
||||
Block => Stmt::Block(<>),
|
||||
"return" <exp: (Exp)?> ";" => Stmt::Return(Return { <> }),
|
||||
}
|
||||
|
||||
// LVal -> Ident { '[' Exp ']' }
|
||||
LVal: LVal = <id: Ident> => LVal { <> };
|
||||
|
||||
// PrimaryExp -> '(' Exp ')' | LVal | Number
|
||||
pub PrimaryExp: Exp = {
|
||||
"(" <e: Exp> ")" => e,
|
||||
<v: LVal> => Exp::lval(v),
|
||||
<n: Number> => Exp::const_(n),
|
||||
}
|
||||
|
||||
// UnaryExp -> PrimaryExp
|
||||
// | Ident '(' [ FuncRParams ] ')'
|
||||
// | UnaryOp UnaryExp
|
||||
pub UnaryExp: Exp = {
|
||||
PrimaryExp => <>,
|
||||
"+" <e: UnaryExp> => e,
|
||||
}
|
||||
|
||||
// AddExp -> UnaryExp | AddExp ('+') UnaryExp
|
||||
pub AddExp: Exp = {
|
||||
UnaryExp => <>,
|
||||
<lhs: AddExp> "+" <rhs: UnaryExp> => Exp::binary(BinaryOp::Add, lhs, rhs),
|
||||
}
|
||||
|
||||
// Exp -> AddExp
|
||||
pub Exp: Exp = AddExp => <>;
|
||||
|
||||
// ConstExp -> AddExp
|
||||
// pub ConstExp: Exp = AddExp => <>;
|
||||
@ -0,0 +1,18 @@
|
||||
pub mod ir;
|
||||
pub mod ir2string;
|
||||
pub mod irgen;
|
||||
pub mod lalrpop;
|
||||
pub mod symboltable;
|
||||
pub mod typecheck;
|
||||
|
||||
pub fn irgen(ast: &mut lalrpop::ast::CompUnit, ptr_width: u8) -> ir::context::Context {
|
||||
let mut irgen = irgen::IrGenContext::default();
|
||||
|
||||
irgen.ctx.set_target(ptr_width as usize);
|
||||
|
||||
crate::frontend::lalrpop::ast::CompUnit::type_check(ast);
|
||||
|
||||
<crate::frontend::lalrpop::ast::CompUnit as irgen::IrGen>::irgen(ast, &mut irgen);
|
||||
|
||||
irgen.context()
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
use rustc_hash::FxHashMap as HashMap;
|
||||
|
||||
use super::{
|
||||
irgen::IrGenResult,
|
||||
lalrpop::ast::{ComptimeValue, Type},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SymbolEntry {
|
||||
pub typ: Type,
|
||||
pub comptime: Option<ComptimeValue>,
|
||||
pub ir_value: Option<IrGenResult>,
|
||||
}
|
||||
|
||||
impl SymbolEntry {
|
||||
pub fn from_ty(typ: Type) -> Self {
|
||||
Self {
|
||||
typ,
|
||||
comptime: None,
|
||||
ir_value: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct SymbolTable {
|
||||
stack: Vec<HashMap<String, SymbolEntry>>,
|
||||
pub curr_ret_ty: Option<Type>,
|
||||
}
|
||||
|
||||
impl SymbolTable {
|
||||
pub fn enter_scope(&mut self) {
|
||||
self.stack.push(HashMap::default());
|
||||
}
|
||||
|
||||
pub fn leave_scope(&mut self) {
|
||||
self.stack.pop();
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, name: impl Into<String>, entry: SymbolEntry) {
|
||||
self.stack.last_mut().unwrap().insert(name.into(), entry);
|
||||
}
|
||||
|
||||
pub fn insert_upper(&mut self, name: impl Into<String>, entry: SymbolEntry, upper: usize) {
|
||||
self.stack
|
||||
.iter_mut()
|
||||
.rev()
|
||||
.nth(upper)
|
||||
.unwrap()
|
||||
.insert(name.into(), entry);
|
||||
}
|
||||
|
||||
pub fn lookup(&self, name: &str) -> Option<&SymbolEntry> {
|
||||
for scope in self.stack.iter().rev() {
|
||||
if let Some(entry) = scope.get(name) {
|
||||
return Some(entry);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn lookup_mut(&mut self, name: &str) -> Option<&mut SymbolEntry> {
|
||||
for scope in self.stack.iter_mut().rev() {
|
||||
if let Some(entry) = scope.get_mut(name) {
|
||||
return Some(entry);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn register_sysylib(&mut self) {
|
||||
assert_eq!(self.stack.len(), 1);
|
||||
// TODO!
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,246 @@
|
||||
use crate::frontend;
|
||||
use crate::frontend::lalrpop::ast::{*};
|
||||
use crate::frontend::symboltable::*;
|
||||
|
||||
impl CompUnit {
|
||||
pub fn type_check(&mut self) {
|
||||
let mut symtable = SymbolTable::default();
|
||||
// 全局作用域
|
||||
symtable.enter_scope();
|
||||
// 注册系统库
|
||||
symtable.register_sysylib();
|
||||
|
||||
for item in self.items.iter_mut() {
|
||||
item.type_check(&mut symtable);
|
||||
}
|
||||
|
||||
// 退出全局作用域
|
||||
symtable.leave_scope();
|
||||
}
|
||||
}
|
||||
|
||||
impl GlobalItem {
|
||||
pub fn type_check(&mut self, symtable: &mut SymbolTable) {
|
||||
match self {
|
||||
GlobalItem::Decl(decl) => match decl {
|
||||
Decl::VarDecl(decl) => decl.type_check(symtable),
|
||||
},
|
||||
GlobalItem::FuncDef(FuncDef {
|
||||
typ,
|
||||
id,
|
||||
params,
|
||||
block,
|
||||
}) => {
|
||||
symtable.enter_scope();
|
||||
// 插入函数参数到作用域
|
||||
let mut param_tys = Vec::new();
|
||||
for param in params.iter() {
|
||||
let typ = param.typ.clone();
|
||||
param_tys.push(typ.clone());
|
||||
symtable.insert(param.id.clone(), SymbolEntry::from_ty(typ.clone()));
|
||||
}
|
||||
|
||||
let func_ty = Type::function(param_tys, typ.clone());
|
||||
|
||||
// 插入函数符号到作用域,位于当前作用域之上,因为我们处于参数作用域
|
||||
symtable.insert_upper(id.clone(), SymbolEntry::from_ty(func_ty), 1);
|
||||
symtable.curr_ret_ty = Some(typ.clone());
|
||||
|
||||
block.type_check(symtable);
|
||||
|
||||
symtable.curr_ret_ty = None;
|
||||
symtable.leave_scope();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VarDecl {
|
||||
pub fn type_check(&mut self, symtable: &mut SymbolTable) {
|
||||
let mut new_defs = Vec::new();
|
||||
|
||||
for mut def in self.defs.drain(..) {
|
||||
let typ = self.typ.clone();
|
||||
let init = def
|
||||
.init
|
||||
.map(|init| {
|
||||
// fold as much as possible
|
||||
let typed_init = init.type_check(Some(&typ), symtable);
|
||||
match typed_init.try_fold(symtable) {
|
||||
Some(val) => Exp::const_(val),
|
||||
None => typed_init,
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
let undef = ComptimeValue::undef(typ.clone());
|
||||
Exp::const_(undef)
|
||||
});
|
||||
|
||||
def.init = Some(frontend::lalrpop::ast::InitVal::Exp(init));
|
||||
|
||||
symtable.insert(def.id.clone(), SymbolEntry::from_ty(typ));
|
||||
new_defs.push(def);
|
||||
}
|
||||
|
||||
self.defs = new_defs;
|
||||
}
|
||||
}
|
||||
|
||||
impl InitVal {
|
||||
pub fn type_check(self, expect_type: Option<&Type>, symboltable: &mut SymbolTable) -> Exp {
|
||||
match self {
|
||||
InitVal::Exp(exp) => exp.type_check(expect_type, symboltable),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Block {
|
||||
pub fn type_check(&mut self, symtable: &mut SymbolTable) {
|
||||
// 进入块作用域
|
||||
symtable.enter_scope();
|
||||
let mut new_items = Vec::new();
|
||||
|
||||
for item in self.items.drain(..) {
|
||||
let item = match item {
|
||||
BlockItem::Decl(decl) => match decl {
|
||||
Decl::VarDecl(mut decl) => {
|
||||
decl.type_check(symtable);
|
||||
BlockItem::Decl(Decl::VarDecl(decl))
|
||||
}
|
||||
},
|
||||
BlockItem::Stmt(stmt) => {
|
||||
let stmt = stmt.type_check(symtable);
|
||||
BlockItem::Stmt(stmt)
|
||||
}
|
||||
};
|
||||
new_items.push(item);
|
||||
}
|
||||
|
||||
self.items = new_items;
|
||||
symtable.leave_scope();
|
||||
}
|
||||
}
|
||||
|
||||
impl Stmt {
|
||||
pub fn type_check(self, symtable: &mut SymbolTable) -> Self {
|
||||
match self {
|
||||
Stmt::Assign(Assign { lval, exp }) => {
|
||||
let id = lval.id; // 直接获取 id 的所有权
|
||||
|
||||
let entry = symtable.lookup(&id).expect("variable not found");
|
||||
|
||||
// 计算最终类型(例如处理数组维度)
|
||||
let typ = &entry.typ;
|
||||
|
||||
// 类型检查表达式
|
||||
let expr = exp.type_check(Some(typ), symtable);
|
||||
|
||||
// 重构 Assign 结构体
|
||||
let assign = Stmt::Assign(Assign {
|
||||
lval: LVal {
|
||||
id, // 使用已解构的 id
|
||||
},
|
||||
exp: expr,
|
||||
});
|
||||
assign
|
||||
}
|
||||
Stmt::ExpStmt(ExpStmt { exp }) => {
|
||||
let expr = exp.map(|expr| expr.type_check(None, symtable));
|
||||
Stmt::ExpStmt(ExpStmt { exp: expr })
|
||||
}
|
||||
Stmt::Block(mut block) => {
|
||||
block.type_check(symtable);
|
||||
Stmt::Block(block)
|
||||
}
|
||||
Stmt::Return(Return { exp }) => {
|
||||
let exp = exp.map(|expr| expr.type_check(symtable.curr_ret_ty.as_ref(), symtable));
|
||||
|
||||
if exp.is_none() {
|
||||
return Stmt::Return(Return { exp });
|
||||
}
|
||||
|
||||
let exp = exp.unwrap();
|
||||
let ret_ty = symtable.curr_ret_ty.as_ref().unwrap();
|
||||
|
||||
if ret_ty.is_int() ^ exp.typ().is_int() {
|
||||
panic!("unsupported return type");
|
||||
}
|
||||
|
||||
Stmt::Return(Return { exp: Some(exp) })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Exp {
|
||||
|
||||
/// 类型检查表达式,返回类型正确的表达式。
|
||||
pub fn get_type(&self) -> &Type {
|
||||
self.typ.as_ref().unwrap()
|
||||
}
|
||||
|
||||
/// 常量折叠
|
||||
pub fn try_fold(&self, symtable: &SymbolTable) -> Option<ComptimeValue> {
|
||||
match &self.kind {
|
||||
ExpKind::Const(val) => Some(val.clone()),
|
||||
ExpKind::Binary(op, lhs, rhs) => {
|
||||
let lhs = lhs.try_fold(symtable)?;
|
||||
let rhs = rhs.try_fold(symtable)?;
|
||||
match op {
|
||||
BinaryOp::Add => Some(lhs + rhs),
|
||||
}
|
||||
}
|
||||
ExpKind::LVal(LVal { id}) => {
|
||||
let entry = symtable.lookup(id).unwrap();
|
||||
let val = entry.comptime.as_ref()?.clone();
|
||||
Some(val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_check(mut self, expect: Option<&Type>, symtable: &SymbolTable) -> Self {
|
||||
if self.typ.is_some() && expect.is_none() {
|
||||
return self;
|
||||
}
|
||||
let mut expr = match self.kind {
|
||||
ExpKind::Const(_) => self,
|
||||
ExpKind::Binary(op, lhs, rhs) => {
|
||||
let lhs = lhs.type_check(None, symtable);
|
||||
let rhs = rhs.type_check(None, symtable);
|
||||
|
||||
let lhs_ty = lhs.get_type().clone();
|
||||
let mut expr = Exp::binary(op, lhs, rhs);
|
||||
|
||||
match op {
|
||||
BinaryOp::Add => {
|
||||
expr.typ = Some(lhs_ty.clone());
|
||||
}
|
||||
}
|
||||
expr
|
||||
}
|
||||
|
||||
ExpKind::LVal(LVal { id }) => {
|
||||
let entry = symtable.lookup(&id).unwrap();
|
||||
let typ = entry.typ.clone();
|
||||
let mut expr = Exp::lval(LVal {
|
||||
id,
|
||||
});
|
||||
expr.typ = Some(typ);
|
||||
expr
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(typ) = expect {
|
||||
if typ.is_int() {
|
||||
expr.typ = Some(typ.clone());
|
||||
} else if typ != expr.get_type() {
|
||||
panic!("unsupported type coercion: {:?}", typ);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(comptime) = expr.try_fold(symtable) {
|
||||
expr = Exp::const_(comptime);
|
||||
}
|
||||
expr
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,113 @@
|
||||
use lalrpop_util::lalrpop_mod;
|
||||
use rustc_hash::FxHashMap as HashMap;
|
||||
use std::io::Result;
|
||||
|
||||
pub mod backend;
|
||||
pub mod frontend;
|
||||
pub mod utils;
|
||||
|
||||
//指定生成的代码的位置
|
||||
lalrpop_mod!(#[allow(clippy::all)] pub sysy, "/frontend/lalrpop/sysy.rs");
|
||||
|
||||
/// 解析命令行参数
|
||||
fn parse_arguments() -> HashMap<String, String> {
|
||||
let mut args_map = HashMap::default();
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
let mut i = 0;
|
||||
while i < args.len() {
|
||||
let arg = args[i].as_str();
|
||||
if arg == "-ast" {
|
||||
args_map.insert(String::from("ast"), args[i + 1].to_string());
|
||||
i += 1;
|
||||
} else if arg == "-ir" {
|
||||
args_map.insert(String::from("ir"), args[i + 1].to_string());
|
||||
i += 1;
|
||||
} else if arg == "-asm" {
|
||||
args_map.insert(String::from("asm"), args[i + 1].to_string());
|
||||
i += 1;
|
||||
} else if arg == "-S" {
|
||||
args_map.insert(String::from("S"), String::from("true"));
|
||||
} else if arg == "-o" {
|
||||
args_map.insert(String::from("o"), args[i + 1].to_string());
|
||||
i += 1;
|
||||
} else if arg == "-O1" {
|
||||
args_map.insert(String::from("O1"), String::from("true"));
|
||||
} else if arg == "-h" {
|
||||
println!("[Compiler] Usage:");
|
||||
println!("[Compiler] compiler [options] source_file");
|
||||
println!("[Compiler] Options:");
|
||||
println!("[Compiler] -ast <file> : Output the AST to a file");
|
||||
println!("[Compiler] -ir <file> : Output the IR to a file");
|
||||
println!(
|
||||
"[Compiler] -asm <file> : Output the ASM to a file( Has higher priority than -S!!! )"
|
||||
);
|
||||
println!("[Compiler] -S : Output the ASM to stdout");
|
||||
println!("[Compiler] -o <file> : Output the ASM to a file");
|
||||
println!("[Compiler] -O1 : Enable optimization level 1");
|
||||
std::process::exit(0);
|
||||
} else {
|
||||
args_map.insert(String::from("source"), arg.to_string());
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
args_map
|
||||
}
|
||||
|
||||
/// 检查命令行参数
|
||||
fn check_args(args: &HashMap<String, String>) {
|
||||
let emit_s = if args.get("S").is_some() && args.get("S").unwrap() == "true" {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let source = args.get("source");
|
||||
let output_file = args.get("o");
|
||||
if source.is_none() {
|
||||
panic!("Error: Source file `{}` not specified", source.unwrap());
|
||||
}
|
||||
if output_file.is_none() && emit_s {
|
||||
panic!("Error: Output file not specified");
|
||||
}
|
||||
if !std::path::Path::new(source.unwrap()).exists() {
|
||||
panic!("Error: Source file `{}` not found", source.unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
// 参数解析与检查
|
||||
let args = parse_arguments();
|
||||
check_args(&args);
|
||||
|
||||
// 提取参数
|
||||
let emit_ast = args.get("ast"); // 输出AST文件
|
||||
let emit_ir = args.get("ir"); // 输出IR文件
|
||||
let emit_asm = args.get("asm"); // 输出ASM文件
|
||||
let emit_s = matches!(args.get("S"), Some(v) if v == "true"); // 适配比赛编译器选项要求,表示生成汇编代码
|
||||
let _optimize = matches!(args.get("O1"), Some(v) if v == "true"); // 优化选项
|
||||
let source = args.get("source"); // 源文件名
|
||||
let output_file = args.get("o"); // 输出文件名
|
||||
|
||||
let src = std::fs::read_to_string(source.unwrap())?; // 读取源文件内容
|
||||
|
||||
let mut ast = sysy::CompUnitParser::new().parse(&src).unwrap();
|
||||
if let Some(ast_file) = emit_ast {
|
||||
std::fs::write(ast_file, format!("{:#?}", ast)).expect("Failed to write AST to file");
|
||||
}
|
||||
|
||||
let mut ir = frontend::irgen(&mut ast, 8); // ARMV8架构
|
||||
|
||||
if let Some(ir_file) = emit_ir {
|
||||
std::fs::write(ir_file, ir.get_ir_string()).expect("Failed to write IR to file");
|
||||
}
|
||||
|
||||
let mir = backend::mirgen(&mut ir);
|
||||
if emit_s || emit_asm.is_some() {
|
||||
let mut asm_file = output_file;
|
||||
if emit_asm.is_some() {
|
||||
asm_file = emit_asm;
|
||||
}
|
||||
std::fs::write(asm_file.unwrap(), mir.get_asm()).expect("Failed to write ASM to file");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
pub mod linked_list;
|
||||
pub mod storage;
|
||||
Binary file not shown.
@ -0,0 +1,16 @@
|
||||
@NUDT_GLOBAL_VAR_a = global i32 1
|
||||
|
||||
@NUDT_GLOBAL_VAR_b = global i32 2
|
||||
|
||||
define i32 @main() {
|
||||
bb_0:
|
||||
%v0 = alloca i32
|
||||
%v2 = load i32, i32* @NUDT_GLOBAL_VAR_a
|
||||
%v4 = load i32, i32* @NUDT_GLOBAL_VAR_b
|
||||
%v5 = add i32 %v2, %v4
|
||||
store i32 %v5, i32* %v0
|
||||
br label %bb_1
|
||||
bb_1:
|
||||
%v6 = load i32, i32* %v0
|
||||
ret i32 %v6
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
.arch armv8-a
|
||||
.text
|
||||
.global main
|
||||
.type main, %function
|
||||
.p2align 3
|
||||
main:
|
||||
sub sp, sp, #272
|
||||
adrp x19, NUDT_GLOBAL_VAR_a
|
||||
add x19, x19, :lo12:NUDT_GLOBAL_VAR_a
|
||||
ldr w22, [x19]
|
||||
adrp x20, NUDT_GLOBAL_VAR_b
|
||||
add x20, x20, :lo12:NUDT_GLOBAL_VAR_b
|
||||
ldr w23, [x20]
|
||||
add w21, w22, w23
|
||||
str w21, [sp]
|
||||
b bb_1
|
||||
bb_1:
|
||||
ldr w24, [sp]
|
||||
mov w0, w24
|
||||
add sp, sp, #272
|
||||
ret
|
||||
|
||||
|
||||
.section .data
|
||||
.p2align 3
|
||||
.global NUDT_GLOBAL_VAR_a
|
||||
.type NUDT_GLOBAL_VAR_a, %object
|
||||
NUDT_GLOBAL_VAR_a:
|
||||
.word 1
|
||||
|
||||
.section .data
|
||||
.p2align 3
|
||||
.global NUDT_GLOBAL_VAR_b
|
||||
.type NUDT_GLOBAL_VAR_b, %object
|
||||
NUDT_GLOBAL_VAR_b:
|
||||
.word 2
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
int main(){
|
||||
const int a[4][2] = {{1, 2}, {3, 4}, {}, 7};
|
||||
const int N = 3;
|
||||
int b[4][2] = {};
|
||||
int c[4][2] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
int d[N + 1][2] = {1, 2, {3}, {5}, a[3][0], 8};
|
||||
int e[4][2][1] = {{d[2][1], {c[2][1]}}, {3, 4}, {5, 6}, {7, 8}};
|
||||
return e[3][1][0] + e[0][0][0] + e[0][1][0] + d[3][0];
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
int a;
|
||||
int func(int p){
|
||||
p = p - 1;
|
||||
return p;
|
||||
}
|
||||
int main(){
|
||||
int b;
|
||||
a = 10;
|
||||
b = func(a);
|
||||
return b;
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
//test add
|
||||
int main(){
|
||||
int a, b;
|
||||
a = 10;
|
||||
b = -1;
|
||||
return a + b;
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
//test sub
|
||||
const int a = 10;
|
||||
int main(){
|
||||
int b;
|
||||
b = 2;
|
||||
return b - a;
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
const int V = 4;
|
||||
const int space = 32;
|
||||
const int LF = 10;
|
||||
|
||||
void printSolution(int color[]) {
|
||||
int i = 0;
|
||||
while (i < V) {
|
||||
putint(color[i]);
|
||||
putch(space);
|
||||
i = i + 1;
|
||||
}
|
||||
putch(LF);
|
||||
}
|
||||
|
||||
void printMessage() {
|
||||
putch(78);putch(111);putch(116);
|
||||
putch(space);
|
||||
putch(101);putch(120);putch(105);putch(115);putch(116);
|
||||
}
|
||||
|
||||
int isSafe(int graph[][V], int color[]) {
|
||||
int i = 0;
|
||||
while (i < V) {
|
||||
int j = i + 1;
|
||||
while (j < V) {
|
||||
if (graph[i][j] && color[j] == color[i])
|
||||
return 0;
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int graphColoring(int graph[][V], int m, int i, int color[]) {
|
||||
if (i == V) {
|
||||
if (isSafe(graph, color)) {
|
||||
printSolution(color);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int j = 1;
|
||||
while (j <= m) {
|
||||
color[i] = j;
|
||||
if (graphColoring(graph, m, i + 1, color))
|
||||
return 1;
|
||||
color[i] = 0;
|
||||
j = j + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int graph[V][V] = {
|
||||
{0, 1, 1, 1},
|
||||
{1, 0, 1, 0},
|
||||
{1, 1, 0, 1},
|
||||
{1, 0, 1, 0}
|
||||
}, m = 3;
|
||||
int color[V], i = 0;
|
||||
while (i < V) {
|
||||
color[i] = 0;
|
||||
i = i + 1;
|
||||
}
|
||||
if (!graphColoring(graph, m, 0, color))
|
||||
printMessage();
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
4 4
|
||||
1 2 3 4
|
||||
5 6 7 8
|
||||
9 10 11 12
|
||||
13 14 15 16
|
||||
4 3
|
||||
9 5 1
|
||||
10 6 2
|
||||
11 7 3
|
||||
12 8 4
|
||||
@ -0,0 +1,60 @@
|
||||
const int MAX_SIZE = 100;
|
||||
int a[MAX_SIZE][MAX_SIZE], b[MAX_SIZE][MAX_SIZE];
|
||||
int res[MAX_SIZE][MAX_SIZE];
|
||||
int n1, m1, n2, m2;
|
||||
void matrix_multiply() {
|
||||
int i = 0;
|
||||
while (i < m1) {
|
||||
int j = 0;
|
||||
while (j < n2) {
|
||||
int k = 0;
|
||||
while (k < n1) {
|
||||
res[i][j] = res[i][j] + a[i][k] * b[k][j];
|
||||
k = k + 1;
|
||||
}
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
int main()
|
||||
{
|
||||
int i, j;
|
||||
m1 = getint();
|
||||
n1 = getint();
|
||||
i = 0;
|
||||
while (i < m1) {
|
||||
j = 0;
|
||||
while (j < n1) {
|
||||
a[i][j] = getint();
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
m2 = getint();
|
||||
n2 = getint();
|
||||
i = 0;
|
||||
while (i < m2) {
|
||||
j = 0;
|
||||
while (j < n2) {
|
||||
b[i][j] = getint();
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
matrix_multiply();
|
||||
i = 0;
|
||||
while (i < m1) {
|
||||
j = 0;
|
||||
while (j < n2) {
|
||||
putint(res[i][j]);
|
||||
putch(32);
|
||||
j = j + 1;
|
||||
}
|
||||
putch(10);
|
||||
i = i + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1 @@
|
||||
int main() { /* scope test */ putch(97); putch(10); int a = 1, putch = 0; { a = a + 2; int b = a + 3; b = b + 4; putch = putch + a + b; { b = b + 5; int main = b + 6; a = a + main; putch = putch + a + b + main; { b = b + a; int a = main + 7; a = a + 8; putch = putch + a + b + main; { b = b + a; int b = main + 9; a = a + 10; const int a = 11; b = b + 12; putch = putch + a + b + main; { main = main + b; int main = b + 13; main = main + a; putch = putch + a + b + main; } putch = putch - main; } putch = putch - b; } putch = putch - a; } } return putch % 77; }
|
||||
@ -0,0 +1,15 @@
|
||||
//test break
|
||||
int main(){
|
||||
int i;
|
||||
i = 0;
|
||||
int sum;
|
||||
sum = 0;
|
||||
while(i < 100){
|
||||
if(i == 50){
|
||||
break;
|
||||
}
|
||||
sum = sum + i;
|
||||
i = i + 1;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
//test the priority of add and mul
|
||||
int main(){
|
||||
int a, b, c, d;
|
||||
a = 10;
|
||||
b = 4;
|
||||
c = 2;
|
||||
d = 2;
|
||||
return (c + a) * (b - d);
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
10
|
||||
0x1.999999999999ap-4 0x1.999999999999ap-3 0x1.3333333333333p-2 0x1.999999999999ap-2 0x1.0000000000000p-1
|
||||
0x1.3333333333333p-1 0x1.6666666666666p-1 0x1.999999999999ap-1 0x1.ccccccccccccdp-1 0x1.0000000000000p+0
|
||||
0x1.199999999999ap+0
|
||||
0x1.199999999999ap+1
|
||||
0x1.a666666666666p+1
|
||||
0x1.199999999999ap+2
|
||||
0x1.6000000000000p+2
|
||||
0x1.a666666666666p+2
|
||||
0x1.ecccccccccccdp+2
|
||||
0x1.199999999999ap+3
|
||||
0x1.3cccccccccccdp+3
|
||||
0x1.4333333333333p+3
|
||||
@ -0,0 +1,98 @@
|
||||
// float global constants
|
||||
const float RADIUS = 5.5, PI = 03.141592653589793, EPS = 1e-6;
|
||||
|
||||
// hexadecimal float constant
|
||||
const float PI_HEX = 0x1.921fb6p+1, HEX2 = 0x.AP-3;
|
||||
|
||||
// float constant evaluation
|
||||
const float FACT = -.33E+5, EVAL1 = PI * RADIUS * RADIUS, EVAL2 = 2 * PI_HEX * RADIUS, EVAL3 = PI * 2 * RADIUS;
|
||||
|
||||
// float constant implicit conversion
|
||||
const float CONV1 = 233, CONV2 = 0xfff;
|
||||
const int MAX = 1e9, TWO = 2.9, THREE = 3.2, FIVE = TWO + THREE;
|
||||
|
||||
// float -> float function
|
||||
float float_abs(float x) {
|
||||
if (x < 0) return -x;
|
||||
return x;
|
||||
}
|
||||
|
||||
// int -> float function & float/int expression
|
||||
float circle_area(int radius) {
|
||||
return (PI * radius * radius + (radius * radius) * PI) / 2;
|
||||
}
|
||||
|
||||
// float -> float -> int function & float/int expression
|
||||
int float_eq(float a, float b) {
|
||||
if (float_abs(a - b) < EPS) {
|
||||
return 1 * 2. / 2;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void error() {
|
||||
putch(101);
|
||||
putch(114);
|
||||
putch(114);
|
||||
putch(111);
|
||||
putch(114);
|
||||
putch(10);
|
||||
}
|
||||
|
||||
void ok() {
|
||||
putch(111);
|
||||
putch(107);
|
||||
putch(10);
|
||||
}
|
||||
|
||||
void assert(int cond) {
|
||||
if (!cond) {
|
||||
error();
|
||||
} else {
|
||||
ok();
|
||||
}
|
||||
}
|
||||
|
||||
void assert_not(int cond) {
|
||||
if (cond) {
|
||||
error();
|
||||
} else {
|
||||
ok();
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
assert_not(float_eq(HEX2, FACT));
|
||||
assert_not(float_eq(EVAL1, EVAL2));
|
||||
assert(float_eq(EVAL2, EVAL3));
|
||||
assert(float_eq(circle_area(RADIUS) /* f->i implicit conversion */,
|
||||
circle_area(FIVE)));
|
||||
assert_not(float_eq(CONV1, CONV2) /* i->f implicit conversion */);
|
||||
|
||||
// float conditional expressions
|
||||
if (1.5) ok();
|
||||
if (!!3.3) ok();
|
||||
if (.0 && 3) error();
|
||||
if (0 || 0.3) ok();
|
||||
|
||||
// float array & I/O functions
|
||||
int i = 1, p = 0;
|
||||
float arr[10] = {1., 2};
|
||||
int len = getfarray(arr);
|
||||
while (i < MAX) {
|
||||
float input = getfloat();
|
||||
float area = PI * input * input, area_trunc = circle_area(input);
|
||||
arr[p] = arr[p] + input;
|
||||
|
||||
putfloat(area);
|
||||
putch(32);
|
||||
putint(area_trunc); // f->i implicit conversion
|
||||
putch(10);
|
||||
|
||||
i = i * - -1e1;
|
||||
p = p + 1;
|
||||
}
|
||||
putfarray(len, arr);
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
int main() {
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
return a + b;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,89 @@
|
||||
const int N = 1024;
|
||||
|
||||
void mm(int n, int A[][N], int B[][N], int C[][N]){
|
||||
int i, j, k;
|
||||
|
||||
i = 0; j = 0;
|
||||
while (i < n){
|
||||
j = 0;
|
||||
while (j < n){
|
||||
C[i][j] = 0;
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
i = 0; j = 0; k = 0;
|
||||
|
||||
while (k < n){
|
||||
i = 0;
|
||||
while (i < n){
|
||||
if (A[i][k] == 0){
|
||||
i = i + 1;
|
||||
continue;
|
||||
}
|
||||
j = 0;
|
||||
while (j < n){
|
||||
C[i][j] = C[i][j] + A[i][k] * B[k][j];
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
k = k + 1;
|
||||
}
|
||||
}
|
||||
|
||||
int A[N][N];
|
||||
int B[N][N];
|
||||
int C[N][N];
|
||||
|
||||
int main(){
|
||||
int n = getint();
|
||||
int i, j;
|
||||
|
||||
i = 0;
|
||||
j = 0;
|
||||
while (i < n){
|
||||
j = 0;
|
||||
while (j < n){
|
||||
A[i][j] = getint();
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
i = 0;
|
||||
j = 0;
|
||||
while (i < n){
|
||||
j = 0;
|
||||
while (j < n){
|
||||
B[i][j] = getint();
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
starttime();
|
||||
|
||||
i = 0;
|
||||
while (i < 5){
|
||||
mm(n, A, B, C);
|
||||
mm(n, A, C, B);
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
int ans = 0;
|
||||
i = 0;
|
||||
while (i < n){
|
||||
j = 0;
|
||||
while (j < n){
|
||||
ans = ans + B[i][j];
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
stoptime();
|
||||
putint(ans);
|
||||
putch(10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,71 @@
|
||||
int x;
|
||||
|
||||
const int N = 2010;
|
||||
|
||||
void mv(int n, int A[][N], int b[], int res[]){
|
||||
int x, y;
|
||||
y = 0;
|
||||
x = 11;
|
||||
int i, j;
|
||||
|
||||
i = 0;
|
||||
while(i < n){
|
||||
res[i] = 0;
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
j = 0;
|
||||
while (i < n){
|
||||
j = 0;
|
||||
while (j < n){
|
||||
if (A[i][j] == 0){
|
||||
x = x * b[i] + b[j];
|
||||
y = y - x;
|
||||
}else{
|
||||
res[i] = res[i] + A[i][j] * b[j];
|
||||
}
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
int A[N][N];
|
||||
int B[N];
|
||||
int C[N];
|
||||
|
||||
int main(){
|
||||
int n = getint();
|
||||
int i, j;
|
||||
|
||||
i = 0;
|
||||
|
||||
while (i < n){
|
||||
j = 0;
|
||||
while (j < n){
|
||||
A[i][j] = getint();
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < n){
|
||||
B[i] = getint();
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
starttime();
|
||||
|
||||
i = 0;
|
||||
while (i < 50){
|
||||
mv(n, A, B, C);
|
||||
mv(n, A, C, B);
|
||||
i = i + 1;
|
||||
}
|
||||
stoptime();
|
||||
|
||||
putarray(n, C);
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,106 @@
|
||||
const int base = 16;
|
||||
|
||||
int getMaxNum(int n, int arr[]){
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
while (i < n){
|
||||
if (arr[i] > ret) ret = arr[i];
|
||||
i = i + 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int getNumPos(int num, int pos){
|
||||
int tmp = 1;
|
||||
int i = 0;
|
||||
while (i < pos){
|
||||
num = num / base;
|
||||
i = i + 1;
|
||||
}
|
||||
return num % base;
|
||||
}
|
||||
|
||||
void radixSort(int bitround, int a[], int l, int r){
|
||||
int head[base] = {};
|
||||
int tail[base] = {};
|
||||
int cnt[base] = {};
|
||||
|
||||
if (bitround == -1 || l + 1 >= r) return;
|
||||
|
||||
{
|
||||
int i = l;
|
||||
|
||||
while (i < r){
|
||||
cnt[getNumPos(a[i], bitround)]
|
||||
= cnt[getNumPos(a[i], bitround)] + 1;
|
||||
i = i + 1;
|
||||
}
|
||||
head[0] = l;
|
||||
tail[0] = l + cnt[0];
|
||||
|
||||
i = 1;
|
||||
while (i < base){
|
||||
head[i] = tail[i - 1];
|
||||
tail[i] = head[i] + cnt[i];
|
||||
i = i + 1;
|
||||
}
|
||||
i = 0;
|
||||
while (i < base){
|
||||
while (head[i] < tail[i]){
|
||||
int v = a[head[i]];
|
||||
while (getNumPos(v, bitround) != i){
|
||||
int t = v;
|
||||
v = a[head[getNumPos(t, bitround)]];
|
||||
a[head[getNumPos(t, bitround)]] = t;
|
||||
head[getNumPos(t, bitround)] = head[getNumPos(t, bitround)] + 1;
|
||||
}
|
||||
a[head[i]] = v;
|
||||
head[i] = head[i] + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int i = l;
|
||||
|
||||
head[0] = l;
|
||||
tail[0] = l + cnt[0];
|
||||
|
||||
i = 0;
|
||||
while (i < base){
|
||||
if (i > 0){
|
||||
head[i] = tail[i - 1];
|
||||
tail[i] = head[i] + cnt[i];
|
||||
}
|
||||
radixSort(bitround - 1, a, head[i], tail[i]);
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int a[30000010];
|
||||
int ans;
|
||||
|
||||
int main(){
|
||||
int n = getarray(a);
|
||||
|
||||
starttime();
|
||||
|
||||
radixSort(8, a, 0, n);
|
||||
|
||||
int i = 0;
|
||||
while (i < n){
|
||||
ans = ans + i * (a[i] % (2 + i));
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
if (ans < 0)
|
||||
ans = -ans;
|
||||
stoptime();
|
||||
putint(ans);
|
||||
putch(10);
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,110 @@
|
||||
int A[1024][1024];
|
||||
int B[1024][1024];
|
||||
int C[1024][1024];
|
||||
|
||||
int main() {
|
||||
int T = getint(); // 矩阵规模
|
||||
int R = getint(); // 重复次数
|
||||
|
||||
int i = 0;
|
||||
while (i < T) {
|
||||
if (i < T / 2) {
|
||||
getarray(A[i]);
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < T) {
|
||||
if (i >= T / 2) {
|
||||
getarray(B[i]);
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
starttime();
|
||||
|
||||
i = 0;
|
||||
while (i < T) {
|
||||
if (i >= T / 2) {
|
||||
int j = 0;
|
||||
while (j < T) {
|
||||
A[i][j] = -1;
|
||||
j = j + 1;
|
||||
}
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < T) {
|
||||
if (i < T / 2) {
|
||||
int j = 0;
|
||||
while (j < T) {
|
||||
B[i][j] = -1;
|
||||
j = j + 1;
|
||||
}
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < T) {
|
||||
int j = 0;
|
||||
while (j < T) {
|
||||
C[i][j] = A[i][j] * 2 + B[i][j] * 3;
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < T) {
|
||||
int j = 0;
|
||||
while (j < T) {
|
||||
int val = C[i][j];
|
||||
val = val * val + 7;
|
||||
val = val / 3;
|
||||
C[i][j] = val;
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < T) {
|
||||
int j = 0;
|
||||
while (j < T) {
|
||||
int k = 0;
|
||||
int sum = 0;
|
||||
while (k < T) {
|
||||
sum = sum + C[i][k] * A[k][j];
|
||||
k = k + 1;
|
||||
}
|
||||
A[i][j] = sum;
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
int total = 0;
|
||||
int r = 0;
|
||||
while (r < R) {
|
||||
i = 0;
|
||||
while (i < T) {
|
||||
int j = 0;
|
||||
while (j < T) {
|
||||
total = total + A[i][j] * A[i][j];
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
r = r + 1;
|
||||
}
|
||||
|
||||
stoptime();
|
||||
|
||||
putint(total);
|
||||
putch(10);
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,82 @@
|
||||
const int mod = 998244353;
|
||||
int d;
|
||||
|
||||
int multiply(int a, int b){
|
||||
if (b == 0) return 0;
|
||||
if (b == 1) return a % mod;
|
||||
int cur = multiply(a, b/2);
|
||||
cur = (cur + cur) % mod;
|
||||
if (b % 2 == 1) return (cur + a) % mod;
|
||||
else return cur;
|
||||
}
|
||||
|
||||
int power(int a, int b){
|
||||
if (b == 0) return 1;
|
||||
int cur = power(a, b/2);
|
||||
cur = multiply(cur, cur);
|
||||
if (b % 2 == 1) return multiply(cur, a);
|
||||
else return cur;
|
||||
}
|
||||
const int maxlen = 2097152;
|
||||
int temp[maxlen], a[maxlen], b[maxlen], c[maxlen];
|
||||
|
||||
int memmove(int dst[], int dst_pos, int src[], int len){
|
||||
int i = 0;
|
||||
while (i < len){
|
||||
dst[dst_pos + i] = src[i];
|
||||
i = i + 1;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
int fft(int arr[], int begin_pos, int n, int w){
|
||||
if (n == 1) return 1;
|
||||
int i = 0;
|
||||
while (i < n){
|
||||
if (i % 2 == 0) temp[i / 2] = arr[i + begin_pos];
|
||||
else temp[n / 2 + i / 2] = arr[i + begin_pos];
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
memmove(arr, begin_pos, temp, n);
|
||||
fft(arr, begin_pos, n / 2, multiply(w, w));
|
||||
fft(arr, begin_pos + n / 2, n / 2, multiply(w, w));
|
||||
i = 0;
|
||||
int wn = 1;
|
||||
while (i < n / 2){
|
||||
int x = arr[begin_pos + i];
|
||||
int y = arr[begin_pos + i + n / 2];
|
||||
arr[begin_pos + i] = (x + multiply(wn, y)) % mod;
|
||||
arr[begin_pos + i + n / 2] = (x - multiply(wn, y) + mod) % mod;
|
||||
wn = multiply(wn, w);
|
||||
i = i + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(){
|
||||
int n = getarray(a);
|
||||
int m = getarray(b);
|
||||
starttime();
|
||||
d = 1;
|
||||
while (d < n + m - 1){
|
||||
d = d * 2;
|
||||
}
|
||||
fft(a, 0, d, power(3, (mod - 1) / d));
|
||||
fft(b, 0, d, power(3, (mod - 1) / d));
|
||||
|
||||
int i = 0;
|
||||
while (i < d){
|
||||
a[i] = multiply(a[i], b[i]);
|
||||
i = i + 1;
|
||||
}
|
||||
fft(a, 0, d, power(3, mod-1 - (mod-1)/d));
|
||||
i = 0;
|
||||
while (i < d){
|
||||
a[i] = multiply(a[i], power(d, mod-2));
|
||||
i = i + 1;
|
||||
}
|
||||
stoptime();
|
||||
putarray(n + m - 1, a);
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
50 50 353434
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
.....................#..#.........................
|
||||
.....................#..#.........................
|
||||
...................##.##.##.......................
|
||||
.....................#..#.........................
|
||||
.....................#..#.........................
|
||||
...................##.##.##.......................
|
||||
.....................#..#.........................
|
||||
.....................#..#.........................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
..................................................
|
||||
@ -0,0 +1,112 @@
|
||||
int sheet1[500][500] = {};
|
||||
int sheet2[500][500] = {};
|
||||
int active = 1;
|
||||
int width;
|
||||
int height;
|
||||
int steps;
|
||||
|
||||
void read_map() {
|
||||
width = getint();
|
||||
height = getint();
|
||||
// width <= 498, height <= 498
|
||||
steps = getint();
|
||||
getch();
|
||||
|
||||
int i = 1;
|
||||
int j = 1;
|
||||
|
||||
while (j <= height) {
|
||||
i = 1;
|
||||
while (i <= width) {
|
||||
int get = getch();
|
||||
if (get == 35) {
|
||||
sheet1[j][i] = 1;
|
||||
} else {
|
||||
sheet1[j][i] = 0;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
// line feed
|
||||
getch();
|
||||
j = j + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void put_map() {
|
||||
int i = 1;
|
||||
int j = 1;
|
||||
|
||||
while (j <= height) {
|
||||
i = 1;
|
||||
while (i <= width) {
|
||||
if (sheet1[j][i] == 1) {
|
||||
putch(35);
|
||||
} else {
|
||||
putch(46);
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
// line feed
|
||||
putch(10);
|
||||
j = j + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void swap12() {
|
||||
int i = 1;
|
||||
int j = 1;
|
||||
|
||||
while (j <= height) {
|
||||
i = 1;
|
||||
while (i <= width) {
|
||||
sheet1[j][i] = sheet2[j][i];
|
||||
i = i + 1;
|
||||
}
|
||||
j = j + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void step(int source[][500], int target[][500]) {
|
||||
int i = 1;
|
||||
int j = 1;
|
||||
|
||||
while (j <= height) {
|
||||
i = 1;
|
||||
while (i <= width) {
|
||||
int alive_count = source[j - 1][i - 1] + source[j - 1][i] +
|
||||
source[j - 1][i + 1] + source[j][i - 1] +
|
||||
source[j][i + 1] + source[j + 1][i - 1] +
|
||||
source[j + 1][i] + source[j + 1][i + 1];
|
||||
if (source[j][i] == 1 && alive_count == 2 ) {
|
||||
target[j][i] = 1;
|
||||
} else if (alive_count == 3) {
|
||||
target[j][i] = 1;
|
||||
} else {
|
||||
target[j][i] = 0;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
j = j + 1;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
read_map();
|
||||
starttime();
|
||||
while (steps > 0) {
|
||||
if (active == 1) {
|
||||
step(sheet1, sheet2);
|
||||
active = 2;
|
||||
} else {
|
||||
step(sheet2, sheet1);
|
||||
active = 1;
|
||||
}
|
||||
steps = steps - 1;
|
||||
}
|
||||
stoptime();
|
||||
if (active == 2) {
|
||||
swap12();
|
||||
}
|
||||
put_map();
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
50000000
|
||||
@ -0,0 +1,331 @@
|
||||
int func(int n) {
|
||||
int sum = 0;
|
||||
int i = 200;
|
||||
int j = 0;
|
||||
int s[100];
|
||||
int m = 0;
|
||||
|
||||
while (m < 100){
|
||||
s[m] = 0;
|
||||
m=m+1;
|
||||
}
|
||||
while(j < n) {
|
||||
if (i > 1){
|
||||
s[1] = 1;
|
||||
if (i > 2){
|
||||
s[2] = 2;
|
||||
if (i > 3){
|
||||
s[3] = 3;
|
||||
if (i > 4){
|
||||
s[4] = 4;
|
||||
if (i > 5){
|
||||
s[5] = 5;
|
||||
if (i > 6){
|
||||
s[6] = 6;
|
||||
if (i > 7){
|
||||
s[7] = 7;
|
||||
if (i > 8){
|
||||
s[8] = 8;
|
||||
if (i > 9){
|
||||
s[9] = 9;
|
||||
if (i > 10){
|
||||
s[10] = 10;
|
||||
if (i > 11){
|
||||
s[11] = 11;
|
||||
if (i > 12){
|
||||
s[12] = 12;
|
||||
if (i > 13){
|
||||
s[13] = 13;
|
||||
if (i > 14){
|
||||
s[14] = 14;
|
||||
if (i > 15){
|
||||
s[15] = 15;
|
||||
if (i > 16){
|
||||
s[16] = 16;
|
||||
if (i > 17){
|
||||
s[17] = 17;
|
||||
if (i > 18){
|
||||
s[18] = 18;
|
||||
if (i > 19){
|
||||
s[19] = 19;
|
||||
if (i > 20){
|
||||
s[20] = 20;
|
||||
if (i > 21){
|
||||
s[21] = 21;
|
||||
if (i > 22){
|
||||
s[22] = 22;
|
||||
if (i > 23){
|
||||
s[23] = 23;
|
||||
if (i > 24){
|
||||
s[24] = 24;
|
||||
if (i > 25){
|
||||
s[25] = 25;
|
||||
if (i > 26){
|
||||
s[26] = 26;
|
||||
if (i > 27){
|
||||
s[27] = 27;
|
||||
if (i > 28){
|
||||
s[28] = 28;
|
||||
if (i > 29){
|
||||
s[29] = 29;
|
||||
if (i > 30){
|
||||
s[30] = 30;
|
||||
if (i > 31){
|
||||
s[31] = 31;
|
||||
if (i > 32){
|
||||
s[32] = 32;
|
||||
if (i > 33){
|
||||
s[33] = 33;
|
||||
if (i > 34){
|
||||
s[34] = 34;
|
||||
if (i > 35){
|
||||
s[35] = 35;
|
||||
if (i > 36){
|
||||
s[36] = 36;
|
||||
if (i > 37){
|
||||
s[37] = 37;
|
||||
if (i > 38){
|
||||
s[38] = 38;
|
||||
if (i > 39){
|
||||
s[39] = 39;
|
||||
if (i > 40){
|
||||
s[40] = 40;
|
||||
if (i > 41){
|
||||
s[41] = 41;
|
||||
if (i > 42){
|
||||
s[42] = 42;
|
||||
if (i > 43){
|
||||
s[43] = 43;
|
||||
if (i > 44){
|
||||
s[44] = 44;
|
||||
if (i > 45){
|
||||
s[45] = 45;
|
||||
if (i > 46){
|
||||
s[46] = 46;
|
||||
if (i > 47){
|
||||
s[47] = 47;
|
||||
if (i > 48){
|
||||
s[48] = 48;
|
||||
if (i > 49){
|
||||
s[49] = 49;
|
||||
if (i > 50){
|
||||
s[50] = 50;
|
||||
if (i > 51){
|
||||
s[51] = 51;
|
||||
if (i > 52){
|
||||
s[52] = 52;
|
||||
if (i > 53){
|
||||
s[53] = 53;
|
||||
if (i > 54){
|
||||
s[54] = 54;
|
||||
if (i > 55){
|
||||
s[55] = 55;
|
||||
if (i > 56){
|
||||
s[56] = 56;
|
||||
if (i > 57){
|
||||
s[57] = 57;
|
||||
if (i > 58){
|
||||
s[58] = 58;
|
||||
if (i > 59){
|
||||
s[59] = 59;
|
||||
if (i > 60){
|
||||
s[60] = 60;
|
||||
if (i > 61){
|
||||
s[61] = 61;
|
||||
if (i > 62){
|
||||
s[62] = 62;
|
||||
if (i > 63){
|
||||
s[63] = 63;
|
||||
if (i > 64){
|
||||
s[64] = 64;
|
||||
if (i > 65){
|
||||
s[65] = 65;
|
||||
if (i > 66){
|
||||
s[66] = 66;
|
||||
if (i > 67){
|
||||
s[67] = 67;
|
||||
if (i > 68){
|
||||
s[68] = 68;
|
||||
if (i > 69){
|
||||
s[69] = 69;
|
||||
if (i > 70){
|
||||
s[70] = 70;
|
||||
if (i > 71){
|
||||
s[71] = 71;
|
||||
if (i > 72){
|
||||
s[72] = 72;
|
||||
if (i > 73){
|
||||
s[73] = 73;
|
||||
if (i > 74){
|
||||
s[74] = 74;
|
||||
if (i > 75){
|
||||
s[75] = 75;
|
||||
if (i > 76){
|
||||
s[76] = 76;
|
||||
if (i > 77){
|
||||
s[77] = 77;
|
||||
if (i > 78){
|
||||
s[78] = 78;
|
||||
if (i > 79){
|
||||
s[79] = 79;
|
||||
if (i > 80){
|
||||
s[80] = 80;
|
||||
if (i > 81){
|
||||
s[81] = 81;
|
||||
if (i > 82){
|
||||
s[82] = 82;
|
||||
if (i > 83){
|
||||
s[83] = 83;
|
||||
if (i > 84){
|
||||
s[84] = 84;
|
||||
if (i > 85){
|
||||
s[85] = 85;
|
||||
if (i > 86){
|
||||
s[86] = 86;
|
||||
if (i > 87){
|
||||
s[87] = 87;
|
||||
if (i > 88){
|
||||
s[88] = 88;
|
||||
if (i > 89){
|
||||
s[89] = 89;
|
||||
if (i > 90){
|
||||
s[90] = 90;
|
||||
if (i > 91){
|
||||
s[91] = 91;
|
||||
if (i > 92){
|
||||
s[92] = 92;
|
||||
if (i > 93){
|
||||
s[93] = 93;
|
||||
if (i > 94){
|
||||
s[94] = 94;
|
||||
if (i > 95){
|
||||
s[95] = 95;
|
||||
if (i > 96){
|
||||
s[96] = 96;
|
||||
if (i > 97){
|
||||
s[97] = 97;
|
||||
if (i > 98){
|
||||
s[98] = 98;
|
||||
if (i > 99){
|
||||
s[99] = 99;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
j=j+1;
|
||||
int m = 0;
|
||||
while (m < 100){
|
||||
sum = sum + s[m];
|
||||
m=m+1;
|
||||
}
|
||||
sum = sum % 65535;
|
||||
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
starttime();
|
||||
int loopcount = getint();
|
||||
putint(func(loopcount));
|
||||
putch(10);
|
||||
stoptime();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -0,0 +1 @@
|
||||
4096
|
||||
@ -0,0 +1,49 @@
|
||||
|
||||
int COUNT = 500000;
|
||||
|
||||
float loop(float x[], float y[], int length) {
|
||||
int i = 0;
|
||||
float accumulator = 0.0;
|
||||
while (i < length) {
|
||||
accumulator = accumulator + x[i] * y[i];
|
||||
i = i + 1;
|
||||
}
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int i = 0, j = 0;
|
||||
int len = getint();
|
||||
float x[4096];
|
||||
float y[4096];
|
||||
float total = 0.0;
|
||||
float a = 0.0;
|
||||
float b = 1.0;
|
||||
starttime();
|
||||
while ( i < COUNT) {
|
||||
if (i % 10) {
|
||||
a = 0.0;
|
||||
b = 1.0;
|
||||
} else {
|
||||
a = a + 0.1;
|
||||
b = b + 0.2;
|
||||
}
|
||||
while ( j < len) {
|
||||
x[j] = a + j;
|
||||
y[j] = b + j;
|
||||
j = j + 1;
|
||||
}
|
||||
total = total + loop(x, y, len);
|
||||
i = i + 1;
|
||||
}
|
||||
stoptime();
|
||||
if ((total - 11442437121638400.000000) <=0.000001 || (total - 11442437121638400.000000) >= -0.000001) {
|
||||
putint(0);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
putint(1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
10000000
|
||||
30 2 5 4 25 8 125 16 625 32 3125 2 5 4 25 8 125 16 625 32 3125 2 5 4 25 8 125 16 625 32 3125
|
||||
@ -0,0 +1,51 @@
|
||||
int matrix[20000000];
|
||||
int a[100000];
|
||||
|
||||
int transpose(int n, int matrix[], int rowsize){
|
||||
int colsize = n / rowsize;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
while (i < colsize){
|
||||
j = 0;
|
||||
while (j < rowsize){
|
||||
if (i < j){
|
||||
j = j + 1;
|
||||
continue;
|
||||
}
|
||||
int curr = matrix[i * rowsize + j];
|
||||
matrix[j * colsize + i] = matrix[i * rowsize + j];
|
||||
matrix[i * rowsize + j] = curr;
|
||||
j = j + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int main(){
|
||||
int n = getint();
|
||||
int len = getarray(a);
|
||||
starttime();
|
||||
int i = 0;
|
||||
while (i < n){
|
||||
matrix[i] = i;
|
||||
i = i + 1;
|
||||
}
|
||||
i = 0;
|
||||
while (i < len){
|
||||
transpose(n, matrix, a[i]);
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
int ans = 0;
|
||||
i = 0;
|
||||
while (i < len){
|
||||
ans = ans + i * i * matrix[i];
|
||||
i = i + 1;
|
||||
}
|
||||
if (ans < 0) ans = -ans;
|
||||
stoptime();
|
||||
putint(ans);
|
||||
putch(10);
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
int func(int i, int j) {
|
||||
return ((i+j) * (i+j+1) / 2 + i + 1);
|
||||
}
|
||||
|
||||
float Vectordot(float v[], float u[], int n) {
|
||||
int i = 0;
|
||||
float sum = 0;
|
||||
while (i < n) {
|
||||
sum =sum+ v[i] * u[i];
|
||||
i=i+1;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
void mult1(float v[], float out[],int n) {
|
||||
int i = 0, j = 0;
|
||||
float sum = 0;
|
||||
|
||||
while (i < n) {
|
||||
while (j < n) {
|
||||
sum =sum+ v[j] / func(i,j);
|
||||
j=j+1;
|
||||
}
|
||||
out[i] = sum;
|
||||
i=i+1;
|
||||
}
|
||||
}
|
||||
|
||||
void mult2(float v[], float out[], int n) {
|
||||
int i = 0, j = 0;
|
||||
float sum = 0;
|
||||
|
||||
while (i < n) {
|
||||
while (j < n) {
|
||||
sum =sum+ v[j] / func(j,i);
|
||||
j=j+1;
|
||||
}
|
||||
out[i] = sum;
|
||||
i=i+1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mult_combin(float v[], float out[], int n, float tmp[]) {
|
||||
mult1(v, tmp, n);
|
||||
mult2(tmp, out, n);
|
||||
}
|
||||
|
||||
float temp = 1;
|
||||
float my_sqrt(float input) {
|
||||
while (temp - input / temp > 1e-6 || temp - input / temp < -1e-6){
|
||||
temp = (temp+input/temp)/2;
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int n = 100000;
|
||||
if (n <= 0) {
|
||||
n = 2000;
|
||||
}
|
||||
starttime();
|
||||
float vectorA[100000], vectorB[100000], Vectortmp[100000];
|
||||
|
||||
int i;
|
||||
while(i < n) {
|
||||
vectorA[i] = 1;
|
||||
i=i+1;
|
||||
}
|
||||
i = 0;
|
||||
while(i < 1000) {
|
||||
mult_combin(vectorA, vectorB, n, Vectortmp);
|
||||
mult_combin(vectorB, vectorA, n, Vectortmp);
|
||||
i=i+1;
|
||||
}
|
||||
stoptime();
|
||||
float result = my_sqrt(Vectordot(vectorA,vectorB, n) / Vectordot(vectorB,vectorB,n));
|
||||
if(result - 1.000000 <= 1e-6 && result - 1.000000 >= -1e-6){
|
||||
putint(1);
|
||||
}else{
|
||||
putint(0);
|
||||
}
|
||||
putch(10);
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
int main(){
|
||||
return a+b;
|
||||
}
|
||||
Loading…
Reference in new issue