1use std::fmt::Write as _;
29
30use rucc_base::{Interner, Symbol};
31
32use crate::func::Func;
33use crate::inst::{Block, BlockCall, Imm, Inst, InstData, MemInfo, Meta, Signature, Value};
34use crate::module::{Alias, Datum, Global, Module, Reloc};
35use crate::{Extra, FORMAT_VERSION, Linkage, MemOrder, Opcode, Type, Visibility};
36
37pub(crate) fn implied_result(opcode: Opcode) -> bool {
47 matches!(
48 opcode,
49 Opcode::ICmp
50 | Opcode::FCmp
51 | Opcode::GlobalAddr
52 | Opcode::Alloca
53 | Opcode::Call
54 | Opcode::CallIndirect
55 | Opcode::TailCall
56 )
57}
58
59#[must_use]
61pub fn print(module: &Module, names: &Interner) -> String {
62 let mut printer = Printer::new(module, names);
63 printer.module();
64 printer.finish()
65}
66
67#[must_use]
69pub fn print_func(module: &Module, func: &Func, names: &Interner) -> String {
70 let mut printer = Printer::new(module, names);
71 printer.func(func);
72 printer.finish()
73}
74
75#[derive(Debug)]
77pub struct Printer<'a> {
78 module: &'a Module,
79 names: &'a Interner,
80 out: String,
81 values: Vec<u32>,
85 blocks: Vec<u32>,
86}
87
88impl<'a> Printer<'a> {
89 #[must_use]
91 pub fn new(module: &'a Module, names: &'a Interner) -> Printer<'a> {
92 Printer { module, names, out: String::new(), values: Vec::new(), blocks: Vec::new() }
93 }
94
95 #[must_use]
97 pub fn finish(self) -> String {
98 self.out
99 }
100
101 pub fn module(&mut self) {
103 let module = self.module;
104 let name = self.names.resolve(module.name);
105 let _ = writeln!(self.out, "; ModuleID = '{name}'");
108 let _ = writeln!(self.out, "; format {FORMAT_VERSION}");
109 let _ = writeln!(self.out, "target triple = \"{}\"", module.triple);
110 let _ = writeln!(self.out, "target datalayout = \"{}\"", module.datalayout);
111
112 if module.globals().next().is_some() {
113 self.out.push('\n');
114 for id in module.globals() {
115 self.global(&module[id]);
116 }
117 }
118 if module.aliases().next().is_some() {
119 self.out.push('\n');
120 for id in module.aliases() {
121 self.alias(&module[id]);
122 }
123 }
124 for id in module.funcs() {
125 self.out.push('\n');
126 self.func(&module[id]);
127 }
128 if module.metadata().next().is_some() {
129 self.out.push('\n');
130 for meta in module.metadata() {
131 self.meta_node(meta);
132 }
133 }
134 }
135
136 fn global(&mut self, global: &Global) {
140 let _ = write!(self.out, "global @{} : ", self.names.resolve(global.name));
141 match self.scalar_init(global) {
142 Some((ty, imm)) => {
146 let _ = write!(self.out, "{ty} = ");
147 self.imm(imm, ty);
148 }
149 None => {
150 let _ = write!(self.out, "bytes {}", global.size);
151 if let Some(init) = global.init {
152 self.out.push_str(" = { ");
153 for (index, &datum) in self.module[init].iter().enumerate() {
154 if index > 0 {
155 self.out.push_str(", ");
156 }
157 self.datum(datum);
158 }
159 self.out.push_str(" }");
160 }
161 }
162 }
163 let _ = write!(self.out, ", align {}", global.align);
164 self.linkage(global.linkage, global.visibility);
165 if let Some(model) = global.tls {
166 let _ = write!(self.out, ", tls({})", model.name());
167 }
168 if global.constant {
169 self.out.push_str(", constant");
170 }
171 self.section(global.section);
172 self.out.push('\n');
173 }
174
175 fn scalar_init(&self, global: &Global) -> Option<(Type, Imm)> {
177 let init = global.init?;
178 let [datum] = self.module[init] else { return None };
179 let Datum::Scalar { ty, value } = datum else { return None };
180 (datum.size(self.module) == global.size).then(|| (ty, self.module[value]))
181 }
182
183 fn datum(&mut self, datum: Datum) {
185 match datum {
186 Datum::Zero(bytes) => {
187 let _ = write!(self.out, "zero {bytes}");
188 }
189 Datum::Bytes(range) => {
190 self.out.push_str("bytes ");
191 let bytes = &self.module[range];
192 self.string(bytes);
193 }
194 Datum::Scalar { ty, value } => {
195 let _ = write!(self.out, "{ty} ");
196 self.imm(self.module[value], ty);
197 }
198 Datum::Addr(reloc) => {
199 let Reloc { symbol, addend, size } = self.module[reloc];
200 let _ = write!(self.out, "addr.{size} @{}", self.names.resolve(symbol));
201 match addend.signum() {
202 1 => {
203 let _ = write!(self.out, " + {addend}");
204 }
205 -1 => {
206 let _ = match addend.checked_neg() {
210 Some(amount) => write!(self.out, " - {amount}"),
211 None => write!(self.out, " + {addend}"),
212 };
213 }
214 _ => {}
215 }
216 }
217 }
218 }
219
220 fn alias(&mut self, alias: &Alias) {
222 let _ = write!(
223 self.out,
224 "{} @{} = @{}",
225 alias.kind.name(),
226 self.names.resolve(alias.name),
227 self.names.resolve(alias.target)
228 );
229 self.linkage(alias.linkage, alias.visibility);
230 self.out.push('\n');
231 }
232
233 pub fn func(&mut self, func: &Func) {
237 self.number(func);
238 let _ = write!(self.out, "func @{}", self.names.resolve(func.name));
239 self.signature(func.signature());
240 self.linkage(func.linkage, func.visibility);
241 if !func.attrs.is_default() {
242 let _ = write!(self.out, ", {}", func.attrs);
243 }
244 self.section(func.section);
245 if func.is_declaration() {
246 self.out.push_str(";\n");
247 return;
248 }
249 self.out.push_str(" {\n");
250 for (index, block) in func.blocks().enumerate() {
251 if index > 0 {
252 self.out.push('\n');
253 }
254 self.block(func, block);
255 }
256 self.out.push_str("}\n");
257 }
258
259 fn number(&mut self, func: &Func) {
264 let counts = func.counts();
265 self.values.clear();
266 self.values.resize(counts.values, u32::MAX);
267 self.blocks.clear();
268 self.blocks.resize(counts.blocks, u32::MAX);
269 let mut next = 0;
270 for (index, block) in func.blocks().enumerate() {
271 self.blocks[block.index()] = index as u32;
272 for ¶m in &func[block].params {
273 self.values[param.index()] = next;
274 next += 1;
275 }
276 for inst in func.insts(block) {
277 for result in func[inst].results() {
278 self.values[result.index()] = next;
279 next += 1;
280 }
281 }
282 }
283 }
284
285 fn signature(&mut self, signature: &Signature) {
287 self.out.push('(');
288 for (index, &ty) in signature.params.iter().enumerate() {
289 if index > 0 {
290 self.out.push_str(", ");
291 }
292 let _ = write!(self.out, "{ty}");
293 }
294 if signature.variadic {
295 if !signature.params.is_empty() {
296 self.out.push_str(", ");
297 }
298 self.out.push_str("...");
299 }
300 self.out.push(')');
301 match signature.returns.as_slice() {
302 [] => {}
303 [ty] => {
304 let _ = write!(self.out, " -> {ty}");
305 }
306 types => {
307 self.out.push_str(" -> (");
308 for (index, &ty) in types.iter().enumerate() {
309 if index > 0 {
310 self.out.push_str(", ");
311 }
312 let _ = write!(self.out, "{ty}");
313 }
314 self.out.push(')');
315 }
316 }
317 }
318
319 fn block(&mut self, func: &Func, block: Block) {
321 let _ = write!(self.out, "block{}", self.blocks[block.index()]);
322 let params = &func[block].params;
323 if !params.is_empty() {
324 self.out.push('(');
325 for (index, ¶m) in params.iter().enumerate() {
326 if index > 0 {
327 self.out.push_str(", ");
328 }
329 self.value(param);
330 let _ = write!(self.out, ": {}", func[param].ty);
331 }
332 self.out.push(')');
333 }
334 self.out.push_str(":\n");
335 for inst in func.insts(block) {
336 self.inst(func, inst);
337 }
338 }
339
340 fn inst(&mut self, func: &Func, inst: Inst) {
342 let data = func[inst];
343 self.out.push_str(" ");
344 for (index, result) in data.results().enumerate() {
345 if index > 0 {
346 self.out.push_str(", ");
347 }
348 self.value(result);
349 }
350 if data.results > 0 {
351 self.out.push_str(" = ");
352 }
353 self.out.push_str(data.opcode.name());
354 self.result_types(func, &data);
355 let _ = write!(self.out, "{}", data.flags);
356 self.operands(func, &data);
357 self.out.push('\n');
358 }
359
360 fn result_types(&mut self, func: &Func, data: &InstData) {
362 let results: Vec<Value> = data.results().collect();
363 match results.as_slice() {
364 [] => {}
365 _ if implied_result(data.opcode) => {}
366 [result] => {
367 let ty = func[*result].ty;
368 let takes_the_same = func[data.args].first().is_some_and(|&arg| func[arg].ty == ty);
369 if !takes_the_same {
370 let _ = write!(self.out, ".{ty}");
371 }
372 }
373 types => {
376 self.out.push_str(".(");
377 for (index, &result) in types.iter().enumerate() {
378 if index > 0 {
379 self.out.push_str(", ");
380 }
381 let _ = write!(self.out, "{}", func[result].ty);
382 }
383 self.out.push(')');
384 }
385 }
386 }
387
388 fn operands(&mut self, func: &Func, data: &InstData) {
390 let args = &func[data.args];
391 match data.extra {
392 Extra::None => self.value_list_spaced(args),
393 Extra::Imm(imm) => {
394 self.out.push(' ');
395 let ty = data.first_result.map_or(Type::VOID, |result| func[result].ty);
396 self.imm(func[imm], ty);
397 }
398 Extra::Symbol(symbol) => {
399 let _ = write!(self.out, " @{}", self.names.resolve(symbol));
400 if !args.is_empty() {
401 self.out.push('(');
402 self.value_list(args);
403 self.out.push(')');
404 }
405 }
406 Extra::IntPred(pred) => {
407 let _ = write!(self.out, " {}", pred.name());
408 self.value_list_spaced(args);
409 }
410 Extra::FloatPred(pred) => {
411 let _ = write!(self.out, " {}", pred.name());
412 self.value_list_spaced(args);
413 }
414 Extra::Mem(mem) => {
415 match (data.opcode, args) {
416 (Opcode::Store | Opcode::AtomicStore, [value, addr]) => {
419 self.out.push(' ');
420 self.value(*value);
421 self.out.push_str(" -> ");
422 self.value(*addr);
423 }
424 _ => self.value_list_spaced(args),
425 }
426 self.mem(func[mem]);
427 }
428 Extra::Rmw(op, mem) => {
429 let _ = write!(self.out, " {}", op.name());
430 self.value_list_spaced(args);
431 self.mem(func[mem]);
432 }
433 Extra::Order(order) => {
434 let _ = write!(self.out, " {}", order.name());
435 }
436 Extra::Targets(targets) => {
437 if !args.is_empty() {
440 self.value_list_spaced(args);
441 self.out.push(',');
442 }
443 for (index, &call) in func[targets].iter().enumerate() {
444 self.out.push_str(if index > 0 { ", " } else { " " });
445 self.block_call(func, call);
446 }
447 }
448 Extra::Call(call) => {
449 let info = func[call];
450 let rest = match info.callee {
451 Some(callee) => {
452 let _ = write!(self.out, " @{}", self.names.resolve(callee));
453 args
454 }
455 None => {
458 self.out.push(' ');
459 match args.split_first() {
460 Some((&addr, rest)) => {
461 self.value(addr);
462 rest
463 }
464 None => {
465 self.out.push_str("%?");
466 &[]
467 }
468 }
469 }
470 };
471 self.out.push('(');
472 self.value_list(rest);
473 self.out.push_str(") : ");
474 self.signature(&func[info.signature]);
475 }
476 Extra::Switch(switch) => {
477 let info = func[switch];
478 let ty = args.first().map_or(Type::VOID, |&arg| func[arg].ty);
479 self.value_list_spaced(args);
480 if let Some((&default, cases)) = func[info.targets].split_first() {
481 self.out.push_str(", ");
482 self.block_call(func, default);
483 self.out.push_str(", [");
484 for (index, (&case, &value)) in cases.iter().zip(&func[info.cases]).enumerate()
485 {
486 if index > 0 {
487 self.out.push_str(", ");
488 }
489 self.imm(value, ty);
490 self.out.push_str(" => ");
491 self.block_call(func, case);
492 }
493 self.out.push(']');
494 }
495 }
496 Extra::Asm(asm) => {
497 let info = func[asm];
498 self.out.push(' ');
499 self.string(self.names.resolve(info.template).as_bytes());
500 self.out.push_str(", ");
501 self.string(self.names.resolve(info.constraints).as_bytes());
502 self.out.push_str(", ");
503 self.string(self.names.resolve(info.clobbers).as_bytes());
504 self.out.push('(');
505 self.value_list(args);
506 self.out.push(')');
507 if !info.targets.is_empty() {
508 self.out.push_str(", labels [");
509 for (index, &call) in func[info.targets].iter().enumerate() {
510 if index > 0 {
511 self.out.push_str(", ");
512 }
513 self.block_call(func, call);
514 }
515 self.out.push(']');
516 }
517 }
518 }
519 }
520
521 fn value_list_spaced(&mut self, args: &[Value]) {
523 if args.is_empty() {
524 return;
525 }
526 self.out.push(' ');
527 self.value_list(args);
528 }
529
530 fn value_list(&mut self, args: &[Value]) {
532 for (index, &arg) in args.iter().enumerate() {
533 if index > 0 {
534 self.out.push_str(", ");
535 }
536 self.value(arg);
537 }
538 }
539
540 fn block_call(&mut self, func: &Func, call: BlockCall) {
542 let _ = write!(self.out, "block{}", self.blocks[call.block.index()]);
543 let args = &func[call.args];
544 if !args.is_empty() {
545 self.out.push('(');
546 self.value_list(args);
547 self.out.push(')');
548 }
549 }
550
551 fn mem(&mut self, info: MemInfo) {
553 if info.size != 0 {
554 let _ = write!(self.out, ", size {}", info.size);
555 }
556 let _ = write!(self.out, ", align {}", info.align);
557 if info.order != MemOrder::NotAtomic {
558 let _ = write!(self.out, ", {}", info.order.name());
559 }
560 if let Some(tbaa) = info.tbaa {
561 let _ = write!(self.out, ", tbaa !{}", tbaa.index());
562 }
563 }
564
565 fn value(&mut self, value: Value) {
567 match self.values.get(value.index()).copied() {
568 Some(number) if number != u32::MAX => {
569 let _ = write!(self.out, "%{number}");
570 }
571 _ => self.out.push_str("%?"),
575 }
576 }
577
578 fn imm(&mut self, imm: Imm, ty: Type) {
580 let scalar = if ty.is_vector() { ty.lane() } else { ty };
581 if scalar.is_float() {
582 let _ = write!(self.out, "{:#x}", imm.bits());
585 } else if scalar.is_int() {
586 let _ = write!(self.out, "{}", imm.signed(scalar));
587 } else {
588 let _ = write!(self.out, "{:#x}", imm.bits());
589 }
590 }
591
592 fn meta_node(&mut self, meta: Meta) {
594 let node = self.module[meta];
595 let _ = write!(self.out, "!{} = tbaa ", meta.index());
596 self.string(self.names.resolve(node.name).as_bytes());
597 if let Some(parent) = node.parent {
598 let _ = write!(self.out, ", parent !{}", parent.index());
599 }
600 let _ = write!(self.out, ", offset {}", node.offset);
601 self.out.push('\n');
602 }
603
604 fn linkage(&mut self, linkage: Linkage, visibility: Visibility) {
606 let _ = write!(self.out, ", linkage({})", linkage.name());
607 if visibility != Visibility::Default {
608 let _ = write!(self.out, ", visibility({})", visibility.name());
609 }
610 }
611
612 fn section(&mut self, section: Option<Symbol>) {
614 if let Some(section) = section {
615 self.out.push_str(", section ");
616 self.string(self.names.resolve(section).as_bytes());
617 }
618 }
619
620 fn string(&mut self, bytes: &[u8]) {
622 self.out.push('"');
623 for &byte in bytes {
624 match byte {
625 b'"' => self.out.push_str("\\\""),
626 b'\\' => self.out.push_str("\\\\"),
627 0x20..=0x7e => self.out.push(byte as char),
628 _ => {
629 let _ = write!(self.out, "\\{byte:02x}");
630 }
631 }
632 }
633 self.out.push('"');
634 }
635}
636
637#[cfg(test)]
638mod tests {
639 use rucc_base::Interner;
640 use rucc_target::{Arch, Env, Os, TargetInfo, Triple};
641
642 use super::*;
643 use crate::func::Builder;
644 use crate::inst::{AsmInfo, CallInfo, MetaNode, SwitchInfo};
645 use crate::module::{AliasKind, TlsModel};
646 use crate::{AttrSet, Attrs, Flags, FloatPred, FpContract, IntPred, RmwOp};
647
648 fn target() -> TargetInfo {
649 TargetInfo::new(Triple::new(Arch::X86_64, Os::Linux, Env::Gnu))
650 }
651
652 #[test]
653 fn the_example_in_the_spec() {
654 let mut names = Interner::new();
655 let mut module = Module::new(names.intern("example.c"), &target());
656
657 let char_node = module.add_meta(MetaNode {
658 name: names.intern("omnipotent char"),
659 parent: None,
660 offset: 0,
661 });
662 let int_node = module.add_meta(MetaNode {
663 name: names.intern("int"),
664 parent: Some(char_node),
665 offset: 0,
666 });
667
668 let i32_ = Type::int(32);
669 let zero_bits = module.add_imm(Imm::int(0, i32_));
670 let init = module.push_data(&[Datum::Scalar { ty: i32_, value: zero_bits }]);
671 let mut counter = Global::new(names.intern("counter"), 4, 4);
672 counter.linkage = Linkage::Internal;
673 counter.init = Some(init);
674 module.add_global(counter);
675
676 let mut func = Func::new(
677 names.intern("sum"),
678 Signature::new().with_params(&[i32_]).with_returns(&[i32_]),
679 );
680 func.attrs = Attrs { set: AttrSet::NOUNWIND, fp_contract: FpContract::On };
681 let entry = func.create_block();
682 let n = func.append_param(entry, i32_);
683 let header = func.create_block();
684 let acc = func.append_param(header, i32_);
685 let i = func.append_param(header, i32_);
686 let exit = func.create_block();
687 let result = func.append_param(exit, i32_);
688
689 let mut b = Builder::new(&mut func, entry);
690 let zero = b.iconst(i32_, 0);
691 let cmp = b.icmp(IntPred::Sle, n, zero);
692 b.br_if(cmp, exit, &[zero], header, &[zero, zero]);
693
694 let mut b = Builder::new(&mut func, header);
695 let one = b.iconst(i32_, 1);
696 let next = b.binary(Opcode::Add, i, one, Flags::NSW);
697 let total = b.binary(Opcode::Add, acc, next, Flags::NSW);
698 let done = b.icmp(IntPred::Sge, next, n);
699 b.br_if(done, exit, &[total], header, &[total, next]);
700
701 let mut b = Builder::new(&mut func, exit);
702 let address = b.value(
703 InstData {
704 extra: Extra::Symbol(names.intern("counter")),
705 ..InstData::new(Opcode::GlobalAddr)
706 },
707 Type::PTR,
708 );
709 b.store(
710 result,
711 address,
712 MemInfo { size: 0, align: 4, order: MemOrder::NotAtomic, tbaa: Some(int_node) },
713 Flags::NONE,
714 );
715 b.ret(&[result]);
716 module.add_func(func);
717
718 assert_eq!(print(&module, &names), crate::fixtures::EXAMPLE);
719 }
720
721 #[test]
722 fn one_of_almost_everything() {
723 let mut names = Interner::new();
724 let mut module = Module::new(names.intern("zoo.c"), &target());
725 let int_node =
726 module.add_meta(MetaNode { name: names.intern("int"), parent: None, offset: 0 });
727
728 let i32_ = Type::int(32);
729 let i64_ = Type::int(64);
730 let f64_ = Type::float(crate::Float::F64);
731 let mut func = Func::new(
732 names.intern("zoo"),
733 Signature::new().with_params(&[i32_, Type::PTR]).with_returns(&[i32_]),
734 );
735 let entry = func.create_block();
736 let n = func.append_param(entry, i32_);
737 let p = func.append_param(entry, Type::PTR);
738 let middle = func.create_block();
739 let other = func.create_block();
740 let exit = func.create_block();
741 let taken = func.append_param(exit, i32_);
742
743 let mut b = Builder::new(&mut func, entry);
744 let minus_one = b.iconst(i64_, -1);
745 let half = b.fconst(f64_, 0x3ff8_0000_0000_0000);
746 let seven = b.func().add_imm(Imm::int(7, i32_));
747 let vector = b.value(
748 InstData { extra: Extra::Imm(seven), ..InstData::new(Opcode::Splat) },
749 Type::vector(i32_, 4),
750 );
751 let stack = b.func().add_mem(MemInfo {
752 size: 16,
753 align: 8,
754 order: MemOrder::NotAtomic,
755 tbaa: None,
756 });
757 let slot = b.value(
758 InstData { extra: Extra::Mem(stack), ..InstData::new(Opcode::Alloca) },
759 Type::PTR,
760 );
761 let args = b.func().push_values(&[slot, minus_one]);
762 let addr = b.value(InstData { args, ..InstData::new(Opcode::PtrAdd) }, Type::PTR);
763 let plain = MemInfo { size: 0, align: 4, order: MemOrder::NotAtomic, tbaa: Some(int_node) };
764 let loaded = b.load(i32_, addr, plain, Flags::NONE);
765 b.store(loaded, addr, plain, Flags::VOLATILE);
766
767 let atomic =
768 b.func().add_mem(MemInfo { size: 0, align: 4, order: MemOrder::SeqCst, tbaa: None });
769 let args = b.func().push_values(&[addr, n]);
770 let old = b.value(
771 InstData {
772 args,
773 extra: Extra::Rmw(RmwOp::Add, atomic),
774 ..InstData::new(Opcode::AtomicRmw)
775 },
776 i32_,
777 );
778 let args = b.func().push_values(&[addr, old, n]);
779 b.inst(
780 InstData { args, extra: Extra::Mem(atomic), ..InstData::new(Opcode::Cmpxchg) },
781 &[i32_, Type::I1],
782 );
783 b.inst(
784 InstData { extra: Extra::Order(MemOrder::SeqCst), ..InstData::new(Opcode::Fence) },
785 &[],
786 );
787 b.unary(Opcode::SExt, n, i64_);
788 b.fcmp(FloatPred::Oeq, half, half, Flags::NONE);
789 let args = b.func().push_values(&[n, n]);
790 b.inst(InstData { args, ..InstData::new(Opcode::SAddOverflow) }, &[i32_, Type::I1]);
791 let puts = b.func().add_signature(
792 Signature::new().with_params(&[Type::PTR]).with_returns(&[i32_]).variadic(),
793 );
794 b.call(names.intern("puts"), puts, &[p]);
795 let indirect =
796 b.func().add_signature(Signature::new().with_params(&[i32_]).with_returns(&[i32_]));
797 let info = b.func().add_call(CallInfo { callee: None, signature: indirect });
798 let args = b.func().push_values(&[p, n]);
799 b.value(
800 InstData { args, extra: Extra::Call(info), ..InstData::new(Opcode::CallIndirect) },
801 i32_,
802 );
803 let copy = b.func().add_mem(MemInfo {
804 size: 16,
805 align: 8,
806 order: MemOrder::NotAtomic,
807 tbaa: None,
808 });
809 let args = b.func().push_values(&[slot, p]);
810 b.inst(InstData { args, extra: Extra::Mem(copy), ..InstData::new(Opcode::Memcpy) }, &[]);
811 let asm = b.func().add_asm(AsmInfo {
812 template: names.intern("pause"),
813 constraints: names.intern(""),
814 clobbers: names.intern("memory"),
815 targets: crate::inst::BlockCallList::EMPTY,
816 });
817 b.inst(
818 InstData {
819 flags: Flags::VOLATILE,
820 extra: Extra::Asm(asm),
821 ..InstData::new(Opcode::InlineAsm)
822 },
823 &[],
824 );
825 let args = b.func().push_values(&[vector]);
826 b.value(
827 InstData {
828 args,
829 extra: Extra::Symbol(names.intern("x86.sse2.pmovmskb")),
830 ..InstData::new(Opcode::TargetIntrinsic)
831 },
832 i32_,
833 );
834 b.jump(middle, &[]);
835
836 let mut b = Builder::new(&mut func, middle);
837 let cases = b.func().push_imms(&[Imm::int(0, i32_), Imm::int(-1, i32_)]);
838 let default = BlockCall { block: other, args: crate::inst::ValueList::EMPTY };
839 let first = BlockCall { block: exit, args: b.func().push_values(&[n]) };
840 let second = BlockCall { block: other, args: crate::inst::ValueList::EMPTY };
841 let targets = b.func().push_block_calls(&[default, first, second]);
842 let switch = b.func().add_switch(SwitchInfo { targets, cases });
843 let args = b.func().push_values(&[n]);
844 b.inst(
845 InstData { args, extra: Extra::Switch(switch), ..InstData::new(Opcode::Switch) },
846 &[],
847 );
848
849 let mut b = Builder::new(&mut func, other);
850 let call = BlockCall { block: exit, args: b.func().push_values(&[n]) };
851 let targets = b.func().push_block_calls(&[call]);
852 let goto = b.func().add_asm(AsmInfo {
853 template: names.intern("jmp %l0"),
854 constraints: names.intern(""),
855 clobbers: names.intern(""),
856 targets,
857 });
858 b.inst(InstData { extra: Extra::Asm(goto), ..InstData::new(Opcode::InlineAsm) }, &[]);
859
860 let mut b = Builder::new(&mut func, exit);
861 b.ret(&[taken]);
862
863 module.add_func(func);
864
865 assert_eq!(print(&module, &names), crate::fixtures::ZOO);
866 }
867
868 #[test]
869 fn the_shapes_a_symbol_comes_in() {
870 let mut names = Interner::new();
871 let mut module = Module::new(names.intern("data.c"), &target());
872
873 let i32_ = Type::int(32);
874 let text = module.push_bytes(b"hi\x00\xff\"\\");
875 let entry_name = names.intern("hi.str");
876 let forward = module.add_reloc(Reloc { symbol: entry_name, addend: 8, size: 8 });
877 let backward = module.add_reloc(Reloc { symbol: entry_name, addend: -8, size: 8 });
878 let seven = module.add_imm(Imm::int(7, i32_));
879 let image = module.push_data(&[
880 Datum::Bytes(text),
881 Datum::Zero(2),
882 Datum::Scalar { ty: i32_, value: seven },
883 Datum::Addr(forward),
884 Datum::Addr(backward),
885 ]);
886 let mut table = Global::new(names.intern("table"), 28, 8);
887 table.init = Some(image);
888 table.constant = true;
889 table.section = Some(names.intern(".rodata.rel"));
890 module.add_global(table);
891
892 let mut errno = Global::new(names.intern("errno"), 4, 4);
893 errno.tls = Some(TlsModel::InitialExec);
894 errno.visibility = Visibility::Hidden;
895 module.add_global(errno);
896
897 let mut alias = Alias::new(names.intern("total"), names.intern("table"));
898 alias.linkage = Linkage::Weak;
899 module.add_alias(alias);
900 let mut memcpy = Alias::new(names.intern("memcpy"), names.intern("memcpy.resolve"));
901 memcpy.kind = AliasKind::IFunc;
902 memcpy.visibility = Visibility::Protected;
903 module.add_alias(memcpy);
904
905 let mut puts = Func::new(
906 names.intern("puts"),
907 Signature::new().with_params(&[Type::PTR]).with_returns(&[i32_]),
908 );
909 puts.linkage = Linkage::External;
910 puts.attrs.set = AttrSet::NOUNWIND | AttrSet::WILLRETURN;
911 module.add_func(puts);
912
913 let mut helper =
914 Func::new(names.intern("helper"), Signature::new().with_returns(&[i32_, i32_]));
915 helper.linkage = Linkage::Internal;
916 helper.section = Some(names.intern(".text.hot"));
917 helper.attrs.set = AttrSet::READNONE | AttrSet::ALWAYS_INLINE;
918 let block = helper.create_block();
919 let mut b = Builder::new(&mut helper, block);
920 let one = b.iconst(i32_, 1);
921 b.ret(&[one, one]);
922 module.add_func(helper);
923
924 assert_eq!(print(&module, &names), crate::fixtures::SYMBOLS);
925 }
926
927 #[test]
928 fn numbering_follows_the_text_and_not_the_tables() {
929 let mut names = Interner::new();
934 let mut module = Module::new(names.intern("order.c"), &target());
935 let i32_ = Type::int(32);
936 let mut func = Func::new(names.intern("f"), Signature::new().with_returns(&[i32_]));
937 let entry = func.create_block();
938 let middle = func.create_block();
939 let exit = func.create_block();
940 let arrived = func.append_param(exit, i32_);
941
942 let mut b = Builder::new(&mut func, exit);
943 b.ret(&[arrived]);
944 let mut b = Builder::new(&mut func, middle);
945 let two = b.iconst(i32_, 2);
946 b.jump(exit, &[two]);
947 let mut b = Builder::new(&mut func, entry);
948 b.jump(middle, &[]);
949 module.add_func(func);
950
951 assert_eq!(
952 print_func(&module, &module[module.funcs().next().unwrap()], &names),
953 "\
954func @f() -> i32, linkage(external) {
955block0:
956 jump block1
957
958block1:
959 %0 = iconst.i32 2
960 jump block2(%0)
961
962block2(%1: i32):
963 return %1
964}
965"
966 );
967 }
968}