From 63d5c4bb35c0500c46c73cb102faea76d67a9a3b Mon Sep 17 00:00:00 2001 From: Jiayi Zhuang Date: Thu, 19 Sep 2024 20:23:28 +0800 Subject: [PATCH 01/11] feat: setup bootstrap and ci --- .github/workflows/main.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 94ed5ee..724c389 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -72,4 +72,4 @@ jobs: steps: # Manually check the status of all dependencies. `if: failure()` does not work. - name: check if any dependency failed - run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' + run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' \ No newline at end of file From 5ab74de2574bd7705189c181868fc716068f7177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BF=98=E5=BF=A7=E5=8C=97=E8=90=B1=E8=8D=89?= Date: Sat, 20 Jul 2024 11:52:04 +0800 Subject: [PATCH 02/11] chore: readme and license --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index 649a0f6..06a6ea6 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,22 @@ C based backend for rustc +[![CI](https://github.com/rust-lang/rustc_codegen_c/actions/workflows/ci.yml/badge.svg)](https://github.com/rust-lang/rustc_codegen_c/actions/workflows/ci.yml) + +This a C codegen backend for rustc, which lowers Rust MIR to C code and compiles +it with a C compiler. + +This code is still highly experimental and not ready for production use. + +## Try it + +```bash +./y.sh rustc example/example.rs +./build/example +``` + +The usage of `y.sh` can be viewed from `./y.sh help`. + ## License This project is licensed under a dual license: MIT or Apache 2.0. From 7d0dec85249e54f86c8bd718151f34a6f0845de8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BF=98=E5=BF=A7=E5=8C=97=E8=90=B1=E8=8D=89?= Date: Sun, 21 Jul 2024 00:32:48 +0800 Subject: [PATCH 03/11] feat(bootstrap): format --- .github/workflows/ci.yml | 35 +++ bootstrap/src/test.rs | 1 + crates/rustc_codegen_c/src/module.rs | 407 +++++++++++++++++++++++++++ 3 files changed, 443 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 crates/rustc_codegen_c/src/module.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..e8e14c8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,35 @@ +name: CI + +on: + push: + pull_request: + +permissions: + contents: read + +env: + CARGO_TERM_COLOR: always + RUST_BACKTRACE: 1 + +jobs: + test: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + + # `rustup show` installs from rust-toolchain.toml + - name: Setup rust toolchain + run: rustup show + + - name: Setup rust cache + uses: Swatinem/rust-cache@v2 + + - name: Install packages + run: | + sudo apt-get install llvm-14-tools + + - name: Run tests + run: ./y test + + - name: Check format + run: ./y fmt --check diff --git a/bootstrap/src/test.rs b/bootstrap/src/test.rs index 476651f..43e4110 100644 --- a/bootstrap/src/test.rs +++ b/bootstrap/src/test.rs @@ -79,6 +79,7 @@ impl TestCommand { } pub enum TestType { + /// Test an executable can be compiled Compile, FileCheck, } diff --git a/crates/rustc_codegen_c/src/module.rs b/crates/rustc_codegen_c/src/module.rs new file mode 100644 index 0000000..db3b26f --- /dev/null +++ b/crates/rustc_codegen_c/src/module.rs @@ -0,0 +1,407 @@ +//! C Module +//! +//! A module is a in-memory representation of a C file. +//! +//! The structure is derived from clang's AST. + +use std::borrow::Cow; +use std::fmt::{Display, Formatter}; + +use parking_lot::RwLock; +use rustc_hash::FxHashMap; +use rustc_type_ir::{IntTy, UintTy}; + +use crate::utils::sharded_slab::{Entry, Id, ShardedSlab}; + +/// Rust's primitive types +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum PimitiveType { + Int(IntTy), + Uint(UintTy), +} + +pub struct ModuleContext { + types: ShardedSlab, + primitive_types: RwLock>, + pub module: Module, +} + +impl Default for ModuleContext { + fn default() -> Self { + Self::new() + } +} + +impl ModuleContext { + pub fn new() -> Self { + Self { + types: ShardedSlab::default(), + primitive_types: RwLock::new(FxHashMap::default()), + module: Module::new(), + } + } + + /// Get the type + pub fn ty(&self, id: CType) -> Entry { + self.types.get(id).unwrap() + } + + /// Get the type of an signed integer + pub fn get_int_type(&self, int: IntTy) -> CType { + if let Some(ty) = self.primitive_types.read().get(&PimitiveType::Int(int)) { + return *ty; + } + + let tykind = match int { + IntTy::Isize => CTypeKind::Builtin("ssize_t".to_string()), + IntTy::I8 => CTypeKind::Builtin("int8_t".to_string()), + IntTy::I16 => CTypeKind::Builtin("int16_t".to_string()), + IntTy::I32 => CTypeKind::Builtin("int32_t".to_string()), + IntTy::I64 => CTypeKind::Builtin("int64_t".to_string()), + IntTy::I128 => todo!(), + }; + let ty = self.types.insert(tykind); + self.primitive_types.write().insert(PimitiveType::Int(int), ty); + ty + } + + /// Get the type of an unsigned integer + pub fn get_uint_type(&self, uint: UintTy) -> CType { + if let Some(ty) = self.primitive_types.read().get(&PimitiveType::Uint(uint)) { + return *ty; + } + + let tykind = match uint { + UintTy::Usize => CTypeKind::Builtin("size_t".to_string()), + UintTy::U8 => CTypeKind::Builtin("uint8_t".to_string()), + UintTy::U16 => CTypeKind::Builtin("uint16_t".to_string()), + UintTy::U32 => CTypeKind::Builtin("uint32_t".to_string()), + UintTy::U64 => CTypeKind::Builtin("uint64_t".to_string()), + UintTy::U128 => todo!(), + }; + let ty = self.types.insert(tykind); + self.primitive_types.write().insert(PimitiveType::Uint(uint), ty); + ty + } +} + +impl Display for ModuleContext { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.module.fmt_with(f, self) + } +} + +pub struct Module { + pub includes: Vec, + pub decls: Vec, +} + +impl Default for Module { + fn default() -> Self { + Self::new() + } +} + +impl Module { + pub fn new() -> Self { + let includes = vec!["stdint.h".to_string()]; + let decls = vec![]; + Self { includes, decls } + } + + pub fn display<'a>(&'a self, ctx: &'a ModuleContext) -> impl Display + 'a { + struct ModuleDisplay<'a>(&'a Module, &'a ModuleContext); + impl<'a> Display for ModuleDisplay<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.0.fmt_with(f, self.1) + } + } + ModuleDisplay(self, ctx) + } + + fn fmt_with(&self, f: &mut Formatter<'_>, ctx: &ModuleContext) -> std::fmt::Result { + for include in &self.includes { + writeln!(f, "#include <{}>", include)?; + } + for decl in &self.decls { + writeln!(f, "{}", decl.display(ctx))?; + } + Ok(()) + } +} + +pub enum CDecl { + Typedef { name: String, ty: CType }, + Record { name: String, fields: Vec }, + Field { name: String, ty: CType }, + Enum { name: String, values: Vec }, + FunctionDecl { name: String, ty: CType, params: Vec }, + Function(CFunction), + // Var { name: String, ty: CType, init: Option }, + Raw(String), +} + +impl CDecl { + pub fn display<'a>(&'a self, ctx: &'a ModuleContext) -> impl Display + 'a { + struct CDeclDisplay<'a>(&'a CDecl, &'a ModuleContext); + impl<'a> Display for CDeclDisplay<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.0.fmt_with(f, self.1) + } + } + CDeclDisplay(self, ctx) + } + + fn fmt_with(&self, f: &mut Formatter<'_>, ctx: &ModuleContext) -> std::fmt::Result { + match self { + CDecl::Typedef { name, ty } => { + write!(f, "typedef {} {};", name, ctx.ty(*ty).display(ctx)) + } + CDecl::Record { name, fields } => { + writeln!(f, "struct {} {{ ", name)?; + for field in fields { + writeln!(f, "{}", field.display(ctx))?; + } + writeln!(f, "}};") + } + CDecl::Field { name, ty } => write!(f, "{} {}", name, ctx.ty(*ty).display(ctx)), + CDecl::Enum { name, values } => { + writeln!(f, "enum {} {{ ", name)?; + for (i, value) in values.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + writeln!(f, "{}", value)?; + } + writeln!(f, "}};") + } + CDecl::FunctionDecl { name, ty, params } => { + write!(f, "{} {}(", ctx.ty(*ty).display(ctx), name)?; + for (i, param) in params.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + write!(f, "{}", ctx.ty(*param).display(ctx))?; + } + write!(f, ");") + } + CDecl::Function(func) => write!(f, "{}", func.display(ctx)), + // CDecl::Var { name, ty, init } => { + // write!(f, "{} {}", ty, name)?; + // if let Some(init) = init { + // write!(f, " = {}", init)?; + // } + // write!(f, ";") + // } + CDecl::Raw(s) => write!(f, "{}", s), + } + } +} + +pub type CType = Id; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum CTypeKind { + Builtin(String), + Pointer(CType), + Record(String), + Array(CType, usize), +} + +impl CTypeKind { + pub fn display<'a>(&'a self, ctx: &'a ModuleContext) -> impl Display + 'a { + struct DisplayCTypeKind<'a>(&'a CTypeKind, &'a ModuleContext); + impl<'a> Display for DisplayCTypeKind<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.0.fmt_with(f, self.1) + } + } + DisplayCTypeKind(self, ctx) + } + + fn fmt_with(&self, f: &mut Formatter<'_>, ctx: &ModuleContext) -> std::fmt::Result { + match self { + CTypeKind::Builtin(ty) => write!(f, "{}", ty), + CTypeKind::Pointer(ty) => write!(f, "{}*", ctx.ty(*ty).display(ctx)), + CTypeKind::Record(ty) => write!(f, "struct {}", ty), + CTypeKind::Array(ty, size) => write!(f, "{}[{}]", ctx.ty(*ty).display(ctx), size), + } + } +} + +pub struct CEnumConstant { + pub name: String, + // pub value: Option, +} + +impl Display for CEnumConstant { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.name)?; + // if let Some(value) = &self.value { + // write!(f, " = {}", value)?; + // } + Ok(()) + } +} + +/// Values of C variable, parameters and scalars +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] +pub enum CValue { + Scalar(i128), + Var(usize), +} + +pub struct CFunction { + pub name: String, + pub ty: CType, + pub params: Vec<(CType, CValue)>, + pub body: Vec, + pub var_names: FxHashMap, +} + +impl CFunction { + pub fn get_var_name(&self, var: CValue) -> Cow { + if let Some(name) = self.var_names.get(&var) { + Cow::Borrowed(name) + } else { + Cow::Owned(match var { + CValue::Scalar(scalar) => format!("{}", scalar), + CValue::Var(index) => format!("_{}", index), + }) + } + } +} + +impl CFunction { + pub fn display<'a>(&'a self, ctx: &'a ModuleContext) -> impl Display + '_ { + struct CFunctionDisplay<'a>(&'a CFunction, &'a ModuleContext); + impl<'a> Display for CFunctionDisplay<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.0.fmt_with(f, self.1) + } + } + CFunctionDisplay(self, ctx) + } + + fn fmt_with(&self, f: &mut Formatter<'_>, ctx: &ModuleContext) -> std::fmt::Result { + write!(f, "{} {}(", ctx.ty(self.ty).display(ctx), self.name)?; + for (i, (ty, param)) in self.params.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + write!(f, "{} {}", ctx.ty(*ty).display(ctx), self.get_var_name(*param))?; + } + write!(f, ") {{")?; + for stmt in &self.body { + writeln!(f, "{}", stmt.display(self, ctx))?; + } + write!(f, "}}") + } +} + +pub enum CStmt { + Compound(Vec), + If { cond: Box, then_br: Box, else_br: Option> }, + Return(Option>), + Decl(Box), + Expr(CExpr), +} + +impl CStmt { + pub fn display<'a>(&'a self, fun: &'a CFunction, ctx: &'a ModuleContext) -> impl Display + '_ { + struct CStmtDisplay<'a>(&'a CStmt, &'a CFunction, &'a ModuleContext); + impl<'a> Display for CStmtDisplay<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.0.fmt_with(f, self.1, self.2) + } + } + CStmtDisplay(self, fun, ctx) + } + + fn fmt_with( + &self, + f: &mut Formatter<'_>, + fun: &CFunction, + ctx: &ModuleContext, + ) -> std::fmt::Result { + match self { + CStmt::Compound(stmts) => { + writeln!(f, "{{")?; + for stmt in stmts { + writeln!(f, "{}", stmt.display(fun, ctx))?; + } + write!(f, "}}") + } + CStmt::If { cond, then_br: then_, else_br: else_ } => { + writeln!(f, "if ({}) {{", cond.display(fun))?; + writeln!(f, "{}", then_.display(fun, ctx))?; + if let Some(else_) = else_ { + writeln!(f, "}} else {{")?; + writeln!(f, "{}", else_.display(fun, ctx))?; + } + write!(f, "}}") + } + CStmt::Return(expr) => { + write!(f, "return")?; + if let Some(expr) = expr { + write!(f, " {}", expr.display(fun))?; + } + write!(f, ";") + } + CStmt::Decl(decl) => write!(f, "{}", decl.display(ctx)), + CStmt::Expr(expr) => write!(f, "{};", expr.display(fun)), + } + } +} + +pub enum CExpr { + Literal(String), + Value(CValue), + BinaryOperator { lhs: Box, rhs: Box, op: String }, + Call { callee: Box, args: Vec }, + Member { expr: Box, arrow: bool, field: String }, +} + +impl CExpr { + pub fn display<'a>(&'a self, fun: &'a CFunction) -> impl Display + '_ { + struct CExprDisplay<'a>(&'a CExpr, &'a CFunction); + impl<'a> Display for CExprDisplay<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.0.fmt_with(f, self.1) + } + } + CExprDisplay(self, fun) + } + + fn fmt_with(&self, f: &mut Formatter<'_>, fun: &CFunction) -> std::fmt::Result { + match self { + CExpr::Literal(lit) => write!(f, "{}", lit), + CExpr::Value(val) => { + let name = fun.get_var_name(*val); + write!(f, "{}", name) + } + CExpr::BinaryOperator { lhs, rhs, op } => { + write!(f, "({} {} {})", lhs.display(fun), op, rhs.display(fun)) + } + CExpr::Call { callee, args } => { + write!(f, "{}(", callee.display(fun))?; + for (i, arg) in args.iter().enumerate() { + if i != 0 { + write!(f, ", ")?; + } + write!(f, "{}", arg.display(fun))?; + } + write!(f, ")") + } + CExpr::Member { expr, arrow, field } => { + write!(f, "{}", expr.display(fun))?; + if *arrow { + write!(f, "->")?; + } else { + write!(f, ".")?; + } + write!(f, "{}", field) + } + } + } +} From 23e321f59094b224c8a0cd4e49fd5df2662f1c71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BF=98=E5=BF=A7=E5=8C=97=E8=90=B1=E8=8D=89?= Date: Wed, 3 Jul 2024 09:40:23 +0800 Subject: [PATCH 04/11] feat: function signature --- bootstrap/src/test.rs | 28 + crates/rustc_codegen_c/Cargo.toml | 4 +- crates/rustc_codegen_c/src/base.rs | 60 +- crates/rustc_codegen_c/src/builder.rs | 690 ++++++++++++++++++ crates/rustc_codegen_c/src/builder/abi.rs | 36 + crates/rustc_codegen_c/src/builder/asm.rs | 20 + .../src/builder/coverage_info.rs | 13 + .../rustc_codegen_c/src/builder/debug_info.rs | 32 + .../src/builder/intrinsic_call.rs | 52 ++ crates/rustc_codegen_c/src/builder/static.rs | 10 + crates/rustc_codegen_c/src/context.rs | 127 ++++ crates/rustc_codegen_c/src/context/asm.rs | 16 + .../rustc_codegen_c/src/context/base_type.rs | 85 +++ crates/rustc_codegen_c/src/context/const.rs | 107 +++ .../rustc_codegen_c/src/context/debug_info.rs | 69 ++ .../src/context/layout_type.rs | 53 ++ crates/rustc_codegen_c/src/context/misc.rs | 48 ++ .../rustc_codegen_c/src/context/pre_define.rs | 48 ++ crates/rustc_codegen_c/src/context/static.rs | 23 + .../src/context/type_membership.rs | 5 + crates/rustc_codegen_c/src/lib.rs | 19 +- crates/rustc_codegen_c/src/module.rs | 336 ++------- crates/rustc_codegen_c/src/write.rs | 63 +- example/example.rs | 15 + example/mini_core.rs | 39 + tests/codegen/filename.rs | 16 + 26 files changed, 1737 insertions(+), 277 deletions(-) create mode 100644 crates/rustc_codegen_c/src/builder.rs create mode 100644 crates/rustc_codegen_c/src/builder/abi.rs create mode 100644 crates/rustc_codegen_c/src/builder/asm.rs create mode 100644 crates/rustc_codegen_c/src/builder/coverage_info.rs create mode 100644 crates/rustc_codegen_c/src/builder/debug_info.rs create mode 100644 crates/rustc_codegen_c/src/builder/intrinsic_call.rs create mode 100644 crates/rustc_codegen_c/src/builder/static.rs create mode 100644 crates/rustc_codegen_c/src/context.rs create mode 100644 crates/rustc_codegen_c/src/context/asm.rs create mode 100644 crates/rustc_codegen_c/src/context/base_type.rs create mode 100644 crates/rustc_codegen_c/src/context/const.rs create mode 100644 crates/rustc_codegen_c/src/context/debug_info.rs create mode 100644 crates/rustc_codegen_c/src/context/layout_type.rs create mode 100644 crates/rustc_codegen_c/src/context/misc.rs create mode 100644 crates/rustc_codegen_c/src/context/pre_define.rs create mode 100644 crates/rustc_codegen_c/src/context/static.rs create mode 100644 crates/rustc_codegen_c/src/context/type_membership.rs create mode 100644 example/example.rs create mode 100644 example/mini_core.rs create mode 100644 tests/codegen/filename.rs diff --git a/bootstrap/src/test.rs b/bootstrap/src/test.rs index 43e4110..d99f6f7 100644 --- a/bootstrap/src/test.rs +++ b/bootstrap/src/test.rs @@ -43,6 +43,10 @@ impl Run for TestCommand { cprint!("Compiling {}...", testcase.name); testcase.build(manifest); } + TestType::CompileLib => { + cprint!("Compiling lib {}...", testcase.name); + testcase.build_lib(manifest); + } } cprintln!("OK"); } @@ -58,6 +62,16 @@ impl TestCommand { let case = case.unwrap(); let filename = case.file_stem().unwrap(); if filename == "mini_core" { + // First compile mini_core + result.insert( + 0, + TestCase { + name: "mini_core".into(), + source: case.clone(), + output: manifest.out_dir.join(Path::new(filename)), + test: TestType::CompileLib, + }, + ); continue; } let name = format!("example/{}", filename.to_string_lossy()); @@ -81,6 +95,7 @@ impl TestCommand { pub enum TestType { /// Test an executable can be compiled Compile, + CompileLib, FileCheck, } @@ -104,6 +119,19 @@ impl TestCase { log::debug!("running {:?}", command); command.status().unwrap(); } + + pub fn build_lib(&self, manifest: &Manifest) { + std::fs::create_dir_all(self.output.parent().unwrap()).unwrap(); + let mut command = manifest.rustc(); + command + .args(["--crate-type", "lib"]) + .arg("-O") + .arg(&self.source) + .arg("--out-dir") + .arg(self.output.parent().unwrap()); + log::debug!("running {:?}", command); + command.status().unwrap(); + } } struct FileChecker { diff --git a/crates/rustc_codegen_c/Cargo.toml b/crates/rustc_codegen_c/Cargo.toml index 98d3d36..5114a66 100644 --- a/crates/rustc_codegen_c/Cargo.toml +++ b/crates/rustc_codegen_c/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_codegen_c" -version = "0.1.0" edition = "2021" +version.workspace = true [lib] crate-type = ["dylib"] @@ -10,4 +10,4 @@ crate-type = ["dylib"] # This package uses rustc crates. [package.metadata.rust-analyzer] -rustc_private=true +rustc_private = true diff --git a/crates/rustc_codegen_c/src/base.rs b/crates/rustc_codegen_c/src/base.rs index 354ba2f..87a2684 100644 --- a/crates/rustc_codegen_c/src/base.rs +++ b/crates/rustc_codegen_c/src/base.rs @@ -1,9 +1,59 @@ -use rustc_codegen_ssa::ModuleCodegen; +use std::time::Instant; + +use rustc_codegen_ssa::mono_item::MonoItemExt; +use rustc_codegen_ssa::{ModuleCodegen, ModuleKind}; +use rustc_middle::dep_graph; use rustc_middle::ty::TyCtxt; +use crate::builder::Builder; +use crate::context::CodegenCx; +use crate::module::Module; + +// note: parallel +// it seems this function will be invoked parallelly (if parallel codegen is enabled) + pub fn compile_codegen_unit( - _tcx: TyCtxt<'_>, - _cgu_name: rustc_span::Symbol, -) -> (ModuleCodegen<()>, u64) { - todo!() + tcx: TyCtxt<'_>, + cgu_name: rustc_span::Symbol, +) -> (ModuleCodegen, u64) { + let start_time = Instant::now(); + + let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx); + let (module, _) = tcx.dep_graph.with_task( + dep_node, + tcx, + cgu_name, + module_codegen, + Some(dep_graph::hash_result), + ); + + let time_to_codegen = start_time.elapsed(); + let cost = time_to_codegen + .as_secs() + .saturating_mul(1_000_000_000) + .saturating_add(time_to_codegen.subsec_nanos() as u64); + + (module, cost) +} + +fn module_codegen(tcx: TyCtxt<'_>, cgu_name: rustc_span::Symbol) -> ModuleCodegen { + let cgu = tcx.codegen_unit(cgu_name); + + let cx = CodegenCx::new(tcx); + + let mono_items = cgu.items_in_deterministic_order(tcx); + for &(mono_item, data) in &mono_items { + mono_item.predefine::>(&cx, data.linkage, data.visibility); + } + + // ... and now that we have everything pre-defined, fill out those definitions. + for &(mono_item, _) in &mono_items { + mono_item.define::>(&cx); + } + + ModuleCodegen { + name: cgu_name.to_string(), + module_llvm: cx.finish(), + kind: ModuleKind::Regular, + } } diff --git a/crates/rustc_codegen_c/src/builder.rs b/crates/rustc_codegen_c/src/builder.rs new file mode 100644 index 0000000..c95266a --- /dev/null +++ b/crates/rustc_codegen_c/src/builder.rs @@ -0,0 +1,690 @@ +#![allow(unused_variables)] // TODO + +use std::ops::Deref; + +use rustc_abi::{HasDataLayout, TargetDataLayout}; +use rustc_codegen_ssa::traits::{BackendTypes, BuilderMethods, HasCodegen}; +use rustc_middle::ty::layout::{ + FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, + TyAndLayout, +}; +use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; +use rustc_target::abi::call::FnAbi; +use rustc_target::spec::{HasTargetSpec, Target}; + +use crate::context::CodegenCx; + +mod abi; +mod asm; +mod coverage_info; +mod debug_info; +mod intrinsic_call; +mod r#static; + +pub struct Builder<'a, 'tcx> { + pub cx: &'a CodegenCx<'tcx>, +} + +impl<'a, 'tcx> Deref for Builder<'a, 'tcx> { + type Target = CodegenCx<'tcx>; + + fn deref<'b>(&'b self) -> &'a Self::Target { + self.cx + } +} + +impl<'tcx> HasCodegen<'tcx> for Builder<'_, 'tcx> { + type CodegenCx = CodegenCx<'tcx>; +} + +impl<'tcx> HasDataLayout for Builder<'_, 'tcx> { + fn data_layout(&self) -> &TargetDataLayout { + todo!() + } +} + +impl<'tcx> HasTyCtxt<'tcx> for Builder<'_, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.cx.tcx() + } +} + +impl<'tcx> HasParamEnv<'tcx> for Builder<'_, 'tcx> { + fn param_env(&self) -> ParamEnv<'tcx> { + self.cx.param_env() + } +} + +impl<'tcx> BackendTypes for Builder<'_, 'tcx> { + type Value = as BackendTypes>::Value; + type Function = as BackendTypes>::Function; + type BasicBlock = as BackendTypes>::BasicBlock; + type Type = as BackendTypes>::Type; + type Funclet = as BackendTypes>::Funclet; + + type DIScope = as BackendTypes>::DIScope; + type DILocation = as BackendTypes>::DILocation; + type DIVariable = as BackendTypes>::DIVariable; +} + +impl<'tcx> HasTargetSpec for Builder<'_, 'tcx> { + fn target_spec(&self) -> &Target { + todo!() + } +} + +impl<'tcx> LayoutOfHelpers<'tcx> for Builder<'_, 'tcx> { + type LayoutOfResult = TyAndLayout<'tcx>; + + fn handle_layout_err(&self, err: LayoutError<'tcx>, span: rustc_span::Span, ty: Ty<'tcx>) -> ! { + todo!() + } +} + +impl<'tcx> FnAbiOfHelpers<'tcx> for Builder<'_, 'tcx> { + type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>; + + fn handle_fn_abi_err( + &self, + err: FnAbiError<'tcx>, + span: rustc_span::Span, + fn_abi_request: FnAbiRequest<'tcx>, + ) -> ! { + todo!() + } +} + +impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { + fn build(cx: &'a Self::CodegenCx, llbb: Self::BasicBlock) -> Self { + Self { cx } + } + + fn cx(&self) -> &Self::CodegenCx { + self.cx + } + + fn llbb(&self) -> Self::BasicBlock { + todo!() + } + + fn set_span(&mut self, _span: rustc_span::Span) {} + + fn append_block(cx: &'a Self::CodegenCx, llfn: Self::Function, name: &str) -> Self::BasicBlock { + crate::todo() + } + + fn append_sibling_block(&mut self, name: &str) -> Self::BasicBlock { + todo!() + } + + fn switch_to_block(&mut self, llbb: Self::BasicBlock) { + todo!() + } + + fn ret_void(&mut self) { + crate::todo() + } + + fn ret(&mut self, v: Self::Value) { + crate::todo() + } + + fn br(&mut self, dest: Self::BasicBlock) { + todo!() + } + + fn cond_br( + &mut self, + cond: Self::Value, + then_llbb: Self::BasicBlock, + else_llbb: Self::BasicBlock, + ) { + todo!() + } + + fn switch( + &mut self, + v: Self::Value, + else_llbb: Self::BasicBlock, + cases: impl ExactSizeIterator, + ) { + todo!() + } + + fn invoke( + &mut self, + llty: Self::Type, + fn_attrs: Option<&rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs>, + fn_abi: Option<&rustc_target::abi::call::FnAbi<'tcx, rustc_middle::ty::Ty<'tcx>>>, + llfn: Self::Value, + args: &[Self::Value], + then: Self::BasicBlock, + catch: Self::BasicBlock, + funclet: Option<&Self::Funclet>, + instance: Option>, + ) -> Self::Value { + todo!() + } + + fn unreachable(&mut self) { + todo!() + } + + fn add(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn fadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn fadd_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn fadd_algebraic(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn sub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn fsub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn fsub_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn fsub_algebraic(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn mul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn fmul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn fmul_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn fmul_algebraic(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn udiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn exactudiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn sdiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn exactsdiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn fdiv(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn fdiv_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn fdiv_algebraic(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn urem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn srem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn frem(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn frem_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn frem_algebraic(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn shl(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn lshr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn ashr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn unchecked_sadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn unchecked_uadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn unchecked_ssub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn unchecked_usub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn unchecked_smul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn unchecked_umul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn and(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn or(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn xor(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value { + todo!() + } + + fn neg(&mut self, v: Self::Value) -> Self::Value { + todo!() + } + + fn fneg(&mut self, v: Self::Value) -> Self::Value { + todo!() + } + + fn not(&mut self, v: Self::Value) -> Self::Value { + todo!() + } + + fn checked_binop( + &mut self, + oop: rustc_codegen_ssa::traits::OverflowOp, + ty: rustc_middle::ty::Ty<'_>, + lhs: Self::Value, + rhs: Self::Value, + ) -> (Self::Value, Self::Value) { + todo!() + } + + fn from_immediate(&mut self, val: Self::Value) -> Self::Value { + todo!() + } + + fn to_immediate_scalar(&mut self, val: Self::Value, scalar: rustc_abi::Scalar) -> Self::Value { + todo!() + } + + fn alloca(&mut self, size: rustc_abi::Size, align: rustc_abi::Align) -> Self::Value { + todo!() + } + + fn dynamic_alloca(&mut self, size: Self::Value, align: rustc_abi::Align) -> Self::Value { + todo!() + } + + fn load(&mut self, ty: Self::Type, ptr: Self::Value, align: rustc_abi::Align) -> Self::Value { + todo!() + } + + fn volatile_load(&mut self, ty: Self::Type, ptr: Self::Value) -> Self::Value { + todo!() + } + + fn atomic_load( + &mut self, + ty: Self::Type, + ptr: Self::Value, + order: rustc_codegen_ssa::common::AtomicOrdering, + size: rustc_abi::Size, + ) -> Self::Value { + todo!() + } + + fn load_operand( + &mut self, + place: rustc_codegen_ssa::mir::place::PlaceRef<'tcx, Self::Value>, + ) -> rustc_codegen_ssa::mir::operand::OperandRef<'tcx, Self::Value> { + todo!() + } + + fn write_operand_repeatedly( + &mut self, + elem: rustc_codegen_ssa::mir::operand::OperandRef<'tcx, Self::Value>, + count: u64, + dest: rustc_codegen_ssa::mir::place::PlaceRef<'tcx, Self::Value>, + ) { + todo!() + } + + fn range_metadata(&mut self, load: Self::Value, range: rustc_abi::WrappingRange) { + todo!() + } + + fn nonnull_metadata(&mut self, load: Self::Value) { + todo!() + } + + fn store( + &mut self, + val: Self::Value, + ptr: Self::Value, + align: rustc_abi::Align, + ) -> Self::Value { + todo!() + } + + fn store_with_flags( + &mut self, + val: Self::Value, + ptr: Self::Value, + align: rustc_abi::Align, + flags: rustc_codegen_ssa::MemFlags, + ) -> Self::Value { + todo!() + } + + fn atomic_store( + &mut self, + val: Self::Value, + ptr: Self::Value, + order: rustc_codegen_ssa::common::AtomicOrdering, + size: rustc_abi::Size, + ) { + todo!() + } + + fn gep(&mut self, ty: Self::Type, ptr: Self::Value, indices: &[Self::Value]) -> Self::Value { + todo!() + } + + fn inbounds_gep( + &mut self, + ty: Self::Type, + ptr: Self::Value, + indices: &[Self::Value], + ) -> Self::Value { + todo!() + } + + fn trunc(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { + todo!() + } + + fn sext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { + todo!() + } + + fn fptoui_sat(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { + todo!() + } + + fn fptosi_sat(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { + todo!() + } + + fn fptoui(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { + todo!() + } + + fn fptosi(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { + todo!() + } + + fn uitofp(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { + todo!() + } + + fn sitofp(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { + todo!() + } + + fn fptrunc(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { + todo!() + } + + fn fpext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { + todo!() + } + + fn ptrtoint(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { + todo!() + } + + fn inttoptr(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { + todo!() + } + + fn bitcast(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { + todo!() + } + + fn intcast(&mut self, val: Self::Value, dest_ty: Self::Type, is_signed: bool) -> Self::Value { + todo!() + } + + fn pointercast(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { + todo!() + } + + fn icmp( + &mut self, + op: rustc_codegen_ssa::common::IntPredicate, + lhs: Self::Value, + rhs: Self::Value, + ) -> Self::Value { + todo!() + } + + fn fcmp( + &mut self, + op: rustc_codegen_ssa::common::RealPredicate, + lhs: Self::Value, + rhs: Self::Value, + ) -> Self::Value { + todo!() + } + + fn memcpy( + &mut self, + dst: Self::Value, + dst_align: rustc_abi::Align, + src: Self::Value, + src_align: rustc_abi::Align, + size: Self::Value, + flags: rustc_codegen_ssa::MemFlags, + ) { + todo!() + } + + fn memmove( + &mut self, + dst: Self::Value, + dst_align: rustc_abi::Align, + src: Self::Value, + src_align: rustc_abi::Align, + size: Self::Value, + flags: rustc_codegen_ssa::MemFlags, + ) { + todo!() + } + + fn memset( + &mut self, + ptr: Self::Value, + fill_byte: Self::Value, + size: Self::Value, + align: rustc_abi::Align, + flags: rustc_codegen_ssa::MemFlags, + ) { + todo!() + } + + fn select( + &mut self, + cond: Self::Value, + then_val: Self::Value, + else_val: Self::Value, + ) -> Self::Value { + todo!() + } + + fn va_arg(&mut self, list: Self::Value, ty: Self::Type) -> Self::Value { + todo!() + } + + fn extract_element(&mut self, vec: Self::Value, idx: Self::Value) -> Self::Value { + todo!() + } + + fn vector_splat(&mut self, num_elts: usize, elt: Self::Value) -> Self::Value { + todo!() + } + + fn extract_value(&mut self, agg_val: Self::Value, idx: u64) -> Self::Value { + todo!() + } + + fn insert_value(&mut self, agg_val: Self::Value, elt: Self::Value, idx: u64) -> Self::Value { + todo!() + } + + fn set_personality_fn(&mut self, personality: Self::Value) { + todo!() + } + + fn cleanup_landing_pad(&mut self, pers_fn: Self::Value) -> (Self::Value, Self::Value) { + todo!() + } + + fn filter_landing_pad(&mut self, pers_fn: Self::Value) -> (Self::Value, Self::Value) { + todo!() + } + + fn resume(&mut self, exn0: Self::Value, exn1: Self::Value) { + todo!() + } + + fn cleanup_pad(&mut self, parent: Option, args: &[Self::Value]) -> Self::Funclet { + todo!() + } + + fn cleanup_ret(&mut self, funclet: &Self::Funclet, unwind: Option) { + todo!() + } + + fn catch_pad(&mut self, parent: Self::Value, args: &[Self::Value]) -> Self::Funclet { + todo!() + } + + fn catch_switch( + &mut self, + parent: Option, + unwind: Option, + handlers: &[Self::BasicBlock], + ) -> Self::Value { + todo!() + } + + fn atomic_cmpxchg( + &mut self, + dst: Self::Value, + cmp: Self::Value, + src: Self::Value, + order: rustc_codegen_ssa::common::AtomicOrdering, + failure_order: rustc_codegen_ssa::common::AtomicOrdering, + weak: bool, + ) -> (Self::Value, Self::Value) { + todo!() + } + + fn atomic_rmw( + &mut self, + op: rustc_codegen_ssa::common::AtomicRmwBinOp, + dst: Self::Value, + src: Self::Value, + order: rustc_codegen_ssa::common::AtomicOrdering, + ) -> Self::Value { + todo!() + } + + fn atomic_fence( + &mut self, + order: rustc_codegen_ssa::common::AtomicOrdering, + scope: rustc_codegen_ssa::common::SynchronizationScope, + ) { + todo!() + } + + fn set_invariant_load(&mut self, load: Self::Value) { + todo!() + } + + fn lifetime_start(&mut self, ptr: Self::Value, size: rustc_abi::Size) { + todo!() + } + + fn lifetime_end(&mut self, ptr: Self::Value, size: rustc_abi::Size) { + todo!() + } + + fn instrprof_increment( + &mut self, + fn_name: Self::Value, + hash: Self::Value, + num_counters: Self::Value, + index: Self::Value, + ) { + todo!() + } + + fn call( + &mut self, + llty: Self::Type, + fn_attrs: Option<&rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs>, + fn_abi: Option<&rustc_target::abi::call::FnAbi<'tcx, rustc_middle::ty::Ty<'tcx>>>, + llfn: Self::Value, + args: &[Self::Value], + funclet: Option<&Self::Funclet>, + instance: Option>, + ) -> Self::Value { + todo!() + } + + fn zext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { + todo!() + } + + fn apply_attrs_to_cleanup_callsite(&mut self, llret: Self::Value) { + todo!() + } +} diff --git a/crates/rustc_codegen_c/src/builder/abi.rs b/crates/rustc_codegen_c/src/builder/abi.rs new file mode 100644 index 0000000..09a596a --- /dev/null +++ b/crates/rustc_codegen_c/src/builder/abi.rs @@ -0,0 +1,36 @@ +use rustc_codegen_ssa::mir::place::PlaceRef; +use rustc_codegen_ssa::traits::{AbiBuilderMethods, ArgAbiMethods}; +use rustc_middle::ty::Ty; +use rustc_target::abi::call::ArgAbi; + +use crate::builder::Builder; + +impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, 'tcx> { + fn get_param(&mut self, index: usize) -> Self::Value { + crate::todo() + } +} + +impl<'tcx> ArgAbiMethods<'tcx> for Builder<'_, 'tcx> { + fn store_fn_arg( + &mut self, + arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, + idx: &mut usize, + dst: PlaceRef<'tcx, Self::Value>, + ) { + todo!() + } + + fn store_arg( + &mut self, + arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, + val: Self::Value, + dst: PlaceRef<'tcx, Self::Value>, + ) { + todo!() + } + + fn arg_memory_ty(&self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>) -> Self::Type { + todo!() + } +} diff --git a/crates/rustc_codegen_c/src/builder/asm.rs b/crates/rustc_codegen_c/src/builder/asm.rs new file mode 100644 index 0000000..15b3d47 --- /dev/null +++ b/crates/rustc_codegen_c/src/builder/asm.rs @@ -0,0 +1,20 @@ +use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use rustc_codegen_ssa::traits::{AsmBuilderMethods, InlineAsmOperandRef}; +use rustc_middle::ty::Instance; + +use crate::builder::Builder; + +impl<'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'tcx> { + fn codegen_inline_asm( + &mut self, + template: &[InlineAsmTemplatePiece], + operands: &[InlineAsmOperandRef<'tcx, Self>], + options: InlineAsmOptions, + line_spans: &[rustc_span::Span], + instance: Instance<'_>, + dest: Option, + catch_funclet: Option<(Self::BasicBlock, Option<&Self::Funclet>)>, + ) { + todo!() + } +} diff --git a/crates/rustc_codegen_c/src/builder/coverage_info.rs b/crates/rustc_codegen_c/src/builder/coverage_info.rs new file mode 100644 index 0000000..1c93b7f --- /dev/null +++ b/crates/rustc_codegen_c/src/builder/coverage_info.rs @@ -0,0 +1,13 @@ +use rustc_codegen_ssa::traits::CoverageInfoBuilderMethods; + +use crate::builder::Builder; + +impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, 'tcx> { + fn add_coverage( + &mut self, + instance: rustc_middle::ty::Instance<'tcx>, + kind: &rustc_middle::mir::coverage::CoverageKind, + ) { + todo!() + } +} diff --git a/crates/rustc_codegen_c/src/builder/debug_info.rs b/crates/rustc_codegen_c/src/builder/debug_info.rs new file mode 100644 index 0000000..5851843 --- /dev/null +++ b/crates/rustc_codegen_c/src/builder/debug_info.rs @@ -0,0 +1,32 @@ +use rustc_codegen_ssa::traits::DebugInfoBuilderMethods; + +use crate::builder::Builder; + +impl DebugInfoBuilderMethods for Builder<'_, '_> { + fn dbg_var_addr( + &mut self, + dbg_var: Self::DIVariable, + dbg_loc: Self::DILocation, + variable_alloca: Self::Value, + direct_offset: rustc_abi::Size, + // NB: each offset implies a deref (i.e. they're steps in a pointer chain). + indirect_offsets: &[rustc_abi::Size], + // Byte range in the `dbg_var` covered by this fragment, + // if this is a fragment of a composite `DIVariable`. + fragment: Option>, + ) { + todo!() + } + + fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation) { + todo!() + } + + fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) { + todo!() + } + + fn set_var_name(&mut self, value: Self::Value, name: &str) { + todo!() + } +} diff --git a/crates/rustc_codegen_c/src/builder/intrinsic_call.rs b/crates/rustc_codegen_c/src/builder/intrinsic_call.rs new file mode 100644 index 0000000..6242c85 --- /dev/null +++ b/crates/rustc_codegen_c/src/builder/intrinsic_call.rs @@ -0,0 +1,52 @@ +use rustc_codegen_ssa::mir::operand::OperandRef; +use rustc_codegen_ssa::traits::IntrinsicCallMethods; +use rustc_middle::ty::{Instance, Ty}; +use rustc_target::abi::call::FnAbi; + +use crate::builder::Builder; + +impl<'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'tcx> { + fn codegen_intrinsic_call( + &mut self, + instance: Instance<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + args: &[OperandRef<'tcx, Self::Value>], + llresult: Self::Value, + span: rustc_span::Span, + ) -> Result<(), Instance<'tcx>> { + todo!() + } + + fn abort(&mut self) { + todo!() + } + + fn assume(&mut self, val: Self::Value) { + todo!() + } + + fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value { + todo!() + } + + fn type_test(&mut self, pointer: Self::Value, typeid: Self::Value) -> Self::Value { + todo!() + } + + fn type_checked_load( + &mut self, + llvtable: Self::Value, + vtable_byte_offset: u64, + typeid: Self::Value, + ) -> Self::Value { + todo!() + } + + fn va_start(&mut self, val: Self::Value) -> Self::Value { + todo!() + } + + fn va_end(&mut self, val: Self::Value) -> Self::Value { + todo!() + } +} diff --git a/crates/rustc_codegen_c/src/builder/static.rs b/crates/rustc_codegen_c/src/builder/static.rs new file mode 100644 index 0000000..38f19d7 --- /dev/null +++ b/crates/rustc_codegen_c/src/builder/static.rs @@ -0,0 +1,10 @@ +use rustc_codegen_ssa::traits::StaticBuilderMethods; +use rustc_hir::def_id::DefId; + +use crate::builder::Builder; + +impl<'tcx> StaticBuilderMethods for Builder<'_, 'tcx> { + fn get_static(&mut self, def_id: DefId) -> Self::Value { + todo!() + } +} diff --git a/crates/rustc_codegen_c/src/context.rs b/crates/rustc_codegen_c/src/context.rs new file mode 100644 index 0000000..45d58f4 --- /dev/null +++ b/crates/rustc_codegen_c/src/context.rs @@ -0,0 +1,127 @@ +#![allow(unused_variables)] // TODO + +use std::cell::RefCell; + +use rustc_abi::{HasDataLayout, TargetDataLayout}; +use rustc_codegen_ssa::traits::BackendTypes; +use rustc_hash::FxHashMap; +use rustc_middle::ty::layout::{ + FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, + TyAndLayout, +}; +use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; +use rustc_target::abi::call::FnAbi; +use rustc_target::spec::{HasTargetSpec, Target}; + +use crate::module::{CDecl, CParamVar, CStmt, CType, Module}; + +mod asm; +mod base_type; +mod r#const; +mod debug_info; +mod layout_type; +mod misc; +mod pre_define; +mod r#static; +mod type_membership; + +pub struct CodegenCx<'tcx> { + pub tcx: TyCtxt<'tcx>, + pub function_abis: RefCell, CType)>>, + pub functions: RefCell>, +} + +impl<'tcx> CodegenCx<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>) -> Self { + Self { + tcx, + function_abis: RefCell::new(FxHashMap::default()), + functions: RefCell::new(FxHashMap::default()), + } + } + + pub fn finish(self) -> Module { + let mut decls = vec![]; + + let function_abis = self.function_abis.borrow(); + for (name, (args, ret)) in function_abis.iter() { + decls.push(CDecl::Function { + name: name.to_string(), + ty: ret.clone(), + params: args.iter().cloned().map(|ty| CParamVar { ty, name: None }).collect(), + body: None, + }); + } + + for (name, instance) in self.functions.into_inner() { + let (args, ret) = &function_abis[&name]; + decls.push(CDecl::Function { + name, + ty: ret.clone(), + params: args.iter().cloned().map(|ty| CParamVar { ty, name: None }).collect(), + body: Some(CStmt::Compound(vec![CStmt::Decl(Box::new(CDecl::Raw(format!( + "// {}", + instance + ))))])), + }); + } + + Module { includes: vec![], decls } + } +} + +impl<'tcx> BackendTypes for CodegenCx<'tcx> { + type Value = (); + type Function = &'tcx str; + type BasicBlock = (); + type Type = (); + type Funclet = (); + type DIScope = (); + type DILocation = (); + type DIVariable = (); +} + +impl<'tcx> HasTargetSpec for CodegenCx<'tcx> { + fn target_spec(&self) -> &Target { + todo!() + } +} + +impl<'tcx> HasParamEnv<'tcx> for CodegenCx<'tcx> { + fn param_env(&self) -> ParamEnv<'tcx> { + ParamEnv::reveal_all() + } +} + +impl<'tcx> HasTyCtxt<'tcx> for CodegenCx<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } +} + +impl HasDataLayout for CodegenCx<'_> { + fn data_layout(&self) -> &TargetDataLayout { + todo!() + } +} + +impl<'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'tcx> { + type LayoutOfResult = TyAndLayout<'tcx>; + + fn handle_layout_err(&self, err: LayoutError<'tcx>, span: rustc_span::Span, ty: Ty<'tcx>) -> ! { + todo!() + } +} + +impl<'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'tcx> { + type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>; + + fn handle_fn_abi_err( + &self, + err: FnAbiError<'tcx>, + span: rustc_span::Span, + fn_abi_request: FnAbiRequest<'tcx>, + ) -> ! { + todo!() + } +} diff --git a/crates/rustc_codegen_c/src/context/asm.rs b/crates/rustc_codegen_c/src/context/asm.rs new file mode 100644 index 0000000..95905ee --- /dev/null +++ b/crates/rustc_codegen_c/src/context/asm.rs @@ -0,0 +1,16 @@ +use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use rustc_codegen_ssa::traits::{AsmMethods, GlobalAsmOperandRef}; + +use crate::context::CodegenCx; + +impl<'tcx> AsmMethods<'tcx> for CodegenCx<'tcx> { + fn codegen_global_asm( + &self, + template: &[InlineAsmTemplatePiece], + operands: &[GlobalAsmOperandRef<'tcx>], + options: InlineAsmOptions, + line_spans: &[rustc_span::Span], + ) { + todo!() + } +} diff --git a/crates/rustc_codegen_c/src/context/base_type.rs b/crates/rustc_codegen_c/src/context/base_type.rs new file mode 100644 index 0000000..9b651f1 --- /dev/null +++ b/crates/rustc_codegen_c/src/context/base_type.rs @@ -0,0 +1,85 @@ +use rustc_codegen_ssa::traits::BaseTypeMethods; + +use crate::context::CodegenCx; + +impl<'tcx> BaseTypeMethods<'tcx> for CodegenCx<'tcx> { + fn type_i8(&self) -> Self::Type { + todo!() + } + + fn type_i16(&self) -> Self::Type { + todo!() + } + + fn type_i32(&self) -> Self::Type { + todo!() + } + + fn type_i64(&self) -> Self::Type { + todo!() + } + + fn type_i128(&self) -> Self::Type { + todo!() + } + + fn type_isize(&self) -> Self::Type { + todo!() + } + + fn type_f16(&self) -> Self::Type { + todo!() + } + + fn type_f32(&self) -> Self::Type { + todo!() + } + + fn type_f64(&self) -> Self::Type { + todo!() + } + + fn type_f128(&self) -> Self::Type { + todo!() + } + + fn type_array(&self, ty: Self::Type, len: u64) -> Self::Type { + todo!() + } + + fn type_func(&self, args: &[Self::Type], ret: Self::Type) -> Self::Type { + todo!() + } + + fn type_kind(&self, ty: Self::Type) -> rustc_codegen_ssa::common::TypeKind { + todo!() + } + + fn type_ptr(&self) -> Self::Type { + todo!() + } + + fn type_ptr_ext(&self, address_space: rustc_abi::AddressSpace) -> Self::Type { + todo!() + } + + fn element_type(&self, ty: Self::Type) -> Self::Type { + todo!() + } + + fn vector_length(&self, ty: Self::Type) -> usize { + todo!() + } + + fn float_width(&self, ty: Self::Type) -> usize { + todo!() + } + + fn int_width(&self, ty: Self::Type) -> u64 { + todo!() + } + + fn val_ty(&self, v: Self::Value) -> Self::Type { + todo!() + } +} diff --git a/crates/rustc_codegen_c/src/context/const.rs b/crates/rustc_codegen_c/src/context/const.rs new file mode 100644 index 0000000..cd39e13 --- /dev/null +++ b/crates/rustc_codegen_c/src/context/const.rs @@ -0,0 +1,107 @@ +use rustc_codegen_ssa::traits::ConstMethods; +use rustc_const_eval::interpret::ConstAllocation; + +use crate::context::CodegenCx; + +impl<'tcx> ConstMethods<'tcx> for CodegenCx<'tcx> { + fn const_null(&self, t: Self::Type) -> Self::Value { + todo!() + } + + fn const_undef(&self, t: Self::Type) -> Self::Value { + todo!() + } + + fn const_poison(&self, t: Self::Type) -> Self::Value { + todo!() + } + + fn const_int(&self, t: Self::Type, i: i64) -> Self::Value { + todo!() + } + + fn const_uint(&self, t: Self::Type, i: u64) -> Self::Value { + todo!() + } + + fn const_uint_big(&self, t: Self::Type, u: u128) -> Self::Value { + todo!() + } + + fn const_bool(&self, val: bool) -> Self::Value { + todo!() + } + + fn const_i16(&self, i: i16) -> Self::Value { + todo!() + } + + fn const_i32(&self, i: i32) -> Self::Value { + todo!() + } + + fn const_i8(&self, i: i8) -> Self::Value { + todo!() + } + + fn const_u32(&self, i: u32) -> Self::Value { + todo!() + } + + fn const_u64(&self, i: u64) -> Self::Value { + todo!() + } + + fn const_u128(&self, i: u128) -> Self::Value { + todo!() + } + + fn const_usize(&self, i: u64) -> Self::Value { + todo!() + } + + fn const_u8(&self, i: u8) -> Self::Value { + todo!() + } + + fn const_real(&self, t: Self::Type, val: f64) -> Self::Value { + todo!() + } + + fn const_str(&self, s: &str) -> (Self::Value, Self::Value) { + todo!() + } + + fn const_struct(&self, elts: &[Self::Value], packed: bool) -> Self::Value { + todo!() + } + + fn const_to_opt_uint(&self, v: Self::Value) -> Option { + todo!() + } + + fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option { + todo!() + } + + fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value { + todo!() + } + + fn scalar_to_backend( + &self, + cv: rustc_const_eval::interpret::Scalar, + layout: rustc_target::abi::Scalar, + llty: Self::Type, + ) -> Self::Value { + crate::todo() + } + + fn const_ptr_byte_offset( + &self, + val: Self::Value, + offset: rustc_target::abi::Size, + ) -> Self::Value { + todo!() + } +} diff --git a/crates/rustc_codegen_c/src/context/debug_info.rs b/crates/rustc_codegen_c/src/context/debug_info.rs new file mode 100644 index 0000000..4d77ecc --- /dev/null +++ b/crates/rustc_codegen_c/src/context/debug_info.rs @@ -0,0 +1,69 @@ +use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, VariableKind}; +use rustc_codegen_ssa::traits::DebugInfoMethods; +use rustc_middle::mir::Body; +use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty}; +use rustc_target::abi::call::FnAbi; + +use crate::context::CodegenCx; + +impl<'tcx> DebugInfoMethods<'tcx> for CodegenCx<'tcx> { + fn create_vtable_debuginfo( + &self, + ty: Ty<'tcx>, + trait_ref: Option>, + vtable: Self::Value, + ) { + todo!() + } + + fn create_function_debug_context( + &self, + instance: Instance<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + llfn: Self::Function, + mir: &Body<'tcx>, + ) -> Option> { + None + } + + fn dbg_scope_fn( + &self, + instance: Instance<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + maybe_definition_llfn: Option, + ) -> Self::DIScope { + todo!() + } + + fn dbg_loc( + &self, + scope: Self::DIScope, + inlined_at: Option, + span: rustc_span::Span, + ) -> Self::DILocation { + todo!() + } + + fn extend_scope_to_file( + &self, + scope_metadata: Self::DIScope, + file: &rustc_span::SourceFile, + ) -> Self::DIScope { + todo!() + } + + fn debuginfo_finalize(&self) { + todo!() + } + + fn create_dbg_var( + &self, + variable_name: rustc_span::Symbol, + variable_type: Ty<'tcx>, + scope_metadata: Self::DIScope, + variable_kind: VariableKind, + span: rustc_span::Span, + ) -> Self::DIVariable { + todo!() + } +} diff --git a/crates/rustc_codegen_c/src/context/layout_type.rs b/crates/rustc_codegen_c/src/context/layout_type.rs new file mode 100644 index 0000000..1af1556 --- /dev/null +++ b/crates/rustc_codegen_c/src/context/layout_type.rs @@ -0,0 +1,53 @@ +use rustc_abi::Abi; +use rustc_codegen_ssa::traits::LayoutTypeMethods; +use rustc_middle::ty::layout::TyAndLayout; +use rustc_middle::ty::Ty; +use rustc_target::abi::call::FnAbi; + +use crate::context::CodegenCx; + +impl<'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'tcx> { + fn backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type { + todo!() + } + + fn cast_backend_type(&self, ty: &rustc_target::abi::call::CastTarget) -> Self::Type { + todo!() + } + + fn fn_decl_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Type { + todo!() + } + + fn fn_ptr_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Type { + todo!() + } + + fn reg_backend_type(&self, ty: &rustc_target::abi::call::Reg) -> Self::Type { + todo!() + } + + fn immediate_backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type { + crate::todo() + } + + fn is_backend_immediate(&self, layout: TyAndLayout<'tcx>) -> bool { + match layout.abi { + Abi::Scalar(_) | Abi::Vector { .. } => true, + Abi::ScalarPair(..) | Abi::Uninhabited | Abi::Aggregate { .. } => false, + } + } + + fn is_backend_scalar_pair(&self, layout: TyAndLayout<'tcx>) -> bool { + todo!() + } + + fn scalar_pair_element_backend_type( + &self, + layout: TyAndLayout<'tcx>, + index: usize, + immediate: bool, + ) -> Self::Type { + todo!() + } +} diff --git a/crates/rustc_codegen_c/src/context/misc.rs b/crates/rustc_codegen_c/src/context/misc.rs new file mode 100644 index 0000000..29152bd --- /dev/null +++ b/crates/rustc_codegen_c/src/context/misc.rs @@ -0,0 +1,48 @@ +use std::cell::RefCell; + +use rustc_codegen_ssa::traits::MiscMethods; +use rustc_hash::FxHashMap; +use rustc_middle::mir::mono::CodegenUnit; +use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty}; + +use crate::context::CodegenCx; + +impl<'tcx> MiscMethods<'tcx> for CodegenCx<'tcx> { + fn vtables( + &self, + ) -> &RefCell, Option>), Self::Value>> { + todo!() + } + + fn get_fn(&self, instance: Instance<'tcx>) -> Self::Function { + self.tcx.symbol_name(instance).name + } + + fn get_fn_addr(&self, instance: Instance<'tcx>) -> Self::Value { + todo!() + } + + fn eh_personality(&self) -> Self::Value { + todo!() + } + + fn sess(&self) -> &rustc_session::Session { + self.tcx.sess + } + + fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx> { + todo!() + } + + fn set_frame_pointer_type(&self, llfn: Self::Function) { + todo!() + } + + fn apply_target_cpu_attr(&self, llfn: Self::Function) { + todo!() + } + + fn declare_c_main(&self, fn_type: Self::Type) -> Option { + todo!() + } +} diff --git a/crates/rustc_codegen_c/src/context/pre_define.rs b/crates/rustc_codegen_c/src/context/pre_define.rs new file mode 100644 index 0000000..b14fd71 --- /dev/null +++ b/crates/rustc_codegen_c/src/context/pre_define.rs @@ -0,0 +1,48 @@ +use rustc_codegen_ssa::traits::PreDefineMethods; +use rustc_hir::def_id::DefId; +use rustc_middle::mir::mono::{Linkage, Visibility}; +use rustc_middle::ty::layout::FnAbiOf; +use rustc_middle::ty::{self, Instance, Ty}; +use rustc_target::abi::call::{ArgAbi, PassMode}; + +use crate::context::CodegenCx; +use crate::module::CType; + +impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'tcx> { + fn predefine_static( + &self, + def_id: DefId, + linkage: Linkage, + visibility: Visibility, + symbol_name: &str, + ) { + todo!() + } + + fn predefine_fn( + &self, + instance: Instance<'tcx>, + linkage: Linkage, + visibility: Visibility, + symbol_name: &str, + ) { + let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); + + let args = fn_abi.args.iter().map(|arg| type_from_abi(arg)).collect(); + let ret = type_from_abi(&fn_abi.ret); + self.function_abis.borrow_mut().insert(symbol_name.to_string(), (args, ret)); + + self.functions.borrow_mut().insert(symbol_name.to_string(), format!("{:?}", instance)); + } +} + +fn type_from_abi(abi: &ArgAbi<'_, Ty>) -> CType { + match &abi.mode { + PassMode::Ignore => CType::Builtin("void".to_string()), + PassMode::Direct(attributes) => { + // TODO: other types + CType::Builtin("int".to_string()) + } + _ => todo!(), + } +} diff --git a/crates/rustc_codegen_c/src/context/static.rs b/crates/rustc_codegen_c/src/context/static.rs new file mode 100644 index 0000000..c28f2eb --- /dev/null +++ b/crates/rustc_codegen_c/src/context/static.rs @@ -0,0 +1,23 @@ +use rustc_abi::Align; +use rustc_codegen_ssa::traits::StaticMethods; +use rustc_hir::def_id::DefId; + +use crate::context::CodegenCx; + +impl<'tcx> StaticMethods for CodegenCx<'tcx> { + fn static_addr_of(&self, cv: Self::Value, align: Align, kind: Option<&str>) -> Self::Value { + todo!() + } + + fn codegen_static(&self, def_id: DefId) { + todo!() + } + + fn add_used_global(&self, global: Self::Value) { + todo!() + } + + fn add_compiler_used_global(&self, global: Self::Value) { + todo!() + } +} diff --git a/crates/rustc_codegen_c/src/context/type_membership.rs b/crates/rustc_codegen_c/src/context/type_membership.rs new file mode 100644 index 0000000..cff6dbe --- /dev/null +++ b/crates/rustc_codegen_c/src/context/type_membership.rs @@ -0,0 +1,5 @@ +use rustc_codegen_ssa::traits::TypeMembershipMethods; + +use crate::context::CodegenCx; + +impl<'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'tcx> {} diff --git a/crates/rustc_codegen_c/src/lib.rs b/crates/rustc_codegen_c/src/lib.rs index 949b2d7..ec65a81 100644 --- a/crates/rustc_codegen_c/src/lib.rs +++ b/crates/rustc_codegen_c/src/lib.rs @@ -1,15 +1,21 @@ #![feature(rustc_private)] +extern crate rustc_abi; extern crate rustc_ast; extern crate rustc_codegen_ssa; +extern crate rustc_const_eval; extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_fluent_macro; +extern crate rustc_hash; +extern crate rustc_hir; extern crate rustc_metadata; extern crate rustc_middle; extern crate rustc_session; extern crate rustc_span; +extern crate rustc_target; +extern crate tracing; use std::sync::Arc; @@ -35,8 +41,13 @@ use rustc_session::config::{OptLevel, OutputFilenames}; use rustc_session::Session; use rustc_span::ErrorGuaranteed; +use crate::module::Module; + mod archive; mod base; +mod builder; +mod context; +mod module; mod util; mod write; @@ -88,6 +99,10 @@ impl CodegenBackend for CCodegen { ) -> Result<(), ErrorGuaranteed> { link_binary(sess, &crate::archive::ArArchiveBuilderBuilder, &codegen_results, outputs) } + + fn supports_parallel(&self) -> bool { + false // Maybe true? + } } impl ExtraBackendMethods for CCodegen { @@ -140,7 +155,7 @@ impl ThinBufferMethods for ThinBuffer { } impl WriteBackendMethods for CCodegen { - type Module = (); + type Module = Module; type TargetMachine = (); type TargetMachineError = (); type ModuleBuffer = ModuleBuffer; @@ -233,3 +248,5 @@ impl WriteBackendMethods for CCodegen { pub fn __rustc_codegen_backend() -> Box { Box::new(CCodegen {}) } + +fn todo() {} diff --git a/crates/rustc_codegen_c/src/module.rs b/crates/rustc_codegen_c/src/module.rs index db3b26f..d123e4f 100644 --- a/crates/rustc_codegen_c/src/module.rs +++ b/crates/rustc_codegen_c/src/module.rs @@ -4,167 +4,51 @@ //! //! The structure is derived from clang's AST. -use std::borrow::Cow; -use std::fmt::{Display, Formatter}; - -use parking_lot::RwLock; -use rustc_hash::FxHashMap; -use rustc_type_ir::{IntTy, UintTy}; - -use crate::utils::sharded_slab::{Entry, Id, ShardedSlab}; - -/// Rust's primitive types -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum PimitiveType { - Int(IntTy), - Uint(UintTy), -} - -pub struct ModuleContext { - types: ShardedSlab, - primitive_types: RwLock>, - pub module: Module, -} - -impl Default for ModuleContext { - fn default() -> Self { - Self::new() - } -} - -impl ModuleContext { - pub fn new() -> Self { - Self { - types: ShardedSlab::default(), - primitive_types: RwLock::new(FxHashMap::default()), - module: Module::new(), - } - } - - /// Get the type - pub fn ty(&self, id: CType) -> Entry { - self.types.get(id).unwrap() - } - - /// Get the type of an signed integer - pub fn get_int_type(&self, int: IntTy) -> CType { - if let Some(ty) = self.primitive_types.read().get(&PimitiveType::Int(int)) { - return *ty; - } - - let tykind = match int { - IntTy::Isize => CTypeKind::Builtin("ssize_t".to_string()), - IntTy::I8 => CTypeKind::Builtin("int8_t".to_string()), - IntTy::I16 => CTypeKind::Builtin("int16_t".to_string()), - IntTy::I32 => CTypeKind::Builtin("int32_t".to_string()), - IntTy::I64 => CTypeKind::Builtin("int64_t".to_string()), - IntTy::I128 => todo!(), - }; - let ty = self.types.insert(tykind); - self.primitive_types.write().insert(PimitiveType::Int(int), ty); - ty - } - - /// Get the type of an unsigned integer - pub fn get_uint_type(&self, uint: UintTy) -> CType { - if let Some(ty) = self.primitive_types.read().get(&PimitiveType::Uint(uint)) { - return *ty; - } - - let tykind = match uint { - UintTy::Usize => CTypeKind::Builtin("size_t".to_string()), - UintTy::U8 => CTypeKind::Builtin("uint8_t".to_string()), - UintTy::U16 => CTypeKind::Builtin("uint16_t".to_string()), - UintTy::U32 => CTypeKind::Builtin("uint32_t".to_string()), - UintTy::U64 => CTypeKind::Builtin("uint64_t".to_string()), - UintTy::U128 => todo!(), - }; - let ty = self.types.insert(tykind); - self.primitive_types.write().insert(PimitiveType::Uint(uint), ty); - ty - } -} - -impl Display for ModuleContext { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - self.module.fmt_with(f, self) - } -} +use std::fmt::Display; +#[derive(Default)] pub struct Module { pub includes: Vec, pub decls: Vec, } -impl Default for Module { - fn default() -> Self { - Self::new() - } -} - -impl Module { - pub fn new() -> Self { - let includes = vec!["stdint.h".to_string()]; - let decls = vec![]; - Self { includes, decls } - } - - pub fn display<'a>(&'a self, ctx: &'a ModuleContext) -> impl Display + 'a { - struct ModuleDisplay<'a>(&'a Module, &'a ModuleContext); - impl<'a> Display for ModuleDisplay<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - self.0.fmt_with(f, self.1) - } - } - ModuleDisplay(self, ctx) - } - - fn fmt_with(&self, f: &mut Formatter<'_>, ctx: &ModuleContext) -> std::fmt::Result { +impl Display for Module { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { for include in &self.includes { writeln!(f, "#include <{}>", include)?; } for decl in &self.decls { - writeln!(f, "{}", decl.display(ctx))?; + writeln!(f, "{}", decl)?; } Ok(()) } } +// TODO: use rustc's memory arena +// TODO: maybe split expr from stmt? + pub enum CDecl { Typedef { name: String, ty: CType }, Record { name: String, fields: Vec }, Field { name: String, ty: CType }, Enum { name: String, values: Vec }, - FunctionDecl { name: String, ty: CType, params: Vec }, - Function(CFunction), - // Var { name: String, ty: CType, init: Option }, + Function { name: String, ty: CType, params: Vec, body: Option }, + Var { name: String, ty: CType, init: Option }, Raw(String), } -impl CDecl { - pub fn display<'a>(&'a self, ctx: &'a ModuleContext) -> impl Display + 'a { - struct CDeclDisplay<'a>(&'a CDecl, &'a ModuleContext); - impl<'a> Display for CDeclDisplay<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - self.0.fmt_with(f, self.1) - } - } - CDeclDisplay(self, ctx) - } - - fn fmt_with(&self, f: &mut Formatter<'_>, ctx: &ModuleContext) -> std::fmt::Result { +impl Display for CDecl { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - CDecl::Typedef { name, ty } => { - write!(f, "typedef {} {};", name, ctx.ty(*ty).display(ctx)) - } + CDecl::Typedef { name, ty } => write!(f, "typedef {} {};", name, ty), CDecl::Record { name, fields } => { writeln!(f, "struct {} {{ ", name)?; for field in fields { - writeln!(f, "{}", field.display(ctx))?; + writeln!(f, "{}", field)?; } writeln!(f, "}};") } - CDecl::Field { name, ty } => write!(f, "{} {}", name, ctx.ty(*ty).display(ctx)), + CDecl::Field { name, ty } => write!(f, "{} {}", name, ty), CDecl::Enum { name, values } => { writeln!(f, "enum {} {{ ", name)?; for (i, value) in values.iter().enumerate() { @@ -175,226 +59,150 @@ impl CDecl { } writeln!(f, "}};") } - CDecl::FunctionDecl { name, ty, params } => { - write!(f, "{} {}(", ctx.ty(*ty).display(ctx), name)?; + CDecl::Function { name, ty, params, body } => { + write!(f, "{} {}(", ty, name)?; for (i, param) in params.iter().enumerate() { if i > 0 { write!(f, ", ")?; } - write!(f, "{}", ctx.ty(*param).display(ctx))?; + write!(f, "{}", param)?; + } + write!(f, ")")?; + if let Some(body) = body { + write!(f, "{}", body) + } else { + write!(f, ";") } - write!(f, ");") } - CDecl::Function(func) => write!(f, "{}", func.display(ctx)), - // CDecl::Var { name, ty, init } => { - // write!(f, "{} {}", ty, name)?; - // if let Some(init) = init { - // write!(f, " = {}", init)?; - // } - // write!(f, ";") - // } + CDecl::Var { name, ty, init } => { + write!(f, "{} {}", ty, name)?; + if let Some(init) = init { + write!(f, " = {}", init)?; + } + write!(f, ";") + } CDecl::Raw(s) => write!(f, "{}", s), } } } -pub type CType = Id; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum CTypeKind { +#[derive(Clone)] +pub enum CType { Builtin(String), - Pointer(CType), + Pointer(Box), Record(String), - Array(CType, usize), + Array(Box, usize), } -impl CTypeKind { - pub fn display<'a>(&'a self, ctx: &'a ModuleContext) -> impl Display + 'a { - struct DisplayCTypeKind<'a>(&'a CTypeKind, &'a ModuleContext); - impl<'a> Display for DisplayCTypeKind<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - self.0.fmt_with(f, self.1) - } - } - DisplayCTypeKind(self, ctx) - } - - fn fmt_with(&self, f: &mut Formatter<'_>, ctx: &ModuleContext) -> std::fmt::Result { +impl Display for CType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - CTypeKind::Builtin(ty) => write!(f, "{}", ty), - CTypeKind::Pointer(ty) => write!(f, "{}*", ctx.ty(*ty).display(ctx)), - CTypeKind::Record(ty) => write!(f, "struct {}", ty), - CTypeKind::Array(ty, size) => write!(f, "{}[{}]", ctx.ty(*ty).display(ctx), size), + CType::Builtin(ty) => write!(f, "{}", ty), + CType::Pointer(ty) => write!(f, "{}*", ty), + CType::Record(ty) => write!(f, "struct {}", ty), + CType::Array(ty, size) => write!(f, "{}[{}]", ty, size), } } } pub struct CEnumConstant { pub name: String, - // pub value: Option, + pub value: Option, } impl Display for CEnumConstant { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.name)?; - // if let Some(value) = &self.value { - // write!(f, " = {}", value)?; - // } + if let Some(value) = &self.value { + write!(f, " = {}", value)?; + } Ok(()) } } -/// Values of C variable, parameters and scalars -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] -pub enum CValue { - Scalar(i128), - Var(usize), -} - -pub struct CFunction { - pub name: String, +pub struct CParamVar { + pub name: Option, pub ty: CType, - pub params: Vec<(CType, CValue)>, - pub body: Vec, - pub var_names: FxHashMap, } -impl CFunction { - pub fn get_var_name(&self, var: CValue) -> Cow { - if let Some(name) = self.var_names.get(&var) { - Cow::Borrowed(name) +impl Display for CParamVar { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if let Some(name) = &self.name { + write!(f, "{} {}", self.ty, name) } else { - Cow::Owned(match var { - CValue::Scalar(scalar) => format!("{}", scalar), - CValue::Var(index) => format!("_{}", index), - }) + write!(f, "{}", self.ty) } } } -impl CFunction { - pub fn display<'a>(&'a self, ctx: &'a ModuleContext) -> impl Display + '_ { - struct CFunctionDisplay<'a>(&'a CFunction, &'a ModuleContext); - impl<'a> Display for CFunctionDisplay<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - self.0.fmt_with(f, self.1) - } - } - CFunctionDisplay(self, ctx) - } - - fn fmt_with(&self, f: &mut Formatter<'_>, ctx: &ModuleContext) -> std::fmt::Result { - write!(f, "{} {}(", ctx.ty(self.ty).display(ctx), self.name)?; - for (i, (ty, param)) in self.params.iter().enumerate() { - if i > 0 { - write!(f, ", ")?; - } - write!(f, "{} {}", ctx.ty(*ty).display(ctx), self.get_var_name(*param))?; - } - write!(f, ") {{")?; - for stmt in &self.body { - writeln!(f, "{}", stmt.display(self, ctx))?; - } - write!(f, "}}") - } -} - pub enum CStmt { Compound(Vec), - If { cond: Box, then_br: Box, else_br: Option> }, + If { cond: Box, then_: Box, else_: Option> }, Return(Option>), Decl(Box), Expr(CExpr), } -impl CStmt { - pub fn display<'a>(&'a self, fun: &'a CFunction, ctx: &'a ModuleContext) -> impl Display + '_ { - struct CStmtDisplay<'a>(&'a CStmt, &'a CFunction, &'a ModuleContext); - impl<'a> Display for CStmtDisplay<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - self.0.fmt_with(f, self.1, self.2) - } - } - CStmtDisplay(self, fun, ctx) - } - - fn fmt_with( - &self, - f: &mut Formatter<'_>, - fun: &CFunction, - ctx: &ModuleContext, - ) -> std::fmt::Result { +impl Display for CStmt { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { CStmt::Compound(stmts) => { writeln!(f, "{{")?; for stmt in stmts { - writeln!(f, "{}", stmt.display(fun, ctx))?; + writeln!(f, "{}", stmt)?; } write!(f, "}}") } - CStmt::If { cond, then_br: then_, else_br: else_ } => { - writeln!(f, "if ({}) {{", cond.display(fun))?; - writeln!(f, "{}", then_.display(fun, ctx))?; + CStmt::If { cond, then_, else_ } => { + writeln!(f, "if ({}) {{", cond)?; + writeln!(f, "{}", then_)?; if let Some(else_) = else_ { writeln!(f, "}} else {{")?; - writeln!(f, "{}", else_.display(fun, ctx))?; + writeln!(f, "{}", else_)?; } write!(f, "}}") } CStmt::Return(expr) => { write!(f, "return")?; if let Some(expr) = expr { - write!(f, " {}", expr.display(fun))?; + write!(f, " {}", expr)?; } write!(f, ";") } - CStmt::Decl(decl) => write!(f, "{}", decl.display(ctx)), - CStmt::Expr(expr) => write!(f, "{};", expr.display(fun)), + CStmt::Decl(decl) => write!(f, "{}", decl), + CStmt::Expr(expr) => write!(f, "{};", expr), } } } pub enum CExpr { Literal(String), - Value(CValue), + DeclRef { name: String }, BinaryOperator { lhs: Box, rhs: Box, op: String }, Call { callee: Box, args: Vec }, Member { expr: Box, arrow: bool, field: String }, } -impl CExpr { - pub fn display<'a>(&'a self, fun: &'a CFunction) -> impl Display + '_ { - struct CExprDisplay<'a>(&'a CExpr, &'a CFunction); - impl<'a> Display for CExprDisplay<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - self.0.fmt_with(f, self.1) - } - } - CExprDisplay(self, fun) - } - - fn fmt_with(&self, f: &mut Formatter<'_>, fun: &CFunction) -> std::fmt::Result { +impl Display for CExpr { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { CExpr::Literal(lit) => write!(f, "{}", lit), - CExpr::Value(val) => { - let name = fun.get_var_name(*val); - write!(f, "{}", name) - } + CExpr::DeclRef { name } => write!(f, "{}", name), CExpr::BinaryOperator { lhs, rhs, op } => { - write!(f, "({} {} {})", lhs.display(fun), op, rhs.display(fun)) + write!(f, "({} {} {})", lhs, op, rhs) } CExpr::Call { callee, args } => { - write!(f, "{}(", callee.display(fun))?; + write!(f, "{}(", callee)?; for (i, arg) in args.iter().enumerate() { if i != 0 { write!(f, ", ")?; } - write!(f, "{}", arg.display(fun))?; + write!(f, "{}", arg)?; } write!(f, ")") } CExpr::Member { expr, arrow, field } => { - write!(f, "{}", expr.display(fun))?; + write!(f, "{}", expr)?; if *arrow { write!(f, "->")?; } else { diff --git a/crates/rustc_codegen_c/src/write.rs b/crates/rustc_codegen_c/src/write.rs index c4e1195..375f5e7 100644 --- a/crates/rustc_codegen_c/src/write.rs +++ b/crates/rustc_codegen_c/src/write.rs @@ -1,20 +1,73 @@ +use std::fs; +use std::io::Write; +use std::process::Stdio; + +use rustc_codegen_ssa::back::command::Command; use rustc_codegen_ssa::back::write::{CodegenContext, ModuleConfig}; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; use rustc_errors::{DiagCtxtHandle, FatalError}; +use rustc_session::config::OutputType; +use tracing::error; + +use crate::module::Module; + +// mini_core.b9ae8e2840b8e4ad-cgu.0 +// mini_core.mini_core.b9ae8e2840b8e4ad-cgu.0.rcgu.o + +// output to `[crate-name].[cgu-name].rcgu.o` pub(crate) unsafe fn codegen( - _cgcx: &CodegenContext, + cgcx: &CodegenContext, _dcx: DiagCtxtHandle<'_>, - _module: ModuleCodegen<()>, + module: ModuleCodegen, _config: &ModuleConfig, ) -> Result { - todo!() + let module_name = module.name.clone(); + let module_name = Some(&module_name[..]); + let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name); + let c_out = obj_out.with_extension("c"); + + // output c source code + let c_out_file = fs::File::create(&c_out).map_err(|_| FatalError)?; + writeln!(&c_out_file, "// file: {}.c", module.name).map_err(|_| FatalError)?; + write!(&c_out_file, "{}", module.module_llvm).map_err(|_| FatalError)?; + + // invoke cc to compile + // TODO: configure cc + // TODO: handle long command line (windows) + // TODO: flush_linked_file (windows) + let mut cmd = Command::new("clang"); + cmd.arg(&c_out).arg("-o").arg(&obj_out).arg("-c"); + let mut cmd = cmd.command(); + let output = match cmd + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .and_then(|child| child.wait_with_output()) + { + Ok(output) => { + output + // flush_linked_file(&output, out_filename)?; + } + Err(e) => { + error!("failed to spawn C compiler: {}", e); + return Err(FatalError); + } + }; + + if !output.status.success() { + error!("compiler stderr:\n{}", String::from_utf8_lossy(&output.stderr)); + error!("compiler stdout:\n{}", String::from_utf8_lossy(&output.stdout)); + return Err(FatalError); + } + + Ok(module.into_compiled_module(true, false, false, false, false, &cgcx.output_filenames)) } pub(crate) fn link( _cgcx: &CodegenContext, _dcx: DiagCtxtHandle<'_>, - mut _modules: Vec>, -) -> Result, FatalError> { + mut _modules: Vec>, +) -> Result, FatalError> { unimplemented!(); } diff --git a/example/example.rs b/example/example.rs new file mode 100644 index 0000000..c929988 --- /dev/null +++ b/example/example.rs @@ -0,0 +1,15 @@ +#![feature(no_core)] +#![no_core] +#![no_main] + +extern crate mini_core; + +#[no_mangle] +pub fn main() -> i32 { + 0 +} + +#[no_mangle] +pub fn foo(x: i32) -> i32 { + x +} diff --git a/example/mini_core.rs b/example/mini_core.rs new file mode 100644 index 0000000..3a69bdf --- /dev/null +++ b/example/mini_core.rs @@ -0,0 +1,39 @@ +#![feature(no_core, lang_items)] +#![no_core] +#![allow(internal_features)] + +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +pub unsafe trait Copy {} + +unsafe impl Copy for bool {} +unsafe impl Copy for u8 {} +unsafe impl Copy for u16 {} +unsafe impl Copy for u32 {} +unsafe impl Copy for u64 {} +unsafe impl Copy for usize {} +unsafe impl Copy for i8 {} +unsafe impl Copy for i16 {} +unsafe impl Copy for i32 {} +unsafe impl Copy for isize {} +unsafe impl Copy for f32 {} +unsafe impl Copy for f64 {} +unsafe impl Copy for char {} +unsafe impl<'a, T: ?Sized> Copy for &'a T {} +unsafe impl Copy for *const T {} +unsafe impl Copy for *mut T {} + +pub mod libc { + #[link(name = "c")] + extern "C" { + pub fn puts(s: *const u8) -> i32; + pub fn printf(format: *const i8, ...) -> i32; + pub fn malloc(size: usize) -> *mut u8; + pub fn free(ptr: *mut u8); + pub fn memcpy(dst: *mut u8, src: *const u8, size: usize); + pub fn memmove(dst: *mut u8, src: *const u8, size: usize); + pub fn strncpy(dst: *mut u8, src: *const u8, size: usize); + } +} diff --git a/tests/codegen/filename.rs b/tests/codegen/filename.rs new file mode 100644 index 0000000..b89870c --- /dev/null +++ b/tests/codegen/filename.rs @@ -0,0 +1,16 @@ +// CHECK: filename + +#![feature(no_core)] +#![no_core] +#![no_main] + +extern crate mini_core; + +// CHECK: function_name +#[no_mangle] +pub fn function_name() -> i32 { + 0 +} + +#[no_mangle] +pub fn main() {} From 00fb47c89ef533de6a7458fb8ad945e41850ee0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BF=98=E5=BF=A7=E5=8C=97=E8=90=B1=E8=8D=89?= Date: Sat, 20 Jul 2024 14:53:21 +0800 Subject: [PATCH 05/11] feat: function params --- crates/rustc_codegen_c/src/builder/abi.rs | 3 +- crates/rustc_codegen_c/src/context.rs | 83 ++++++---- crates/rustc_codegen_c/src/context/const.rs | 10 +- crates/rustc_codegen_c/src/context/misc.rs | 2 +- .../rustc_codegen_c/src/context/pre_define.rs | 7 +- crates/rustc_codegen_c/src/lib.rs | 5 +- crates/rustc_codegen_c/src/module.rs | 153 ++++++++++++------ crates/rustc_codegen_c/src/slab.rs | 0 crates/rustc_codegen_c/src/util.rs | 5 - crates/rustc_codegen_c/src/utils.rs | 1 + crates/rustc_codegen_c/src/utils/slab.rs | 73 +++++++++ tests/codegen/params_count.rs | 15 ++ 12 files changed, 269 insertions(+), 88 deletions(-) create mode 100644 crates/rustc_codegen_c/src/slab.rs delete mode 100644 crates/rustc_codegen_c/src/util.rs create mode 100644 crates/rustc_codegen_c/src/utils.rs create mode 100644 crates/rustc_codegen_c/src/utils/slab.rs create mode 100644 tests/codegen/params_count.rs diff --git a/crates/rustc_codegen_c/src/builder/abi.rs b/crates/rustc_codegen_c/src/builder/abi.rs index 09a596a..3ef5cc5 100644 --- a/crates/rustc_codegen_c/src/builder/abi.rs +++ b/crates/rustc_codegen_c/src/builder/abi.rs @@ -4,10 +4,11 @@ use rustc_middle::ty::Ty; use rustc_target::abi::call::ArgAbi; use crate::builder::Builder; +use crate::module::CValue; impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, 'tcx> { fn get_param(&mut self, index: usize) -> Self::Value { - crate::todo() + CValue::Var(index) } } diff --git a/crates/rustc_codegen_c/src/context.rs b/crates/rustc_codegen_c/src/context.rs index 45d58f4..edc9648 100644 --- a/crates/rustc_codegen_c/src/context.rs +++ b/crates/rustc_codegen_c/src/context.rs @@ -9,11 +9,12 @@ use rustc_middle::ty::layout::{ FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout, }; -use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{Instance, ParamEnv, Ty, TyCtxt}; use rustc_target::abi::call::FnAbi; use rustc_target::spec::{HasTargetSpec, Target}; -use crate::module::{CDecl, CParamVar, CStmt, CType, Module}; +use crate::module::{CDecl, CFunction, CStmt, CType, CValue, Module}; +use crate::utils::slab::{Id, Slab}; mod asm; mod base_type; @@ -27,43 +28,28 @@ mod type_membership; pub struct CodegenCx<'tcx> { pub tcx: TyCtxt<'tcx>, - pub function_abis: RefCell, CType)>>, - pub functions: RefCell>, + pub function_instances: RefCell, Id>>, + pub functions: RefCell>, } impl<'tcx> CodegenCx<'tcx> { pub fn new(tcx: TyCtxt<'tcx>) -> Self { Self { tcx, - function_abis: RefCell::new(FxHashMap::default()), - functions: RefCell::new(FxHashMap::default()), + function_instances: RefCell::new(FxHashMap::default()), + functions: RefCell::new(Slab::default()), } } pub fn finish(self) -> Module { let mut decls = vec![]; - let function_abis = self.function_abis.borrow(); - for (name, (args, ret)) in function_abis.iter() { - decls.push(CDecl::Function { - name: name.to_string(), - ty: ret.clone(), - params: args.iter().cloned().map(|ty| CParamVar { ty, name: None }).collect(), - body: None, - }); + for function in self.functions.borrow().iter() { + decls.push(function.decl()); } - for (name, instance) in self.functions.into_inner() { - let (args, ret) = &function_abis[&name]; - decls.push(CDecl::Function { - name, - ty: ret.clone(), - params: args.iter().cloned().map(|ty| CParamVar { ty, name: None }).collect(), - body: Some(CStmt::Compound(vec![CStmt::Decl(Box::new(CDecl::Raw(format!( - "// {}", - instance - ))))])), - }); + for function in self.functions.into_inner() { + decls.push(CDecl::Function(function.build())); } Module { includes: vec![], decls } @@ -71,8 +57,8 @@ impl<'tcx> CodegenCx<'tcx> { } impl<'tcx> BackendTypes for CodegenCx<'tcx> { - type Value = (); - type Function = &'tcx str; + type Value = CValue; + type Function = Id; type BasicBlock = (); type Type = (); type Funclet = (); @@ -125,3 +111,46 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'tcx> { todo!() } } + +pub struct CFunctionBuilder { + pub name: String, + pub ty: CType, + pub params: Vec<(CType, CValue)>, + pub body: Vec, + pub var_names: FxHashMap, + var_counter: usize, +} + +impl CFunctionBuilder { + pub fn new(name: String, ty: CType, params: Vec) -> Self { + let params: Vec<_> = + params.into_iter().enumerate().map(|(i, ty)| (ty, CValue::Var(i))).collect(); + let var_counter = params.len(); + + Self { name, ty, params, body: Vec::new(), var_counter, var_names: FxHashMap::default() } + } + + pub fn build(self) -> CFunction { + CFunction { + name: self.name, + ty: self.ty, + params: self.params, + body: self.body, + var_names: self.var_names, + } + } + + pub fn decl(&self) -> CDecl { + CDecl::FunctionDecl { + name: self.name.clone(), + ty: self.ty.clone(), + params: self.params.iter().map(|(ty, _)| ty.clone()).collect(), + } + } + + pub fn next_value(&mut self) -> CValue { + let val = CValue::Var(self.var_counter); + self.var_counter += 1; + val + } +} diff --git a/crates/rustc_codegen_c/src/context/const.rs b/crates/rustc_codegen_c/src/context/const.rs index cd39e13..01d372b 100644 --- a/crates/rustc_codegen_c/src/context/const.rs +++ b/crates/rustc_codegen_c/src/context/const.rs @@ -1,7 +1,8 @@ use rustc_codegen_ssa::traits::ConstMethods; -use rustc_const_eval::interpret::ConstAllocation; +use rustc_const_eval::interpret::{ConstAllocation, Scalar}; use crate::context::CodegenCx; +use crate::module::CValue; impl<'tcx> ConstMethods<'tcx> for CodegenCx<'tcx> { fn const_null(&self, t: Self::Type) -> Self::Value { @@ -90,11 +91,14 @@ impl<'tcx> ConstMethods<'tcx> for CodegenCx<'tcx> { fn scalar_to_backend( &self, - cv: rustc_const_eval::interpret::Scalar, + cv: Scalar, layout: rustc_target::abi::Scalar, llty: Self::Type, ) -> Self::Value { - crate::todo() + match cv { + Scalar::Int(scalar) => CValue::Scalar(scalar.to_int(scalar.size())), + Scalar::Ptr(_, _) => todo!(), + } } fn const_ptr_byte_offset( diff --git a/crates/rustc_codegen_c/src/context/misc.rs b/crates/rustc_codegen_c/src/context/misc.rs index 29152bd..085523d 100644 --- a/crates/rustc_codegen_c/src/context/misc.rs +++ b/crates/rustc_codegen_c/src/context/misc.rs @@ -15,7 +15,7 @@ impl<'tcx> MiscMethods<'tcx> for CodegenCx<'tcx> { } fn get_fn(&self, instance: Instance<'tcx>) -> Self::Function { - self.tcx.symbol_name(instance).name + *self.function_instances.borrow().get(&instance).unwrap() } fn get_fn_addr(&self, instance: Instance<'tcx>) -> Self::Value { diff --git a/crates/rustc_codegen_c/src/context/pre_define.rs b/crates/rustc_codegen_c/src/context/pre_define.rs index b14fd71..f516c83 100644 --- a/crates/rustc_codegen_c/src/context/pre_define.rs +++ b/crates/rustc_codegen_c/src/context/pre_define.rs @@ -5,7 +5,7 @@ use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::{self, Instance, Ty}; use rustc_target::abi::call::{ArgAbi, PassMode}; -use crate::context::CodegenCx; +use crate::context::{CFunctionBuilder, CodegenCx}; use crate::module::CType; impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'tcx> { @@ -30,9 +30,10 @@ impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'tcx> { let args = fn_abi.args.iter().map(|arg| type_from_abi(arg)).collect(); let ret = type_from_abi(&fn_abi.ret); - self.function_abis.borrow_mut().insert(symbol_name.to_string(), (args, ret)); - self.functions.borrow_mut().insert(symbol_name.to_string(), format!("{:?}", instance)); + let function = CFunctionBuilder::new(symbol_name.to_string(), ret, args); + let function_id = self.functions.borrow_mut().insert(function); + self.function_instances.borrow_mut().insert(instance, function_id); } } diff --git a/crates/rustc_codegen_c/src/lib.rs b/crates/rustc_codegen_c/src/lib.rs index ec65a81..a71d4b8 100644 --- a/crates/rustc_codegen_c/src/lib.rs +++ b/crates/rustc_codegen_c/src/lib.rs @@ -43,12 +43,13 @@ use rustc_span::ErrorGuaranteed; use crate::module::Module; + mod archive; mod base; mod builder; mod context; mod module; -mod util; +mod utils; mod write; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } @@ -62,7 +63,7 @@ impl CodegenBackend for CCodegen { } fn provide(&self, providers: &mut Providers) { - providers.global_backend_features = |tcx, ()| util::global_backend_features(tcx) + providers.global_backend_features = |_tcx, ()| vec![] } fn codegen_crate( diff --git a/crates/rustc_codegen_c/src/module.rs b/crates/rustc_codegen_c/src/module.rs index d123e4f..ee27b6a 100644 --- a/crates/rustc_codegen_c/src/module.rs +++ b/crates/rustc_codegen_c/src/module.rs @@ -4,8 +4,11 @@ //! //! The structure is derived from clang's AST. +use std::borrow::Cow; use std::fmt::Display; +use rustc_hash::FxHashMap; + #[derive(Default)] pub struct Module { pub includes: Vec, @@ -25,15 +28,15 @@ impl Display for Module { } // TODO: use rustc's memory arena -// TODO: maybe split expr from stmt? pub enum CDecl { Typedef { name: String, ty: CType }, Record { name: String, fields: Vec }, Field { name: String, ty: CType }, Enum { name: String, values: Vec }, - Function { name: String, ty: CType, params: Vec, body: Option }, - Var { name: String, ty: CType, init: Option }, + FunctionDecl { name: String, ty: CType, params: Vec }, + Function(CFunction), + // Var { name: String, ty: CType, init: Option }, Raw(String), } @@ -59,7 +62,7 @@ impl Display for CDecl { } writeln!(f, "}};") } - CDecl::Function { name, ty, params, body } => { + CDecl::FunctionDecl { name, ty, params } => { write!(f, "{} {}(", ty, name)?; for (i, param) in params.iter().enumerate() { if i > 0 { @@ -67,20 +70,16 @@ impl Display for CDecl { } write!(f, "{}", param)?; } - write!(f, ")")?; - if let Some(body) = body { - write!(f, "{}", body) - } else { - write!(f, ";") - } - } - CDecl::Var { name, ty, init } => { - write!(f, "{} {}", ty, name)?; - if let Some(init) = init { - write!(f, " = {}", init)?; - } - write!(f, ";") + write!(f, ");") } + CDecl::Function(func) => write!(f, "{}", func), + // CDecl::Var { name, ty, init } => { + // write!(f, "{} {}", ty, name)?; + // if let Some(init) = init { + // write!(f, " = {}", init)?; + // } + // write!(f, ";") + // } CDecl::Raw(s) => write!(f, "{}", s), } } @@ -107,102 +106,164 @@ impl Display for CType { pub struct CEnumConstant { pub name: String, - pub value: Option, + // pub value: Option, } impl Display for CEnumConstant { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.name)?; - if let Some(value) = &self.value { - write!(f, " = {}", value)?; - } + // if let Some(value) = &self.value { + // write!(f, " = {}", value)?; + // } Ok(()) } } -pub struct CParamVar { - pub name: Option, +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] +pub enum CValue { + Scalar(i128), + Var(usize), +} + +pub struct CFunction { + pub name: String, pub ty: CType, + pub params: Vec<(CType, CValue)>, + pub body: Vec, + pub var_names: FxHashMap, } -impl Display for CParamVar { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if let Some(name) = &self.name { - write!(f, "{} {}", self.ty, name) +impl CFunction { + pub fn get_var_name(&self, var: CValue) -> Cow { + if let Some(name) = self.var_names.get(&var) { + Cow::Borrowed(name) } else { - write!(f, "{}", self.ty) + Cow::Owned(match var { + CValue::Scalar(scalar) => format!("{}", scalar), + CValue::Var(index) => format!("_{}", index), + }) + } + } +} + +impl Display for CFunction { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{} {}(", self.ty, self.name)?; + for (i, (ty, param)) in self.params.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + write!(f, "{} {}", ty, self.get_var_name(*param))?; + } + write!(f, ") {{")?; + for stmt in &self.body { + writeln!(f, "{}", stmt.display(self))?; } + write!(f, "}}") } } pub enum CStmt { Compound(Vec), - If { cond: Box, then_: Box, else_: Option> }, + If { cond: Box, then_br: Box, else_br: Option> }, Return(Option>), Decl(Box), Expr(CExpr), } -impl Display for CStmt { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl CStmt { + pub fn display<'a>(&'a self, function: &'a CFunction) -> impl Display + '_ { + struct CStmtDisplay<'a> { + stmt: &'a CStmt, + function: &'a CFunction, + } + + impl<'a> Display for CStmtDisplay<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.stmt.fmt_with(f, self.function) + } + } + + CStmtDisplay { stmt: self, function } + } + + fn fmt_with(&self, f: &mut std::fmt::Formatter<'_>, function: &CFunction) -> std::fmt::Result { match self { CStmt::Compound(stmts) => { writeln!(f, "{{")?; for stmt in stmts { - writeln!(f, "{}", stmt)?; + writeln!(f, "{}", stmt.display(function))?; } write!(f, "}}") } - CStmt::If { cond, then_, else_ } => { - writeln!(f, "if ({}) {{", cond)?; - writeln!(f, "{}", then_)?; + CStmt::If { cond, then_br: then_, else_br: else_ } => { + writeln!(f, "if ({}) {{", cond.display(function))?; + writeln!(f, "{}", then_.display(function))?; if let Some(else_) = else_ { writeln!(f, "}} else {{")?; - writeln!(f, "{}", else_)?; + writeln!(f, "{}", else_.display(function))?; } write!(f, "}}") } CStmt::Return(expr) => { write!(f, "return")?; if let Some(expr) = expr { - write!(f, " {}", expr)?; + write!(f, " {}", expr.display(function))?; } write!(f, ";") } CStmt::Decl(decl) => write!(f, "{}", decl), - CStmt::Expr(expr) => write!(f, "{};", expr), + CStmt::Expr(expr) => write!(f, "{};", expr.display(function)), } } } pub enum CExpr { Literal(String), - DeclRef { name: String }, + Value(CValue), BinaryOperator { lhs: Box, rhs: Box, op: String }, Call { callee: Box, args: Vec }, Member { expr: Box, arrow: bool, field: String }, } -impl Display for CExpr { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl CExpr { + pub fn display<'a>(&'a self, function: &'a CFunction) -> impl Display + '_ { + struct CExprDisplay<'a> { + expr: &'a CExpr, + function: &'a CFunction, + } + + impl<'a> Display for CExprDisplay<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.expr.fmt_with(f, self.function) + } + } + + CExprDisplay { expr: self, function } + } + + fn fmt_with(&self, f: &mut std::fmt::Formatter<'_>, function: &CFunction) -> std::fmt::Result { match self { CExpr::Literal(lit) => write!(f, "{}", lit), - CExpr::DeclRef { name } => write!(f, "{}", name), + CExpr::Value(val) => { + let name = function.get_var_name(*val); + write!(f, "{}", name) + } CExpr::BinaryOperator { lhs, rhs, op } => { - write!(f, "({} {} {})", lhs, op, rhs) + write!(f, "({} {} {})", lhs.display(function), op, rhs.display(function)) } CExpr::Call { callee, args } => { - write!(f, "{}(", callee)?; + write!(f, "{}(", callee.display(function))?; for (i, arg) in args.iter().enumerate() { if i != 0 { write!(f, ", ")?; } - write!(f, "{}", arg)?; + write!(f, "{}", arg.display(function))?; } write!(f, ")") } CExpr::Member { expr, arrow, field } => { - write!(f, "{}", expr)?; + write!(f, "{}", expr.display(function))?; if *arrow { write!(f, "->")?; } else { diff --git a/crates/rustc_codegen_c/src/slab.rs b/crates/rustc_codegen_c/src/slab.rs new file mode 100644 index 0000000..e69de29 diff --git a/crates/rustc_codegen_c/src/util.rs b/crates/rustc_codegen_c/src/util.rs deleted file mode 100644 index e7859b0..0000000 --- a/crates/rustc_codegen_c/src/util.rs +++ /dev/null @@ -1,5 +0,0 @@ -use rustc_middle::ty::TyCtxt; - -pub fn global_backend_features(_tcx: TyCtxt<'_>) -> Vec { - vec![] -} diff --git a/crates/rustc_codegen_c/src/utils.rs b/crates/rustc_codegen_c/src/utils.rs new file mode 100644 index 0000000..7c9d543 --- /dev/null +++ b/crates/rustc_codegen_c/src/utils.rs @@ -0,0 +1 @@ +pub mod slab; \ No newline at end of file diff --git a/crates/rustc_codegen_c/src/utils/slab.rs b/crates/rustc_codegen_c/src/utils/slab.rs new file mode 100644 index 0000000..6e36042 --- /dev/null +++ b/crates/rustc_codegen_c/src/utils/slab.rs @@ -0,0 +1,73 @@ +pub struct Slab { + data: Vec, +} + + + +impl Default for Slab { + fn default() -> Self { + Self::new() + } +} + +impl Slab { + pub const fn new() -> Self { + Self { data: Vec::new() } + } + + pub fn insert(&mut self, value: T) -> Id { + let index = self.data.len(); + self.data.push(value); + Id { index, _phantom: std::marker::PhantomData } + } + + pub fn get(&self, id: Id) -> Option<&T> { + self.data.get(id.index) + } + + pub fn iter(&self) -> std::slice::Iter<'_, T> { + self.data.iter() + } +} + +impl IntoIterator for Slab { + type Item = T; + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> std::vec::IntoIter { + self.data.into_iter() + } +} + +pub struct Id { + index: usize, + _phantom: std::marker::PhantomData, +} + +impl Copy for Id{} + +impl Clone for Id { + fn clone(&self) -> Self { + *self + } +} + +impl PartialEq for Id { + fn eq(&self, other: &Self) -> bool { + self.index == other.index + } +} + +impl Eq for Id {} + +impl std::fmt::Debug for Id { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.index) + } +} + +impl std::hash::Hash for Id { + fn hash(&self, state: &mut H) { + self.index.hash(state); + } +} diff --git a/tests/codegen/params_count.rs b/tests/codegen/params_count.rs new file mode 100644 index 0000000..4d0a14b --- /dev/null +++ b/tests/codegen/params_count.rs @@ -0,0 +1,15 @@ +#![feature(no_core)] +#![no_core] +#![no_main] + +extern crate mini_core; + +// expect three int params +// CHECK: {{((int .*,?\s?){3})}} +#[no_mangle] +pub fn foo(_x: i32, _y: i32, _z: i32) -> i32 { + 0 +} + +#[no_mangle] +pub fn main() {} From d142fabd75f202c13e2e1876291b524563f48a26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BF=98=E5=BF=A7=E5=8C=97=E8=90=B1=E8=8D=89?= Date: Sat, 20 Jul 2024 16:09:36 +0800 Subject: [PATCH 06/11] feat: return value --- README.md | 9 +++++++-- crates/rustc_codegen_c/src/builder.rs | 17 ++++++++++++----- crates/rustc_codegen_c/src/builder/abi.rs | 1 + crates/rustc_codegen_c/src/context.rs | 7 ++++++- crates/rustc_codegen_c/src/module.rs | 1 + crates/rustc_codegen_c/src/utils/slab.rs | 15 +++++++++++++++ tests/codegen/filename.rs | 4 +++- tests/codegen/params_count.rs | 4 +++- tests/codegen/ret_value.rs | 12 ++++++++++++ 9 files changed, 60 insertions(+), 10 deletions(-) create mode 100644 tests/codegen/ret_value.rs diff --git a/README.md b/README.md index 06a6ea6..a370b0a 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,17 @@ This code is still highly experimental and not ready for production use. ## Try it +In the root directory of the project, run the following command: + ```bash -./y.sh rustc example/example.rs +./y rustc example/example.rs ./build/example ``` -The usage of `y.sh` can be viewed from `./y.sh help`. +The usage of `./y` can be viewed from `./y help`. + +Note: only Linux is supported at the moment. `clang` is required to compile C code, +and LLVM FileCheck is required to test the codegen. ## License diff --git a/crates/rustc_codegen_c/src/builder.rs b/crates/rustc_codegen_c/src/builder.rs index c95266a..d3ef439 100644 --- a/crates/rustc_codegen_c/src/builder.rs +++ b/crates/rustc_codegen_c/src/builder.rs @@ -12,7 +12,9 @@ use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_target::abi::call::FnAbi; use rustc_target::spec::{HasTargetSpec, Target}; -use crate::context::CodegenCx; +use crate::context::{CFunctionBuilder, CodegenCx}; +use crate::module::{CExpr, CStmt}; +use crate::utils::slab::Id; mod abi; mod asm; @@ -23,6 +25,7 @@ mod r#static; pub struct Builder<'a, 'tcx> { pub cx: &'a CodegenCx<'tcx>, + bb: Id, } impl<'a, 'tcx> Deref for Builder<'a, 'tcx> { @@ -96,7 +99,7 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for Builder<'_, 'tcx> { impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { fn build(cx: &'a Self::CodegenCx, llbb: Self::BasicBlock) -> Self { - Self { cx } + Self { cx, bb: llbb } } fn cx(&self) -> &Self::CodegenCx { @@ -110,7 +113,9 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { fn set_span(&mut self, _span: rustc_span::Span) {} fn append_block(cx: &'a Self::CodegenCx, llfn: Self::Function, name: &str) -> Self::BasicBlock { - crate::todo() + // assume there is only one basic block + // more complicated cases will be handled in the future + llfn } fn append_sibling_block(&mut self, name: &str) -> Self::BasicBlock { @@ -122,11 +127,13 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { } fn ret_void(&mut self) { - crate::todo() + let mut fuctions = self.cx.functions.borrow_mut(); + fuctions[self.bb].push_stmt(CStmt::Return(None)); } fn ret(&mut self, v: Self::Value) { - crate::todo() + let mut fuctions = self.cx.functions.borrow_mut(); + fuctions[self.bb].push_stmt(CStmt::Return(Some(Box::new(CExpr::Value(v))))); } fn br(&mut self, dest: Self::BasicBlock) { diff --git a/crates/rustc_codegen_c/src/builder/abi.rs b/crates/rustc_codegen_c/src/builder/abi.rs index 3ef5cc5..c654549 100644 --- a/crates/rustc_codegen_c/src/builder/abi.rs +++ b/crates/rustc_codegen_c/src/builder/abi.rs @@ -8,6 +8,7 @@ use crate::module::CValue; impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, 'tcx> { fn get_param(&mut self, index: usize) -> Self::Value { + // Params are first n variables in the function CValue::Var(index) } } diff --git a/crates/rustc_codegen_c/src/context.rs b/crates/rustc_codegen_c/src/context.rs index edc9648..37e6a89 100644 --- a/crates/rustc_codegen_c/src/context.rs +++ b/crates/rustc_codegen_c/src/context.rs @@ -29,6 +29,7 @@ mod type_membership; pub struct CodegenCx<'tcx> { pub tcx: TyCtxt<'tcx>, pub function_instances: RefCell, Id>>, + // TODO: better inner mutablity for slab pub functions: RefCell>, } @@ -59,7 +60,7 @@ impl<'tcx> CodegenCx<'tcx> { impl<'tcx> BackendTypes for CodegenCx<'tcx> { type Value = CValue; type Function = Id; - type BasicBlock = (); + type BasicBlock = Id; type Type = (); type Funclet = (); type DIScope = (); @@ -153,4 +154,8 @@ impl CFunctionBuilder { self.var_counter += 1; val } + + pub fn push_stmt(&mut self, stmt: CStmt) { + self.body.push(stmt); + } } diff --git a/crates/rustc_codegen_c/src/module.rs b/crates/rustc_codegen_c/src/module.rs index ee27b6a..11b0e28 100644 --- a/crates/rustc_codegen_c/src/module.rs +++ b/crates/rustc_codegen_c/src/module.rs @@ -119,6 +119,7 @@ impl Display for CEnumConstant { } } +/// Values of C variable, parameters and scalars #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] pub enum CValue { Scalar(i128), diff --git a/crates/rustc_codegen_c/src/utils/slab.rs b/crates/rustc_codegen_c/src/utils/slab.rs index 6e36042..b6d11ce 100644 --- a/crates/rustc_codegen_c/src/utils/slab.rs +++ b/crates/rustc_codegen_c/src/utils/slab.rs @@ -1,3 +1,5 @@ +use std::ops::{Index, IndexMut}; + pub struct Slab { data: Vec, } @@ -39,6 +41,19 @@ impl IntoIterator for Slab { } } +impl Index> for Slab { + type Output = T; + fn index(&self, id: Id) -> &T { + &self.data[id.index] + } +} + +impl IndexMut> for Slab { + fn index_mut(&mut self, id: Id) -> &mut T { + &mut self.data[id.index] + } +} + pub struct Id { index: usize, _phantom: std::marker::PhantomData, diff --git a/tests/codegen/filename.rs b/tests/codegen/filename.rs index b89870c..3a0eef8 100644 --- a/tests/codegen/filename.rs +++ b/tests/codegen/filename.rs @@ -13,4 +13,6 @@ pub fn function_name() -> i32 { } #[no_mangle] -pub fn main() {} +pub fn main() -> i32 { + 0 +} diff --git a/tests/codegen/params_count.rs b/tests/codegen/params_count.rs index 4d0a14b..01a846f 100644 --- a/tests/codegen/params_count.rs +++ b/tests/codegen/params_count.rs @@ -12,4 +12,6 @@ pub fn foo(_x: i32, _y: i32, _z: i32) -> i32 { } #[no_mangle] -pub fn main() {} +pub fn main() -> i32 { + 0 +} diff --git a/tests/codegen/ret_value.rs b/tests/codegen/ret_value.rs new file mode 100644 index 0000000..02c0d2e --- /dev/null +++ b/tests/codegen/ret_value.rs @@ -0,0 +1,12 @@ +#![feature(no_core)] +#![no_core] +#![no_main] + +extern crate mini_core; + +// expect three int params +// CHECK: 42 +#[no_mangle] +pub fn main() -> i32 { + 42 +} From a57986127f4e8a35c77407bc76d4236d3c0e473d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BF=98=E5=BF=A7=E5=8C=97=E8=90=B1=E8=8D=89?= Date: Sun, 21 Jul 2024 00:21:48 +0800 Subject: [PATCH 07/11] feat: integer types --- crates/rustc_codegen_c/src/base.rs | 6 +- crates/rustc_codegen_c/src/context.rs | 23 +- .../src/context/layout_type.rs | 7 +- .../rustc_codegen_c/src/context/pre_define.rs | 21 +- crates/rustc_codegen_c/src/lib.rs | 10 +- crates/rustc_codegen_c/src/module.rs | 264 +++++++++++++----- crates/rustc_codegen_c/src/slab.rs | 0 crates/rustc_codegen_c/src/utils.rs | 3 +- .../rustc_codegen_c/src/utils/sharded_slab.rs | 28 ++ crates/rustc_codegen_c/src/utils/slab.rs | 12 +- crates/rustc_codegen_c/src/write.rs | 13 +- example/example.rs | 2 +- example/mini_core.rs | 93 +++++- tests/codegen/params_count.rs | 2 +- 14 files changed, 364 insertions(+), 120 deletions(-) delete mode 100644 crates/rustc_codegen_c/src/slab.rs create mode 100644 crates/rustc_codegen_c/src/utils/sharded_slab.rs diff --git a/crates/rustc_codegen_c/src/base.rs b/crates/rustc_codegen_c/src/base.rs index 87a2684..a8b6d77 100644 --- a/crates/rustc_codegen_c/src/base.rs +++ b/crates/rustc_codegen_c/src/base.rs @@ -7,7 +7,7 @@ use rustc_middle::ty::TyCtxt; use crate::builder::Builder; use crate::context::CodegenCx; -use crate::module::Module; +use crate::module::ModuleContext; // note: parallel // it seems this function will be invoked parallelly (if parallel codegen is enabled) @@ -15,7 +15,7 @@ use crate::module::Module; pub fn compile_codegen_unit( tcx: TyCtxt<'_>, cgu_name: rustc_span::Symbol, -) -> (ModuleCodegen, u64) { +) -> (ModuleCodegen, u64) { let start_time = Instant::now(); let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx); @@ -36,7 +36,7 @@ pub fn compile_codegen_unit( (module, cost) } -fn module_codegen(tcx: TyCtxt<'_>, cgu_name: rustc_span::Symbol) -> ModuleCodegen { +fn module_codegen(tcx: TyCtxt<'_>, cgu_name: rustc_span::Symbol) -> ModuleCodegen { let cgu = tcx.codegen_unit(cgu_name); let cx = CodegenCx::new(tcx); diff --git a/crates/rustc_codegen_c/src/context.rs b/crates/rustc_codegen_c/src/context.rs index 37e6a89..a2cc885 100644 --- a/crates/rustc_codegen_c/src/context.rs +++ b/crates/rustc_codegen_c/src/context.rs @@ -13,7 +13,7 @@ use rustc_middle::ty::{Instance, ParamEnv, Ty, TyCtxt}; use rustc_target::abi::call::FnAbi; use rustc_target::spec::{HasTargetSpec, Target}; -use crate::module::{CDecl, CFunction, CStmt, CType, CValue, Module}; +use crate::module::{CDecl, CFunction, CStmt, CType, CValue, ModuleContext}; use crate::utils::slab::{Id, Slab}; mod asm; @@ -28,6 +28,7 @@ mod type_membership; pub struct CodegenCx<'tcx> { pub tcx: TyCtxt<'tcx>, + pub mcx: ModuleContext, pub function_instances: RefCell, Id>>, // TODO: better inner mutablity for slab pub functions: RefCell>, @@ -35,25 +36,23 @@ pub struct CodegenCx<'tcx> { impl<'tcx> CodegenCx<'tcx> { pub fn new(tcx: TyCtxt<'tcx>) -> Self { + let mcx = ModuleContext::new(); Self { tcx, + mcx, function_instances: RefCell::new(FxHashMap::default()), functions: RefCell::new(Slab::default()), } } - pub fn finish(self) -> Module { - let mut decls = vec![]; - + pub fn finish(mut self) -> ModuleContext { for function in self.functions.borrow().iter() { - decls.push(function.decl()); + self.mcx.module.decls.push(function.decl()); } - for function in self.functions.into_inner() { - decls.push(CDecl::Function(function.build())); + self.mcx.module.decls.push(CDecl::Function(function.build())); } - - Module { includes: vec![], decls } + self.mcx } } @@ -61,7 +60,7 @@ impl<'tcx> BackendTypes for CodegenCx<'tcx> { type Value = CValue; type Function = Id; type BasicBlock = Id; - type Type = (); + type Type = CType; type Funclet = (); type DIScope = (); type DILocation = (); @@ -144,8 +143,8 @@ impl CFunctionBuilder { pub fn decl(&self) -> CDecl { CDecl::FunctionDecl { name: self.name.clone(), - ty: self.ty.clone(), - params: self.params.iter().map(|(ty, _)| ty.clone()).collect(), + ty: self.ty, + params: self.params.iter().map(|(ty, _)| *ty).collect(), } } diff --git a/crates/rustc_codegen_c/src/context/layout_type.rs b/crates/rustc_codegen_c/src/context/layout_type.rs index 1af1556..5a20983 100644 --- a/crates/rustc_codegen_c/src/context/layout_type.rs +++ b/crates/rustc_codegen_c/src/context/layout_type.rs @@ -3,6 +3,7 @@ use rustc_codegen_ssa::traits::LayoutTypeMethods; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::Ty; use rustc_target::abi::call::FnAbi; +use rustc_type_ir::TyKind; use crate::context::CodegenCx; @@ -28,7 +29,11 @@ impl<'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'tcx> { } fn immediate_backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type { - crate::todo() + match layout.ty.kind() { + TyKind::Int(int) => self.mcx.get_int_type(*int), + TyKind::Uint(uint) => self.mcx.get_uint_type(*uint), + _ => todo!(), + } } fn is_backend_immediate(&self, layout: TyAndLayout<'tcx>) -> bool { diff --git a/crates/rustc_codegen_c/src/context/pre_define.rs b/crates/rustc_codegen_c/src/context/pre_define.rs index f516c83..4e53bee 100644 --- a/crates/rustc_codegen_c/src/context/pre_define.rs +++ b/crates/rustc_codegen_c/src/context/pre_define.rs @@ -1,12 +1,10 @@ -use rustc_codegen_ssa::traits::PreDefineMethods; +use rustc_codegen_ssa::traits::{LayoutTypeMethods, PreDefineMethods}; use rustc_hir::def_id::DefId; use rustc_middle::mir::mono::{Linkage, Visibility}; use rustc_middle::ty::layout::FnAbiOf; -use rustc_middle::ty::{self, Instance, Ty}; -use rustc_target::abi::call::{ArgAbi, PassMode}; +use rustc_middle::ty::{self, Instance}; use crate::context::{CFunctionBuilder, CodegenCx}; -use crate::module::CType; impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'tcx> { fn predefine_static( @@ -28,22 +26,11 @@ impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'tcx> { ) { let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); - let args = fn_abi.args.iter().map(|arg| type_from_abi(arg)).collect(); - let ret = type_from_abi(&fn_abi.ret); + let args = fn_abi.args.iter().map(|arg| self.immediate_backend_type(arg.layout)).collect(); + let ret = self.immediate_backend_type(fn_abi.ret.layout); let function = CFunctionBuilder::new(symbol_name.to_string(), ret, args); let function_id = self.functions.borrow_mut().insert(function); self.function_instances.borrow_mut().insert(instance, function_id); } } - -fn type_from_abi(abi: &ArgAbi<'_, Ty>) -> CType { - match &abi.mode { - PassMode::Ignore => CType::Builtin("void".to_string()), - PassMode::Direct(attributes) => { - // TODO: other types - CType::Builtin("int".to_string()) - } - _ => todo!(), - } -} diff --git a/crates/rustc_codegen_c/src/lib.rs b/crates/rustc_codegen_c/src/lib.rs index a71d4b8..c3afde6 100644 --- a/crates/rustc_codegen_c/src/lib.rs +++ b/crates/rustc_codegen_c/src/lib.rs @@ -1,5 +1,6 @@ #![feature(rustc_private)] +extern crate parking_lot; extern crate rustc_abi; extern crate rustc_ast; extern crate rustc_codegen_ssa; @@ -15,6 +16,8 @@ extern crate rustc_middle; extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; +extern crate rustc_type_ir; +extern crate sharded_slab; extern crate tracing; use std::sync::Arc; @@ -41,8 +44,7 @@ use rustc_session::config::{OptLevel, OutputFilenames}; use rustc_session::Session; use rustc_span::ErrorGuaranteed; -use crate::module::Module; - +use crate::module::ModuleContext; mod archive; mod base; @@ -156,7 +158,7 @@ impl ThinBufferMethods for ThinBuffer { } impl WriteBackendMethods for CCodegen { - type Module = Module; + type Module = ModuleContext; type TargetMachine = (); type TargetMachineError = (); type ModuleBuffer = ModuleBuffer; @@ -249,5 +251,3 @@ impl WriteBackendMethods for CCodegen { pub fn __rustc_codegen_backend() -> Box { Box::new(CCodegen {}) } - -fn todo() {} diff --git a/crates/rustc_codegen_c/src/module.rs b/crates/rustc_codegen_c/src/module.rs index 11b0e28..d92334d 100644 --- a/crates/rustc_codegen_c/src/module.rs +++ b/crates/rustc_codegen_c/src/module.rs @@ -5,30 +5,135 @@ //! The structure is derived from clang's AST. use std::borrow::Cow; -use std::fmt::Display; +use std::fmt::{Display, Formatter}; +use parking_lot::RwLock; use rustc_hash::FxHashMap; +use rustc_type_ir::{IntTy, UintTy}; + +use crate::utils::sharded_slab::{Entry, Id, ShardedSlab}; + +/// Rust's primitive types +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum PimitiveType { + Int(IntTy), + Uint(UintTy), +} + +pub struct ModuleContext { + types: ShardedSlab, + primitive_types: RwLock>, + pub module: Module, +} + +impl Default for ModuleContext { + fn default() -> Self { + Self::new() + } +} + +impl ModuleContext { + pub fn new() -> Self { + Self { + types: ShardedSlab::default(), + primitive_types: RwLock::new(FxHashMap::default()), + module: Module::new(), + } + } + + /// Get the type + pub fn ty(&self, id: CType) -> Entry { + self.types.get(id).unwrap() + } + + /// Get the type of an signed integer + pub fn get_int_type(&self, int: IntTy) -> CType { + if let Some(ty) = self.primitive_types.read().get(&PimitiveType::Int(int)) { + return *ty; + } + + let tykind = match int { + IntTy::Isize => CTypeKind::Builtin("ssize_t".to_string()), + IntTy::I8 => CTypeKind::Builtin("int8_t".to_string()), + IntTy::I16 => CTypeKind::Builtin("int16_t".to_string()), + IntTy::I32 => CTypeKind::Builtin("int32_t".to_string()), + IntTy::I64 => CTypeKind::Builtin("int64_t".to_string()), + IntTy::I128 => todo!(), + }; + let ty = self.types.insert(tykind); + self.primitive_types + .write() + .insert(PimitiveType::Int(int), ty); + ty + } + + /// Get the type of an unsigned integer + pub fn get_uint_type(&self, uint: UintTy) -> CType { + if let Some(ty) = self.primitive_types.read().get(&PimitiveType::Uint(uint)) { + return *ty; + } + + let tykind = match uint { + UintTy::Usize => CTypeKind::Builtin("size_t".to_string()), + UintTy::U8 => CTypeKind::Builtin("uint8_t".to_string()), + UintTy::U16 => CTypeKind::Builtin("uint16_t".to_string()), + UintTy::U32 => CTypeKind::Builtin("uint32_t".to_string()), + UintTy::U64 => CTypeKind::Builtin("uint64_t".to_string()), + UintTy::U128 => todo!(), + }; + let ty = self.types.insert(tykind); + self.primitive_types + .write() + .insert(PimitiveType::Uint(uint), ty); + ty + } +} + +impl Display for ModuleContext { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.module.fmt_with(f, self) + } +} -#[derive(Default)] pub struct Module { pub includes: Vec, pub decls: Vec, } -impl Display for Module { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl Default for Module { + fn default() -> Self { + Self::new() + } +} + +impl Module { + pub fn new() -> Self { + let includes = vec!["stdint.h".to_string()]; + let decls = vec![]; + Self { includes, decls } + } + + pub fn display<'a>(&'a self, ctx: &'a ModuleContext) -> impl Display + 'a { + struct ModuleDisplay<'a>(&'a Module, &'a ModuleContext); + impl<'a> Display for ModuleDisplay<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.0.fmt_with(f, self.1) + } + } + ModuleDisplay(self, ctx) + } + + fn fmt_with(&self, f: &mut Formatter<'_>, ctx: &ModuleContext) -> std::fmt::Result { for include in &self.includes { writeln!(f, "#include <{}>", include)?; } for decl in &self.decls { - writeln!(f, "{}", decl)?; + writeln!(f, "{}", decl.display(ctx))?; } Ok(()) } } -// TODO: use rustc's memory arena - pub enum CDecl { Typedef { name: String, ty: CType }, Record { name: String, fields: Vec }, @@ -40,18 +145,30 @@ pub enum CDecl { Raw(String), } -impl Display for CDecl { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl CDecl { + pub fn display<'a>(&'a self, ctx: &'a ModuleContext) -> impl Display + 'a { + struct CDeclDisplay<'a>(&'a CDecl, &'a ModuleContext); + impl<'a> Display for CDeclDisplay<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.0.fmt_with(f, self.1) + } + } + CDeclDisplay(self, ctx) + } + + fn fmt_with(&self, f: &mut Formatter<'_>, ctx: &ModuleContext) -> std::fmt::Result { match self { - CDecl::Typedef { name, ty } => write!(f, "typedef {} {};", name, ty), + CDecl::Typedef { name, ty } => { + write!(f, "typedef {} {};", name, ctx.ty(*ty).display(ctx)) + } CDecl::Record { name, fields } => { writeln!(f, "struct {} {{ ", name)?; for field in fields { - writeln!(f, "{}", field)?; + writeln!(f, "{}", field.display(ctx))?; } writeln!(f, "}};") } - CDecl::Field { name, ty } => write!(f, "{} {}", name, ty), + CDecl::Field { name, ty } => write!(f, "{} {}", name, ctx.ty(*ty).display(ctx)), CDecl::Enum { name, values } => { writeln!(f, "enum {} {{ ", name)?; for (i, value) in values.iter().enumerate() { @@ -63,16 +180,16 @@ impl Display for CDecl { writeln!(f, "}};") } CDecl::FunctionDecl { name, ty, params } => { - write!(f, "{} {}(", ty, name)?; + write!(f, "{} {}(", ctx.ty(*ty).display(ctx), name)?; for (i, param) in params.iter().enumerate() { if i > 0 { write!(f, ", ")?; } - write!(f, "{}", param)?; + write!(f, "{}", ctx.ty(*param).display(ctx))?; } write!(f, ");") } - CDecl::Function(func) => write!(f, "{}", func), + CDecl::Function(func) => write!(f, "{}", func.display(ctx)), // CDecl::Var { name, ty, init } => { // write!(f, "{} {}", ty, name)?; // if let Some(init) = init { @@ -85,21 +202,33 @@ impl Display for CDecl { } } -#[derive(Clone)] -pub enum CType { +pub type CType = Id; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum CTypeKind { Builtin(String), - Pointer(Box), + Pointer(CType), Record(String), - Array(Box, usize), + Array(CType, usize), } -impl Display for CType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl CTypeKind { + pub fn display<'a>(&'a self, ctx: &'a ModuleContext) -> impl Display + 'a { + struct DisplayCTypeKind<'a>(&'a CTypeKind, &'a ModuleContext); + impl<'a> Display for DisplayCTypeKind<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.0.fmt_with(f, self.1) + } + } + DisplayCTypeKind(self, ctx) + } + + fn fmt_with(&self, f: &mut Formatter<'_>, ctx: &ModuleContext) -> std::fmt::Result { match self { - CType::Builtin(ty) => write!(f, "{}", ty), - CType::Pointer(ty) => write!(f, "{}*", ty), - CType::Record(ty) => write!(f, "struct {}", ty), - CType::Array(ty, size) => write!(f, "{}[{}]", ty, size), + CTypeKind::Builtin(ty) => write!(f, "{}", ty), + CTypeKind::Pointer(ty) => write!(f, "{}*", ctx.ty(*ty).display(ctx)), + CTypeKind::Record(ty) => write!(f, "struct {}", ty), + CTypeKind::Array(ty, size) => write!(f, "{}[{}]", ctx.ty(*ty).display(ctx), size), } } } @@ -110,7 +239,7 @@ pub struct CEnumConstant { } impl Display for CEnumConstant { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.name)?; // if let Some(value) = &self.value { // write!(f, " = {}", value)?; @@ -147,18 +276,28 @@ impl CFunction { } } -impl Display for CFunction { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{} {}(", self.ty, self.name)?; +impl CFunction { + pub fn display<'a>(&'a self, ctx: &'a ModuleContext) -> impl Display + '_ { + struct CFunctionDisplay<'a>(&'a CFunction, &'a ModuleContext); + impl<'a> Display for CFunctionDisplay<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.0.fmt_with(f, self.1) + } + } + CFunctionDisplay(self, ctx) + } + + fn fmt_with(&self, f: &mut Formatter<'_>, ctx: &ModuleContext) -> std::fmt::Result { + write!(f, "{} {}(", ctx.ty(self.ty).display(ctx), self.name)?; for (i, (ty, param)) in self.params.iter().enumerate() { if i > 0 { write!(f, ", ")?; } - write!(f, "{} {}", ty, self.get_var_name(*param))?; + write!(f, "{} {}", ctx.ty(*ty).display(ctx), self.get_var_name(*param))?; } write!(f, ") {{")?; for stmt in &self.body { - writeln!(f, "{}", stmt.display(self))?; + writeln!(f, "{}", stmt.display(self, ctx))?; } write!(f, "}}") } @@ -173,48 +312,48 @@ pub enum CStmt { } impl CStmt { - pub fn display<'a>(&'a self, function: &'a CFunction) -> impl Display + '_ { - struct CStmtDisplay<'a> { - stmt: &'a CStmt, - function: &'a CFunction, - } - + pub fn display<'a>(&'a self, fun: &'a CFunction, ctx: &'a ModuleContext) -> impl Display + '_ { + struct CStmtDisplay<'a>(&'a CStmt, &'a CFunction, &'a ModuleContext); impl<'a> Display for CStmtDisplay<'a> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.stmt.fmt_with(f, self.function) + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.0.fmt_with(f, self.1, self.2) } } - - CStmtDisplay { stmt: self, function } + CStmtDisplay(self, fun, ctx) } - fn fmt_with(&self, f: &mut std::fmt::Formatter<'_>, function: &CFunction) -> std::fmt::Result { + fn fmt_with( + &self, + f: &mut Formatter<'_>, + fun: &CFunction, + ctx: &ModuleContext, + ) -> std::fmt::Result { match self { CStmt::Compound(stmts) => { writeln!(f, "{{")?; for stmt in stmts { - writeln!(f, "{}", stmt.display(function))?; + writeln!(f, "{}", stmt.display(fun, ctx))?; } write!(f, "}}") } CStmt::If { cond, then_br: then_, else_br: else_ } => { - writeln!(f, "if ({}) {{", cond.display(function))?; - writeln!(f, "{}", then_.display(function))?; + writeln!(f, "if ({}) {{", cond.display(fun))?; + writeln!(f, "{}", then_.display(fun, ctx))?; if let Some(else_) = else_ { writeln!(f, "}} else {{")?; - writeln!(f, "{}", else_.display(function))?; + writeln!(f, "{}", else_.display(fun, ctx))?; } write!(f, "}}") } CStmt::Return(expr) => { write!(f, "return")?; if let Some(expr) = expr { - write!(f, " {}", expr.display(function))?; + write!(f, " {}", expr.display(fun))?; } write!(f, ";") } - CStmt::Decl(decl) => write!(f, "{}", decl), - CStmt::Expr(expr) => write!(f, "{};", expr.display(function)), + CStmt::Decl(decl) => write!(f, "{}", decl.display(ctx)), + CStmt::Expr(expr) => write!(f, "{};", expr.display(fun)), } } } @@ -228,43 +367,38 @@ pub enum CExpr { } impl CExpr { - pub fn display<'a>(&'a self, function: &'a CFunction) -> impl Display + '_ { - struct CExprDisplay<'a> { - expr: &'a CExpr, - function: &'a CFunction, - } - + pub fn display<'a>(&'a self, fun: &'a CFunction) -> impl Display + '_ { + struct CExprDisplay<'a>(&'a CExpr, &'a CFunction); impl<'a> Display for CExprDisplay<'a> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.expr.fmt_with(f, self.function) + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.0.fmt_with(f, self.1) } } - - CExprDisplay { expr: self, function } + CExprDisplay(self, fun) } - fn fmt_with(&self, f: &mut std::fmt::Formatter<'_>, function: &CFunction) -> std::fmt::Result { + fn fmt_with(&self, f: &mut Formatter<'_>, fun: &CFunction) -> std::fmt::Result { match self { CExpr::Literal(lit) => write!(f, "{}", lit), CExpr::Value(val) => { - let name = function.get_var_name(*val); + let name = fun.get_var_name(*val); write!(f, "{}", name) } CExpr::BinaryOperator { lhs, rhs, op } => { - write!(f, "({} {} {})", lhs.display(function), op, rhs.display(function)) + write!(f, "({} {} {})", lhs.display(fun), op, rhs.display(fun)) } CExpr::Call { callee, args } => { - write!(f, "{}(", callee.display(function))?; + write!(f, "{}(", callee.display(fun))?; for (i, arg) in args.iter().enumerate() { if i != 0 { write!(f, ", ")?; } - write!(f, "{}", arg.display(function))?; + write!(f, "{}", arg.display(fun))?; } write!(f, ")") } CExpr::Member { expr, arrow, field } => { - write!(f, "{}", expr.display(function))?; + write!(f, "{}", expr.display(fun))?; if *arrow { write!(f, "->")?; } else { diff --git a/crates/rustc_codegen_c/src/slab.rs b/crates/rustc_codegen_c/src/slab.rs deleted file mode 100644 index e69de29..0000000 diff --git a/crates/rustc_codegen_c/src/utils.rs b/crates/rustc_codegen_c/src/utils.rs index 7c9d543..1005563 100644 --- a/crates/rustc_codegen_c/src/utils.rs +++ b/crates/rustc_codegen_c/src/utils.rs @@ -1 +1,2 @@ -pub mod slab; \ No newline at end of file +pub mod sharded_slab; +pub mod slab; diff --git a/crates/rustc_codegen_c/src/utils/sharded_slab.rs b/crates/rustc_codegen_c/src/utils/sharded_slab.rs new file mode 100644 index 0000000..5128e89 --- /dev/null +++ b/crates/rustc_codegen_c/src/utils/sharded_slab.rs @@ -0,0 +1,28 @@ +pub use sharded_slab::Entry; + +pub use crate::utils::slab::Id; + +pub struct ShardedSlab { + inner: sharded_slab::Slab, +} + +impl Default for ShardedSlab { + fn default() -> Self { + Self::new() + } +} + +impl ShardedSlab { + pub fn new() -> Self { + Self { inner: sharded_slab::Slab::new() } + } + + pub fn insert(&self, value: T) -> Id { + let index = self.inner.insert(value).expect("sharded slab is full"); + Id::new(index) + } + + pub fn get(&self, id: Id) -> Option> { + self.inner.get(id.index) + } +} diff --git a/crates/rustc_codegen_c/src/utils/slab.rs b/crates/rustc_codegen_c/src/utils/slab.rs index b6d11ce..9d4cb2a 100644 --- a/crates/rustc_codegen_c/src/utils/slab.rs +++ b/crates/rustc_codegen_c/src/utils/slab.rs @@ -4,8 +4,6 @@ pub struct Slab { data: Vec, } - - impl Default for Slab { fn default() -> Self { Self::new() @@ -55,11 +53,17 @@ impl IndexMut> for Slab { } pub struct Id { - index: usize, + pub(super) index: usize, _phantom: std::marker::PhantomData, } -impl Copy for Id{} +impl Id { + pub(super) fn new(index: usize) -> Self { + Self { index, _phantom: std::marker::PhantomData } + } +} + +impl Copy for Id {} impl Clone for Id { fn clone(&self) -> Self { diff --git a/crates/rustc_codegen_c/src/write.rs b/crates/rustc_codegen_c/src/write.rs index 375f5e7..79f657f 100644 --- a/crates/rustc_codegen_c/src/write.rs +++ b/crates/rustc_codegen_c/src/write.rs @@ -9,17 +9,12 @@ use rustc_errors::{DiagCtxtHandle, FatalError}; use rustc_session::config::OutputType; use tracing::error; -use crate::module::Module; - -// mini_core.b9ae8e2840b8e4ad-cgu.0 -// mini_core.mini_core.b9ae8e2840b8e4ad-cgu.0.rcgu.o - -// output to `[crate-name].[cgu-name].rcgu.o` +use crate::module::ModuleContext; pub(crate) unsafe fn codegen( cgcx: &CodegenContext, _dcx: DiagCtxtHandle<'_>, - module: ModuleCodegen, + module: ModuleCodegen, _config: &ModuleConfig, ) -> Result { let module_name = module.name.clone(); @@ -67,7 +62,7 @@ pub(crate) unsafe fn codegen( pub(crate) fn link( _cgcx: &CodegenContext, _dcx: DiagCtxtHandle<'_>, - mut _modules: Vec>, -) -> Result, FatalError> { + mut _modules: Vec>, +) -> Result, FatalError> { unimplemented!(); } diff --git a/example/example.rs b/example/example.rs index c929988..3882f1f 100644 --- a/example/example.rs +++ b/example/example.rs @@ -10,6 +10,6 @@ pub fn main() -> i32 { } #[no_mangle] -pub fn foo(x: i32) -> i32 { +pub fn foo(x: u64) -> u64 { x } diff --git a/example/mini_core.rs b/example/mini_core.rs index 3a69bdf..1a720fe 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -1,7 +1,11 @@ -#![feature(no_core, lang_items)] +#![feature(no_core, lang_items, rustc_attrs, intrinsics, decl_macro)] #![no_core] #![allow(internal_features)] +// #[rustc_builtin_macro] +// #[rustc_macro_transparency = "semitransparent"] +// pub macro stringify($($t:tt)*) { /* compiler built-in */ } + #[lang = "sized"] pub trait Sized {} @@ -25,6 +29,93 @@ unsafe impl<'a, T: ?Sized> Copy for &'a T {} unsafe impl Copy for *const T {} unsafe impl Copy for *mut T {} +// #[lang = "add"] +// pub trait Add { +// type Output; + +// #[must_use = "this returns the result of the operation, without modifying the original"] +// fn add(self, rhs: Rhs) -> Self::Output; +// } + +// impl Add for i32 { +// type Output = i32; + +// #[inline] +// fn add(self, other: i32) -> i32 { self + other } +// } + +// #[lang = "panic"] +// #[track_caller] +// pub fn panic(_msg: &'static str) -> ! { +// unsafe { +// libc::puts("Panicking\n\0" as *const str as *const u8); +// intrinsics::abort(); +// } +// } + +// #[lang = "panic_location"] +// #[allow(dead_code)] +// struct PanicLocation { +// file: &'static str, +// line: u32, +// column: u32, +// } + +// macro_rules! panic_const { +// ($($lang:ident = $message:expr,)+) => { +// pub mod panic_const { +// use super::*; + +// $( +// #[track_caller] +// #[lang = stringify!($lang)] +// pub fn $lang() -> ! { +// panic($message); +// } +// )+ +// } +// } +// } + +// panic_const! { +// panic_const_add_overflow = "attempt to add with overflow", +// panic_const_sub_overflow = "attempt to subtract with overflow", +// panic_const_mul_overflow = "attempt to multiply with overflow", +// panic_const_div_overflow = "attempt to divide with overflow", +// panic_const_rem_overflow = "attempt to calculate the remainder with overflow", +// panic_const_neg_overflow = "attempt to negate with overflow", +// panic_const_shr_overflow = "attempt to shift right with overflow", +// panic_const_shl_overflow = "attempt to shift left with overflow", +// panic_const_div_by_zero = "attempt to divide by zero", +// panic_const_rem_by_zero = "attempt to calculate the remainder with a divisor of zero", +// } + +// pub mod intrinsics { +// use crate::Sized; + +// extern "rust-intrinsic" { +// #[rustc_safe_intrinsic] +// pub fn abort() -> !; +// #[rustc_safe_intrinsic] +// pub fn size_of() -> usize; +// pub fn size_of_val(val: *const T) -> usize; +// #[rustc_safe_intrinsic] +// pub fn min_align_of() -> usize; +// pub fn min_align_of_val(val: *const T) -> usize; +// pub fn copy(src: *const T, dst: *mut T, count: usize); +// pub fn transmute(e: T) -> U; +// pub fn ctlz_nonzero(x: T) -> u32; +// #[rustc_safe_intrinsic] +// pub fn needs_drop() -> bool; +// #[rustc_safe_intrinsic] +// pub fn bitreverse(x: T) -> T; +// #[rustc_safe_intrinsic] +// pub fn bswap(x: T) -> T; +// pub fn write_bytes(dst: *mut T, val: u8, count: usize); +// pub fn unreachable() -> !; +// } +// } + pub mod libc { #[link(name = "c")] extern "C" { diff --git a/tests/codegen/params_count.rs b/tests/codegen/params_count.rs index 01a846f..83f9963 100644 --- a/tests/codegen/params_count.rs +++ b/tests/codegen/params_count.rs @@ -5,7 +5,7 @@ extern crate mini_core; // expect three int params -// CHECK: {{((int .*,?\s?){3})}} +// CHECK: {{((int32_t .*,?\s?){3})}} #[no_mangle] pub fn foo(_x: i32, _y: i32, _z: i32) -> i32 { 0 From af1173bc895a163515f390e29cba3d64cb46fc33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BF=98=E5=BF=A7=E5=8C=97=E8=90=B1=E8=8D=89?= Date: Sun, 21 Jul 2024 14:41:44 +0800 Subject: [PATCH 08/11] feat: integer cast --- crates/Cargo.lock | 3 + crates/rustc_codegen_c/Cargo.toml | 1 + crates/rustc_codegen_c/src/base.rs | 24 +- crates/rustc_codegen_c/src/builder.rs | 92 ++-- crates/rustc_codegen_c/src/builder/abi.rs | 8 +- crates/rustc_codegen_c/src/builder/asm.rs | 2 +- .../src/builder/coverage_info.rs | 2 +- .../rustc_codegen_c/src/builder/debug_info.rs | 2 +- .../src/builder/intrinsic_call.rs | 2 +- crates/rustc_codegen_c/src/builder/static.rs | 2 +- crates/rustc_codegen_c/src/context.rs | 113 ++--- crates/rustc_codegen_c/src/context/asm.rs | 2 +- .../rustc_codegen_c/src/context/base_type.rs | 2 +- crates/rustc_codegen_c/src/context/const.rs | 4 +- .../rustc_codegen_c/src/context/debug_info.rs | 2 +- .../src/context/layout_type.rs | 2 +- crates/rustc_codegen_c/src/context/misc.rs | 2 +- .../rustc_codegen_c/src/context/pre_define.rs | 15 +- crates/rustc_codegen_c/src/context/static.rs | 2 +- .../src/context/type_membership.rs | 2 +- crates/rustc_codegen_c/src/helper.h | 12 + crates/rustc_codegen_c/src/lib.rs | 10 +- crates/rustc_codegen_c/src/module.rs | 411 ------------------ crates/rustc_codegen_c/src/utils.rs | 2 - .../rustc_codegen_c/src/utils/sharded_slab.rs | 28 -- crates/rustc_codegen_c/src/utils/slab.rs | 92 ---- crates/rustc_codegen_c/src/write.rs | 19 +- example/example.rs | 4 +- example/mini_core.rs | 91 ---- tests/bless/basic_math.c | 26 ++ 30 files changed, 182 insertions(+), 797 deletions(-) create mode 100644 crates/rustc_codegen_c/src/helper.h delete mode 100644 crates/rustc_codegen_c/src/module.rs delete mode 100644 crates/rustc_codegen_c/src/utils.rs delete mode 100644 crates/rustc_codegen_c/src/utils/sharded_slab.rs delete mode 100644 crates/rustc_codegen_c/src/utils/slab.rs create mode 100644 tests/bless/basic_math.c diff --git a/crates/Cargo.lock b/crates/Cargo.lock index 87c0f98..063b212 100644 --- a/crates/Cargo.lock +++ b/crates/Cargo.lock @@ -5,6 +5,9 @@ version = 3 [[package]] name = "rustc_codegen_c" version = "0.1.0" +dependencies = [ + "rustc_codegen_c_ast", +] [[package]] name = "rustc_codegen_c_ast" diff --git a/crates/rustc_codegen_c/Cargo.toml b/crates/rustc_codegen_c/Cargo.toml index 5114a66..5a52156 100644 --- a/crates/rustc_codegen_c/Cargo.toml +++ b/crates/rustc_codegen_c/Cargo.toml @@ -7,6 +7,7 @@ version.workspace = true crate-type = ["dylib"] [dependencies] +rustc_codegen_c_ast = { path = "../rustc_codegen_c_ast" } # This package uses rustc crates. [package.metadata.rust-analyzer] diff --git a/crates/rustc_codegen_c/src/base.rs b/crates/rustc_codegen_c/src/base.rs index a8b6d77..bdac635 100644 --- a/crates/rustc_codegen_c/src/base.rs +++ b/crates/rustc_codegen_c/src/base.rs @@ -1,5 +1,6 @@ use std::time::Instant; +use rustc_codegen_c_ast::{ModuleArena, ModuleCtx}; use rustc_codegen_ssa::mono_item::MonoItemExt; use rustc_codegen_ssa::{ModuleCodegen, ModuleKind}; use rustc_middle::dep_graph; @@ -7,7 +8,9 @@ use rustc_middle::ty::TyCtxt; use crate::builder::Builder; use crate::context::CodegenCx; -use crate::module::ModuleContext; + +/// Needed helper functions +const HELPER: &str = include_str!("./helper.h"); // note: parallel // it seems this function will be invoked parallelly (if parallel codegen is enabled) @@ -15,7 +18,7 @@ use crate::module::ModuleContext; pub fn compile_codegen_unit( tcx: TyCtxt<'_>, cgu_name: rustc_span::Symbol, -) -> (ModuleCodegen, u64) { +) -> (ModuleCodegen, u64) { let start_time = Instant::now(); let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx); @@ -36,24 +39,23 @@ pub fn compile_codegen_unit( (module, cost) } -fn module_codegen(tcx: TyCtxt<'_>, cgu_name: rustc_span::Symbol) -> ModuleCodegen { +fn module_codegen(tcx: TyCtxt<'_>, cgu_name: rustc_span::Symbol) -> ModuleCodegen { let cgu = tcx.codegen_unit(cgu_name); - let cx = CodegenCx::new(tcx); + let mcx = ModuleArena::new(HELPER); + let mcx = ModuleCtx(&mcx); + let cx = CodegenCx::new(tcx, mcx); let mono_items = cgu.items_in_deterministic_order(tcx); for &(mono_item, data) in &mono_items { - mono_item.predefine::>(&cx, data.linkage, data.visibility); + mono_item.predefine::>(&cx, data.linkage, data.visibility); } // ... and now that we have everything pre-defined, fill out those definitions. for &(mono_item, _) in &mono_items { - mono_item.define::>(&cx); + mono_item.define::>(&cx); } - ModuleCodegen { - name: cgu_name.to_string(), - module_llvm: cx.finish(), - kind: ModuleKind::Regular, - } + let module = mcx.to_string(); + ModuleCodegen { name: cgu_name.to_string(), module_llvm: module, kind: ModuleKind::Regular } } diff --git a/crates/rustc_codegen_c/src/builder.rs b/crates/rustc_codegen_c/src/builder.rs index d3ef439..a067393 100644 --- a/crates/rustc_codegen_c/src/builder.rs +++ b/crates/rustc_codegen_c/src/builder.rs @@ -3,6 +3,7 @@ use std::ops::Deref; use rustc_abi::{HasDataLayout, TargetDataLayout}; +use rustc_codegen_c_ast::func::CFunc; use rustc_codegen_ssa::traits::{BackendTypes, BuilderMethods, HasCodegen}; use rustc_middle::ty::layout::{ FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, @@ -12,9 +13,7 @@ use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_target::abi::call::FnAbi; use rustc_target::spec::{HasTargetSpec, Target}; -use crate::context::{CFunctionBuilder, CodegenCx}; -use crate::module::{CExpr, CStmt}; -use crate::utils::slab::Id; +use crate::context::CodegenCx; mod abi; mod asm; @@ -23,60 +22,64 @@ mod debug_info; mod intrinsic_call; mod r#static; -pub struct Builder<'a, 'tcx> { - pub cx: &'a CodegenCx<'tcx>, - bb: Id, +/// Codegen builder. +/// +/// It is created for each function and provides the local context for code generation. +pub struct Builder<'a, 'tcx, 'mx> { + /// The associated codegen context. + pub cx: &'a CodegenCx<'tcx, 'mx>, + bb: CFunc<'mx>, } -impl<'a, 'tcx> Deref for Builder<'a, 'tcx> { - type Target = CodegenCx<'tcx>; +impl<'a, 'tcx, 'mx> Deref for Builder<'a, 'tcx, 'mx> { + type Target = CodegenCx<'tcx, 'mx>; fn deref<'b>(&'b self) -> &'a Self::Target { self.cx } } -impl<'tcx> HasCodegen<'tcx> for Builder<'_, 'tcx> { - type CodegenCx = CodegenCx<'tcx>; +impl<'tcx, 'mx> HasCodegen<'tcx> for Builder<'_, 'tcx, 'mx> { + type CodegenCx = CodegenCx<'tcx, 'mx>; } -impl<'tcx> HasDataLayout for Builder<'_, 'tcx> { +impl<'tcx, 'mx> HasDataLayout for Builder<'_, 'tcx, 'mx> { fn data_layout(&self) -> &TargetDataLayout { todo!() } } -impl<'tcx> HasTyCtxt<'tcx> for Builder<'_, 'tcx> { +impl<'tcx, 'mx> HasTyCtxt<'tcx> for Builder<'_, 'tcx, 'mx> { fn tcx(&self) -> TyCtxt<'tcx> { self.cx.tcx() } } -impl<'tcx> HasParamEnv<'tcx> for Builder<'_, 'tcx> { +impl<'tcx, 'mx> HasParamEnv<'tcx> for Builder<'_, 'tcx, 'mx> { fn param_env(&self) -> ParamEnv<'tcx> { self.cx.param_env() } } -impl<'tcx> BackendTypes for Builder<'_, 'tcx> { - type Value = as BackendTypes>::Value; - type Function = as BackendTypes>::Function; - type BasicBlock = as BackendTypes>::BasicBlock; - type Type = as BackendTypes>::Type; - type Funclet = as BackendTypes>::Funclet; +impl<'tcx, 'mx> BackendTypes for Builder<'_, 'tcx, 'mx> { + type Value = as BackendTypes>::Value; + type Function = as BackendTypes>::Function; + type BasicBlock = as BackendTypes>::BasicBlock; + type Type = as BackendTypes>::Type; + type Funclet = as BackendTypes>::Funclet; - type DIScope = as BackendTypes>::DIScope; - type DILocation = as BackendTypes>::DILocation; - type DIVariable = as BackendTypes>::DIVariable; + type DIScope = as BackendTypes>::DIScope; + type DILocation = as BackendTypes>::DILocation; + type DIVariable = as BackendTypes>::DIVariable; } -impl<'tcx> HasTargetSpec for Builder<'_, 'tcx> { +impl<'tcx, 'mx> HasTargetSpec for Builder<'_, 'tcx, 'mx> { fn target_spec(&self) -> &Target { todo!() } } -impl<'tcx> LayoutOfHelpers<'tcx> for Builder<'_, 'tcx> { +impl<'tcx, 'mx> LayoutOfHelpers<'tcx> for Builder<'_, 'tcx, 'mx> { type LayoutOfResult = TyAndLayout<'tcx>; fn handle_layout_err(&self, err: LayoutError<'tcx>, span: rustc_span::Span, ty: Ty<'tcx>) -> ! { @@ -84,7 +87,7 @@ impl<'tcx> LayoutOfHelpers<'tcx> for Builder<'_, 'tcx> { } } -impl<'tcx> FnAbiOfHelpers<'tcx> for Builder<'_, 'tcx> { +impl<'tcx, 'mx> FnAbiOfHelpers<'tcx> for Builder<'_, 'tcx, 'mx> { type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>; fn handle_fn_abi_err( @@ -97,7 +100,7 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for Builder<'_, 'tcx> { } } -impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { +impl<'a, 'tcx, 'mx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx, 'mx> { fn build(cx: &'a Self::CodegenCx, llbb: Self::BasicBlock) -> Self { Self { cx, bb: llbb } } @@ -127,13 +130,11 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { } fn ret_void(&mut self) { - let mut fuctions = self.cx.functions.borrow_mut(); - fuctions[self.bb].push_stmt(CStmt::Return(None)); + self.bb.0.push_stmt(self.cx.mcx.ret(None)); } fn ret(&mut self, v: Self::Value) { - let mut fuctions = self.cx.functions.borrow_mut(); - fuctions[self.bb].push_stmt(CStmt::Return(Some(Box::new(CExpr::Value(v))))); + self.bb.0.push_stmt(self.cx.mcx.ret(Some(self.cx.mcx.value(v)))) } fn br(&mut self, dest: Self::BasicBlock) { @@ -495,8 +496,37 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> { todo!() } + /// Performs cast between integers, x as ty in Rust. + /// + /// If the bit width is different, a truncation or extension is required. + /// The type of extension—sign-extension or zero-extension—depends on the + /// signedness of the source type. + /// + /// According to the C17 standard, section "6.3.1.3 Signed and unsigned + /// integers", casting to an unsigned integer behaves the same as in Rust. + /// However, casting to a signed integer is implementation-defined. + /// + /// Therefore, a two-step cast is necessary. First, cast to an unsigned + /// integer via explicit conversion. Then, use a helper function to cast the + /// result to a signed integer. fn intcast(&mut self, val: Self::Value, dest_ty: Self::Type, is_signed: bool) -> Self::Value { - todo!() + let mcx = self.cx.mcx; + let ret = self.bb.0.next_local_var(); + + let mut cast = mcx.cast(dest_ty, mcx.value(val)); + if dest_ty.is_signed() { + cast = mcx.call( + mcx.raw("__rust_utos"), + vec![ + mcx.raw(dest_ty.to_unsigned().to_str()), + mcx.raw(dest_ty.to_str()), + cast, + mcx.raw(dest_ty.max_value()), + ], + ); + } + self.bb.0.push_stmt(mcx.decl_stmt(mcx.var(ret, dest_ty, Some(cast)))); + ret } fn pointercast(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value { diff --git a/crates/rustc_codegen_c/src/builder/abi.rs b/crates/rustc_codegen_c/src/builder/abi.rs index c654549..563aa87 100644 --- a/crates/rustc_codegen_c/src/builder/abi.rs +++ b/crates/rustc_codegen_c/src/builder/abi.rs @@ -1,19 +1,19 @@ +use rustc_codegen_c_ast::expr::CValue; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::{AbiBuilderMethods, ArgAbiMethods}; use rustc_middle::ty::Ty; use rustc_target::abi::call::ArgAbi; use crate::builder::Builder; -use crate::module::CValue; -impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, 'tcx> { +impl<'tcx, 'mx> AbiBuilderMethods<'tcx> for Builder<'_, 'tcx, 'mx> { fn get_param(&mut self, index: usize) -> Self::Value { // Params are first n variables in the function - CValue::Var(index) + CValue::Local(index) } } -impl<'tcx> ArgAbiMethods<'tcx> for Builder<'_, 'tcx> { +impl<'tcx, 'mx> ArgAbiMethods<'tcx> for Builder<'_, 'tcx, 'mx> { fn store_fn_arg( &mut self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, diff --git a/crates/rustc_codegen_c/src/builder/asm.rs b/crates/rustc_codegen_c/src/builder/asm.rs index 15b3d47..a967044 100644 --- a/crates/rustc_codegen_c/src/builder/asm.rs +++ b/crates/rustc_codegen_c/src/builder/asm.rs @@ -4,7 +4,7 @@ use rustc_middle::ty::Instance; use crate::builder::Builder; -impl<'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'tcx> { +impl<'tcx, 'mx> AsmBuilderMethods<'tcx> for Builder<'_, 'tcx, 'mx> { fn codegen_inline_asm( &mut self, template: &[InlineAsmTemplatePiece], diff --git a/crates/rustc_codegen_c/src/builder/coverage_info.rs b/crates/rustc_codegen_c/src/builder/coverage_info.rs index 1c93b7f..adabf33 100644 --- a/crates/rustc_codegen_c/src/builder/coverage_info.rs +++ b/crates/rustc_codegen_c/src/builder/coverage_info.rs @@ -2,7 +2,7 @@ use rustc_codegen_ssa::traits::CoverageInfoBuilderMethods; use crate::builder::Builder; -impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, 'tcx> { +impl<'tcx, 'mx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, 'tcx, 'mx> { fn add_coverage( &mut self, instance: rustc_middle::ty::Instance<'tcx>, diff --git a/crates/rustc_codegen_c/src/builder/debug_info.rs b/crates/rustc_codegen_c/src/builder/debug_info.rs index 5851843..374a380 100644 --- a/crates/rustc_codegen_c/src/builder/debug_info.rs +++ b/crates/rustc_codegen_c/src/builder/debug_info.rs @@ -2,7 +2,7 @@ use rustc_codegen_ssa::traits::DebugInfoBuilderMethods; use crate::builder::Builder; -impl DebugInfoBuilderMethods for Builder<'_, '_> { +impl DebugInfoBuilderMethods for Builder<'_, '_, '_> { fn dbg_var_addr( &mut self, dbg_var: Self::DIVariable, diff --git a/crates/rustc_codegen_c/src/builder/intrinsic_call.rs b/crates/rustc_codegen_c/src/builder/intrinsic_call.rs index 6242c85..de31b4a 100644 --- a/crates/rustc_codegen_c/src/builder/intrinsic_call.rs +++ b/crates/rustc_codegen_c/src/builder/intrinsic_call.rs @@ -5,7 +5,7 @@ use rustc_target::abi::call::FnAbi; use crate::builder::Builder; -impl<'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'tcx> { +impl<'tcx, 'mx> IntrinsicCallMethods<'tcx> for Builder<'_, 'tcx, 'mx> { fn codegen_intrinsic_call( &mut self, instance: Instance<'tcx>, diff --git a/crates/rustc_codegen_c/src/builder/static.rs b/crates/rustc_codegen_c/src/builder/static.rs index 38f19d7..122048a 100644 --- a/crates/rustc_codegen_c/src/builder/static.rs +++ b/crates/rustc_codegen_c/src/builder/static.rs @@ -3,7 +3,7 @@ use rustc_hir::def_id::DefId; use crate::builder::Builder; -impl<'tcx> StaticBuilderMethods for Builder<'_, 'tcx> { +impl<'tcx, 'mx> StaticBuilderMethods for Builder<'_, 'tcx, 'mx> { fn get_static(&mut self, def_id: DefId) -> Self::Value { todo!() } diff --git a/crates/rustc_codegen_c/src/context.rs b/crates/rustc_codegen_c/src/context.rs index a2cc885..afdfbfc 100644 --- a/crates/rustc_codegen_c/src/context.rs +++ b/crates/rustc_codegen_c/src/context.rs @@ -3,6 +3,10 @@ use std::cell::RefCell; use rustc_abi::{HasDataLayout, TargetDataLayout}; +use rustc_codegen_c_ast::expr::CValue; +use rustc_codegen_c_ast::func::CFunc; +use rustc_codegen_c_ast::ty::CTy; +use rustc_codegen_c_ast::ModuleCtx; use rustc_codegen_ssa::traits::BackendTypes; use rustc_hash::FxHashMap; use rustc_middle::ty::layout::{ @@ -13,9 +17,6 @@ use rustc_middle::ty::{Instance, ParamEnv, Ty, TyCtxt}; use rustc_target::abi::call::FnAbi; use rustc_target::spec::{HasTargetSpec, Target}; -use crate::module::{CDecl, CFunction, CStmt, CType, CValue, ModuleContext}; -use crate::utils::slab::{Id, Slab}; - mod asm; mod base_type; mod r#const; @@ -26,72 +27,61 @@ mod pre_define; mod r#static; mod type_membership; -pub struct CodegenCx<'tcx> { +/// Codegen context. +/// +/// It provides the global context for code generation. +pub struct CodegenCx<'tcx, 'mx> { + /// The type context. See [`TyCtxt`]. pub tcx: TyCtxt<'tcx>, - pub mcx: ModuleContext, - pub function_instances: RefCell, Id>>, - // TODO: better inner mutablity for slab - pub functions: RefCell>, + /// The output and context for the outputed module. + pub mcx: ModuleCtx<'mx>, + /// Mapping from Rust function instances to their corresponding C functions. + pub function_instances: RefCell, CFunc<'mx>>>, } -impl<'tcx> CodegenCx<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>) -> Self { - let mcx = ModuleContext::new(); - Self { - tcx, - mcx, - function_instances: RefCell::new(FxHashMap::default()), - functions: RefCell::new(Slab::default()), - } - } - - pub fn finish(mut self) -> ModuleContext { - for function in self.functions.borrow().iter() { - self.mcx.module.decls.push(function.decl()); - } - for function in self.functions.into_inner() { - self.mcx.module.decls.push(CDecl::Function(function.build())); - } - self.mcx +impl<'tcx, 'mx> CodegenCx<'tcx, 'mx> { + pub fn new(tcx: TyCtxt<'tcx>, mcx: ModuleCtx<'mx>) -> Self { + mcx.module().push_include("stdint.h"); + Self { tcx, mcx, function_instances: RefCell::new(FxHashMap::default()) } } } -impl<'tcx> BackendTypes for CodegenCx<'tcx> { - type Value = CValue; - type Function = Id; - type BasicBlock = Id; - type Type = CType; +impl<'tcx, 'mx> BackendTypes for CodegenCx<'tcx, 'mx> { + type Value = CValue<'mx>; + type Function = CFunc<'mx>; + type BasicBlock = CFunc<'mx>; + type Type = CTy<'mx>; type Funclet = (); type DIScope = (); type DILocation = (); type DIVariable = (); } -impl<'tcx> HasTargetSpec for CodegenCx<'tcx> { +impl<'tcx, 'mx> HasTargetSpec for CodegenCx<'tcx, 'mx> { fn target_spec(&self) -> &Target { todo!() } } -impl<'tcx> HasParamEnv<'tcx> for CodegenCx<'tcx> { +impl<'tcx, 'mx> HasParamEnv<'tcx> for CodegenCx<'tcx, 'mx> { fn param_env(&self) -> ParamEnv<'tcx> { ParamEnv::reveal_all() } } -impl<'tcx> HasTyCtxt<'tcx> for CodegenCx<'tcx> { +impl<'tcx, 'mx> HasTyCtxt<'tcx> for CodegenCx<'tcx, 'mx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } } -impl HasDataLayout for CodegenCx<'_> { +impl<'tcx, 'mx> HasDataLayout for CodegenCx<'tcx, 'mx> { fn data_layout(&self) -> &TargetDataLayout { todo!() } } -impl<'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'tcx> { +impl<'tcx, 'mx> LayoutOfHelpers<'tcx> for CodegenCx<'tcx, 'mx> { type LayoutOfResult = TyAndLayout<'tcx>; fn handle_layout_err(&self, err: LayoutError<'tcx>, span: rustc_span::Span, ty: Ty<'tcx>) -> ! { @@ -99,7 +89,7 @@ impl<'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'tcx> { } } -impl<'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'tcx> { +impl<'tcx, 'mx> FnAbiOfHelpers<'tcx> for CodegenCx<'tcx, 'mx> { type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>; fn handle_fn_abi_err( @@ -111,50 +101,3 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'tcx> { todo!() } } - -pub struct CFunctionBuilder { - pub name: String, - pub ty: CType, - pub params: Vec<(CType, CValue)>, - pub body: Vec, - pub var_names: FxHashMap, - var_counter: usize, -} - -impl CFunctionBuilder { - pub fn new(name: String, ty: CType, params: Vec) -> Self { - let params: Vec<_> = - params.into_iter().enumerate().map(|(i, ty)| (ty, CValue::Var(i))).collect(); - let var_counter = params.len(); - - Self { name, ty, params, body: Vec::new(), var_counter, var_names: FxHashMap::default() } - } - - pub fn build(self) -> CFunction { - CFunction { - name: self.name, - ty: self.ty, - params: self.params, - body: self.body, - var_names: self.var_names, - } - } - - pub fn decl(&self) -> CDecl { - CDecl::FunctionDecl { - name: self.name.clone(), - ty: self.ty, - params: self.params.iter().map(|(ty, _)| *ty).collect(), - } - } - - pub fn next_value(&mut self) -> CValue { - let val = CValue::Var(self.var_counter); - self.var_counter += 1; - val - } - - pub fn push_stmt(&mut self, stmt: CStmt) { - self.body.push(stmt); - } -} diff --git a/crates/rustc_codegen_c/src/context/asm.rs b/crates/rustc_codegen_c/src/context/asm.rs index 95905ee..768fb9e 100644 --- a/crates/rustc_codegen_c/src/context/asm.rs +++ b/crates/rustc_codegen_c/src/context/asm.rs @@ -3,7 +3,7 @@ use rustc_codegen_ssa::traits::{AsmMethods, GlobalAsmOperandRef}; use crate::context::CodegenCx; -impl<'tcx> AsmMethods<'tcx> for CodegenCx<'tcx> { +impl<'tcx, 'mx> AsmMethods<'tcx> for CodegenCx<'tcx, 'mx> { fn codegen_global_asm( &self, template: &[InlineAsmTemplatePiece], diff --git a/crates/rustc_codegen_c/src/context/base_type.rs b/crates/rustc_codegen_c/src/context/base_type.rs index 9b651f1..8254373 100644 --- a/crates/rustc_codegen_c/src/context/base_type.rs +++ b/crates/rustc_codegen_c/src/context/base_type.rs @@ -2,7 +2,7 @@ use rustc_codegen_ssa::traits::BaseTypeMethods; use crate::context::CodegenCx; -impl<'tcx> BaseTypeMethods<'tcx> for CodegenCx<'tcx> { +impl<'tcx, 'mx> BaseTypeMethods<'tcx> for CodegenCx<'tcx, 'mx> { fn type_i8(&self) -> Self::Type { todo!() } diff --git a/crates/rustc_codegen_c/src/context/const.rs b/crates/rustc_codegen_c/src/context/const.rs index 01d372b..99c868f 100644 --- a/crates/rustc_codegen_c/src/context/const.rs +++ b/crates/rustc_codegen_c/src/context/const.rs @@ -1,10 +1,10 @@ +use rustc_codegen_c_ast::expr::CValue; use rustc_codegen_ssa::traits::ConstMethods; use rustc_const_eval::interpret::{ConstAllocation, Scalar}; use crate::context::CodegenCx; -use crate::module::CValue; -impl<'tcx> ConstMethods<'tcx> for CodegenCx<'tcx> { +impl<'tcx, 'mx> ConstMethods<'tcx> for CodegenCx<'tcx, 'mx> { fn const_null(&self, t: Self::Type) -> Self::Value { todo!() } diff --git a/crates/rustc_codegen_c/src/context/debug_info.rs b/crates/rustc_codegen_c/src/context/debug_info.rs index 4d77ecc..2ee05fc 100644 --- a/crates/rustc_codegen_c/src/context/debug_info.rs +++ b/crates/rustc_codegen_c/src/context/debug_info.rs @@ -6,7 +6,7 @@ use rustc_target::abi::call::FnAbi; use crate::context::CodegenCx; -impl<'tcx> DebugInfoMethods<'tcx> for CodegenCx<'tcx> { +impl<'tcx, 'mx> DebugInfoMethods<'tcx> for CodegenCx<'tcx, 'mx> { fn create_vtable_debuginfo( &self, ty: Ty<'tcx>, diff --git a/crates/rustc_codegen_c/src/context/layout_type.rs b/crates/rustc_codegen_c/src/context/layout_type.rs index 5a20983..fb10c22 100644 --- a/crates/rustc_codegen_c/src/context/layout_type.rs +++ b/crates/rustc_codegen_c/src/context/layout_type.rs @@ -7,7 +7,7 @@ use rustc_type_ir::TyKind; use crate::context::CodegenCx; -impl<'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'tcx> { +impl<'tcx, 'mx> LayoutTypeMethods<'tcx> for CodegenCx<'tcx, 'mx> { fn backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type { todo!() } diff --git a/crates/rustc_codegen_c/src/context/misc.rs b/crates/rustc_codegen_c/src/context/misc.rs index 085523d..9487ed3 100644 --- a/crates/rustc_codegen_c/src/context/misc.rs +++ b/crates/rustc_codegen_c/src/context/misc.rs @@ -7,7 +7,7 @@ use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty}; use crate::context::CodegenCx; -impl<'tcx> MiscMethods<'tcx> for CodegenCx<'tcx> { +impl<'tcx, 'mx> MiscMethods<'tcx> for CodegenCx<'tcx, 'mx> { fn vtables( &self, ) -> &RefCell, Option>), Self::Value>> { diff --git a/crates/rustc_codegen_c/src/context/pre_define.rs b/crates/rustc_codegen_c/src/context/pre_define.rs index 4e53bee..b10c73b 100644 --- a/crates/rustc_codegen_c/src/context/pre_define.rs +++ b/crates/rustc_codegen_c/src/context/pre_define.rs @@ -1,12 +1,14 @@ +use rustc_codegen_c_ast::func::CFuncKind; use rustc_codegen_ssa::traits::{LayoutTypeMethods, PreDefineMethods}; +use rustc_data_structures::intern::Interned; use rustc_hir::def_id::DefId; use rustc_middle::mir::mono::{Linkage, Visibility}; use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::{self, Instance}; -use crate::context::{CFunctionBuilder, CodegenCx}; +use crate::context::CodegenCx; -impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'tcx> { +impl<'tcx, 'mx> PreDefineMethods<'tcx> for CodegenCx<'tcx, 'mx> { fn predefine_static( &self, def_id: DefId, @@ -26,11 +28,12 @@ impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'tcx> { ) { let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); - let args = fn_abi.args.iter().map(|arg| self.immediate_backend_type(arg.layout)).collect(); + let args = fn_abi.args.iter().map(|arg| self.immediate_backend_type(arg.layout)); let ret = self.immediate_backend_type(fn_abi.ret.layout); - let function = CFunctionBuilder::new(symbol_name.to_string(), ret, args); - let function_id = self.functions.borrow_mut().insert(function); - self.function_instances.borrow_mut().insert(instance, function_id); + let func = CFuncKind::new(self.mcx.alloc_str(symbol_name), ret, args); + let func = Interned::new_unchecked(self.mcx.func(func)); + self.mcx.module().push_func(func); + self.function_instances.borrow_mut().insert(instance, func); } } diff --git a/crates/rustc_codegen_c/src/context/static.rs b/crates/rustc_codegen_c/src/context/static.rs index c28f2eb..4110068 100644 --- a/crates/rustc_codegen_c/src/context/static.rs +++ b/crates/rustc_codegen_c/src/context/static.rs @@ -4,7 +4,7 @@ use rustc_hir::def_id::DefId; use crate::context::CodegenCx; -impl<'tcx> StaticMethods for CodegenCx<'tcx> { +impl<'tcx, 'mx> StaticMethods for CodegenCx<'tcx, 'mx> { fn static_addr_of(&self, cv: Self::Value, align: Align, kind: Option<&str>) -> Self::Value { todo!() } diff --git a/crates/rustc_codegen_c/src/context/type_membership.rs b/crates/rustc_codegen_c/src/context/type_membership.rs index cff6dbe..2d6bc53 100644 --- a/crates/rustc_codegen_c/src/context/type_membership.rs +++ b/crates/rustc_codegen_c/src/context/type_membership.rs @@ -2,4 +2,4 @@ use rustc_codegen_ssa::traits::TypeMembershipMethods; use crate::context::CodegenCx; -impl<'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'tcx> {} +impl<'tcx, 'mx> TypeMembershipMethods<'tcx> for CodegenCx<'tcx, 'mx> {} diff --git a/crates/rustc_codegen_c/src/helper.h b/crates/rustc_codegen_c/src/helper.h new file mode 100644 index 0000000..907f233 --- /dev/null +++ b/crates/rustc_codegen_c/src/helper.h @@ -0,0 +1,12 @@ +/* Some helper macros for the generated code */ + +/** Casts an unsigned integer to a signed integer of the same size. + * This is used to avoid UB when do integer casting in Rust. + * + * The parameter `u` is the unsigned type, `s` is the signed type, + * `v` is the value to cast, and `m` is the maximum value of the signed type.\ + * + * example: `__rust_utos(uint32_t, int32_t, x, INT32_MAX)` + */ +#define __rust_utos(u, s, v, m) \ + ((v) <= (m) ? ((s)v) : ((s)((u)(v) - (u)(m) - 1))) diff --git a/crates/rustc_codegen_c/src/lib.rs b/crates/rustc_codegen_c/src/lib.rs index c3afde6..488d805 100644 --- a/crates/rustc_codegen_c/src/lib.rs +++ b/crates/rustc_codegen_c/src/lib.rs @@ -1,6 +1,5 @@ #![feature(rustc_private)] -extern crate parking_lot; extern crate rustc_abi; extern crate rustc_ast; extern crate rustc_codegen_ssa; @@ -17,7 +16,6 @@ extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; extern crate rustc_type_ir; -extern crate sharded_slab; extern crate tracing; use std::sync::Arc; @@ -44,14 +42,10 @@ use rustc_session::config::{OptLevel, OutputFilenames}; use rustc_session::Session; use rustc_span::ErrorGuaranteed; -use crate::module::ModuleContext; - mod archive; mod base; mod builder; mod context; -mod module; -mod utils; mod write; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } @@ -104,7 +98,7 @@ impl CodegenBackend for CCodegen { } fn supports_parallel(&self) -> bool { - false // Maybe true? + false } } @@ -158,7 +152,7 @@ impl ThinBufferMethods for ThinBuffer { } impl WriteBackendMethods for CCodegen { - type Module = ModuleContext; + type Module = String; type TargetMachine = (); type TargetMachineError = (); type ModuleBuffer = ModuleBuffer; diff --git a/crates/rustc_codegen_c/src/module.rs b/crates/rustc_codegen_c/src/module.rs deleted file mode 100644 index d92334d..0000000 --- a/crates/rustc_codegen_c/src/module.rs +++ /dev/null @@ -1,411 +0,0 @@ -//! C Module -//! -//! A module is a in-memory representation of a C file. -//! -//! The structure is derived from clang's AST. - -use std::borrow::Cow; -use std::fmt::{Display, Formatter}; - -use parking_lot::RwLock; -use rustc_hash::FxHashMap; -use rustc_type_ir::{IntTy, UintTy}; - -use crate::utils::sharded_slab::{Entry, Id, ShardedSlab}; - -/// Rust's primitive types -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum PimitiveType { - Int(IntTy), - Uint(UintTy), -} - -pub struct ModuleContext { - types: ShardedSlab, - primitive_types: RwLock>, - pub module: Module, -} - -impl Default for ModuleContext { - fn default() -> Self { - Self::new() - } -} - -impl ModuleContext { - pub fn new() -> Self { - Self { - types: ShardedSlab::default(), - primitive_types: RwLock::new(FxHashMap::default()), - module: Module::new(), - } - } - - /// Get the type - pub fn ty(&self, id: CType) -> Entry { - self.types.get(id).unwrap() - } - - /// Get the type of an signed integer - pub fn get_int_type(&self, int: IntTy) -> CType { - if let Some(ty) = self.primitive_types.read().get(&PimitiveType::Int(int)) { - return *ty; - } - - let tykind = match int { - IntTy::Isize => CTypeKind::Builtin("ssize_t".to_string()), - IntTy::I8 => CTypeKind::Builtin("int8_t".to_string()), - IntTy::I16 => CTypeKind::Builtin("int16_t".to_string()), - IntTy::I32 => CTypeKind::Builtin("int32_t".to_string()), - IntTy::I64 => CTypeKind::Builtin("int64_t".to_string()), - IntTy::I128 => todo!(), - }; - let ty = self.types.insert(tykind); - self.primitive_types - .write() - .insert(PimitiveType::Int(int), ty); - ty - } - - /// Get the type of an unsigned integer - pub fn get_uint_type(&self, uint: UintTy) -> CType { - if let Some(ty) = self.primitive_types.read().get(&PimitiveType::Uint(uint)) { - return *ty; - } - - let tykind = match uint { - UintTy::Usize => CTypeKind::Builtin("size_t".to_string()), - UintTy::U8 => CTypeKind::Builtin("uint8_t".to_string()), - UintTy::U16 => CTypeKind::Builtin("uint16_t".to_string()), - UintTy::U32 => CTypeKind::Builtin("uint32_t".to_string()), - UintTy::U64 => CTypeKind::Builtin("uint64_t".to_string()), - UintTy::U128 => todo!(), - }; - let ty = self.types.insert(tykind); - self.primitive_types - .write() - .insert(PimitiveType::Uint(uint), ty); - ty - } -} - -impl Display for ModuleContext { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - self.module.fmt_with(f, self) - } -} - -pub struct Module { - pub includes: Vec, - pub decls: Vec, -} - -impl Default for Module { - fn default() -> Self { - Self::new() - } -} - -impl Module { - pub fn new() -> Self { - let includes = vec!["stdint.h".to_string()]; - let decls = vec![]; - Self { includes, decls } - } - - pub fn display<'a>(&'a self, ctx: &'a ModuleContext) -> impl Display + 'a { - struct ModuleDisplay<'a>(&'a Module, &'a ModuleContext); - impl<'a> Display for ModuleDisplay<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - self.0.fmt_with(f, self.1) - } - } - ModuleDisplay(self, ctx) - } - - fn fmt_with(&self, f: &mut Formatter<'_>, ctx: &ModuleContext) -> std::fmt::Result { - for include in &self.includes { - writeln!(f, "#include <{}>", include)?; - } - for decl in &self.decls { - writeln!(f, "{}", decl.display(ctx))?; - } - Ok(()) - } -} - -pub enum CDecl { - Typedef { name: String, ty: CType }, - Record { name: String, fields: Vec }, - Field { name: String, ty: CType }, - Enum { name: String, values: Vec }, - FunctionDecl { name: String, ty: CType, params: Vec }, - Function(CFunction), - // Var { name: String, ty: CType, init: Option }, - Raw(String), -} - -impl CDecl { - pub fn display<'a>(&'a self, ctx: &'a ModuleContext) -> impl Display + 'a { - struct CDeclDisplay<'a>(&'a CDecl, &'a ModuleContext); - impl<'a> Display for CDeclDisplay<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - self.0.fmt_with(f, self.1) - } - } - CDeclDisplay(self, ctx) - } - - fn fmt_with(&self, f: &mut Formatter<'_>, ctx: &ModuleContext) -> std::fmt::Result { - match self { - CDecl::Typedef { name, ty } => { - write!(f, "typedef {} {};", name, ctx.ty(*ty).display(ctx)) - } - CDecl::Record { name, fields } => { - writeln!(f, "struct {} {{ ", name)?; - for field in fields { - writeln!(f, "{}", field.display(ctx))?; - } - writeln!(f, "}};") - } - CDecl::Field { name, ty } => write!(f, "{} {}", name, ctx.ty(*ty).display(ctx)), - CDecl::Enum { name, values } => { - writeln!(f, "enum {} {{ ", name)?; - for (i, value) in values.iter().enumerate() { - if i > 0 { - write!(f, ", ")?; - } - writeln!(f, "{}", value)?; - } - writeln!(f, "}};") - } - CDecl::FunctionDecl { name, ty, params } => { - write!(f, "{} {}(", ctx.ty(*ty).display(ctx), name)?; - for (i, param) in params.iter().enumerate() { - if i > 0 { - write!(f, ", ")?; - } - write!(f, "{}", ctx.ty(*param).display(ctx))?; - } - write!(f, ");") - } - CDecl::Function(func) => write!(f, "{}", func.display(ctx)), - // CDecl::Var { name, ty, init } => { - // write!(f, "{} {}", ty, name)?; - // if let Some(init) = init { - // write!(f, " = {}", init)?; - // } - // write!(f, ";") - // } - CDecl::Raw(s) => write!(f, "{}", s), - } - } -} - -pub type CType = Id; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum CTypeKind { - Builtin(String), - Pointer(CType), - Record(String), - Array(CType, usize), -} - -impl CTypeKind { - pub fn display<'a>(&'a self, ctx: &'a ModuleContext) -> impl Display + 'a { - struct DisplayCTypeKind<'a>(&'a CTypeKind, &'a ModuleContext); - impl<'a> Display for DisplayCTypeKind<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - self.0.fmt_with(f, self.1) - } - } - DisplayCTypeKind(self, ctx) - } - - fn fmt_with(&self, f: &mut Formatter<'_>, ctx: &ModuleContext) -> std::fmt::Result { - match self { - CTypeKind::Builtin(ty) => write!(f, "{}", ty), - CTypeKind::Pointer(ty) => write!(f, "{}*", ctx.ty(*ty).display(ctx)), - CTypeKind::Record(ty) => write!(f, "struct {}", ty), - CTypeKind::Array(ty, size) => write!(f, "{}[{}]", ctx.ty(*ty).display(ctx), size), - } - } -} - -pub struct CEnumConstant { - pub name: String, - // pub value: Option, -} - -impl Display for CEnumConstant { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.name)?; - // if let Some(value) = &self.value { - // write!(f, " = {}", value)?; - // } - Ok(()) - } -} - -/// Values of C variable, parameters and scalars -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] -pub enum CValue { - Scalar(i128), - Var(usize), -} - -pub struct CFunction { - pub name: String, - pub ty: CType, - pub params: Vec<(CType, CValue)>, - pub body: Vec, - pub var_names: FxHashMap, -} - -impl CFunction { - pub fn get_var_name(&self, var: CValue) -> Cow { - if let Some(name) = self.var_names.get(&var) { - Cow::Borrowed(name) - } else { - Cow::Owned(match var { - CValue::Scalar(scalar) => format!("{}", scalar), - CValue::Var(index) => format!("_{}", index), - }) - } - } -} - -impl CFunction { - pub fn display<'a>(&'a self, ctx: &'a ModuleContext) -> impl Display + '_ { - struct CFunctionDisplay<'a>(&'a CFunction, &'a ModuleContext); - impl<'a> Display for CFunctionDisplay<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - self.0.fmt_with(f, self.1) - } - } - CFunctionDisplay(self, ctx) - } - - fn fmt_with(&self, f: &mut Formatter<'_>, ctx: &ModuleContext) -> std::fmt::Result { - write!(f, "{} {}(", ctx.ty(self.ty).display(ctx), self.name)?; - for (i, (ty, param)) in self.params.iter().enumerate() { - if i > 0 { - write!(f, ", ")?; - } - write!(f, "{} {}", ctx.ty(*ty).display(ctx), self.get_var_name(*param))?; - } - write!(f, ") {{")?; - for stmt in &self.body { - writeln!(f, "{}", stmt.display(self, ctx))?; - } - write!(f, "}}") - } -} - -pub enum CStmt { - Compound(Vec), - If { cond: Box, then_br: Box, else_br: Option> }, - Return(Option>), - Decl(Box), - Expr(CExpr), -} - -impl CStmt { - pub fn display<'a>(&'a self, fun: &'a CFunction, ctx: &'a ModuleContext) -> impl Display + '_ { - struct CStmtDisplay<'a>(&'a CStmt, &'a CFunction, &'a ModuleContext); - impl<'a> Display for CStmtDisplay<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - self.0.fmt_with(f, self.1, self.2) - } - } - CStmtDisplay(self, fun, ctx) - } - - fn fmt_with( - &self, - f: &mut Formatter<'_>, - fun: &CFunction, - ctx: &ModuleContext, - ) -> std::fmt::Result { - match self { - CStmt::Compound(stmts) => { - writeln!(f, "{{")?; - for stmt in stmts { - writeln!(f, "{}", stmt.display(fun, ctx))?; - } - write!(f, "}}") - } - CStmt::If { cond, then_br: then_, else_br: else_ } => { - writeln!(f, "if ({}) {{", cond.display(fun))?; - writeln!(f, "{}", then_.display(fun, ctx))?; - if let Some(else_) = else_ { - writeln!(f, "}} else {{")?; - writeln!(f, "{}", else_.display(fun, ctx))?; - } - write!(f, "}}") - } - CStmt::Return(expr) => { - write!(f, "return")?; - if let Some(expr) = expr { - write!(f, " {}", expr.display(fun))?; - } - write!(f, ";") - } - CStmt::Decl(decl) => write!(f, "{}", decl.display(ctx)), - CStmt::Expr(expr) => write!(f, "{};", expr.display(fun)), - } - } -} - -pub enum CExpr { - Literal(String), - Value(CValue), - BinaryOperator { lhs: Box, rhs: Box, op: String }, - Call { callee: Box, args: Vec }, - Member { expr: Box, arrow: bool, field: String }, -} - -impl CExpr { - pub fn display<'a>(&'a self, fun: &'a CFunction) -> impl Display + '_ { - struct CExprDisplay<'a>(&'a CExpr, &'a CFunction); - impl<'a> Display for CExprDisplay<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - self.0.fmt_with(f, self.1) - } - } - CExprDisplay(self, fun) - } - - fn fmt_with(&self, f: &mut Formatter<'_>, fun: &CFunction) -> std::fmt::Result { - match self { - CExpr::Literal(lit) => write!(f, "{}", lit), - CExpr::Value(val) => { - let name = fun.get_var_name(*val); - write!(f, "{}", name) - } - CExpr::BinaryOperator { lhs, rhs, op } => { - write!(f, "({} {} {})", lhs.display(fun), op, rhs.display(fun)) - } - CExpr::Call { callee, args } => { - write!(f, "{}(", callee.display(fun))?; - for (i, arg) in args.iter().enumerate() { - if i != 0 { - write!(f, ", ")?; - } - write!(f, "{}", arg.display(fun))?; - } - write!(f, ")") - } - CExpr::Member { expr, arrow, field } => { - write!(f, "{}", expr.display(fun))?; - if *arrow { - write!(f, "->")?; - } else { - write!(f, ".")?; - } - write!(f, "{}", field) - } - } - } -} diff --git a/crates/rustc_codegen_c/src/utils.rs b/crates/rustc_codegen_c/src/utils.rs deleted file mode 100644 index 1005563..0000000 --- a/crates/rustc_codegen_c/src/utils.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod sharded_slab; -pub mod slab; diff --git a/crates/rustc_codegen_c/src/utils/sharded_slab.rs b/crates/rustc_codegen_c/src/utils/sharded_slab.rs deleted file mode 100644 index 5128e89..0000000 --- a/crates/rustc_codegen_c/src/utils/sharded_slab.rs +++ /dev/null @@ -1,28 +0,0 @@ -pub use sharded_slab::Entry; - -pub use crate::utils::slab::Id; - -pub struct ShardedSlab { - inner: sharded_slab::Slab, -} - -impl Default for ShardedSlab { - fn default() -> Self { - Self::new() - } -} - -impl ShardedSlab { - pub fn new() -> Self { - Self { inner: sharded_slab::Slab::new() } - } - - pub fn insert(&self, value: T) -> Id { - let index = self.inner.insert(value).expect("sharded slab is full"); - Id::new(index) - } - - pub fn get(&self, id: Id) -> Option> { - self.inner.get(id.index) - } -} diff --git a/crates/rustc_codegen_c/src/utils/slab.rs b/crates/rustc_codegen_c/src/utils/slab.rs deleted file mode 100644 index 9d4cb2a..0000000 --- a/crates/rustc_codegen_c/src/utils/slab.rs +++ /dev/null @@ -1,92 +0,0 @@ -use std::ops::{Index, IndexMut}; - -pub struct Slab { - data: Vec, -} - -impl Default for Slab { - fn default() -> Self { - Self::new() - } -} - -impl Slab { - pub const fn new() -> Self { - Self { data: Vec::new() } - } - - pub fn insert(&mut self, value: T) -> Id { - let index = self.data.len(); - self.data.push(value); - Id { index, _phantom: std::marker::PhantomData } - } - - pub fn get(&self, id: Id) -> Option<&T> { - self.data.get(id.index) - } - - pub fn iter(&self) -> std::slice::Iter<'_, T> { - self.data.iter() - } -} - -impl IntoIterator for Slab { - type Item = T; - type IntoIter = std::vec::IntoIter; - - fn into_iter(self) -> std::vec::IntoIter { - self.data.into_iter() - } -} - -impl Index> for Slab { - type Output = T; - fn index(&self, id: Id) -> &T { - &self.data[id.index] - } -} - -impl IndexMut> for Slab { - fn index_mut(&mut self, id: Id) -> &mut T { - &mut self.data[id.index] - } -} - -pub struct Id { - pub(super) index: usize, - _phantom: std::marker::PhantomData, -} - -impl Id { - pub(super) fn new(index: usize) -> Self { - Self { index, _phantom: std::marker::PhantomData } - } -} - -impl Copy for Id {} - -impl Clone for Id { - fn clone(&self) -> Self { - *self - } -} - -impl PartialEq for Id { - fn eq(&self, other: &Self) -> bool { - self.index == other.index - } -} - -impl Eq for Id {} - -impl std::fmt::Debug for Id { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.index) - } -} - -impl std::hash::Hash for Id { - fn hash(&self, state: &mut H) { - self.index.hash(state); - } -} diff --git a/crates/rustc_codegen_c/src/write.rs b/crates/rustc_codegen_c/src/write.rs index 79f657f..9358b3f 100644 --- a/crates/rustc_codegen_c/src/write.rs +++ b/crates/rustc_codegen_c/src/write.rs @@ -9,12 +9,10 @@ use rustc_errors::{DiagCtxtHandle, FatalError}; use rustc_session::config::OutputType; use tracing::error; -use crate::module::ModuleContext; - pub(crate) unsafe fn codegen( cgcx: &CodegenContext, _dcx: DiagCtxtHandle<'_>, - module: ModuleCodegen, + module: ModuleCodegen, _config: &ModuleConfig, ) -> Result { let module_name = module.name.clone(); @@ -28,9 +26,9 @@ pub(crate) unsafe fn codegen( write!(&c_out_file, "{}", module.module_llvm).map_err(|_| FatalError)?; // invoke cc to compile - // TODO: configure cc - // TODO: handle long command line (windows) - // TODO: flush_linked_file (windows) + // FIXME: configure cc + // FIXME: handle long command line (windows) + // FIXME: flush_linked_file (windows) let mut cmd = Command::new("clang"); cmd.arg(&c_out).arg("-o").arg(&obj_out).arg("-c"); let mut cmd = cmd.command(); @@ -40,10 +38,7 @@ pub(crate) unsafe fn codegen( .spawn() .and_then(|child| child.wait_with_output()) { - Ok(output) => { - output - // flush_linked_file(&output, out_filename)?; - } + Ok(output) => output, Err(e) => { error!("failed to spawn C compiler: {}", e); return Err(FatalError); @@ -62,7 +57,7 @@ pub(crate) unsafe fn codegen( pub(crate) fn link( _cgcx: &CodegenContext, _dcx: DiagCtxtHandle<'_>, - mut _modules: Vec>, -) -> Result, FatalError> { + mut _modules: Vec>, +) -> Result, FatalError> { unimplemented!(); } diff --git a/example/example.rs b/example/example.rs index 3882f1f..6198e1e 100644 --- a/example/example.rs +++ b/example/example.rs @@ -10,6 +10,6 @@ pub fn main() -> i32 { } #[no_mangle] -pub fn foo(x: u64) -> u64 { - x +pub fn foo(x: u8, _y: u8) -> i64 { + x as i64 } diff --git a/example/mini_core.rs b/example/mini_core.rs index 1a720fe..b93dd93 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -2,10 +2,6 @@ #![no_core] #![allow(internal_features)] -// #[rustc_builtin_macro] -// #[rustc_macro_transparency = "semitransparent"] -// pub macro stringify($($t:tt)*) { /* compiler built-in */ } - #[lang = "sized"] pub trait Sized {} @@ -29,93 +25,6 @@ unsafe impl<'a, T: ?Sized> Copy for &'a T {} unsafe impl Copy for *const T {} unsafe impl Copy for *mut T {} -// #[lang = "add"] -// pub trait Add { -// type Output; - -// #[must_use = "this returns the result of the operation, without modifying the original"] -// fn add(self, rhs: Rhs) -> Self::Output; -// } - -// impl Add for i32 { -// type Output = i32; - -// #[inline] -// fn add(self, other: i32) -> i32 { self + other } -// } - -// #[lang = "panic"] -// #[track_caller] -// pub fn panic(_msg: &'static str) -> ! { -// unsafe { -// libc::puts("Panicking\n\0" as *const str as *const u8); -// intrinsics::abort(); -// } -// } - -// #[lang = "panic_location"] -// #[allow(dead_code)] -// struct PanicLocation { -// file: &'static str, -// line: u32, -// column: u32, -// } - -// macro_rules! panic_const { -// ($($lang:ident = $message:expr,)+) => { -// pub mod panic_const { -// use super::*; - -// $( -// #[track_caller] -// #[lang = stringify!($lang)] -// pub fn $lang() -> ! { -// panic($message); -// } -// )+ -// } -// } -// } - -// panic_const! { -// panic_const_add_overflow = "attempt to add with overflow", -// panic_const_sub_overflow = "attempt to subtract with overflow", -// panic_const_mul_overflow = "attempt to multiply with overflow", -// panic_const_div_overflow = "attempt to divide with overflow", -// panic_const_rem_overflow = "attempt to calculate the remainder with overflow", -// panic_const_neg_overflow = "attempt to negate with overflow", -// panic_const_shr_overflow = "attempt to shift right with overflow", -// panic_const_shl_overflow = "attempt to shift left with overflow", -// panic_const_div_by_zero = "attempt to divide by zero", -// panic_const_rem_by_zero = "attempt to calculate the remainder with a divisor of zero", -// } - -// pub mod intrinsics { -// use crate::Sized; - -// extern "rust-intrinsic" { -// #[rustc_safe_intrinsic] -// pub fn abort() -> !; -// #[rustc_safe_intrinsic] -// pub fn size_of() -> usize; -// pub fn size_of_val(val: *const T) -> usize; -// #[rustc_safe_intrinsic] -// pub fn min_align_of() -> usize; -// pub fn min_align_of_val(val: *const T) -> usize; -// pub fn copy(src: *const T, dst: *mut T, count: usize); -// pub fn transmute(e: T) -> U; -// pub fn ctlz_nonzero(x: T) -> u32; -// #[rustc_safe_intrinsic] -// pub fn needs_drop() -> bool; -// #[rustc_safe_intrinsic] -// pub fn bitreverse(x: T) -> T; -// #[rustc_safe_intrinsic] -// pub fn bswap(x: T) -> T; -// pub fn write_bytes(dst: *mut T, val: u8, count: usize); -// pub fn unreachable() -> !; -// } -// } - pub mod libc { #[link(name = "c")] extern "C" { diff --git a/tests/bless/basic_math.c b/tests/bless/basic_math.c new file mode 100644 index 0000000..eb12df6 --- /dev/null +++ b/tests/bless/basic_math.c @@ -0,0 +1,26 @@ +// file: basic_math.3cfc46df15d2d47-cgu.0.c +#include + +/* Some helper macros for the generated code */ + +/** Casts an unsigned integer to a signed integer of the same size. + * This is used to avoid UB when do integer casting in Rust. + * + * The parameter `u` is the unsigned type, `s` is the signed type, + * `v` is the value to cast, and `m` is the maximum value of the signed type.\ + * + * example: `__rust_utos(uint32_t, int32_t, x, INT32_MAX)` + */ +#define __rust_utos(u, s, v, m) \ + ((v) <= (m) ? ((s)v) : ((s)((u)(v) - (u)(m) - 1))) + +int32_t main(); +int64_t foo(uint8_t _0, uint16_t _1, uint32_t _2); + +int32_t main() { return 0; } + +int64_t foo(uint8_t _0, uint16_t _1, uint32_t _2) +{ + int64_t _3 = __rust_utos(uint64_t, int64_t, (int64_t) _0, INT64_MAX); + return _3; +} From 59cf35c6e0d71f26317b181aae77b6f016a9ccf1 Mon Sep 17 00:00:00 2001 From: Jiayi Zhuang Date: Thu, 12 Sep 2024 15:59:07 +0800 Subject: [PATCH 09/11] feat: setup ci --- .github/workflows/ci.yml | 35 ----------------------------------- 1 file changed, 35 deletions(-) delete mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index e8e14c8..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: CI - -on: - push: - pull_request: - -permissions: - contents: read - -env: - CARGO_TERM_COLOR: always - RUST_BACKTRACE: 1 - -jobs: - test: - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v4 - - # `rustup show` installs from rust-toolchain.toml - - name: Setup rust toolchain - run: rustup show - - - name: Setup rust cache - uses: Swatinem/rust-cache@v2 - - - name: Install packages - run: | - sudo apt-get install llvm-14-tools - - - name: Run tests - run: ./y test - - - name: Check format - run: ./y fmt --check From db427c7a90216c4354ea7d5487c65f84e63c8c9b Mon Sep 17 00:00:00 2001 From: Jiayi Zhuang Date: Sun, 29 Sep 2024 13:18:15 +0800 Subject: [PATCH 10/11] chore: fix eof newline --- .github/workflows/main.yaml | 2 +- README.md | 4 +- bootstrap/src/fmt.rs | 2 +- bootstrap/src/test.rs | 48 ++++++++++---------- example/example.rs => examples/basic_math.rs | 0 {example => tests/auxiliary}/mini_core.rs | 0 tests/codegen/filename.rs | 2 + tests/codegen/params_count.rs | 9 +++- tests/codegen/ret_value.rs | 3 +- 9 files changed, 39 insertions(+), 31 deletions(-) rename example/example.rs => examples/basic_math.rs (100%) rename {example => tests/auxiliary}/mini_core.rs (100%) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 724c389..94ed5ee 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -72,4 +72,4 @@ jobs: steps: # Manually check the status of all dependencies. `if: failure()` does not work. - name: check if any dependency failed - run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' \ No newline at end of file + run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' diff --git a/README.md b/README.md index a370b0a..6d0ed04 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ This code is still highly experimental and not ready for production use. In the root directory of the project, run the following command: ```bash -./y rustc example/example.rs -./build/example +./y rustc examples/basic_math.rs +./build/basic_math ``` The usage of `./y` can be viewed from `./y help`. diff --git a/bootstrap/src/fmt.rs b/bootstrap/src/fmt.rs index e4a1d3b..33553ff 100644 --- a/bootstrap/src/fmt.rs +++ b/bootstrap/src/fmt.rs @@ -23,7 +23,7 @@ impl Run for FmtCommand { .args(["--manifest-path", "crates/Cargo.toml"]) .arg("--all"), ); - for file in glob("example/**/*.rs").unwrap() { + for file in glob("examples/**/*.rs").unwrap() { self.perform(Command::new("rustfmt").args(["--edition", "2021"]).arg(file.unwrap())); } for file in glob("tests/**/*.rs").unwrap() { diff --git a/bootstrap/src/test.rs b/bootstrap/src/test.rs index d99f6f7..770045e 100644 --- a/bootstrap/src/test.rs +++ b/bootstrap/src/test.rs @@ -37,7 +37,7 @@ impl Run for TestCommand { TestType::FileCheck => { cprint!("File checking {}...", testcase.name); testcase.build(manifest); - filechecker.run(&testcase.source, &testcase.output); + filechecker.run(&testcase.source, &testcase.output_file); } TestType::Compile => { cprint!("Compiling {}...", testcase.name); @@ -57,26 +57,22 @@ impl TestCommand { pub fn collect_testcases(&self, manifest: &Manifest) -> Vec { let mut result = vec![]; + // Test auxiliary (should compile first) + for case in glob("tests/auxiliary/*.rs").unwrap() { + let case = case.unwrap(); + let filename = case.file_stem().unwrap(); + let name = format!("auxiliary/{}", filename.to_string_lossy()); + let output_file = manifest.out_dir.join(filename); + result.push(TestCase { name, source: case, output_file, test: TestType::CompileLib }) + } + // Examples - for case in glob("example/*.rs").unwrap() { + for case in glob("examples/*.rs").unwrap() { let case = case.unwrap(); let filename = case.file_stem().unwrap(); - if filename == "mini_core" { - // First compile mini_core - result.insert( - 0, - TestCase { - name: "mini_core".into(), - source: case.clone(), - output: manifest.out_dir.join(Path::new(filename)), - test: TestType::CompileLib, - }, - ); - continue; - } - let name = format!("example/{}", filename.to_string_lossy()); - let output = manifest.out_dir.join("example").join(filename); - result.push(TestCase { name, source: case, output, test: TestType::Compile }) + let name = format!("examples/{}", filename.to_string_lossy()); + let output_file = manifest.out_dir.join("examples").join(filename); + result.push(TestCase { name, source: case, output_file, test: TestType::Compile }) } // Codegen tests @@ -84,8 +80,8 @@ impl TestCommand { let case = case.unwrap(); let filename = case.file_stem().unwrap(); let name = format!("codegen/{}", filename.to_string_lossy()); - let output = manifest.out_dir.join("tests/codegen").join(filename); - result.push(TestCase { name, source: case, output, test: TestType::FileCheck }) + let output_file = manifest.out_dir.join("tests/codegen").join(filename); + result.push(TestCase { name, source: case, output_file, test: TestType::FileCheck }) } result @@ -102,33 +98,35 @@ pub enum TestType { pub struct TestCase { pub name: String, pub source: PathBuf, - pub output: PathBuf, + pub output_file: PathBuf, pub test: TestType, } impl TestCase { pub fn build(&self, manifest: &Manifest) { - std::fs::create_dir_all(self.output.parent().unwrap()).unwrap(); + let output_dir = self.output_file.parent().unwrap(); + std::fs::create_dir_all(output_dir).unwrap(); let mut command = manifest.rustc(); command .args(["--crate-type", "bin"]) .arg("-O") .arg(&self.source) .arg("-o") - .arg(&self.output); + .arg(&self.output_file); log::debug!("running {:?}", command); command.status().unwrap(); } pub fn build_lib(&self, manifest: &Manifest) { - std::fs::create_dir_all(self.output.parent().unwrap()).unwrap(); + let output_dir = self.output_file.parent().unwrap(); + std::fs::create_dir_all(output_dir).unwrap(); let mut command = manifest.rustc(); command .args(["--crate-type", "lib"]) .arg("-O") .arg(&self.source) .arg("--out-dir") - .arg(self.output.parent().unwrap()); + .arg(self.output_file.parent().unwrap()); log::debug!("running {:?}", command); command.status().unwrap(); } diff --git a/example/example.rs b/examples/basic_math.rs similarity index 100% rename from example/example.rs rename to examples/basic_math.rs diff --git a/example/mini_core.rs b/tests/auxiliary/mini_core.rs similarity index 100% rename from example/mini_core.rs rename to tests/auxiliary/mini_core.rs diff --git a/tests/codegen/filename.rs b/tests/codegen/filename.rs index 3a0eef8..5def484 100644 --- a/tests/codegen/filename.rs +++ b/tests/codegen/filename.rs @@ -1,3 +1,5 @@ +//! Test that the generated code has the filename and function name in it + // CHECK: filename #![feature(no_core)] diff --git a/tests/codegen/params_count.rs b/tests/codegen/params_count.rs index 83f9963..f4645c9 100644 --- a/tests/codegen/params_count.rs +++ b/tests/codegen/params_count.rs @@ -1,11 +1,18 @@ +//! Test that the generated code has the right number of parameters + #![feature(no_core)] #![no_core] #![no_main] extern crate mini_core; +// CHECK-LABEL: foo +// CHECK-LABEL: main + // expect three int params -// CHECK: {{((int32_t .*,?\s?){3})}} +// CHECK-LABEL: foo +// CHECK: (int32_t {{[a-zA-Z_][a-zA-Z0-9_]*}}, int32_t {{[a-zA-Z_][a-zA-Z0-9_]*}}, int32_t {{[a-zA-Z_][a-zA-Z0-9_]*}}) +// CHECK: return 0; #[no_mangle] pub fn foo(_x: i32, _y: i32, _z: i32) -> i32 { 0 diff --git a/tests/codegen/ret_value.rs b/tests/codegen/ret_value.rs index 02c0d2e..4b1ebd6 100644 --- a/tests/codegen/ret_value.rs +++ b/tests/codegen/ret_value.rs @@ -1,10 +1,11 @@ +//! Test that we can return a value from a function #![feature(no_core)] #![no_core] #![no_main] extern crate mini_core; -// expect three int params +// CHECK-LABEL: main // CHECK: 42 #[no_mangle] pub fn main() -> i32 { From a4ecb6993ea05340b4d485a9a2786d4be6eb4b05 Mon Sep 17 00:00:00 2001 From: Jiayi Zhuang Date: Tue, 22 Oct 2024 18:44:10 +0800 Subject: [PATCH 11/11] feat: bless test --- bootstrap/Cargo.lock | 20 ++++-- bootstrap/Cargo.toml | 2 + bootstrap/src/test.rs | 132 +++++++++++++++++++++++++--------- examples/basic_math.rs | 2 + tests/bless/basic_math.rs | 17 +++++ tests/codegen/filename.rs | 2 + tests/codegen/params_count.rs | 4 +- tests/codegen/ret_value.rs | 5 +- 8 files changed, 142 insertions(+), 42 deletions(-) create mode 100644 tests/bless/basic_math.rs diff --git a/bootstrap/Cargo.lock b/bootstrap/Cargo.lock index 698bdbd..f32432f 100644 --- a/bootstrap/Cargo.lock +++ b/bootstrap/Cargo.lock @@ -265,9 +265,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -277,9 +277,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", @@ -288,9 +288,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rustix" @@ -305,6 +305,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "similar" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" + [[package]] name = "strsim" version = "0.11.1" @@ -435,5 +441,7 @@ dependencies = [ "env_logger", "glob", "log", + "regex", + "similar", "which", ] diff --git a/bootstrap/Cargo.toml b/bootstrap/Cargo.toml index 3c61ecd..78e4729 100644 --- a/bootstrap/Cargo.toml +++ b/bootstrap/Cargo.toml @@ -10,4 +10,6 @@ color-print = "0.3.6" env_logger = "0.11.5" glob = "0.3.1" log = "0.4.22" +regex = "1.11.1" +similar = "2.6.0" which = "6.0.1" diff --git a/bootstrap/src/test.rs b/bootstrap/src/test.rs index 770045e..90d9d68 100644 --- a/bootstrap/src/test.rs +++ b/bootstrap/src/test.rs @@ -5,6 +5,7 @@ use anstream::{eprint as print, eprintln as println}; use clap::Args; use color_print::{cprint, cprintln}; use glob::glob; +use similar::{ChangeTag, TextDiff}; use which::which; use crate::manifest::Manifest; @@ -12,7 +13,11 @@ use crate::Run; /// Run tests #[derive(Args, Debug)] -pub struct TestCommand {} +pub struct TestCommand { + /// Update the blessed output + #[clap(long)] + pub bless: bool, +} impl Run for TestCommand { fn run(&self, manifest: &Manifest) { @@ -37,7 +42,12 @@ impl Run for TestCommand { TestType::FileCheck => { cprint!("File checking {}...", testcase.name); testcase.build(manifest); - filechecker.run(&testcase.source, &testcase.output_file); + filechecker.run(&testcase); + } + TestType::Bless => { + cprint!("Blessing {}...", testcase.name); + testcase.build(manifest); + bless(self.bless, &testcase); } TestType::Compile => { cprint!("Compiling {}...", testcase.name); @@ -55,16 +65,7 @@ impl Run for TestCommand { impl TestCommand { pub fn collect_testcases(&self, manifest: &Manifest) -> Vec { - let mut result = vec![]; - - // Test auxiliary (should compile first) - for case in glob("tests/auxiliary/*.rs").unwrap() { - let case = case.unwrap(); - let filename = case.file_stem().unwrap(); - let name = format!("auxiliary/{}", filename.to_string_lossy()); - let output_file = manifest.out_dir.join(filename); - result.push(TestCase { name, source: case, output_file, test: TestType::CompileLib }) - } + let mut tests = vec![]; // Examples for case in glob("examples/*.rs").unwrap() { @@ -72,7 +73,7 @@ impl TestCommand { let filename = case.file_stem().unwrap(); let name = format!("examples/{}", filename.to_string_lossy()); let output_file = manifest.out_dir.join("examples").join(filename); - result.push(TestCase { name, source: case, output_file, test: TestType::Compile }) + tests.push(TestCase { name, source: case, output_file, test: TestType::Compile }) } // Codegen tests @@ -81,18 +82,49 @@ impl TestCommand { let filename = case.file_stem().unwrap(); let name = format!("codegen/{}", filename.to_string_lossy()); let output_file = manifest.out_dir.join("tests/codegen").join(filename); - result.push(TestCase { name, source: case, output_file, test: TestType::FileCheck }) + tests.push(TestCase { name, source: case, output_file, test: TestType::FileCheck }) + } + + // Bless tests - the output should be the same as the last run + for case in glob("tests/bless/*.rs").unwrap() { + let case = case.unwrap(); + let filename = case.file_stem().unwrap(); + let name = format!("bless/{}", filename.to_string_lossy()); + let output_file = manifest.out_dir.join("tests/bless").join(filename); + tests.push(TestCase { name, source: case, output_file, test: TestType::Bless }) } - result + // Collect test-auxiliary + let aux_use = regex::Regex::new(r"^//@\s*aux-build:(?P.*)").unwrap(); + let mut auxiliary = vec![]; + for case in tests.iter() { + let source = std::fs::read_to_string(&case.source).unwrap(); + for cap in aux_use.captures_iter(&source) { + let fname = cap.name("fname").unwrap().as_str(); + let source = Path::new("tests/auxiliary").join(fname); + let filename = source.file_stem().unwrap(); + let name = format!("auxiliary/{}", filename.to_string_lossy()); + let output_file = manifest.out_dir.join(filename); // aux files are output to the base directory + auxiliary.push(TestCase { name, source, output_file, test: TestType::CompileLib }) + } + } + + // Compile auxiliary before the tests + let mut cases = auxiliary; + cases.extend(tests); + cases } } pub enum TestType { /// Test an executable can be compiled Compile, + /// Test a library can be compiled CompileLib, + /// Run LLVM FileCheck on the generated code FileCheck, + /// Bless test - the output should be the same as the last run + Bless, } pub struct TestCase { @@ -125,11 +157,27 @@ impl TestCase { .args(["--crate-type", "lib"]) .arg("-O") .arg(&self.source) - .arg("--out-dir") - .arg(self.output_file.parent().unwrap()); + .arg("--out-dir") // we use `--out-dir` to integrate with the default name convention + .arg(output_dir); // so here we ignore the filename and just use the directory log::debug!("running {:?}", command); command.status().unwrap(); } + + /// Get the generated C file f + pub fn generated(&self) -> PathBuf { + let case = self.source.file_stem().unwrap().to_string_lossy(); + let generated = std::fs::read_dir(self.output_file.parent().unwrap()) + .unwrap() + .filter_map(|entry| entry.ok()) + .find(|entry| { + let filename = entry.file_name(); + let filename = filename.to_string_lossy(); + filename.ends_with(".c") && filename.starts_with(case.as_ref()) + }); + + assert!(generated.is_some(), "could not find {case}'s generated file"); + generated.unwrap().path() + } } struct FileChecker { @@ -153,25 +201,41 @@ impl FileChecker { Self { filecheck } } - fn run(&self, source: &Path, output: &Path) { - let case = source.file_stem().unwrap().to_string_lossy(); - let generated = std::fs::read_dir(output.parent().unwrap()) - .unwrap() - .filter_map(|entry| entry.ok()) - .find(|entry| { - let filename = entry.file_name(); - let filename = filename.to_string_lossy(); - filename.ends_with(".c") && filename.starts_with(case.as_ref()) - }); - - assert!(generated.is_some(), "could not find {case}'s generated file"); - let generated = generated.unwrap(); - - let generated = File::open(generated.path()).unwrap(); + fn run(&self, case: &TestCase) { + let generated = File::open(case.generated()).unwrap(); let mut command = std::process::Command::new(&self.filecheck); - command.arg(source).stdin(generated); + command.arg(&case.source).stdin(generated); log::debug!("running {:?}", command); let output = command.output().unwrap(); - assert!(output.status.success(), "failed to run FileCheck on {case}"); + assert!( + output.status.success(), + "failed to run FileCheck on {}", + case.source.file_stem().unwrap().to_string_lossy() + ); + } +} + +fn bless(update: bool, case: &TestCase) { + let output = case.generated(); + let blessed = case.source.with_extension("c"); + if update { + std::fs::copy(output, blessed).unwrap(); + } else { + let output = std::fs::read_to_string(output).unwrap(); + let blessed = std::fs::read_to_string(blessed).unwrap(); + + let diff = TextDiff::from_lines(&blessed, &output); + if diff.ratio() < 1.0 { + cprintln!("output does not match blessed output"); + for change in diff.iter_all_changes() { + let lineno = change.old_index().unwrap_or(change.new_index().unwrap_or(0)); + match change.tag() { + ChangeTag::Equal => print!(" {:4}| {}", lineno, change), + ChangeTag::Insert => cprint!("+{:4}| {}", lineno, change), + ChangeTag::Delete => cprint!("-{:4}| {}", lineno, change), + } + } + std::process::exit(1); + } } } diff --git a/examples/basic_math.rs b/examples/basic_math.rs index 6198e1e..c870300 100644 --- a/examples/basic_math.rs +++ b/examples/basic_math.rs @@ -1,3 +1,5 @@ +//@ aux-build:mini_core.rs + #![feature(no_core)] #![no_core] #![no_main] diff --git a/tests/bless/basic_math.rs b/tests/bless/basic_math.rs new file mode 100644 index 0000000..689b04a --- /dev/null +++ b/tests/bless/basic_math.rs @@ -0,0 +1,17 @@ +//@ aux-build:mini_core.rs + +#![feature(no_core)] +#![no_core] +#![no_main] + +extern crate mini_core; + +#[no_mangle] +pub fn main() -> i32 { + 0 +} + +#[no_mangle] +pub fn foo(x: u8, _y: u16, _z: u32) -> i64 { + x as i64 +} diff --git a/tests/codegen/filename.rs b/tests/codegen/filename.rs index 5def484..0a5d4b9 100644 --- a/tests/codegen/filename.rs +++ b/tests/codegen/filename.rs @@ -1,5 +1,7 @@ //! Test that the generated code has the filename and function name in it +//@ aux-build:mini_core.rs + // CHECK: filename #![feature(no_core)] diff --git a/tests/codegen/params_count.rs b/tests/codegen/params_count.rs index f4645c9..6468ed3 100644 --- a/tests/codegen/params_count.rs +++ b/tests/codegen/params_count.rs @@ -1,5 +1,7 @@ //! Test that the generated code has the right number of parameters +//@ aux-build:mini_core.rs + #![feature(no_core)] #![no_core] #![no_main] @@ -11,7 +13,7 @@ extern crate mini_core; // expect three int params // CHECK-LABEL: foo -// CHECK: (int32_t {{[a-zA-Z_][a-zA-Z0-9_]*}}, int32_t {{[a-zA-Z_][a-zA-Z0-9_]*}}, int32_t {{[a-zA-Z_][a-zA-Z0-9_]*}}) +// CHECK: (int32_t {{[[:alnum:]_]*}}, int32_t {{[[:alnum:]_]*}}, int32_t {{[[:alnum:]_]*}}) // CHECK: return 0; #[no_mangle] pub fn foo(_x: i32, _y: i32, _z: i32) -> i32 { diff --git a/tests/codegen/ret_value.rs b/tests/codegen/ret_value.rs index 4b1ebd6..19ce069 100644 --- a/tests/codegen/ret_value.rs +++ b/tests/codegen/ret_value.rs @@ -1,4 +1,7 @@ //! Test that we can return a value from a function + +//@ aux-build:mini_core.rs + #![feature(no_core)] #![no_core] #![no_main] @@ -6,7 +9,7 @@ extern crate mini_core; // CHECK-LABEL: main -// CHECK: 42 +// CHECK: return 42; #[no_mangle] pub fn main() -> i32 { 42