Skip to main content

cranelift_reader/
parser.rs

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