1 //! Parser for .clif files. 2 3 use crate::error::{Location, ParseError, ParseResult}; 4 use crate::isaspec; 5 use crate::lexer::{LexError, Lexer, LocatedError, LocatedToken, Token}; 6 use crate::run_command::{Comparison, Invocation, RunCommand}; 7 use crate::sourcemap::SourceMap; 8 use crate::testcommand::TestCommand; 9 use crate::testfile::{Comment, Details, Feature, TestFile}; 10 use cranelift_codegen::data_value::DataValue; 11 use cranelift_codegen::entity::EntityRef; 12 use cranelift_codegen::ir; 13 use cranelift_codegen::ir::entities::AnyEntity; 14 use cranelift_codegen::ir::immediates::{Ieee32, Ieee64, Imm64, Offset32, Uimm32, Uimm64}; 15 use cranelift_codegen::ir::instructions::{InstructionData, InstructionFormat, VariableArgs}; 16 use cranelift_codegen::ir::types::INVALID; 17 use cranelift_codegen::ir::types::*; 18 use cranelift_codegen::ir::{ 19 AbiParam, ArgumentExtension, ArgumentLoc, ArgumentPurpose, Block, Constant, ConstantData, 20 ExtFuncData, ExternalName, FuncRef, Function, GlobalValue, GlobalValueData, Heap, HeapData, 21 HeapStyle, JumpTable, JumpTableData, MemFlags, Opcode, SigRef, Signature, StackSlot, 22 StackSlotData, StackSlotKind, Table, TableData, Type, Value, ValueLoc, 23 }; 24 use cranelift_codegen::isa::{self, CallConv, Encoding, RegUnit, TargetIsa}; 25 use cranelift_codegen::packed_option::ReservedValue; 26 use cranelift_codegen::{settings, settings::Configurable, timing}; 27 use smallvec::SmallVec; 28 use std::mem; 29 use std::str::FromStr; 30 use std::{u16, u32}; 31 use target_lexicon::Triple; 32 33 /// After some quick benchmarks a program should never have more than 100,000 blocks. 34 const MAX_BLOCKS_IN_A_FUNCTION: u32 = 100_000; 35 36 /// Parse the entire `text` into a list of functions. 37 /// 38 /// Any test commands or target declarations are ignored. 39 pub fn parse_functions(text: &str) -> ParseResult<Vec<Function>> { 40 let _tt = timing::parse_text(); 41 parse_test(text, ParseOptions::default()) 42 .map(|file| file.functions.into_iter().map(|(func, _)| func).collect()) 43 } 44 45 /// Options for configuring the parsing of filetests. 46 pub struct ParseOptions<'a> { 47 /// Compiler passes to run on the parsed functions. 48 pub passes: Option<&'a [String]>, 49 /// Target ISA for compiling the parsed functions, e.g. "x86_64 skylake". 50 pub target: Option<&'a str>, 51 /// Default calling convention used when none is specified for a parsed function. 52 pub default_calling_convention: CallConv, 53 /// Default for unwind-info setting (enabled or disabled). 54 pub unwind_info: bool, 55 } 56 57 impl Default for ParseOptions<'_> { 58 fn default() -> Self { 59 Self { 60 passes: None, 61 target: None, 62 default_calling_convention: CallConv::Fast, 63 unwind_info: false, 64 } 65 } 66 } 67 68 /// Parse the entire `text` as a test case file. 69 /// 70 /// The returned `TestFile` contains direct references to substrings of `text`. 71 pub fn parse_test<'a>(text: &'a str, options: ParseOptions<'a>) -> ParseResult<TestFile<'a>> { 72 let _tt = timing::parse_text(); 73 let mut parser = Parser::new(text); 74 75 // Gather the preamble comments. 76 parser.start_gathering_comments(); 77 78 let isa_spec: isaspec::IsaSpec; 79 let commands: Vec<TestCommand<'a>>; 80 81 // Check for specified passes and target, if present throw out test commands/targets specified 82 // in file. 83 match options.passes { 84 Some(pass_vec) => { 85 parser.parse_test_commands(); 86 commands = parser.parse_cmdline_passes(pass_vec); 87 parser.parse_target_specs(&options)?; 88 isa_spec = parser.parse_cmdline_target(options.target)?; 89 } 90 None => { 91 commands = parser.parse_test_commands(); 92 isa_spec = parser.parse_target_specs(&options)?; 93 } 94 }; 95 let features = parser.parse_cranelift_features()?; 96 97 #[cfg(feature = "experimental_x64")] 98 { 99 // If the test mentioned that it must run on x86_64, and the experimental_x64 feature is 100 // not present, we might run into parsing errors, because some TargetIsa information is 101 // left unimplemented in the new backend (e.g. register names). 102 // 103 // Users of this function must do some special treatment when the test requires to run on 104 // x86_64 without the experimental_x64 feature, until we switch to using the new x64 105 // backend by default. 106 // 107 // In the meanwhile, return a minimal TestFile containing the features/isa_spec, so the 108 // caller can ignore this. 109 if let isaspec::IsaSpec::Some(ref isas) = isa_spec { 110 if isas.iter().any(|isa| isa.name() == "x64") 111 && !features.contains(&Feature::With("experimental_x64")) 112 { 113 return Ok(TestFile { 114 commands, 115 isa_spec, 116 features, 117 preamble_comments: Vec::new(), 118 functions: Vec::new(), 119 }); 120 } 121 } 122 } 123 124 // Decide between using the calling convention passed in the options or using the 125 // host's calling convention--if any tests are to be run on the host we should default to the 126 // host's calling convention. 127 parser = if commands.iter().any(|tc| tc.command == "run") { 128 let host_default_calling_convention = CallConv::triple_default(&Triple::host()); 129 parser.with_default_calling_convention(host_default_calling_convention) 130 } else { 131 parser.with_default_calling_convention(options.default_calling_convention) 132 }; 133 134 parser.token(); 135 parser.claim_gathered_comments(AnyEntity::Function); 136 137 let preamble_comments = parser.take_comments(); 138 let functions = parser.parse_function_list(isa_spec.unique_isa())?; 139 140 Ok(TestFile { 141 commands, 142 isa_spec, 143 features, 144 preamble_comments, 145 functions, 146 }) 147 } 148 149 /// Parse a CLIF comment `text` as a run command. 150 /// 151 /// Return: 152 /// - `Ok(None)` if the comment is not intended to be a `RunCommand` (i.e. does not start with `run` 153 /// or `print` 154 /// - `Ok(Some(command))` if the comment is intended as a `RunCommand` and can be parsed to one 155 /// - `Err` otherwise. 156 pub fn parse_run_command<'a>(text: &str, signature: &Signature) -> ParseResult<Option<RunCommand>> { 157 let _tt = timing::parse_text(); 158 // We remove leading spaces and semi-colons for convenience here instead of at the call sites 159 // since this function will be attempting to parse a RunCommand from a CLIF comment. 160 let trimmed_text = text.trim_start_matches(|c| c == ' ' || c == ';'); 161 let mut parser = Parser::new(trimmed_text); 162 match parser.token() { 163 Some(Token::Identifier("run")) | Some(Token::Identifier("print")) => { 164 parser.parse_run_command(signature).map(|c| Some(c)) 165 } 166 Some(_) | None => Ok(None), 167 } 168 } 169 170 pub struct Parser<'a> { 171 lex: Lexer<'a>, 172 173 lex_error: Option<LexError>, 174 175 /// Current lookahead token. 176 lookahead: Option<Token<'a>>, 177 178 /// Location of lookahead. 179 loc: Location, 180 181 /// Are we gathering any comments that we encounter? 182 gathering_comments: bool, 183 184 /// The gathered comments; claim them with `claim_gathered_comments`. 185 gathered_comments: Vec<&'a str>, 186 187 /// Comments collected so far. 188 comments: Vec<Comment<'a>>, 189 190 /// Default calling conventions; used when none is specified. 191 default_calling_convention: CallConv, 192 } 193 194 /// Context for resolving references when parsing a single function. 195 struct Context<'a> { 196 function: Function, 197 map: SourceMap, 198 199 /// Aliases to resolve once value definitions are known. 200 aliases: Vec<Value>, 201 202 /// Reference to the unique_isa for things like parsing target-specific instruction encoding 203 /// information. This is only `Some` if exactly one set of `isa` directives were found in the 204 /// prologue (it is valid to have directives for multiple different targets, but in that case 205 /// we couldn't know which target the provided encodings are intended for) 206 unique_isa: Option<&'a dyn TargetIsa>, 207 } 208 209 impl<'a> Context<'a> { 210 fn new(f: Function, unique_isa: Option<&'a dyn TargetIsa>) -> Self { 211 Self { 212 function: f, 213 map: SourceMap::new(), 214 unique_isa, 215 aliases: Vec::new(), 216 } 217 } 218 219 // Get the index of a recipe name if it exists. 220 fn find_recipe_index(&self, recipe_name: &str) -> Option<u16> { 221 if let Some(unique_isa) = self.unique_isa { 222 unique_isa 223 .encoding_info() 224 .names 225 .iter() 226 .position(|&name| name == recipe_name) 227 .map(|idx| idx as u16) 228 } else { 229 None 230 } 231 } 232 233 // Allocate a new stack slot. 234 fn add_ss(&mut self, ss: StackSlot, data: StackSlotData, loc: Location) -> ParseResult<()> { 235 self.map.def_ss(ss, loc)?; 236 while self.function.stack_slots.next_key().index() <= ss.index() { 237 self.function 238 .create_stack_slot(StackSlotData::new(StackSlotKind::SpillSlot, 0)); 239 } 240 self.function.stack_slots[ss] = data; 241 Ok(()) 242 } 243 244 // Resolve a reference to a stack slot. 245 fn check_ss(&self, ss: StackSlot, loc: Location) -> ParseResult<()> { 246 if !self.map.contains_ss(ss) { 247 err!(loc, "undefined stack slot {}", ss) 248 } else { 249 Ok(()) 250 } 251 } 252 253 // Allocate a global value slot. 254 fn add_gv(&mut self, gv: GlobalValue, data: GlobalValueData, loc: Location) -> ParseResult<()> { 255 self.map.def_gv(gv, loc)?; 256 while self.function.global_values.next_key().index() <= gv.index() { 257 self.function.create_global_value(GlobalValueData::Symbol { 258 name: ExternalName::testcase(""), 259 offset: Imm64::new(0), 260 colocated: false, 261 tls: false, 262 }); 263 } 264 self.function.global_values[gv] = data; 265 Ok(()) 266 } 267 268 // Resolve a reference to a global value. 269 fn check_gv(&self, gv: GlobalValue, loc: Location) -> ParseResult<()> { 270 if !self.map.contains_gv(gv) { 271 err!(loc, "undefined global value {}", gv) 272 } else { 273 Ok(()) 274 } 275 } 276 277 // Allocate a heap slot. 278 fn add_heap(&mut self, heap: Heap, data: HeapData, loc: Location) -> ParseResult<()> { 279 self.map.def_heap(heap, loc)?; 280 while self.function.heaps.next_key().index() <= heap.index() { 281 self.function.create_heap(HeapData { 282 base: GlobalValue::reserved_value(), 283 min_size: Uimm64::new(0), 284 offset_guard_size: Uimm64::new(0), 285 style: HeapStyle::Static { 286 bound: Uimm64::new(0), 287 }, 288 index_type: INVALID, 289 }); 290 } 291 self.function.heaps[heap] = data; 292 Ok(()) 293 } 294 295 // Resolve a reference to a heap. 296 fn check_heap(&self, heap: Heap, loc: Location) -> ParseResult<()> { 297 if !self.map.contains_heap(heap) { 298 err!(loc, "undefined heap {}", heap) 299 } else { 300 Ok(()) 301 } 302 } 303 304 // Allocate a table slot. 305 fn add_table(&mut self, table: Table, data: TableData, loc: Location) -> ParseResult<()> { 306 while self.function.tables.next_key().index() <= table.index() { 307 self.function.create_table(TableData { 308 base_gv: GlobalValue::reserved_value(), 309 min_size: Uimm64::new(0), 310 bound_gv: GlobalValue::reserved_value(), 311 element_size: Uimm64::new(0), 312 index_type: INVALID, 313 }); 314 } 315 self.function.tables[table] = data; 316 self.map.def_table(table, loc) 317 } 318 319 // Resolve a reference to a table. 320 fn check_table(&self, table: Table, loc: Location) -> ParseResult<()> { 321 if !self.map.contains_table(table) { 322 err!(loc, "undefined table {}", table) 323 } else { 324 Ok(()) 325 } 326 } 327 328 // Allocate a new signature. 329 fn add_sig( 330 &mut self, 331 sig: SigRef, 332 data: Signature, 333 loc: Location, 334 defaultcc: CallConv, 335 ) -> ParseResult<()> { 336 self.map.def_sig(sig, loc)?; 337 while self.function.dfg.signatures.next_key().index() <= sig.index() { 338 self.function.import_signature(Signature::new(defaultcc)); 339 } 340 self.function.dfg.signatures[sig] = data; 341 Ok(()) 342 } 343 344 // Resolve a reference to a signature. 345 fn check_sig(&self, sig: SigRef, loc: Location) -> ParseResult<()> { 346 if !self.map.contains_sig(sig) { 347 err!(loc, "undefined signature {}", sig) 348 } else { 349 Ok(()) 350 } 351 } 352 353 // Allocate a new external function. 354 fn add_fn(&mut self, fn_: FuncRef, data: ExtFuncData, loc: Location) -> ParseResult<()> { 355 self.map.def_fn(fn_, loc)?; 356 while self.function.dfg.ext_funcs.next_key().index() <= fn_.index() { 357 self.function.import_function(ExtFuncData { 358 name: ExternalName::testcase(""), 359 signature: SigRef::reserved_value(), 360 colocated: false, 361 }); 362 } 363 self.function.dfg.ext_funcs[fn_] = data; 364 Ok(()) 365 } 366 367 // Resolve a reference to a function. 368 fn check_fn(&self, fn_: FuncRef, loc: Location) -> ParseResult<()> { 369 if !self.map.contains_fn(fn_) { 370 err!(loc, "undefined function {}", fn_) 371 } else { 372 Ok(()) 373 } 374 } 375 376 // Allocate a new jump table. 377 fn add_jt(&mut self, jt: JumpTable, data: JumpTableData, loc: Location) -> ParseResult<()> { 378 self.map.def_jt(jt, loc)?; 379 while self.function.jump_tables.next_key().index() <= jt.index() { 380 self.function.create_jump_table(JumpTableData::new()); 381 } 382 self.function.jump_tables[jt] = data; 383 Ok(()) 384 } 385 386 // Resolve a reference to a jump table. 387 fn check_jt(&self, jt: JumpTable, loc: Location) -> ParseResult<()> { 388 if !self.map.contains_jt(jt) { 389 err!(loc, "undefined jump table {}", jt) 390 } else { 391 Ok(()) 392 } 393 } 394 395 // Allocate a new constant. 396 fn add_constant( 397 &mut self, 398 constant: Constant, 399 data: ConstantData, 400 loc: Location, 401 ) -> ParseResult<()> { 402 self.map.def_constant(constant, loc)?; 403 self.function.dfg.constants.set(constant, data); 404 Ok(()) 405 } 406 407 // Configure the stack limit of the current function. 408 fn add_stack_limit(&mut self, limit: GlobalValue, loc: Location) -> ParseResult<()> { 409 if self.function.stack_limit.is_some() { 410 return err!(loc, "stack limit defined twice"); 411 } 412 self.function.stack_limit = Some(limit); 413 Ok(()) 414 } 415 416 // Resolve a reference to a constant. 417 fn check_constant(&self, c: Constant, loc: Location) -> ParseResult<()> { 418 if !self.map.contains_constant(c) { 419 err!(loc, "undefined constant {}", c) 420 } else { 421 Ok(()) 422 } 423 } 424 425 // Allocate a new block. 426 fn add_block(&mut self, block: Block, loc: Location) -> ParseResult<Block> { 427 self.map.def_block(block, loc)?; 428 while self.function.dfg.num_blocks() <= block.index() { 429 self.function.dfg.make_block(); 430 } 431 self.function.layout.append_block(block); 432 Ok(block) 433 } 434 } 435 436 impl<'a> Parser<'a> { 437 /// Create a new `Parser` which reads `text`. The referenced text must outlive the parser. 438 pub fn new(text: &'a str) -> Self { 439 Self { 440 lex: Lexer::new(text), 441 lex_error: None, 442 lookahead: None, 443 loc: Location { line_number: 0 }, 444 gathering_comments: false, 445 gathered_comments: Vec::new(), 446 comments: Vec::new(), 447 default_calling_convention: CallConv::Fast, 448 } 449 } 450 451 /// Modify the default calling convention; returns a new parser with the changed calling 452 /// convention. 453 pub fn with_default_calling_convention(self, default_calling_convention: CallConv) -> Self { 454 Self { 455 default_calling_convention, 456 ..self 457 } 458 } 459 460 // Consume the current lookahead token and return it. 461 fn consume(&mut self) -> Token<'a> { 462 self.lookahead.take().expect("No token to consume") 463 } 464 465 // Consume the whole line following the current lookahead token. 466 // Return the text of the line tail. 467 fn consume_line(&mut self) -> &'a str { 468 let rest = self.lex.rest_of_line(); 469 self.consume(); 470 rest 471 } 472 473 // Get the current lookahead token, after making sure there is one. 474 fn token(&mut self) -> Option<Token<'a>> { 475 // clippy says self.lookahead is immutable so this loop is either infinite or never 476 // running. I don't think this is true - self.lookahead is mutated in the loop body - so 477 // maybe this is a clippy bug? Either way, disable clippy for this. 478 #[cfg_attr(feature = "cargo-clippy", allow(clippy::while_immutable_condition))] 479 while self.lookahead.is_none() { 480 match self.lex.next() { 481 Some(Ok(LocatedToken { token, location })) => { 482 match token { 483 Token::Comment(text) => { 484 if self.gathering_comments { 485 self.gathered_comments.push(text); 486 } 487 } 488 _ => self.lookahead = Some(token), 489 } 490 self.loc = location; 491 } 492 Some(Err(LocatedError { error, location })) => { 493 self.lex_error = Some(error); 494 self.loc = location; 495 break; 496 } 497 None => break, 498 } 499 } 500 self.lookahead 501 } 502 503 // Enable gathering of all comments encountered. 504 fn start_gathering_comments(&mut self) { 505 debug_assert!(!self.gathering_comments); 506 self.gathering_comments = true; 507 debug_assert!(self.gathered_comments.is_empty()); 508 } 509 510 // Claim the comments gathered up to the current position for the 511 // given entity. 512 fn claim_gathered_comments<E: Into<AnyEntity>>(&mut self, entity: E) { 513 debug_assert!(self.gathering_comments); 514 let entity = entity.into(); 515 self.comments.extend( 516 self.gathered_comments 517 .drain(..) 518 .map(|text| Comment { entity, text }), 519 ); 520 self.gathering_comments = false; 521 } 522 523 // Get the comments collected so far, clearing out the internal list. 524 fn take_comments(&mut self) -> Vec<Comment<'a>> { 525 debug_assert!(!self.gathering_comments); 526 mem::replace(&mut self.comments, Vec::new()) 527 } 528 529 // Match and consume a token without payload. 530 fn match_token(&mut self, want: Token<'a>, err_msg: &str) -> ParseResult<Token<'a>> { 531 if self.token() == Some(want) { 532 Ok(self.consume()) 533 } else { 534 err!(self.loc, err_msg) 535 } 536 } 537 538 // If the next token is a `want`, consume it, otherwise do nothing. 539 fn optional(&mut self, want: Token<'a>) -> bool { 540 if self.token() == Some(want) { 541 self.consume(); 542 true 543 } else { 544 false 545 } 546 } 547 548 // Match and consume a specific identifier string. 549 // Used for pseudo-keywords like "stack_slot" that only appear in certain contexts. 550 fn match_identifier(&mut self, want: &'static str, err_msg: &str) -> ParseResult<Token<'a>> { 551 if self.token() == Some(Token::Identifier(want)) { 552 Ok(self.consume()) 553 } else { 554 err!(self.loc, err_msg) 555 } 556 } 557 558 // Match and consume a type. 559 fn match_type(&mut self, err_msg: &str) -> ParseResult<Type> { 560 if let Some(Token::Type(t)) = self.token() { 561 self.consume(); 562 Ok(t) 563 } else { 564 err!(self.loc, err_msg) 565 } 566 } 567 568 // Match and consume a stack slot reference. 569 fn match_ss(&mut self, err_msg: &str) -> ParseResult<StackSlot> { 570 if let Some(Token::StackSlot(ss)) = self.token() { 571 self.consume(); 572 if let Some(ss) = StackSlot::with_number(ss) { 573 return Ok(ss); 574 } 575 } 576 err!(self.loc, err_msg) 577 } 578 579 // Match and consume a global value reference. 580 fn match_gv(&mut self, err_msg: &str) -> ParseResult<GlobalValue> { 581 if let Some(Token::GlobalValue(gv)) = self.token() { 582 self.consume(); 583 if let Some(gv) = GlobalValue::with_number(gv) { 584 return Ok(gv); 585 } 586 } 587 err!(self.loc, err_msg) 588 } 589 590 // Match and consume a function reference. 591 fn match_fn(&mut self, err_msg: &str) -> ParseResult<FuncRef> { 592 if let Some(Token::FuncRef(fnref)) = self.token() { 593 self.consume(); 594 if let Some(fnref) = FuncRef::with_number(fnref) { 595 return Ok(fnref); 596 } 597 } 598 err!(self.loc, err_msg) 599 } 600 601 // Match and consume a signature reference. 602 fn match_sig(&mut self, err_msg: &str) -> ParseResult<SigRef> { 603 if let Some(Token::SigRef(sigref)) = self.token() { 604 self.consume(); 605 if let Some(sigref) = SigRef::with_number(sigref) { 606 return Ok(sigref); 607 } 608 } 609 err!(self.loc, err_msg) 610 } 611 612 // Match and consume a heap reference. 613 fn match_heap(&mut self, err_msg: &str) -> ParseResult<Heap> { 614 if let Some(Token::Heap(heap)) = self.token() { 615 self.consume(); 616 if let Some(heap) = Heap::with_number(heap) { 617 return Ok(heap); 618 } 619 } 620 err!(self.loc, err_msg) 621 } 622 623 // Match and consume a table reference. 624 fn match_table(&mut self, err_msg: &str) -> ParseResult<Table> { 625 if let Some(Token::Table(table)) = self.token() { 626 self.consume(); 627 if let Some(table) = Table::with_number(table) { 628 return Ok(table); 629 } 630 } 631 err!(self.loc, err_msg) 632 } 633 634 // Match and consume a jump table reference. 635 fn match_jt(&mut self) -> ParseResult<JumpTable> { 636 if let Some(Token::JumpTable(jt)) = self.token() { 637 self.consume(); 638 if let Some(jt) = JumpTable::with_number(jt) { 639 return Ok(jt); 640 } 641 } 642 err!(self.loc, "expected jump table number: jt«n»") 643 } 644 645 // Match and consume a constant reference. 646 fn match_constant(&mut self) -> ParseResult<Constant> { 647 if let Some(Token::Constant(c)) = self.token() { 648 self.consume(); 649 if let Some(c) = Constant::with_number(c) { 650 return Ok(c); 651 } 652 } 653 err!(self.loc, "expected constant number: const«n»") 654 } 655 656 // Match and consume a stack limit token 657 fn match_stack_limit(&mut self) -> ParseResult<()> { 658 if let Some(Token::Identifier("stack_limit")) = self.token() { 659 self.consume(); 660 return Ok(()); 661 } 662 err!(self.loc, "expected identifier: stack_limit") 663 } 664 665 // Match and consume a block reference. 666 fn match_block(&mut self, err_msg: &str) -> ParseResult<Block> { 667 if let Some(Token::Block(block)) = self.token() { 668 self.consume(); 669 Ok(block) 670 } else { 671 err!(self.loc, err_msg) 672 } 673 } 674 675 // Match and consume a value reference. 676 fn match_value(&mut self, err_msg: &str) -> ParseResult<Value> { 677 if let Some(Token::Value(v)) = self.token() { 678 self.consume(); 679 Ok(v) 680 } else { 681 err!(self.loc, err_msg) 682 } 683 } 684 685 fn error(&self, message: &str) -> ParseError { 686 ParseError { 687 location: self.loc, 688 message: message.to_string(), 689 is_warning: false, 690 } 691 } 692 693 // Match and consume an Imm64 immediate. 694 fn match_imm64(&mut self, err_msg: &str) -> ParseResult<Imm64> { 695 if let Some(Token::Integer(text)) = self.token() { 696 self.consume(); 697 // Lexer just gives us raw text that looks like an integer. 698 // Parse it as an Imm64 to check for overflow and other issues. 699 text.parse().map_err(|e| self.error(e)) 700 } else { 701 err!(self.loc, err_msg) 702 } 703 } 704 705 // Match and consume a hexadeximal immediate 706 fn match_hexadecimal_constant(&mut self, err_msg: &str) -> ParseResult<ConstantData> { 707 if let Some(Token::Integer(text)) = self.token() { 708 self.consume(); 709 text.parse().map_err(|e| { 710 self.error(&format!( 711 "expected hexadecimal immediate, failed to parse: {}", 712 e 713 )) 714 }) 715 } else { 716 err!(self.loc, err_msg) 717 } 718 } 719 720 // Match and consume a sequence of immediate bytes (uimm8); e.g. [0x42 0x99 0x32] 721 fn match_constant_data(&mut self) -> ParseResult<ConstantData> { 722 self.match_token(Token::LBracket, "expected an opening left bracket")?; 723 let mut data = ConstantData::default(); 724 while !self.optional(Token::RBracket) { 725 data = data.append(self.match_uimm8("expected a sequence of bytes (uimm8)")?); 726 } 727 Ok(data) 728 } 729 730 // Match and consume either a hexadecimal Uimm128 immediate (e.g. 0x000102...) or its literal 731 // list form (e.g. [0 1 2...]). For convenience, since uimm128 values are stored in the 732 // `ConstantPool`, this returns `ConstantData`. 733 fn match_uimm128(&mut self, controlling_type: Type) -> ParseResult<ConstantData> { 734 let expected_size = controlling_type.bytes() as usize; 735 let constant_data = if self.optional(Token::LBracket) { 736 // parse using a list of values, e.g. vconst.i32x4 [0 1 2 3] 737 let uimm128 = self.parse_literals_to_constant_data(controlling_type)?; 738 self.match_token(Token::RBracket, "expected a terminating right bracket")?; 739 uimm128 740 } else { 741 // parse using a hexadecimal value, e.g. 0x000102... 742 let uimm128 = 743 self.match_hexadecimal_constant("expected an immediate hexadecimal operand")?; 744 uimm128.expand_to(expected_size) 745 }; 746 747 if constant_data.len() == expected_size { 748 Ok(constant_data) 749 } else { 750 Err(self.error(&format!( 751 "expected parsed constant to have {} bytes", 752 expected_size 753 ))) 754 } 755 } 756 757 // Match and consume a Uimm64 immediate. 758 fn match_uimm64(&mut self, err_msg: &str) -> ParseResult<Uimm64> { 759 if let Some(Token::Integer(text)) = self.token() { 760 self.consume(); 761 // Lexer just gives us raw text that looks like an integer. 762 // Parse it as an Uimm64 to check for overflow and other issues. 763 text.parse() 764 .map_err(|_| self.error("expected u64 decimal immediate")) 765 } else { 766 err!(self.loc, err_msg) 767 } 768 } 769 770 // Match and consume a Uimm32 immediate. 771 fn match_uimm32(&mut self, err_msg: &str) -> ParseResult<Uimm32> { 772 if let Some(Token::Integer(text)) = self.token() { 773 self.consume(); 774 // Lexer just gives us raw text that looks like an integer. 775 // Parse it as an Uimm32 to check for overflow and other issues. 776 text.parse().map_err(|e| self.error(e)) 777 } else { 778 err!(self.loc, err_msg) 779 } 780 } 781 782 // Match and consume a u8 immediate. 783 // This is used for lane numbers in SIMD vectors. 784 fn match_uimm8(&mut self, err_msg: &str) -> ParseResult<u8> { 785 if let Some(Token::Integer(text)) = self.token() { 786 self.consume(); 787 // Lexer just gives us raw text that looks like an integer. 788 if text.starts_with("0x") { 789 // Parse it as a u8 in hexadecimal form. 790 u8::from_str_radix(&text[2..], 16) 791 .map_err(|_| self.error("unable to parse u8 as a hexadecimal immediate")) 792 } else { 793 // Parse it as a u8 to check for overflow and other issues. 794 text.parse() 795 .map_err(|_| self.error("expected u8 decimal immediate")) 796 } 797 } else { 798 err!(self.loc, err_msg) 799 } 800 } 801 802 // Match and consume an i8 immediate. 803 fn match_imm8(&mut self, err_msg: &str) -> ParseResult<i8> { 804 if let Some(Token::Integer(text)) = self.token() { 805 self.consume(); 806 let negative = text.starts_with('-'); 807 let positive = text.starts_with('+'); 808 let text = if negative || positive { 809 // Strip sign prefix. 810 &text[1..] 811 } else { 812 text 813 }; 814 815 // Parse the text value; the lexer gives us raw text that looks like an integer. 816 let value = if text.starts_with("0x") { 817 // Skip underscores. 818 let text = text.replace("_", ""); 819 // Parse it as a i8 in hexadecimal form. 820 u8::from_str_radix(&text[2..], 16) 821 .map_err(|_| self.error("unable to parse i8 as a hexadecimal immediate"))? 822 } else { 823 // Parse it as a i8 to check for overflow and other issues. 824 text.parse() 825 .map_err(|_| self.error("expected i8 decimal immediate"))? 826 }; 827 828 // Apply sign if necessary. 829 let signed = if negative { 830 let value = value.wrapping_neg() as i8; 831 if value > 0 { 832 return Err(self.error("negative number too small")); 833 } 834 value 835 } else { 836 value as i8 837 }; 838 839 Ok(signed) 840 } else { 841 err!(self.loc, err_msg) 842 } 843 } 844 845 // Match and consume a signed 16-bit immediate. 846 fn match_imm16(&mut self, err_msg: &str) -> ParseResult<i16> { 847 if let Some(Token::Integer(text)) = self.token() { 848 self.consume(); 849 let negative = text.starts_with('-'); 850 let positive = text.starts_with('+'); 851 let text = if negative || positive { 852 // Strip sign prefix. 853 &text[1..] 854 } else { 855 text 856 }; 857 858 // Parse the text value; the lexer gives us raw text that looks like an integer. 859 let value = if text.starts_with("0x") { 860 // Skip underscores. 861 let text = text.replace("_", ""); 862 // Parse it as a i16 in hexadecimal form. 863 u16::from_str_radix(&text[2..], 16) 864 .map_err(|_| self.error("unable to parse i16 as a hexadecimal immediate"))? 865 } else { 866 // Parse it as a i16 to check for overflow and other issues. 867 text.parse() 868 .map_err(|_| self.error("expected i16 decimal immediate"))? 869 }; 870 871 // Apply sign if necessary. 872 let signed = if negative { 873 let value = value.wrapping_neg() as i16; 874 if value > 0 { 875 return Err(self.error("negative number too small")); 876 } 877 value 878 } else { 879 value as i16 880 }; 881 882 Ok(signed) 883 } else { 884 err!(self.loc, err_msg) 885 } 886 } 887 888 // Match and consume an i32 immediate. 889 // This is used for stack argument byte offsets. 890 fn match_imm32(&mut self, err_msg: &str) -> ParseResult<i32> { 891 if let Some(Token::Integer(text)) = self.token() { 892 self.consume(); 893 let negative = text.starts_with('-'); 894 let positive = text.starts_with('+'); 895 let text = if negative || positive { 896 // Strip sign prefix. 897 &text[1..] 898 } else { 899 text 900 }; 901 902 // Parse the text value; the lexer gives us raw text that looks like an integer. 903 let value = if text.starts_with("0x") { 904 // Skip underscores. 905 let text = text.replace("_", ""); 906 // Parse it as a i32 in hexadecimal form. 907 u32::from_str_radix(&text[2..], 16) 908 .map_err(|_| self.error("unable to parse i32 as a hexadecimal immediate"))? 909 } else { 910 // Parse it as a i32 to check for overflow and other issues. 911 text.parse() 912 .map_err(|_| self.error("expected i32 decimal immediate"))? 913 }; 914 915 // Apply sign if necessary. 916 let signed = if negative { 917 let value = value.wrapping_neg() as i32; 918 if value > 0 { 919 return Err(self.error("negative number too small")); 920 } 921 value 922 } else { 923 value as i32 924 }; 925 926 Ok(signed) 927 } else { 928 err!(self.loc, err_msg) 929 } 930 } 931 932 // Match and consume an optional offset32 immediate. 933 // 934 // Note that this will match an empty string as an empty offset, and that if an offset is 935 // present, it must contain a sign. 936 fn optional_offset32(&mut self) -> ParseResult<Offset32> { 937 if let Some(Token::Integer(text)) = self.token() { 938 if text.starts_with('+') || text.starts_with('-') { 939 self.consume(); 940 // Lexer just gives us raw text that looks like an integer. 941 // Parse it as an `Offset32` to check for overflow and other issues. 942 return text.parse().map_err(|e| self.error(e)); 943 } 944 } 945 // An offset32 operand can be absent. 946 Ok(Offset32::new(0)) 947 } 948 949 // Match and consume an optional offset32 immediate. 950 // 951 // Note that this will match an empty string as an empty offset, and that if an offset is 952 // present, it must contain a sign. 953 fn optional_offset_imm64(&mut self) -> ParseResult<Imm64> { 954 if let Some(Token::Integer(text)) = self.token() { 955 if text.starts_with('+') || text.starts_with('-') { 956 self.consume(); 957 // Lexer just gives us raw text that looks like an integer. 958 // Parse it as an `Offset32` to check for overflow and other issues. 959 return text.parse().map_err(|e| self.error(e)); 960 } 961 } 962 // If no explicit offset is present, the offset is 0. 963 Ok(Imm64::new(0)) 964 } 965 966 // Match and consume an Ieee32 immediate. 967 fn match_ieee32(&mut self, err_msg: &str) -> ParseResult<Ieee32> { 968 if let Some(Token::Float(text)) = self.token() { 969 self.consume(); 970 // Lexer just gives us raw text that looks like a float. 971 // Parse it as an Ieee32 to check for the right number of digits and other issues. 972 text.parse().map_err(|e| self.error(e)) 973 } else { 974 err!(self.loc, err_msg) 975 } 976 } 977 978 // Match and consume an Ieee64 immediate. 979 fn match_ieee64(&mut self, err_msg: &str) -> ParseResult<Ieee64> { 980 if let Some(Token::Float(text)) = self.token() { 981 self.consume(); 982 // Lexer just gives us raw text that looks like a float. 983 // Parse it as an Ieee64 to check for the right number of digits and other issues. 984 text.parse().map_err(|e| self.error(e)) 985 } else { 986 err!(self.loc, err_msg) 987 } 988 } 989 990 // Match and consume a boolean immediate. 991 fn match_bool(&mut self, err_msg: &str) -> ParseResult<bool> { 992 if let Some(Token::Identifier(text)) = self.token() { 993 self.consume(); 994 match text { 995 "true" => Ok(true), 996 "false" => Ok(false), 997 _ => err!(self.loc, err_msg), 998 } 999 } else { 1000 err!(self.loc, err_msg) 1001 } 1002 } 1003 1004 // Match and consume an enumerated immediate, like one of the condition codes. 1005 fn match_enum<T: FromStr>(&mut self, err_msg: &str) -> ParseResult<T> { 1006 if let Some(Token::Identifier(text)) = self.token() { 1007 self.consume(); 1008 text.parse().map_err(|_| self.error(err_msg)) 1009 } else { 1010 err!(self.loc, err_msg) 1011 } 1012 } 1013 1014 // Match and a consume a possibly empty sequence of memory operation flags. 1015 fn optional_memflags(&mut self) -> MemFlags { 1016 let mut flags = MemFlags::new(); 1017 while let Some(Token::Identifier(text)) = self.token() { 1018 if flags.set_by_name(text) { 1019 self.consume(); 1020 } else { 1021 break; 1022 } 1023 } 1024 flags 1025 } 1026 1027 // Match and consume an identifier. 1028 fn match_any_identifier(&mut self, err_msg: &str) -> ParseResult<&'a str> { 1029 if let Some(Token::Identifier(text)) = self.token() { 1030 self.consume(); 1031 Ok(text) 1032 } else { 1033 err!(self.loc, err_msg) 1034 } 1035 } 1036 1037 // Match and consume a HexSequence that fits into a u16. 1038 // This is used for instruction encodings. 1039 fn match_hex16(&mut self, err_msg: &str) -> ParseResult<u16> { 1040 if let Some(Token::HexSequence(bits_str)) = self.token() { 1041 self.consume(); 1042 // The only error we anticipate from this parse is overflow, the lexer should 1043 // already have ensured that the string doesn't contain invalid characters, and 1044 // isn't empty or negative. 1045 u16::from_str_radix(bits_str, 16) 1046 .map_err(|_| self.error("the hex sequence given overflows the u16 type")) 1047 } else { 1048 err!(self.loc, err_msg) 1049 } 1050 } 1051 1052 // Match and consume a register unit either by number `%15` or by name `%rax`. 1053 fn match_regunit(&mut self, isa: Option<&dyn TargetIsa>) -> ParseResult<RegUnit> { 1054 if let Some(Token::Name(name)) = self.token() { 1055 self.consume(); 1056 match isa { 1057 Some(isa) => isa 1058 .register_info() 1059 .parse_regunit(name) 1060 .ok_or_else(|| self.error("invalid register name")), 1061 None => name 1062 .parse() 1063 .map_err(|_| self.error("invalid register number")), 1064 } 1065 } else { 1066 match isa { 1067 Some(isa) => err!(self.loc, "Expected {} register unit", isa.name()), 1068 None => err!(self.loc, "Expected register unit number"), 1069 } 1070 } 1071 } 1072 1073 /// Parse an optional source location. 1074 /// 1075 /// Return an optional source location if no real location is present. 1076 fn optional_srcloc(&mut self) -> ParseResult<ir::SourceLoc> { 1077 if let Some(Token::SourceLoc(text)) = self.token() { 1078 match u32::from_str_radix(text, 16) { 1079 Ok(num) => { 1080 self.consume(); 1081 Ok(ir::SourceLoc::new(num)) 1082 } 1083 Err(_) => return err!(self.loc, "invalid source location: {}", text), 1084 } 1085 } else { 1086 Ok(Default::default()) 1087 } 1088 } 1089 1090 /// Parse a list of literals (i.e. integers, floats, booleans); e.g. `0 1 2 3`, usually as 1091 /// part of something like `vconst.i32x4 [0 1 2 3]`. 1092 fn parse_literals_to_constant_data(&mut self, ty: Type) -> ParseResult<ConstantData> { 1093 macro_rules! consume { 1094 ( $ty:ident, $match_fn:expr ) => {{ 1095 assert!($ty.is_vector()); 1096 let mut data = ConstantData::default(); 1097 for _ in 0..$ty.lane_count() { 1098 data = data.append($match_fn); 1099 } 1100 data 1101 }}; 1102 } 1103 1104 fn boolean_to_vec(value: bool, ty: Type) -> Vec<u8> { 1105 let lane_size = ty.bytes() / u32::from(ty.lane_count()); 1106 if lane_size < 1 { 1107 panic!("The boolean lane must have a byte size greater than zero."); 1108 } 1109 let value = if value { 0xFF } else { 0 }; 1110 vec![value; lane_size as usize] 1111 } 1112 1113 if !ty.is_vector() { 1114 err!(self.loc, "Expected a controlling vector type, not {}", ty) 1115 } else { 1116 let constant_data = match ty.lane_type() { 1117 I8 => consume!(ty, self.match_uimm8("Expected an 8-bit unsigned integer")?), 1118 I16 => consume!(ty, self.match_imm16("Expected a 16-bit integer")?), 1119 I32 => consume!(ty, self.match_imm32("Expected a 32-bit integer")?), 1120 I64 => consume!(ty, self.match_imm64("Expected a 64-bit integer")?), 1121 F32 => consume!(ty, self.match_ieee32("Expected a 32-bit float")?), 1122 F64 => consume!(ty, self.match_ieee64("Expected a 64-bit float")?), 1123 b if b.is_bool() => consume!( 1124 ty, 1125 boolean_to_vec(self.match_bool("Expected a boolean")?, ty) 1126 ), 1127 _ => return err!(self.loc, "Expected a type of: float, int, bool"), 1128 }; 1129 Ok(constant_data) 1130 } 1131 } 1132 1133 /// Parse a list of test command passes specified in command line. 1134 pub fn parse_cmdline_passes(&mut self, passes: &'a [String]) -> Vec<TestCommand<'a>> { 1135 let mut list = Vec::new(); 1136 for pass in passes { 1137 list.push(TestCommand::new(pass)); 1138 } 1139 list 1140 } 1141 1142 /// Parse a list of test commands. 1143 pub fn parse_test_commands(&mut self) -> Vec<TestCommand<'a>> { 1144 let mut list = Vec::new(); 1145 while self.token() == Some(Token::Identifier("test")) { 1146 list.push(TestCommand::new(self.consume_line())); 1147 } 1148 list 1149 } 1150 1151 /// Parse a target spec. 1152 /// 1153 /// Accept the target from the command line for pass command. 1154 /// 1155 fn parse_cmdline_target(&mut self, target_pass: Option<&str>) -> ParseResult<isaspec::IsaSpec> { 1156 // Were there any `target` commands specified? 1157 let mut specified_target = false; 1158 1159 let mut targets = Vec::new(); 1160 let flag_builder = settings::builder(); 1161 1162 if let Some(targ) = target_pass { 1163 let loc = self.loc; 1164 let triple = match Triple::from_str(targ) { 1165 Ok(triple) => triple, 1166 Err(err) => return err!(loc, err), 1167 }; 1168 let isa_builder = match isa::lookup(triple) { 1169 Err(isa::LookupError::SupportDisabled) => { 1170 return err!(loc, "support disabled target '{}'", targ); 1171 } 1172 Err(isa::LookupError::Unsupported) => { 1173 return warn!(loc, "unsupported target '{}'", targ); 1174 } 1175 Ok(b) => b, 1176 }; 1177 specified_target = true; 1178 1179 // Construct a trait object with the aggregate settings. 1180 targets.push(isa_builder.finish(settings::Flags::new(flag_builder.clone()))); 1181 } 1182 1183 if !specified_target { 1184 // No `target` commands. 1185 Ok(isaspec::IsaSpec::None(settings::Flags::new(flag_builder))) 1186 } else { 1187 Ok(isaspec::IsaSpec::Some(targets)) 1188 } 1189 } 1190 1191 /// Parse a list of target specs. 1192 /// 1193 /// Accept a mix of `target` and `set` command lines. The `set` commands are cumulative. 1194 /// 1195 fn parse_target_specs(&mut self, options: &ParseOptions) -> ParseResult<isaspec::IsaSpec> { 1196 // Were there any `target` commands? 1197 let mut seen_target = false; 1198 // Location of last `set` command since the last `target`. 1199 let mut last_set_loc = None; 1200 1201 let mut targets = Vec::new(); 1202 let mut flag_builder = settings::builder(); 1203 1204 let unwind_info = if options.unwind_info { "true" } else { "false" }; 1205 flag_builder 1206 .set("unwind_info", unwind_info) 1207 .expect("unwind_info option should be present"); 1208 1209 while let Some(Token::Identifier(command)) = self.token() { 1210 match command { 1211 "set" => { 1212 last_set_loc = Some(self.loc); 1213 isaspec::parse_options( 1214 self.consume_line().trim().split_whitespace(), 1215 &mut flag_builder, 1216 self.loc, 1217 ) 1218 .map_err(|err| ParseError::from(err))?; 1219 } 1220 "target" => { 1221 let loc = self.loc; 1222 // Grab the whole line so the lexer won't go looking for tokens on the 1223 // following lines. 1224 let mut words = self.consume_line().trim().split_whitespace(); 1225 // Look for `target foo`. 1226 let target_name = match words.next() { 1227 Some(w) => w, 1228 None => return err!(loc, "expected target triple"), 1229 }; 1230 let triple = match Triple::from_str(target_name) { 1231 Ok(triple) => triple, 1232 Err(err) => return err!(loc, err), 1233 }; 1234 let mut isa_builder = match isa::lookup(triple) { 1235 Err(isa::LookupError::SupportDisabled) => { 1236 continue; 1237 } 1238 Err(isa::LookupError::Unsupported) => { 1239 return warn!(loc, "unsupported target '{}'", target_name); 1240 } 1241 Ok(b) => b, 1242 }; 1243 last_set_loc = None; 1244 seen_target = true; 1245 // Apply the target-specific settings to `isa_builder`. 1246 isaspec::parse_options(words, &mut isa_builder, self.loc)?; 1247 1248 // Construct a trait object with the aggregate settings. 1249 targets.push(isa_builder.finish(settings::Flags::new(flag_builder.clone()))); 1250 } 1251 _ => break, 1252 } 1253 } 1254 1255 if !seen_target { 1256 // No `target` commands, but we allow for `set` commands. 1257 Ok(isaspec::IsaSpec::None(settings::Flags::new(flag_builder))) 1258 } else if let Some(loc) = last_set_loc { 1259 err!( 1260 loc, 1261 "dangling 'set' command after ISA specification has no effect." 1262 ) 1263 } else { 1264 Ok(isaspec::IsaSpec::Some(targets)) 1265 } 1266 } 1267 1268 /// Parse a list of expected features that Cranelift should be compiled with, or without. 1269 pub fn parse_cranelift_features(&mut self) -> ParseResult<Vec<Feature<'a>>> { 1270 let mut list = Vec::new(); 1271 while self.token() == Some(Token::Identifier("feature")) { 1272 self.consume(); 1273 let has = !self.optional(Token::Not); 1274 match (self.token(), has) { 1275 (Some(Token::String(flag)), true) => list.push(Feature::With(flag)), 1276 (Some(Token::String(flag)), false) => list.push(Feature::Without(flag)), 1277 (tok, _) => { 1278 return err!( 1279 self.loc, 1280 format!("Expected feature flag string, got {:?}", tok) 1281 ) 1282 } 1283 } 1284 self.consume(); 1285 } 1286 Ok(list) 1287 } 1288 1289 /// Parse a list of function definitions. 1290 /// 1291 /// This is the top-level parse function matching the whole contents of a file. 1292 pub fn parse_function_list( 1293 &mut self, 1294 unique_isa: Option<&dyn TargetIsa>, 1295 ) -> ParseResult<Vec<(Function, Details<'a>)>> { 1296 let mut list = Vec::new(); 1297 while self.token().is_some() { 1298 list.push(self.parse_function(unique_isa)?); 1299 } 1300 if let Some(err) = self.lex_error { 1301 return match err { 1302 LexError::InvalidChar => err!(self.loc, "invalid character"), 1303 }; 1304 } 1305 Ok(list) 1306 } 1307 1308 // Parse a whole function definition. 1309 // 1310 // function ::= * "function" name signature "{" preamble function-body "}" 1311 // 1312 fn parse_function( 1313 &mut self, 1314 unique_isa: Option<&dyn TargetIsa>, 1315 ) -> ParseResult<(Function, Details<'a>)> { 1316 // Begin gathering comments. 1317 // Make sure we don't include any comments before the `function` keyword. 1318 self.token(); 1319 debug_assert!(self.comments.is_empty()); 1320 self.start_gathering_comments(); 1321 1322 self.match_identifier("function", "expected 'function'")?; 1323 1324 let location = self.loc; 1325 1326 // function ::= "function" * name signature "{" preamble function-body "}" 1327 let name = self.parse_external_name()?; 1328 1329 // function ::= "function" name * signature "{" preamble function-body "}" 1330 let sig = self.parse_signature(unique_isa)?; 1331 1332 let mut ctx = Context::new(Function::with_name_signature(name, sig), unique_isa); 1333 1334 // function ::= "function" name signature * "{" preamble function-body "}" 1335 self.match_token(Token::LBrace, "expected '{' before function body")?; 1336 1337 self.token(); 1338 self.claim_gathered_comments(AnyEntity::Function); 1339 1340 // function ::= "function" name signature "{" * preamble function-body "}" 1341 self.parse_preamble(&mut ctx)?; 1342 // function ::= "function" name signature "{" preamble * function-body "}" 1343 self.parse_function_body(&mut ctx)?; 1344 // function ::= "function" name signature "{" preamble function-body * "}" 1345 self.match_token(Token::RBrace, "expected '}' after function body")?; 1346 1347 // Collect any comments following the end of the function, then stop gathering comments. 1348 self.start_gathering_comments(); 1349 self.token(); 1350 self.claim_gathered_comments(AnyEntity::Function); 1351 1352 let details = Details { 1353 location, 1354 comments: self.take_comments(), 1355 map: ctx.map, 1356 }; 1357 1358 Ok((ctx.function, details)) 1359 } 1360 1361 // Parse an external name. 1362 // 1363 // For example, in a function decl, the parser would be in this state: 1364 // 1365 // function ::= "function" * name signature { ... } 1366 // 1367 fn parse_external_name(&mut self) -> ParseResult<ExternalName> { 1368 match self.token() { 1369 Some(Token::Name(s)) => { 1370 self.consume(); 1371 s.parse() 1372 .map_err(|_| self.error("invalid test case or libcall name")) 1373 } 1374 Some(Token::UserRef(namespace)) => { 1375 self.consume(); 1376 match self.token() { 1377 Some(Token::Colon) => { 1378 self.consume(); 1379 match self.token() { 1380 Some(Token::Integer(index_str)) => { 1381 let index: u32 = 1382 u32::from_str_radix(index_str, 10).map_err(|_| { 1383 self.error("the integer given overflows the u32 type") 1384 })?; 1385 self.consume(); 1386 Ok(ExternalName::user(namespace, index)) 1387 } 1388 _ => err!(self.loc, "expected integer"), 1389 } 1390 } 1391 _ => err!(self.loc, "expected colon"), 1392 } 1393 } 1394 _ => err!(self.loc, "expected external name"), 1395 } 1396 } 1397 1398 // Parse a function signature. 1399 // 1400 // signature ::= * "(" [paramlist] ")" ["->" retlist] [callconv] 1401 // 1402 fn parse_signature(&mut self, unique_isa: Option<&dyn TargetIsa>) -> ParseResult<Signature> { 1403 // Calling convention defaults to `fast`, but can be changed. 1404 let mut sig = Signature::new(self.default_calling_convention); 1405 1406 self.match_token(Token::LPar, "expected function signature: ( args... )")?; 1407 // signature ::= "(" * [abi-param-list] ")" ["->" retlist] [callconv] 1408 if self.token() != Some(Token::RPar) { 1409 sig.params = self.parse_abi_param_list(unique_isa)?; 1410 } 1411 self.match_token(Token::RPar, "expected ')' after function arguments")?; 1412 if self.optional(Token::Arrow) { 1413 sig.returns = self.parse_abi_param_list(unique_isa)?; 1414 } 1415 1416 // The calling convention is optional. 1417 if let Some(Token::Identifier(text)) = self.token() { 1418 match text.parse() { 1419 Ok(cc) => { 1420 self.consume(); 1421 sig.call_conv = cc; 1422 } 1423 _ => return err!(self.loc, "unknown calling convention: {}", text), 1424 } 1425 } 1426 1427 Ok(sig) 1428 } 1429 1430 // Parse list of function parameter / return value types. 1431 // 1432 // paramlist ::= * param { "," param } 1433 // 1434 fn parse_abi_param_list( 1435 &mut self, 1436 unique_isa: Option<&dyn TargetIsa>, 1437 ) -> ParseResult<Vec<AbiParam>> { 1438 let mut list = Vec::new(); 1439 1440 // abi-param-list ::= * abi-param { "," abi-param } 1441 list.push(self.parse_abi_param(unique_isa)?); 1442 1443 // abi-param-list ::= abi-param * { "," abi-param } 1444 while self.optional(Token::Comma) { 1445 // abi-param-list ::= abi-param { "," * abi-param } 1446 list.push(self.parse_abi_param(unique_isa)?); 1447 } 1448 1449 Ok(list) 1450 } 1451 1452 // Parse a single argument type with flags. 1453 fn parse_abi_param(&mut self, unique_isa: Option<&dyn TargetIsa>) -> ParseResult<AbiParam> { 1454 // abi-param ::= * type { flag } [ argumentloc ] 1455 let mut arg = AbiParam::new(self.match_type("expected parameter type")?); 1456 1457 // abi-param ::= type * { flag } [ argumentloc ] 1458 while let Some(Token::Identifier(s)) = self.token() { 1459 match s { 1460 "uext" => arg.extension = ArgumentExtension::Uext, 1461 "sext" => arg.extension = ArgumentExtension::Sext, 1462 "sarg" => { 1463 self.consume(); 1464 self.match_token(Token::LPar, "expected '(' to begin sarg size")?; 1465 let size = self.match_uimm32("expected byte-size in sarg decl")?; 1466 self.match_token(Token::RPar, "expected ')' to end sarg size")?; 1467 arg.purpose = ArgumentPurpose::StructArgument(size.into()); 1468 continue; 1469 } 1470 _ => { 1471 if let Ok(purpose) = s.parse() { 1472 arg.purpose = purpose; 1473 } else { 1474 break; 1475 } 1476 } 1477 } 1478 self.consume(); 1479 } 1480 1481 // abi-param ::= type { flag } * [ argumentloc ] 1482 arg.location = self.parse_argument_location(unique_isa)?; 1483 1484 Ok(arg) 1485 } 1486 1487 // Parse an argument location specifier; either a register or a byte offset into the stack. 1488 fn parse_argument_location( 1489 &mut self, 1490 unique_isa: Option<&dyn TargetIsa>, 1491 ) -> ParseResult<ArgumentLoc> { 1492 // argumentloc ::= '[' regname | uimm32 ']' 1493 if self.optional(Token::LBracket) { 1494 let result = match self.token() { 1495 Some(Token::Name(name)) => { 1496 self.consume(); 1497 if let Some(isa) = unique_isa { 1498 isa.register_info() 1499 .parse_regunit(name) 1500 .map(ArgumentLoc::Reg) 1501 .ok_or_else(|| self.error("invalid register name")) 1502 } else { 1503 err!(self.loc, "argument location requires exactly one isa") 1504 } 1505 } 1506 Some(Token::Integer(_)) => { 1507 let offset = self.match_imm32("expected stack argument byte offset")?; 1508 Ok(ArgumentLoc::Stack(offset)) 1509 } 1510 Some(Token::Minus) => { 1511 self.consume(); 1512 Ok(ArgumentLoc::Unassigned) 1513 } 1514 _ => err!(self.loc, "expected argument location"), 1515 }; 1516 1517 self.match_token( 1518 Token::RBracket, 1519 "expected ']' to end argument location annotation", 1520 )?; 1521 1522 result 1523 } else { 1524 Ok(ArgumentLoc::Unassigned) 1525 } 1526 } 1527 1528 // Parse the function preamble. 1529 // 1530 // preamble ::= * { preamble-decl } 1531 // preamble-decl ::= * stack-slot-decl 1532 // * function-decl 1533 // * signature-decl 1534 // * jump-table-decl 1535 // * stack-limit-decl 1536 // 1537 // The parsed decls are added to `ctx` rather than returned. 1538 fn parse_preamble(&mut self, ctx: &mut Context) -> ParseResult<()> { 1539 loop { 1540 match self.token() { 1541 Some(Token::StackSlot(..)) => { 1542 self.start_gathering_comments(); 1543 let loc = self.loc; 1544 self.parse_stack_slot_decl() 1545 .and_then(|(ss, dat)| ctx.add_ss(ss, dat, loc)) 1546 } 1547 Some(Token::GlobalValue(..)) => { 1548 self.start_gathering_comments(); 1549 self.parse_global_value_decl() 1550 .and_then(|(gv, dat)| ctx.add_gv(gv, dat, self.loc)) 1551 } 1552 Some(Token::Heap(..)) => { 1553 self.start_gathering_comments(); 1554 self.parse_heap_decl() 1555 .and_then(|(heap, dat)| ctx.add_heap(heap, dat, self.loc)) 1556 } 1557 Some(Token::Table(..)) => { 1558 self.start_gathering_comments(); 1559 self.parse_table_decl() 1560 .and_then(|(table, dat)| ctx.add_table(table, dat, self.loc)) 1561 } 1562 Some(Token::SigRef(..)) => { 1563 self.start_gathering_comments(); 1564 self.parse_signature_decl(ctx.unique_isa) 1565 .and_then(|(sig, dat)| { 1566 ctx.add_sig(sig, dat, self.loc, self.default_calling_convention) 1567 }) 1568 } 1569 Some(Token::FuncRef(..)) => { 1570 self.start_gathering_comments(); 1571 self.parse_function_decl(ctx) 1572 .and_then(|(fn_, dat)| ctx.add_fn(fn_, dat, self.loc)) 1573 } 1574 Some(Token::JumpTable(..)) => { 1575 self.start_gathering_comments(); 1576 self.parse_jump_table_decl() 1577 .and_then(|(jt, dat)| ctx.add_jt(jt, dat, self.loc)) 1578 } 1579 Some(Token::Constant(..)) => { 1580 self.start_gathering_comments(); 1581 self.parse_constant_decl() 1582 .and_then(|(c, v)| ctx.add_constant(c, v, self.loc)) 1583 } 1584 Some(Token::Identifier("stack_limit")) => { 1585 self.start_gathering_comments(); 1586 self.parse_stack_limit_decl() 1587 .and_then(|gv| ctx.add_stack_limit(gv, self.loc)) 1588 } 1589 // More to come.. 1590 _ => return Ok(()), 1591 }?; 1592 } 1593 } 1594 1595 // Parse a stack slot decl. 1596 // 1597 // stack-slot-decl ::= * StackSlot(ss) "=" stack-slot-kind Bytes {"," stack-slot-flag} 1598 // stack-slot-kind ::= "explicit_slot" 1599 // | "spill_slot" 1600 // | "incoming_arg" 1601 // | "outgoing_arg" 1602 fn parse_stack_slot_decl(&mut self) -> ParseResult<(StackSlot, StackSlotData)> { 1603 let ss = self.match_ss("expected stack slot number: ss«n»")?; 1604 self.match_token(Token::Equal, "expected '=' in stack slot declaration")?; 1605 let kind = self.match_enum("expected stack slot kind")?; 1606 1607 // stack-slot-decl ::= StackSlot(ss) "=" stack-slot-kind * Bytes {"," stack-slot-flag} 1608 let bytes: i64 = self 1609 .match_imm64("expected byte-size in stack_slot decl")? 1610 .into(); 1611 if bytes < 0 { 1612 return err!(self.loc, "negative stack slot size"); 1613 } 1614 if bytes > i64::from(u32::MAX) { 1615 return err!(self.loc, "stack slot too large"); 1616 } 1617 let mut data = StackSlotData::new(kind, bytes as u32); 1618 1619 // Take additional options. 1620 while self.optional(Token::Comma) { 1621 match self.match_any_identifier("expected stack slot flags")? { 1622 "offset" => data.offset = Some(self.match_imm32("expected byte offset")?), 1623 other => return err!(self.loc, "Unknown stack slot flag '{}'", other), 1624 } 1625 } 1626 1627 // Collect any trailing comments. 1628 self.token(); 1629 self.claim_gathered_comments(ss); 1630 1631 // TBD: stack-slot-decl ::= StackSlot(ss) "=" stack-slot-kind Bytes * {"," stack-slot-flag} 1632 Ok((ss, data)) 1633 } 1634 1635 // Parse a global value decl. 1636 // 1637 // global-val-decl ::= * GlobalValue(gv) "=" global-val-desc 1638 // global-val-desc ::= "vmctx" 1639 // | "load" "." type "notrap" "aligned" GlobalValue(base) [offset] 1640 // | "iadd_imm" "(" GlobalValue(base) ")" imm64 1641 // | "symbol" ["colocated"] name + imm64 1642 // 1643 fn parse_global_value_decl(&mut self) -> ParseResult<(GlobalValue, GlobalValueData)> { 1644 let gv = self.match_gv("expected global value number: gv«n»")?; 1645 1646 self.match_token(Token::Equal, "expected '=' in global value declaration")?; 1647 1648 let data = match self.match_any_identifier("expected global value kind")? { 1649 "vmctx" => GlobalValueData::VMContext, 1650 "load" => { 1651 self.match_token( 1652 Token::Dot, 1653 "expected '.' followed by type in load global value decl", 1654 )?; 1655 let global_type = self.match_type("expected load type")?; 1656 let flags = self.optional_memflags(); 1657 let base = self.match_gv("expected global value: gv«n»")?; 1658 let offset = self.optional_offset32()?; 1659 1660 if !(flags.notrap() && flags.aligned()) { 1661 return err!(self.loc, "global-value load must be notrap and aligned"); 1662 } 1663 GlobalValueData::Load { 1664 base, 1665 offset, 1666 global_type, 1667 readonly: flags.readonly(), 1668 } 1669 } 1670 "iadd_imm" => { 1671 self.match_token( 1672 Token::Dot, 1673 "expected '.' followed by type in iadd_imm global value decl", 1674 )?; 1675 let global_type = self.match_type("expected iadd type")?; 1676 let base = self.match_gv("expected global value: gv«n»")?; 1677 self.match_token( 1678 Token::Comma, 1679 "expected ',' followed by rhs in iadd_imm global value decl", 1680 )?; 1681 let offset = self.match_imm64("expected iadd_imm immediate")?; 1682 GlobalValueData::IAddImm { 1683 base, 1684 offset, 1685 global_type, 1686 } 1687 } 1688 "symbol" => { 1689 let colocated = self.optional(Token::Identifier("colocated")); 1690 let tls = self.optional(Token::Identifier("tls")); 1691 let name = self.parse_external_name()?; 1692 let offset = self.optional_offset_imm64()?; 1693 GlobalValueData::Symbol { 1694 name, 1695 offset, 1696 colocated, 1697 tls, 1698 } 1699 } 1700 other => return err!(self.loc, "Unknown global value kind '{}'", other), 1701 }; 1702 1703 // Collect any trailing comments. 1704 self.token(); 1705 self.claim_gathered_comments(gv); 1706 1707 Ok((gv, data)) 1708 } 1709 1710 // Parse a heap decl. 1711 // 1712 // heap-decl ::= * Heap(heap) "=" heap-desc 1713 // heap-desc ::= heap-style heap-base { "," heap-attr } 1714 // heap-style ::= "static" | "dynamic" 1715 // heap-base ::= GlobalValue(base) 1716 // heap-attr ::= "min" Imm64(bytes) 1717 // | "bound" Imm64(bytes) 1718 // | "offset_guard" Imm64(bytes) 1719 // | "index_type" type 1720 // 1721 fn parse_heap_decl(&mut self) -> ParseResult<(Heap, HeapData)> { 1722 let heap = self.match_heap("expected heap number: heap«n»")?; 1723 self.match_token(Token::Equal, "expected '=' in heap declaration")?; 1724 1725 let style_name = self.match_any_identifier("expected 'static' or 'dynamic'")?; 1726 1727 // heap-desc ::= heap-style * heap-base { "," heap-attr } 1728 // heap-base ::= * GlobalValue(base) 1729 let base = match self.token() { 1730 Some(Token::GlobalValue(base_num)) => match GlobalValue::with_number(base_num) { 1731 Some(gv) => gv, 1732 None => return err!(self.loc, "invalid global value number for heap base"), 1733 }, 1734 _ => return err!(self.loc, "expected heap base"), 1735 }; 1736 self.consume(); 1737 1738 let mut data = HeapData { 1739 base, 1740 min_size: 0.into(), 1741 offset_guard_size: 0.into(), 1742 style: HeapStyle::Static { bound: 0.into() }, 1743 index_type: ir::types::I32, 1744 }; 1745 1746 // heap-desc ::= heap-style heap-base * { "," heap-attr } 1747 while self.optional(Token::Comma) { 1748 match self.match_any_identifier("expected heap attribute name")? { 1749 "min" => { 1750 data.min_size = self.match_uimm64("expected integer min size")?; 1751 } 1752 "bound" => { 1753 data.style = match style_name { 1754 "dynamic" => HeapStyle::Dynamic { 1755 bound_gv: self.match_gv("expected gv bound")?, 1756 }, 1757 "static" => HeapStyle::Static { 1758 bound: self.match_uimm64("expected integer bound")?, 1759 }, 1760 t => return err!(self.loc, "unknown heap style '{}'", t), 1761 }; 1762 } 1763 "offset_guard" => { 1764 data.offset_guard_size = 1765 self.match_uimm64("expected integer offset-guard size")?; 1766 } 1767 "index_type" => { 1768 data.index_type = self.match_type("expected index type")?; 1769 } 1770 t => return err!(self.loc, "unknown heap attribute '{}'", t), 1771 } 1772 } 1773 1774 // Collect any trailing comments. 1775 self.token(); 1776 self.claim_gathered_comments(heap); 1777 1778 Ok((heap, data)) 1779 } 1780 1781 // Parse a table decl. 1782 // 1783 // table-decl ::= * Table(table) "=" table-desc 1784 // table-desc ::= table-style table-base { "," table-attr } 1785 // table-style ::= "dynamic" 1786 // table-base ::= GlobalValue(base) 1787 // table-attr ::= "min" Imm64(bytes) 1788 // | "bound" Imm64(bytes) 1789 // | "element_size" Imm64(bytes) 1790 // | "index_type" type 1791 // 1792 fn parse_table_decl(&mut self) -> ParseResult<(Table, TableData)> { 1793 let table = self.match_table("expected table number: table«n»")?; 1794 self.match_token(Token::Equal, "expected '=' in table declaration")?; 1795 1796 let style_name = self.match_any_identifier("expected 'static' or 'dynamic'")?; 1797 1798 // table-desc ::= table-style * table-base { "," table-attr } 1799 // table-base ::= * GlobalValue(base) 1800 let base = match self.token() { 1801 Some(Token::GlobalValue(base_num)) => match GlobalValue::with_number(base_num) { 1802 Some(gv) => gv, 1803 None => return err!(self.loc, "invalid global value number for table base"), 1804 }, 1805 _ => return err!(self.loc, "expected table base"), 1806 }; 1807 self.consume(); 1808 1809 let mut data = TableData { 1810 base_gv: base, 1811 min_size: 0.into(), 1812 bound_gv: GlobalValue::reserved_value(), 1813 element_size: 0.into(), 1814 index_type: ir::types::I32, 1815 }; 1816 1817 // table-desc ::= * { "," table-attr } 1818 while self.optional(Token::Comma) { 1819 match self.match_any_identifier("expected table attribute name")? { 1820 "min" => { 1821 data.min_size = self.match_uimm64("expected integer min size")?; 1822 } 1823 "bound" => { 1824 data.bound_gv = match style_name { 1825 "dynamic" => self.match_gv("expected gv bound")?, 1826 t => return err!(self.loc, "unknown table style '{}'", t), 1827 }; 1828 } 1829 "element_size" => { 1830 data.element_size = self.match_uimm64("expected integer element size")?; 1831 } 1832 "index_type" => { 1833 data.index_type = self.match_type("expected index type")?; 1834 } 1835 t => return err!(self.loc, "unknown table attribute '{}'", t), 1836 } 1837 } 1838 1839 // Collect any trailing comments. 1840 self.token(); 1841 self.claim_gathered_comments(table); 1842 1843 Ok((table, data)) 1844 } 1845 1846 // Parse a signature decl. 1847 // 1848 // signature-decl ::= SigRef(sigref) "=" signature 1849 // 1850 fn parse_signature_decl( 1851 &mut self, 1852 unique_isa: Option<&dyn TargetIsa>, 1853 ) -> ParseResult<(SigRef, Signature)> { 1854 let sig = self.match_sig("expected signature number: sig«n»")?; 1855 self.match_token(Token::Equal, "expected '=' in signature decl")?; 1856 let data = self.parse_signature(unique_isa)?; 1857 1858 // Collect any trailing comments. 1859 self.token(); 1860 self.claim_gathered_comments(sig); 1861 1862 Ok((sig, data)) 1863 } 1864 1865 // Parse a function decl. 1866 // 1867 // Two variants: 1868 // 1869 // function-decl ::= FuncRef(fnref) "=" ["colocated"]" name function-decl-sig 1870 // function-decl-sig ::= SigRef(sig) | signature 1871 // 1872 // The first variant allocates a new signature reference. The second references an existing 1873 // signature which must be declared first. 1874 // 1875 fn parse_function_decl(&mut self, ctx: &mut Context) -> ParseResult<(FuncRef, ExtFuncData)> { 1876 let fn_ = self.match_fn("expected function number: fn«n»")?; 1877 self.match_token(Token::Equal, "expected '=' in function decl")?; 1878 1879 let loc = self.loc; 1880 1881 // function-decl ::= FuncRef(fnref) "=" * ["colocated"] name function-decl-sig 1882 let colocated = self.optional(Token::Identifier("colocated")); 1883 1884 // function-decl ::= FuncRef(fnref) "=" ["colocated"] * name function-decl-sig 1885 let name = self.parse_external_name()?; 1886 1887 // function-decl ::= FuncRef(fnref) "=" ["colocated"] name * function-decl-sig 1888 let data = match self.token() { 1889 Some(Token::LPar) => { 1890 // function-decl ::= FuncRef(fnref) "=" ["colocated"] name * signature 1891 let sig = self.parse_signature(ctx.unique_isa)?; 1892 let sigref = ctx.function.import_signature(sig); 1893 ctx.map 1894 .def_entity(sigref.into(), loc) 1895 .expect("duplicate SigRef entities created"); 1896 ExtFuncData { 1897 name, 1898 signature: sigref, 1899 colocated, 1900 } 1901 } 1902 Some(Token::SigRef(sig_src)) => { 1903 let sig = match SigRef::with_number(sig_src) { 1904 None => { 1905 return err!(self.loc, "attempted to use invalid signature ss{}", sig_src); 1906 } 1907 Some(sig) => sig, 1908 }; 1909 ctx.check_sig(sig, self.loc)?; 1910 self.consume(); 1911 ExtFuncData { 1912 name, 1913 signature: sig, 1914 colocated, 1915 } 1916 } 1917 _ => return err!(self.loc, "expected 'function' or sig«n» in function decl"), 1918 }; 1919 1920 // Collect any trailing comments. 1921 self.token(); 1922 self.claim_gathered_comments(fn_); 1923 1924 Ok((fn_, data)) 1925 } 1926 1927 // Parse a jump table decl. 1928 // 1929 // jump-table-decl ::= * JumpTable(jt) "=" "jump_table" "[" jt-entry {"," jt-entry} "]" 1930 fn parse_jump_table_decl(&mut self) -> ParseResult<(JumpTable, JumpTableData)> { 1931 let jt = self.match_jt()?; 1932 self.match_token(Token::Equal, "expected '=' in jump_table decl")?; 1933 self.match_identifier("jump_table", "expected 'jump_table'")?; 1934 self.match_token(Token::LBracket, "expected '[' before jump table contents")?; 1935 1936 let mut data = JumpTableData::new(); 1937 1938 // jump-table-decl ::= JumpTable(jt) "=" "jump_table" "[" * Block(dest) {"," Block(dest)} "]" 1939 match self.token() { 1940 Some(Token::Block(dest)) => { 1941 self.consume(); 1942 data.push_entry(dest); 1943 1944 loop { 1945 match self.token() { 1946 Some(Token::Comma) => { 1947 self.consume(); 1948 if let Some(Token::Block(dest)) = self.token() { 1949 self.consume(); 1950 data.push_entry(dest); 1951 } else { 1952 return err!(self.loc, "expected jump_table entry"); 1953 } 1954 } 1955 Some(Token::RBracket) => break, 1956 _ => return err!(self.loc, "expected ']' after jump table contents"), 1957 } 1958 } 1959 } 1960 Some(Token::RBracket) => (), 1961 _ => return err!(self.loc, "expected jump_table entry"), 1962 } 1963 1964 self.consume(); 1965 1966 // Collect any trailing comments. 1967 self.token(); 1968 self.claim_gathered_comments(jt); 1969 1970 Ok((jt, data)) 1971 } 1972 1973 // Parse a constant decl. 1974 // 1975 // constant-decl ::= * Constant(c) "=" ty? "[" literal {"," literal} "]" 1976 fn parse_constant_decl(&mut self) -> ParseResult<(Constant, ConstantData)> { 1977 let name = self.match_constant()?; 1978 self.match_token(Token::Equal, "expected '=' in constant decl")?; 1979 let data = if let Some(Token::Type(_)) = self.token() { 1980 let ty = self.match_type("expected type of constant")?; 1981 self.match_uimm128(ty) 1982 } else { 1983 self.match_constant_data() 1984 }?; 1985 1986 // Collect any trailing comments. 1987 self.token(); 1988 self.claim_gathered_comments(name); 1989 1990 Ok((name, data)) 1991 } 1992 1993 // Parse a stack limit decl 1994 // 1995 // stack-limit-decl ::= * StackLimit "=" GlobalValue(gv) 1996 fn parse_stack_limit_decl(&mut self) -> ParseResult<GlobalValue> { 1997 self.match_stack_limit()?; 1998 self.match_token(Token::Equal, "expected '=' in stack limit decl")?; 1999 let limit = match self.token() { 2000 Some(Token::GlobalValue(base_num)) => match GlobalValue::with_number(base_num) { 2001 Some(gv) => gv, 2002 None => return err!(self.loc, "invalid global value number for stack limit"), 2003 }, 2004 _ => return err!(self.loc, "expected global value"), 2005 }; 2006 self.consume(); 2007 2008 // Collect any trailing comments. 2009 self.token(); 2010 self.claim_gathered_comments(AnyEntity::StackLimit); 2011 2012 Ok(limit) 2013 } 2014 2015 // Parse a function body, add contents to `ctx`. 2016 // 2017 // function-body ::= * { extended-basic-block } 2018 // 2019 fn parse_function_body(&mut self, ctx: &mut Context) -> ParseResult<()> { 2020 while self.token() != Some(Token::RBrace) { 2021 self.parse_basic_block(ctx)?; 2022 } 2023 2024 // Now that we've seen all defined values in the function, ensure that 2025 // all references refer to a definition. 2026 for block in &ctx.function.layout { 2027 for inst in ctx.function.layout.block_insts(block) { 2028 for value in ctx.function.dfg.inst_args(inst) { 2029 if !ctx.map.contains_value(*value) { 2030 return err!( 2031 ctx.map.location(AnyEntity::Inst(inst)).unwrap(), 2032 "undefined operand value {}", 2033 value 2034 ); 2035 } 2036 } 2037 } 2038 } 2039 2040 for alias in &ctx.aliases { 2041 if !ctx.function.dfg.set_alias_type_for_parser(*alias) { 2042 let loc = ctx.map.location(AnyEntity::Value(*alias)).unwrap(); 2043 return err!(loc, "alias cycle involving {}", alias); 2044 } 2045 } 2046 2047 Ok(()) 2048 } 2049 2050 // Parse a basic block, add contents to `ctx`. 2051 // 2052 // extended-basic-block ::= * block-header { instruction } 2053 // block-header ::= Block(block) [block-params] ":" 2054 // 2055 fn parse_basic_block(&mut self, ctx: &mut Context) -> ParseResult<()> { 2056 // Collect comments for the next block. 2057 self.start_gathering_comments(); 2058 2059 let block_num = self.match_block("expected block header")?; 2060 let block = ctx.add_block(block_num, self.loc)?; 2061 2062 if block_num.as_u32() >= MAX_BLOCKS_IN_A_FUNCTION { 2063 return Err(self.error("too many blocks")); 2064 } 2065 2066 if !self.optional(Token::Colon) { 2067 // block-header ::= Block(block) [ * block-params ] ":" 2068 self.parse_block_params(ctx, block)?; 2069 self.match_token(Token::Colon, "expected ':' after block parameters")?; 2070 } 2071 2072 // Collect any trailing comments. 2073 self.token(); 2074 self.claim_gathered_comments(block); 2075 2076 // extended-basic-block ::= block-header * { instruction } 2077 while match self.token() { 2078 Some(Token::Value(_)) 2079 | Some(Token::Identifier(_)) 2080 | Some(Token::LBracket) 2081 | Some(Token::SourceLoc(_)) => true, 2082 _ => false, 2083 } { 2084 let srcloc = self.optional_srcloc()?; 2085 let (encoding, result_locations) = self.parse_instruction_encoding(ctx)?; 2086 2087 // We need to parse instruction results here because they are shared 2088 // between the parsing of value aliases and the parsing of instructions. 2089 // 2090 // inst-results ::= Value(v) { "," Value(v) } 2091 let results = self.parse_inst_results()?; 2092 2093 for result in &results { 2094 while ctx.function.dfg.num_values() <= result.index() { 2095 ctx.function.dfg.make_invalid_value_for_parser(); 2096 } 2097 } 2098 2099 match self.token() { 2100 Some(Token::Arrow) => { 2101 self.consume(); 2102 self.parse_value_alias(&results, ctx)?; 2103 } 2104 Some(Token::Equal) => { 2105 self.consume(); 2106 self.parse_instruction( 2107 &results, 2108 srcloc, 2109 encoding, 2110 result_locations, 2111 ctx, 2112 block, 2113 )?; 2114 } 2115 _ if !results.is_empty() => return err!(self.loc, "expected -> or ="), 2116 _ => self.parse_instruction( 2117 &results, 2118 srcloc, 2119 encoding, 2120 result_locations, 2121 ctx, 2122 block, 2123 )?, 2124 } 2125 } 2126 2127 Ok(()) 2128 } 2129 2130 // Parse parenthesized list of block parameters. Returns a vector of (u32, Type) pairs with the 2131 // value numbers of the defined values and the defined types. 2132 // 2133 // block-params ::= * "(" block-param { "," block-param } ")" 2134 fn parse_block_params(&mut self, ctx: &mut Context, block: Block) -> ParseResult<()> { 2135 // block-params ::= * "(" block-param { "," block-param } ")" 2136 self.match_token(Token::LPar, "expected '(' before block parameters")?; 2137 2138 // block-params ::= "(" * block-param { "," block-param } ")" 2139 self.parse_block_param(ctx, block)?; 2140 2141 // block-params ::= "(" block-param * { "," block-param } ")" 2142 while self.optional(Token::Comma) { 2143 // block-params ::= "(" block-param { "," * block-param } ")" 2144 self.parse_block_param(ctx, block)?; 2145 } 2146 2147 // block-params ::= "(" block-param { "," block-param } * ")" 2148 self.match_token(Token::RPar, "expected ')' after block parameters")?; 2149 2150 Ok(()) 2151 } 2152 2153 // Parse a single block parameter declaration, and append it to `block`. 2154 // 2155 // block-param ::= * Value(v) ":" Type(t) arg-loc? 2156 // arg-loc ::= "[" value-location "]" 2157 // 2158 fn parse_block_param(&mut self, ctx: &mut Context, block: Block) -> ParseResult<()> { 2159 // block-param ::= * Value(v) ":" Type(t) arg-loc? 2160 let v = self.match_value("block argument must be a value")?; 2161 let v_location = self.loc; 2162 // block-param ::= Value(v) * ":" Type(t) arg-loc? 2163 self.match_token(Token::Colon, "expected ':' after block argument")?; 2164 // block-param ::= Value(v) ":" * Type(t) arg-loc? 2165 2166 while ctx.function.dfg.num_values() <= v.index() { 2167 ctx.function.dfg.make_invalid_value_for_parser(); 2168 } 2169 2170 let t = self.match_type("expected block argument type")?; 2171 // Allocate the block argument. 2172 ctx.function.dfg.append_block_param_for_parser(block, t, v); 2173 ctx.map.def_value(v, v_location)?; 2174 2175 // block-param ::= Value(v) ":" Type(t) * arg-loc? 2176 if self.optional(Token::LBracket) { 2177 let loc = self.parse_value_location(ctx)?; 2178 ctx.function.locations[v] = loc; 2179 self.match_token(Token::RBracket, "expected ']' after value location")?; 2180 } 2181 2182 Ok(()) 2183 } 2184 2185 fn parse_value_location(&mut self, ctx: &Context) -> ParseResult<ValueLoc> { 2186 match self.token() { 2187 Some(Token::StackSlot(src_num)) => { 2188 self.consume(); 2189 let ss = match StackSlot::with_number(src_num) { 2190 None => { 2191 return err!( 2192 self.loc, 2193 "attempted to use invalid stack slot ss{}", 2194 src_num 2195 ); 2196 } 2197 Some(ss) => ss, 2198 }; 2199 ctx.check_ss(ss, self.loc)?; 2200 Ok(ValueLoc::Stack(ss)) 2201 } 2202 Some(Token::Name(name)) => { 2203 self.consume(); 2204 if let Some(isa) = ctx.unique_isa { 2205 isa.register_info() 2206 .parse_regunit(name) 2207 .map(ValueLoc::Reg) 2208 .ok_or_else(|| self.error("invalid register value location")) 2209 } else { 2210 err!(self.loc, "value location requires exactly one isa") 2211 } 2212 } 2213 Some(Token::Minus) => { 2214 self.consume(); 2215 Ok(ValueLoc::Unassigned) 2216 } 2217 _ => err!(self.loc, "invalid value location"), 2218 } 2219 } 2220 2221 fn parse_instruction_encoding( 2222 &mut self, 2223 ctx: &Context, 2224 ) -> ParseResult<(Option<Encoding>, Option<Vec<ValueLoc>>)> { 2225 let (mut encoding, mut result_locations) = (None, None); 2226 2227 // encoding ::= "[" encoding_literal result_locations "]" 2228 if self.optional(Token::LBracket) { 2229 // encoding_literal ::= "-" | Identifier HexSequence 2230 if !self.optional(Token::Minus) { 2231 let recipe = self.match_any_identifier("expected instruction encoding or '-'")?; 2232 let bits = self.match_hex16("expected a hex sequence")?; 2233 2234 if let Some(recipe_index) = ctx.find_recipe_index(recipe) { 2235 encoding = Some(Encoding::new(recipe_index, bits)); 2236 } else if ctx.unique_isa.is_some() { 2237 return err!(self.loc, "invalid instruction recipe"); 2238 } else { 2239 // We allow encodings to be specified when there's no unique ISA purely 2240 // for convenience, eg when copy-pasting code for a test. 2241 } 2242 } 2243 2244 // result_locations ::= ("," ( "-" | names ) )? 2245 // names ::= Name { "," Name } 2246 if self.optional(Token::Comma) { 2247 let mut results = Vec::new(); 2248 2249 results.push(self.parse_value_location(ctx)?); 2250 while self.optional(Token::Comma) { 2251 results.push(self.parse_value_location(ctx)?); 2252 } 2253 2254 result_locations = Some(results); 2255 } 2256 2257 self.match_token( 2258 Token::RBracket, 2259 "expected ']' to terminate instruction encoding", 2260 )?; 2261 } 2262 2263 Ok((encoding, result_locations)) 2264 } 2265 2266 // Parse instruction results and return them. 2267 // 2268 // inst-results ::= Value(v) { "," Value(v) } 2269 // 2270 fn parse_inst_results(&mut self) -> ParseResult<SmallVec<[Value; 1]>> { 2271 // Result value numbers. 2272 let mut results = SmallVec::new(); 2273 2274 // instruction ::= * [inst-results "="] Opcode(opc) ["." Type] ... 2275 // inst-results ::= * Value(v) { "," Value(v) } 2276 if let Some(Token::Value(v)) = self.token() { 2277 self.consume(); 2278 2279 results.push(v); 2280 2281 // inst-results ::= Value(v) * { "," Value(v) } 2282 while self.optional(Token::Comma) { 2283 // inst-results ::= Value(v) { "," * Value(v) } 2284 results.push(self.match_value("expected result value")?); 2285 } 2286 } 2287 2288 Ok(results) 2289 } 2290 2291 // Parse a value alias, and append it to `block`. 2292 // 2293 // value_alias ::= [inst-results] "->" Value(v) 2294 // 2295 fn parse_value_alias(&mut self, results: &[Value], ctx: &mut Context) -> ParseResult<()> { 2296 if results.len() != 1 { 2297 return err!(self.loc, "wrong number of aliases"); 2298 } 2299 let result = results[0]; 2300 let dest = self.match_value("expected value alias")?; 2301 2302 // Allow duplicate definitions of aliases, as long as they are identical. 2303 if ctx.map.contains_value(result) { 2304 if let Some(old) = ctx.function.dfg.value_alias_dest_for_serialization(result) { 2305 if old != dest { 2306 return err!( 2307 self.loc, 2308 "value {} is already defined as an alias with destination {}", 2309 result, 2310 old 2311 ); 2312 } 2313 } else { 2314 return err!(self.loc, "value {} is already defined"); 2315 } 2316 } else { 2317 ctx.map.def_value(result, self.loc)?; 2318 } 2319 2320 if !ctx.map.contains_value(dest) { 2321 return err!(self.loc, "value {} is not yet defined", dest); 2322 } 2323 2324 ctx.function 2325 .dfg 2326 .make_value_alias_for_serialization(dest, result); 2327 2328 ctx.aliases.push(result); 2329 Ok(()) 2330 } 2331 2332 // Parse an instruction, append it to `block`. 2333 // 2334 // instruction ::= [inst-results "="] Opcode(opc) ["." Type] ... 2335 // 2336 fn parse_instruction( 2337 &mut self, 2338 results: &[Value], 2339 srcloc: ir::SourceLoc, 2340 encoding: Option<Encoding>, 2341 result_locations: Option<Vec<ValueLoc>>, 2342 ctx: &mut Context, 2343 block: Block, 2344 ) -> ParseResult<()> { 2345 // Define the result values. 2346 for val in results { 2347 ctx.map.def_value(*val, self.loc)?; 2348 } 2349 2350 // Collect comments for the next instruction. 2351 self.start_gathering_comments(); 2352 2353 // instruction ::= [inst-results "="] * Opcode(opc) ["." Type] ... 2354 let opcode = if let Some(Token::Identifier(text)) = self.token() { 2355 match text.parse() { 2356 Ok(opc) => opc, 2357 Err(msg) => return err!(self.loc, "{}: '{}'", msg, text), 2358 } 2359 } else { 2360 return err!(self.loc, "expected instruction opcode"); 2361 }; 2362 let opcode_loc = self.loc; 2363 self.consume(); 2364 2365 // Look for a controlling type variable annotation. 2366 // instruction ::= [inst-results "="] Opcode(opc) * ["." Type] ... 2367 let explicit_ctrl_type = if self.optional(Token::Dot) { 2368 Some(self.match_type("expected type after 'opcode.'")?) 2369 } else { 2370 None 2371 }; 2372 2373 // instruction ::= [inst-results "="] Opcode(opc) ["." Type] * ... 2374 let inst_data = self.parse_inst_operands(ctx, opcode, explicit_ctrl_type)?; 2375 2376 // We're done parsing the instruction now. 2377 // 2378 // We still need to check that the number of result values in the source matches the opcode 2379 // or function call signature. We also need to create values with the right type for all 2380 // the instruction results. 2381 let ctrl_typevar = self.infer_typevar(ctx, opcode, explicit_ctrl_type, &inst_data)?; 2382 let inst = ctx.function.dfg.make_inst(inst_data); 2383 let num_results = 2384 ctx.function 2385 .dfg 2386 .make_inst_results_for_parser(inst, ctrl_typevar, results); 2387 ctx.function.layout.append_inst(inst, block); 2388 ctx.map 2389 .def_entity(inst.into(), opcode_loc) 2390 .expect("duplicate inst references created"); 2391 2392 if !srcloc.is_default() { 2393 ctx.function.srclocs[inst] = srcloc; 2394 } 2395 2396 if let Some(encoding) = encoding { 2397 ctx.function.encodings[inst] = encoding; 2398 } 2399 2400 if results.len() != num_results { 2401 return err!( 2402 self.loc, 2403 "instruction produces {} result values, {} given", 2404 num_results, 2405 results.len() 2406 ); 2407 } 2408 2409 if let Some(ref result_locations) = result_locations { 2410 if results.len() != result_locations.len() { 2411 return err!( 2412 self.loc, 2413 "instruction produces {} result values, but {} locations were \ 2414 specified", 2415 results.len(), 2416 result_locations.len() 2417 ); 2418 } 2419 } 2420 2421 if let Some(result_locations) = result_locations { 2422 for (&value, loc) in ctx 2423 .function 2424 .dfg 2425 .inst_results(inst) 2426 .iter() 2427 .zip(result_locations) 2428 { 2429 ctx.function.locations[value] = loc; 2430 } 2431 } 2432 2433 // Collect any trailing comments. 2434 self.token(); 2435 self.claim_gathered_comments(inst); 2436 2437 Ok(()) 2438 } 2439 2440 // Type inference for polymorphic instructions. 2441 // 2442 // The controlling type variable can be specified explicitly as 'splat.i32x4 v5', or it can be 2443 // inferred from `inst_data.typevar_operand` for some opcodes. 2444 // 2445 // Returns the controlling typevar for a polymorphic opcode, or `INVALID` for a non-polymorphic 2446 // opcode. 2447 fn infer_typevar( 2448 &self, 2449 ctx: &Context, 2450 opcode: Opcode, 2451 explicit_ctrl_type: Option<Type>, 2452 inst_data: &InstructionData, 2453 ) -> ParseResult<Type> { 2454 let constraints = opcode.constraints(); 2455 let ctrl_type = match explicit_ctrl_type { 2456 Some(t) => t, 2457 None => { 2458 if constraints.use_typevar_operand() { 2459 // This is an opcode that supports type inference, AND there was no 2460 // explicit type specified. Look up `ctrl_value` to see if it was defined 2461 // already. 2462 // TBD: If it is defined in another block, the type should have been 2463 // specified explicitly. It is unfortunate that the correctness of IR 2464 // depends on the layout of the blocks. 2465 let ctrl_src_value = inst_data 2466 .typevar_operand(&ctx.function.dfg.value_lists) 2467 .expect("Constraints <-> Format inconsistency"); 2468 if !ctx.map.contains_value(ctrl_src_value) { 2469 return err!( 2470 self.loc, 2471 "type variable required for polymorphic opcode, e.g. '{}.{}'; \ 2472 can't infer from {} which is not yet defined", 2473 opcode, 2474 constraints.ctrl_typeset().unwrap().example(), 2475 ctrl_src_value 2476 ); 2477 } 2478 if !ctx.function.dfg.value_is_valid_for_parser(ctrl_src_value) { 2479 return err!( 2480 self.loc, 2481 "type variable required for polymorphic opcode, e.g. '{}.{}'; \ 2482 can't infer from {} which is not yet resolved", 2483 opcode, 2484 constraints.ctrl_typeset().unwrap().example(), 2485 ctrl_src_value 2486 ); 2487 } 2488 ctx.function.dfg.value_type(ctrl_src_value) 2489 } else if constraints.is_polymorphic() { 2490 // This opcode does not support type inference, so the explicit type 2491 // variable is required. 2492 return err!( 2493 self.loc, 2494 "type variable required for polymorphic opcode, e.g. '{}.{}'", 2495 opcode, 2496 constraints.ctrl_typeset().unwrap().example() 2497 ); 2498 } else { 2499 // This is a non-polymorphic opcode. No typevar needed. 2500 INVALID 2501 } 2502 } 2503 }; 2504 2505 // Verify that `ctrl_type` is valid for the controlling type variable. We don't want to 2506 // attempt deriving types from an incorrect basis. 2507 // This is not a complete type check. The verifier does that. 2508 if let Some(typeset) = constraints.ctrl_typeset() { 2509 // This is a polymorphic opcode. 2510 if !typeset.contains(ctrl_type) { 2511 return err!( 2512 self.loc, 2513 "{} is not a valid typevar for {}", 2514 ctrl_type, 2515 opcode 2516 ); 2517 } 2518 // Treat it as a syntax error to specify a typevar on a non-polymorphic opcode. 2519 } else if ctrl_type != INVALID { 2520 return err!(self.loc, "{} does not take a typevar", opcode); 2521 } 2522 2523 Ok(ctrl_type) 2524 } 2525 2526 // Parse comma-separated value list into a VariableArgs struct. 2527 // 2528 // value_list ::= [ value { "," value } ] 2529 // 2530 fn parse_value_list(&mut self) -> ParseResult<VariableArgs> { 2531 let mut args = VariableArgs::new(); 2532 2533 if let Some(Token::Value(v)) = self.token() { 2534 args.push(v); 2535 self.consume(); 2536 } else { 2537 return Ok(args); 2538 } 2539 2540 while self.optional(Token::Comma) { 2541 args.push(self.match_value("expected value in argument list")?); 2542 } 2543 2544 Ok(args) 2545 } 2546 2547 fn parse_value_sequence(&mut self) -> ParseResult<VariableArgs> { 2548 let mut args = VariableArgs::new(); 2549 2550 if let Some(Token::Value(v)) = self.token() { 2551 args.push(v); 2552 self.consume(); 2553 } else { 2554 return Ok(args); 2555 } 2556 2557 while self.optional(Token::Plus) { 2558 args.push(self.match_value("expected value in argument list")?); 2559 } 2560 2561 Ok(args) 2562 } 2563 2564 // Parse an optional value list enclosed in parentheses. 2565 fn parse_opt_value_list(&mut self) -> ParseResult<VariableArgs> { 2566 if !self.optional(Token::LPar) { 2567 return Ok(VariableArgs::new()); 2568 } 2569 2570 let args = self.parse_value_list()?; 2571 2572 self.match_token(Token::RPar, "expected ')' after arguments")?; 2573 2574 Ok(args) 2575 } 2576 2577 /// Parse a CLIF run command. 2578 /// 2579 /// run-command ::= "run" [":" invocation comparison expected] 2580 /// \ "print" [":" invocation] 2581 fn parse_run_command(&mut self, sig: &Signature) -> ParseResult<RunCommand> { 2582 // skip semicolon 2583 match self.token() { 2584 Some(Token::Identifier("run")) => { 2585 self.consume(); 2586 if self.optional(Token::Colon) { 2587 let invocation = self.parse_run_invocation(sig)?; 2588 let comparison = self.parse_run_comparison()?; 2589 let expected = self.parse_run_returns(sig)?; 2590 Ok(RunCommand::Run(invocation, comparison, expected)) 2591 } else if sig.params.is_empty() 2592 && sig.returns.len() == 1 2593 && sig.returns[0].value_type.is_bool() 2594 { 2595 // To match the existing run behavior that does not require an explicit 2596 // invocation, we create an invocation from a function like `() -> b*` and 2597 // compare it to `true`. 2598 let invocation = Invocation::new("default", vec![]); 2599 let expected = vec![DataValue::B(true)]; 2600 let comparison = Comparison::Equals; 2601 Ok(RunCommand::Run(invocation, comparison, expected)) 2602 } else { 2603 Err(self.error("unable to parse the run command")) 2604 } 2605 } 2606 Some(Token::Identifier("print")) => { 2607 self.consume(); 2608 if self.optional(Token::Colon) { 2609 Ok(RunCommand::Print(self.parse_run_invocation(sig)?)) 2610 } else if sig.params.is_empty() { 2611 // To allow printing of functions like `() -> *`, we create a no-arg invocation. 2612 let invocation = Invocation::new("default", vec![]); 2613 Ok(RunCommand::Print(invocation)) 2614 } else { 2615 Err(self.error("unable to parse the print command")) 2616 } 2617 } 2618 _ => Err(self.error("expected a 'run:' or 'print:' command")), 2619 } 2620 } 2621 2622 /// Parse the invocation of a CLIF function. 2623 /// 2624 /// This is different from parsing a CLIF `call`; it is used in parsing run commands like 2625 /// `run: %fn(42, 4.2) == false`. 2626 /// 2627 /// invocation ::= name "(" [data-value-list] ")" 2628 fn parse_run_invocation(&mut self, sig: &Signature) -> ParseResult<Invocation> { 2629 if let Some(Token::Name(name)) = self.token() { 2630 self.consume(); 2631 self.match_token( 2632 Token::LPar, 2633 "expected invocation parentheses, e.g. %fn(...)", 2634 )?; 2635 2636 let args = self.parse_data_value_list( 2637 &sig.params.iter().map(|a| a.value_type).collect::<Vec<_>>(), 2638 )?; 2639 2640 self.match_token( 2641 Token::RPar, 2642 "expected invocation parentheses, e.g. %fn(...)", 2643 )?; 2644 Ok(Invocation::new(name, args)) 2645 } else { 2646 Err(self.error("expected a function name, e.g. %my_fn")) 2647 } 2648 } 2649 2650 /// Parse a comparison operator for run commands. 2651 /// 2652 /// comparison ::= "==" | "!=" 2653 fn parse_run_comparison(&mut self) -> ParseResult<Comparison> { 2654 if self.optional(Token::Equal) { 2655 self.match_token(Token::Equal, "expected another =")?; 2656 Ok(Comparison::Equals) 2657 } else if self.optional(Token::Not) { 2658 self.match_token(Token::Equal, "expected a =")?; 2659 Ok(Comparison::NotEquals) 2660 } else { 2661 Err(self.error("unable to parse a valid comparison operator")) 2662 } 2663 } 2664 2665 /// Parse the expected return values of a run invocation. 2666 /// 2667 /// expected ::= "[" "]" 2668 /// | data-value 2669 /// | "[" data-value-list "]" 2670 fn parse_run_returns(&mut self, sig: &Signature) -> ParseResult<Vec<DataValue>> { 2671 if sig.returns.len() != 1 { 2672 self.match_token(Token::LBracket, "expected a left bracket [")?; 2673 } 2674 2675 let returns = self 2676 .parse_data_value_list(&sig.returns.iter().map(|a| a.value_type).collect::<Vec<_>>())?; 2677 2678 if sig.returns.len() != 1 { 2679 self.match_token(Token::RBracket, "expected a right bracket ]")?; 2680 } 2681 Ok(returns) 2682 } 2683 2684 /// Parse a comma-separated list of data values. 2685 /// 2686 /// data-value-list ::= [data-value {"," data-value-list}] 2687 fn parse_data_value_list(&mut self, types: &[Type]) -> ParseResult<Vec<DataValue>> { 2688 let mut values = vec![]; 2689 for ty in types.iter().take(1) { 2690 values.push(self.parse_data_value(*ty)?); 2691 } 2692 for ty in types.iter().skip(1) { 2693 self.match_token( 2694 Token::Comma, 2695 "expected a comma between invocation arguments", 2696 )?; 2697 values.push(self.parse_data_value(*ty)?); 2698 } 2699 Ok(values) 2700 } 2701 2702 /// Parse a data value; e.g. `42`, `4.2`, `true`. 2703 /// 2704 /// data-value-list ::= [data-value {"," data-value-list}] 2705 fn parse_data_value(&mut self, ty: Type) -> ParseResult<DataValue> { 2706 let dv = match ty { 2707 I8 => DataValue::from(self.match_imm8("expected a i8")?), 2708 I16 => DataValue::from(self.match_imm16("expected an i16")?), 2709 I32 => DataValue::from(self.match_imm32("expected an i32")?), 2710 I64 => DataValue::from(Into::<i64>::into(self.match_imm64("expected an i64")?)), 2711 F32 => DataValue::from(self.match_ieee32("expected an f32")?), 2712 F64 => DataValue::from(self.match_ieee64("expected an f64")?), 2713 _ if ty.is_vector() => { 2714 let as_vec = self.match_uimm128(ty)?.into_vec(); 2715 if as_vec.len() == 16 { 2716 let mut as_array = [0; 16]; 2717 as_array.copy_from_slice(&as_vec[..16]); 2718 DataValue::from(as_array) 2719 } else { 2720 return Err(self.error("only 128-bit vectors are currently supported")); 2721 } 2722 } 2723 _ if ty.is_bool() && !ty.is_vector() => { 2724 DataValue::from(self.match_bool("expected a boolean")?) 2725 } 2726 _ => return Err(self.error(&format!("don't know how to parse data values of: {}", ty))), 2727 }; 2728 Ok(dv) 2729 } 2730 2731 // Parse the operands following the instruction opcode. 2732 // This depends on the format of the opcode. 2733 fn parse_inst_operands( 2734 &mut self, 2735 ctx: &mut Context, 2736 opcode: Opcode, 2737 explicit_control_type: Option<Type>, 2738 ) -> ParseResult<InstructionData> { 2739 let idata = match opcode.format() { 2740 InstructionFormat::Unary => InstructionData::Unary { 2741 opcode, 2742 arg: self.match_value("expected SSA value operand")?, 2743 }, 2744 InstructionFormat::UnaryImm => InstructionData::UnaryImm { 2745 opcode, 2746 imm: self.match_imm64("expected immediate integer operand")?, 2747 }, 2748 InstructionFormat::UnaryIeee32 => InstructionData::UnaryIeee32 { 2749 opcode, 2750 imm: self.match_ieee32("expected immediate 32-bit float operand")?, 2751 }, 2752 InstructionFormat::UnaryIeee64 => InstructionData::UnaryIeee64 { 2753 opcode, 2754 imm: self.match_ieee64("expected immediate 64-bit float operand")?, 2755 }, 2756 InstructionFormat::UnaryBool => InstructionData::UnaryBool { 2757 opcode, 2758 imm: self.match_bool("expected immediate boolean operand")?, 2759 }, 2760 InstructionFormat::UnaryConst => { 2761 let constant_handle = if let Some(Token::Constant(_)) = self.token() { 2762 // If handed a `const?`, use that. 2763 let c = self.match_constant()?; 2764 ctx.check_constant(c, self.loc)?; 2765 c 2766 } else if let Some(controlling_type) = explicit_control_type { 2767 // If an explicit control type is present, we expect a sized value and insert 2768 // it in the constant pool. 2769 let uimm128 = self.match_uimm128(controlling_type)?; 2770 ctx.function.dfg.constants.insert(uimm128) 2771 } else { 2772 return err!( 2773 self.loc, 2774 "Expected either a const entity or a typed value, e.g. inst.i32x4 [...]" 2775 ); 2776 }; 2777 InstructionData::UnaryConst { 2778 opcode, 2779 constant_handle, 2780 } 2781 } 2782 InstructionFormat::UnaryGlobalValue => { 2783 let gv = self.match_gv("expected global value")?; 2784 ctx.check_gv(gv, self.loc)?; 2785 InstructionData::UnaryGlobalValue { 2786 opcode, 2787 global_value: gv, 2788 } 2789 } 2790 InstructionFormat::Binary => { 2791 let lhs = self.match_value("expected SSA value first operand")?; 2792 self.match_token(Token::Comma, "expected ',' between operands")?; 2793 let rhs = self.match_value("expected SSA value second operand")?; 2794 InstructionData::Binary { 2795 opcode, 2796 args: [lhs, rhs], 2797 } 2798 } 2799 InstructionFormat::BinaryImm8 => { 2800 let arg = self.match_value("expected SSA value first operand")?; 2801 self.match_token(Token::Comma, "expected ',' between operands")?; 2802 let imm = self.match_uimm8("expected unsigned 8-bit immediate")?; 2803 InstructionData::BinaryImm8 { opcode, arg, imm } 2804 } 2805 InstructionFormat::BinaryImm64 => { 2806 let lhs = self.match_value("expected SSA value first operand")?; 2807 self.match_token(Token::Comma, "expected ',' between operands")?; 2808 let rhs = self.match_imm64("expected immediate integer second operand")?; 2809 InstructionData::BinaryImm64 { 2810 opcode, 2811 arg: lhs, 2812 imm: rhs, 2813 } 2814 } 2815 InstructionFormat::Ternary => { 2816 // Names here refer to the `select` instruction. 2817 // This format is also use by `fma`. 2818 let ctrl_arg = self.match_value("expected SSA value control operand")?; 2819 self.match_token(Token::Comma, "expected ',' between operands")?; 2820 let true_arg = self.match_value("expected SSA value true operand")?; 2821 self.match_token(Token::Comma, "expected ',' between operands")?; 2822 let false_arg = self.match_value("expected SSA value false operand")?; 2823 InstructionData::Ternary { 2824 opcode, 2825 args: [ctrl_arg, true_arg, false_arg], 2826 } 2827 } 2828 InstructionFormat::MultiAry => { 2829 let args = self.parse_value_list()?; 2830 InstructionData::MultiAry { 2831 opcode, 2832 args: args.into_value_list(&[], &mut ctx.function.dfg.value_lists), 2833 } 2834 } 2835 InstructionFormat::NullAry => InstructionData::NullAry { opcode }, 2836 InstructionFormat::Jump => { 2837 // Parse the destination block number. 2838 let block_num = self.match_block("expected jump destination block")?; 2839 let args = self.parse_opt_value_list()?; 2840 InstructionData::Jump { 2841 opcode, 2842 destination: block_num, 2843 args: args.into_value_list(&[], &mut ctx.function.dfg.value_lists), 2844 } 2845 } 2846 InstructionFormat::Branch => { 2847 let ctrl_arg = self.match_value("expected SSA value control operand")?; 2848 self.match_token(Token::Comma, "expected ',' between operands")?; 2849 let block_num = self.match_block("expected branch destination block")?; 2850 let args = self.parse_opt_value_list()?; 2851 InstructionData::Branch { 2852 opcode, 2853 destination: block_num, 2854 args: args.into_value_list(&[ctrl_arg], &mut ctx.function.dfg.value_lists), 2855 } 2856 } 2857 InstructionFormat::BranchInt => { 2858 let cond = self.match_enum("expected intcc condition code")?; 2859 let arg = self.match_value("expected SSA value first operand")?; 2860 self.match_token(Token::Comma, "expected ',' between operands")?; 2861 let block_num = self.match_block("expected branch destination block")?; 2862 let args = self.parse_opt_value_list()?; 2863 InstructionData::BranchInt { 2864 opcode, 2865 cond, 2866 destination: block_num, 2867 args: args.into_value_list(&[arg], &mut ctx.function.dfg.value_lists), 2868 } 2869 } 2870 InstructionFormat::BranchFloat => { 2871 let cond = self.match_enum("expected floatcc condition code")?; 2872 let arg = self.match_value("expected SSA value first operand")?; 2873 self.match_token(Token::Comma, "expected ',' between operands")?; 2874 let block_num = self.match_block("expected branch destination block")?; 2875 let args = self.parse_opt_value_list()?; 2876 InstructionData::BranchFloat { 2877 opcode, 2878 cond, 2879 destination: block_num, 2880 args: args.into_value_list(&[arg], &mut ctx.function.dfg.value_lists), 2881 } 2882 } 2883 InstructionFormat::BranchIcmp => { 2884 let cond = self.match_enum("expected intcc condition code")?; 2885 let lhs = self.match_value("expected SSA value first operand")?; 2886 self.match_token(Token::Comma, "expected ',' between operands")?; 2887 let rhs = self.match_value("expected SSA value second operand")?; 2888 self.match_token(Token::Comma, "expected ',' between operands")?; 2889 let block_num = self.match_block("expected branch destination block")?; 2890 let args = self.parse_opt_value_list()?; 2891 InstructionData::BranchIcmp { 2892 opcode, 2893 cond, 2894 destination: block_num, 2895 args: args.into_value_list(&[lhs, rhs], &mut ctx.function.dfg.value_lists), 2896 } 2897 } 2898 InstructionFormat::BranchTable => { 2899 let arg = self.match_value("expected SSA value operand")?; 2900 self.match_token(Token::Comma, "expected ',' between operands")?; 2901 let block_num = self.match_block("expected branch destination block")?; 2902 self.match_token(Token::Comma, "expected ',' between operands")?; 2903 let table = self.match_jt()?; 2904 ctx.check_jt(table, self.loc)?; 2905 InstructionData::BranchTable { 2906 opcode, 2907 arg, 2908 destination: block_num, 2909 table, 2910 } 2911 } 2912 InstructionFormat::BranchTableBase => { 2913 let table = self.match_jt()?; 2914 ctx.check_jt(table, self.loc)?; 2915 InstructionData::BranchTableBase { opcode, table } 2916 } 2917 InstructionFormat::BranchTableEntry => { 2918 let index = self.match_value("expected SSA value operand")?; 2919 self.match_token(Token::Comma, "expected ',' between operands")?; 2920 let base = self.match_value("expected SSA value operand")?; 2921 self.match_token(Token::Comma, "expected ',' between operands")?; 2922 let imm = self.match_uimm8("expected width")?; 2923 self.match_token(Token::Comma, "expected ',' between operands")?; 2924 let table = self.match_jt()?; 2925 ctx.check_jt(table, self.loc)?; 2926 InstructionData::BranchTableEntry { 2927 opcode, 2928 args: [index, base], 2929 imm, 2930 table, 2931 } 2932 } 2933 InstructionFormat::IndirectJump => { 2934 let arg = self.match_value("expected SSA value operand")?; 2935 self.match_token(Token::Comma, "expected ',' between operands")?; 2936 let table = self.match_jt()?; 2937 ctx.check_jt(table, self.loc)?; 2938 InstructionData::IndirectJump { opcode, arg, table } 2939 } 2940 InstructionFormat::TernaryImm8 => { 2941 let lhs = self.match_value("expected SSA value first operand")?; 2942 self.match_token(Token::Comma, "expected ',' between operands")?; 2943 let rhs = self.match_value("expected SSA value last operand")?; 2944 self.match_token(Token::Comma, "expected ',' between operands")?; 2945 let imm = self.match_uimm8("expected 8-bit immediate")?; 2946 InstructionData::TernaryImm8 { 2947 opcode, 2948 imm, 2949 args: [lhs, rhs], 2950 } 2951 } 2952 InstructionFormat::Shuffle => { 2953 let a = self.match_value("expected SSA value first operand")?; 2954 self.match_token(Token::Comma, "expected ',' between operands")?; 2955 let b = self.match_value("expected SSA value second operand")?; 2956 self.match_token(Token::Comma, "expected ',' between operands")?; 2957 let uimm128 = self.match_uimm128(I8X16)?; 2958 let mask = ctx.function.dfg.immediates.push(uimm128); 2959 InstructionData::Shuffle { 2960 opcode, 2961 mask, 2962 args: [a, b], 2963 } 2964 } 2965 InstructionFormat::IntCompare => { 2966 let cond = self.match_enum("expected intcc condition code")?; 2967 let lhs = self.match_value("expected SSA value first operand")?; 2968 self.match_token(Token::Comma, "expected ',' between operands")?; 2969 let rhs = self.match_value("expected SSA value second operand")?; 2970 InstructionData::IntCompare { 2971 opcode, 2972 cond, 2973 args: [lhs, rhs], 2974 } 2975 } 2976 InstructionFormat::IntCompareImm => { 2977 let cond = self.match_enum("expected intcc condition code")?; 2978 let lhs = self.match_value("expected SSA value first operand")?; 2979 self.match_token(Token::Comma, "expected ',' between operands")?; 2980 let rhs = self.match_imm64("expected immediate second operand")?; 2981 InstructionData::IntCompareImm { 2982 opcode, 2983 cond, 2984 arg: lhs, 2985 imm: rhs, 2986 } 2987 } 2988 InstructionFormat::IntCond => { 2989 let cond = self.match_enum("expected intcc condition code")?; 2990 let arg = self.match_value("expected SSA value")?; 2991 InstructionData::IntCond { opcode, cond, arg } 2992 } 2993 InstructionFormat::FloatCompare => { 2994 let cond = self.match_enum("expected floatcc condition code")?; 2995 let lhs = self.match_value("expected SSA value first operand")?; 2996 self.match_token(Token::Comma, "expected ',' between operands")?; 2997 let rhs = self.match_value("expected SSA value second operand")?; 2998 InstructionData::FloatCompare { 2999 opcode, 3000 cond, 3001 args: [lhs, rhs], 3002 } 3003 } 3004 InstructionFormat::FloatCond => { 3005 let cond = self.match_enum("expected floatcc condition code")?; 3006 let arg = self.match_value("expected SSA value")?; 3007 InstructionData::FloatCond { opcode, cond, arg } 3008 } 3009 InstructionFormat::IntSelect => { 3010 let cond = self.match_enum("expected intcc condition code")?; 3011 let guard = self.match_value("expected SSA value first operand")?; 3012 self.match_token(Token::Comma, "expected ',' between operands")?; 3013 let v_true = self.match_value("expected SSA value second operand")?; 3014 self.match_token(Token::Comma, "expected ',' between operands")?; 3015 let v_false = self.match_value("expected SSA value third operand")?; 3016 InstructionData::IntSelect { 3017 opcode, 3018 cond, 3019 args: [guard, v_true, v_false], 3020 } 3021 } 3022 InstructionFormat::Call => { 3023 let func_ref = self.match_fn("expected function reference")?; 3024 ctx.check_fn(func_ref, self.loc)?; 3025 self.match_token(Token::LPar, "expected '(' before arguments")?; 3026 let args = self.parse_value_list()?; 3027 self.match_token(Token::RPar, "expected ')' after arguments")?; 3028 InstructionData::Call { 3029 opcode, 3030 func_ref, 3031 args: args.into_value_list(&[], &mut ctx.function.dfg.value_lists), 3032 } 3033 } 3034 InstructionFormat::CallIndirect => { 3035 let sig_ref = self.match_sig("expected signature reference")?; 3036 ctx.check_sig(sig_ref, self.loc)?; 3037 self.match_token(Token::Comma, "expected ',' between operands")?; 3038 let callee = self.match_value("expected SSA value callee operand")?; 3039 self.match_token(Token::LPar, "expected '(' before arguments")?; 3040 let args = self.parse_value_list()?; 3041 self.match_token(Token::RPar, "expected ')' after arguments")?; 3042 InstructionData::CallIndirect { 3043 opcode, 3044 sig_ref, 3045 args: args.into_value_list(&[callee], &mut ctx.function.dfg.value_lists), 3046 } 3047 } 3048 InstructionFormat::FuncAddr => { 3049 let func_ref = self.match_fn("expected function reference")?; 3050 ctx.check_fn(func_ref, self.loc)?; 3051 InstructionData::FuncAddr { opcode, func_ref } 3052 } 3053 InstructionFormat::StackLoad => { 3054 let ss = self.match_ss("expected stack slot number: ss«n»")?; 3055 ctx.check_ss(ss, self.loc)?; 3056 let offset = self.optional_offset32()?; 3057 InstructionData::StackLoad { 3058 opcode, 3059 stack_slot: ss, 3060 offset, 3061 } 3062 } 3063 InstructionFormat::StackStore => { 3064 let arg = self.match_value("expected SSA value operand")?; 3065 self.match_token(Token::Comma, "expected ',' between operands")?; 3066 let ss = self.match_ss("expected stack slot number: ss«n»")?; 3067 ctx.check_ss(ss, self.loc)?; 3068 let offset = self.optional_offset32()?; 3069 InstructionData::StackStore { 3070 opcode, 3071 arg, 3072 stack_slot: ss, 3073 offset, 3074 } 3075 } 3076 InstructionFormat::HeapAddr => { 3077 let heap = self.match_heap("expected heap identifier")?; 3078 ctx.check_heap(heap, self.loc)?; 3079 self.match_token(Token::Comma, "expected ',' between operands")?; 3080 let arg = self.match_value("expected SSA value heap address")?; 3081 self.match_token(Token::Comma, "expected ',' between operands")?; 3082 let imm = self.match_uimm32("expected 32-bit integer size")?; 3083 InstructionData::HeapAddr { 3084 opcode, 3085 heap, 3086 arg, 3087 imm, 3088 } 3089 } 3090 InstructionFormat::TableAddr => { 3091 let table = self.match_table("expected table identifier")?; 3092 ctx.check_table(table, self.loc)?; 3093 self.match_token(Token::Comma, "expected ',' between operands")?; 3094 let arg = self.match_value("expected SSA value table address")?; 3095 self.match_token(Token::Comma, "expected ',' between operands")?; 3096 let offset = self.optional_offset32()?; 3097 InstructionData::TableAddr { 3098 opcode, 3099 table, 3100 arg, 3101 offset, 3102 } 3103 } 3104 InstructionFormat::Load => { 3105 let flags = self.optional_memflags(); 3106 let addr = self.match_value("expected SSA value address")?; 3107 let offset = self.optional_offset32()?; 3108 InstructionData::Load { 3109 opcode, 3110 flags, 3111 arg: addr, 3112 offset, 3113 } 3114 } 3115 InstructionFormat::LoadComplex => { 3116 let flags = self.optional_memflags(); 3117 let args = self.parse_value_sequence()?; 3118 let offset = self.optional_offset32()?; 3119 InstructionData::LoadComplex { 3120 opcode, 3121 flags, 3122 args: args.into_value_list(&[], &mut ctx.function.dfg.value_lists), 3123 offset, 3124 } 3125 } 3126 InstructionFormat::Store => { 3127 let flags = self.optional_memflags(); 3128 let arg = self.match_value("expected SSA value operand")?; 3129 self.match_token(Token::Comma, "expected ',' between operands")?; 3130 let addr = self.match_value("expected SSA value address")?; 3131 let offset = self.optional_offset32()?; 3132 InstructionData::Store { 3133 opcode, 3134 flags, 3135 args: [arg, addr], 3136 offset, 3137 } 3138 } 3139 3140 InstructionFormat::StoreComplex => { 3141 let flags = self.optional_memflags(); 3142 let src = self.match_value("expected SSA value operand")?; 3143 self.match_token(Token::Comma, "expected ',' between operands")?; 3144 let args = self.parse_value_sequence()?; 3145 let offset = self.optional_offset32()?; 3146 InstructionData::StoreComplex { 3147 opcode, 3148 flags, 3149 args: args.into_value_list(&[src], &mut ctx.function.dfg.value_lists), 3150 offset, 3151 } 3152 } 3153 InstructionFormat::RegMove => { 3154 let arg = self.match_value("expected SSA value operand")?; 3155 self.match_token(Token::Comma, "expected ',' between operands")?; 3156 let src = self.match_regunit(ctx.unique_isa)?; 3157 self.match_token(Token::Arrow, "expected '->' between register units")?; 3158 let dst = self.match_regunit(ctx.unique_isa)?; 3159 InstructionData::RegMove { 3160 opcode, 3161 arg, 3162 src, 3163 dst, 3164 } 3165 } 3166 InstructionFormat::CopySpecial => { 3167 let src = self.match_regunit(ctx.unique_isa)?; 3168 self.match_token(Token::Arrow, "expected '->' between register units")?; 3169 let dst = self.match_regunit(ctx.unique_isa)?; 3170 InstructionData::CopySpecial { opcode, src, dst } 3171 } 3172 InstructionFormat::CopyToSsa => InstructionData::CopyToSsa { 3173 opcode, 3174 src: self.match_regunit(ctx.unique_isa)?, 3175 }, 3176 InstructionFormat::RegSpill => { 3177 let arg = self.match_value("expected SSA value operand")?; 3178 self.match_token(Token::Comma, "expected ',' between operands")?; 3179 let src = self.match_regunit(ctx.unique_isa)?; 3180 self.match_token(Token::Arrow, "expected '->' before destination stack slot")?; 3181 let dst = self.match_ss("expected stack slot number: ss«n»")?; 3182 ctx.check_ss(dst, self.loc)?; 3183 InstructionData::RegSpill { 3184 opcode, 3185 arg, 3186 src, 3187 dst, 3188 } 3189 } 3190 InstructionFormat::RegFill => { 3191 let arg = self.match_value("expected SSA value operand")?; 3192 self.match_token(Token::Comma, "expected ',' between operands")?; 3193 let src = self.match_ss("expected stack slot number: ss«n»")?; 3194 ctx.check_ss(src, self.loc)?; 3195 self.match_token( 3196 Token::Arrow, 3197 "expected '->' before destination register units", 3198 )?; 3199 let dst = self.match_regunit(ctx.unique_isa)?; 3200 InstructionData::RegFill { 3201 opcode, 3202 arg, 3203 src, 3204 dst, 3205 } 3206 } 3207 InstructionFormat::Trap => { 3208 let code = self.match_enum("expected trap code")?; 3209 InstructionData::Trap { opcode, code } 3210 } 3211 InstructionFormat::CondTrap => { 3212 let arg = self.match_value("expected SSA value operand")?; 3213 self.match_token(Token::Comma, "expected ',' between operands")?; 3214 let code = self.match_enum("expected trap code")?; 3215 InstructionData::CondTrap { opcode, arg, code } 3216 } 3217 InstructionFormat::IntCondTrap => { 3218 let cond = self.match_enum("expected intcc condition code")?; 3219 let arg = self.match_value("expected SSA value operand")?; 3220 self.match_token(Token::Comma, "expected ',' between operands")?; 3221 let code = self.match_enum("expected trap code")?; 3222 InstructionData::IntCondTrap { 3223 opcode, 3224 cond, 3225 arg, 3226 code, 3227 } 3228 } 3229 InstructionFormat::FloatCondTrap => { 3230 let cond = self.match_enum("expected floatcc condition code")?; 3231 let arg = self.match_value("expected SSA value operand")?; 3232 self.match_token(Token::Comma, "expected ',' between operands")?; 3233 let code = self.match_enum("expected trap code")?; 3234 InstructionData::FloatCondTrap { 3235 opcode, 3236 cond, 3237 arg, 3238 code, 3239 } 3240 } 3241 InstructionFormat::AtomicCas => { 3242 let flags = self.optional_memflags(); 3243 let addr = self.match_value("expected SSA value address")?; 3244 self.match_token(Token::Comma, "expected ',' between operands")?; 3245 let expected = self.match_value("expected SSA value address")?; 3246 self.match_token(Token::Comma, "expected ',' between operands")?; 3247 let replacement = self.match_value("expected SSA value address")?; 3248 InstructionData::AtomicCas { 3249 opcode, 3250 flags, 3251 args: [addr, expected, replacement], 3252 } 3253 } 3254 InstructionFormat::AtomicRmw => { 3255 let flags = self.optional_memflags(); 3256 let op = self.match_enum("expected AtomicRmwOp")?; 3257 let addr = self.match_value("expected SSA value address")?; 3258 self.match_token(Token::Comma, "expected ',' between operands")?; 3259 let arg2 = self.match_value("expected SSA value address")?; 3260 InstructionData::AtomicRmw { 3261 opcode, 3262 flags, 3263 op, 3264 args: [addr, arg2], 3265 } 3266 } 3267 InstructionFormat::LoadNoOffset => { 3268 let flags = self.optional_memflags(); 3269 let addr = self.match_value("expected SSA value address")?; 3270 InstructionData::LoadNoOffset { 3271 opcode, 3272 flags, 3273 arg: addr, 3274 } 3275 } 3276 InstructionFormat::StoreNoOffset => { 3277 let flags = self.optional_memflags(); 3278 let arg = self.match_value("expected SSA value operand")?; 3279 self.match_token(Token::Comma, "expected ',' between operands")?; 3280 let addr = self.match_value("expected SSA value address")?; 3281 InstructionData::StoreNoOffset { 3282 opcode, 3283 flags, 3284 args: [arg, addr], 3285 } 3286 } 3287 }; 3288 Ok(idata) 3289 } 3290 } 3291 3292 #[cfg(test)] 3293 mod tests { 3294 use super::*; 3295 use crate::error::ParseError; 3296 use crate::isaspec::IsaSpec; 3297 use crate::testfile::{Comment, Details}; 3298 use cranelift_codegen::ir::entities::AnyEntity; 3299 use cranelift_codegen::ir::types; 3300 use cranelift_codegen::ir::StackSlotKind; 3301 use cranelift_codegen::ir::{ArgumentExtension, ArgumentPurpose}; 3302 use cranelift_codegen::isa::CallConv; 3303 3304 #[test] 3305 fn argument_type() { 3306 let mut p = Parser::new("i32 sext"); 3307 let arg = p.parse_abi_param(None).unwrap(); 3308 assert_eq!(arg.value_type, types::I32); 3309 assert_eq!(arg.extension, ArgumentExtension::Sext); 3310 assert_eq!(arg.purpose, ArgumentPurpose::Normal); 3311 let ParseError { 3312 location, 3313 message, 3314 is_warning, 3315 } = p.parse_abi_param(None).unwrap_err(); 3316 assert_eq!(location.line_number, 1); 3317 assert_eq!(message, "expected parameter type"); 3318 assert!(!is_warning); 3319 } 3320 3321 #[test] 3322 fn aliases() { 3323 let (func, details) = Parser::new( 3324 "function %qux() system_v { 3325 block0: 3326 v4 = iconst.i8 6 3327 v3 -> v4 3328 v1 = iadd_imm v3, 17 3329 }", 3330 ) 3331 .parse_function(None) 3332 .unwrap(); 3333 assert_eq!(func.name.to_string(), "%qux"); 3334 let v4 = details.map.lookup_str("v4").unwrap(); 3335 assert_eq!(v4.to_string(), "v4"); 3336 let v3 = details.map.lookup_str("v3").unwrap(); 3337 assert_eq!(v3.to_string(), "v3"); 3338 match v3 { 3339 AnyEntity::Value(v3) => { 3340 let aliased_to = func.dfg.resolve_aliases(v3); 3341 assert_eq!(aliased_to.to_string(), "v4"); 3342 } 3343 _ => panic!("expected value: {}", v3), 3344 } 3345 } 3346 3347 #[test] 3348 fn signature() { 3349 let sig = Parser::new("()system_v").parse_signature(None).unwrap(); 3350 assert_eq!(sig.params.len(), 0); 3351 assert_eq!(sig.returns.len(), 0); 3352 assert_eq!(sig.call_conv, CallConv::SystemV); 3353 3354 let sig2 = Parser::new("(i8 uext, f32, f64, i32 sret) -> i32 sext, f64 baldrdash_system_v") 3355 .parse_signature(None) 3356 .unwrap(); 3357 assert_eq!( 3358 sig2.to_string(), 3359 "(i8 uext, f32, f64, i32 sret) -> i32 sext, f64 baldrdash_system_v" 3360 ); 3361 assert_eq!(sig2.call_conv, CallConv::BaldrdashSystemV); 3362 3363 // Old-style signature without a calling convention. 3364 assert_eq!( 3365 Parser::new("()").parse_signature(None).unwrap().to_string(), 3366 "() fast" 3367 ); 3368 assert_eq!( 3369 Parser::new("() notacc") 3370 .parse_signature(None) 3371 .unwrap_err() 3372 .to_string(), 3373 "1: unknown calling convention: notacc" 3374 ); 3375 3376 // `void` is not recognized as a type by the lexer. It should not appear in files. 3377 assert_eq!( 3378 Parser::new("() -> void") 3379 .parse_signature(None) 3380 .unwrap_err() 3381 .to_string(), 3382 "1: expected parameter type" 3383 ); 3384 assert_eq!( 3385 Parser::new("i8 -> i8") 3386 .parse_signature(None) 3387 .unwrap_err() 3388 .to_string(), 3389 "1: expected function signature: ( args... )" 3390 ); 3391 assert_eq!( 3392 Parser::new("(i8 -> i8") 3393 .parse_signature(None) 3394 .unwrap_err() 3395 .to_string(), 3396 "1: expected ')' after function arguments" 3397 ); 3398 } 3399 3400 #[test] 3401 fn stack_slot_decl() { 3402 let (func, _) = Parser::new( 3403 "function %foo() system_v { 3404 ss3 = incoming_arg 13 3405 ss1 = spill_slot 1 3406 }", 3407 ) 3408 .parse_function(None) 3409 .unwrap(); 3410 assert_eq!(func.name.to_string(), "%foo"); 3411 let mut iter = func.stack_slots.keys(); 3412 let _ss0 = iter.next().unwrap(); 3413 let ss1 = iter.next().unwrap(); 3414 assert_eq!(ss1.to_string(), "ss1"); 3415 assert_eq!(func.stack_slots[ss1].kind, StackSlotKind::SpillSlot); 3416 assert_eq!(func.stack_slots[ss1].size, 1); 3417 let _ss2 = iter.next().unwrap(); 3418 let ss3 = iter.next().unwrap(); 3419 assert_eq!(ss3.to_string(), "ss3"); 3420 assert_eq!(func.stack_slots[ss3].kind, StackSlotKind::IncomingArg); 3421 assert_eq!(func.stack_slots[ss3].size, 13); 3422 assert_eq!(iter.next(), None); 3423 3424 // Catch duplicate definitions. 3425 assert_eq!( 3426 Parser::new( 3427 "function %bar() system_v { 3428 ss1 = spill_slot 13 3429 ss1 = spill_slot 1 3430 }", 3431 ) 3432 .parse_function(None) 3433 .unwrap_err() 3434 .to_string(), 3435 "3: duplicate entity: ss1" 3436 ); 3437 } 3438 3439 #[test] 3440 fn block_header() { 3441 let (func, _) = Parser::new( 3442 "function %blocks() system_v { 3443 block0: 3444 block4(v3: i32): 3445 }", 3446 ) 3447 .parse_function(None) 3448 .unwrap(); 3449 assert_eq!(func.name.to_string(), "%blocks"); 3450 3451 let mut blocks = func.layout.blocks(); 3452 3453 let block0 = blocks.next().unwrap(); 3454 assert_eq!(func.dfg.block_params(block0), &[]); 3455 3456 let block4 = blocks.next().unwrap(); 3457 let block4_args = func.dfg.block_params(block4); 3458 assert_eq!(block4_args.len(), 1); 3459 assert_eq!(func.dfg.value_type(block4_args[0]), types::I32); 3460 } 3461 3462 #[test] 3463 fn duplicate_block() { 3464 let ParseError { 3465 location, 3466 message, 3467 is_warning, 3468 } = Parser::new( 3469 "function %blocks() system_v { 3470 block0: 3471 block0: 3472 return 2", 3473 ) 3474 .parse_function(None) 3475 .unwrap_err(); 3476 3477 assert_eq!(location.line_number, 3); 3478 assert_eq!(message, "duplicate entity: block0"); 3479 assert!(!is_warning); 3480 } 3481 3482 #[test] 3483 fn number_of_blocks() { 3484 let ParseError { 3485 location, 3486 message, 3487 is_warning, 3488 } = Parser::new( 3489 "function %a() { 3490 block100000:", 3491 ) 3492 .parse_function(None) 3493 .unwrap_err(); 3494 3495 assert_eq!(location.line_number, 2); 3496 assert_eq!(message, "too many blocks"); 3497 assert!(!is_warning); 3498 } 3499 3500 #[test] 3501 fn duplicate_jt() { 3502 let ParseError { 3503 location, 3504 message, 3505 is_warning, 3506 } = Parser::new( 3507 "function %blocks() system_v { 3508 jt0 = jump_table [] 3509 jt0 = jump_table []", 3510 ) 3511 .parse_function(None) 3512 .unwrap_err(); 3513 3514 assert_eq!(location.line_number, 3); 3515 assert_eq!(message, "duplicate entity: jt0"); 3516 assert!(!is_warning); 3517 } 3518 3519 #[test] 3520 fn duplicate_ss() { 3521 let ParseError { 3522 location, 3523 message, 3524 is_warning, 3525 } = Parser::new( 3526 "function %blocks() system_v { 3527 ss0 = explicit_slot 8 3528 ss0 = explicit_slot 8", 3529 ) 3530 .parse_function(None) 3531 .unwrap_err(); 3532 3533 assert_eq!(location.line_number, 3); 3534 assert_eq!(message, "duplicate entity: ss0"); 3535 assert!(!is_warning); 3536 } 3537 3538 #[test] 3539 fn duplicate_gv() { 3540 let ParseError { 3541 location, 3542 message, 3543 is_warning, 3544 } = Parser::new( 3545 "function %blocks() system_v { 3546 gv0 = vmctx 3547 gv0 = vmctx", 3548 ) 3549 .parse_function(None) 3550 .unwrap_err(); 3551 3552 assert_eq!(location.line_number, 3); 3553 assert_eq!(message, "duplicate entity: gv0"); 3554 assert!(!is_warning); 3555 } 3556 3557 #[test] 3558 fn duplicate_heap() { 3559 let ParseError { 3560 location, 3561 message, 3562 is_warning, 3563 } = Parser::new( 3564 "function %blocks() system_v { 3565 heap0 = static gv0, min 0x1000, bound 0x10_0000, offset_guard 0x1000 3566 heap0 = static gv0, min 0x1000, bound 0x10_0000, offset_guard 0x1000", 3567 ) 3568 .parse_function(None) 3569 .unwrap_err(); 3570 3571 assert_eq!(location.line_number, 3); 3572 assert_eq!(message, "duplicate entity: heap0"); 3573 assert!(!is_warning); 3574 } 3575 3576 #[test] 3577 fn duplicate_sig() { 3578 let ParseError { 3579 location, 3580 message, 3581 is_warning, 3582 } = Parser::new( 3583 "function %blocks() system_v { 3584 sig0 = () 3585 sig0 = ()", 3586 ) 3587 .parse_function(None) 3588 .unwrap_err(); 3589 3590 assert_eq!(location.line_number, 3); 3591 assert_eq!(message, "duplicate entity: sig0"); 3592 assert!(!is_warning); 3593 } 3594 3595 #[test] 3596 fn duplicate_fn() { 3597 let ParseError { 3598 location, 3599 message, 3600 is_warning, 3601 } = Parser::new( 3602 "function %blocks() system_v { 3603 sig0 = () 3604 fn0 = %foo sig0 3605 fn0 = %foo sig0", 3606 ) 3607 .parse_function(None) 3608 .unwrap_err(); 3609 3610 assert_eq!(location.line_number, 4); 3611 assert_eq!(message, "duplicate entity: fn0"); 3612 assert!(!is_warning); 3613 } 3614 3615 #[test] 3616 fn comments() { 3617 let (func, Details { comments, .. }) = Parser::new( 3618 "; before 3619 function %comment() system_v { ; decl 3620 ss10 = outgoing_arg 13 ; stackslot. 3621 ; Still stackslot. 3622 jt10 = jump_table [block0] 3623 ; Jumptable 3624 block0: ; Basic block 3625 trap user42; Instruction 3626 } ; Trailing. 3627 ; More trailing.", 3628 ) 3629 .parse_function(None) 3630 .unwrap(); 3631 assert_eq!(func.name.to_string(), "%comment"); 3632 assert_eq!(comments.len(), 8); // no 'before' comment. 3633 assert_eq!( 3634 comments[0], 3635 Comment { 3636 entity: AnyEntity::Function, 3637 text: "; decl", 3638 } 3639 ); 3640 assert_eq!(comments[1].entity.to_string(), "ss10"); 3641 assert_eq!(comments[2].entity.to_string(), "ss10"); 3642 assert_eq!(comments[2].text, "; Still stackslot."); 3643 assert_eq!(comments[3].entity.to_string(), "jt10"); 3644 assert_eq!(comments[3].text, "; Jumptable"); 3645 assert_eq!(comments[4].entity.to_string(), "block0"); 3646 assert_eq!(comments[4].text, "; Basic block"); 3647 3648 assert_eq!(comments[5].entity.to_string(), "inst0"); 3649 assert_eq!(comments[5].text, "; Instruction"); 3650 3651 assert_eq!(comments[6].entity, AnyEntity::Function); 3652 assert_eq!(comments[7].entity, AnyEntity::Function); 3653 } 3654 3655 #[test] 3656 fn test_file() { 3657 let tf = parse_test( 3658 r#"; before 3659 test cfg option=5 3660 test verify 3661 set enable_float=false 3662 feature "foo" 3663 feature !"bar" 3664 ; still preamble 3665 function %comment() system_v {}"#, 3666 ParseOptions::default(), 3667 ) 3668 .unwrap(); 3669 assert_eq!(tf.commands.len(), 2); 3670 assert_eq!(tf.commands[0].command, "cfg"); 3671 assert_eq!(tf.commands[1].command, "verify"); 3672 match tf.isa_spec { 3673 IsaSpec::None(s) => { 3674 assert!(s.enable_verifier()); 3675 assert!(!s.enable_float()); 3676 } 3677 _ => panic!("unexpected ISAs"), 3678 } 3679 assert_eq!(tf.features[0], Feature::With(&"foo")); 3680 assert_eq!(tf.features[1], Feature::Without(&"bar")); 3681 assert_eq!(tf.preamble_comments.len(), 2); 3682 assert_eq!(tf.preamble_comments[0].text, "; before"); 3683 assert_eq!(tf.preamble_comments[1].text, "; still preamble"); 3684 assert_eq!(tf.functions.len(), 1); 3685 assert_eq!(tf.functions[0].0.name.to_string(), "%comment"); 3686 } 3687 3688 #[test] 3689 fn isa_spec() { 3690 assert!(parse_test( 3691 "target 3692 function %foo() system_v {}", 3693 ParseOptions::default() 3694 ) 3695 .is_err()); 3696 3697 assert!(parse_test( 3698 "target x86_64 3699 set enable_float=false 3700 function %foo() system_v {}", 3701 ParseOptions::default() 3702 ) 3703 .is_err()); 3704 3705 match parse_test( 3706 "set enable_float=false 3707 target x86_64 3708 function %foo() system_v {}", 3709 ParseOptions::default(), 3710 ) 3711 .unwrap() 3712 .isa_spec 3713 { 3714 IsaSpec::None(_) => panic!("Expected some ISA"), 3715 IsaSpec::Some(v) => { 3716 assert_eq!(v.len(), 1); 3717 #[cfg(not(feature = "experimental_x64"))] 3718 assert_eq!(v[0].name(), "x86"); 3719 #[cfg(feature = "experimental_x64")] 3720 assert_eq!(v[0].name(), "x64"); 3721 } 3722 } 3723 } 3724 3725 #[test] 3726 fn user_function_name() { 3727 // Valid characters in the name: 3728 let func = Parser::new( 3729 "function u1:2() system_v { 3730 block0: 3731 trap int_divz 3732 }", 3733 ) 3734 .parse_function(None) 3735 .unwrap() 3736 .0; 3737 assert_eq!(func.name.to_string(), "u1:2"); 3738 3739 // Invalid characters in the name: 3740 let mut parser = Parser::new( 3741 "function u123:abc() system_v { 3742 block0: 3743 trap stk_ovf 3744 }", 3745 ); 3746 assert!(parser.parse_function(None).is_err()); 3747 3748 // Incomplete function names should not be valid: 3749 let mut parser = Parser::new( 3750 "function u() system_v { 3751 block0: 3752 trap int_ovf 3753 }", 3754 ); 3755 assert!(parser.parse_function(None).is_err()); 3756 3757 let mut parser = Parser::new( 3758 "function u0() system_v { 3759 block0: 3760 trap int_ovf 3761 }", 3762 ); 3763 assert!(parser.parse_function(None).is_err()); 3764 3765 let mut parser = Parser::new( 3766 "function u0:() system_v { 3767 block0: 3768 trap int_ovf 3769 }", 3770 ); 3771 assert!(parser.parse_function(None).is_err()); 3772 } 3773 3774 #[test] 3775 fn change_default_calling_convention() { 3776 let code = "function %test() { 3777 block0: 3778 return 3779 }"; 3780 3781 // By default the parser will use the fast calling convention if none is specified. 3782 let mut parser = Parser::new(code); 3783 assert_eq!( 3784 parser.parse_function(None).unwrap().0.signature.call_conv, 3785 CallConv::Fast 3786 ); 3787 3788 // However, we can specify a different calling convention to be the default. 3789 let mut parser = Parser::new(code).with_default_calling_convention(CallConv::Cold); 3790 assert_eq!( 3791 parser.parse_function(None).unwrap().0.signature.call_conv, 3792 CallConv::Cold 3793 ); 3794 } 3795 3796 #[test] 3797 fn u8_as_hex() { 3798 fn parse_as_uimm8(text: &str) -> ParseResult<u8> { 3799 Parser::new(text).match_uimm8("unable to parse u8") 3800 } 3801 3802 assert_eq!(parse_as_uimm8("0").unwrap(), 0); 3803 assert_eq!(parse_as_uimm8("0xff").unwrap(), 255); 3804 assert!(parse_as_uimm8("-1").is_err()); 3805 assert!(parse_as_uimm8("0xffa").is_err()); 3806 } 3807 3808 #[test] 3809 fn i16_as_hex() { 3810 fn parse_as_imm16(text: &str) -> ParseResult<i16> { 3811 Parser::new(text).match_imm16("unable to parse i16") 3812 } 3813 3814 assert_eq!(parse_as_imm16("0x8000").unwrap(), -32768); 3815 assert_eq!(parse_as_imm16("0xffff").unwrap(), -1); 3816 assert_eq!(parse_as_imm16("0").unwrap(), 0); 3817 assert_eq!(parse_as_imm16("0x7fff").unwrap(), 32767); 3818 assert_eq!( 3819 parse_as_imm16("-0x0001").unwrap(), 3820 parse_as_imm16("0xffff").unwrap() 3821 ); 3822 assert_eq!( 3823 parse_as_imm16("-0x7fff").unwrap(), 3824 parse_as_imm16("0x8001").unwrap() 3825 ); 3826 assert!(parse_as_imm16("0xffffa").is_err()); 3827 } 3828 3829 #[test] 3830 fn i32_as_hex() { 3831 fn parse_as_imm32(text: &str) -> ParseResult<i32> { 3832 Parser::new(text).match_imm32("unable to parse i32") 3833 } 3834 3835 assert_eq!(parse_as_imm32("0x80000000").unwrap(), -2147483648); 3836 assert_eq!(parse_as_imm32("0xffffffff").unwrap(), -1); 3837 assert_eq!(parse_as_imm32("0").unwrap(), 0); 3838 assert_eq!(parse_as_imm32("0x7fffffff").unwrap(), 2147483647); 3839 assert_eq!( 3840 parse_as_imm32("-0x00000001").unwrap(), 3841 parse_as_imm32("0xffffffff").unwrap() 3842 ); 3843 assert_eq!( 3844 parse_as_imm32("-0x7fffffff").unwrap(), 3845 parse_as_imm32("0x80000001").unwrap() 3846 ); 3847 assert!(parse_as_imm32("0xffffffffa").is_err()); 3848 } 3849 3850 #[test] 3851 fn i64_as_hex() { 3852 fn parse_as_imm64(text: &str) -> ParseResult<Imm64> { 3853 Parser::new(text).match_imm64("unable to parse Imm64") 3854 } 3855 3856 assert_eq!( 3857 parse_as_imm64("0x8000000000000000").unwrap(), 3858 Imm64::new(-9223372036854775808) 3859 ); 3860 assert_eq!( 3861 parse_as_imm64("0xffffffffffffffff").unwrap(), 3862 Imm64::new(-1) 3863 ); 3864 assert_eq!(parse_as_imm64("0").unwrap(), Imm64::new(0)); 3865 assert_eq!( 3866 parse_as_imm64("0x7fffffffffffffff").unwrap(), 3867 Imm64::new(9223372036854775807) 3868 ); 3869 assert_eq!( 3870 parse_as_imm64("-0x0000000000000001").unwrap(), 3871 parse_as_imm64("0xffffffffffffffff").unwrap() 3872 ); 3873 assert_eq!( 3874 parse_as_imm64("-0x7fffffffffffffff").unwrap(), 3875 parse_as_imm64("0x8000000000000001").unwrap() 3876 ); 3877 assert!(parse_as_imm64("0xffffffffffffffffa").is_err()); 3878 } 3879 3880 #[test] 3881 fn uimm128() { 3882 macro_rules! parse_as_constant_data { 3883 ($text:expr, $type:expr) => {{ 3884 Parser::new($text).parse_literals_to_constant_data($type) 3885 }}; 3886 } 3887 macro_rules! can_parse_as_constant_data { 3888 ($text:expr, $type:expr) => {{ 3889 assert!(parse_as_constant_data!($text, $type).is_ok()) 3890 }}; 3891 } 3892 macro_rules! cannot_parse_as_constant_data { 3893 ($text:expr, $type:expr) => {{ 3894 assert!(parse_as_constant_data!($text, $type).is_err()) 3895 }}; 3896 } 3897 3898 can_parse_as_constant_data!("1 2 3 4", I32X4); 3899 can_parse_as_constant_data!("1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16", I8X16); 3900 can_parse_as_constant_data!("0x1.1 0x2.2 0x3.3 0x4.4", F32X4); 3901 can_parse_as_constant_data!("0x0 0x1 0x2 0x3", I32X4); 3902 can_parse_as_constant_data!("true false true false true false true false", B16X8); 3903 can_parse_as_constant_data!("0 -1", I64X2); 3904 can_parse_as_constant_data!("true false", B64X2); 3905 can_parse_as_constant_data!("true true true true true", B32X4); // note that parse_literals_to_constant_data will leave extra tokens unconsumed 3906 3907 cannot_parse_as_constant_data!("1 2 3", I32X4); 3908 cannot_parse_as_constant_data!(" ", F32X4); 3909 } 3910 3911 #[test] 3912 fn parse_constant_from_booleans() { 3913 let c = Parser::new("true false true false") 3914 .parse_literals_to_constant_data(B32X4) 3915 .unwrap(); 3916 assert_eq!( 3917 c.into_vec(), 3918 [0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0] 3919 ) 3920 } 3921 3922 #[test] 3923 fn parse_unbounded_constants() { 3924 // Unlike match_uimm128, match_constant_data can parse byte sequences of any size: 3925 assert_eq!( 3926 Parser::new("[0 1]").match_constant_data().unwrap(), 3927 vec![0, 1].into() 3928 ); 3929 3930 // Only parse byte literals: 3931 assert!(Parser::new("[256]").match_constant_data().is_err()); 3932 } 3933 3934 #[test] 3935 fn parse_run_commands() { 3936 // Helper for creating signatures. 3937 fn sig(ins: &[Type], outs: &[Type]) -> Signature { 3938 let mut sig = Signature::new(CallConv::Fast); 3939 for i in ins { 3940 sig.params.push(AbiParam::new(*i)); 3941 } 3942 for o in outs { 3943 sig.returns.push(AbiParam::new(*o)); 3944 } 3945 sig 3946 } 3947 3948 // Helper for parsing run commands. 3949 fn parse(text: &str, sig: &Signature) -> ParseResult<RunCommand> { 3950 Parser::new(text).parse_run_command(sig) 3951 } 3952 3953 // Check that we can parse and display the same set of run commands. 3954 fn assert_roundtrip(text: &str, sig: &Signature) { 3955 assert_eq!(parse(text, sig).unwrap().to_string(), text); 3956 } 3957 assert_roundtrip("run: %fn0() == 42", &sig(&[], &[I32])); 3958 assert_roundtrip( 3959 "run: %fn0(8, 16, 32, 64) == true", 3960 &sig(&[I8, I16, I32, I64], &[B8]), 3961 ); 3962 assert_roundtrip( 3963 "run: %my_func(true) == 0x0f0e0d0c0b0a09080706050403020100", 3964 &sig(&[B32], &[I8X16]), 3965 ); 3966 3967 // Verify that default invocations are created when not specified. 3968 assert_eq!( 3969 parse("run", &sig(&[], &[B32])).unwrap().to_string(), 3970 "run: %default() == true" 3971 ); 3972 assert_eq!( 3973 parse("print", &sig(&[], &[F32X4, I16X8])) 3974 .unwrap() 3975 .to_string(), 3976 "print: %default()" 3977 ); 3978 3979 // Demonstrate some unparseable cases. 3980 assert!(parse("print", &sig(&[I32], &[B32])).is_err()); 3981 assert!(parse("run", &sig(&[], &[I32])).is_err()); 3982 assert!(parse("print:", &sig(&[], &[])).is_err()); 3983 assert!(parse("run: ", &sig(&[], &[])).is_err()); 3984 } 3985 3986 #[test] 3987 fn parse_data_values() { 3988 fn parse(text: &str, ty: Type) -> DataValue { 3989 Parser::new(text).parse_data_value(ty).unwrap() 3990 } 3991 3992 assert_eq!(parse("8", I8).to_string(), "8"); 3993 assert_eq!(parse("16", I16).to_string(), "16"); 3994 assert_eq!(parse("32", I32).to_string(), "32"); 3995 assert_eq!(parse("64", I64).to_string(), "64"); 3996 assert_eq!(parse("0x32.32", F32).to_string(), "0x1.919000p5"); 3997 assert_eq!(parse("0x64.64", F64).to_string(), "0x1.9190000000000p6"); 3998 assert_eq!(parse("true", B1).to_string(), "true"); 3999 assert_eq!(parse("false", B64).to_string(), "false"); 4000 assert_eq!( 4001 parse("[0 1 2 3]", I32X4).to_string(), 4002 "0x00000003000000020000000100000000" 4003 ); 4004 } 4005 } 4006