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                F16 => consume!(ty, self.match_ieee16("Expected a 16-bit float")?),
1009                F32 => consume!(ty, self.match_ieee32("Expected a 32-bit float")?),
1010                F64 => consume!(ty, self.match_ieee64("Expected a 64-bit float")?),
1011                _ => return err!(self.loc, "Expected a type of: float, int, bool"),
1012            };
1013            Ok(constant_data)
1014        }
1015    }
1016
1017    /// Parse a list of test command passes specified in command line.
1018    pub fn parse_cmdline_passes(&mut self, passes: &'a [String]) -> Vec<TestCommand<'a>> {
1019        let mut list = Vec::new();
1020        for pass in passes {
1021            list.push(TestCommand::new(pass));
1022        }
1023        list
1024    }
1025
1026    /// Parse a list of test commands.
1027    pub fn parse_test_commands(&mut self) -> Vec<TestCommand<'a>> {
1028        let mut list = Vec::new();
1029        while self.token() == Some(Token::Identifier("test")) {
1030            list.push(TestCommand::new(self.consume_line()));
1031        }
1032        list
1033    }
1034
1035    /// Parse a target spec.
1036    ///
1037    /// Accept the target from the command line for pass command.
1038    ///
1039    fn parse_cmdline_target(&mut self, target_pass: Option<&str>) -> ParseResult<isaspec::IsaSpec> {
1040        // Were there any `target` commands specified?
1041        let mut specified_target = false;
1042
1043        let mut targets = Vec::new();
1044        let flag_builder = settings::builder();
1045
1046        if let Some(targ) = target_pass {
1047            let loc = self.loc;
1048            let triple = match Triple::from_str(targ) {
1049                Ok(triple) => triple,
1050                Err(err) => return err!(loc, err),
1051            };
1052            let isa_builder = match isa::lookup(triple) {
1053                Err(isa::LookupError::SupportDisabled) => {
1054                    return err!(loc, "support disabled target '{}'", targ);
1055                }
1056                Err(isa::LookupError::Unsupported) => {
1057                    return warn!(loc, "unsupported target '{}'", targ);
1058                }
1059                Ok(b) => b,
1060            };
1061            specified_target = true;
1062
1063            // Construct a trait object with the aggregate settings.
1064            targets.push(
1065                isa_builder
1066                    .finish(settings::Flags::new(flag_builder.clone()))
1067                    .map_err(|e| ParseError {
1068                        location: loc,
1069                        message: format!("invalid ISA flags for '{targ}': {e:?}"),
1070                        is_warning: false,
1071                    })?,
1072            );
1073        }
1074
1075        if !specified_target {
1076            // No `target` commands.
1077            Ok(isaspec::IsaSpec::None(settings::Flags::new(flag_builder)))
1078        } else {
1079            Ok(isaspec::IsaSpec::Some(targets))
1080        }
1081    }
1082
1083    /// Parse a list of target specs.
1084    ///
1085    /// Accept a mix of `target` and `set` command lines. The `set` commands are cumulative.
1086    ///
1087    fn parse_target_specs(&mut self, options: &ParseOptions) -> ParseResult<isaspec::IsaSpec> {
1088        // Were there any `target` commands?
1089        let mut seen_target = false;
1090        // Location of last `set` command since the last `target`.
1091        let mut last_set_loc = None;
1092
1093        let mut targets = Vec::new();
1094        let mut flag_builder = settings::builder();
1095
1096        let bool_to_str = |val: bool| {
1097            if val { "true" } else { "false" }
1098        };
1099
1100        // default to enabling cfg info
1101        flag_builder
1102            .set(
1103                "machine_code_cfg_info",
1104                bool_to_str(options.machine_code_cfg_info),
1105            )
1106            .expect("machine_code_cfg_info option should be present");
1107
1108        flag_builder
1109            .set("unwind_info", bool_to_str(options.unwind_info))
1110            .expect("unwind_info option should be present");
1111
1112        while let Some(Token::Identifier(command)) = self.token() {
1113            match command {
1114                "set" => {
1115                    last_set_loc = Some(self.loc);
1116                    isaspec::parse_options(
1117                        self.consume_line().trim().split_whitespace(),
1118                        &mut flag_builder,
1119                        self.loc,
1120                    )
1121                    .map_err(|err| ParseError::from(err))?;
1122                }
1123                "target" => {
1124                    let loc = self.loc;
1125                    // Grab the whole line so the lexer won't go looking for tokens on the
1126                    // following lines.
1127                    let mut words = self.consume_line().trim().split_whitespace().peekable();
1128                    // Look for `target foo`.
1129                    let target_name = match words.next() {
1130                        Some(w) => w,
1131                        None => return err!(loc, "expected target triple"),
1132                    };
1133                    let triple = match Triple::from_str(target_name) {
1134                        Ok(triple) => triple,
1135                        Err(err) => return err!(loc, err),
1136                    };
1137                    let mut isa_builder = match isa::lookup(triple) {
1138                        Err(isa::LookupError::SupportDisabled) => {
1139                            continue;
1140                        }
1141                        Err(isa::LookupError::Unsupported) => {
1142                            return warn!(loc, "unsupported target '{}'", target_name);
1143                        }
1144                        Ok(b) => b,
1145                    };
1146                    last_set_loc = None;
1147                    seen_target = true;
1148                    // Apply the target-specific settings to `isa_builder`.
1149                    isaspec::parse_options(words, &mut isa_builder, self.loc)?;
1150
1151                    // Construct a trait object with the aggregate settings.
1152                    targets.push(
1153                        isa_builder
1154                            .finish(settings::Flags::new(flag_builder.clone()))
1155                            .map_err(|e| ParseError {
1156                                location: loc,
1157                                message: format!("invalid ISA flags for '{target_name}': {e:?}"),
1158                                is_warning: false,
1159                            })?,
1160                    );
1161                }
1162                _ => break,
1163            }
1164        }
1165
1166        if !seen_target {
1167            // No `target` commands, but we allow for `set` commands.
1168            Ok(isaspec::IsaSpec::None(settings::Flags::new(flag_builder)))
1169        } else if let Some(loc) = last_set_loc {
1170            err!(
1171                loc,
1172                "dangling 'set' command after ISA specification has no effect."
1173            )
1174        } else {
1175            Ok(isaspec::IsaSpec::Some(targets))
1176        }
1177    }
1178
1179    /// Parse a list of expected features that Cranelift should be compiled with, or without.
1180    pub fn parse_cranelift_features(&mut self) -> ParseResult<Vec<Feature<'a>>> {
1181        let mut list = Vec::new();
1182        while self.token() == Some(Token::Identifier("feature")) {
1183            self.consume();
1184            let has = !self.optional(Token::Bang);
1185            match (self.token(), has) {
1186                (Some(Token::String(flag)), true) => list.push(Feature::With(flag)),
1187                (Some(Token::String(flag)), false) => list.push(Feature::Without(flag)),
1188                (tok, _) => {
1189                    return err!(
1190                        self.loc,
1191                        format!("Expected feature flag string, got {:?}", tok)
1192                    );
1193                }
1194            }
1195            self.consume();
1196        }
1197        Ok(list)
1198    }
1199
1200    /// Parse a list of function definitions.
1201    ///
1202    /// This is the top-level parse function matching the whole contents of a file.
1203    pub fn parse_function_list(&mut self) -> ParseResult<Vec<(Function, Details<'a>)>> {
1204        let mut list = Vec::new();
1205        while self.token().is_some() {
1206            list.push(self.parse_function()?);
1207        }
1208        if let Some(err) = self.lex_error {
1209            return match err {
1210                LexError::InvalidChar => err!(self.loc, "invalid character"),
1211            };
1212        }
1213        Ok(list)
1214    }
1215
1216    // Parse a whole function definition.
1217    //
1218    // function ::= * "function" name signature "{" preamble function-body "}"
1219    //
1220    fn parse_function(&mut self) -> ParseResult<(Function, Details<'a>)> {
1221        // Begin gathering comments.
1222        // Make sure we don't include any comments before the `function` keyword.
1223        self.token();
1224        debug_assert!(self.comments.is_empty());
1225        self.start_gathering_comments();
1226
1227        self.match_identifier("function", "expected 'function'")?;
1228
1229        let location = self.loc;
1230
1231        // function ::= "function" * name signature "{" preamble function-body "}"
1232        let name = self.parse_user_func_name()?;
1233
1234        // function ::= "function" name * signature "{" preamble function-body "}"
1235        let sig = self.parse_signature()?;
1236
1237        let mut ctx = Context::new(Function::with_name_signature(name, sig));
1238
1239        // function ::= "function" name signature * "{" preamble function-body "}"
1240        self.match_token(Token::LBrace, "expected '{' before function body")?;
1241
1242        self.token();
1243        self.claim_gathered_comments(AnyEntity::Function);
1244
1245        // function ::= "function" name signature "{" * preamble function-body "}"
1246        self.parse_preamble(&mut ctx)?;
1247        // function ::= "function" name signature "{"  preamble * function-body "}"
1248        self.parse_function_body(&mut ctx)?;
1249        // function ::= "function" name signature "{" preamble function-body * "}"
1250        self.match_token(Token::RBrace, "expected '}' after function body")?;
1251
1252        // Collect any comments following the end of the function, then stop gathering comments.
1253        self.start_gathering_comments();
1254        self.token();
1255        self.claim_gathered_comments(AnyEntity::Function);
1256
1257        // Claim all the declared user-defined function names.
1258        for (user_func_ref, user_external_name) in
1259            std::mem::take(&mut self.predeclared_external_names)
1260        {
1261            let actual_ref = ctx
1262                .function
1263                .declare_imported_user_function(user_external_name);
1264            assert_eq!(user_func_ref, actual_ref);
1265        }
1266
1267        let details = Details {
1268            location,
1269            comments: self.take_comments(),
1270            map: ctx.map,
1271        };
1272
1273        Ok((ctx.function, details))
1274    }
1275
1276    // Parse a user-defined function name
1277    //
1278    // For example, in a function decl, the parser would be in this state:
1279    //
1280    // function ::= "function" * name signature { ... }
1281    //
1282    fn parse_user_func_name(&mut self) -> ParseResult<UserFuncName> {
1283        match self.token() {
1284            Some(Token::Name(s)) => {
1285                self.consume();
1286                Ok(UserFuncName::testcase(s))
1287            }
1288            Some(Token::UserRef(namespace)) => {
1289                self.consume();
1290                match self.token() {
1291                    Some(Token::Colon) => {
1292                        self.consume();
1293                        match self.token() {
1294                            Some(Token::Integer(index_str)) => {
1295                                self.consume();
1296                                let index: u32 =
1297                                    u32::from_str_radix(index_str, 10).map_err(|_| {
1298                                        self.error("the integer given overflows the u32 type")
1299                                    })?;
1300                                Ok(UserFuncName::user(namespace, index))
1301                            }
1302                            _ => err!(self.loc, "expected integer"),
1303                        }
1304                    }
1305                    _ => {
1306                        err!(self.loc, "expected user function name in the form uX:Y")
1307                    }
1308                }
1309            }
1310            _ => err!(self.loc, "expected external name"),
1311        }
1312    }
1313
1314    // Parse an external name.
1315    //
1316    // For example, in a function reference decl, the parser would be in this state:
1317    //
1318    // fn0 = * name signature
1319    //
1320    fn parse_external_name(&mut self) -> ParseResult<ExternalName> {
1321        match self.token() {
1322            Some(Token::Name(s)) => {
1323                self.consume();
1324                s.parse()
1325                    .map_err(|_| self.error("invalid test case or libcall name"))
1326            }
1327
1328            Some(Token::UserNameRef(name_ref)) => {
1329                self.consume();
1330                Ok(ExternalName::user(UserExternalNameRef::new(
1331                    name_ref as usize,
1332                )))
1333            }
1334
1335            Some(Token::UserRef(namespace)) => {
1336                self.consume();
1337                if let Some(Token::Colon) = self.token() {
1338                    self.consume();
1339                    match self.token() {
1340                        Some(Token::Integer(index_str)) => {
1341                            let index: u32 = u32::from_str_radix(index_str, 10).map_err(|_| {
1342                                self.error("the integer given overflows the u32 type")
1343                            })?;
1344                            self.consume();
1345
1346                            // Deduplicate the reference (O(n), but should be fine for tests),
1347                            // to follow `FunctionParameters::declare_imported_user_function`,
1348                            // otherwise this will cause ref mismatches when asserted below.
1349                            let name_ref = self
1350                                .predeclared_external_names
1351                                .iter()
1352                                .find_map(|(reff, name)| {
1353                                    if name.index == index && name.namespace == namespace {
1354                                        Some(reff)
1355                                    } else {
1356                                        None
1357                                    }
1358                                })
1359                                .unwrap_or_else(|| {
1360                                    self.predeclared_external_names
1361                                        .push(ir::UserExternalName { namespace, index })
1362                                });
1363
1364                            Ok(ExternalName::user(name_ref))
1365                        }
1366                        _ => err!(self.loc, "expected integer"),
1367                    }
1368                } else {
1369                    err!(self.loc, "expected colon")
1370                }
1371            }
1372
1373            _ => err!(self.loc, "expected external name"),
1374        }
1375    }
1376
1377    // Parse a function signature.
1378    //
1379    // signature ::=  * "(" [paramlist] ")" ["->" retlist] [callconv]
1380    //
1381    fn parse_signature(&mut self) -> ParseResult<Signature> {
1382        // Calling convention defaults to `fast`, but can be changed.
1383        let mut sig = Signature::new(self.default_calling_convention);
1384
1385        self.match_token(Token::LPar, "expected function signature: ( args... )")?;
1386        // signature ::=  "(" * [abi-param-list] ")" ["->" retlist] [callconv]
1387        if self.token() != Some(Token::RPar) {
1388            sig.params = self.parse_abi_param_list()?;
1389        }
1390        self.match_token(Token::RPar, "expected ')' after function arguments")?;
1391        if self.optional(Token::Arrow) {
1392            sig.returns = self.parse_abi_param_list()?;
1393        }
1394
1395        // The calling convention is optional.
1396        match self.token() {
1397            Some(Token::Identifier(text)) => match text.parse() {
1398                Ok(cc) => {
1399                    self.consume();
1400                    sig.call_conv = cc;
1401                }
1402                _ => return err!(self.loc, "unknown calling convention: {}", text),
1403            },
1404            _ => {}
1405        }
1406
1407        Ok(sig)
1408    }
1409
1410    // Parse list of function parameter / return value types.
1411    //
1412    // paramlist ::= * param { "," param }
1413    //
1414    fn parse_abi_param_list(&mut self) -> ParseResult<Vec<AbiParam>> {
1415        let mut list = Vec::new();
1416
1417        // abi-param-list ::= * abi-param { "," abi-param }
1418        list.push(self.parse_abi_param()?);
1419
1420        // abi-param-list ::= abi-param * { "," abi-param }
1421        while self.optional(Token::Comma) {
1422            // abi-param-list ::= abi-param { "," * abi-param }
1423            list.push(self.parse_abi_param()?);
1424        }
1425
1426        Ok(list)
1427    }
1428
1429    // Parse a single argument type with flags.
1430    fn parse_abi_param(&mut self) -> ParseResult<AbiParam> {
1431        // abi-param ::= * type { flag }
1432        let mut arg = AbiParam::new(self.match_type("expected parameter type")?);
1433
1434        // abi-param ::= type * { flag }
1435        while let Some(Token::Identifier(s)) = self.token() {
1436            match s {
1437                "uext" => arg.extension = ArgumentExtension::Uext,
1438                "sext" => arg.extension = ArgumentExtension::Sext,
1439                "sarg" => {
1440                    self.consume();
1441                    self.match_token(Token::LPar, "expected '(' to begin sarg size")?;
1442                    let size = self.match_uimm32("expected byte-size in sarg decl")?;
1443                    self.match_token(Token::RPar, "expected ')' to end sarg size")?;
1444                    arg.purpose = ArgumentPurpose::StructArgument(size.into());
1445                    continue;
1446                }
1447                _ => {
1448                    if let Ok(purpose) = s.parse() {
1449                        arg.purpose = purpose;
1450                    } else {
1451                        break;
1452                    }
1453                }
1454            }
1455            self.consume();
1456        }
1457
1458        Ok(arg)
1459    }
1460
1461    // Parse the function preamble.
1462    //
1463    // preamble      ::= * { preamble-decl }
1464    // preamble-decl ::= * stack-slot-decl
1465    //                   * function-decl
1466    //                   * signature-decl
1467    //                   * jump-table-decl
1468    //                   * stack-limit-decl
1469    //
1470    // The parsed decls are added to `ctx` rather than returned.
1471    fn parse_preamble(&mut self, ctx: &mut Context) -> ParseResult<()> {
1472        loop {
1473            match self.token() {
1474                Some(Token::StackSlot(..)) => {
1475                    self.start_gathering_comments();
1476                    let loc = self.loc;
1477                    self.parse_stack_slot_decl()
1478                        .and_then(|(ss, dat)| ctx.add_ss(ss, dat, loc))
1479                }
1480                Some(Token::DynamicStackSlot(..)) => {
1481                    self.start_gathering_comments();
1482                    let loc = self.loc;
1483                    self.parse_dynamic_stack_slot_decl()
1484                        .and_then(|(dss, dat)| ctx.add_dss(dss, dat, loc))
1485                }
1486                Some(Token::DynamicType(..)) => {
1487                    self.start_gathering_comments();
1488                    let loc = self.loc;
1489                    self.parse_dynamic_type_decl()
1490                        .and_then(|(dt, dat)| ctx.add_dt(dt, dat, loc))
1491                }
1492                Some(Token::GlobalValue(..)) => {
1493                    self.start_gathering_comments();
1494                    self.parse_global_value_decl(&mut ctx.function.dfg.mem_flags)
1495                        .and_then(|(gv, dat)| ctx.add_gv(gv, dat, self.loc))
1496                }
1497                Some(Token::SigRef(..)) => {
1498                    self.start_gathering_comments();
1499                    self.parse_signature_decl().and_then(|(sig, dat)| {
1500                        ctx.add_sig(sig, dat, self.loc, self.default_calling_convention)
1501                    })
1502                }
1503                Some(Token::FuncRef(..)) => {
1504                    self.start_gathering_comments();
1505                    self.parse_function_decl(ctx)
1506                        .and_then(|(fn_, dat)| ctx.add_fn(fn_, dat, self.loc))
1507                }
1508                Some(Token::Constant(..)) => {
1509                    self.start_gathering_comments();
1510                    self.parse_constant_decl()
1511                        .and_then(|(c, v)| ctx.add_constant(c, v, self.loc))
1512                }
1513                Some(Token::Identifier("stack_limit")) => {
1514                    self.start_gathering_comments();
1515                    self.parse_stack_limit_decl()
1516                        .and_then(|gv| ctx.add_stack_limit(gv, self.loc))
1517                }
1518                Some(Token::AliasRegion(..)) => {
1519                    self.start_gathering_comments();
1520                    self.parse_alias_region_decl()
1521                        .and_then(|(ar, dat)| ctx.add_alias_region(ar, dat, self.loc))
1522                }
1523                // More to come..
1524                _ => return Ok(()),
1525            }?;
1526        }
1527    }
1528
1529    // Parse a stack slot decl.
1530    //
1531    // stack-slot-decl ::= * StackSlot(ss) "=" stack-slot-kind Bytes {"," stack-slot-flag}
1532    // stack-slot-kind ::= "explicit_slot"
1533    //                   | "spill_slot"
1534    //                   | "incoming_arg"
1535    //                   | "outgoing_arg"
1536    // stack-slot-flag ::= "align" "=" Bytes | "key" "=" uimm64
1537    fn parse_stack_slot_decl(&mut self) -> ParseResult<(StackSlot, StackSlotData)> {
1538        let ss = self.match_ss("expected stack slot number: ss«n»")?;
1539        self.match_token(Token::Equal, "expected '=' in stack slot declaration")?;
1540        let kind = self.match_enum("expected stack slot kind")?;
1541
1542        // stack-slot-decl ::= StackSlot(ss) "=" stack-slot-kind * Bytes {"," stack-slot-flag}
1543        let bytes: i64 = self
1544            .match_imm64("expected byte-size in stack_slot decl")?
1545            .into();
1546        if bytes < 0 {
1547            return err!(self.loc, "negative stack slot size");
1548        }
1549        if bytes > i64::from(u32::MAX) {
1550            return err!(self.loc, "stack slot too large");
1551        }
1552
1553        let mut align = 1;
1554        let mut key = None;
1555
1556        while self.token() == Some(Token::Comma) {
1557            self.consume();
1558            match self.token() {
1559                Some(Token::Identifier("align")) => {
1560                    self.consume();
1561                    self.match_token(Token::Equal, "expected `=` after flag")?;
1562                    let align64: i64 = self
1563                        .match_imm64("expected alignment-size after `align` flag")?
1564                        .into();
1565                    align = u32::try_from(align64)
1566                        .map_err(|_| self.error("alignment must be a 32-bit unsigned integer"))?;
1567                }
1568                Some(Token::Identifier("key")) => {
1569                    self.consume();
1570                    self.match_token(Token::Equal, "expected `=` after flag")?;
1571                    let value = self.match_uimm64("expected `u64` value for `key` flag")?;
1572                    key = Some(StackSlotKey::new(value.into()));
1573                }
1574                _ => {
1575                    return Err(self.error("invalid flag for stack slot"));
1576                }
1577            }
1578        }
1579
1580        if !align.is_power_of_two() {
1581            return err!(self.loc, "stack slot alignment is not a power of two");
1582        }
1583        let align_shift = u8::try_from(align.ilog2()).unwrap(); // Always succeeds: range 0..=31.
1584
1585        let data = match key {
1586            Some(key) => StackSlotData::new_with_key(kind, bytes as u32, align_shift, key),
1587            None => StackSlotData::new(kind, bytes as u32, align_shift),
1588        };
1589
1590        // Collect any trailing comments.
1591        self.token();
1592        self.claim_gathered_comments(ss);
1593
1594        // TBD: stack-slot-decl ::= StackSlot(ss) "=" stack-slot-kind Bytes * {"," stack-slot-flag}
1595        Ok((ss, data))
1596    }
1597
1598    fn parse_dynamic_stack_slot_decl(
1599        &mut self,
1600    ) -> ParseResult<(DynamicStackSlot, DynamicStackSlotData)> {
1601        let dss = self.match_dss("expected stack slot number: dss«n»")?;
1602        self.match_token(Token::Equal, "expected '=' in stack slot declaration")?;
1603        let kind = self.match_enum("expected stack slot kind")?;
1604        let dt = self.match_dt("expected dynamic type")?;
1605        let data = DynamicStackSlotData::new(kind, dt);
1606        // Collect any trailing comments.
1607        self.token();
1608        self.claim_gathered_comments(dss);
1609
1610        // TBD: stack-slot-decl ::= StackSlot(ss) "=" stack-slot-kind Bytes * {"," stack-slot-flag}
1611        Ok((dss, data))
1612    }
1613
1614    fn parse_dynamic_type_decl(&mut self) -> ParseResult<(DynamicType, DynamicTypeData)> {
1615        let dt = self.match_dt("expected dynamic type number: dt«n»")?;
1616        self.match_token(Token::Equal, "expected '=' in stack slot declaration")?;
1617        let vector_base_ty = self.match_type("expected base type")?;
1618        assert!(vector_base_ty.is_vector(), "expected vector type");
1619        self.match_token(
1620            Token::Multiply,
1621            "expected '*' followed by a dynamic scale value",
1622        )?;
1623        let dyn_scale = self.match_gv("expected dynamic scale global value")?;
1624        let data = DynamicTypeData::new(vector_base_ty, dyn_scale);
1625        // Collect any trailing comments.
1626        self.token();
1627        self.claim_gathered_comments(dt);
1628        Ok((dt, data))
1629    }
1630
1631    // Parse a global value decl.
1632    //
1633    // global-val-decl ::= * GlobalValue(gv) "=" global-val-desc
1634    // global-val-desc ::= "vmctx"
1635    //                   | "load" "." type "notrap" "aligned" GlobalValue(base) [offset]
1636    //                   | "iadd_imm" "(" GlobalValue(base) ")" imm64
1637    //                   | "symbol" ["colocated"] name + imm64
1638    //                   | "dyn_scale_target_const" "." type
1639    //
1640    fn parse_global_value_decl(
1641        &mut self,
1642        mem_flags: &mut MemFlagsSet,
1643    ) -> ParseResult<(GlobalValue, GlobalValueData)> {
1644        let gv = self.match_gv("expected global value number: gv«n»")?;
1645
1646        self.match_token(Token::Equal, "expected '=' in global value declaration")?;
1647
1648        let data = match self.match_any_identifier("expected global value kind")? {
1649            "vmctx" => GlobalValueData::VMContext,
1650            "load" => {
1651                self.match_token(
1652                    Token::Dot,
1653                    "expected '.' followed by type in load global value decl",
1654                )?;
1655                let global_type = self.match_type("expected load type")?;
1656                let flags_data = self.optional_memflags()?;
1657                let base = self.match_gv("expected global value: gv«n»")?;
1658                let offset = self.optional_offset32()?;
1659
1660                if !(flags_data.notrap() && flags_data.aligned()) {
1661                    return err!(self.loc, "global-value load must be notrap and aligned");
1662                }
1663                let flags = mem_flags.insert(flags_data).unwrap();
1664                GlobalValueData::Load {
1665                    base,
1666                    offset,
1667                    global_type,
1668                    flags,
1669                }
1670            }
1671            "iadd_imm" => {
1672                self.match_token(
1673                    Token::Dot,
1674                    "expected '.' followed by type in iadd_imm global value decl",
1675                )?;
1676                let global_type = self.match_type("expected iadd type")?;
1677                let base = self.match_gv("expected global value: gv«n»")?;
1678                self.match_token(
1679                    Token::Comma,
1680                    "expected ',' followed by rhs in iadd_imm global value decl",
1681                )?;
1682                let offset = self.match_imm64("expected iadd_imm immediate")?;
1683                GlobalValueData::IAddImm {
1684                    base,
1685                    offset,
1686                    global_type,
1687                }
1688            }
1689            "symbol" => {
1690                let colocated = self.optional(Token::Identifier("colocated"));
1691                let tls = self.optional(Token::Identifier("tls"));
1692                let name = self.parse_external_name()?;
1693                let offset = self.optional_offset_imm64()?;
1694                GlobalValueData::Symbol {
1695                    name,
1696                    offset,
1697                    colocated,
1698                    tls,
1699                }
1700            }
1701            "dyn_scale_target_const" => {
1702                self.match_token(
1703                    Token::Dot,
1704                    "expected '.' followed by type in dynamic scale global value decl",
1705                )?;
1706                let vector_type = self.match_type("expected load type")?;
1707                assert!(vector_type.is_vector(), "Expected vector type");
1708                GlobalValueData::DynScaleTargetConst { vector_type }
1709            }
1710            other => return err!(self.loc, "Unknown global value kind '{}'", other),
1711        };
1712
1713        // Collect any trailing comments.
1714        self.token();
1715        self.claim_gathered_comments(gv);
1716
1717        Ok((gv, data))
1718    }
1719
1720    // Parse a signature decl.
1721    //
1722    // signature-decl ::= SigRef(sigref) "=" signature
1723    //
1724    fn parse_signature_decl(&mut self) -> ParseResult<(SigRef, Signature)> {
1725        let sig = self.match_sig("expected signature number: sig«n»")?;
1726        self.match_token(Token::Equal, "expected '=' in signature decl")?;
1727        let data = self.parse_signature()?;
1728
1729        // Collect any trailing comments.
1730        self.token();
1731        self.claim_gathered_comments(sig);
1732
1733        Ok((sig, data))
1734    }
1735
1736    // Parse a function decl.
1737    //
1738    // Two variants:
1739    //
1740    // function-decl ::= FuncRef(fnref) "=" ["colocated"] ["patchable"] name function-decl-sig
1741    // function-decl-sig ::= SigRef(sig) | signature
1742    //
1743    // The first variant allocates a new signature reference. The second references an existing
1744    // signature which must be declared first.
1745    //
1746    fn parse_function_decl(&mut self, ctx: &mut Context) -> ParseResult<(FuncRef, ExtFuncData)> {
1747        let fn_ = self.match_fn("expected function number: fn«n»")?;
1748        self.match_token(Token::Equal, "expected '=' in function decl")?;
1749
1750        let loc = self.loc;
1751
1752        // function-decl ::= FuncRef(fnref) "=" * ["colocated"] ["patchable"] name function-decl-sig
1753        let colocated = self.optional(Token::Identifier("colocated"));
1754        // function-decl ::= FuncRef(fnref) "=" ["colocated"] * ["patchable"] name function-decl-sig
1755        let patchable = self.optional(Token::Identifier("patchable"));
1756
1757        // function-decl ::= FuncRef(fnref) "=" ["colocated"] ["patchable"] * name function-decl-sig
1758        let name = self.parse_external_name()?;
1759
1760        // function-decl ::= FuncRef(fnref) "=" ["colocated"] ["patchable"] name * function-decl-sig
1761        let data = match self.token() {
1762            Some(Token::LPar) => {
1763                // function-decl ::= FuncRef(fnref) "=" ["colocated"] ["patchable"] name * signature
1764                let sig = self.parse_signature()?;
1765                let sigref = ctx.function.import_signature(sig);
1766                ctx.map
1767                    .def_entity(sigref.into(), loc)
1768                    .expect("duplicate SigRef entities created");
1769                ExtFuncData {
1770                    name,
1771                    signature: sigref,
1772                    colocated,
1773                    patchable,
1774                }
1775            }
1776            Some(Token::SigRef(sig_src)) => {
1777                let sig = match SigRef::with_number(sig_src) {
1778                    None => {
1779                        return err!(self.loc, "attempted to use invalid signature ss{}", sig_src);
1780                    }
1781                    Some(sig) => sig,
1782                };
1783                ctx.check_sig(sig, self.loc)?;
1784                self.consume();
1785                ExtFuncData {
1786                    name,
1787                    signature: sig,
1788                    colocated,
1789                    patchable,
1790                }
1791            }
1792            _ => return err!(self.loc, "expected 'function' or sig«n» in function decl"),
1793        };
1794
1795        // Collect any trailing comments.
1796        self.token();
1797        self.claim_gathered_comments(fn_);
1798
1799        Ok((fn_, data))
1800    }
1801
1802    // Parse a jump table literal.
1803    //
1804    // jump-table-lit ::= "[" block(args) {"," block(args) } "]"
1805    //                  | "[]"
1806    fn parse_jump_table(
1807        &mut self,
1808        ctx: &mut Context,
1809        def: ir::BlockCall,
1810    ) -> ParseResult<ir::JumpTable> {
1811        self.match_token(Token::LBracket, "expected '[' before jump table contents")?;
1812
1813        let mut data = Vec::new();
1814
1815        match self.token() {
1816            Some(Token::Block(dest)) => {
1817                self.consume();
1818                let args = self.parse_opt_block_call_args()?;
1819                data.push(ctx.function.dfg.block_call(dest, &args));
1820
1821                loop {
1822                    match self.token() {
1823                        Some(Token::Comma) => {
1824                            self.consume();
1825                            if let Some(Token::Block(dest)) = self.token() {
1826                                self.consume();
1827                                let args = self.parse_opt_block_call_args()?;
1828                                data.push(ctx.function.dfg.block_call(dest, &args));
1829                            } else {
1830                                return err!(self.loc, "expected jump_table entry");
1831                            }
1832                        }
1833                        Some(Token::RBracket) => break,
1834                        _ => return err!(self.loc, "expected ']' after jump table contents"),
1835                    }
1836                }
1837            }
1838            Some(Token::RBracket) => (),
1839            _ => return err!(self.loc, "expected jump_table entry"),
1840        }
1841
1842        self.consume();
1843
1844        Ok(ctx
1845            .function
1846            .dfg
1847            .jump_tables
1848            .push(JumpTableData::new(def, &data)))
1849    }
1850
1851    // Parse an exception-table decl.
1852    //
1853    // exception-table ::= * SigRef(sig) "," BlockCall "," "[" (exception-table-entry ( "," exception-table-entry )*)? "]"
1854    // exception-table-entry ::=   ExceptionTag(tag) ":" BlockCall
1855    //                           | "default" ":" BlockCall
1856    //                           | "context" value
1857    fn parse_exception_table(&mut self, ctx: &mut Context) -> ParseResult<ir::ExceptionTable> {
1858        let sig = self.match_sig("expected signature of called function")?;
1859        self.match_token(Token::Comma, "expected comma after signature argument")?;
1860
1861        let mut handlers = vec![];
1862
1863        let block_num = self.match_block("expected branch destination block")?;
1864        let args = self.parse_opt_block_call_args()?;
1865        let normal_return = ctx.function.dfg.block_call(block_num, &args);
1866
1867        self.match_token(
1868            Token::Comma,
1869            "expected comma after normal-return destination",
1870        )?;
1871
1872        self.match_token(
1873            Token::LBracket,
1874            "expected an open-bracket for exception table list",
1875        )?;
1876        loop {
1877            match self.token() {
1878                Some(Token::RBracket) => {
1879                    break;
1880                }
1881                Some(Token::ExceptionTag(tag)) => {
1882                    self.consume();
1883                    self.match_token(Token::Colon, "expected ':' after exception tag")?;
1884                    let tag = ir::ExceptionTag::from_u32(tag);
1885                    let block_num = self.match_block("expected branch destination block")?;
1886                    let args = self.parse_opt_block_call_args()?;
1887                    let block_call = ctx.function.dfg.block_call(block_num, &args);
1888                    handlers.push(ir::ExceptionTableItem::Tag(tag, block_call));
1889                }
1890                Some(Token::Identifier("default")) => {
1891                    self.consume();
1892                    self.match_token(Token::Colon, "expected ':' after 'default'")?;
1893                    let block_num = self.match_block("expected branch destination block")?;
1894                    let args = self.parse_opt_block_call_args()?;
1895                    let block_call = ctx.function.dfg.block_call(block_num, &args);
1896                    handlers.push(ir::ExceptionTableItem::Default(block_call));
1897                }
1898                Some(Token::Identifier("context")) => {
1899                    self.consume();
1900                    let val = self.match_value("expected value for exception-handler context")?;
1901                    handlers.push(ir::ExceptionTableItem::Context(val));
1902                }
1903                _ => return err!(self.loc, "invalid token"),
1904            }
1905
1906            if let Some(Token::Comma) = self.token() {
1907                self.consume();
1908            } else {
1909                break;
1910            }
1911        }
1912        self.match_token(Token::RBracket, "expected closing bracket")?;
1913
1914        Ok(ctx
1915            .function
1916            .dfg
1917            .exception_tables
1918            .push(ir::ExceptionTableData::new(sig, normal_return, handlers)))
1919    }
1920
1921    // Parse a constant decl.
1922    //
1923    // constant-decl ::= * Constant(c) "=" ty? "[" literal {"," literal} "]"
1924    fn parse_constant_decl(&mut self) -> ParseResult<(Constant, ConstantData)> {
1925        let name = self.match_constant()?;
1926        self.match_token(Token::Equal, "expected '=' in constant decl")?;
1927        let data = if let Some(Token::Type(_)) = self.token() {
1928            let ty = self.match_type("expected type of constant")?;
1929            self.match_uimm128(ty)
1930        } else {
1931            self.match_hexadecimal_constant("expected an immediate hexadecimal operand")
1932        }?;
1933
1934        // Collect any trailing comments.
1935        self.token();
1936        self.claim_gathered_comments(name);
1937
1938        Ok((name, data))
1939    }
1940
1941    // Parse an alias region decl
1942    //
1943    // alias-region-decl ::= * AliasRegion(region) "=" Integer String
1944    fn parse_alias_region_decl(&mut self) -> ParseResult<(ir::AliasRegion, ir::AliasRegionData)> {
1945        let ar_num = match self.token() {
1946            Some(Token::AliasRegion(n)) => n,
1947            _ => return err!(self.loc, "expected alias region number"),
1948        };
1949        self.consume();
1950        let ar = ir::AliasRegion::new(usize::try_from(ar_num).unwrap());
1951
1952        self.match_token(Token::Equal, "expected '=' in alias region decl")?;
1953
1954        let user_id = match self.token() {
1955            Some(Token::Integer(s)) => u32::from_str_radix(s, 10)
1956                .map_err(|_| self.error("expected integer user_id for alias region"))?,
1957            _ => return err!(self.loc, "expected integer user_id for alias region"),
1958        };
1959        self.consume();
1960
1961        let description = match self.token() {
1962            Some(Token::String(s)) => s.to_owned(),
1963            _ => return err!(self.loc, "expected string description for alias region"),
1964        };
1965        self.consume();
1966
1967        let data = ir::AliasRegionData {
1968            user_id,
1969            description: std::borrow::Cow::Owned(description),
1970        };
1971
1972        // Collect any trailing comments.
1973        self.token();
1974        self.claim_gathered_comments(ir::AliasRegion::new(usize::try_from(ar_num).unwrap()));
1975
1976        Ok((ar, data))
1977    }
1978
1979    // Parse a stack limit decl
1980    //
1981    // stack-limit-decl ::= * StackLimit "=" GlobalValue(gv)
1982    fn parse_stack_limit_decl(&mut self) -> ParseResult<GlobalValue> {
1983        self.match_stack_limit()?;
1984        self.match_token(Token::Equal, "expected '=' in stack limit decl")?;
1985        let limit = match self.token() {
1986            Some(Token::GlobalValue(base_num)) => match GlobalValue::with_number(base_num) {
1987                Some(gv) => gv,
1988                None => return err!(self.loc, "invalid global value number for stack limit"),
1989            },
1990            _ => return err!(self.loc, "expected global value"),
1991        };
1992        self.consume();
1993
1994        // Collect any trailing comments.
1995        self.token();
1996        self.claim_gathered_comments(AnyEntity::StackLimit);
1997
1998        Ok(limit)
1999    }
2000
2001    // Parse a function body, add contents to `ctx`.
2002    //
2003    // function-body ::= * { extended-basic-block }
2004    //
2005    fn parse_function_body(&mut self, ctx: &mut Context) -> ParseResult<()> {
2006        while self.token() != Some(Token::RBrace) {
2007            self.parse_basic_block(ctx)?;
2008        }
2009
2010        // Now that we've seen all defined values in the function, ensure that
2011        // all references refer to a definition.
2012        for block in &ctx.function.layout {
2013            for inst in ctx.function.layout.block_insts(block) {
2014                for value in ctx.function.dfg.inst_values(inst) {
2015                    if !ctx.map.contains_value(value) {
2016                        return err!(
2017                            ctx.map.location(AnyEntity::Inst(inst)).unwrap(),
2018                            "undefined operand value {}",
2019                            value
2020                        );
2021                    }
2022                }
2023            }
2024        }
2025
2026        for alias in &ctx.aliases {
2027            if !ctx.function.dfg.set_alias_type_for_parser(*alias) {
2028                let loc = ctx.map.location(AnyEntity::Value(*alias)).unwrap();
2029                return err!(loc, "alias cycle involving {}", alias);
2030            }
2031        }
2032
2033        Ok(())
2034    }
2035
2036    // Parse a basic block, add contents to `ctx`.
2037    //
2038    // extended-basic-block ::= * block-header { instruction }
2039    // block-header         ::= Block(block) [block-params] [block-flags] ":"
2040    // block-flags          ::= [Cold]
2041    //
2042    fn parse_basic_block(&mut self, ctx: &mut Context) -> ParseResult<()> {
2043        // Collect comments for the next block.
2044        self.start_gathering_comments();
2045
2046        let block_num = self.match_block("expected block header")?;
2047        let block = ctx.add_block(block_num, self.loc)?;
2048
2049        if block_num.as_u32() >= MAX_BLOCKS_IN_A_FUNCTION {
2050            return Err(self.error("too many blocks"));
2051        }
2052
2053        if self.token() == Some(Token::LPar) {
2054            self.parse_block_params(ctx, block)?;
2055        }
2056
2057        if self.optional(Token::Cold) {
2058            ctx.set_cold_block(block);
2059        }
2060
2061        self.match_token(Token::Colon, "expected ':' after block parameters")?;
2062
2063        // Collect any trailing comments.
2064        self.token();
2065        self.claim_gathered_comments(block);
2066
2067        // extended-basic-block ::= block-header * { instruction }
2068        while match self.token() {
2069            Some(Token::Value(_))
2070            | Some(Token::Identifier(_))
2071            | Some(Token::LBracket)
2072            | Some(Token::SourceLoc(_))
2073            | Some(Token::LAngle) => true,
2074            _ => false,
2075        } {
2076            // Debug tags are written before the source location (see
2077            // `write_debug_tags`), so parse them in that order.
2078            let debug_tags = self.optional_debug_tags()?;
2079
2080            let srcloc = self.optional_srcloc()?;
2081
2082            // We need to parse instruction results here because they are shared
2083            // between the parsing of value aliases and the parsing of instructions.
2084            //
2085            // inst-results ::= Value(v) { "," Value(v) }
2086            let results = self.parse_inst_results()?;
2087
2088            for result in &results {
2089                while ctx.function.dfg.num_values() <= result.index() {
2090                    ctx.function.dfg.make_invalid_value_for_parser();
2091                }
2092            }
2093
2094            match self.token() {
2095                Some(Token::Arrow) => {
2096                    self.consume();
2097                    self.parse_value_alias(&results, ctx)?;
2098                }
2099                Some(Token::Equal) => {
2100                    self.consume();
2101                    self.parse_instruction(&results, srcloc, debug_tags, ctx, block)?;
2102                }
2103                _ if !results.is_empty() => return err!(self.loc, "expected -> or ="),
2104                _ => self.parse_instruction(&results, srcloc, debug_tags, ctx, block)?,
2105            }
2106        }
2107
2108        Ok(())
2109    }
2110
2111    // Parse parenthesized list of block parameters.
2112    //
2113    // block-params ::= * "(" ( block-param { "," block-param } )? ")"
2114    fn parse_block_params(&mut self, ctx: &mut Context, block: Block) -> ParseResult<()> {
2115        // block-params ::= * "(" ( block-param { "," block-param } )? ")"
2116        self.match_token(Token::LPar, "expected '(' before block parameters")?;
2117
2118        // block-params ::= "(" * ")"
2119        if self.token() == Some(Token::RPar) {
2120            self.consume();
2121            return Ok(());
2122        }
2123
2124        // block-params ::= "(" * block-param { "," block-param } ")"
2125        self.parse_block_param(ctx, block)?;
2126
2127        // block-params ::= "(" block-param * { "," block-param } ")"
2128        while self.optional(Token::Comma) {
2129            // block-params ::= "(" block-param { "," * block-param } ")"
2130            self.parse_block_param(ctx, block)?;
2131        }
2132
2133        // block-params ::= "(" block-param { "," block-param } * ")"
2134        self.match_token(Token::RPar, "expected ')' after block parameters")?;
2135
2136        Ok(())
2137    }
2138
2139    // Parse a single block parameter declaration, and append it to `block`.
2140    //
2141    // block-param ::= * Value(v) ":" Type(t) arg-loc?
2142    // arg-loc ::= "[" value-location "]"
2143    //
2144    fn parse_block_param(&mut self, ctx: &mut Context, block: Block) -> ParseResult<()> {
2145        // block-param ::= * Value(v) ":" Type(t) arg-loc?
2146        let v = self.match_value("block argument must be a value")?;
2147        let v_location = self.loc;
2148        self.match_token(Token::Colon, "expected ':' after block argument")?;
2149        // block-param ::= Value(v) ":" * Type(t) arg-loc?
2150        while ctx.function.dfg.num_values() <= v.index() {
2151            ctx.function.dfg.make_invalid_value_for_parser();
2152        }
2153
2154        let t = self.match_type("expected block argument type")?;
2155        // Allocate the block argument.
2156        ctx.function.dfg.append_block_param_for_parser(block, t, v);
2157        ctx.map.def_value(v, v_location)?;
2158
2159        Ok(())
2160    }
2161
2162    // Parse instruction results and return them.
2163    //
2164    // inst-results ::= Value(v) { "," Value(v) }
2165    //
2166    fn parse_inst_results(&mut self) -> ParseResult<SmallVec<[Value; 1]>> {
2167        // Result value numbers.
2168        let mut results = SmallVec::new();
2169
2170        // instruction  ::=  * [inst-results "="] Opcode(opc) ["." Type] ...
2171        // inst-results ::= * Value(v) { "," Value(v) }
2172        if let Some(Token::Value(v)) = self.token() {
2173            self.consume();
2174
2175            results.push(v);
2176
2177            // inst-results ::= Value(v) * { "," Value(v) }
2178            while self.optional(Token::Comma) {
2179                // inst-results ::= Value(v) { "," * Value(v) }
2180                let v = self.match_value("expected result value")?;
2181                results.push(v);
2182            }
2183        }
2184
2185        Ok(results)
2186    }
2187
2188    // Parse a value alias, and append it to `block`.
2189    //
2190    // value_alias ::= [inst-results] "->" Value(v)
2191    //
2192    fn parse_value_alias(&mut self, results: &[Value], ctx: &mut Context) -> ParseResult<()> {
2193        if results.len() != 1 {
2194            return err!(self.loc, "wrong number of aliases");
2195        }
2196        let result = results[0];
2197        let dest = self.match_value("expected value alias")?;
2198
2199        // Allow duplicate definitions of aliases, as long as they are identical.
2200        if ctx.map.contains_value(result) {
2201            if let Some(old) = ctx.function.dfg.value_alias_dest_for_serialization(result) {
2202                if old != dest {
2203                    return err!(
2204                        self.loc,
2205                        "value {} is already defined as an alias with destination {}",
2206                        result,
2207                        old
2208                    );
2209                }
2210            } else {
2211                return err!(self.loc, "value {} is already defined");
2212            }
2213        } else {
2214            ctx.map.def_value(result, self.loc)?;
2215        }
2216
2217        if !ctx.map.contains_value(dest) {
2218            return err!(self.loc, "value {} is not yet defined", dest);
2219        }
2220
2221        ctx.function
2222            .dfg
2223            .make_value_alias_for_serialization(dest, result);
2224
2225        ctx.aliases.push(result);
2226        Ok(())
2227    }
2228
2229    // Parse an instruction, append it to `block`.
2230    //
2231    // instruction ::= [inst-results "="] Opcode(opc) ["." Type] ...
2232    //
2233    fn parse_instruction(
2234        &mut self,
2235        results: &[Value],
2236        srcloc: ir::SourceLoc,
2237        debug_tags: Vec<DebugTag>,
2238        ctx: &mut Context,
2239        block: Block,
2240    ) -> ParseResult<()> {
2241        // Define the result values.
2242        for val in results {
2243            ctx.map.def_value(*val, self.loc)?;
2244        }
2245
2246        // Collect comments for the next instruction.
2247        self.start_gathering_comments();
2248
2249        // instruction ::=  [inst-results "="] * Opcode(opc) ["." Type] ...
2250        let opcode = if let Some(Token::Identifier(text)) = self.token() {
2251            match text.parse() {
2252                Ok(opc) => opc,
2253                Err(msg) => return err!(self.loc, "{}: '{}'", msg, text),
2254            }
2255        } else {
2256            return err!(self.loc, "expected instruction opcode");
2257        };
2258        let opcode_loc = self.loc;
2259        self.consume();
2260
2261        // Look for a controlling type variable annotation.
2262        // instruction ::=  [inst-results "="] Opcode(opc) * ["." Type] ...
2263        let explicit_ctrl_type = if self.optional(Token::Dot) {
2264            if let Some(Token::Type(_t)) = self.token() {
2265                Some(self.match_type("expected type after 'opcode.'")?)
2266            } else {
2267                let dt = self.match_dt("expected dynamic type")?;
2268                self.concrete_from_dt(dt, ctx)
2269            }
2270        } else {
2271            None
2272        };
2273
2274        // instruction ::=  [inst-results "="] Opcode(opc) ["." Type] * ...
2275        let inst_data = self.parse_inst_operands(ctx, opcode, explicit_ctrl_type)?;
2276
2277        let ctrl_typevar = self.infer_typevar(ctx, opcode, explicit_ctrl_type, &inst_data)?;
2278        let inst = ctx.function.dfg.make_inst(inst_data);
2279
2280        // Attach stack map, if present.
2281        if self.optional(Token::Comma) {
2282            self.match_token(
2283                Token::Identifier("stack_map"),
2284                "expected `stack_map = [...]`",
2285            )?;
2286            if !opcode.is_call() || opcode.is_return() {
2287                return err!(
2288                    self.loc,
2289                    "stack map can only be attached to a (non-tail) call"
2290                );
2291            }
2292
2293            self.match_token(Token::Equal, "expected `= [...]`")?;
2294            self.match_token(Token::LBracket, "expected `[...]`")?;
2295            while !self.optional(Token::RBracket) {
2296                let ty = self.match_type("expected `<type> @ <slot> + <offset>`")?;
2297                self.match_token(Token::At, "expected `@ <slot> + <offset>`")?;
2298                let slot = self.match_ss("expected `<slot> + <offset>`")?;
2299                let offset: u32 = match self.token() {
2300                    Some(Token::Integer(s)) if s.starts_with('+') => {
2301                        self.match_uimm32("expected a u32 offset")?.into()
2302                    }
2303                    _ => {
2304                        self.match_token(Token::Plus, "expected `+ <offset>`")?;
2305                        self.match_uimm32("expected a u32 offset")?.into()
2306                    }
2307                };
2308                ctx.function
2309                    .dfg
2310                    .append_user_stack_map_entry(inst, ir::UserStackMapEntry { ty, slot, offset });
2311                if !self.optional(Token::Comma) {
2312                    self.match_token(Token::RBracket, "expected `,` or `]`")?;
2313                    break;
2314                }
2315            }
2316        }
2317
2318        // We're done parsing the instruction data itself.
2319        //
2320        // We still need to check that the number of result values in
2321        // the source matches the opcode or function call
2322        // signature. We also need to create values with the right
2323        // type for all the instruction results.
2324        let num_results =
2325            ctx.function
2326                .dfg
2327                .make_inst_results_for_parser(inst, ctrl_typevar, results);
2328        ctx.function.layout.append_inst(inst, block);
2329        ctx.map
2330            .def_entity(inst.into(), opcode_loc)
2331            .expect("duplicate inst references created");
2332
2333        if !srcloc.is_default() {
2334            ctx.function.set_srcloc(inst, srcloc);
2335        }
2336        if !debug_tags.is_empty() {
2337            ctx.function.debug_tags.set(inst, debug_tags);
2338        }
2339
2340        if results.len() != num_results {
2341            return err!(
2342                self.loc,
2343                "instruction produces {} result values, {} given",
2344                num_results,
2345                results.len()
2346            );
2347        }
2348
2349        // Collect any trailing comments.
2350        self.token();
2351        self.claim_gathered_comments(inst);
2352
2353        Ok(())
2354    }
2355
2356    // Type inference for polymorphic instructions.
2357    //
2358    // The controlling type variable can be specified explicitly as 'splat.i32x4 v5', or it can be
2359    // inferred from `inst_data.typevar_operand` for some opcodes.
2360    //
2361    // Returns the controlling typevar for a polymorphic opcode, or `INVALID` for a non-polymorphic
2362    // opcode.
2363    fn infer_typevar(
2364        &self,
2365        ctx: &Context,
2366        opcode: Opcode,
2367        explicit_ctrl_type: Option<Type>,
2368        inst_data: &InstructionData,
2369    ) -> ParseResult<Type> {
2370        let constraints = opcode.constraints();
2371        let ctrl_type = match explicit_ctrl_type {
2372            Some(t) => t,
2373            None => {
2374                if constraints.use_typevar_operand() {
2375                    // This is an opcode that supports type inference, AND there was no
2376                    // explicit type specified. Look up `ctrl_value` to see if it was defined
2377                    // already.
2378                    // TBD: If it is defined in another block, the type should have been
2379                    // specified explicitly. It is unfortunate that the correctness of IR
2380                    // depends on the layout of the blocks.
2381                    let ctrl_src_value = inst_data
2382                        .typevar_operand(&ctx.function.dfg.value_lists)
2383                        .expect("Constraints <-> Format inconsistency");
2384                    if !ctx.map.contains_value(ctrl_src_value) {
2385                        return err!(
2386                            self.loc,
2387                            "type variable required for polymorphic opcode, e.g. '{}.{}'; \
2388                             can't infer from {} which is not yet defined",
2389                            opcode,
2390                            constraints.ctrl_typeset().unwrap().example(),
2391                            ctrl_src_value
2392                        );
2393                    }
2394                    if !ctx.function.dfg.value_is_valid_for_parser(ctrl_src_value) {
2395                        return err!(
2396                            self.loc,
2397                            "type variable required for polymorphic opcode, e.g. '{}.{}'; \
2398                             can't infer from {} which is not yet resolved",
2399                            opcode,
2400                            constraints.ctrl_typeset().unwrap().example(),
2401                            ctrl_src_value
2402                        );
2403                    }
2404                    ctx.function.dfg.value_type(ctrl_src_value)
2405                } else if constraints.is_polymorphic() {
2406                    // This opcode does not support type inference, so the explicit type
2407                    // variable is required.
2408                    return err!(
2409                        self.loc,
2410                        "type variable required for polymorphic opcode, e.g. '{}.{}'",
2411                        opcode,
2412                        constraints.ctrl_typeset().unwrap().example()
2413                    );
2414                } else {
2415                    // This is a non-polymorphic opcode. No typevar needed.
2416                    INVALID
2417                }
2418            }
2419        };
2420
2421        // Verify that `ctrl_type` is valid for the controlling type variable. We don't want to
2422        // attempt deriving types from an incorrect basis.
2423        // This is not a complete type check. The verifier does that.
2424        if let Some(typeset) = constraints.ctrl_typeset() {
2425            // This is a polymorphic opcode.
2426            if !typeset.contains(ctrl_type) {
2427                return err!(
2428                    self.loc,
2429                    "{} is not a valid typevar for {}",
2430                    ctrl_type,
2431                    opcode
2432                );
2433            }
2434        // Treat it as a syntax error to specify a typevar on a non-polymorphic opcode.
2435        } else if ctrl_type != INVALID {
2436            return err!(self.loc, "{} does not take a typevar", opcode);
2437        }
2438
2439        Ok(ctrl_type)
2440    }
2441
2442    // Parse comma-separated value list into a VariableArgs struct.
2443    //
2444    // value_list ::= [ value { "," value } ]
2445    //
2446    fn parse_value_list(&mut self) -> ParseResult<VariableArgs> {
2447        let mut args = VariableArgs::new();
2448
2449        if let Some(Token::Value(v)) = self.token() {
2450            args.push(v);
2451            self.consume();
2452        } else {
2453            return Ok(args);
2454        }
2455
2456        while self.optional(Token::Comma) {
2457            args.push(self.match_value("expected value in argument list")?);
2458        }
2459
2460        Ok(args)
2461    }
2462
2463    /// Parse an optional list of block-call arguments enclosed in
2464    /// parentheses.
2465    fn parse_opt_block_call_args(&mut self) -> ParseResult<Vec<BlockArg>> {
2466        if !self.optional(Token::LPar) {
2467            return Ok(vec![]);
2468        }
2469
2470        let mut args = vec![];
2471        while self.token() != Some(Token::RPar) {
2472            args.push(self.parse_block_call_arg()?);
2473            if self.token() == Some(Token::Comma) {
2474                self.consume();
2475            } else {
2476                break;
2477            }
2478        }
2479
2480        self.match_token(Token::RPar, "expected ')' after arguments")?;
2481
2482        Ok(args)
2483    }
2484
2485    fn parse_block_call_arg(&mut self) -> ParseResult<BlockArg> {
2486        match self.token() {
2487            Some(Token::Value(v)) => {
2488                self.consume();
2489                Ok(BlockArg::Value(v))
2490            }
2491            Some(Token::TryCallRet(i)) => {
2492                self.consume();
2493                Ok(BlockArg::TryCallRet(i))
2494            }
2495            Some(Token::TryCallExn(i)) => {
2496                self.consume();
2497                Ok(BlockArg::TryCallExn(i))
2498            }
2499            tok => Err(self.error(&format!("unexpected token: {tok:?}"))),
2500        }
2501    }
2502
2503    /// Parse a CLIF run command.
2504    ///
2505    /// run-command ::= "run" [":" invocation comparison expected]
2506    ///               \ "print" [":" invocation]
2507    fn parse_run_command(&mut self, sig: &Signature) -> ParseResult<RunCommand> {
2508        // skip semicolon
2509        match self.token() {
2510            Some(Token::Identifier("run")) => {
2511                self.consume();
2512                if self.optional(Token::Colon) {
2513                    let invocation = self.parse_run_invocation(sig)?;
2514                    let comparison = self.parse_run_comparison()?;
2515                    let expected = self.parse_run_returns(sig)?;
2516                    Ok(RunCommand::Run(invocation, comparison, expected))
2517                } else if sig.params.is_empty()
2518                    && sig.returns.len() == 1
2519                    && sig.returns[0].value_type.is_int()
2520                {
2521                    // To match the existing run behavior that does not require an explicit
2522                    // invocation, we create an invocation from a function like `() -> i*` and
2523                    // require the result to be non-zero.
2524                    let invocation = Invocation::new("default", vec![]);
2525                    let expected = vec![DataValue::I8(0)];
2526                    let comparison = Comparison::NotEquals;
2527                    Ok(RunCommand::Run(invocation, comparison, expected))
2528                } else {
2529                    Err(self.error("unable to parse the run command"))
2530                }
2531            }
2532            Some(Token::Identifier("print")) => {
2533                self.consume();
2534                if self.optional(Token::Colon) {
2535                    Ok(RunCommand::Print(self.parse_run_invocation(sig)?))
2536                } else if sig.params.is_empty() {
2537                    // To allow printing of functions like `() -> *`, we create a no-arg invocation.
2538                    let invocation = Invocation::new("default", vec![]);
2539                    Ok(RunCommand::Print(invocation))
2540                } else {
2541                    Err(self.error("unable to parse the print command"))
2542                }
2543            }
2544            _ => Err(self.error("expected a 'run:' or 'print:' command")),
2545        }
2546    }
2547
2548    /// Parse the invocation of a CLIF function.
2549    ///
2550    /// This is different from parsing a CLIF `call`; it is used in parsing run commands like
2551    /// `run: %fn(42, 4.2) == false`.
2552    ///
2553    /// invocation ::= name "(" [data-value-list] ")"
2554    fn parse_run_invocation(&mut self, sig: &Signature) -> ParseResult<Invocation> {
2555        if let Some(Token::Name(name)) = self.token() {
2556            self.consume();
2557            self.match_token(
2558                Token::LPar,
2559                "expected invocation parentheses, e.g. %fn(...)",
2560            )?;
2561
2562            let arg_types = sig
2563                .params
2564                .iter()
2565                .map(|abi| abi.value_type)
2566                .collect::<Vec<_>>();
2567            let args = self.parse_data_value_list(&arg_types)?;
2568
2569            self.match_token(
2570                Token::RPar,
2571                "expected invocation parentheses, e.g. %fn(...)",
2572            )?;
2573            Ok(Invocation::new(name, args))
2574        } else {
2575            Err(self.error("expected a function name, e.g. %my_fn"))
2576        }
2577    }
2578
2579    /// Parse a comparison operator for run commands.
2580    ///
2581    /// comparison ::= "==" | "!="
2582    fn parse_run_comparison(&mut self) -> ParseResult<Comparison> {
2583        if self.optional(Token::Equal) {
2584            self.match_token(Token::Equal, "expected another =")?;
2585            Ok(Comparison::Equals)
2586        } else if self.optional(Token::Bang) {
2587            self.match_token(Token::Equal, "expected a =")?;
2588            Ok(Comparison::NotEquals)
2589        } else {
2590            Err(self.error("unable to parse a valid comparison operator"))
2591        }
2592    }
2593
2594    /// Parse the expected return values of a run invocation.
2595    ///
2596    /// expected ::= "[" "]"
2597    ///            | data-value
2598    ///            | "[" data-value-list "]"
2599    fn parse_run_returns(&mut self, sig: &Signature) -> ParseResult<Vec<DataValue>> {
2600        if sig.returns.len() != 1 {
2601            self.match_token(Token::LBracket, "expected a left bracket [")?;
2602        }
2603
2604        let returns = self
2605            .parse_data_value_list(&sig.returns.iter().map(|a| a.value_type).collect::<Vec<_>>())?;
2606
2607        if sig.returns.len() != 1 {
2608            self.match_token(Token::RBracket, "expected a right bracket ]")?;
2609        }
2610        Ok(returns)
2611    }
2612
2613    /// Parse a comma-separated list of data values.
2614    ///
2615    /// data-value-list ::= [data-value {"," data-value-list}]
2616    fn parse_data_value_list(&mut self, types: &[Type]) -> ParseResult<Vec<DataValue>> {
2617        let mut values = vec![];
2618        for ty in types.iter().take(1) {
2619            values.push(self.parse_data_value(*ty)?);
2620        }
2621        for ty in types.iter().skip(1) {
2622            self.match_token(
2623                Token::Comma,
2624                "expected a comma between invocation arguments",
2625            )?;
2626            values.push(self.parse_data_value(*ty)?);
2627        }
2628        Ok(values)
2629    }
2630
2631    /// Parse a data value; e.g. `42`, `4.2`, `true`.
2632    ///
2633    /// data-value-list ::= [data-value {"," data-value-list}]
2634    fn parse_data_value(&mut self, ty: Type) -> ParseResult<DataValue> {
2635        let dv = match ty {
2636            I8 => DataValue::from(self.match_imm8("expected a i8")?),
2637            I16 => DataValue::from(self.match_imm16("expected an i16")?),
2638            I32 => DataValue::from(self.match_imm32("expected an i32")?),
2639            I64 => DataValue::from(Into::<i64>::into(self.match_imm64("expected an i64")?)),
2640            I128 => DataValue::from(self.match_imm128("expected an i128")?),
2641            F16 => DataValue::from(self.match_ieee16("expected an f16")?),
2642            F32 => DataValue::from(self.match_ieee32("expected an f32")?),
2643            F64 => DataValue::from(self.match_ieee64("expected an f64")?),
2644            F128 => DataValue::from(self.match_ieee128("expected an f128")?),
2645            _ if (ty.is_vector() || ty.is_dynamic_vector()) => {
2646                let as_vec = self.match_uimm128(ty)?.into_vec();
2647                let slice = as_vec.as_slice();
2648                match slice.len() {
2649                    16 => DataValue::V128(slice.try_into().unwrap()),
2650                    8 => DataValue::V64(slice.try_into().unwrap()),
2651                    4 => DataValue::V32(slice.try_into().unwrap()),
2652                    2 => DataValue::V16(slice.try_into().unwrap()),
2653                    _ => {
2654                        return Err(
2655                            self.error("vectors larger than 128 bits are not currently supported")
2656                        );
2657                    }
2658                }
2659            }
2660            _ => return Err(self.error(&format!("don't know how to parse data values of: {ty}"))),
2661        };
2662        Ok(dv)
2663    }
2664
2665    // Parse the operands following the instruction opcode.
2666    // This depends on the format of the opcode.
2667    fn parse_inst_operands(
2668        &mut self,
2669        ctx: &mut Context,
2670        opcode: Opcode,
2671        explicit_control_type: Option<Type>,
2672    ) -> ParseResult<InstructionData> {
2673        let idata = match opcode.format() {
2674            InstructionFormat::Unary => InstructionData::Unary {
2675                opcode,
2676                arg: self.match_value("expected SSA value operand")?,
2677            },
2678            InstructionFormat::UnaryImm => {
2679                let msg = |bits| format!("expected immediate {bits}-bit integer operand");
2680                let unsigned = match explicit_control_type {
2681                    Some(types::I8) => self.match_imm8(&msg(8))? as u8 as i64,
2682                    Some(types::I16) => self.match_imm16(&msg(16))? as u16 as i64,
2683                    Some(types::I32) => self.match_imm32(&msg(32))? as u32 as i64,
2684                    Some(types::I64) => self.match_imm64(&msg(64))?.bits(),
2685                    _ => {
2686                        return err!(
2687                            self.loc,
2688                            "expected one of the following type: i8, i16, i32 or i64"
2689                        );
2690                    }
2691                };
2692                InstructionData::UnaryImm {
2693                    opcode,
2694                    imm: Imm64::new(unsigned),
2695                }
2696            }
2697            InstructionFormat::UnaryIeee16 => InstructionData::UnaryIeee16 {
2698                opcode,
2699                imm: self.match_ieee16("expected immediate 16-bit float operand")?,
2700            },
2701            InstructionFormat::UnaryIeee32 => InstructionData::UnaryIeee32 {
2702                opcode,
2703                imm: self.match_ieee32("expected immediate 32-bit float operand")?,
2704            },
2705            InstructionFormat::UnaryIeee64 => InstructionData::UnaryIeee64 {
2706                opcode,
2707                imm: self.match_ieee64("expected immediate 64-bit float operand")?,
2708            },
2709            InstructionFormat::UnaryConst => {
2710                let constant_handle = if let Some(Token::Constant(_)) = self.token() {
2711                    // If handed a `const?`, use that.
2712                    let c = self.match_constant()?;
2713                    ctx.check_constant(c, self.loc)?;
2714                    c
2715                } else if opcode == Opcode::F128const {
2716                    let ieee128 = self.match_ieee128("expected immediate 128-bit float operand")?;
2717                    ctx.function.dfg.constants.insert(ieee128.into())
2718                } else if let Some(controlling_type) = explicit_control_type {
2719                    // If an explicit control type is present, we expect a sized value and insert
2720                    // it in the constant pool.
2721                    let uimm128 = self.match_uimm128(controlling_type)?;
2722                    ctx.function.dfg.constants.insert(uimm128)
2723                } else {
2724                    return err!(
2725                        self.loc,
2726                        "Expected either a const entity or a typed value, e.g. inst.i32x4 [...]"
2727                    );
2728                };
2729                InstructionData::UnaryConst {
2730                    opcode,
2731                    constant_handle,
2732                }
2733            }
2734            InstructionFormat::UnaryGlobalValue => {
2735                let gv = self.match_gv("expected global value")?;
2736                ctx.check_gv(gv, self.loc)?;
2737                InstructionData::UnaryGlobalValue {
2738                    opcode,
2739                    global_value: gv,
2740                }
2741            }
2742            InstructionFormat::Binary => {
2743                let lhs = self.match_value("expected SSA value first operand")?;
2744                self.match_token(Token::Comma, "expected ',' between operands")?;
2745                let rhs = self.match_value("expected SSA value second operand")?;
2746                InstructionData::Binary {
2747                    opcode,
2748                    args: [lhs, rhs],
2749                }
2750            }
2751            InstructionFormat::BinaryImm8 => {
2752                let arg = self.match_value("expected SSA value first operand")?;
2753                self.match_token(Token::Comma, "expected ',' between operands")?;
2754                let imm = self.match_uimm8("expected unsigned 8-bit immediate")?;
2755                InstructionData::BinaryImm8 { opcode, arg, imm }
2756            }
2757            InstructionFormat::Ternary => {
2758                // Names here refer to the `select` instruction.
2759                // This format is also use by `fma`.
2760                let ctrl_arg = self.match_value("expected SSA value control operand")?;
2761                self.match_token(Token::Comma, "expected ',' between operands")?;
2762                let true_arg = self.match_value("expected SSA value true operand")?;
2763                self.match_token(Token::Comma, "expected ',' between operands")?;
2764                let false_arg = self.match_value("expected SSA value false operand")?;
2765                InstructionData::Ternary {
2766                    opcode,
2767                    args: [ctrl_arg, true_arg, false_arg],
2768                }
2769            }
2770            InstructionFormat::MultiAry => {
2771                let args = self.parse_value_list()?;
2772                InstructionData::MultiAry {
2773                    opcode,
2774                    args: args.into_value_list(&[], &mut ctx.function.dfg.value_lists),
2775                }
2776            }
2777            InstructionFormat::NullAry => InstructionData::NullAry { opcode },
2778            InstructionFormat::Jump => {
2779                // Parse the destination block number.
2780                let block_num = self.match_block("expected jump destination block")?;
2781                let args = self.parse_opt_block_call_args()?;
2782                let destination = ctx.function.dfg.block_call(block_num, &args);
2783                InstructionData::Jump {
2784                    opcode,
2785                    destination,
2786                }
2787            }
2788            InstructionFormat::Brif => {
2789                let arg = self.match_value("expected SSA value control operand")?;
2790                self.match_token(Token::Comma, "expected ',' between operands")?;
2791                let block_then = {
2792                    let block_num = self.match_block("expected branch then block")?;
2793                    let args = self.parse_opt_block_call_args()?;
2794                    ctx.function.dfg.block_call(block_num, &args)
2795                };
2796                self.match_token(Token::Comma, "expected ',' between operands")?;
2797                let block_else = {
2798                    let block_num = self.match_block("expected branch else block")?;
2799                    let args = self.parse_opt_block_call_args()?;
2800                    ctx.function.dfg.block_call(block_num, &args)
2801                };
2802                InstructionData::Brif {
2803                    opcode,
2804                    arg,
2805                    blocks: [block_then, block_else],
2806                }
2807            }
2808            InstructionFormat::BranchTable => {
2809                let arg = self.match_value("expected SSA value operand")?;
2810                self.match_token(Token::Comma, "expected ',' between operands")?;
2811                let block_num = self.match_block("expected branch destination block")?;
2812                let args = self.parse_opt_block_call_args()?;
2813                let destination = ctx.function.dfg.block_call(block_num, &args);
2814                self.match_token(Token::Comma, "expected ',' between operands")?;
2815                let table = self.parse_jump_table(ctx, destination)?;
2816                InstructionData::BranchTable { opcode, arg, table }
2817            }
2818            InstructionFormat::TernaryImm8 => {
2819                let lhs = self.match_value("expected SSA value first operand")?;
2820                self.match_token(Token::Comma, "expected ',' between operands")?;
2821                let rhs = self.match_value("expected SSA value last operand")?;
2822                self.match_token(Token::Comma, "expected ',' between operands")?;
2823                let imm = self.match_uimm8("expected 8-bit immediate")?;
2824                InstructionData::TernaryImm8 {
2825                    opcode,
2826                    imm,
2827                    args: [lhs, rhs],
2828                }
2829            }
2830            InstructionFormat::Shuffle => {
2831                let a = self.match_value("expected SSA value first operand")?;
2832                self.match_token(Token::Comma, "expected ',' between operands")?;
2833                let b = self.match_value("expected SSA value second operand")?;
2834                self.match_token(Token::Comma, "expected ',' between operands")?;
2835                let uimm128 = self.match_uimm128(I8X16)?;
2836                let imm = ctx.function.dfg.immediates.push(uimm128);
2837                InstructionData::Shuffle {
2838                    opcode,
2839                    imm,
2840                    args: [a, b],
2841                }
2842            }
2843            InstructionFormat::IntCompare => {
2844                let cond = self.match_enum("expected intcc condition code")?;
2845                let lhs = self.match_value("expected SSA value first operand")?;
2846                self.match_token(Token::Comma, "expected ',' between operands")?;
2847                let rhs = self.match_value("expected SSA value second operand")?;
2848                InstructionData::IntCompare {
2849                    opcode,
2850                    cond,
2851                    args: [lhs, rhs],
2852                }
2853            }
2854            InstructionFormat::FloatCompare => {
2855                let cond = self.match_enum("expected floatcc condition code")?;
2856                let lhs = self.match_value("expected SSA value first operand")?;
2857                self.match_token(Token::Comma, "expected ',' between operands")?;
2858                let rhs = self.match_value("expected SSA value second operand")?;
2859                InstructionData::FloatCompare {
2860                    opcode,
2861                    cond,
2862                    args: [lhs, rhs],
2863                }
2864            }
2865            InstructionFormat::Call => {
2866                let func_ref = self.match_fn("expected function reference")?;
2867                ctx.check_fn(func_ref, self.loc)?;
2868                self.match_token(Token::LPar, "expected '(' before arguments")?;
2869                let args = self.parse_value_list()?;
2870                self.match_token(Token::RPar, "expected ')' after arguments")?;
2871                InstructionData::Call {
2872                    opcode,
2873                    func_ref,
2874                    args: args.into_value_list(&[], &mut ctx.function.dfg.value_lists),
2875                }
2876            }
2877            InstructionFormat::CallIndirect => {
2878                let sig_ref = self.match_sig("expected signature reference")?;
2879                ctx.check_sig(sig_ref, self.loc)?;
2880                self.match_token(Token::Comma, "expected ',' between operands")?;
2881                let callee = self.match_value("expected SSA value callee operand")?;
2882                self.match_token(Token::LPar, "expected '(' before arguments")?;
2883                let args = self.parse_value_list()?;
2884                self.match_token(Token::RPar, "expected ')' after arguments")?;
2885                InstructionData::CallIndirect {
2886                    opcode,
2887                    sig_ref,
2888                    args: args.into_value_list(&[callee], &mut ctx.function.dfg.value_lists),
2889                }
2890            }
2891            InstructionFormat::TryCall => {
2892                let func_ref = self.match_fn("expected function reference")?;
2893                ctx.check_fn(func_ref, self.loc)?;
2894                self.match_token(Token::LPar, "expected '(' before arguments")?;
2895                let args = self.parse_value_list()?;
2896                self.match_token(Token::RPar, "expected ')' after arguments")?;
2897                self.match_token(Token::Comma, "expected ',' after argument list")?;
2898                let exception = self.parse_exception_table(ctx)?;
2899                InstructionData::TryCall {
2900                    opcode,
2901                    func_ref,
2902                    args: args.into_value_list(&[], &mut ctx.function.dfg.value_lists),
2903                    exception,
2904                }
2905            }
2906            InstructionFormat::TryCallIndirect => {
2907                let callee = self.match_value("expected SSA value callee operand")?;
2908                self.match_token(Token::LPar, "expected '(' before arguments")?;
2909                let args = self.parse_value_list()?;
2910                self.match_token(Token::RPar, "expected ')' after arguments")?;
2911                self.match_token(Token::Comma, "expected ',' after argument list")?;
2912                let exception = self.parse_exception_table(ctx)?;
2913                InstructionData::TryCallIndirect {
2914                    opcode,
2915                    args: args.into_value_list(&[callee], &mut ctx.function.dfg.value_lists),
2916                    exception,
2917                }
2918            }
2919            InstructionFormat::FuncAddr => {
2920                let func_ref = self.match_fn("expected function reference")?;
2921                ctx.check_fn(func_ref, self.loc)?;
2922                InstructionData::FuncAddr { opcode, func_ref }
2923            }
2924            InstructionFormat::StackAddr => {
2925                let ss = self.match_ss("expected stack slot number: ss«n»")?;
2926                ctx.check_ss(ss, self.loc)?;
2927                let offset = self.optional_offset32()?;
2928                InstructionData::StackAddr {
2929                    opcode,
2930                    stack_slot: ss,
2931                    offset,
2932                }
2933            }
2934            InstructionFormat::DynamicStackAddr => {
2935                let dss = self.match_dss("expected dynamic stack slot number: dss«n»")?;
2936                ctx.check_dss(dss, self.loc)?;
2937                InstructionData::DynamicStackAddr {
2938                    opcode,
2939                    dynamic_stack_slot: dss,
2940                }
2941            }
2942            InstructionFormat::Load => {
2943                let flags = self.optional_memflags()?;
2944                let flags = ctx.function.dfg.mem_flags.insert(flags).unwrap();
2945                let addr = self.match_value("expected SSA value address")?;
2946                let offset = self.optional_offset32()?;
2947                InstructionData::Load {
2948                    opcode,
2949                    flags,
2950                    arg: addr,
2951                    offset,
2952                }
2953            }
2954            InstructionFormat::Store => {
2955                let flags = self.optional_memflags()?;
2956                let flags = ctx.function.dfg.mem_flags.insert(flags).unwrap();
2957                let arg = self.match_value("expected SSA value operand")?;
2958                self.match_token(Token::Comma, "expected ',' between operands")?;
2959                let addr = self.match_value("expected SSA value address")?;
2960                let offset = self.optional_offset32()?;
2961                InstructionData::Store {
2962                    opcode,
2963                    flags,
2964                    args: [arg, addr],
2965                    offset,
2966                }
2967            }
2968            InstructionFormat::Trap => {
2969                let code = self.match_enum("expected trap code")?;
2970                InstructionData::Trap { opcode, code }
2971            }
2972            InstructionFormat::CondTrap => {
2973                let arg = self.match_value("expected SSA value operand")?;
2974                self.match_token(Token::Comma, "expected ',' between operands")?;
2975                let code = self.match_enum("expected trap code")?;
2976                InstructionData::CondTrap { opcode, arg, code }
2977            }
2978            InstructionFormat::AtomicCas => {
2979                let flags = self.optional_memflags()?;
2980                let flags = ctx.function.dfg.mem_flags.insert(flags).unwrap();
2981                let addr = self.match_value("expected SSA value address")?;
2982                self.match_token(Token::Comma, "expected ',' between operands")?;
2983                let expected = self.match_value("expected SSA value address")?;
2984                self.match_token(Token::Comma, "expected ',' between operands")?;
2985                let replacement = self.match_value("expected SSA value address")?;
2986                InstructionData::AtomicCas {
2987                    opcode,
2988                    flags,
2989                    args: [addr, expected, replacement],
2990                }
2991            }
2992            InstructionFormat::AtomicRmw => {
2993                let flags = self.optional_memflags()?;
2994                let flags = ctx.function.dfg.mem_flags.insert(flags).unwrap();
2995                let op = self.match_enum("expected AtomicRmwOp")?;
2996                let addr = self.match_value("expected SSA value address")?;
2997                self.match_token(Token::Comma, "expected ',' between operands")?;
2998                let arg2 = self.match_value("expected SSA value address")?;
2999                InstructionData::AtomicRmw {
3000                    opcode,
3001                    flags,
3002                    op,
3003                    args: [addr, arg2],
3004                }
3005            }
3006            InstructionFormat::LoadNoOffset => {
3007                let flags = self.optional_memflags()?;
3008                let flags = ctx.function.dfg.mem_flags.insert(flags).unwrap();
3009                let addr = self.match_value("expected SSA value address")?;
3010                InstructionData::LoadNoOffset {
3011                    opcode,
3012                    flags,
3013                    arg: addr,
3014                }
3015            }
3016            InstructionFormat::StoreNoOffset => {
3017                let flags = self.optional_memflags()?;
3018                let flags = ctx.function.dfg.mem_flags.insert(flags).unwrap();
3019                let arg = self.match_value("expected SSA value operand")?;
3020                self.match_token(Token::Comma, "expected ',' between operands")?;
3021                let addr = self.match_value("expected SSA value address")?;
3022                InstructionData::StoreNoOffset {
3023                    opcode,
3024                    flags,
3025                    args: [arg, addr],
3026                }
3027            }
3028            InstructionFormat::IntAddTrap => {
3029                let a = self.match_value("expected SSA value operand")?;
3030                self.match_token(Token::Comma, "expected ',' between operands")?;
3031                let b = self.match_value("expected SSA value operand")?;
3032                self.match_token(Token::Comma, "expected ',' between operands")?;
3033                let code = self.match_enum("expected trap code")?;
3034                InstructionData::IntAddTrap {
3035                    opcode,
3036                    args: [a, b],
3037                    code,
3038                }
3039            }
3040            InstructionFormat::ExceptionHandlerAddress => {
3041                let block = self.match_block("expected block")?;
3042                self.match_token(Token::Comma, "expected ',' between operands")?;
3043                let imm = self.match_imm64("expected immediate handler index")?;
3044                InstructionData::ExceptionHandlerAddress { opcode, block, imm }
3045            }
3046        };
3047        Ok(idata)
3048    }
3049}
3050
3051#[cfg(test)]
3052mod tests {
3053    use super::*;
3054    use crate::isaspec::IsaSpec;
3055
3056    #[test]
3057    fn argument_type() {
3058        let mut p = Parser::new("i32 sext");
3059        let arg = p.parse_abi_param().unwrap();
3060        assert_eq!(arg.value_type, types::I32);
3061        assert_eq!(arg.extension, ArgumentExtension::Sext);
3062        assert_eq!(arg.purpose, ArgumentPurpose::Normal);
3063        let ParseError {
3064            location,
3065            message,
3066            is_warning,
3067        } = p.parse_abi_param().unwrap_err();
3068        assert_eq!(location.line_number, 1);
3069        assert_eq!(message, "expected parameter type");
3070        assert!(!is_warning);
3071    }
3072
3073    #[test]
3074    fn aliases() {
3075        let (func, details) = Parser::new(
3076            "function %qux() system_v {
3077                                           block0:
3078                                             v4 = iconst.i8 6
3079                                             v3 -> v4
3080                                             v5 = iconst.i8 17
3081                                             v1 = iadd v3, v5
3082                                           }",
3083        )
3084        .parse_function()
3085        .unwrap();
3086        assert_eq!(func.name.to_string(), "%qux");
3087        let v4 = details.map.lookup_str("v4").unwrap();
3088        assert_eq!(v4.to_string(), "v4");
3089        let v3 = details.map.lookup_str("v3").unwrap();
3090        assert_eq!(v3.to_string(), "v3");
3091        match v3 {
3092            AnyEntity::Value(v3) => {
3093                let aliased_to = func.dfg.resolve_aliases(v3);
3094                assert_eq!(aliased_to.to_string(), "v4");
3095            }
3096            _ => panic!("expected value: {v3}"),
3097        }
3098    }
3099
3100    #[test]
3101    fn signature() {
3102        let sig = Parser::new("()system_v").parse_signature().unwrap();
3103        assert_eq!(sig.params.len(), 0);
3104        assert_eq!(sig.returns.len(), 0);
3105        assert_eq!(sig.call_conv, CallConv::SystemV);
3106
3107        let sig2 =
3108            Parser::new("(i8 uext, f16, f32, f64, f128, i32 sret) -> i32 sext, f64 system_v")
3109                .parse_signature()
3110                .unwrap();
3111        assert_eq!(
3112            sig2.to_string(),
3113            "(i8 uext, f16, f32, f64, f128, i32 sret) -> i32 sext, f64 system_v"
3114        );
3115        assert_eq!(sig2.call_conv, CallConv::SystemV);
3116
3117        // Old-style signature without a calling convention.
3118        assert_eq!(
3119            Parser::new("()").parse_signature().unwrap().to_string(),
3120            "() fast"
3121        );
3122        assert_eq!(
3123            Parser::new("() notacc")
3124                .parse_signature()
3125                .unwrap_err()
3126                .to_string(),
3127            "1: unknown calling convention: notacc"
3128        );
3129
3130        // `void` is not recognized as a type by the lexer. It should not appear in files.
3131        assert_eq!(
3132            Parser::new("() -> void")
3133                .parse_signature()
3134                .unwrap_err()
3135                .to_string(),
3136            "1: expected parameter type"
3137        );
3138        assert_eq!(
3139            Parser::new("i8 -> i8")
3140                .parse_signature()
3141                .unwrap_err()
3142                .to_string(),
3143            "1: expected function signature: ( args... )"
3144        );
3145        assert_eq!(
3146            Parser::new("(i8 -> i8")
3147                .parse_signature()
3148                .unwrap_err()
3149                .to_string(),
3150            "1: expected ')' after function arguments"
3151        );
3152    }
3153
3154    #[test]
3155    fn stack_slot_decl() {
3156        let (func, _) = Parser::new(
3157            "function %foo() system_v {
3158                                       ss3 = explicit_slot 13
3159                                       ss1 = explicit_slot 1
3160                                     }",
3161        )
3162        .parse_function()
3163        .unwrap();
3164        assert_eq!(func.name.to_string(), "%foo");
3165        let mut iter = func.sized_stack_slots.keys();
3166        let _ss0 = iter.next().unwrap();
3167        let ss1 = iter.next().unwrap();
3168        assert_eq!(ss1.to_string(), "ss1");
3169        assert_eq!(
3170            func.sized_stack_slots[ss1].kind,
3171            StackSlotKind::ExplicitSlot
3172        );
3173        assert_eq!(func.sized_stack_slots[ss1].size, 1);
3174        let _ss2 = iter.next().unwrap();
3175        let ss3 = iter.next().unwrap();
3176        assert_eq!(ss3.to_string(), "ss3");
3177        assert_eq!(
3178            func.sized_stack_slots[ss3].kind,
3179            StackSlotKind::ExplicitSlot
3180        );
3181        assert_eq!(func.sized_stack_slots[ss3].size, 13);
3182        assert_eq!(iter.next(), None);
3183
3184        // Catch duplicate definitions.
3185        assert_eq!(
3186            Parser::new(
3187                "function %bar() system_v {
3188                                    ss1  = explicit_slot 13
3189                                    ss1  = explicit_slot 1
3190                                }",
3191            )
3192            .parse_function()
3193            .unwrap_err()
3194            .to_string(),
3195            "3: duplicate entity: ss1"
3196        );
3197    }
3198
3199    #[test]
3200    fn block_header() {
3201        let (func, _) = Parser::new(
3202            "function %blocks() system_v {
3203                                     block0:
3204                                     block4(v3: i32):
3205                                     }",
3206        )
3207        .parse_function()
3208        .unwrap();
3209        assert_eq!(func.name.to_string(), "%blocks");
3210
3211        let mut blocks = func.layout.blocks();
3212
3213        let block0 = blocks.next().unwrap();
3214        assert_eq!(func.dfg.block_params(block0), &[]);
3215
3216        let block4 = blocks.next().unwrap();
3217        let block4_args = func.dfg.block_params(block4);
3218        assert_eq!(block4_args.len(), 1);
3219        assert_eq!(func.dfg.value_type(block4_args[0]), types::I32);
3220    }
3221
3222    #[test]
3223    fn duplicate_block() {
3224        let ParseError {
3225            location,
3226            message,
3227            is_warning,
3228        } = Parser::new(
3229            "function %blocks() system_v {
3230                block0:
3231                block0:
3232                    return 2",
3233        )
3234        .parse_function()
3235        .unwrap_err();
3236
3237        assert_eq!(location.line_number, 3);
3238        assert_eq!(message, "duplicate entity: block0");
3239        assert!(!is_warning);
3240    }
3241
3242    #[test]
3243    fn number_of_blocks() {
3244        let ParseError {
3245            location,
3246            message,
3247            is_warning,
3248        } = Parser::new(
3249            "function %a() {
3250                block100000:",
3251        )
3252        .parse_function()
3253        .unwrap_err();
3254
3255        assert_eq!(location.line_number, 2);
3256        assert_eq!(message, "too many blocks");
3257        assert!(!is_warning);
3258    }
3259
3260    #[test]
3261    fn duplicate_ss() {
3262        let ParseError {
3263            location,
3264            message,
3265            is_warning,
3266        } = Parser::new(
3267            "function %blocks() system_v {
3268                ss0 = explicit_slot 8
3269                ss0 = explicit_slot 8",
3270        )
3271        .parse_function()
3272        .unwrap_err();
3273
3274        assert_eq!(location.line_number, 3);
3275        assert_eq!(message, "duplicate entity: ss0");
3276        assert!(!is_warning);
3277    }
3278
3279    #[test]
3280    fn duplicate_gv() {
3281        let ParseError {
3282            location,
3283            message,
3284            is_warning,
3285        } = Parser::new(
3286            "function %blocks() system_v {
3287                gv0 = vmctx
3288                gv0 = vmctx",
3289        )
3290        .parse_function()
3291        .unwrap_err();
3292
3293        assert_eq!(location.line_number, 3);
3294        assert_eq!(message, "duplicate entity: gv0");
3295        assert!(!is_warning);
3296    }
3297
3298    #[test]
3299    fn duplicate_sig() {
3300        let ParseError {
3301            location,
3302            message,
3303            is_warning,
3304        } = Parser::new(
3305            "function %blocks() system_v {
3306                sig0 = ()
3307                sig0 = ()",
3308        )
3309        .parse_function()
3310        .unwrap_err();
3311
3312        assert_eq!(location.line_number, 3);
3313        assert_eq!(message, "duplicate entity: sig0");
3314        assert!(!is_warning);
3315    }
3316
3317    #[test]
3318    fn duplicate_fn() {
3319        let ParseError {
3320            location,
3321            message,
3322            is_warning,
3323        } = Parser::new(
3324            "function %blocks() system_v {
3325                sig0 = ()
3326                fn0 = %foo sig0
3327                fn0 = %foo sig0",
3328        )
3329        .parse_function()
3330        .unwrap_err();
3331
3332        assert_eq!(location.line_number, 4);
3333        assert_eq!(message, "duplicate entity: fn0");
3334        assert!(!is_warning);
3335    }
3336
3337    #[test]
3338    fn comments() {
3339        let (func, Details { comments, .. }) = Parser::new(
3340            "; before
3341                         function %comment() system_v { ; decl
3342                            ss10  = explicit_slot 13 ; stackslot.
3343                            ; Still stackslot.
3344                         block0: ; Basic block
3345                         trap user42; Instruction
3346                         } ; Trailing.
3347                         ; More trailing.",
3348        )
3349        .parse_function()
3350        .unwrap();
3351        assert_eq!(func.name.to_string(), "%comment");
3352        assert_eq!(comments.len(), 7); // no 'before' comment.
3353        assert_eq!(
3354            comments[0],
3355            Comment {
3356                entity: AnyEntity::Function,
3357                text: "; decl",
3358            }
3359        );
3360        assert_eq!(comments[1].entity.to_string(), "ss10");
3361        assert_eq!(comments[2].entity.to_string(), "ss10");
3362        assert_eq!(comments[2].text, "; Still stackslot.");
3363        assert_eq!(comments[3].entity.to_string(), "block0");
3364        assert_eq!(comments[3].text, "; Basic block");
3365
3366        assert_eq!(comments[4].entity.to_string(), "inst0");
3367        assert_eq!(comments[4].text, "; Instruction");
3368
3369        assert_eq!(comments[5].entity, AnyEntity::Function);
3370        assert_eq!(comments[6].entity, AnyEntity::Function);
3371    }
3372
3373    #[test]
3374    fn test_file() {
3375        let tf = parse_test(
3376            r#"; before
3377                             test cfg option=5
3378                             test verify
3379                             set unwind_info=false
3380                             feature "foo"
3381                             feature !"bar"
3382                             ; still preamble
3383                             function %comment() system_v {}"#,
3384            ParseOptions::default(),
3385        )
3386        .unwrap();
3387        assert_eq!(tf.commands.len(), 2);
3388        assert_eq!(tf.commands[0].command, "cfg");
3389        assert_eq!(tf.commands[1].command, "verify");
3390        match tf.isa_spec {
3391            IsaSpec::None(s) => {
3392                assert!(s.enable_verifier());
3393                assert!(!s.unwind_info());
3394            }
3395            _ => panic!("unexpected ISAs"),
3396        }
3397        assert_eq!(tf.features[0], Feature::With(&"foo"));
3398        assert_eq!(tf.features[1], Feature::Without(&"bar"));
3399        assert_eq!(tf.preamble_comments.len(), 2);
3400        assert_eq!(tf.preamble_comments[0].text, "; before");
3401        assert_eq!(tf.preamble_comments[1].text, "; still preamble");
3402        assert_eq!(tf.functions.len(), 1);
3403        assert_eq!(tf.functions[0].0.name.to_string(), "%comment");
3404    }
3405
3406    #[test]
3407    fn isa_spec() {
3408        assert!(
3409            parse_test(
3410                "target
3411                            function %foo() system_v {}",
3412                ParseOptions::default()
3413            )
3414            .is_err()
3415        );
3416
3417        assert!(
3418            parse_test(
3419                "target x86_64
3420                            set unwind_info=false
3421                            function %foo() system_v {}",
3422                ParseOptions::default()
3423            )
3424            .is_err()
3425        );
3426
3427        match parse_test(
3428            "set unwind_info=false
3429                          target x86_64
3430                          function %foo() system_v {}",
3431            ParseOptions::default(),
3432        )
3433        .unwrap()
3434        .isa_spec
3435        {
3436            IsaSpec::None(_) => panic!("Expected some ISA"),
3437            IsaSpec::Some(v) => {
3438                assert_eq!(v.len(), 1);
3439                assert!(v[0].name() == "x64" || v[0].name() == "x86");
3440            }
3441        }
3442    }
3443
3444    #[test]
3445    fn user_function_name() {
3446        // Valid characters in the name:
3447        let func = Parser::new(
3448            "function u1:2() system_v {
3449                                           block0:
3450                                             trap int_divz
3451                                           }",
3452        )
3453        .parse_function()
3454        .unwrap()
3455        .0;
3456        assert_eq!(func.name.to_string(), "u1:2");
3457
3458        // Invalid characters in the name:
3459        let mut parser = Parser::new(
3460            "function u123:abc() system_v {
3461                                           block0:
3462                                             trap stk_ovf
3463                                           }",
3464        );
3465        assert!(parser.parse_function().is_err());
3466
3467        // Incomplete function names should not be valid:
3468        let mut parser = Parser::new(
3469            "function u() system_v {
3470                                           block0:
3471                                             trap int_ovf
3472                                           }",
3473        );
3474        assert!(parser.parse_function().is_err());
3475
3476        let mut parser = Parser::new(
3477            "function u0() system_v {
3478                                           block0:
3479                                             trap int_ovf
3480                                           }",
3481        );
3482        assert!(parser.parse_function().is_err());
3483
3484        let mut parser = Parser::new(
3485            "function u0:() system_v {
3486                                           block0:
3487                                             trap int_ovf
3488                                           }",
3489        );
3490        assert!(parser.parse_function().is_err());
3491    }
3492
3493    #[test]
3494    fn change_default_calling_convention() {
3495        let code = "function %test() {
3496        block0:
3497            return
3498        }";
3499
3500        // By default the parser will use the fast calling convention if none is specified.
3501        let mut parser = Parser::new(code);
3502        assert_eq!(
3503            parser.parse_function().unwrap().0.signature.call_conv,
3504            CallConv::Fast
3505        );
3506
3507        // However, we can specify a different calling convention to be the default.
3508        let mut parser = Parser::new(code).with_default_calling_convention(CallConv::PreserveAll);
3509        assert_eq!(
3510            parser.parse_function().unwrap().0.signature.call_conv,
3511            CallConv::PreserveAll
3512        );
3513    }
3514
3515    #[test]
3516    fn u8_as_hex() {
3517        fn parse_as_uimm8(text: &str) -> ParseResult<u8> {
3518            Parser::new(text).match_uimm8("unable to parse u8")
3519        }
3520
3521        assert_eq!(parse_as_uimm8("0").unwrap(), 0);
3522        assert_eq!(parse_as_uimm8("0xff").unwrap(), 255);
3523        assert!(parse_as_uimm8("-1").is_err());
3524        assert!(parse_as_uimm8("0xffa").is_err());
3525    }
3526
3527    #[test]
3528    fn i16_as_hex() {
3529        fn parse_as_imm16(text: &str) -> ParseResult<i16> {
3530            Parser::new(text).match_imm16("unable to parse i16")
3531        }
3532
3533        assert_eq!(parse_as_imm16("0x8000").unwrap(), -32768);
3534        assert_eq!(parse_as_imm16("0xffff").unwrap(), -1);
3535        assert_eq!(parse_as_imm16("0").unwrap(), 0);
3536        assert_eq!(parse_as_imm16("0x7fff").unwrap(), 32767);
3537        assert_eq!(
3538            parse_as_imm16("-0x0001").unwrap(),
3539            parse_as_imm16("0xffff").unwrap()
3540        );
3541        assert_eq!(
3542            parse_as_imm16("-0x7fff").unwrap(),
3543            parse_as_imm16("0x8001").unwrap()
3544        );
3545        assert!(parse_as_imm16("0xffffa").is_err());
3546    }
3547
3548    #[test]
3549    fn i32_as_hex() {
3550        fn parse_as_imm32(text: &str) -> ParseResult<i32> {
3551            Parser::new(text).match_imm32("unable to parse i32")
3552        }
3553
3554        assert_eq!(parse_as_imm32("0x80000000").unwrap(), -2147483648);
3555        assert_eq!(parse_as_imm32("0xffffffff").unwrap(), -1);
3556        assert_eq!(parse_as_imm32("0").unwrap(), 0);
3557        assert_eq!(parse_as_imm32("0x7fffffff").unwrap(), 2147483647);
3558        assert_eq!(
3559            parse_as_imm32("-0x00000001").unwrap(),
3560            parse_as_imm32("0xffffffff").unwrap()
3561        );
3562        assert_eq!(
3563            parse_as_imm32("-0x7fffffff").unwrap(),
3564            parse_as_imm32("0x80000001").unwrap()
3565        );
3566        assert!(parse_as_imm32("0xffffffffa").is_err());
3567    }
3568
3569    #[test]
3570    fn i64_as_hex() {
3571        fn parse_as_imm64(text: &str) -> ParseResult<Imm64> {
3572            Parser::new(text).match_imm64("unable to parse Imm64")
3573        }
3574
3575        assert_eq!(
3576            parse_as_imm64("0x8000000000000000").unwrap(),
3577            Imm64::new(-9223372036854775808)
3578        );
3579        assert_eq!(
3580            parse_as_imm64("0xffffffffffffffff").unwrap(),
3581            Imm64::new(-1)
3582        );
3583        assert_eq!(parse_as_imm64("0").unwrap(), Imm64::new(0));
3584        assert_eq!(
3585            parse_as_imm64("0x7fffffffffffffff").unwrap(),
3586            Imm64::new(9223372036854775807)
3587        );
3588        assert_eq!(
3589            parse_as_imm64("-0x0000000000000001").unwrap(),
3590            parse_as_imm64("0xffffffffffffffff").unwrap()
3591        );
3592        assert_eq!(
3593            parse_as_imm64("-0x7fffffffffffffff").unwrap(),
3594            parse_as_imm64("0x8000000000000001").unwrap()
3595        );
3596        assert!(parse_as_imm64("0xffffffffffffffffa").is_err());
3597    }
3598
3599    #[test]
3600    fn uimm128() {
3601        macro_rules! parse_as_constant_data {
3602            ($text:expr, $type:expr) => {{ Parser::new($text).parse_literals_to_constant_data($type) }};
3603        }
3604        macro_rules! can_parse_as_constant_data {
3605            ($text:expr, $type:expr) => {{ assert!(parse_as_constant_data!($text, $type).is_ok()) }};
3606        }
3607        macro_rules! cannot_parse_as_constant_data {
3608            ($text:expr, $type:expr) => {{ assert!(parse_as_constant_data!($text, $type).is_err()) }};
3609        }
3610
3611        can_parse_as_constant_data!("1 2 3 4", I32X4);
3612        can_parse_as_constant_data!("1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16", I8X16);
3613        can_parse_as_constant_data!("0x1.1 0x2.2 0x3.3 0x4.4", F32X4);
3614        can_parse_as_constant_data!("0x0 0x1 0x2 0x3", I32X4);
3615        can_parse_as_constant_data!("-1 0 -1 0 -1 0 -1 0", I16X8);
3616        can_parse_as_constant_data!("0 -1", I64X2);
3617        can_parse_as_constant_data!("-1 0", I64X2);
3618        can_parse_as_constant_data!("-1 -1 -1 -1 -1", I32X4); // note that parse_literals_to_constant_data will leave extra tokens unconsumed
3619
3620        cannot_parse_as_constant_data!("1 2 3", I32X4);
3621        cannot_parse_as_constant_data!(" ", F32X4);
3622    }
3623
3624    #[test]
3625    fn parse_constant_from_booleans() {
3626        let c = Parser::new("-1 0 -1 0")
3627            .parse_literals_to_constant_data(I32X4)
3628            .unwrap();
3629        assert_eq!(
3630            c.into_vec(),
3631            [
3632                0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0
3633            ]
3634        )
3635    }
3636
3637    #[test]
3638    fn parse_unbounded_constants() {
3639        // Unlike match_uimm128, match_hexadecimal_constant can parse byte sequences of any size:
3640        assert_eq!(
3641            Parser::new("0x0100")
3642                .match_hexadecimal_constant("err message")
3643                .unwrap(),
3644            vec![0, 1].into()
3645        );
3646
3647        // Only parse hexadecimal constants:
3648        assert!(
3649            Parser::new("228")
3650                .match_hexadecimal_constant("err message")
3651                .is_err()
3652        );
3653    }
3654
3655    #[test]
3656    fn parse_run_commands() {
3657        // Helper for creating signatures.
3658        fn sig(ins: &[Type], outs: &[Type]) -> Signature {
3659            let mut sig = Signature::new(CallConv::Fast);
3660            for i in ins {
3661                sig.params.push(AbiParam::new(*i));
3662            }
3663            for o in outs {
3664                sig.returns.push(AbiParam::new(*o));
3665            }
3666            sig
3667        }
3668
3669        // Helper for parsing run commands.
3670        fn parse(text: &str, sig: &Signature) -> ParseResult<RunCommand> {
3671            Parser::new(text).parse_run_command(sig)
3672        }
3673
3674        // Check that we can parse and display the same set of run commands.
3675        fn assert_roundtrip(text: &str, sig: &Signature) {
3676            assert_eq!(parse(text, sig).unwrap().to_string(), text);
3677        }
3678        assert_roundtrip("run: %fn0() == 42", &sig(&[], &[I32]));
3679        assert_roundtrip(
3680            "run: %fn0(8, 16, 32, 64) == 1",
3681            &sig(&[I8, I16, I32, I64], &[I8]),
3682        );
3683        assert_roundtrip(
3684            "run: %my_func(1) == 0x0f0e0d0c0b0a09080706050403020100",
3685            &sig(&[I32], &[I8X16]),
3686        );
3687
3688        // Verify that default invocations are created when not specified.
3689        assert_eq!(
3690            parse("run", &sig(&[], &[I32])).unwrap().to_string(),
3691            "run: %default() != 0"
3692        );
3693        assert_eq!(
3694            parse("print", &sig(&[], &[F32X4, I16X8]))
3695                .unwrap()
3696                .to_string(),
3697            "print: %default()"
3698        );
3699
3700        // Demonstrate some unparsable cases.
3701        assert!(parse("print", &sig(&[I32], &[I32])).is_err());
3702        assert!(parse("print:", &sig(&[], &[])).is_err());
3703        assert!(parse("run: ", &sig(&[], &[])).is_err());
3704    }
3705
3706    #[test]
3707    fn parse_data_values() {
3708        fn parse(text: &str, ty: Type) -> DataValue {
3709            Parser::new(text).parse_data_value(ty).unwrap()
3710        }
3711
3712        assert_eq!(parse("8", I8).to_string(), "8");
3713        assert_eq!(parse("16", I16).to_string(), "16");
3714        assert_eq!(parse("32", I32).to_string(), "32");
3715        assert_eq!(parse("64", I64).to_string(), "64");
3716        assert_eq!(
3717            parse("0x01234567_01234567_01234567_01234567", I128).to_string(),
3718            "1512366032949150931280199141537564007"
3719        );
3720        assert_eq!(parse("1234567", I128).to_string(), "1234567");
3721        assert_eq!(parse("0x16.1", F16).to_string(), "0x1.610p4");
3722        assert_eq!(parse("0x32.32", F32).to_string(), "0x1.919000p5");
3723        assert_eq!(parse("0x64.64", F64).to_string(), "0x1.9190000000000p6");
3724        assert_eq!(
3725            parse("0x128.128", F128).to_string(),
3726            "0x1.2812800000000000000000000000p8"
3727        );
3728        assert_eq!(
3729            parse("[0 1 2 3]", I32X4).to_string(),
3730            "0x00000003000000020000000100000000"
3731        );
3732        assert_eq!(parse("[1 2]", I32X2).to_string(), "0x0000000200000001");
3733        assert_eq!(parse("[1 2 3 4]", I8X4).to_string(), "0x04030201");
3734        assert_eq!(parse("[1 2]", I8X2).to_string(), "0x0201");
3735    }
3736
3737    #[test]
3738    fn parse_cold_blocks() {
3739        let code = "function %test() {
3740        block0 cold:
3741            return
3742        block1(v0: i32) cold:
3743            return
3744        block2(v1: i32):
3745            return
3746        }";
3747
3748        let mut parser = Parser::new(code);
3749        let func = parser.parse_function().unwrap().0;
3750        assert_eq!(func.layout.blocks().count(), 3);
3751        assert!(func.layout.is_cold(Block::from_u32(0)));
3752        assert!(func.layout.is_cold(Block::from_u32(1)));
3753        assert!(!func.layout.is_cold(Block::from_u32(2)));
3754    }
3755}