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