1 //! Cranelift file reader library. 2 //! 3 //! The `cranelift_reader` library supports reading .clif files. This functionality is needed for 4 //! testing Cranelift, but is not essential for a JIT compiler. 5 6 #![deny( 7 missing_docs, 8 trivial_numeric_casts, 9 unused_extern_crates, 10 unstable_features 11 )] 12 #![warn(unused_import_braces)] 13 14 pub use crate::error::{Location, ParseError, ParseResult}; 15 pub use crate::isaspec::{parse_option, parse_options, IsaSpec, ParseOptionError}; 16 pub use crate::parser::{parse_functions, parse_run_command, parse_test, ParseOptions}; 17 pub use crate::run_command::{Comparison, Invocation, RunCommand}; 18 pub use crate::sourcemap::SourceMap; 19 pub use crate::testcommand::{TestCommand, TestOption}; 20 pub use crate::testfile::{Comment, Details, Feature, TestFile}; 21 22 mod error; 23 mod isaspec; 24 mod lexer; 25 mod parser; 26 mod run_command; 27 mod sourcemap; 28 mod testcommand; 29 mod testfile; 30 31 use anyhow::{Error, Result}; 32 use cranelift_codegen::isa::{self, OwnedTargetIsa}; 33 use cranelift_codegen::settings::{self, FlagsOrIsa}; 34 use std::str::FromStr; 35 use target_lexicon::Triple; 36 37 /// Like `FlagsOrIsa`, but holds ownership. 38 #[allow(missing_docs)] 39 pub enum OwnedFlagsOrIsa { 40 Flags(settings::Flags), 41 Isa(OwnedTargetIsa), 42 } 43 44 impl OwnedFlagsOrIsa { 45 /// Produce a FlagsOrIsa reference. 46 pub fn as_fisa(&self) -> FlagsOrIsa { 47 match *self { 48 Self::Flags(ref flags) => FlagsOrIsa::from(flags), 49 Self::Isa(ref isa) => FlagsOrIsa::from(&**isa), 50 } 51 } 52 } 53 54 /// Parse "set" and "triple" commands. 55 pub fn parse_sets_and_triple(flag_set: &[String], flag_triple: &str) -> Result<OwnedFlagsOrIsa> { 56 let mut flag_builder = settings::builder(); 57 58 // Collect unknown system-wide settings, so we can try to parse them as target specific 59 // settings, if a target is defined. 60 let mut unknown_settings = Vec::new(); 61 for flag in flag_set { 62 match parse_option(flag, &mut flag_builder, Location { line_number: 0 }) { 63 Err(ParseOptionError::UnknownFlag { name, .. }) => { 64 unknown_settings.push(name); 65 } 66 Err(ParseOptionError::UnknownValue { name, value, .. }) => { 67 unknown_settings.push(format!("{}={}", name, value)); 68 } 69 Err(ParseOptionError::Generic(err)) => return Err(err.into()), 70 Ok(()) => {} 71 } 72 } 73 74 let mut words = flag_triple.trim().split_whitespace(); 75 // Look for `target foo`. 76 if let Some(triple_name) = words.next() { 77 let triple = match Triple::from_str(triple_name) { 78 Ok(triple) => triple, 79 Err(parse_error) => return Err(Error::from(parse_error)), 80 }; 81 82 let mut isa_builder = isa::lookup(triple).map_err(|err| match err { 83 isa::LookupError::SupportDisabled => { 84 anyhow::anyhow!("support for triple '{}' is disabled", triple_name) 85 } 86 isa::LookupError::Unsupported => anyhow::anyhow!( 87 "support for triple '{}' is not implemented yet", 88 triple_name 89 ), 90 })?; 91 92 // Try to parse system-wide unknown settings as target-specific settings. 93 parse_options( 94 unknown_settings.iter().map(|x| x.as_str()), 95 &mut isa_builder, 96 Location { line_number: 0 }, 97 ) 98 .map_err(ParseError::from)?; 99 100 // Apply the ISA-specific settings to `isa_builder`. 101 parse_options(words, &mut isa_builder, Location { line_number: 0 }) 102 .map_err(ParseError::from)?; 103 104 Ok(OwnedFlagsOrIsa::Isa( 105 isa_builder.finish(settings::Flags::new(flag_builder))?, 106 )) 107 } else { 108 if !unknown_settings.is_empty() { 109 anyhow::bail!("unknown settings: '{}'", unknown_settings.join("', '")); 110 } 111 Ok(OwnedFlagsOrIsa::Flags(settings::Flags::new(flag_builder))) 112 } 113 } 114