diff --git a/README.md b/README.md
index 649a0f6..6d0ed04 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,27 @@
C based backend for rustc
+[](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
+
+In the root directory of the project, run the following command:
+
+```bash
+./y rustc examples/basic_math.rs
+./build/basic_math
+```
+
+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
This project is licensed under a dual license: MIT or Apache 2.0.
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/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 476651f..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,12 +42,21 @@ impl Run for TestCommand {
TestType::FileCheck => {
cprint!("File checking {}...", testcase.name);
testcase.build(manifest);
- filechecker.run(&testcase.source, &testcase.output);
+ filechecker.run(&testcase);
+ }
+ TestType::Bless => {
+ cprint!("Blessing {}...", testcase.name);
+ testcase.build(manifest);
+ bless(self.bless, &testcase);
}
TestType::Compile => {
cprint!("Compiling {}...", testcase.name);
testcase.build(manifest);
}
+ TestType::CompileLib => {
+ cprint!("Compiling lib {}...", testcase.name);
+ testcase.build_lib(manifest);
+ }
}
cprintln!("OK");
}
@@ -51,18 +65,15 @@ impl Run for TestCommand {
impl TestCommand {
pub fn collect_testcases(&self, manifest: &Manifest) -> Vec {
- let mut result = vec![];
+ let mut tests = vec![];
// 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" {
- 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);
+ tests.push(TestCase { name, source: case, output_file, test: TestType::Compile })
}
// Codegen tests
@@ -70,39 +81,103 @@ 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);
+ 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 })
+ }
+
+ // 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 })
+ }
}
- result
+ // 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 {
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) {
+ 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") // 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 {
@@ -126,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/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 98d3d36..5a52156 100644
--- a/crates/rustc_codegen_c/Cargo.toml
+++ b/crates/rustc_codegen_c/Cargo.toml
@@ -1,13 +1,14 @@
[package]
name = "rustc_codegen_c"
-version = "0.1.0"
edition = "2021"
+version.workspace = true
[lib]
crate-type = ["dylib"]
[dependencies]
+rustc_codegen_c_ast = { path = "../rustc_codegen_c_ast" }
# 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..bdac635 100644
--- a/crates/rustc_codegen_c/src/base.rs
+++ b/crates/rustc_codegen_c/src/base.rs
@@ -1,9 +1,61 @@
-use rustc_codegen_ssa::ModuleCodegen;
+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;
use rustc_middle::ty::TyCtxt;
+use crate::builder::Builder;
+use crate::context::CodegenCx;
+
+/// 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)
+
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 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);
+ }
+
+ // ... and now that we have everything pre-defined, fill out those definitions.
+ for &(mono_item, _) in &mono_items {
+ mono_item.define::>(&cx);
+ }
+
+ 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
new file mode 100644
index 0000000..a067393
--- /dev/null
+++ b/crates/rustc_codegen_c/src/builder.rs
@@ -0,0 +1,727 @@
+#![allow(unused_variables)] // TODO
+
+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,
+ 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;
+
+/// 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, 'mx> Deref for Builder<'a, 'tcx, 'mx> {
+ type Target = CodegenCx<'tcx, 'mx>;
+
+ fn deref<'b>(&'b self) -> &'a Self::Target {
+ self.cx
+ }
+}
+
+impl<'tcx, 'mx> HasCodegen<'tcx> for Builder<'_, 'tcx, 'mx> {
+ type CodegenCx = CodegenCx<'tcx, 'mx>;
+}
+
+impl<'tcx, 'mx> HasDataLayout for Builder<'_, 'tcx, 'mx> {
+ fn data_layout(&self) -> &TargetDataLayout {
+ todo!()
+ }
+}
+
+impl<'tcx, 'mx> HasTyCtxt<'tcx> for Builder<'_, 'tcx, 'mx> {
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.cx.tcx()
+ }
+}
+
+impl<'tcx, 'mx> HasParamEnv<'tcx> for Builder<'_, 'tcx, 'mx> {
+ fn param_env(&self) -> ParamEnv<'tcx> {
+ self.cx.param_env()
+ }
+}
+
+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;
+}
+
+impl<'tcx, 'mx> HasTargetSpec for Builder<'_, 'tcx, 'mx> {
+ fn target_spec(&self) -> &Target {
+ todo!()
+ }
+}
+
+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>) -> ! {
+ todo!()
+ }
+}
+
+impl<'tcx, 'mx> FnAbiOfHelpers<'tcx> for Builder<'_, 'tcx, 'mx> {
+ 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, 'mx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx, 'mx> {
+ fn build(cx: &'a Self::CodegenCx, llbb: Self::BasicBlock) -> Self {
+ Self { cx, bb: llbb }
+ }
+
+ 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 {
+ // 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 {
+ todo!()
+ }
+
+ fn switch_to_block(&mut self, llbb: Self::BasicBlock) {
+ todo!()
+ }
+
+ fn ret_void(&mut self) {
+ self.bb.0.push_stmt(self.cx.mcx.ret(None));
+ }
+
+ fn ret(&mut self, v: Self::Value) {
+ self.bb.0.push_stmt(self.cx.mcx.ret(Some(self.cx.mcx.value(v))))
+ }
+
+ 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!()
+ }
+
+ /// 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 {
+ 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 {
+ 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..563aa87
--- /dev/null
+++ b/crates/rustc_codegen_c/src/builder/abi.rs
@@ -0,0 +1,38 @@
+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;
+
+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::Local(index)
+ }
+}
+
+impl<'tcx, 'mx> ArgAbiMethods<'tcx> for Builder<'_, 'tcx, 'mx> {
+ 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..a967044
--- /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, 'mx> AsmBuilderMethods<'tcx> for Builder<'_, 'tcx, 'mx> {
+ 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..adabf33
--- /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, 'mx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, 'tcx, 'mx> {
+ 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..374a380
--- /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..de31b4a
--- /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, 'mx> IntrinsicCallMethods<'tcx> for Builder<'_, 'tcx, 'mx> {
+ 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..122048a
--- /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, '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
new file mode 100644
index 0000000..afdfbfc
--- /dev/null
+++ b/crates/rustc_codegen_c/src/context.rs
@@ -0,0 +1,103 @@
+#![allow(unused_variables)] // TODO
+
+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::{
+ FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers,
+ TyAndLayout,
+};
+use rustc_middle::ty::{Instance, ParamEnv, Ty, TyCtxt};
+use rustc_target::abi::call::FnAbi;
+use rustc_target::spec::{HasTargetSpec, Target};
+
+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;
+
+/// Codegen context.
+///
+/// It provides the global context for code generation.
+pub struct CodegenCx<'tcx, 'mx> {
+ /// The type context. See [`TyCtxt`].
+ pub tcx: TyCtxt<'tcx>,
+ /// 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, '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, '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, 'mx> HasTargetSpec for CodegenCx<'tcx, 'mx> {
+ fn target_spec(&self) -> &Target {
+ todo!()
+ }
+}
+
+impl<'tcx, 'mx> HasParamEnv<'tcx> for CodegenCx<'tcx, 'mx> {
+ fn param_env(&self) -> ParamEnv<'tcx> {
+ ParamEnv::reveal_all()
+ }
+}
+
+impl<'tcx, 'mx> HasTyCtxt<'tcx> for CodegenCx<'tcx, 'mx> {
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+}
+
+impl<'tcx, 'mx> HasDataLayout for CodegenCx<'tcx, 'mx> {
+ fn data_layout(&self) -> &TargetDataLayout {
+ todo!()
+ }
+}
+
+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>) -> ! {
+ todo!()
+ }
+}
+
+impl<'tcx, 'mx> FnAbiOfHelpers<'tcx> for CodegenCx<'tcx, 'mx> {
+ 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..768fb9e
--- /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, 'mx> AsmMethods<'tcx> for CodegenCx<'tcx, 'mx> {
+ 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..8254373
--- /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, 'mx> BaseTypeMethods<'tcx> for CodegenCx<'tcx, 'mx> {
+ 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..99c868f
--- /dev/null
+++ b/crates/rustc_codegen_c/src/context/const.rs
@@ -0,0 +1,111 @@
+use rustc_codegen_c_ast::expr::CValue;
+use rustc_codegen_ssa::traits::ConstMethods;
+use rustc_const_eval::interpret::{ConstAllocation, Scalar};
+
+use crate::context::CodegenCx;
+
+impl<'tcx, 'mx> ConstMethods<'tcx> for CodegenCx<'tcx, 'mx> {
+ 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: Scalar,
+ layout: rustc_target::abi::Scalar,
+ llty: Self::Type,
+ ) -> Self::Value {
+ match cv {
+ Scalar::Int(scalar) => CValue::Scalar(scalar.to_int(scalar.size())),
+ Scalar::Ptr(_, _) => 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..2ee05fc
--- /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, 'mx> DebugInfoMethods<'tcx> for CodegenCx<'tcx, 'mx> {
+ 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..fb10c22
--- /dev/null
+++ b/crates/rustc_codegen_c/src/context/layout_type.rs
@@ -0,0 +1,58 @@
+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 rustc_type_ir::TyKind;
+
+use crate::context::CodegenCx;
+
+impl<'tcx, 'mx> LayoutTypeMethods<'tcx> for CodegenCx<'tcx, 'mx> {
+ 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 {
+ 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 {
+ 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..9487ed3
--- /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, 'mx> MiscMethods<'tcx> for CodegenCx<'tcx, 'mx> {
+ fn vtables(
+ &self,
+ ) -> &RefCell, Option>), Self::Value>> {
+ todo!()
+ }
+
+ fn get_fn(&self, instance: Instance<'tcx>) -> Self::Function {
+ *self.function_instances.borrow().get(&instance).unwrap()
+ }
+
+ 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..b10c73b
--- /dev/null
+++ b/crates/rustc_codegen_c/src/context/pre_define.rs
@@ -0,0 +1,39 @@
+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::CodegenCx;
+
+impl<'tcx, 'mx> PreDefineMethods<'tcx> for CodegenCx<'tcx, 'mx> {
+ 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| self.immediate_backend_type(arg.layout));
+ let ret = self.immediate_backend_type(fn_abi.ret.layout);
+
+ 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
new file mode 100644
index 0000000..4110068
--- /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, 'mx> StaticMethods for CodegenCx<'tcx, 'mx> {
+ 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..2d6bc53
--- /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, '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 949b2d7..488d805 100644
--- a/crates/rustc_codegen_c/src/lib.rs
+++ b/crates/rustc_codegen_c/src/lib.rs
@@ -1,15 +1,22 @@
#![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 rustc_type_ir;
+extern crate tracing;
use std::sync::Arc;
@@ -37,7 +44,8 @@ use rustc_span::ErrorGuaranteed;
mod archive;
mod base;
-mod util;
+mod builder;
+mod context;
mod write;
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
@@ -51,7 +59,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(
@@ -88,6 +96,10 @@ impl CodegenBackend for CCodegen {
) -> Result<(), ErrorGuaranteed> {
link_binary(sess, &crate::archive::ArArchiveBuilderBuilder, &codegen_results, outputs)
}
+
+ fn supports_parallel(&self) -> bool {
+ false
+ }
}
impl ExtraBackendMethods for CCodegen {
@@ -140,7 +152,7 @@ impl ThinBufferMethods for ThinBuffer {
}
impl WriteBackendMethods for CCodegen {
- type Module = ();
+ type Module = String;
type TargetMachine = ();
type TargetMachineError = ();
type ModuleBuffer = ModuleBuffer;
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/write.rs b/crates/rustc_codegen_c/src/write.rs
index c4e1195..9358b3f 100644
--- a/crates/rustc_codegen_c/src/write.rs
+++ b/crates/rustc_codegen_c/src/write.rs
@@ -1,20 +1,63 @@
+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;
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
+ // 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();
+ let output = match cmd
+ .stdout(Stdio::piped())
+ .stderr(Stdio::piped())
+ .spawn()
+ .and_then(|child| child.wait_with_output())
+ {
+ Ok(output) => output,
+ 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/examples/basic_math.rs b/examples/basic_math.rs
new file mode 100644
index 0000000..c870300
--- /dev/null
+++ b/examples/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: u8) -> i64 {
+ x as i64
+}
diff --git a/tests/auxiliary/mini_core.rs b/tests/auxiliary/mini_core.rs
new file mode 100644
index 0000000..b93dd93
--- /dev/null
+++ b/tests/auxiliary/mini_core.rs
@@ -0,0 +1,39 @@
+#![feature(no_core, lang_items, rustc_attrs, intrinsics, decl_macro)]
+#![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/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;
+}
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
new file mode 100644
index 0000000..0a5d4b9
--- /dev/null
+++ b/tests/codegen/filename.rs
@@ -0,0 +1,22 @@
+//! Test that the generated code has the filename and function name in it
+
+//@ aux-build:mini_core.rs
+
+// 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() -> i32 {
+ 0
+}
diff --git a/tests/codegen/params_count.rs b/tests/codegen/params_count.rs
new file mode 100644
index 0000000..6468ed3
--- /dev/null
+++ b/tests/codegen/params_count.rs
@@ -0,0 +1,26 @@
+//! Test that the generated code has the right number of parameters
+
+//@ aux-build:mini_core.rs
+
+#![feature(no_core)]
+#![no_core]
+#![no_main]
+
+extern crate mini_core;
+
+// CHECK-LABEL: foo
+// CHECK-LABEL: main
+
+// expect three int params
+// CHECK-LABEL: foo
+// 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 {
+ 0
+}
+
+#[no_mangle]
+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..19ce069
--- /dev/null
+++ b/tests/codegen/ret_value.rs
@@ -0,0 +1,16 @@
+//! Test that we can return a value from a function
+
+//@ aux-build:mini_core.rs
+
+#![feature(no_core)]
+#![no_core]
+#![no_main]
+
+extern crate mini_core;
+
+// CHECK-LABEL: main
+// CHECK: return 42;
+#[no_mangle]
+pub fn main() -> i32 {
+ 42
+}