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    Abi, AsmInfo, Block, BlockCall, CallInfo, Imm, Inst, InstData, MemInfo, Meta, MetaNode, Param,
43    Signature, 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.param()?);
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.param()?);
417                    if !self.eat(",") {
418                        break;
419                    }
420                }
421                self.expect(")")?;
422            } else {
423                signature.returns.push(self.param()?);
424            }
425        }
426        Ok(signature)
427    }
428
429    /// One parameter: a type, and what the ABI asks of it when the text says anything.
430    fn param(&mut self) -> Result<Param, ParseError> {
431        let ty = self.ty()?;
432        let abi = match self.peek_word() {
433            "sext" => {
434                self.word();
435                Abi::Sext
436            }
437            "zext" => {
438                self.word();
439                Abi::Zext
440            }
441            word @ ("byval" | "sret") => {
442                let indirect = word == "byval";
443                self.word();
444                self.expect("(")?;
445                let size = self.u64()?;
446                self.expect(",")?;
447                self.expect("align")?;
448                let align = self.u32()?;
449                self.expect(")")?;
450                if indirect { Abi::ByVal { size, align } } else { Abi::Sret { size, align } }
451            }
452            _ => Abi::Plain,
453        };
454        Ok(Param { ty, abi })
455    }
456
457    fn attrs(&mut self) -> Result<Attrs, ParseError> {
458        self.expect("(")?;
459        let mut attrs = Attrs::NONE;
460        loop {
461            let word = self.word();
462            if self.eat("=") {
463                let value = self.word();
464                match word {
465                    "fp_contract" => match FpContract::from_name(value) {
466                        Some(contract) => attrs.fp_contract = contract,
467                        None => return self.fail(format!("`{value}` is not a contraction")),
468                    },
469                    other => return self.fail(format!("`{other}` takes no value")),
470                }
471            } else {
472                match AttrSet::from_name(word) {
473                    Some(attr) => attrs.set |= attr,
474                    None => return self.fail(format!("`{word}` is not an attribute")),
475                }
476            }
477            if !self.eat(",") {
478                break;
479            }
480        }
481        self.expect(")")?;
482        Ok(attrs)
483    }
484
485    /// The blocks of a function, up to the closing brace.
486    fn body(&mut self) -> Result<Vec<PendingBlock<'a>>, ParseError> {
487        let mut blocks: Vec<PendingBlock<'a>> = Vec::new();
488        loop {
489            self.skip_blank_lines();
490            if self.eat("}") {
491                self.end_of_line()?;
492                return Ok(blocks);
493            }
494            if self.at_end() {
495                return self.fail("the function is not closed");
496            }
497            if self.peek_word().starts_with("block") {
498                let number = self.block_ref()?;
499                if number as usize != blocks.len() {
500                    return self.fail(format!(
501                        "blocks are numbered in order and block{} comes next",
502                        blocks.len()
503                    ));
504                }
505                let mut params = Vec::new();
506                if self.eat("(") {
507                    loop {
508                        let value = self.value_ref()?;
509                        self.expect(":")?;
510                        params.push((value, self.ty()?));
511                        if !self.eat(",") {
512                            break;
513                        }
514                    }
515                    self.expect(")")?;
516                }
517                self.expect(":")?;
518                self.end_of_line()?;
519                blocks.push(PendingBlock { params, insts: Vec::new() });
520                continue;
521            }
522            let inst = self.inst()?;
523            match blocks.last_mut() {
524                Some(block) => block.insts.push(inst),
525                None => return self.fail("an instruction before any block"),
526            }
527        }
528    }
529
530    /// One instruction line.
531    fn inst(&mut self) -> Result<PendingInst<'a>, ParseError> {
532        let line = self.line;
533        let mut results = Vec::new();
534        if self.peek_is("%") {
535            results = self.value_list()?;
536            self.expect("=")?;
537        }
538
539        let word = self.word();
540        let Some(opcode) = Opcode::from_name(word) else {
541            return self.fail(format!("`{word}` is not an opcode"));
542        };
543        let (written, flags) = self.suffixes()?;
544
545        let mut args = Vec::new();
546        let extra = match opcode.extra_kind() {
547            ExtraKind::None => {
548                args = self.value_list()?;
549                PendingExtra::None
550            }
551            ExtraKind::Imm => PendingExtra::Imm(self.imm_text()?),
552            ExtraKind::Symbol => {
553                let symbol = self.symbol()?;
554                if self.eat("(") {
555                    args = self.value_list()?;
556                    self.expect(")")?;
557                }
558                PendingExtra::Symbol(symbol)
559            }
560            ExtraKind::IntPred => {
561                let word = self.word();
562                let Some(pred) = IntPred::from_name(word) else {
563                    return self.fail(format!("`{word}` is not an integer comparison"));
564                };
565                args = self.value_list()?;
566                PendingExtra::IntPred(pred)
567            }
568            ExtraKind::FloatPred => {
569                let word = self.word();
570                let Some(pred) = FloatPred::from_name(word) else {
571                    return self.fail(format!("`{word}` is not a floating point comparison"));
572                };
573                args = self.value_list()?;
574                PendingExtra::FloatPred(pred)
575            }
576            ExtraKind::Mem => {
577                if matches!(opcode, Opcode::Store | Opcode::AtomicStore) {
578                    // A store reads left to right like the assignment it came from.
579                    let value = self.value_ref()?;
580                    self.expect("->")?;
581                    args = vec![value, self.value_ref()?];
582                } else {
583                    args = self.value_list()?;
584                }
585                PendingExtra::Mem(self.mem()?)
586            }
587            ExtraKind::Rmw => {
588                let word = self.word();
589                let Some(op) = RmwOp::from_name(word) else {
590                    return self.fail(format!("`{word}` is not a read-modify-write"));
591                };
592                args = self.value_list()?;
593                PendingExtra::Rmw(op, self.mem()?)
594            }
595            ExtraKind::Order => {
596                let word = self.word();
597                let Some(order) = MemOrder::from_name(word) else {
598                    return self.fail(format!("`{word}` is not an ordering"));
599                };
600                PendingExtra::Order(order)
601            }
602            ExtraKind::Targets => {
603                args = self.value_list()?;
604                if !args.is_empty() {
605                    self.expect(",")?;
606                }
607                let mut targets = Vec::new();
608                loop {
609                    targets.push(self.block_call()?);
610                    if !self.eat(",") {
611                        break;
612                    }
613                }
614                PendingExtra::Targets(targets)
615            }
616            ExtraKind::Call => {
617                let callee = if self.peek_is("@") {
618                    Some(self.symbol()?)
619                } else {
620                    args.push(self.value_ref()?);
621                    None
622                };
623                self.expect("(")?;
624                args.extend(self.value_list()?);
625                self.expect(")")?;
626                self.expect(":")?;
627                PendingExtra::Call { callee, signature: self.signature()? }
628            }
629            ExtraKind::Switch => {
630                args = self.value_list()?;
631                let mut targets = Vec::new();
632                let mut cases = Vec::new();
633                if self.eat(",") {
634                    targets.push(self.block_call()?);
635                    self.expect(",")?;
636                    self.expect("[")?;
637                    if !self.eat("]") {
638                        loop {
639                            cases.push(self.imm_text()?);
640                            self.expect("=>")?;
641                            targets.push(self.block_call()?);
642                            if !self.eat(",") {
643                                break;
644                            }
645                        }
646                        self.expect("]")?;
647                    }
648                }
649                PendingExtra::Switch { targets, cases }
650            }
651            ExtraKind::Asm => {
652                let template = self.symbol_from_string()?;
653                self.expect(",")?;
654                let constraints = self.symbol_from_string()?;
655                self.expect(",")?;
656                let clobbers = self.symbol_from_string()?;
657                self.expect("(")?;
658                args = self.value_list()?;
659                self.expect(")")?;
660                let mut targets = Vec::new();
661                if self.eat(",") {
662                    self.expect("labels")?;
663                    self.expect("[")?;
664                    loop {
665                        targets.push(self.block_call()?);
666                        if !self.eat(",") {
667                            break;
668                        }
669                    }
670                    self.expect("]")?;
671                }
672                PendingExtra::Asm { template, constraints, clobbers, targets }
673            }
674        };
675        self.end_of_line()?;
676        Ok(PendingInst { opcode, flags, results, written, args, extra, line })
677    }
678
679    /// The dotted things after an opcode: the result types, then the flags.
680    fn suffixes(&mut self) -> Result<(Vec<Type>, Flags), ParseError> {
681        let mut written = Vec::new();
682        let mut flags = Flags::NONE;
683        while self.at(".") {
684            self.pos += 1;
685            if self.at("(") {
686                self.pos += 1;
687                loop {
688                    written.push(self.ty()?);
689                    if !self.eat(",") {
690                        break;
691                    }
692                }
693                self.expect(")")?;
694                continue;
695            }
696            let word = self.glued_word();
697            if let Some(flag) = Flags::from_name(word) {
698                flags |= flag;
699            } else if let Some(ty) = Type::parse(word) {
700                written.push(ty);
701            } else {
702                return self.fail(format!("`{word}` is neither a type nor a flag"));
703            }
704        }
705        Ok((written, flags))
706    }
707
708    /// What an access carries beyond its address.
709    fn mem(&mut self) -> Result<MemInfo, ParseError> {
710        let mut info = MemInfo { size: 0, align: 1, order: MemOrder::NotAtomic, tbaa: None };
711        while self.eat(",") {
712            let word = self.word();
713            match word {
714                "size" => info.size = self.u64()?,
715                "align" => info.align = self.u32()?,
716                "tbaa" => info.tbaa = Some(self.meta_ref()?),
717                _ => match MemOrder::from_name(word) {
718                    Some(order) => info.order = order,
719                    None => return self.fail(format!("an access has no `{word}`")),
720                },
721            }
722        }
723        Ok(info)
724    }
725
726    /// A branch target and the values it passes.
727    fn block_call(&mut self) -> Result<PendingCall, ParseError> {
728        let block = self.block_ref()?;
729        let mut args = Vec::new();
730        if self.eat("(") {
731            args = self.value_list()?;
732            self.expect(")")?;
733        }
734        Ok(PendingCall { block, args })
735    }
736
737    // Building the function.
738
739    /// Works out every value's type, then creates the blocks and instructions in print order.
740    fn build(&mut self, func: &mut Func, blocks: &[PendingBlock<'a>]) -> Result<(), ParseError> {
741        let count = self.check_numbering(blocks)?;
742        let types = self.value_types(blocks, count)?;
743
744        let mut next = 0;
745        for pending in blocks {
746            let block = func.create_block();
747            for &(number, ty) in &pending.params {
748                if number != next {
749                    self.line = self.line_of(blocks, number);
750                    return self
751                        .fail(format!("values are numbered in order and %{next} comes next"));
752                }
753                func.append_param(block, ty);
754                next += 1;
755            }
756            for inst in &pending.insts {
757                if inst.results.first().is_some_and(|&first| first != next) {
758                    self.line = inst.line;
759                    return self
760                        .fail(format!("values are numbered in order and %{next} comes next"));
761                }
762                let built = self.build_inst(func, inst, &types)?;
763                func.append_inst(block, built);
764                next += inst.results.len() as u32;
765            }
766        }
767        Ok(())
768    }
769
770    /// Checks that every number the text uses is one the text also defines.
771    ///
772    /// The answer is how many values there are, which is what everything after this is sized by.
773    fn check_numbering(&mut self, blocks: &[PendingBlock<'a>]) -> Result<u32, ParseError> {
774        let mut count = 0;
775        for pending in blocks {
776            count += pending.params.len();
777            for inst in &pending.insts {
778                count += inst.results.len();
779            }
780        }
781        let count = count as u32;
782        let total = blocks.len() as u32;
783        for pending in blocks {
784            for inst in &pending.insts {
785                self.line = inst.line;
786                for &arg in &inst.args {
787                    if arg >= count {
788                        return self.fail(format!("%{arg} is used and never defined"));
789                    }
790                }
791                for call in inst_calls(inst) {
792                    if call.block >= total {
793                        return self.fail(format!("block{} is used and never defined", call.block));
794                    }
795                    for &arg in &call.args {
796                        if arg >= count {
797                            return self.fail(format!("%{arg} is used and never defined"));
798                        }
799                    }
800                }
801            }
802        }
803        Ok(count)
804    }
805
806    /// The type of every value, worked out from the ones the text writes down.
807    ///
808    /// A block parameter has its type at the block and an instruction either has its written
809    /// after the opcode or takes it from an operand, so this is a fixed point over a graph whose
810    /// only cycles run through parameters. It converges in as many rounds as the longest chain
811    /// of instructions each taking its type from the one below it in the text.
812    fn value_types(
813        &mut self,
814        blocks: &[PendingBlock<'a>],
815        count: u32,
816    ) -> Result<Vec<Option<Type>>, ParseError> {
817        let mut types = vec![None; count as usize];
818        for pending in blocks {
819            for &(number, ty) in &pending.params {
820                types[number as usize] = Some(ty);
821            }
822        }
823        loop {
824            let mut progress = false;
825            for pending in blocks {
826                for inst in &pending.insts {
827                    let Some(&first) = inst.results.first() else { continue };
828                    if types[first as usize].is_some() {
829                        continue;
830                    }
831                    let Some(resolved) = result_types(inst, &types) else { continue };
832                    if resolved.len() != inst.results.len() {
833                        self.line = inst.line;
834                        return self.fail(format!(
835                            "{} produces {} values and the text names {}",
836                            inst.opcode.name(),
837                            resolved.len(),
838                            inst.results.len()
839                        ));
840                    }
841                    for (&number, ty) in inst.results.iter().zip(resolved) {
842                        types[number as usize] = Some(ty);
843                    }
844                    progress = true;
845                }
846            }
847            if !progress {
848                break;
849            }
850        }
851        for pending in blocks {
852            for inst in &pending.insts {
853                if inst.results.first().is_some_and(|&first| types[first as usize].is_none()) {
854                    self.line = inst.line;
855                    return self.fail(format!(
856                        "nothing in the text says what {} produces",
857                        inst.opcode.name()
858                    ));
859                }
860            }
861        }
862        Ok(types)
863    }
864
865    fn build_inst(
866        &mut self,
867        func: &mut Func,
868        pending: &PendingInst<'a>,
869        types: &[Option<Type>],
870    ) -> Result<Inst, ParseError> {
871        let results: Vec<Type> = pending
872            .results
873            .iter()
874            .map(|&number| types[number as usize].unwrap_or(Type::VOID))
875            .collect();
876        let args: Vec<Value> =
877            pending.args.iter().map(|&number| Value::from_usize(number as usize)).collect();
878        let arg_list = func.push_values(&args);
879
880        let extra = match &pending.extra {
881            PendingExtra::None => Extra::None,
882            PendingExtra::Imm(text) => {
883                let ty = results.first().copied().unwrap_or(Type::VOID);
884                self.line = pending.line;
885                let imm = self.imm(text, ty)?;
886                Extra::Imm(func.add_imm(imm))
887            }
888            PendingExtra::Symbol(symbol) => Extra::Symbol(*symbol),
889            PendingExtra::IntPred(pred) => Extra::IntPred(*pred),
890            PendingExtra::FloatPred(pred) => Extra::FloatPred(*pred),
891            PendingExtra::Mem(info) => Extra::Mem(func.add_mem(*info)),
892            PendingExtra::Rmw(op, info) => Extra::Rmw(*op, func.add_mem(*info)),
893            PendingExtra::Order(order) => Extra::Order(*order),
894            PendingExtra::Targets(targets) => {
895                let calls = build_calls(func, targets);
896                Extra::Targets(func.push_block_calls(&calls))
897            }
898            PendingExtra::Call { callee, signature } => {
899                let sig = func.add_signature(signature.clone());
900                Extra::Call(func.add_call(CallInfo { callee: *callee, signature: sig }))
901            }
902            PendingExtra::Switch { targets, cases } => {
903                let ty = pending
904                    .args
905                    .first()
906                    .and_then(|&number| types[number as usize])
907                    .unwrap_or(Type::VOID);
908                self.line = pending.line;
909                let mut imms = Vec::with_capacity(cases.len());
910                for case in cases {
911                    imms.push(self.imm(case, ty)?);
912                }
913                let calls = build_calls(func, targets);
914                let targets = func.push_block_calls(&calls);
915                let cases = func.push_imms(&imms);
916                Extra::Switch(func.add_switch(SwitchInfo { targets, cases }))
917            }
918            PendingExtra::Asm { template, constraints, clobbers, targets } => {
919                let calls = build_calls(func, targets);
920                let targets = func.push_block_calls(&calls);
921                Extra::Asm(func.add_asm(AsmInfo {
922                    template: *template,
923                    constraints: *constraints,
924                    clobbers: *clobbers,
925                    targets,
926                }))
927            }
928        };
929
930        let data = InstData {
931            opcode: pending.opcode,
932            flags: pending.flags,
933            args: arg_list,
934            extra,
935            ..InstData::new(pending.opcode)
936        };
937        Ok(func.create_inst(data, &results, Span::DUMMY))
938    }
939
940    /// The line a value number is defined on, for a message about the numbering.
941    fn line_of(&self, blocks: &[PendingBlock<'a>], number: u32) -> u32 {
942        for pending in blocks {
943            for inst in &pending.insts {
944                if inst.results.contains(&number) {
945                    return inst.line;
946                }
947            }
948        }
949        self.line
950    }
951
952    // Tokens.
953
954    /// A constant, read as the type it is a constant of.
955    fn imm(&mut self, text: &str, ty: Type) -> Result<Imm, ParseError> {
956        let scalar = if ty.is_vector() { ty.lane() } else { ty };
957        if scalar.is_int() {
958            match parse_i128(text) {
959                Some(value) => Ok(Imm::int(value, scalar)),
960                None => self.fail(format!("`{text}` is not an {scalar}")),
961            }
962        } else {
963            match text.strip_prefix("0x").and_then(|rest| u128::from_str_radix(rest, 16).ok()) {
964                Some(bits) => Ok(Imm::from_bits(bits)),
965                None => self.fail(format!("`{text}` is not the bits of a {scalar}")),
966            }
967        }
968    }
969
970    /// The text of a constant, which is a sign, digits, and the letters a hexadecimal one has.
971    fn imm_text(&mut self) -> Result<&'a str, ParseError> {
972        self.spaces();
973        let start = self.pos;
974        if self.at("-") {
975            self.pos += 1;
976        }
977        while self.peek().is_some_and(|byte| byte.is_ascii_alphanumeric()) {
978            self.pos += 1;
979        }
980        if self.pos == start {
981            return self.fail("a constant was expected");
982        }
983        Ok(&self.text[start..self.pos])
984    }
985
986    fn ty(&mut self) -> Result<Type, ParseError> {
987        let word = self.word();
988        match Type::parse(word) {
989            Some(ty) => Ok(ty),
990            None => self.fail(format!("`{word}` is not a type")),
991        }
992    }
993
994    /// A `%n`, giving back the number.
995    fn value_ref(&mut self) -> Result<u32, ParseError> {
996        self.expect("%")?;
997        self.u32()
998    }
999
1000    /// A run of `%n` separated by commas, stopping at the first comma not followed by one.
1001    fn value_list(&mut self) -> Result<Vec<u32>, ParseError> {
1002        let mut values = Vec::new();
1003        if !self.peek_is("%") {
1004            return Ok(values);
1005        }
1006        loop {
1007            values.push(self.value_ref()?);
1008            let save = self.pos;
1009            if !self.eat(",") {
1010                return Ok(values);
1011            }
1012            if !self.peek_is("%") {
1013                self.pos = save;
1014                return Ok(values);
1015            }
1016        }
1017    }
1018
1019    /// A `blockN`, giving back the number.
1020    fn block_ref(&mut self) -> Result<u32, ParseError> {
1021        let word = self.word();
1022        match word.strip_prefix("block").and_then(parse_u32) {
1023            Some(number) => Ok(number),
1024            None => self.fail(format!("`{word}` is not a block")),
1025        }
1026    }
1027
1028    /// A `!n`, remembering it so that one nothing defines is reported.
1029    fn meta_ref(&mut self) -> Result<Meta, ParseError> {
1030        self.expect("!")?;
1031        let index = self.u32()?;
1032        let seen = self.meta_used.is_none_or(|(used, _)| index > used);
1033        if seen {
1034            self.meta_used = Some((index, self.line));
1035        }
1036        Ok(Idx::from_usize(index as usize))
1037    }
1038
1039    /// An `@name`, interned.
1040    fn symbol(&mut self) -> Result<Symbol, ParseError> {
1041        self.expect("@")?;
1042        let start = self.pos;
1043        while self.peek().is_some_and(is_name_byte) {
1044            self.pos += 1;
1045        }
1046        if self.pos == start {
1047            return self.fail("a name was expected");
1048        }
1049        let name = &self.text[start..self.pos];
1050        Ok(self.names.intern(name))
1051    }
1052
1053    /// A quoted string, interned, which is what a section and a template are.
1054    fn symbol_from_string(&mut self) -> Result<Symbol, ParseError> {
1055        let text = self.quoted_str()?;
1056        Ok(self.names.intern(&text))
1057    }
1058
1059    /// A quoted string that has to be text rather than arbitrary bytes.
1060    fn quoted_str(&mut self) -> Result<String, ParseError> {
1061        let bytes = self.string()?;
1062        match String::from_utf8(bytes) {
1063            Ok(text) => Ok(text),
1064            Err(_) => self.fail("that string is not text"),
1065        }
1066    }
1067
1068    /// A quoted string, which may hold any bytes at all.
1069    fn string(&mut self) -> Result<Vec<u8>, ParseError> {
1070        self.expect("\"")?;
1071        let mut bytes = Vec::new();
1072        loop {
1073            let Some(byte) = self.peek() else {
1074                return self.fail("that string is not closed");
1075            };
1076            self.pos += 1;
1077            match byte {
1078                b'"' => return Ok(bytes),
1079                b'\n' => return self.fail("that string is not closed"),
1080                b'\\' => {
1081                    let escape = match self.peek() {
1082                        Some(b'"') => b'"',
1083                        Some(b'\\') => b'\\',
1084                        _ => {
1085                            let hex = self.text.get(self.pos..self.pos + 2);
1086                            match hex.and_then(|hex| u8::from_str_radix(hex, 16).ok()) {
1087                                Some(byte) => {
1088                                    self.pos += 2;
1089                                    bytes.push(byte);
1090                                    continue;
1091                                }
1092                                None => return self.fail("that is not an escape"),
1093                            }
1094                        }
1095                    };
1096                    self.pos += 1;
1097                    bytes.push(escape);
1098                }
1099                _ => bytes.push(byte),
1100            }
1101        }
1102    }
1103
1104    fn u32(&mut self) -> Result<u32, ParseError> {
1105        let word = self.word();
1106        match parse_u32(word) {
1107            Some(number) => Ok(number),
1108            None => self.fail(format!("`{word}` is not a number")),
1109        }
1110    }
1111
1112    fn u64(&mut self) -> Result<u64, ParseError> {
1113        let word = self.word();
1114        match parse_u64(word) {
1115            Some(number) => Ok(number),
1116            None => self.fail(format!("`{word}` is not a number")),
1117        }
1118    }
1119
1120    fn i64(&mut self) -> Result<i64, ParseError> {
1121        let word = self.word();
1122        match parse_u64(word).and_then(|number| i64::try_from(number).ok()) {
1123            Some(number) => Ok(number),
1124            None => self.fail(format!("`{word}` is not an offset")),
1125        }
1126    }
1127
1128    /// One of the keyword parenthesised after a name, as in `linkage(internal)`.
1129    fn parenthesised<T>(
1130        &mut self,
1131        from_name: impl Fn(&str) -> Option<T>,
1132        what: &str,
1133    ) -> Result<T, ParseError> {
1134        self.expect("(")?;
1135        let word = self.word();
1136        let Some(value) = from_name(word) else {
1137            return self.fail(format!("`{word}` is not {what}"));
1138        };
1139        self.expect(")")?;
1140        Ok(value)
1141    }
1142
1143    // The cursor.
1144
1145    fn fail<T>(&self, message: impl Into<String>) -> Result<T, ParseError> {
1146        Err(ParseError { line: self.line, message: message.into() })
1147    }
1148
1149    fn peek(&self) -> Option<u8> {
1150        self.text.as_bytes().get(self.pos).copied()
1151    }
1152
1153    fn at(&self, text: &str) -> bool {
1154        self.text[self.pos..].starts_with(text)
1155    }
1156
1157    fn at_end(&self) -> bool {
1158        self.pos >= self.text.len()
1159    }
1160
1161    /// Whether that text comes next, ignoring the spaces in front of it.
1162    fn peek_is(&self, text: &str) -> bool {
1163        self.text[self.pos..].trim_start_matches([' ', '\t']).starts_with(text)
1164    }
1165
1166    fn spaces(&mut self) {
1167        while matches!(self.peek(), Some(b' ' | b'\t')) {
1168            self.pos += 1;
1169        }
1170    }
1171
1172    fn eat(&mut self, text: &str) -> bool {
1173        self.spaces();
1174        if self.at(text) {
1175            self.pos += text.len();
1176            return true;
1177        }
1178        false
1179    }
1180
1181    fn expect(&mut self, text: &str) -> Result<(), ParseError> {
1182        if self.eat(text) {
1183            return Ok(());
1184        }
1185        self.fail(format!("`{text}` was expected"))
1186    }
1187
1188    /// A word of letters, digits and underscores, after the spaces in front of it.
1189    fn word(&mut self) -> &'a str {
1190        self.spaces();
1191        self.glued_word()
1192    }
1193
1194    /// The same, with nothing skipped, which is what a suffix after a dot is.
1195    fn glued_word(&mut self) -> &'a str {
1196        let start = self.pos;
1197        while self.peek().is_some_and(|byte| byte.is_ascii_alphanumeric() || byte == b'_') {
1198            self.pos += 1;
1199        }
1200        &self.text[start..self.pos]
1201    }
1202
1203    /// The next word without consuming it, for deciding what a line is.
1204    fn peek_word(&self) -> &'a str {
1205        let rest = self.text[self.pos..].trim_start_matches([' ', '\t']);
1206        let end =
1207            rest.find(|c: char| !(c.is_ascii_alphanumeric() || c == '_')).unwrap_or(rest.len());
1208        &rest[..end]
1209    }
1210
1211    /// Whether that word comes next, consuming it if so.
1212    fn eat_word(&mut self, word: &str) -> bool {
1213        if self.peek_word() == word {
1214            self.word();
1215            return true;
1216        }
1217        false
1218    }
1219
1220    fn end_of_line(&mut self) -> Result<(), ParseError> {
1221        self.spaces();
1222        if self.at_end() {
1223            return Ok(());
1224        }
1225        if self.at("\n") {
1226            self.pos += 1;
1227            self.line += 1;
1228            return Ok(());
1229        }
1230        let rest = &self.text[self.pos..];
1231        let end = rest.find('\n').unwrap_or(rest.len());
1232        self.fail(format!("`{}` is left over at the end of the line", &rest[..end]))
1233    }
1234
1235    fn skip_blank_lines(&mut self) {
1236        loop {
1237            let save = self.pos;
1238            self.spaces();
1239            if self.at("\n") {
1240                self.pos += 1;
1241                self.line += 1;
1242            } else {
1243                self.pos = save;
1244                return;
1245            }
1246        }
1247    }
1248}
1249
1250/// Every branch target an instruction has, whichever payload holds them.
1251fn inst_calls<'p>(inst: &'p PendingInst<'_>) -> &'p [PendingCall] {
1252    match &inst.extra {
1253        PendingExtra::Targets(targets)
1254        | PendingExtra::Switch { targets, .. }
1255        | PendingExtra::Asm { targets, .. } => targets,
1256        _ => &[],
1257    }
1258}
1259
1260/// The branch targets of an instruction, with their arguments put in the function's pool.
1261fn build_calls(func: &mut Func, targets: &[PendingCall]) -> Vec<BlockCall> {
1262    targets
1263        .iter()
1264        .map(|call| {
1265            let args: Vec<Value> =
1266                call.args.iter().map(|&number| Value::from_usize(number as usize)).collect();
1267            BlockCall {
1268                block: Block::from_usize(call.block as usize),
1269                args: func.push_values(&args),
1270            }
1271        })
1272        .collect()
1273}
1274
1275/// What an instruction produces, or `None` while an operand's type is still unknown.
1276///
1277/// This is the reading half of the rule the printer writes by, which is why the two of them
1278/// name the same opcodes: a type is in the text only where the operands do not say it.
1279fn result_types(inst: &PendingInst<'_>, types: &[Option<Type>]) -> Option<Vec<Type>> {
1280    if inst.results.is_empty() {
1281        return Some(Vec::new());
1282    }
1283    if !inst.written.is_empty() {
1284        return Some(inst.written.clone());
1285    }
1286    match inst.opcode {
1287        Opcode::GlobalAddr | Opcode::BlockAddr | Opcode::Alloca => Some(vec![Type::PTR]),
1288        Opcode::ICmp | Opcode::FCmp => {
1289            let ty = arg_type(inst, types)?;
1290            Some(vec![ty.with_lane(Type::I1)])
1291        }
1292        Opcode::Call | Opcode::CallIndirect | Opcode::TailCall => match &inst.extra {
1293            PendingExtra::Call { signature, .. } => Some(signature.return_types().collect()),
1294            _ => None,
1295        },
1296        _ => Some(vec![arg_type(inst, types)?]),
1297    }
1298}
1299
1300/// The type of an instruction's first operand, if it is known yet.
1301fn arg_type(inst: &PendingInst<'_>, types: &[Option<Type>]) -> Option<Type> {
1302    let &first = inst.args.first()?;
1303    *types.get(first as usize)?
1304}
1305
1306/// A decimal number with no sign and no leading zero, which is the only form the printer writes.
1307fn parse_u64(text: &str) -> Option<u64> {
1308    if text.is_empty() || (text.starts_with('0') && text.len() > 1) {
1309        return None;
1310    }
1311    if !text.bytes().all(|byte| byte.is_ascii_digit()) {
1312        return None;
1313    }
1314    text.parse().ok()
1315}
1316
1317fn parse_u32(text: &str) -> Option<u32> {
1318    parse_u64(text).and_then(|number| u32::try_from(number).ok())
1319}
1320
1321/// A decimal integer, with a minus sign for a negative one, as the printer writes them.
1322fn parse_i128(text: &str) -> Option<i128> {
1323    let (negative, digits) = match text.strip_prefix('-') {
1324        Some(rest) => (true, rest),
1325        None => (false, text),
1326    };
1327    if digits.is_empty() || (digits.starts_with('0') && digits.len() > 1) {
1328        return None;
1329    }
1330    if negative && digits == "0" {
1331        return None;
1332    }
1333    if !digits.bytes().all(|byte| byte.is_ascii_digit()) {
1334        return None;
1335    }
1336    let magnitude: u128 = digits.parse().ok()?;
1337    if negative {
1338        // The most negative number has no positive counterpart, so it is built by negating the
1339        // wrapped value rather than by converting first.
1340        (magnitude <= 1 << 127).then(|| (magnitude as i128).wrapping_neg())
1341    } else {
1342        i128::try_from(magnitude).ok()
1343    }
1344}
1345
1346/// Whether a byte can appear in a symbol name.
1347///
1348/// Dots are in, because a compiler names things `hi.str` and `memcpy.resolve` and the assembler
1349/// takes them.
1350fn is_name_byte(byte: u8) -> bool {
1351    byte.is_ascii_alphanumeric() || matches!(byte, b'_' | b'.' | b'$')
1352}
1353
1354#[cfg(test)]
1355mod tests {
1356    use rucc_base::Interner;
1357
1358    use super::*;
1359    use crate::fixtures::{EXAMPLE, SYMBOLS, ZOO};
1360    use crate::print;
1361
1362    /// Reads a module and writes it back out, which is the whole claim this file makes.
1363    fn round_trip(text: &str) -> String {
1364        let mut names = Interner::new();
1365        let module = match parse(text, &mut names) {
1366            Ok(module) => module,
1367            Err(error) => panic!("{error}"),
1368        };
1369        print(&module, &names)
1370    }
1371
1372    fn error(text: &str) -> String {
1373        let mut names = Interner::new();
1374        match parse(text, &mut names) {
1375            Ok(_) => panic!("that was expected to be turned down"),
1376            Err(error) => error.to_string(),
1377        }
1378    }
1379
1380    const HEADER: &str = "\
1381; ModuleID = 'example.c'
1382; format 0
1383target triple = \"x86_64-unknown-linux-gnu\"
1384target datalayout = \"e-p:64:64-i64:64-f80:128-S128\"
1385";
1386
1387    #[test]
1388    fn the_example_in_the_spec_comes_back_byte_for_byte() {
1389        assert_eq!(round_trip(EXAMPLE), EXAMPLE);
1390    }
1391
1392    #[test]
1393    fn one_of_almost_everything_comes_back_byte_for_byte() {
1394        assert_eq!(round_trip(ZOO), ZOO);
1395    }
1396
1397    #[test]
1398    fn the_shapes_a_symbol_comes_in_come_back_byte_for_byte() {
1399        assert_eq!(round_trip(SYMBOLS), SYMBOLS);
1400    }
1401
1402    #[test]
1403    fn a_value_defined_after_it_is_used() {
1404        // Block layout order is not required to put a definition before its uses, so the type
1405        // of %2 is only known after the whole function has been read. This is the case the two
1406        // passes exist for.
1407        let text = format!(
1408            "{HEADER}
1409func @late() -> i64, linkage(external) {{
1410block0:
1411    jump block2
1412
1413block1(%0: i64):
1414    %1 = add %2, %0
1415    return %1
1416
1417block2:
1418    %2 = iconst.i64 7
1419    jump block1(%2)
1420}}
1421"
1422        );
1423        assert_eq!(round_trip(&text), text);
1424    }
1425
1426    #[test]
1427    fn what_the_abi_asks_of_a_parameter_comes_back_byte_for_byte() {
1428        // A `struct` return, a `struct` argument, and a `char` the callee may read a whole
1429        // register of. None of it is written on a type, because none of it is a fact about one.
1430        let text = format!(
1431            "{HEADER}
1432func @f(ptr sret(24, align 8), ptr byval(16, align 8), i8 zext), linkage(external) {{
1433block0(%0: ptr, %1: ptr, %2: i8):
1434    return
1435}}
1436
1437func @g(i8 sext) -> i8 sext, linkage(external);
1438"
1439        );
1440        assert_eq!(round_trip(&text), text);
1441    }
1442
1443    #[test]
1444    fn a_word_that_is_not_an_attribute_is_not_read_as_one() {
1445        let text = format!(
1446            "{HEADER}
1447func @f(ptr inreg), linkage(external);
1448"
1449        );
1450        assert_eq!(error(&text), "line 6: `)` was expected");
1451    }
1452
1453    #[test]
1454    fn an_empty_module_is_its_header() {
1455        assert_eq!(round_trip(HEADER), HEADER);
1456    }
1457
1458    #[test]
1459    fn the_format_version_is_checked_before_anything_else() {
1460        let text = "; ModuleID = 'a.c'\n; format 99\n";
1461        assert_eq!(error(text), "line 2: this build reads format 0 and the text says format 99");
1462    }
1463
1464    #[test]
1465    fn an_opcode_nobody_has_is_reported_with_its_line() {
1466        let text = format!(
1467            "{HEADER}
1468func @f(), linkage(external) {{
1469block0:
1470    getelementptr %0
1471}}
1472"
1473        );
1474        assert_eq!(error(&text), "line 8: `getelementptr` is not an opcode");
1475    }
1476
1477    #[test]
1478    fn a_value_nothing_defines_is_reported() {
1479        let text = format!(
1480            "{HEADER}
1481func @f(i32) -> i32, linkage(external) {{
1482block0(%0: i32):
1483    %1 = add %0, %9
1484    return %1
1485}}
1486"
1487        );
1488        assert_eq!(error(&text), "line 8: %9 is used and never defined");
1489    }
1490
1491    #[test]
1492    fn a_block_nothing_defines_is_reported() {
1493        let text = format!(
1494            "{HEADER}
1495func @f(), linkage(external) {{
1496block0:
1497    jump block7
1498}}
1499"
1500        );
1501        assert_eq!(error(&text), "line 8: block7 is used and never defined");
1502    }
1503
1504    #[test]
1505    fn values_have_to_be_numbered_in_print_order() {
1506        let text = format!(
1507            "{HEADER}
1508func @f() -> i32, linkage(external) {{
1509block0:
1510    %1 = iconst.i32 0
1511    %0 = iconst.i32 1
1512    return %1
1513}}
1514"
1515        );
1516        assert_eq!(error(&text), "line 8: values are numbered in order and %0 comes next");
1517    }
1518
1519    #[test]
1520    fn blocks_have_to_be_numbered_in_print_order() {
1521        let text = format!(
1522            "{HEADER}
1523func @f(), linkage(external) {{
1524block1:
1525    return
1526}}
1527"
1528        );
1529        assert_eq!(error(&text), "line 7: blocks are numbered in order and block0 comes next");
1530    }
1531
1532    #[test]
1533    fn metadata_nobody_defines_is_reported() {
1534        let text = format!(
1535            "{HEADER}
1536func @f(ptr), linkage(external) {{
1537block0(%0: ptr):
1538    %1 = load.i32 %0, align 4, tbaa !3
1539    return
1540}}
1541"
1542        );
1543        assert_eq!(error(&text), "line 8: !3 is used and never defined");
1544    }
1545
1546    #[test]
1547    fn a_type_nothing_says_is_reported_rather_than_guessed() {
1548        let text = format!(
1549            "{HEADER}
1550func @f(), linkage(external) {{
1551block0:
1552    %0 = add
1553    return
1554}}
1555"
1556        );
1557        assert_eq!(error(&text), "line 8: nothing in the text says what add produces");
1558    }
1559
1560    #[test]
1561    fn a_line_with_something_left_on_it_is_turned_down() {
1562        let text = format!(
1563            "{HEADER}
1564global @x : i32 = 0, align 4, linkage(internal) and then some
1565"
1566        );
1567        assert_eq!(error(&text), "line 6: `and then some` is left over at the end of the line");
1568    }
1569
1570    #[test]
1571    fn a_constant_that_is_not_one_is_turned_down() {
1572        let text = format!(
1573            "{HEADER}
1574global @x : i32 = 007, align 4, linkage(internal)
1575"
1576        );
1577        assert_eq!(error(&text), "line 6: `007` is not an i32");
1578    }
1579
1580    #[test]
1581    fn a_number_is_read_the_way_the_printer_writes_it() {
1582        assert_eq!(parse_i128("-1"), Some(-1));
1583        assert_eq!(parse_i128("0"), Some(0));
1584        assert_eq!(parse_i128("-0"), None);
1585        assert_eq!(parse_i128("+1"), None);
1586        assert_eq!(parse_i128("01"), None);
1587        assert_eq!(parse_i128(""), None);
1588        assert_eq!(parse_i128("170141183460469231731687303715884105728"), None);
1589        assert_eq!(parse_i128("-170141183460469231731687303715884105728"), Some(i128::MIN));
1590    }
1591
1592    #[test]
1593    fn every_opcode_says_which_payload_it_carries() {
1594        // A payload the parser does not expect for that opcode is text it cannot read back, so
1595        // the two of them agreeing is what this file rests on.
1596        for opcode in Opcode::all() {
1597            let kind = opcode.extra_kind();
1598            let expected = match opcode {
1599                Opcode::IConst | Opcode::FConst | Opcode::Splat => ExtraKind::Imm,
1600                Opcode::GlobalAddr | Opcode::TargetIntrinsic => ExtraKind::Symbol,
1601                Opcode::ICmp => ExtraKind::IntPred,
1602                Opcode::FCmp => ExtraKind::FloatPred,
1603                Opcode::Fence => ExtraKind::Order,
1604                Opcode::AtomicRmw => ExtraKind::Rmw,
1605                Opcode::Switch => ExtraKind::Switch,
1606                Opcode::InlineAsm => ExtraKind::Asm,
1607                Opcode::Jump | Opcode::BrIf | Opcode::BlockAddr | Opcode::IndirectBr => {
1608                    ExtraKind::Targets
1609                }
1610                Opcode::Call | Opcode::CallIndirect | Opcode::TailCall => ExtraKind::Call,
1611                Opcode::Alloca
1612                | Opcode::Load
1613                | Opcode::Store
1614                | Opcode::Memcpy
1615                | Opcode::Memmove
1616                | Opcode::Memset
1617                | Opcode::AtomicLoad
1618                | Opcode::AtomicStore
1619                | Opcode::Cmpxchg => ExtraKind::Mem,
1620                _ => ExtraKind::None,
1621            };
1622            assert_eq!(kind, expected, "{}", opcode.name());
1623        }
1624    }
1625}