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