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