From db3cec4a724dd61e744ec93601f9d1f3c4c8651b Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Wed, 11 Mar 2020 23:53:22 -0400 Subject: [PATCH] Make target configurable It still does nothing even if you configure it lol --- src/data/mod.rs | 3 ++- src/ir/mod.rs | 7 ++++--- src/lex/cpp.rs | 5 +++-- src/lib.rs | 29 ++++++++++++++++++++++++++--- src/main.rs | 5 +++++ src/parse/mod.rs | 13 ++++++------- 6 files changed, 46 insertions(+), 16 deletions(-) diff --git a/src/data/mod.rs b/src/data/mod.rs index 46df98bb..0ea68e07 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -530,6 +530,7 @@ impl TryFrom for Radix { mod tests { use crate::data::lex::test::cpp; use crate::Parser; + use target_lexicon::Triple; #[test] fn type_display() { @@ -545,7 +546,7 @@ mod tests { for ty in types.iter() { let mut lexer = cpp(ty); let first = lexer.next().unwrap().unwrap(); - let mut parser = Parser::new(first, &mut lexer, false); + let mut parser = Parser::new(first, &mut lexer, Triple::host(), false); let parsed_ty = parser.type_name().unwrap().data.0; assert_eq!(&parsed_ty.to_string(), *ty); diff --git a/src/ir/mod.rs b/src/ir/mod.rs index c407d11d..14f741e9 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -48,11 +48,12 @@ struct Compiler { pub(crate) fn compile( module: Module, program: Vec>, + target: Triple, debug: bool, ) -> (Result, CompileError>, VecDeque) { // really we'd like to have all errors but that requires a refactor let mut err = None; - let mut compiler = Compiler::new(module, debug); + let mut compiler = Compiler::new(module, target, debug); for decl in program { let current = match (decl.data.symbol.ctype.clone(), decl.data.init) { (Type::Function(func_type), None) => compiler @@ -91,7 +92,7 @@ pub(crate) fn compile( } impl Compiler { - fn new(module: Module, debug: bool) -> Compiler { + fn new(module: Module, target: Triple, debug: bool) -> Compiler { Compiler { module, scope: Scope::new(), @@ -101,7 +102,7 @@ impl Compiler { // the initial value doesn't really matter last_saw_loop: true, strings: Default::default(), - target: Triple::host(), + target, error_handler: Default::default(), debug, } diff --git a/src/lex/cpp.rs b/src/lex/cpp.rs index 9c58737c..9f66fdcb 100644 --- a/src/lex/cpp.rs +++ b/src/lex/cpp.rs @@ -7,6 +7,7 @@ use std::path::{Path, PathBuf}; use std::rc::Rc; use codespan::FileId; +use target_lexicon::Triple; use super::{Lexer, Token}; use crate::arch::TARGET; @@ -721,7 +722,7 @@ impl<'a> PreProcessor<'a> { fn boolean_expr(&mut self) -> Result { // TODO: is this unwrap safe? there should only be scalar types in a cpp directive... // TODO: should this use the target arch or the host arch? - let target = target_lexicon::Triple::host(); + let target = Triple::host(); match self.cpp_expr()?.truthy().unwrap().constexpr(&target)?.data { (Literal::Int(i), Type::Bool) => Ok(i != 0), _ => unreachable!("bug in const_fold or parser: cpp cond should be boolean"), @@ -843,7 +844,7 @@ impl<'a> PreProcessor<'a> { // TODO: remove(0) is bad and I should feel bad // TODO: this only returns the first error because anything else requires a refactor let first = cpp_tokens.remove(0)?; - let mut parser = crate::Parser::new(first, cpp_tokens.into_iter(), false); + let mut parser = crate::Parser::new(first, cpp_tokens.into_iter(), Triple::host(), false); // TODO: catch expressions that aren't allowed // (see https://github.com/jyn514/rcc/issues/5#issuecomment-575339427) // TODO: can semantic errors happen here? should we check? diff --git a/src/lib.rs b/src/lib.rs index b08f1337..d2516f0d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,7 @@ use cranelift::codegen::settings::{Configurable, Flags}; use cranelift::prelude::isa::TargetIsa; use cranelift_module::{Backend, Module}; use cranelift_object::{ObjectBackend, ObjectBuilder, ObjectTrapCollection}; +use target_lexicon::Triple; /// The `Source` type for `codespan::Files`. /// @@ -81,7 +82,7 @@ impl From> for Error { } } -#[derive(Debug, Default)] +#[derive(Debug)] pub struct Opt { /// If set, print all tokens found by the lexer in addition to compiling. pub debug_lex: bool, @@ -105,6 +106,28 @@ pub struct Opt { /// The directories to consider as part of the search path. pub search_path: Vec, + + /// The target triple to compile to. + /// + /// Defaults to the host target. + pub target: Triple, +} + +// We can't derive(Default) for Opt because Triple::default() is Triple::Unknown :( +impl Default for Opt { + fn default() -> Self { + Opt { + debug_lex: false, + debug_ast: false, + debug_asm: false, + no_link: false, + #[cfg(feature = "jit")] + jit: false, + max_errors: None, + search_path: Vec::new(), + target: Triple::host(), + } + } } /// Preprocess the source and return the tokens. @@ -225,7 +248,7 @@ pub fn compile( }; let mut hir = vec![]; - let mut parser = Parser::new(first, &mut cpp, opt.debug_ast); + let mut parser = Parser::new(first, &mut cpp, opt.target.clone(), opt.debug_ast); for res in &mut parser { match res { Ok(decl) => hir.push(decl), @@ -241,7 +264,7 @@ pub fn compile( if !errs.is_empty() { return (Err(Error::Source(errs)), warnings); } - let (result, ir_warnings) = ir::compile(module, hir, opt.debug_asm); + let (result, ir_warnings) = ir::compile(module, hir, opt.target.clone(), opt.debug_asm); warnings.extend(ir_warnings); (result.map_err(Error::from), warnings) } diff --git a/src/main.rs b/src/main.rs index dc091b47..24947532 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,6 +28,7 @@ use rcc::{ link, preprocess, Error, Files, Opt, }; use std::ffi::OsStr; +use target_lexicon::Triple; use tempfile::NamedTempFile; static ERRORS: AtomicUsize = AtomicUsize::new(0); @@ -60,6 +61,7 @@ OPTIONS: --max-errors The maximum number of errors to allow before giving up. Use 0 to allow unlimited errors. [default: 10] -I, --include Add a directory to the local include path (`#include \"file.h\"`) + --target The target platform to compile to. Allows cross-compilation. ARGS: The file to read C source from. \"-\" means stdin (use ./- to read a file called '-'). @@ -266,6 +268,9 @@ fn parse_args() -> Result<(BinOpt, PathBuf), pico_args::Error> { debug_asm: input.contains("--debug-asm"), debug_ast: input.contains(["-a", "--debug-ast"]), no_link: input.contains(["-c", "--no-link"]), + target: input + .opt_value_from_str("--target")? + .unwrap_or_else(Triple::host), #[cfg(feature = "jit")] jit: input.contains("--jit"), max_errors, diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 8389e82a..eac10a1d 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -92,7 +92,7 @@ where /// I would rather ensure `I` has at least one token, /// but I don't know a good way to do that without requiring users to /// use `std::iter::once`. - pub fn new(first: Locatable, tokens: I, debug: bool) -> Self { + pub fn new(first: Locatable, tokens: I, target: Triple, debug: bool) -> Self { Parser { scope: Default::default(), tag_scope: Default::default(), @@ -103,8 +103,7 @@ where next: None, current_function: None, debug, - // TODO: allow cross-compilation - target: Triple::host(), + target, error_handler: ErrorHandler::new(), recursion_guard: Default::default(), } @@ -405,7 +404,7 @@ pub(crate) mod tests { use crate::lex::PreProcessor as Lexer; pub(crate) use super::expr::tests::parse_expr; - use super::Parser; + use super::{Parser, Triple}; pub(crate) type ParseType = CompileResult>; pub(crate) fn parse(input: &str) -> Option { @@ -467,7 +466,7 @@ pub(crate) mod tests { pub(crate) fn parser(input: &str) -> Parser { let mut lexer = cpp(input); let first = lexer.next().unwrap().unwrap(); - Parser::new(first, lexer, false) + Parser::new(first, lexer, Triple::host(), false) } #[test] fn peek() { @@ -520,7 +519,7 @@ pub(crate) mod tests { first in any::(), tokens in arb_vec_result_locatable_token() ) { - let mut parser = Parser::new(Locatable { data: first, location: Location::default() }, tokens.into_iter(), false); + let mut parser = Parser::new(Locatable { data: first, location: Location::default() }, tokens.into_iter(), Triple::host(), false); let peek = parser.peek_token().cloned(); let next = parser.next_token().map(|l| l.data); @@ -533,7 +532,7 @@ pub(crate) mod tests { first in any::(), tokens in arb_vec_result_locatable_token() ) { - let mut parser = Parser::new(Locatable { data: first, location: Location::default() }, tokens.into_iter(), false); + let mut parser = Parser::new(Locatable { data: first, location: Location::default() }, tokens.into_iter(), Triple::host(), false); let peek = parser.peek_next_token().cloned(); parser.next_token();