Skip to main content

rucc_ir/
parse.rs

1//! The parser: text back into a module.
2//!
3//! Design: `spec/08-ir.md` section 8.8.
4//!
5//! The other half of the round trip. What the printer wrote, this reads, and printing the
6//! result gives the same bytes back. That is what makes the IR testable without the front end,
7//! what makes a dump worth trusting, and what lets a fuzzer make IR directly.
8//!
9//! # Forward references
10//!
11//! A branch names a block that has not been read yet, and, less obviously, an instruction can
12//! use a value defined further down the text: the blocks are printed in layout order, and
13//! layout order is not required to be an order in which every definition comes before its uses.
14//!
15//! Blocks are easy, because a block is an index and the index is the number in the text. Values
16//! are not, because creating an instruction needs the types of the values it produces, and for
17//! most opcodes that type is the type of the first operand, which may be one of the values that
18//! have not been read yet.
19//!
20//! So a function is read in two passes. The first turns the text into a list of blocks holding
21//! instructions whose operands are still just the numbers they were written as. The second
22//! works out the type of every value and then builds the function. Working the types out
23//! terminates because the only cycles in the definition graph run through block parameters, and
24//! a block parameter has its type written at the block.
25//!
26//! # Numbering
27//!
28//! Values are numbered from zero in print order and so are blocks, so building the function in
29//! print order gives every value and every block the index its number in the text says. The
30//! parser checks that as it goes rather than assuming it, which is what catches a text whose
31//! numbering does not add up.
32
33use std::fmt;
34
35use rucc_base::{Idx, Interner, Symbol};
36use rucc_diag::Span;
37use rucc_target::{TargetInfo, Triple};
38
39use crate::attrs::{AttrSet, Attrs, FpContract};
40use crate::func::Func;
41use crate::inst::{
42    AsmInfo, Block, BlockCall, CallInfo, Imm, Inst, InstData, MemInfo, Meta, MetaNode, Signature,
43    SwitchInfo, Value,
44};
45use crate::module::{
46    Alias, AliasKind, DataLayout, Datum, Global, Linkage, Module, Reloc, TlsModel, Visibility,
47};
48use crate::{
49    Extra, ExtraKind, FORMAT_VERSION, Flags, FloatPred, IntPred, MemOrder, Opcode, RmwOp, Type,
50};
51
52/// Why a module could not be read.
53///
54/// One error and then nothing, rather than a list. A malformed IR dump is a bug in whatever
55/// wrote it or a file somebody edited by hand, and in both cases the first thing that does not
56/// add up is the thing worth reporting.
57#[derive(Clone, Debug, PartialEq, Eq)]
58pub struct ParseError {
59    /// Which line of the text, counting from one.
60    pub line: u32,
61    /// What was wrong with it.
62    pub message: String,
63}
64
65impl fmt::Display for ParseError {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        write!(f, "line {}: {}", self.line, self.message)
68    }
69}
70
71impl std::error::Error for ParseError {}
72
73/// Reads a module from the text the printer writes.
74///
75/// Names are interned into `names`, which is the same interner the printer will be given when
76/// the module is written back out.
77///
78/// # Errors
79///
80/// Gives back the first thing in the text that does not add up, with the line it is on.
81pub fn parse(text: &str, names: &mut Interner) -> Result<Module, ParseError> {
82    Parser::new(text, names).module()
83}
84
85/// Reading one text.
86struct Parser<'a, 'n> {
87    text: &'a str,
88    pos: usize,
89    line: u32,
90    names: &'n mut Interner,
91    /// The highest metadata node any instruction referred to, so that a reference to one that
92    /// is never defined is caught rather than left as an index into nothing.
93    meta_used: Option<(u32, u32)>,
94}
95
96/// A block, read but not yet built.
97struct PendingBlock<'a> {
98    params: Vec<(u32, Type)>,
99    insts: Vec<PendingInst<'a>>,
100}
101
102/// An instruction, read but not yet built. Every value is still the number it was written as.
103struct PendingInst<'a> {
104    opcode: Opcode,
105    flags: Flags,
106    results: Vec<u32>,
107    /// The types written after the opcode, which is none when the operands say them.
108    written: Vec<Type>,
109    args: Vec<u32>,
110    extra: PendingExtra<'a>,
111    line: u32,
112}
113
114/// A branch target, read but not yet built.
115struct PendingCall {
116    block: u32,
117    args: Vec<u32>,
118}
119
120/// The payload of an instruction, read but not yet built.
121enum PendingExtra<'a> {
122    None,
123    /// The text of the constant, which cannot be read until the result type is known.
124    Imm(&'a str),
125    Symbol(Symbol),
126    IntPred(IntPred),
127    FloatPred(FloatPred),
128    Mem(MemInfo),
129    Rmw(RmwOp, MemInfo),
130    Order(MemOrder),
131    Targets(Vec<PendingCall>),
132    Call {
133        callee: Option<Symbol>,
134        signature: Signature,
135    },
136    Switch {
137        targets: Vec<PendingCall>,
138        cases: Vec<&'a str>,
139    },
140    Asm {
141        template: Symbol,
142        constraints: Symbol,
143        clobbers: Symbol,
144        targets: Vec<PendingCall>,
145    },
146}
147
148impl<'a, 'n> Parser<'a, 'n> {
149    fn new(text: &'a str, names: &'n mut Interner) -> Self {
150        Parser { text, pos: 0, line: 1, names, meta_used: None }
151    }
152
153    // The whole module.
154
155    fn module(mut self) -> Result<Module, ParseError> {
156        let name = self.header_name()?;
157        self.expect("; format ")?;
158        let version = self.u32()?;
159        if version != FORMAT_VERSION {
160            return self.fail(format!(
161                "this build reads format {FORMAT_VERSION} and the text says format {version}"
162            ));
163        }
164        self.end_of_line()?;
165
166        self.expect("target triple = ")?;
167        let triple = self.quoted_str()?;
168        let Ok(triple) = triple.parse::<Triple>() else {
169            return self.fail(format!("`{triple}` is not a target triple"));
170        };
171        self.end_of_line()?;
172
173        self.expect("target datalayout = ")?;
174        let layout = self.quoted_str()?;
175        let Some(datalayout) = DataLayout::parse(&layout) else {
176            return self.fail(format!("`{layout}` is not a data layout"));
177        };
178        self.end_of_line()?;
179
180        let name = self.names.intern(&name);
181        let mut module = Module::new(name, &TargetInfo::new(triple));
182        module.datalayout = datalayout;
183
184        loop {
185            self.skip_blank_lines();
186            if self.at_end() {
187                break;
188            }
189            match self.peek_word() {
190                "global" => self.global(&mut module)?,
191                "alias" | "ifunc" => self.alias(&mut module)?,
192                "func" => self.func(&mut module)?,
193                _ if self.at("!") => self.meta(&mut module)?,
194                other => return self.fail(format!("`{other}` does not start anything")),
195            }
196        }
197
198        if let Some((used, line)) = self.meta_used {
199            let count = module.counts().metadata as u32;
200            if used >= count {
201                self.line = line;
202                return self.fail(format!("!{used} is used and never defined"));
203            }
204        }
205        Ok(module)
206    }
207
208    /// The `; ModuleID = 'name'` line, whose name is not quoted the way everything else is.
209    fn header_name(&mut self) -> Result<String, ParseError> {
210        self.expect("; ModuleID = '")?;
211        let start = self.pos;
212        let Some(end) = self.text[start..].find('\'') else {
213            return self.fail("the module name is not closed");
214        };
215        let name = self.text[start..start + end].to_string();
216        self.pos = start + end + 1;
217        self.end_of_line()?;
218        Ok(name)
219    }
220
221    // Globals, aliases and metadata.
222
223    fn global(&mut self, module: &mut Module) -> Result<(), ParseError> {
224        self.expect("global")?;
225        let name = self.symbol()?;
226        self.expect(":")?;
227
228        let mut global = Global::new(name, 0, 1);
229        if self.eat_word("bytes") {
230            global.size = self.u64()?;
231            if self.eat("=") {
232                self.expect("{")?;
233                let mut data = Vec::new();
234                loop {
235                    data.push(self.datum(module)?);
236                    if !self.eat(",") {
237                        break;
238                    }
239                }
240                self.expect("}")?;
241                global.init = Some(module.push_data(&data));
242            }
243        } else {
244            let ty = self.ty()?;
245            self.expect("=")?;
246            let text = self.imm_text()?;
247            let value = self.imm(text, ty)?;
248            let datum = Datum::Scalar { ty, value: module.add_imm(value) };
249            global.size = datum.size(module);
250            global.init = Some(module.push_data(&[datum]));
251        }
252
253        while self.eat(",") {
254            match self.word() {
255                "align" => global.align = self.u32()?,
256                "linkage" => {
257                    global.linkage = self.parenthesised(Linkage::from_name, "a linkage")?
258                }
259                "visibility" => {
260                    global.visibility =
261                        self.parenthesised(Visibility::from_name, "a visibility")?;
262                }
263                "tls" => {
264                    global.tls =
265                        Some(self.parenthesised(TlsModel::from_name, "a thread-local model")?);
266                }
267                "constant" => global.constant = true,
268                "section" => global.section = Some(self.symbol_from_string()?),
269                other => return self.fail(format!("a global has no `{other}`")),
270            }
271        }
272        self.end_of_line()?;
273        module.add_global(global);
274        Ok(())
275    }
276
277    /// One piece of a global's image.
278    fn datum(&mut self, module: &mut Module) -> Result<Datum, ParseError> {
279        match self.peek_word() {
280            "zero" => {
281                self.expect("zero")?;
282                Ok(Datum::Zero(self.u64()?))
283            }
284            "bytes" => {
285                self.expect("bytes")?;
286                let bytes = self.string()?;
287                Ok(Datum::Bytes(module.push_bytes(&bytes)))
288            }
289            "addr" => {
290                self.expect("addr")?;
291                self.expect(".")?;
292                let size = self.u32()?;
293                let symbol = self.symbol()?;
294                let addend = if self.eat("+") {
295                    self.i64()?
296                } else if self.eat("-") {
297                    let amount = self.i64()?;
298                    match amount.checked_neg() {
299                        Some(negated) => negated,
300                        None => return self.fail("that offset has no negative"),
301                    }
302                } else {
303                    0
304                };
305                Ok(Datum::Addr(module.add_reloc(Reloc { symbol, addend, size })))
306            }
307            _ => {
308                let ty = self.ty()?;
309                let text = self.imm_text()?;
310                let value = self.imm(text, ty)?;
311                Ok(Datum::Scalar { ty, value: module.add_imm(value) })
312            }
313        }
314    }
315
316    fn alias(&mut self, module: &mut Module) -> Result<(), ParseError> {
317        let word = self.word();
318        let Some(kind) = AliasKind::from_name(word) else {
319            return self.fail(format!("`{word}` is not a kind of alias"));
320        };
321        let name = self.symbol()?;
322        self.expect("=")?;
323        let target = self.symbol()?;
324        let mut alias = Alias::new(name, target);
325        alias.kind = kind;
326        while self.eat(",") {
327            match self.word() {
328                "linkage" => alias.linkage = self.parenthesised(Linkage::from_name, "a linkage")?,
329                "visibility" => {
330                    alias.visibility = self.parenthesised(Visibility::from_name, "a visibility")?;
331                }
332                other => return self.fail(format!("an alias has no `{other}`")),
333            }
334        }
335        self.end_of_line()?;
336        module.add_alias(alias);
337        Ok(())
338    }
339
340    fn meta(&mut self, module: &mut Module) -> Result<(), ParseError> {
341        let index = self.meta_ref()?;
342        let expected = module.counts().metadata as u32;
343        if index.raw() != expected {
344            return self.fail(format!("metadata is numbered in order and !{expected} comes next"));
345        }
346        self.expect("=")?;
347        self.expect("tbaa")?;
348        let name = self.symbol_from_string()?;
349        let mut node = MetaNode { name, parent: None, offset: 0 };
350        while self.eat(",") {
351            match self.word() {
352                "parent" => node.parent = Some(self.meta_ref()?),
353                "offset" => node.offset = self.u64()?,
354                other => return self.fail(format!("a metadata node has no `{other}`")),
355            }
356        }
357        if node.parent.is_some_and(|parent| parent.raw() >= index.raw()) {
358            return self.fail("a metadata node's parent comes before it");
359        }
360        self.end_of_line()?;
361        module.add_meta(node);
362        Ok(())
363    }
364
365    // Functions.
366
367    fn func(&mut self, module: &mut Module) -> Result<(), ParseError> {
368        self.expect("func")?;
369        let name = self.symbol()?;
370        let signature = self.signature()?;
371        let mut func = Func::new(name, signature);
372        while self.eat(",") {
373            match self.word() {
374                "linkage" => func.linkage = self.parenthesised(Linkage::from_name, "a linkage")?,
375                "visibility" => {
376                    func.visibility = self.parenthesised(Visibility::from_name, "a visibility")?;
377                }
378                "attrs" => func.attrs = self.attrs()?,
379                "section" => func.section = Some(self.symbol_from_string()?),
380                other => return self.fail(format!("a function has no `{other}`")),
381            }
382        }
383        if self.eat(";") {
384            self.end_of_line()?;
385            module.add_func(func);
386            return Ok(());
387        }
388        self.expect("{")?;
389        self.end_of_line()?;
390        let blocks = self.body()?;
391        self.build(&mut func, &blocks)?;
392        module.add_func(func);
393        Ok(())
394    }
395
396    /// The parameter and result types, in parentheses and after an arrow.
397    fn signature(&mut self) -> Result<Signature, ParseError> {
398        self.expect("(")?;
399        let mut signature = Signature::new();
400        if !self.eat(")") {
401            loop {
402                if self.eat("...") {
403                    signature.variadic = true;
404                    break;
405                }
406                signature.params.push(self.ty()?);
407                if !self.eat(",") {
408                    break;
409                }
410            }
411            self.expect(")")?;
412        }
413        if self.eat("->") {
414            if self.eat("(") {
415                loop {
416                    signature.returns.push(self.ty()?);
417                    if !self.eat(",") {
418                        break;
419                    }
420                }
421                self.expect(")")?;
422            } else {
423                signature.returns.push(self.ty()?);
424            }
425        }
426        Ok(signature)
427    }
428
429    fn attrs(&mut self) -> Result<Attrs, ParseError> {
430        self.expect("(")?;
431        let mut attrs = Attrs::NONE;
432        loop {
433            let word = self.word();
434            if self.eat("=") {
435                let value = self.word();
436                match word {
437                    "fp_contract" => match FpContract::from_name(value) {
438                        Some(contract) => attrs.fp_contract = contract,
439                        None => return self.fail(format!("`{value}` is not a contraction")),
440                    },
441                    other => return self.fail(format!("`{other}` takes no value")),
442                }
443            } else {
444                match AttrSet::from_name(word) {
445                    Some(attr) => attrs.set |= attr,
446                    None => return self.fail(format!("`{word}` is not an attribute")),
447                }
448            }
449            if !self.eat(",") {
450                break;
451            }
452        }
453        self.expect(")")?;
454        Ok(attrs)
455    }
456
457    /// The blocks of a function, up to the closing brace.
458    fn body(&mut self) -> Result<Vec<PendingBlock<'a>>, ParseError> {
459        let mut blocks: Vec<PendingBlock<'a>> = Vec::new();
460        loop {
461            self.skip_blank_lines();
462            if self.eat("}") {
463                self.end_of_line()?;
464                return Ok(blocks);
465            }
466            if self.at_end() {
467                return self.fail("the function is not closed");
468            }
469            if self.peek_word().starts_with("block") {
470                let number = self.block_ref()?;
471                if number as usize != blocks.len() {
472                    return self.fail(format!(
473                        "blocks are numbered in order and block{} comes next",
474                        blocks.len()
475                    ));
476                }
477                let mut params = Vec::new();
478                if self.eat("(") {
479                    loop {
480                        let value = self.value_ref()?;
481                        self.expect(":")?;
482                        params.push((value, self.ty()?));
483                        if !self.eat(",") {
484                            break;
485                        }
486                    }
487                    self.expect(")")?;
488                }
489                self.expect(":")?;
490                self.end_of_line()?;
491                blocks.push(PendingBlock { params, insts: Vec::new() });
492                continue;
493            }
494            let inst = self.inst()?;
495            match blocks.last_mut() {
496                Some(block) => block.insts.push(inst),
497                None => return self.fail("an instruction before any block"),
498            }
499        }
500    }
501
502    /// One instruction line.
503    fn inst(&mut self) -> Result<PendingInst<'a>, ParseError> {
504        let line = self.line;
505        let mut results = Vec::new();
506        if self.peek_is("%") {
507            results = self.value_list()?;
508            self.expect("=")?;
509        }
510
511        let word = self.word();
512        let Some(opcode) = Opcode::from_name(word) else {
513            return self.fail(format!("`{word}` is not an opcode"));
514        };
515        let (written, flags) = self.suffixes()?;
516
517        let mut args = Vec::new();
518        let extra = match opcode.extra_kind() {
519            ExtraKind::None => {
520                args = self.value_list()?;
521                PendingExtra::None
522            }
523            ExtraKind::Imm => PendingExtra::Imm(self.imm_text()?),
524            ExtraKind::Symbol => {
525                let symbol = self.symbol()?;
526                if self.eat("(") {
527                    args = self.value_list()?;
528                    self.expect(")")?;
529                }
530                PendingExtra::Symbol(symbol)
531            }
532            ExtraKind::IntPred => {
533                let word = self.word();
534                let Some(pred) = IntPred::from_name(word) else {
535                    return self.fail(format!("`{word}` is not an integer comparison"));
536                };
537                args = self.value_list()?;
538                PendingExtra::IntPred(pred)
539            }
540            ExtraKind::FloatPred => {
541                let word = self.word();
542                let Some(pred) = FloatPred::from_name(word) else {
543                    return self.fail(format!("`{word}` is not a floating point comparison"));
544                };
545                args = self.value_list()?;
546                PendingExtra::FloatPred(pred)
547            }
548            ExtraKind::Mem => {
549                if matches!(opcode, Opcode::Store | Opcode::AtomicStore) {
550                    // A store reads left to right like the assignment it came from.
551                    let value = self.value_ref()?;
552                    self.expect("->")?;
553                    args = vec![value, self.value_ref()?];
554                } else {
555                    args = self.value_list()?;
556                }
557                PendingExtra::Mem(self.mem()?)
558            }
559            ExtraKind::Rmw => {
560                let word = self.word();
561                let Some(op) = RmwOp::from_name(word) else {
562                    return self.fail(format!("`{word}` is not a read-modify-write"));
563                };
564                args = self.value_list()?;
565                PendingExtra::Rmw(op, self.mem()?)
566            }
567            ExtraKind::Order => {
568                let word = self.word();
569                let Some(order) = MemOrder::from_name(word) else {
570                    return self.fail(format!("`{word}` is not an ordering"));
571                };
572                PendingExtra::Order(order)
573            }
574            ExtraKind::Targets => {
575                args = self.value_list()?;
576                if !args.is_empty() {
577                    self.expect(",")?;
578                }
579                let mut targets = Vec::new();
580                loop {
581                    targets.push(self.block_call()?);
582                    if !self.eat(",") {
583                        break;
584                    }
585                }
586                PendingExtra::Targets(targets)
587            }
588            ExtraKind::Call => {
589                let callee = if self.peek_is("@") {
590                    Some(self.symbol()?)
591                } else {
592                    args.push(self.value_ref()?);
593                    None
594                };
595                self.expect("(")?;
596                args.extend(self.value_list()?);
597                self.expect(")")?;
598                self.expect(":")?;
599                PendingExtra::Call { callee, signature: self.signature()? }
600            }
601            ExtraKind::Switch => {
602                args = self.value_list()?;
603                let mut targets = Vec::new();
604                let mut cases = Vec::new();
605                if self.eat(",") {
606                    targets.push(self.block_call()?);
607                    self.expect(",")?;
608                    self.expect("[")?;
609                    if !self.eat("]") {
610                        loop {
611                            cases.push(self.imm_text()?);
612                            self.expect("=>")?;
613                            targets.push(self.block_call()?);
614                            if !self.eat(",") {
615                                break;
616                            }
617                        }
618                        self.expect("]")?;
619                    }
620                }
621                PendingExtra::Switch { targets, cases }
622            }
623            ExtraKind::Asm => {
624                let template = self.symbol_from_string()?;
625                self.expect(",")?;
626                let constraints = self.symbol_from_string()?;
627                self.expect(",")?;
628                let clobbers = self.symbol_from_string()?;
629                self.expect("(")?;
630                args = self.value_list()?;
631                self.expect(")")?;
632                let mut targets = Vec::new();
633                if self.eat(",") {
634                    self.expect("labels")?;
635                    self.expect("[")?;
636                    loop {
637                        targets.push(self.block_call()?);
638                        if !self.eat(",") {
639                            break;
640                        }
641                    }
642                    self.expect("]")?;
643                }
644                PendingExtra::Asm { template, constraints, clobbers, targets }
645            }
646        };
647        self.end_of_line()?;
648        Ok(PendingInst { opcode, flags, results, written, args, extra, line })
649    }
650
651    /// The dotted things after an opcode: the result types, then the flags.
652    fn suffixes(&mut self) -> Result<(Vec<Type>, Flags), ParseError> {
653        let mut written = Vec::new();
654        let mut flags = Flags::NONE;
655        while self.at(".") {
656            self.pos += 1;
657            if self.at("(") {
658                self.pos += 1;
659                loop {
660                    written.push(self.ty()?);
661                    if !self.eat(",") {
662                        break;
663                    }
664                }
665                self.expect(")")?;
666                continue;
667            }
668            let word = self.glued_word();
669            if let Some(flag) = Flags::from_name(word) {
670                flags |= flag;
671            } else if let Some(ty) = Type::parse(word) {
672                written.push(ty);
673            } else {
674                return self.fail(format!("`{word}` is neither a type nor a flag"));
675            }
676        }
677        Ok((written, flags))
678    }
679
680    /// What an access carries beyond its address.
681    fn mem(&mut self) -> Result<MemInfo, ParseError> {
682        let mut info = MemInfo { size: 0, align: 1, order: MemOrder::NotAtomic, tbaa: None };
683        while self.eat(",") {
684            let word = self.word();
685            match word {
686                "size" => info.size = self.u64()?,
687                "align" => info.align = self.u32()?,
688                "tbaa" => info.tbaa = Some(self.meta_ref()?),
689                _ => match MemOrder::from_name(word) {
690                    Some(order) => info.order = order,
691                    None => return self.fail(format!("an access has no `{word}`")),
692                },
693            }
694        }
695        Ok(info)
696    }
697
698    /// A branch target and the values it passes.
699    fn block_call(&mut self) -> Result<PendingCall, ParseError> {
700        let block = self.block_ref()?;
701        let mut args = Vec::new();
702        if self.eat("(") {
703            args = self.value_list()?;
704            self.expect(")")?;
705        }
706        Ok(PendingCall { block, args })
707    }
708
709    // Building the function.
710
711    /// Works out every value's type, then creates the blocks and instructions in print order.
712    fn build(&mut self, func: &mut Func, blocks: &[PendingBlock<'a>]) -> Result<(), ParseError> {
713        let count = self.check_numbering(blocks)?;
714        let types = self.value_types(blocks, count)?;
715
716        let mut next = 0;
717        for pending in blocks {
718            let block = func.create_block();
719            for &(number, ty) in &pending.params {
720                if number != next {
721                    self.line = self.line_of(blocks, number);
722                    return self
723                        .fail(format!("values are numbered in order and %{next} comes next"));
724                }
725                func.append_param(block, ty);
726                next += 1;
727            }
728            for inst in &pending.insts {
729                if inst.results.first().is_some_and(|&first| first != next) {
730                    self.line = inst.line;
731                    return self
732                        .fail(format!("values are numbered in order and %{next} comes next"));
733                }
734                let built = self.build_inst(func, inst, &types)?;
735                func.append_inst(block, built);
736                next += inst.results.len() as u32;
737            }
738        }
739        Ok(())
740    }
741
742    /// Checks that every number the text uses is one the text also defines.
743    ///
744    /// The answer is how many values there are, which is what everything after this is sized by.
745    fn check_numbering(&mut self, blocks: &[PendingBlock<'a>]) -> Result<u32, ParseError> {
746        let mut count = 0;
747        for pending in blocks {
748            count += pending.params.len();
749            for inst in &pending.insts {
750                count += inst.results.len();
751            }
752        }
753        let count = count as u32;
754        let total = blocks.len() as u32;
755        for pending in blocks {
756            for inst in &pending.insts {
757                self.line = inst.line;
758                for &arg in &inst.args {
759                    if arg >= count {
760                        return self.fail(format!("%{arg} is used and never defined"));
761                    }
762                }
763                for call in inst_calls(inst) {
764                    if call.block >= total {
765                        return self.fail(format!("block{} is used and never defined", call.block));
766                    }
767                    for &arg in &call.args {
768                        if arg >= count {
769                            return self.fail(format!("%{arg} is used and never defined"));
770                        }
771                    }
772                }
773            }
774        }
775        Ok(count)
776    }
777
778    /// The type of every value, worked out from the ones the text writes down.
779    ///
780    /// A block parameter has its type at the block and an instruction either has its written
781    /// after the opcode or takes it from an operand, so this is a fixed point over a graph whose
782    /// only cycles run through parameters. It converges in as many rounds as the longest chain
783    /// of instructions each taking its type from the one below it in the text.
784    fn value_types(
785        &mut self,
786        blocks: &[PendingBlock<'a>],
787        count: u32,
788    ) -> Result<Vec<Option<Type>>, ParseError> {
789        let mut types = vec![None; count as usize];
790        for pending in blocks {
791            for &(number, ty) in &pending.params {
792                types[number as usize] = Some(ty);
793            }
794        }
795        loop {
796            let mut progress = false;
797            for pending in blocks {
798                for inst in &pending.insts {
799                    let Some(&first) = inst.results.first() else { continue };
800                    if types[first as usize].is_some() {
801                        continue;
802                    }
803                    let Some(resolved) = result_types(inst, &types) else { continue };
804                    if resolved.len() != inst.results.len() {
805                        self.line = inst.line;
806                        return self.fail(format!(
807                            "{} produces {} values and the text names {}",
808                            inst.opcode.name(),
809                            resolved.len(),
810                            inst.results.len()
811                        ));
812                    }
813                    for (&number, ty) in inst.results.iter().zip(resolved) {
814                        types[number as usize] = Some(ty);
815                    }
816                    progress = true;
817                }
818            }
819            if !progress {
820                break;
821            }
822        }
823        for pending in blocks {
824            for inst in &pending.insts {
825                if inst.results.first().is_some_and(|&first| types[first as usize].is_none()) {
826                    self.line = inst.line;
827                    return self.fail(format!(
828                        "nothing in the text says what {} produces",
829                        inst.opcode.name()
830                    ));
831                }
832            }
833        }
834        Ok(types)
835    }
836
837    fn build_inst(
838        &mut self,
839        func: &mut Func,
840        pending: &PendingInst<'a>,
841        types: &[Option<Type>],
842    ) -> Result<Inst, ParseError> {
843        let results: Vec<Type> = pending
844            .results
845            .iter()
846            .map(|&number| types[number as usize].unwrap_or(Type::VOID))
847            .collect();
848        let args: Vec<Value> =
849            pending.args.iter().map(|&number| Value::from_usize(number as usize)).collect();
850        let arg_list = func.push_values(&args);
851
852        let extra = match &pending.extra {
853            PendingExtra::None => Extra::None,
854            PendingExtra::Imm(text) => {
855                let ty = results.first().copied().unwrap_or(Type::VOID);
856                self.line = pending.line;
857                let imm = self.imm(text, ty)?;
858                Extra::Imm(func.add_imm(imm))
859            }
860            PendingExtra::Symbol(symbol) => Extra::Symbol(*symbol),
861            PendingExtra::IntPred(pred) => Extra::IntPred(*pred),
862            PendingExtra::FloatPred(pred) => Extra::FloatPred(*pred),
863            PendingExtra::Mem(info) => Extra::Mem(func.add_mem(*info)),
864            PendingExtra::Rmw(op, info) => Extra::Rmw(*op, func.add_mem(*info)),
865            PendingExtra::Order(order) => Extra::Order(*order),
866            PendingExtra::Targets(targets) => {
867                let calls = build_calls(func, targets);
868                Extra::Targets(func.push_block_calls(&calls))
869            }
870            PendingExtra::Call { callee, signature } => {
871                let sig = func.add_signature(signature.clone());
872                Extra::Call(func.add_call(CallInfo { callee: *callee, signature: sig }))
873            }
874            PendingExtra::Switch { targets, cases } => {
875                let ty = pending
876                    .args
877                    .first()
878                    .and_then(|&number| types[number as usize])
879                    .unwrap_or(Type::VOID);
880                self.line = pending.line;
881                let mut imms = Vec::with_capacity(cases.len());
882                for case in cases {
883                    imms.push(self.imm(case, ty)?);
884                }
885                let calls = build_calls(func, targets);
886                let targets = func.push_block_calls(&calls);
887                let cases = func.push_imms(&imms);
888                Extra::Switch(func.add_switch(SwitchInfo { targets, cases }))
889            }
890            PendingExtra::Asm { template, constraints, clobbers, targets } => {
891                let calls = build_calls(func, targets);
892                let targets = func.push_block_calls(&calls);
893                Extra::Asm(func.add_asm(AsmInfo {
894                    template: *template,
895                    constraints: *constraints,
896                    clobbers: *clobbers,
897                    targets,
898                }))
899            }
900        };
901
902        let data = InstData {
903            opcode: pending.opcode,
904            flags: pending.flags,
905            args: arg_list,
906            extra,
907            ..InstData::new(pending.opcode)
908        };
909        Ok(func.create_inst(data, &results, Span::DUMMY))
910    }
911
912    /// The line a value number is defined on, for a message about the numbering.
913    fn line_of(&self, blocks: &[PendingBlock<'a>], number: u32) -> u32 {
914        for pending in blocks {
915            for inst in &pending.insts {
916                if inst.results.contains(&number) {
917                    return inst.line;
918                }
919            }
920        }
921        self.line
922    }
923
924    // Tokens.
925
926    /// A constant, read as the type it is a constant of.
927    fn imm(&mut self, text: &str, ty: Type) -> Result<Imm, ParseError> {
928        let scalar = if ty.is_vector() { ty.lane() } else { ty };
929        if scalar.is_int() {
930            match parse_i128(text) {
931                Some(value) => Ok(Imm::int(value, scalar)),
932                None => self.fail(format!("`{text}` is not an {scalar}")),
933            }
934        } else {
935            match text.strip_prefix("0x").and_then(|rest| u128::from_str_radix(rest, 16).ok()) {
936                Some(bits) => Ok(Imm::from_bits(bits)),
937                None => self.fail(format!("`{text}` is not the bits of a {scalar}")),
938            }
939        }
940    }
941
942    /// The text of a constant, which is a sign, digits, and the letters a hexadecimal one has.
943    fn imm_text(&mut self) -> Result<&'a str, ParseError> {
944        self.spaces();
945        let start = self.pos;
946        if self.at("-") {
947            self.pos += 1;
948        }
949        while self.peek().is_some_and(|byte| byte.is_ascii_alphanumeric()) {
950            self.pos += 1;
951        }
952        if self.pos == start {
953            return self.fail("a constant was expected");
954        }
955        Ok(&self.text[start..self.pos])
956    }
957
958    fn ty(&mut self) -> Result<Type, ParseError> {
959        let word = self.word();
960        match Type::parse(word) {
961            Some(ty) => Ok(ty),
962            None => self.fail(format!("`{word}` is not a type")),
963        }
964    }
965
966    /// A `%n`, giving back the number.
967    fn value_ref(&mut self) -> Result<u32, ParseError> {
968        self.expect("%")?;
969        self.u32()
970    }
971
972    /// A run of `%n` separated by commas, stopping at the first comma not followed by one.
973    fn value_list(&mut self) -> Result<Vec<u32>, ParseError> {
974        let mut values = Vec::new();
975        if !self.peek_is("%") {
976            return Ok(values);
977        }
978        loop {
979            values.push(self.value_ref()?);
980            let save = self.pos;
981            if !self.eat(",") {
982                return Ok(values);
983            }
984            if !self.peek_is("%") {
985                self.pos = save;
986                return Ok(values);
987            }
988        }
989    }
990
991    /// A `blockN`, giving back the number.
992    fn block_ref(&mut self) -> Result<u32, ParseError> {
993        let word = self.word();
994        match word.strip_prefix("block").and_then(parse_u32) {
995            Some(number) => Ok(number),
996            None => self.fail(format!("`{word}` is not a block")),
997        }
998    }
999
1000    /// A `!n`, remembering it so that one nothing defines is reported.
1001    fn meta_ref(&mut self) -> Result<Meta, ParseError> {
1002        self.expect("!")?;
1003        let index = self.u32()?;
1004        let seen = self.meta_used.is_none_or(|(used, _)| index > used);
1005        if seen {
1006            self.meta_used = Some((index, self.line));
1007        }
1008        Ok(Idx::from_usize(index as usize))
1009    }
1010
1011    /// An `@name`, interned.
1012    fn symbol(&mut self) -> Result<Symbol, ParseError> {
1013        self.expect("@")?;
1014        let start = self.pos;
1015        while self.peek().is_some_and(is_name_byte) {
1016            self.pos += 1;
1017        }
1018        if self.pos == start {
1019            return self.fail("a name was expected");
1020        }
1021        let name = &self.text[start..self.pos];
1022        Ok(self.names.intern(name))
1023    }
1024
1025    /// A quoted string, interned, which is what a section and a template are.
1026    fn symbol_from_string(&mut self) -> Result<Symbol, ParseError> {
1027        let text = self.quoted_str()?;
1028        Ok(self.names.intern(&text))
1029    }
1030
1031    /// A quoted string that has to be text rather than arbitrary bytes.
1032    fn quoted_str(&mut self) -> Result<String, ParseError> {
1033        let bytes = self.string()?;
1034        match String::from_utf8(bytes) {
1035            Ok(text) => Ok(text),
1036            Err(_) => self.fail("that string is not text"),
1037        }
1038    }
1039
1040    /// A quoted string, which may hold any bytes at all.
1041    fn string(&mut self) -> Result<Vec<u8>, ParseError> {
1042        self.expect("\"")?;
1043        let mut bytes = Vec::new();
1044        loop {
1045            let Some(byte) = self.peek() else {
1046                return self.fail("that string is not closed");
1047            };
1048            self.pos += 1;
1049            match byte {
1050                b'"' => return Ok(bytes),
1051                b'\n' => return self.fail("that string is not closed"),
1052                b'\\' => {
1053                    let escape = match self.peek() {
1054                        Some(b'"') => b'"',
1055                        Some(b'\\') => b'\\',
1056                        _ => {
1057                            let hex = self.text.get(self.pos..self.pos + 2);
1058                            match hex.and_then(|hex| u8::from_str_radix(hex, 16).ok()) {
1059                                Some(byte) => {
1060                                    self.pos += 2;
1061                                    bytes.push(byte);
1062                                    continue;
1063                                }
1064                                None => return self.fail("that is not an escape"),
1065                            }
1066                        }
1067                    };
1068                    self.pos += 1;
1069                    bytes.push(escape);
1070                }
1071                _ => bytes.push(byte),
1072            }
1073        }
1074    }
1075
1076    fn u32(&mut self) -> Result<u32, ParseError> {
1077        let word = self.word();
1078        match parse_u32(word) {
1079            Some(number) => Ok(number),
1080            None => self.fail(format!("`{word}` is not a number")),
1081        }
1082    }
1083
1084    fn u64(&mut self) -> Result<u64, ParseError> {
1085        let word = self.word();
1086        match parse_u64(word) {
1087            Some(number) => Ok(number),
1088            None => self.fail(format!("`{word}` is not a number")),
1089        }
1090    }
1091
1092    fn i64(&mut self) -> Result<i64, ParseError> {
1093        let word = self.word();
1094        match parse_u64(word).and_then(|number| i64::try_from(number).ok()) {
1095            Some(number) => Ok(number),
1096            None => self.fail(format!("`{word}` is not an offset")),
1097        }
1098    }
1099
1100    /// One of the keyword parenthesised after a name, as in `linkage(internal)`.
1101    fn parenthesised<T>(
1102        &mut self,
1103        from_name: impl Fn(&str) -> Option<T>,
1104        what: &str,
1105    ) -> Result<T, ParseError> {
1106        self.expect("(")?;
1107        let word = self.word();
1108        let Some(value) = from_name(word) else {
1109            return self.fail(format!("`{word}` is not {what}"));
1110        };
1111        self.expect(")")?;
1112        Ok(value)
1113    }
1114
1115    // The cursor.
1116
1117    fn fail<T>(&self, message: impl Into<String>) -> Result<T, ParseError> {
1118        Err(ParseError { line: self.line, message: message.into() })
1119    }
1120
1121    fn peek(&self) -> Option<u8> {
1122        self.text.as_bytes().get(self.pos).copied()
1123    }
1124
1125    fn at(&self, text: &str) -> bool {
1126        self.text[self.pos..].starts_with(text)
1127    }
1128
1129    fn at_end(&self) -> bool {
1130        self.pos >= self.text.len()
1131    }
1132
1133    /// Whether that text comes next, ignoring the spaces in front of it.
1134    fn peek_is(&self, text: &str) -> bool {
1135        self.text[self.pos..].trim_start_matches([' ', '\t']).starts_with(text)
1136    }
1137
1138    fn spaces(&mut self) {
1139        while matches!(self.peek(), Some(b' ' | b'\t')) {
1140            self.pos += 1;
1141        }
1142    }
1143
1144    fn eat(&mut self, text: &str) -> bool {
1145        self.spaces();
1146        if self.at(text) {
1147            self.pos += text.len();
1148            return true;
1149        }
1150        false
1151    }
1152
1153    fn expect(&mut self, text: &str) -> Result<(), ParseError> {
1154        if self.eat(text) {
1155            return Ok(());
1156        }
1157        self.fail(format!("`{text}` was expected"))
1158    }
1159
1160    /// A word of letters, digits and underscores, after the spaces in front of it.
1161    fn word(&mut self) -> &'a str {
1162        self.spaces();
1163        self.glued_word()
1164    }
1165
1166    /// The same, with nothing skipped, which is what a suffix after a dot is.
1167    fn glued_word(&mut self) -> &'a str {
1168        let start = self.pos;
1169        while self.peek().is_some_and(|byte| byte.is_ascii_alphanumeric() || byte == b'_') {
1170            self.pos += 1;
1171        }
1172        &self.text[start..self.pos]
1173    }
1174
1175    /// The next word without consuming it, for deciding what a line is.
1176    fn peek_word(&self) -> &'a str {
1177        let rest = self.text[self.pos..].trim_start_matches([' ', '\t']);
1178        let end =
1179            rest.find(|c: char| !(c.is_ascii_alphanumeric() || c == '_')).unwrap_or(rest.len());
1180        &rest[..end]
1181    }
1182
1183    /// Whether that word comes next, consuming it if so.
1184    fn eat_word(&mut self, word: &str) -> bool {
1185        if self.peek_word() == word {
1186            self.word();
1187            return true;
1188        }
1189        false
1190    }
1191
1192    fn end_of_line(&mut self) -> Result<(), ParseError> {
1193        self.spaces();
1194        if self.at_end() {
1195            return Ok(());
1196        }
1197        if self.at("\n") {
1198            self.pos += 1;
1199            self.line += 1;
1200            return Ok(());
1201        }
1202        let rest = &self.text[self.pos..];
1203        let end = rest.find('\n').unwrap_or(rest.len());
1204        self.fail(format!("`{}` is left over at the end of the line", &rest[..end]))
1205    }
1206
1207    fn skip_blank_lines(&mut self) {
1208        loop {
1209            let save = self.pos;
1210            self.spaces();
1211            if self.at("\n") {
1212                self.pos += 1;
1213                self.line += 1;
1214            } else {
1215                self.pos = save;
1216                return;
1217            }
1218        }
1219    }
1220}
1221
1222/// Every branch target an instruction has, whichever payload holds them.
1223fn inst_calls<'p>(inst: &'p PendingInst<'_>) -> &'p [PendingCall] {
1224    match &inst.extra {
1225        PendingExtra::Targets(targets)
1226        | PendingExtra::Switch { targets, .. }
1227        | PendingExtra::Asm { targets, .. } => targets,
1228        _ => &[],
1229    }
1230}
1231
1232/// The branch targets of an instruction, with their arguments put in the function's pool.
1233fn build_calls(func: &mut Func, targets: &[PendingCall]) -> Vec<BlockCall> {
1234    targets
1235        .iter()
1236        .map(|call| {
1237            let args: Vec<Value> =
1238                call.args.iter().map(|&number| Value::from_usize(number as usize)).collect();
1239            BlockCall {
1240                block: Block::from_usize(call.block as usize),
1241                args: func.push_values(&args),
1242            }
1243        })
1244        .collect()
1245}
1246
1247/// What an instruction produces, or `None` while an operand's type is still unknown.
1248///
1249/// This is the reading half of the rule the printer writes by, which is why the two of them
1250/// name the same opcodes: a type is in the text only where the operands do not say it.
1251fn result_types(inst: &PendingInst<'_>, types: &[Option<Type>]) -> Option<Vec<Type>> {
1252    if inst.results.is_empty() {
1253        return Some(Vec::new());
1254    }
1255    if !inst.written.is_empty() {
1256        return Some(inst.written.clone());
1257    }
1258    match inst.opcode {
1259        Opcode::GlobalAddr | Opcode::Alloca => Some(vec![Type::PTR]),
1260        Opcode::ICmp | Opcode::FCmp => {
1261            let ty = arg_type(inst, types)?;
1262            Some(vec![ty.with_lane(Type::I1)])
1263        }
1264        Opcode::Call | Opcode::CallIndirect | Opcode::TailCall => match &inst.extra {
1265            PendingExtra::Call { signature, .. } => Some(signature.returns.clone()),
1266            _ => None,
1267        },
1268        _ => Some(vec![arg_type(inst, types)?]),
1269    }
1270}
1271
1272/// The type of an instruction's first operand, if it is known yet.
1273fn arg_type(inst: &PendingInst<'_>, types: &[Option<Type>]) -> Option<Type> {
1274    let &first = inst.args.first()?;
1275    *types.get(first as usize)?
1276}
1277
1278/// A decimal number with no sign and no leading zero, which is the only form the printer writes.
1279fn parse_u64(text: &str) -> Option<u64> {
1280    if text.is_empty() || (text.starts_with('0') && text.len() > 1) {
1281        return None;
1282    }
1283    if !text.bytes().all(|byte| byte.is_ascii_digit()) {
1284        return None;
1285    }
1286    text.parse().ok()
1287}
1288
1289fn parse_u32(text: &str) -> Option<u32> {
1290    parse_u64(text).and_then(|number| u32::try_from(number).ok())
1291}
1292
1293/// A decimal integer, with a minus sign for a negative one, as the printer writes them.
1294fn parse_i128(text: &str) -> Option<i128> {
1295    let (negative, digits) = match text.strip_prefix('-') {
1296        Some(rest) => (true, rest),
1297        None => (false, text),
1298    };
1299    if digits.is_empty() || (digits.starts_with('0') && digits.len() > 1) {
1300        return None;
1301    }
1302    if negative && digits == "0" {
1303        return None;
1304    }
1305    if !digits.bytes().all(|byte| byte.is_ascii_digit()) {
1306        return None;
1307    }
1308    let magnitude: u128 = digits.parse().ok()?;
1309    if negative {
1310        // The most negative number has no positive counterpart, so it is built by negating the
1311        // wrapped value rather than by converting first.
1312        (magnitude <= 1 << 127).then(|| (magnitude as i128).wrapping_neg())
1313    } else {
1314        i128::try_from(magnitude).ok()
1315    }
1316}
1317
1318/// Whether a byte can appear in a symbol name.
1319///
1320/// Dots are in, because a compiler names things `hi.str` and `memcpy.resolve` and the assembler
1321/// takes them.
1322fn is_name_byte(byte: u8) -> bool {
1323    byte.is_ascii_alphanumeric() || matches!(byte, b'_' | b'.' | b'$')
1324}
1325
1326#[cfg(test)]
1327mod tests {
1328    use rucc_base::Interner;
1329
1330    use super::*;
1331    use crate::fixtures::{EXAMPLE, SYMBOLS, ZOO};
1332    use crate::print;
1333
1334    /// Reads a module and writes it back out, which is the whole claim this file makes.
1335    fn round_trip(text: &str) -> String {
1336        let mut names = Interner::new();
1337        let module = match parse(text, &mut names) {
1338            Ok(module) => module,
1339            Err(error) => panic!("{error}"),
1340        };
1341        print(&module, &names)
1342    }
1343
1344    fn error(text: &str) -> String {
1345        let mut names = Interner::new();
1346        match parse(text, &mut names) {
1347            Ok(_) => panic!("that was expected to be turned down"),
1348            Err(error) => error.to_string(),
1349        }
1350    }
1351
1352    const HEADER: &str = "\
1353; ModuleID = 'example.c'
1354; format 0
1355target triple = \"x86_64-unknown-linux-gnu\"
1356target datalayout = \"e-p:64:64-i64:64-f80:128-S128\"
1357";
1358
1359    #[test]
1360    fn the_example_in_the_spec_comes_back_byte_for_byte() {
1361        assert_eq!(round_trip(EXAMPLE), EXAMPLE);
1362    }
1363
1364    #[test]
1365    fn one_of_almost_everything_comes_back_byte_for_byte() {
1366        assert_eq!(round_trip(ZOO), ZOO);
1367    }
1368
1369    #[test]
1370    fn the_shapes_a_symbol_comes_in_come_back_byte_for_byte() {
1371        assert_eq!(round_trip(SYMBOLS), SYMBOLS);
1372    }
1373
1374    #[test]
1375    fn a_value_defined_after_it_is_used() {
1376        // Block layout order is not required to put a definition before its uses, so the type
1377        // of %2 is only known after the whole function has been read. This is the case the two
1378        // passes exist for.
1379        let text = format!(
1380            "{HEADER}
1381func @late() -> i64, linkage(external) {{
1382block0:
1383    jump block2
1384
1385block1(%0: i64):
1386    %1 = add %2, %0
1387    return %1
1388
1389block2:
1390    %2 = iconst.i64 7
1391    jump block1(%2)
1392}}
1393"
1394        );
1395        assert_eq!(round_trip(&text), text);
1396    }
1397
1398    #[test]
1399    fn an_empty_module_is_its_header() {
1400        assert_eq!(round_trip(HEADER), HEADER);
1401    }
1402
1403    #[test]
1404    fn the_format_version_is_checked_before_anything_else() {
1405        let text = "; ModuleID = 'a.c'\n; format 99\n";
1406        assert_eq!(error(text), "line 2: this build reads format 0 and the text says format 99");
1407    }
1408
1409    #[test]
1410    fn an_opcode_nobody_has_is_reported_with_its_line() {
1411        let text = format!(
1412            "{HEADER}
1413func @f(), linkage(external) {{
1414block0:
1415    getelementptr %0
1416}}
1417"
1418        );
1419        assert_eq!(error(&text), "line 8: `getelementptr` is not an opcode");
1420    }
1421
1422    #[test]
1423    fn a_value_nothing_defines_is_reported() {
1424        let text = format!(
1425            "{HEADER}
1426func @f(i32) -> i32, linkage(external) {{
1427block0(%0: i32):
1428    %1 = add %0, %9
1429    return %1
1430}}
1431"
1432        );
1433        assert_eq!(error(&text), "line 8: %9 is used and never defined");
1434    }
1435
1436    #[test]
1437    fn a_block_nothing_defines_is_reported() {
1438        let text = format!(
1439            "{HEADER}
1440func @f(), linkage(external) {{
1441block0:
1442    jump block7
1443}}
1444"
1445        );
1446        assert_eq!(error(&text), "line 8: block7 is used and never defined");
1447    }
1448
1449    #[test]
1450    fn values_have_to_be_numbered_in_print_order() {
1451        let text = format!(
1452            "{HEADER}
1453func @f() -> i32, linkage(external) {{
1454block0:
1455    %1 = iconst.i32 0
1456    %0 = iconst.i32 1
1457    return %1
1458}}
1459"
1460        );
1461        assert_eq!(error(&text), "line 8: values are numbered in order and %0 comes next");
1462    }
1463
1464    #[test]
1465    fn blocks_have_to_be_numbered_in_print_order() {
1466        let text = format!(
1467            "{HEADER}
1468func @f(), linkage(external) {{
1469block1:
1470    return
1471}}
1472"
1473        );
1474        assert_eq!(error(&text), "line 7: blocks are numbered in order and block0 comes next");
1475    }
1476
1477    #[test]
1478    fn metadata_nobody_defines_is_reported() {
1479        let text = format!(
1480            "{HEADER}
1481func @f(ptr), linkage(external) {{
1482block0(%0: ptr):
1483    %1 = load.i32 %0, align 4, tbaa !3
1484    return
1485}}
1486"
1487        );
1488        assert_eq!(error(&text), "line 8: !3 is used and never defined");
1489    }
1490
1491    #[test]
1492    fn a_type_nothing_says_is_reported_rather_than_guessed() {
1493        let text = format!(
1494            "{HEADER}
1495func @f(), linkage(external) {{
1496block0:
1497    %0 = add
1498    return
1499}}
1500"
1501        );
1502        assert_eq!(error(&text), "line 8: nothing in the text says what add produces");
1503    }
1504
1505    #[test]
1506    fn a_line_with_something_left_on_it_is_turned_down() {
1507        let text = format!(
1508            "{HEADER}
1509global @x : i32 = 0, align 4, linkage(internal) and then some
1510"
1511        );
1512        assert_eq!(error(&text), "line 6: `and then some` is left over at the end of the line");
1513    }
1514
1515    #[test]
1516    fn a_constant_that_is_not_one_is_turned_down() {
1517        let text = format!(
1518            "{HEADER}
1519global @x : i32 = 007, align 4, linkage(internal)
1520"
1521        );
1522        assert_eq!(error(&text), "line 6: `007` is not an i32");
1523    }
1524
1525    #[test]
1526    fn a_number_is_read_the_way_the_printer_writes_it() {
1527        assert_eq!(parse_i128("-1"), Some(-1));
1528        assert_eq!(parse_i128("0"), Some(0));
1529        assert_eq!(parse_i128("-0"), None);
1530        assert_eq!(parse_i128("+1"), None);
1531        assert_eq!(parse_i128("01"), None);
1532        assert_eq!(parse_i128(""), None);
1533        assert_eq!(parse_i128("170141183460469231731687303715884105728"), None);
1534        assert_eq!(parse_i128("-170141183460469231731687303715884105728"), Some(i128::MIN));
1535    }
1536
1537    #[test]
1538    fn every_opcode_says_which_payload_it_carries() {
1539        // A payload the parser does not expect for that opcode is text it cannot read back, so
1540        // the two of them agreeing is what this file rests on.
1541        for opcode in Opcode::all() {
1542            let kind = opcode.extra_kind();
1543            let expected = match opcode {
1544                Opcode::IConst | Opcode::FConst | Opcode::Splat => ExtraKind::Imm,
1545                Opcode::GlobalAddr | Opcode::TargetIntrinsic => ExtraKind::Symbol,
1546                Opcode::ICmp => ExtraKind::IntPred,
1547                Opcode::FCmp => ExtraKind::FloatPred,
1548                Opcode::Fence => ExtraKind::Order,
1549                Opcode::AtomicRmw => ExtraKind::Rmw,
1550                Opcode::Switch => ExtraKind::Switch,
1551                Opcode::InlineAsm => ExtraKind::Asm,
1552                Opcode::Jump | Opcode::BrIf => ExtraKind::Targets,
1553                Opcode::Call | Opcode::CallIndirect | Opcode::TailCall => ExtraKind::Call,
1554                Opcode::Alloca
1555                | Opcode::Load
1556                | Opcode::Store
1557                | Opcode::Memcpy
1558                | Opcode::Memmove
1559                | Opcode::Memset
1560                | Opcode::AtomicLoad
1561                | Opcode::AtomicStore
1562                | Opcode::Cmpxchg => ExtraKind::Mem,
1563                _ => ExtraKind::None,
1564            };
1565            assert_eq!(kind, expected, "{}", opcode.name());
1566        }
1567    }
1568}