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