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