Skip to content

Commit cff07cb

Browse files
committed
feat: add basic support for function call
Signed-off-by: xizheyin <[email protected]>
1 parent 97669d6 commit cff07cb

File tree

10 files changed

+356
-38
lines changed

10 files changed

+356
-38
lines changed

bootstrap/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ trait Run {
7777
output
7878
}
7979
// Command ran but did not complete
80-
Ok(output) => panic!("command failed: {output:?}"),
80+
Ok(output) => panic!("command failed: {}", String::from_utf8_lossy(&output.stderr)),
8181
Err(e) => panic!("command failed: {e:?}"),
8282
}
8383
}

bootstrap/src/test.rs

Lines changed: 154 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ impl Run for TestCommand {
5858
self.log_action_context("source", &testcase.source.display());
5959
self.log_action_context("output", &testcase.output_file.display());
6060
testcase.build(manifest);
61-
bless(self.bless, &testcase);
61+
self.bless(self.bless, &testcase);
6262
}
6363
TestType::Compile => {
6464
self.log_action_start("TEST Compile", &testcase.name);
@@ -72,6 +72,13 @@ impl Run for TestCommand {
7272
self.log_action_context("output", &testcase.output_file.display());
7373
testcase.build_lib(manifest);
7474
}
75+
TestType::Runtime => {
76+
self.log_action_start("TEST Runtime", &testcase.name);
77+
self.log_action_context("source", &testcase.source.display());
78+
self.log_action_context("output", &testcase.output_file.display());
79+
testcase.build(manifest);
80+
self.run_and_check_output(&testcase);
81+
}
7582
}
7683
}
7784
}
@@ -84,7 +91,6 @@ impl Run for TestCommand {
8491
impl TestCommand {
8592
pub fn collect_testcases(&self, manifest: &Manifest) -> Vec<TestCase> {
8693
let mut cases = vec![];
87-
8894
let verbose = self.verbose;
8995

9096
// Examples
@@ -117,6 +123,20 @@ impl TestCommand {
117123
cases.push(testcase);
118124
}
119125

126+
// Runtime tests - compile, run and compare output
127+
for case in glob("tests/runit/*.rs").unwrap() {
128+
let case = case.unwrap();
129+
let filename = case.file_stem().unwrap();
130+
// Skip the test runner
131+
if filename == "runner" {
132+
continue;
133+
}
134+
let name = format!("runit/{}", filename.to_string_lossy());
135+
let output_file = manifest.out_dir.join("tests/runit").join(filename);
136+
let testcase = TestCase::new(name, case, output_file, TestType::Runtime, verbose);
137+
cases.push(testcase);
138+
}
139+
120140
// Collect test-auxiliary
121141
let aux_use = regex::Regex::new(r"\s*//@\s*aux-build:(?P<fname>.*)").unwrap();
122142
let mut auxiliaries = vec![];
@@ -145,6 +165,134 @@ impl TestCommand {
145165
testcases.extend(cases);
146166
testcases
147167
}
168+
169+
fn bless(&self, update: bool, case: &TestCase) {
170+
let output = case.generated();
171+
let blessed = case.source.with_extension("c");
172+
173+
self.log_action_context("checking", &blessed.display());
174+
if update {
175+
self.log_action_context("updating", &blessed.display());
176+
std::fs::copy(output, &blessed).unwrap();
177+
self.log_action_context("result", "updated");
178+
} else {
179+
let output = std::fs::read_to_string(output).unwrap();
180+
let blessed = std::fs::read_to_string(&blessed).unwrap();
181+
182+
let diff = TextDiff::from_lines(&blessed, &output);
183+
if diff.ratio() < 1.0 {
184+
cprintln!("<r,s>output does not match blessed output</r,s>");
185+
for change in diff.iter_all_changes() {
186+
let lineno = change.old_index().unwrap_or(change.new_index().unwrap_or(0));
187+
match change.tag() {
188+
ChangeTag::Equal => print!(" {:4}| {}", lineno, change),
189+
ChangeTag::Insert => cprint!("<g>+{:4}| {}</g>", lineno, change),
190+
ChangeTag::Delete => cprint!("<r>-{:4}| {}</r>", lineno, change),
191+
}
192+
}
193+
std::process::exit(1);
194+
}
195+
self.log_action_context("result", "passed");
196+
}
197+
}
198+
199+
/// Run a runtime test and compare its output with the expected output
200+
fn run_and_check_output(&self, testcase: &TestCase) {
201+
// Run the test
202+
self.log_action_context("running", &testcase.output_file.display());
203+
let output = std::process::Command::new(&testcase.output_file)
204+
.output()
205+
.unwrap_or_else(|e| panic!("failed to run {}: {}", testcase.output_file.display(), e));
206+
207+
// Check return value
208+
let actual_return = output.status.code().unwrap_or_else(|| {
209+
panic!("Process terminated by signal: {}", testcase.output_file.display())
210+
});
211+
212+
let expected_return_path = testcase.source.with_extension("ret");
213+
if expected_return_path.exists() {
214+
self.log_action_context("checking return value", &expected_return_path.display());
215+
let expected_return = std::fs::read_to_string(&expected_return_path)
216+
.unwrap_or_else(|e| {
217+
panic!("failed to read {}: {}", expected_return_path.display(), e)
218+
})
219+
.trim()
220+
.parse::<i32>()
221+
.unwrap_or_else(|e| {
222+
panic!("invalid return value in {}: {}", expected_return_path.display(), e)
223+
});
224+
225+
if actual_return != expected_return {
226+
cprintln!("<r,s>return value does not match expected value</r,s>");
227+
cprintln!("expected: {}", expected_return);
228+
cprintln!("actual: {}", actual_return);
229+
std::process::exit(1);
230+
}
231+
self.log_action_context("return value", "passed");
232+
}
233+
234+
// Check stdout
235+
let actual_output = String::from_utf8_lossy(&output.stdout).into_owned();
236+
let expected_output_path = testcase.source.with_extension("out");
237+
238+
if !expected_output_path.exists() {
239+
panic!("expected output file {} does not exist", expected_output_path.display());
240+
}
241+
242+
self.log_action_context("checking stdout", &expected_output_path.display());
243+
let expected_output = std::fs::read_to_string(&expected_output_path)
244+
.unwrap_or_else(|e| panic!("failed to read {}: {}", expected_output_path.display(), e));
245+
246+
let diff = TextDiff::from_lines(&expected_output, &actual_output);
247+
if diff.ratio() < 1.0 {
248+
cprintln!("<r,s>stdout does not match expected output</r,s>");
249+
for change in diff.iter_all_changes() {
250+
let lineno = change.old_index().unwrap_or(change.new_index().unwrap_or(0));
251+
match change.tag() {
252+
ChangeTag::Equal => print!(" {:4}| {}", lineno, change),
253+
ChangeTag::Insert => cprint!("<g>+{:4}| {}</g>", lineno, change),
254+
ChangeTag::Delete => cprint!("<r>-{:4}| {}</r>", lineno, change),
255+
}
256+
}
257+
std::process::exit(1);
258+
}
259+
self.log_action_context("stdout", "passed");
260+
261+
// Check stderr if there's any output
262+
if !output.stderr.is_empty() {
263+
let stderr_str = String::from_utf8_lossy(&output.stderr).into_owned();
264+
let expected_stderr_path = testcase.source.with_extension("err");
265+
266+
if expected_stderr_path.exists() {
267+
self.log_action_context("checking stderr", &expected_stderr_path.display());
268+
let expected_stderr = std::fs::read_to_string(&expected_stderr_path)
269+
.unwrap_or_else(|e| {
270+
panic!("failed to read {}: {}", expected_stderr_path.display(), e)
271+
});
272+
273+
let diff = TextDiff::from_lines(&expected_stderr, &stderr_str);
274+
if diff.ratio() < 1.0 {
275+
cprintln!("<r,s>stderr does not match expected output</r,s>");
276+
for change in diff.iter_all_changes() {
277+
let lineno = change.old_index().unwrap_or(change.new_index().unwrap_or(0));
278+
match change.tag() {
279+
ChangeTag::Equal => print!(" {:4}| {}", lineno, change),
280+
ChangeTag::Insert => cprint!("<g>+{:4}| {}</g>", lineno, change),
281+
ChangeTag::Delete => cprint!("<r>-{:4}| {}</r>", lineno, change),
282+
}
283+
}
284+
std::process::exit(1);
285+
}
286+
self.log_action_context("stderr", "passed");
287+
} else if !stderr_str.trim().is_empty() {
288+
// If there's no .err file but we got stderr output, that's unexpected
289+
cprintln!("<r,s>unexpected stderr output:</r,s>");
290+
cprintln!("{}", stderr_str);
291+
std::process::exit(1);
292+
}
293+
}
294+
self.log_action_context("result", "all checks passed");
295+
}
148296
}
149297

150298
#[derive(Debug)]
@@ -157,14 +305,18 @@ pub enum TestType {
157305
FileCheck,
158306
/// Bless test - the output should be the same as the last run
159307
Bless,
308+
/// Runtime test - compile, run and compare output
309+
Runtime,
160310
}
311+
161312
impl TestType {
162313
pub fn as_str(&self) -> &'static str {
163314
match self {
164315
TestType::Compile => "compile",
165316
TestType::CompileLib => "compile-lib",
166317
TestType::FileCheck => "filecheck",
167318
TestType::Bless => "bless",
319+
TestType::Runtime => "runtime",
168320
}
169321
}
170322
}
@@ -286,28 +438,3 @@ impl FileChecker {
286438
);
287439
}
288440
}
289-
290-
fn bless(update: bool, case: &TestCase) {
291-
let output = case.generated();
292-
let blessed = case.source.with_extension("c");
293-
if update {
294-
std::fs::copy(output, blessed).unwrap();
295-
} else {
296-
let output = std::fs::read_to_string(output).unwrap();
297-
let blessed = std::fs::read_to_string(blessed).unwrap();
298-
299-
let diff = TextDiff::from_lines(&blessed, &output);
300-
if diff.ratio() < 1.0 {
301-
cprintln!("<r,s>output does not match blessed output</r,s>");
302-
for change in diff.iter_all_changes() {
303-
let lineno = change.old_index().unwrap_or(change.new_index().unwrap_or(0));
304-
match change.tag() {
305-
ChangeTag::Equal => print!(" {:4}| {}", lineno, change),
306-
ChangeTag::Insert => cprint!("<g>+{:4}| {}</g>", lineno, change),
307-
ChangeTag::Delete => cprint!("<r>-{:4}| {}</r>", lineno, change),
308-
}
309-
}
310-
std::process::exit(1);
311-
}
312-
}
313-
}

crates/rustc_codegen_c/src/builder.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use std::ops::Deref;
44

55
use rustc_abi::{HasDataLayout, TargetDataLayout};
6+
use rustc_codegen_c_ast::expr::{CExpr, CValue};
67
use rustc_codegen_c_ast::func::CFunc;
78
use rustc_codegen_ssa::traits::{BackendTypes, BuilderMethods, HasCodegen};
89
use rustc_middle::ty::layout::{
@@ -714,7 +715,19 @@ impl<'a, 'tcx, 'mx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx, 'mx> {
714715
funclet: Option<&Self::Funclet>,
715716
instance: Option<rustc_middle::ty::Instance<'tcx>>,
716717
) -> Self::Value {
717-
todo!()
718+
use crate::rustc_codegen_ssa::traits::LayoutTypeMethods;
719+
720+
let fn_abi = fn_abi.unwrap();
721+
let ret_ty = self.cx.immediate_backend_type(fn_abi.ret.layout);
722+
723+
let args = args.iter().map(|v| self.mcx.value(*v)).collect();
724+
725+
let call = self.mcx.call(self.mcx.value(llfn), args);
726+
let ret = self.bb.0.next_local_var();
727+
728+
self.bb.0.push_stmt(self.mcx.decl_stmt(self.mcx.var(ret, ret_ty, Some(call))));
729+
730+
ret
718731
}
719732

720733
fn zext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value {

crates/rustc_codegen_c/src/context/layout_type.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use rustc_abi::Abi;
2+
use rustc_codegen_c_ast::ty::CTy;
23
use rustc_codegen_ssa::traits::LayoutTypeMethods;
34
use rustc_middle::ty::layout::TyAndLayout;
45
use rustc_middle::ty::Ty;
@@ -17,7 +18,7 @@ impl<'tcx, 'mx> LayoutTypeMethods<'tcx> for CodegenCx<'tcx, 'mx> {
1718
}
1819

1920
fn fn_decl_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Type {
20-
todo!()
21+
CTy::Void
2122
}
2223

2324
fn fn_ptr_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Type {

crates/rustc_codegen_c/src/context/misc.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::cell::RefCell;
22

3+
use rustc_codegen_c_ast::expr::CValue;
34
use rustc_codegen_ssa::traits::MiscMethods;
45
use rustc_hash::FxHashMap;
56
use rustc_middle::mir::mono::CodegenUnit;
@@ -19,7 +20,11 @@ impl<'tcx, 'mx> MiscMethods<'tcx> for CodegenCx<'tcx, 'mx> {
1920
}
2021

2122
fn get_fn_addr(&self, instance: Instance<'tcx>) -> Self::Value {
22-
todo!()
23+
let funcs = self.mcx.module().funcs.borrow();
24+
let path = self.tcx.def_path_debug_str(instance.def_id());
25+
let name = path.split("::").last().unwrap();
26+
let func = funcs.iter().find(|f| f.0.name == name).unwrap();
27+
CValue::Func(func.0.name)
2328
}
2429

2530
fn eh_personality(&self) -> Self::Value {

0 commit comments

Comments
 (0)