Skip to main content

rucc_ir/
print.rs

1//! The printer: a module as text.
2//!
3//! Design: `spec/08-ir.md` section 8.8.
4//!
5//! The printer and the parser round-trip byte for byte, which is what makes the IR testable on
6//! its own, what makes `-fdump-ir=after-<pass>` worth reading, and what lets a fuzzer make IR
7//! directly rather than through the front end. The printer is written first because the parser
8//! has to read what it writes.
9//!
10//! # What decides the text
11//!
12//! Nothing printed here is a fact about the tables the module happens to be in. Values are
13//! numbered in the order they are printed rather than by their index, blocks likewise, and a
14//! signature is written out at the call rather than as a number into a side table. So printing
15//! a module, parsing it back and printing it again gives the same bytes even when the second
16//! module's tables are laid out differently from the first's, which is the property that makes
17//! the round trip worth testing at all.
18//!
19//! A type is written on an instruction only where it cannot be worked out from the operands:
20//! on one that takes none, and on one whose result is a different type from its first operand.
21//! Everything else would be a second copy of something already on the line above, and a second
22//! copy is a thing that can disagree.
23//!
24//! Spans are not printed. Debug information has its own form and it is written in a later
25//! milestone; the round trip is a claim about the text, not about the source locations behind
26//! it.
27
28use std::fmt::Write as _;
29
30use rucc_base::{Interner, Symbol};
31
32use crate::func::Func;
33use crate::inst::{
34    Abi, Block, BlockCall, Imm, Inst, InstData, MemInfo, Meta, Param, Signature, Value,
35};
36use crate::module::{Alias, Datum, Global, Module, Reloc};
37use crate::{Extra, FORMAT_VERSION, Linkage, MemOrder, Opcode, Type, Visibility};
38
39/// Whether the opcode says what it produces without a type having to be written down.
40///
41/// A comparison produces `i1`, one per lane of what it compared. The two that produce an
42/// address produce an address. A call produces what its signature says, and the signature is
43/// written out on the same line. Everything else either takes an operand of the type it
44/// produces, in which case that operand says it, or has the type written after the opcode.
45///
46/// The printer and the parser share this, because a rule the two of them state separately is a
47/// rule they will eventually state differently.
48pub(crate) fn implied_result(opcode: Opcode) -> bool {
49    matches!(
50        opcode,
51        Opcode::ICmp
52            | Opcode::FCmp
53            | Opcode::GlobalAddr
54            | Opcode::BlockAddr
55            | Opcode::Alloca
56            | Opcode::Call
57            | Opcode::CallIndirect
58            | Opcode::TailCall
59    )
60}
61
62/// The whole module, as text.
63#[must_use]
64pub fn print(module: &Module, names: &Interner) -> String {
65    let mut printer = Printer::new(module, names);
66    printer.module();
67    printer.finish()
68}
69
70/// One function of a module, as text, for a dump of a single function.
71#[must_use]
72pub fn print_func(module: &Module, func: &Func, names: &Interner) -> String {
73    let mut printer = Printer::new(module, names);
74    printer.func(func);
75    printer.finish()
76}
77
78/// A module being written out.
79#[derive(Debug)]
80pub struct Printer<'a> {
81    module: &'a Module,
82    names: &'a Interner,
83    out: String,
84    // The number each value and each block is printed as, in print order, indexed by the index
85    // it has in the function being printed. `u32::MAX` for one that has not been reached,
86    // which only happens in a function the verifier would turn down.
87    values: Vec<u32>,
88    blocks: Vec<u32>,
89}
90
91impl<'a> Printer<'a> {
92    /// A printer over one module, whose names are in `names`.
93    #[must_use]
94    pub fn new(module: &'a Module, names: &'a Interner) -> Printer<'a> {
95        Printer { module, names, out: String::new(), values: Vec::new(), blocks: Vec::new() }
96    }
97
98    /// The text written so far.
99    #[must_use]
100    pub fn finish(self) -> String {
101        self.out
102    }
103
104    /// The header, then the globals, the aliases, the functions and the metadata.
105    pub fn module(&mut self) {
106        let module = self.module;
107        let name = self.names.resolve(module.name);
108        // Writing to a `String` cannot fail, which is why the result is dropped here and at
109        // every other `write!` in this file rather than turned into a panic to reason about.
110        let _ = writeln!(self.out, "; ModuleID = '{name}'");
111        let _ = writeln!(self.out, "; format {FORMAT_VERSION}");
112        let _ = writeln!(self.out, "target triple = \"{}\"", module.triple);
113        let _ = writeln!(self.out, "target datalayout = \"{}\"", module.datalayout);
114
115        if module.globals().next().is_some() {
116            self.out.push('\n');
117            for id in module.globals() {
118                self.global(&module[id]);
119            }
120        }
121        if module.aliases().next().is_some() {
122            self.out.push('\n');
123            for id in module.aliases() {
124                self.alias(&module[id]);
125            }
126        }
127        for id in module.funcs() {
128            self.out.push('\n');
129            self.func(&module[id]);
130        }
131        if module.metadata().next().is_some() {
132            self.out.push('\n');
133            for meta in module.metadata() {
134                self.meta_node(meta);
135            }
136        }
137    }
138
139    // Globals and aliases.
140
141    /// One global variable, on one line.
142    fn global(&mut self, global: &Global) {
143        let _ = write!(self.out, "global @{} : ", self.names.resolve(global.name));
144        match self.scalar_init(global) {
145            // The shorthand for the common case, which is a global holding one number. It is
146            // used only when the type accounts for the whole size, so that reading it back
147            // gives the size again without its having been written down.
148            Some((ty, imm)) => {
149                let _ = write!(self.out, "{ty} = ");
150                self.imm(imm, ty);
151            }
152            None => {
153                let _ = write!(self.out, "bytes {}", global.size);
154                if let Some(init) = global.init {
155                    // An image with nothing in it is written `{}`, with no space inside, because
156                    // the spaces in the other spelling are there to hold the pieces apart and an
157                    // empty image has none to hold. A zero sized object is where this comes from:
158                    // `char x[0] = { };` at file scope has an image and the image has no pieces,
159                    // and the reader used to stop on the empty one because it asked for a piece
160                    // before it looked for the brace.
161                    let data = &self.module[init];
162                    if data.is_empty() {
163                        self.out.push_str(" = {}");
164                    } else {
165                        self.out.push_str(" = { ");
166                        for (index, &datum) in data.iter().enumerate() {
167                            if index > 0 {
168                                self.out.push_str(", ");
169                            }
170                            self.datum(datum);
171                        }
172                        self.out.push_str(" }");
173                    }
174                }
175            }
176        }
177        let _ = write!(self.out, ", align {}", global.align);
178        self.linkage(global.linkage, global.visibility);
179        if let Some(model) = global.tls {
180            let _ = write!(self.out, ", tls({})", model.name());
181        }
182        if global.constant {
183            self.out.push_str(", constant");
184        }
185        self.section(global.section);
186        self.out.push('\n');
187    }
188
189    /// The type and the value of a global that holds exactly one scalar filling it.
190    fn scalar_init(&self, global: &Global) -> Option<(Type, Imm)> {
191        let init = global.init?;
192        let [datum] = self.module[init] else { return None };
193        let Datum::Scalar { ty, value } = datum else { return None };
194        (datum.size(self.module) == global.size).then(|| (ty, self.module[value]))
195    }
196
197    /// One piece of a global's image.
198    fn datum(&mut self, datum: Datum) {
199        match datum {
200            Datum::Zero(bytes) => {
201                let _ = write!(self.out, "zero {bytes}");
202            }
203            Datum::Bytes(range) => {
204                self.out.push_str("bytes ");
205                let bytes = &self.module[range];
206                self.string(bytes);
207            }
208            Datum::Scalar { ty, value } => {
209                let _ = write!(self.out, "{ty} ");
210                self.imm(self.module[value], ty);
211            }
212            Datum::Addr(reloc) => {
213                let Reloc { symbol, addend, size } = self.module[reloc];
214                let _ = write!(self.out, "addr.{size} @{}", self.names.resolve(symbol));
215                match addend.signum() {
216                    1 => {
217                        let _ = write!(self.out, " + {addend}");
218                    }
219                    -1 => {
220                        // Written as a subtraction rather than as a negative addend, because
221                        // `+ -8` is a thing nobody reads twice the same way. `i64::MIN` has no
222                        // positive counterpart, so it keeps the sign it came with.
223                        let _ = match addend.checked_neg() {
224                            Some(amount) => write!(self.out, " - {amount}"),
225                            None => write!(self.out, " + {addend}"),
226                        };
227                    }
228                    _ => {}
229                }
230            }
231        }
232    }
233
234    /// One alias, on one line.
235    fn alias(&mut self, alias: &Alias) {
236        let _ = write!(
237            self.out,
238            "{} @{} = @{}",
239            alias.kind.name(),
240            self.names.resolve(alias.name),
241            self.names.resolve(alias.target)
242        );
243        self.linkage(alias.linkage, alias.visibility);
244        self.out.push('\n');
245    }
246
247    // Functions.
248
249    /// One function: its signature, then its blocks, or a semicolon if it has none.
250    pub fn func(&mut self, func: &Func) {
251        self.number(func);
252        let _ = write!(self.out, "func @{}", self.names.resolve(func.name));
253        self.signature(func.signature());
254        self.linkage(func.linkage, func.visibility);
255        if !func.attrs.is_default() {
256            let _ = write!(self.out, ", {}", func.attrs);
257        }
258        self.section(func.section);
259        if func.is_declaration() {
260            self.out.push_str(";\n");
261            return;
262        }
263        self.out.push_str(" {\n");
264        for (index, block) in func.blocks().enumerate() {
265            if index > 0 {
266                self.out.push('\n');
267            }
268            self.block(func, block);
269        }
270        self.out.push_str("}\n");
271    }
272
273    /// Gives every value and every block of a function the number it is printed as.
274    ///
275    /// In print order, which is what makes the text a fact about the function's shape rather
276    /// than about which order its tables were filled in.
277    fn number(&mut self, func: &Func) {
278        let counts = func.counts();
279        self.values.clear();
280        self.values.resize(counts.values, u32::MAX);
281        self.blocks.clear();
282        self.blocks.resize(counts.blocks, u32::MAX);
283        let mut next = 0;
284        for (index, block) in func.blocks().enumerate() {
285            self.blocks[block.index()] = index as u32;
286            for &param in &func[block].params {
287                self.values[param.index()] = next;
288                next += 1;
289            }
290            for inst in func.insts(block) {
291                for result in func[inst].results() {
292                    self.values[result.index()] = next;
293                    next += 1;
294                }
295            }
296        }
297    }
298
299    /// The parameter and result types of a function or a call, with what the ABI asks of each.
300    fn signature(&mut self, signature: &Signature) {
301        self.out.push('(');
302        for (index, param) in signature.params.iter().enumerate() {
303            if index > 0 {
304                self.out.push_str(", ");
305            }
306            self.param(param);
307        }
308        if signature.variadic {
309            if !signature.params.is_empty() {
310                self.out.push_str(", ");
311            }
312            self.out.push_str("...");
313        }
314        self.out.push(')');
315        match signature.returns.as_slice() {
316            [] => {}
317            [param] => {
318                self.out.push_str(" -> ");
319                self.param(param);
320            }
321            params => {
322                self.out.push_str(" -> (");
323                for (index, param) in params.iter().enumerate() {
324                    if index > 0 {
325                        self.out.push_str(", ");
326                    }
327                    self.param(param);
328                }
329                self.out.push(')');
330            }
331        }
332    }
333
334    /// One parameter: its type, and what the ABI asks of it when that is anything.
335    fn param(&mut self, param: &Param) {
336        let _ = write!(self.out, "{}", param.ty);
337        self.abi(param.abi);
338    }
339
340    /// What the ABI asks of a value, after whatever it is written on, and nothing at all when
341    /// the answer is that it travels as itself.
342    fn abi(&mut self, abi: Abi) {
343        let _ = match abi {
344            Abi::Plain => Ok(()),
345            Abi::Sext => write!(self.out, " sext"),
346            Abi::Zext => write!(self.out, " zext"),
347            Abi::ByVal { size, align } => write!(self.out, " byval({size}, align {align})"),
348            Abi::Sret { size, align } => write!(self.out, " sret({size}, align {align})"),
349        };
350    }
351
352    /// One block: its label with its parameters, then its instructions.
353    fn block(&mut self, func: &Func, block: Block) {
354        let _ = write!(self.out, "block{}", self.blocks[block.index()]);
355        let params = &func[block].params;
356        if !params.is_empty() {
357            self.out.push('(');
358            for (index, &param) in params.iter().enumerate() {
359                if index > 0 {
360                    self.out.push_str(", ");
361                }
362                self.value(param);
363                let _ = write!(self.out, ": {}", func[param].ty);
364            }
365            self.out.push(')');
366        }
367        self.out.push_str(":\n");
368        for inst in func.insts(block) {
369            self.inst(func, inst);
370        }
371    }
372
373    /// One instruction, indented, on one line.
374    fn inst(&mut self, func: &Func, inst: Inst) {
375        let data = func[inst];
376        self.out.push_str("    ");
377        for (index, result) in data.results().enumerate() {
378            if index > 0 {
379                self.out.push_str(", ");
380            }
381            self.value(result);
382        }
383        if data.results > 0 {
384            self.out.push_str(" = ");
385        }
386        self.out.push_str(data.opcode.name());
387        self.result_types(func, &data);
388        let _ = write!(self.out, "{}", data.flags);
389        self.operands(func, &data);
390        self.out.push('\n');
391    }
392
393    /// The type suffix, where the operands do not already say what the result is.
394    fn result_types(&mut self, func: &Func, data: &InstData) {
395        let results: Vec<Value> = data.results().collect();
396        match results.as_slice() {
397            [] => {}
398            _ if implied_result(data.opcode) => {}
399            [result] => {
400                let ty = func[*result].ty;
401                let takes_the_same = func[data.args].first().is_some_and(|&arg| func[arg].ty == ty);
402                if !takes_the_same {
403                    let _ = write!(self.out, ".{ty}");
404                }
405            }
406            // The handful that produce two. Both are written, because neither of them follows
407            // from the operands in a way worth remembering a rule for.
408            types => {
409                self.out.push_str(".(");
410                for (index, &result) in types.iter().enumerate() {
411                    if index > 0 {
412                        self.out.push_str(", ");
413                    }
414                    let _ = write!(self.out, "{}", func[result].ty);
415                }
416                self.out.push(')');
417            }
418        }
419    }
420
421    /// Everything to the right of the opcode.
422    fn operands(&mut self, func: &Func, data: &InstData) {
423        let args = &func[data.args];
424        match data.extra {
425            Extra::None => self.value_list_spaced(args),
426            Extra::Imm(imm) => {
427                self.out.push(' ');
428                let ty = data.first_result.map_or(Type::VOID, |result| func[result].ty);
429                self.imm(func[imm], ty);
430            }
431            Extra::Symbol(symbol) => {
432                let _ = write!(self.out, " @{}", self.names.resolve(symbol));
433                if !args.is_empty() {
434                    self.out.push('(');
435                    self.value_list(args);
436                    self.out.push(')');
437                }
438            }
439            Extra::IntPred(pred) => {
440                let _ = write!(self.out, " {}", pred.name());
441                self.value_list_spaced(args);
442            }
443            Extra::FloatPred(pred) => {
444                let _ = write!(self.out, " {}", pred.name());
445                self.value_list_spaced(args);
446            }
447            Extra::Mem(mem) => {
448                match (data.opcode, args) {
449                    // A store reads left to right like the assignment it came from, which is
450                    // worth one special case in the printer and one in the parser.
451                    (Opcode::Store | Opcode::AtomicStore, [value, addr]) => {
452                        self.out.push(' ');
453                        self.value(*value);
454                        self.out.push_str(" -> ");
455                        self.value(*addr);
456                    }
457                    _ => self.value_list_spaced(args),
458                }
459                self.mem(func[mem]);
460            }
461            Extra::Rmw(op, mem) => {
462                let _ = write!(self.out, " {}", op.name());
463                self.value_list_spaced(args);
464                self.mem(func[mem]);
465            }
466            Extra::Order(order) => {
467                let _ = write!(self.out, " {}", order.name());
468            }
469            Extra::Targets(targets) => {
470                // A conditional branch names its condition first and then both arms. A jump
471                // has no operands at all and is its target.
472                if !args.is_empty() {
473                    self.value_list_spaced(args);
474                    self.out.push(',');
475                }
476                for (index, &call) in func[targets].iter().enumerate() {
477                    self.out.push_str(if index > 0 { ", " } else { " " });
478                    self.block_call(func, call);
479                }
480            }
481            Extra::Call(call) => {
482                let info = func[call];
483                let rest = match info.callee {
484                    Some(callee) => {
485                        let _ = write!(self.out, " @{}", self.names.resolve(callee));
486                        args
487                    }
488                    // An indirect call takes the address it calls as its first operand, and
489                    // the rest are the arguments.
490                    None => {
491                        self.out.push(' ');
492                        match args.split_first() {
493                            Some((&addr, rest)) => {
494                                self.value(addr);
495                                rest
496                            }
497                            None => {
498                                self.out.push_str("%?");
499                                &[]
500                            }
501                        }
502                    }
503                };
504                self.out.push('(');
505                // An argument the signature names says how it travels there, and one past the
506                // end of the list has nowhere else to say it than here.
507                let named = func[info.signature].params.len();
508                let varargs = &func[info.varargs];
509                for (index, &arg) in rest.iter().enumerate() {
510                    if index > 0 {
511                        self.out.push_str(", ");
512                    }
513                    self.value(arg);
514                    if let Some(&abi) = index.checked_sub(named).and_then(|at| varargs.get(at)) {
515                        self.abi(abi);
516                    }
517                }
518                self.out.push_str(") : ");
519                self.signature(&func[info.signature]);
520            }
521            Extra::Switch(switch) => {
522                let info = func[switch];
523                let ty = args.first().map_or(Type::VOID, |&arg| func[arg].ty);
524                self.value_list_spaced(args);
525                if let Some((&default, cases)) = func[info.targets].split_first() {
526                    self.out.push_str(", ");
527                    self.block_call(func, default);
528                    self.out.push_str(", [");
529                    for (index, (&case, &value)) in cases.iter().zip(&func[info.cases]).enumerate()
530                    {
531                        if index > 0 {
532                            self.out.push_str(", ");
533                        }
534                        self.imm(value, ty);
535                        self.out.push_str(" => ");
536                        self.block_call(func, case);
537                    }
538                    self.out.push(']');
539                }
540            }
541            Extra::Asm(asm) => {
542                let info = func[asm];
543                self.out.push(' ');
544                self.string(self.names.resolve(info.template).as_bytes());
545                self.out.push_str(", ");
546                self.string(self.names.resolve(info.constraints).as_bytes());
547                self.out.push_str(", ");
548                self.string(self.names.resolve(info.clobbers).as_bytes());
549                self.out.push('(');
550                self.value_list(args);
551                self.out.push(')');
552                if !info.targets.is_empty() {
553                    self.out.push_str(", labels [");
554                    for (index, &call) in func[info.targets].iter().enumerate() {
555                        if index > 0 {
556                            self.out.push_str(", ");
557                        }
558                        self.block_call(func, call);
559                    }
560                    self.out.push(']');
561                }
562            }
563        }
564    }
565
566    /// The operands, separated by commas, with a leading space when there are any.
567    fn value_list_spaced(&mut self, args: &[Value]) {
568        if args.is_empty() {
569            return;
570        }
571        self.out.push(' ');
572        self.value_list(args);
573    }
574
575    /// The operands, separated by commas, with nothing in front.
576    fn value_list(&mut self, args: &[Value]) {
577        for (index, &arg) in args.iter().enumerate() {
578            if index > 0 {
579                self.out.push_str(", ");
580            }
581            self.value(arg);
582        }
583    }
584
585    /// A branch target, with the values it passes.
586    fn block_call(&mut self, func: &Func, call: BlockCall) {
587        let _ = write!(self.out, "block{}", self.blocks[call.block.index()]);
588        let args = &func[call.args];
589        if !args.is_empty() {
590            self.out.push('(');
591            self.value_list(args);
592            self.out.push(')');
593        }
594    }
595
596    /// What an access carries beyond its address.
597    fn mem(&mut self, info: MemInfo) {
598        if info.size != 0 {
599            let _ = write!(self.out, ", size {}", info.size);
600        }
601        let _ = write!(self.out, ", align {}", info.align);
602        if info.order != MemOrder::NotAtomic {
603            let _ = write!(self.out, ", {}", info.order.name());
604        }
605        if let Some(tbaa) = info.tbaa {
606            let _ = write!(self.out, ", tbaa !{}", tbaa.index());
607        }
608    }
609
610    /// One value, as the number it was given in print order.
611    fn value(&mut self, value: Value) {
612        match self.values.get(value.index()).copied() {
613            Some(number) if number != u32::MAX => {
614                let _ = write!(self.out, "%{number}");
615            }
616            // A use with no definition anywhere ahead of it. The verifier turns this down, and
617            // printing something rather than panicking is what makes the printer usable for
618            // finding out why.
619            _ => self.out.push_str("%?"),
620        }
621    }
622
623    /// One constant, read as the type it is a constant of.
624    fn imm(&mut self, imm: Imm, ty: Type) {
625        let scalar = if ty.is_vector() { ty.lane() } else { ty };
626        if scalar.is_float() {
627            // The bit pattern, because a decimal that reads back as the same value needs a
628            // printer this compiler has not written yet, and because a NaN payload survives.
629            let _ = write!(self.out, "{:#x}", imm.bits());
630        } else if scalar.is_int() {
631            let _ = write!(self.out, "{}", imm.signed(scalar));
632        } else {
633            let _ = write!(self.out, "{:#x}", imm.bits());
634        }
635    }
636
637    /// One metadata node, on one line.
638    fn meta_node(&mut self, meta: Meta) {
639        let node = self.module[meta];
640        let _ = write!(self.out, "!{} = tbaa ", meta.index());
641        self.string(self.names.resolve(node.name).as_bytes());
642        if let Some(parent) = node.parent {
643            let _ = write!(self.out, ", parent !{}", parent.index());
644        }
645        let _ = write!(self.out, ", offset {}", node.offset);
646        self.out.push('\n');
647    }
648
649    /// The linkage and, where it is not the ordinary one, the visibility.
650    fn linkage(&mut self, linkage: Linkage, visibility: Visibility) {
651        let _ = write!(self.out, ", linkage({})", linkage.name());
652        if visibility != Visibility::Default {
653            let _ = write!(self.out, ", visibility({})", visibility.name());
654        }
655    }
656
657    /// The section, where one was asked for.
658    fn section(&mut self, section: Option<Symbol>) {
659        if let Some(section) = section {
660            self.out.push_str(", section ");
661            self.string(self.names.resolve(section).as_bytes());
662        }
663    }
664
665    /// A byte string, quoted, with everything outside printable ASCII in hexadecimal.
666    fn string(&mut self, bytes: &[u8]) {
667        self.out.push('"');
668        for &byte in bytes {
669            match byte {
670                b'"' => self.out.push_str("\\\""),
671                b'\\' => self.out.push_str("\\\\"),
672                0x20..=0x7e => self.out.push(byte as char),
673                _ => {
674                    let _ = write!(self.out, "\\{byte:02x}");
675                }
676            }
677        }
678        self.out.push('"');
679    }
680}
681
682#[cfg(test)]
683mod tests {
684    use rucc_base::Interner;
685    use rucc_target::{Arch, Env, Os, TargetInfo, Triple};
686
687    use super::*;
688    use crate::func::Builder;
689    use crate::inst::{AsmInfo, CallInfo, MetaNode, SwitchInfo};
690    use crate::module::{AliasKind, TlsModel};
691    use crate::{AttrSet, Attrs, Flags, FloatPred, FpContract, IntPred, RmwOp};
692
693    fn target() -> TargetInfo {
694        TargetInfo::new(Triple::new(Arch::X86_64, Os::Linux, Env::Gnu))
695    }
696
697    #[test]
698    fn the_example_in_the_spec() {
699        let mut names = Interner::new();
700        let mut module = Module::new(names.intern("example.c"), &target());
701
702        let char_node = module.add_meta(MetaNode {
703            name: names.intern("omnipotent char"),
704            parent: None,
705            offset: 0,
706        });
707        let int_node = module.add_meta(MetaNode {
708            name: names.intern("int"),
709            parent: Some(char_node),
710            offset: 0,
711        });
712
713        let i32_ = Type::int(32);
714        let zero_bits = module.add_imm(Imm::int(0, i32_));
715        let init = module.push_data(&[Datum::Scalar { ty: i32_, value: zero_bits }]);
716        let mut counter = Global::new(names.intern("counter"), 4, 4);
717        counter.linkage = Linkage::Internal;
718        counter.init = Some(init);
719        module.add_global(counter);
720
721        let mut func = Func::new(
722            names.intern("sum"),
723            Signature::new().with_params(&[i32_]).with_returns(&[i32_]),
724        );
725        func.attrs = Attrs { set: AttrSet::NOUNWIND, fp_contract: FpContract::On };
726        let entry = func.create_block();
727        let n = func.append_param(entry, i32_);
728        let header = func.create_block();
729        let acc = func.append_param(header, i32_);
730        let i = func.append_param(header, i32_);
731        let exit = func.create_block();
732        let result = func.append_param(exit, i32_);
733
734        let mut b = Builder::new(&mut func, entry);
735        let zero = b.iconst(i32_, 0);
736        let cmp = b.icmp(IntPred::Sle, n, zero);
737        b.br_if(cmp, exit, &[zero], header, &[zero, zero]);
738
739        let mut b = Builder::new(&mut func, header);
740        let one = b.iconst(i32_, 1);
741        let next = b.binary(Opcode::Add, i, one, Flags::NSW);
742        let total = b.binary(Opcode::Add, acc, next, Flags::NSW);
743        let done = b.icmp(IntPred::Sge, next, n);
744        b.br_if(done, exit, &[total], header, &[total, next]);
745
746        let mut b = Builder::new(&mut func, exit);
747        let address = b.value(
748            InstData {
749                extra: Extra::Symbol(names.intern("counter")),
750                ..InstData::new(Opcode::GlobalAddr)
751            },
752            Type::PTR,
753        );
754        b.store(
755            result,
756            address,
757            MemInfo { size: 0, align: 4, order: MemOrder::NotAtomic, tbaa: Some(int_node) },
758            Flags::NONE,
759        );
760        b.ret(&[result]);
761        module.add_func(func);
762
763        assert_eq!(print(&module, &names), crate::fixtures::EXAMPLE);
764    }
765
766    #[test]
767    fn one_of_almost_everything() {
768        let mut names = Interner::new();
769        let mut module = Module::new(names.intern("zoo.c"), &target());
770        let int_node =
771            module.add_meta(MetaNode { name: names.intern("int"), parent: None, offset: 0 });
772
773        let i32_ = Type::int(32);
774        let i64_ = Type::int(64);
775        let f64_ = Type::float(crate::Float::F64);
776        let mut func = Func::new(
777            names.intern("zoo"),
778            Signature::new().with_params(&[i32_, Type::PTR]).with_returns(&[i32_]),
779        );
780        let entry = func.create_block();
781        let n = func.append_param(entry, i32_);
782        let p = func.append_param(entry, Type::PTR);
783        let middle = func.create_block();
784        let other = func.create_block();
785        let exit = func.create_block();
786        let taken = func.append_param(exit, i32_);
787        let arrival = func.create_block();
788
789        let mut b = Builder::new(&mut func, entry);
790        let minus_one = b.iconst(i64_, -1);
791        let half = b.fconst(f64_, 0x3ff8_0000_0000_0000);
792        let seven = b.func().add_imm(Imm::int(7, i32_));
793        let vector = b.value(
794            InstData { extra: Extra::Imm(seven), ..InstData::new(Opcode::Splat) },
795            Type::vector(i32_, 4),
796        );
797        let stack = b.func().add_mem(MemInfo {
798            size: 16,
799            align: 8,
800            order: MemOrder::NotAtomic,
801            tbaa: None,
802        });
803        let slot = b.value(
804            InstData { extra: Extra::Mem(stack), ..InstData::new(Opcode::Alloca) },
805            Type::PTR,
806        );
807        let args = b.func().push_values(&[slot, minus_one]);
808        let addr = b.value(InstData { args, ..InstData::new(Opcode::PtrAdd) }, Type::PTR);
809        let plain = MemInfo { size: 0, align: 4, order: MemOrder::NotAtomic, tbaa: Some(int_node) };
810        let loaded = b.load(i32_, addr, plain, Flags::NONE);
811        b.store(loaded, addr, plain, Flags::VOLATILE);
812
813        let atomic =
814            b.func().add_mem(MemInfo { size: 0, align: 4, order: MemOrder::SeqCst, tbaa: None });
815        let args = b.func().push_values(&[addr, n]);
816        let old = b.value(
817            InstData {
818                args,
819                extra: Extra::Rmw(RmwOp::Add, atomic),
820                ..InstData::new(Opcode::AtomicRmw)
821            },
822            i32_,
823        );
824        let args = b.func().push_values(&[addr, old, n]);
825        b.inst(
826            InstData { args, extra: Extra::Mem(atomic), ..InstData::new(Opcode::Cmpxchg) },
827            &[i32_, Type::I1],
828        );
829        b.inst(
830            InstData { extra: Extra::Order(MemOrder::SeqCst), ..InstData::new(Opcode::Fence) },
831            &[],
832        );
833        b.unary(Opcode::SExt, n, i64_);
834        b.fcmp(FloatPred::Oeq, half, half, Flags::NONE);
835        let args = b.func().push_values(&[n, n]);
836        b.inst(InstData { args, ..InstData::new(Opcode::SAddOverflow) }, &[i32_, Type::I1]);
837        let puts = b.func().add_signature(
838            Signature::new().with_params(&[Type::PTR]).with_returns(&[i32_]).variadic(),
839        );
840        b.call_varargs(
841            names.intern("puts"),
842            puts,
843            &[p, slot],
844            &[Abi::ByVal { size: 16, align: 8 }],
845        );
846        let indirect =
847            b.func().add_signature(Signature::new().with_params(&[i32_]).with_returns(&[i32_]));
848        let varargs = b.func().push_abis(&[]);
849        let info = b.func().add_call(CallInfo { callee: None, signature: indirect, varargs });
850        let args = b.func().push_values(&[p, n]);
851        b.value(
852            InstData { args, extra: Extra::Call(info), ..InstData::new(Opcode::CallIndirect) },
853            i32_,
854        );
855        let copy = b.func().add_mem(MemInfo {
856            size: 16,
857            align: 8,
858            order: MemOrder::NotAtomic,
859            tbaa: None,
860        });
861        let args = b.func().push_values(&[slot, p]);
862        b.inst(InstData { args, extra: Extra::Mem(copy), ..InstData::new(Opcode::Memcpy) }, &[]);
863        let asm = b.func().add_asm(AsmInfo {
864            template: names.intern("pause"),
865            constraints: names.intern(""),
866            clobbers: names.intern("memory"),
867            targets: crate::inst::BlockCallList::EMPTY,
868        });
869        b.inst(
870            InstData {
871                flags: Flags::VOLATILE,
872                extra: Extra::Asm(asm),
873                ..InstData::new(Opcode::InlineAsm)
874            },
875            &[],
876        );
877        let args = b.func().push_values(&[vector]);
878        b.value(
879            InstData {
880                args,
881                extra: Extra::Symbol(names.intern("x86.sse2.pmovmskb")),
882                ..InstData::new(Opcode::TargetIntrinsic)
883            },
884            i32_,
885        );
886        b.jump(middle, &[]);
887
888        let mut b = Builder::new(&mut func, middle);
889        let cases = b.func().push_imms(&[Imm::int(0, i32_), Imm::int(-1, i32_)]);
890        let default = BlockCall { block: other, args: crate::inst::ValueList::EMPTY };
891        let first = BlockCall { block: exit, args: b.func().push_values(&[n]) };
892        let second = BlockCall { block: other, args: crate::inst::ValueList::EMPTY };
893        let targets = b.func().push_block_calls(&[default, first, second]);
894        let switch = b.func().add_switch(SwitchInfo { targets, cases });
895        let args = b.func().push_values(&[n]);
896        b.inst(
897            InstData { args, extra: Extra::Switch(switch), ..InstData::new(Opcode::Switch) },
898            &[],
899        );
900
901        let mut b = Builder::new(&mut func, other);
902        let address = b.block_addr(arrival);
903        b.indirect_br(address, &[arrival]);
904
905        let mut b = Builder::new(&mut func, exit);
906        b.ret(&[taken]);
907
908        let mut b = Builder::new(&mut func, arrival);
909        let call = BlockCall { block: exit, args: b.func().push_values(&[n]) };
910        let targets = b.func().push_block_calls(&[call]);
911        let goto = b.func().add_asm(AsmInfo {
912            template: names.intern("jmp %l0"),
913            constraints: names.intern(""),
914            clobbers: names.intern(""),
915            targets,
916        });
917        b.inst(InstData { extra: Extra::Asm(goto), ..InstData::new(Opcode::InlineAsm) }, &[]);
918
919        module.add_func(func);
920
921        assert_eq!(print(&module, &names), crate::fixtures::ZOO);
922    }
923
924    #[test]
925    fn the_shapes_a_symbol_comes_in() {
926        let mut names = Interner::new();
927        let mut module = Module::new(names.intern("data.c"), &target());
928
929        let i32_ = Type::int(32);
930        let text = module.push_bytes(b"hi\x00\xff\"\\");
931        let entry_name = names.intern("hi.str");
932        let forward = module.add_reloc(Reloc { symbol: entry_name, addend: 8, size: 8 });
933        let backward = module.add_reloc(Reloc { symbol: entry_name, addend: -8, size: 8 });
934        let seven = module.add_imm(Imm::int(7, i32_));
935        let image = module.push_data(&[
936            Datum::Bytes(text),
937            Datum::Zero(2),
938            Datum::Scalar { ty: i32_, value: seven },
939            Datum::Addr(forward),
940            Datum::Addr(backward),
941        ]);
942        let mut table = Global::new(names.intern("table"), 28, 8);
943        table.init = Some(image);
944        table.constant = true;
945        table.section = Some(names.intern(".rodata.rel"));
946        module.add_global(table);
947
948        let mut errno = Global::new(names.intern("errno"), 4, 4);
949        errno.tls = Some(TlsModel::InitialExec);
950        errno.visibility = Visibility::Hidden;
951        module.add_global(errno);
952
953        // A zero sized object with an initialiser, which `char x[0] = { };` at file scope is.
954        // The image is there and has nothing in it, which is not the same as the global that has
955        // no image at all, and the two have to print differently for the reader to tell them
956        // apart.
957        let mut nothing = Global::new(names.intern("nothing"), 0, 1);
958        nothing.init = Some(module.push_data(&[]));
959        nothing.linkage = Linkage::Internal;
960        module.add_global(nothing);
961
962        let mut alias = Alias::new(names.intern("total"), names.intern("table"));
963        alias.linkage = Linkage::Weak;
964        module.add_alias(alias);
965        let mut memcpy = Alias::new(names.intern("memcpy"), names.intern("memcpy.resolve"));
966        memcpy.kind = AliasKind::IFunc;
967        memcpy.visibility = Visibility::Protected;
968        module.add_alias(memcpy);
969
970        let mut puts = Func::new(
971            names.intern("puts"),
972            Signature::new().with_params(&[Type::PTR]).with_returns(&[i32_]),
973        );
974        puts.linkage = Linkage::External;
975        puts.attrs.set = AttrSet::NOUNWIND | AttrSet::WILLRETURN;
976        module.add_func(puts);
977
978        let mut helper =
979            Func::new(names.intern("helper"), Signature::new().with_returns(&[i32_, i32_]));
980        helper.linkage = Linkage::Internal;
981        helper.section = Some(names.intern(".text.hot"));
982        helper.attrs.set = AttrSet::READNONE | AttrSet::ALWAYS_INLINE;
983        let block = helper.create_block();
984        let mut b = Builder::new(&mut helper, block);
985        let one = b.iconst(i32_, 1);
986        b.ret(&[one, one]);
987        module.add_func(helper);
988
989        assert_eq!(print(&module, &names), crate::fixtures::SYMBOLS);
990    }
991
992    #[test]
993    fn a_signature_writes_what_the_abi_asks_of_each_parameter() {
994        let mut names = Interner::new();
995        let module = Module::new(names.intern("abi.c"), &target());
996        let mut func = Func::new(
997            names.intern("f"),
998            Signature::new()
999                .and_param(Param::with_abi(Type::PTR, Abi::Sret { size: 24, align: 8 }))
1000                .and_param(Param::with_abi(Type::PTR, Abi::ByVal { size: 16, align: 8 }))
1001                .and_param(Param::with_abi(Type::int(8), Abi::Zext))
1002                .and_param(Param::new(Type::int(32))),
1003        );
1004        let entry = func.create_block();
1005        for param in [Type::PTR, Type::PTR, Type::int(8), Type::int(32)] {
1006            func.append_param(entry, param);
1007        }
1008        let mut b = Builder::new(&mut func, entry);
1009        b.ret(&[]);
1010
1011        assert_eq!(
1012            print_func(&module, &func, &names),
1013            "\
1014func @f(ptr sret(24, align 8), ptr byval(16, align 8), i8 zext, i32), linkage(external) {
1015block0(%0: ptr, %1: ptr, %2: i8, %3: i32):
1016    return
1017}
1018"
1019        );
1020    }
1021
1022    #[test]
1023    fn a_call_writes_what_the_abi_asks_of_an_argument_its_signature_does_not_name() {
1024        let mut names = Interner::new();
1025        let module = Module::new(names.intern("varargs.c"), &target());
1026        let i32_ = Type::int(32);
1027        let mut func = Func::new(names.intern("f"), Signature::new().with_params(&[Type::PTR]));
1028        let entry = func.create_block();
1029        let p = func.append_param(entry, Type::PTR);
1030        let mut b = Builder::new(&mut func, entry);
1031        let sig = b.func().add_signature(
1032            Signature::new().with_params(&[Type::PTR]).with_returns(&[i32_]).variadic(),
1033        );
1034        let one = b.iconst(i32_, 1);
1035        b.call_varargs(
1036            names.intern("printf"),
1037            sig,
1038            &[p, one, p],
1039            &[Abi::Plain, Abi::ByVal { size: 24, align: 8 }],
1040        );
1041        b.ret(&[]);
1042
1043        assert_eq!(
1044            print_func(&module, &func, &names),
1045            "\
1046func @f(ptr), linkage(external) {
1047block0(%0: ptr):
1048    %1 = iconst.i32 1
1049    %2 = call @printf(%0, %1, %0 byval(24, align 8)) : (ptr, ...) -> i32
1050    return
1051}
1052"
1053        );
1054    }
1055
1056    #[test]
1057    fn numbering_follows_the_text_and_not_the_tables() {
1058        // The blocks are laid out entry, middle, exit, and their contents are built in the
1059        // opposite order, so every index in the tables runs against the order they print in.
1060        // The numbers in the text have to come out in reading order anyway, because that is
1061        // what makes printing a module, parsing it and printing it again give the same bytes.
1062        let mut names = Interner::new();
1063        let mut module = Module::new(names.intern("order.c"), &target());
1064        let i32_ = Type::int(32);
1065        let mut func = Func::new(names.intern("f"), Signature::new().with_returns(&[i32_]));
1066        let entry = func.create_block();
1067        let middle = func.create_block();
1068        let exit = func.create_block();
1069        let arrived = func.append_param(exit, i32_);
1070
1071        let mut b = Builder::new(&mut func, exit);
1072        b.ret(&[arrived]);
1073        let mut b = Builder::new(&mut func, middle);
1074        let two = b.iconst(i32_, 2);
1075        b.jump(exit, &[two]);
1076        let mut b = Builder::new(&mut func, entry);
1077        b.jump(middle, &[]);
1078        module.add_func(func);
1079
1080        assert_eq!(
1081            print_func(&module, &module[module.funcs().next().unwrap()], &names),
1082            "\
1083func @f() -> i32, linkage(external) {
1084block0:
1085    jump block1
1086
1087block1:
1088    %0 = iconst.i32 2
1089    jump block2(%0)
1090
1091block2(%1: i32):
1092    return %1
1093}
1094"
1095        );
1096    }
1097}