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