This commit is contained in:
nora 2023-05-24 20:24:19 +02:00
parent f321d0e9e1
commit ee0b311261
12 changed files with 265 additions and 36 deletions

9
.gitignore vendored
View file

@ -1,5 +1,8 @@
/target
.idea
.vscode
/.idea
/.vscode
# for testing things
_*.c
/_*.c
# any object files and a.out
*.o
*.out

107
Cargo.lock generated
View file

@ -19,6 +19,17 @@ dependencies = [
"version_check",
]
[[package]]
name = "ahash"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57e6e951cfbb2db8de1828d49073a113a29fd7117b1596caa781a258c7e38d72"
dependencies = [
"cfg-if",
"once_cell",
"version_check",
]
[[package]]
name = "aho-corasick"
version = "0.7.18"
@ -72,6 +83,12 @@ version = "3.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
version = "1.0.73"
@ -85,8 +102,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "codegen_x86"
name = "codegen"
version = "0.1.0"
dependencies = [
"analysis",
"iced-x86",
"object",
"parser",
]
[[package]]
name = "console"
@ -178,7 +201,7 @@ version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
dependencies = [
"ahash",
"ahash 0.7.6",
]
[[package]]
@ -187,6 +210,24 @@ version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3"
[[package]]
name = "hashbrown"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
dependencies = [
"ahash 0.8.0",
]
[[package]]
name = "iced-x86"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dd04b950d75b3498320253b17fb92745b2cc79ead8814aede2f7c1bab858bec"
dependencies = [
"lazy_static",
]
[[package]]
name = "indexmap"
version = "1.9.1"
@ -283,6 +324,20 @@ dependencies = [
"libc",
]
[[package]]
name = "object"
version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1"
dependencies = [
"crc32fast",
"flate2",
"hashbrown 0.13.2",
"indexmap",
"memchr",
"ruzstd",
]
[[package]]
name = "once_cell"
version = "1.12.0"
@ -402,6 +457,17 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "ruzstd"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a15e661f0f9dac21f3494fe5d23a6338c0ac116a2d22c2b63010acd89467ffe"
dependencies = [
"byteorder",
"thiserror",
"twox-hash",
]
[[package]]
name = "ryu"
version = "1.0.10"
@ -484,6 +550,12 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043"
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "syn"
version = "1.0.98"
@ -538,6 +610,26 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "thiserror"
version = "1.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "time"
version = "0.3.11"
@ -549,6 +641,16 @@ dependencies = [
"num_threads",
]
[[package]]
name = "twox-hash"
version = "1.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
dependencies = [
"cfg-if",
"static_assertions",
]
[[package]]
name = "unicode-ident"
version = "1.0.1"
@ -576,6 +678,7 @@ version = "0.1.0"
dependencies = [
"analysis",
"bumpalo",
"codegen",
"dbg-pls",
"parser",
]

View file

@ -1,5 +1,5 @@
[workspace]
members = [".", "./parser", "./analysis", "./codegen_x86"]
members = [".", "./parser", "./analysis", "./codegen"]
[package]
name = "uwucc"
@ -11,5 +11,6 @@ edition = "2021"
[dependencies]
bumpalo = "3.10.0"
analysis = { path = "./analysis" }
codegen = { path = "./codegen" }
parser = { path = "./parser" }
dbg-pls = { version = "0.3.2", features = ["derive", "colors"] }

View file

@ -12,7 +12,7 @@ use crate::{
};
#[derive(Debug)]
pub(crate) struct LoweringCx<'cx> {
pub struct LoweringCx<'cx> {
tys: RefCell<FxHashSet<&'cx TyKind<'cx>>>,
layouts: RefCell<FxHashSet<&'cx Layout>>,
string_literals: RefCell<FxHashMap<&'cx [u8], DefId>>,
@ -23,7 +23,7 @@ pub(crate) struct LoweringCx<'cx> {
}
impl<'cx> LoweringCx<'cx> {
pub(crate) fn new(arena: &'cx bumpalo::Bump) -> Self {
pub fn new(arena: &'cx bumpalo::Bump) -> Self {
LoweringCx {
tys: RefCell::default(),
layouts: RefCell::default(),

View file

@ -2,17 +2,18 @@
#![warn(rust_2018_idioms)]
mod ctxt;
mod ir;
pub mod ir;
mod lower;
mod ty;
pub mod ty;
pub use ctxt::LoweringCx;
pub use lower::lower_translation_unit;
use parser::Span;
#[derive(Debug)]
pub struct Error {
msg: String,
span: Span,
span: Option<Span>,
notes: Vec<Note>,
}
@ -26,7 +27,15 @@ impl Error {
pub fn new(msg: impl Into<String>, span: Span) -> Self {
Self {
msg: msg.into(),
span,
span: Some(span),
notes: Vec::new(),
}
}
pub fn new_without_span(msg: impl Into<String>) -> Self {
Self {
msg: msg.into(),
span: None,
notes: Vec::new(),
}
}

View file

@ -21,11 +21,9 @@ use crate::{
type Result<T, E = Error> = std::result::Result<T, E>;
pub fn lower_translation_unit<'cx>(
arena: &'cx bumpalo::Bump,
lcx: &mut LoweringCx<'cx>,
ast: &ast::TranslationUnit,
) -> Result<Ir<'cx>, Error> {
let mut lcx = LoweringCx::new(arena);
let mut ir = Ir {
funcs: FxHashMap::default(),
};

20
codegen/Cargo.toml Normal file
View file

@ -0,0 +1,20 @@
[package]
name = "codegen"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
analysis = { path = "../analysis" }
iced-x86 = { version = "1.18.0", default-features = false, features = [
"encoder",
"block_encoder",
"op_code_info",
"instr_info",
"nasm", # for debugging output
"code_asm",
"std",
] }
object = { version = "0.31.1", features = ["write"] }
parser = { path = "../parser" }

72
codegen/src/lib.rs Normal file
View file

@ -0,0 +1,72 @@
mod x86;
use std::process::Stdio;
use analysis::{ir::Ir, LoweringCx};
use object::{
elf,
write::{Object, Symbol},
};
type Result<T, E = analysis::Error> = std::result::Result<T, E>;
pub fn generate<'cx>(lcx: &LoweringCx<'cx>, ir: &Ir<'cx>) -> Result<()> {
let mut obj = Object::new(
object::BinaryFormat::Elf,
object::Architecture::X86_64,
object::Endianness::Little,
);
let text = obj.add_section(Vec::new(), b".text".to_vec(), object::SectionKind::Text);
for (_def_id, func) in &ir.funcs {
let code = x86::generate_func(lcx, func)?;
let offset = obj.append_section_data(text, &code, 8);
let sym = Symbol {
name: func.name.as_str(|s| s.as_bytes().to_vec()),
value: offset,
size: code.len().try_into().unwrap(),
kind: object::SymbolKind::Text,
scope: object::SymbolScope::Linkage,
weak: false,
section: object::write::SymbolSection::Section(text),
flags: object::SymbolFlags::Elf {
st_info: ((elf::STB_GLOBAL) << 4) | (elf::STT_FUNC),
st_other: elf::STV_DEFAULT,
},
};
obj.add_symbol(sym);
}
let object_file = obj.write().map_err(|err| {
analysis::Error::new_without_span(format!("failed to create object file: {err}"))
})?;
std::fs::write("main.o", object_file).map_err(|err| {
analysis::Error::new_without_span(format!("failed to write object file main.o: {err}"))
})?;
let output = std::process::Command::new("cc")
.arg("main.o")
.stdout(Stdio::inherit())
.stdout(Stdio::inherit())
.output()
.map_err(|err| analysis::Error::new_without_span(format!("failed to spawn `cc`: {err}")))?;
if !output.status.success() {
return Err(analysis::Error::new_without_span(format!(
"linking with `cc` failed"
)));
} else {
std::fs::remove_file("main.o").map_err(|err| {
analysis::Error::new_without_span(format!(
"failed to remove temporary file main.o: {err}"
))
})?;
}
Ok(())
}

32
codegen/src/x86.rs Normal file
View file

@ -0,0 +1,32 @@
use analysis::{ir::Func, LoweringCx};
use iced_x86::{code_asm as x, IcedError};
use parser::Span;
use crate::Result;
trait IcedErrExt {
type T;
fn sp(self, span: Span) -> Result<Self::T, analysis::Error>;
}
impl<T> IcedErrExt for Result<T, IcedError> {
type T = T;
fn sp(self, span: Span) -> Result<Self::T, analysis::Error> {
self.map_err(|e| analysis::Error::new(e.to_string(), span))
}
}
pub fn generate_func<'cx>(_lcx: &LoweringCx<'cx>, func: &Func<'cx>) -> Result<Vec<u8>> {
assert_eq!(func.arity, 0, "arguments??? in MY uwucc????");
let sp = func.def_span;
let mut a = x::CodeAssembler::new(64).sp(sp)?;
a.xor(x::rax, x::rax).sp(sp)?;
a.ret().sp(sp)?;
let code = a.assemble(0x4000).sp(sp)?;
Ok(code)
}

View file

@ -1,8 +0,0 @@
[package]
name = "codegen_x86"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -1,6 +0,0 @@
#![allow(dead_code)] // TODO: no
#![warn(rust_2018_idioms)]
pub fn generate() {
println!("ud2");
}

View file

@ -1,3 +1,5 @@
use analysis::LoweringCx;
fn main() {
let input_file = std::env::args().nth(1).expect("first argument");
let src = std::fs::read_to_string(&input_file).unwrap_or_else(|err| {
@ -16,12 +18,15 @@ fn main() {
println!("// END CODE -------------------");
let arena = bumpalo::Bump::new();
let mut lcx = LoweringCx::new(&arena);
let ir = analysis::lower_translation_unit(&arena, &ast);
match ir {
Ok(_) => {}
Err(err) => {
let ir = analysis::lower_translation_unit(&mut lcx, &ast).unwrap_or_else(|err| {
dbg!(err);
}
}
std::process::exit(1);
});
codegen::generate(&lcx, &ir).unwrap_or_else(|err| {
dbg!(err);
std::process::exit(1);
});
}