1use 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
39pub(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#[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#[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#[derive(Debug)]
80pub struct Printer<'a> {
81 module: &'a Module,
82 names: &'a Interner,
83 out: String,
84 values: Vec<u32>,
88 blocks: Vec<u32>,
89}
90
91impl<'a> Printer<'a> {
92 #[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 #[must_use]
100 pub fn finish(self) -> String {
101 self.out
102 }
103
104 pub fn module(&mut self) {
106 let module = self.module;
107 let name = self.names.resolve(module.name);
108 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 fn global(&mut self, global: &Global) {
143 let _ = write!(self.out, "global @{} : ", self.names.resolve(global.name));
144 match self.scalar_init(global) {
145 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 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 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 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 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 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 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 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 ¶m 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 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 fn param(&mut self, param: &Param) {
336 let _ = write!(self.out, "{}", param.ty);
337 self.abi(param.abi);
338 }
339
340 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 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, ¶m) 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 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 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 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 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 (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 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 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 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 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 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 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 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 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 _ => self.out.push_str("%?"),
620 }
621 }
622
623 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 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 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 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 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 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 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 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}