1use crate::basic_block::BasicBlock;
4use crate::context::{BlockId, ConstId, Context, InstrId, TypeId, ValueRef};
5use crate::function::Function;
6use crate::instruction::{FastMathFlags, InstrKind};
7use crate::module::Module;
8use crate::types::{FloatKind, StructType, TypeData};
9use crate::value::ConstantData;
10use std::fmt::Write as FmtWrite;
11
12pub struct Printer<'a> {
14 ctx: &'a Context,
16}
17
18impl<'a> Printer<'a> {
19 pub fn new(ctx: &'a Context) -> Self {
21 Printer { ctx }
22 }
23
24 pub fn print_module(&self, module: &Module) -> String {
26 let mut out = String::new();
27
28 if let Some(ref sf) = module.source_filename {
30 writeln!(out, "source_filename = {:?}", sf).unwrap();
31 }
32 if let Some(ref dl) = module.data_layout {
33 writeln!(out, "target datalayout = {:?}", dl).unwrap();
34 }
35 if let Some(ref tt) = module.target_triple {
36 writeln!(out, "target triple = {:?}", tt).unwrap();
37 }
38
39 if !module.named_types.is_empty() {
41 writeln!(out).unwrap();
42 for (name, ty) in &module.named_types {
43 write!(out, "%{} = type ", name).unwrap();
44 if let TypeData::Struct(st) = self.ctx.get_type(*ty) {
45 self.write_struct_body(&mut out, st);
46 } else {
47 self.write_type(&mut out, *ty);
48 }
49 writeln!(out).unwrap();
50 }
51 }
52
53 if !module.globals.is_empty() {
55 writeln!(out).unwrap();
56 for gv in &module.globals {
57 let linkage = gv.linkage.as_str();
58 if !linkage.is_empty() {
59 write!(out, "@{} = {} ", gv.name, linkage).unwrap();
60 } else {
61 write!(out, "@{} = ", gv.name).unwrap();
62 }
63 if gv.is_constant {
64 write!(out, "constant ").unwrap();
65 } else {
66 write!(out, "global ").unwrap();
67 }
68 self.write_type(&mut out, gv.ty);
69 if let Some(init) = gv.initializer {
70 write!(out, " ").unwrap();
71 self.write_const_value(&mut out, init);
72 } else {
73 write!(out, " undef").unwrap();
74 }
75 writeln!(out).unwrap();
76 }
77 }
78
79 for func in &module.functions {
81 writeln!(out).unwrap();
82 self.write_function(&mut out, func);
83 }
84
85 if !module.named_metadata.is_empty() || !module.metadata_nodes.is_empty() {
86 writeln!(out).unwrap();
87 for (name, value) in &module.named_metadata {
88 writeln!(out, "!{} = {}", name, value).unwrap();
89 }
90 let mut ids: Vec<u32> = module.metadata_nodes.keys().copied().collect();
91 ids.sort_unstable();
92 for id in ids {
93 if let Some(value) = module.metadata_node(id) {
94 writeln!(out, "!{} = {}", id, value).unwrap();
95 }
96 }
97 }
98
99 out
100 }
101
102 fn write_type(&self, out: &mut String, ty: TypeId) {
107 match self.ctx.get_type(ty) {
108 TypeData::Void => out.push_str("void"),
109 TypeData::Integer(bits) => {
110 write!(out, "i{}", bits).unwrap();
111 }
112 TypeData::Float(kind) => out.push_str(float_kind_str(*kind)),
113 TypeData::Pointer => out.push_str("ptr"),
114 TypeData::Label => out.push_str("label"),
115 TypeData::Metadata => out.push_str("metadata"),
116 TypeData::Array { element, len } => {
117 let elem = *element;
118 let l = *len;
119 write!(out, "[{} x ", l).unwrap();
120 self.write_type(out, elem);
121 out.push(']');
122 }
123 TypeData::Vector {
124 element,
125 len,
126 scalable,
127 } => {
128 let elem = *element;
129 let l = *len;
130 let sc = *scalable;
131 if sc {
132 write!(out, "<vscale x {} x ", l).unwrap();
133 } else {
134 write!(out, "<{} x ", l).unwrap();
135 }
136 self.write_type(out, elem);
137 out.push('>');
138 }
139 TypeData::Struct(st) => {
140 if let Some(ref name) = st.name.clone() {
141 write!(out, "%{}", name).unwrap();
142 } else {
143 let st = st.clone();
144 self.write_struct_body(out, &st);
145 }
146 }
147 TypeData::Function(ft) => {
148 let ft = ft.clone();
149 self.write_type(out, ft.ret);
150 out.push_str(" (");
151 for (i, &p) in ft.params.iter().enumerate() {
152 if i > 0 {
153 out.push_str(", ");
154 }
155 self.write_type(out, p);
156 }
157 if ft.variadic {
158 if !ft.params.is_empty() {
159 out.push_str(", ");
160 }
161 out.push_str("...");
162 }
163 out.push(')');
164 }
165 }
166 }
167
168 fn write_struct_body(&self, out: &mut String, st: &StructType) {
169 if st.packed {
170 out.push('<');
171 }
172 out.push_str("{ ");
173 for (i, &f) in st.fields.iter().enumerate() {
174 if i > 0 {
175 out.push_str(", ");
176 }
177 self.write_type(out, f);
178 }
179 out.push_str(" }");
180 if st.packed {
181 out.push('>');
182 }
183 }
184
185 fn write_const_with_type(&self, out: &mut String, id: ConstId) {
191 let ty = self.ctx.type_of_const(id);
192 self.write_type(out, ty);
193 out.push(' ');
194 self.write_const_value(out, id);
195 }
196
197 fn write_const_value(&self, out: &mut String, id: ConstId) {
198 match self.ctx.get_const(id) {
199 ConstantData::Int { val, .. } => {
200 write!(out, "{}", *val as i64).unwrap();
201 }
202 ConstantData::IntWide { words, .. } => {
203 out.push_str("0x");
205 for w in words.iter().rev() {
206 write!(out, "{:016x}", w).unwrap();
207 }
208 }
209 ConstantData::Float { ty, bits } => {
210 match self.ctx.get_type(*ty) {
211 TypeData::Float(FloatKind::Single) => {
212 let f = f32::from_bits(*bits as u32);
213 let d = f as f64;
215 write!(out, "0x{:016X}", d.to_bits()).unwrap();
216 }
217 _ => {
218 write!(out, "0x{:016X}", bits).unwrap();
220 }
221 }
222 }
223 ConstantData::Null(_) => out.push_str("null"),
224 ConstantData::Undef(_) => out.push_str("undef"),
225 ConstantData::Poison(_) => out.push_str("poison"),
226 ConstantData::ZeroInitializer(_) => out.push_str("zeroinitializer"),
227 ConstantData::Array { elements, .. } => {
228 out.push('[');
229 for (i, &e) in elements.iter().enumerate() {
230 if i > 0 {
231 out.push_str(", ");
232 }
233 self.write_const_with_type(out, e);
234 }
235 out.push(']');
236 }
237 ConstantData::Struct { fields, .. } => {
238 out.push_str("{ ");
239 for (i, &f) in fields.iter().enumerate() {
240 if i > 0 {
241 out.push_str(", ");
242 }
243 self.write_const_with_type(out, f);
244 }
245 out.push_str(" }");
246 }
247 ConstantData::Vector { elements, .. } => {
248 out.push('<');
249 for (i, &e) in elements.iter().enumerate() {
250 if i > 0 {
251 out.push_str(", ");
252 }
253 self.write_const_with_type(out, e);
254 }
255 out.push('>');
256 }
257 ConstantData::GlobalRef { name, .. } => {
258 write!(out, "@{}", name).unwrap();
259 }
260 }
261 }
262
263 fn write_typed_value(&self, out: &mut String, vref: ValueRef, func: &Function) {
269 let ty = self.type_of_vref(vref, func);
270 self.write_type(out, ty);
271 out.push(' ');
272 self.write_value(out, vref, func);
273 }
274
275 fn write_value(&self, out: &mut String, vref: ValueRef, func: &Function) {
276 match vref {
277 ValueRef::Instruction(id) => {
278 if let Some(ref name) = func.instr(id).name {
279 write!(out, "%{}", name).unwrap();
280 } else {
281 write!(out, "%v{}", id.0).unwrap();
282 }
283 }
284 ValueRef::Argument(id) => {
285 let arg = func.arg(id);
286 if arg.name.is_empty() {
287 write!(out, "%{}", id.0).unwrap();
288 } else {
289 write!(out, "%{}", arg.name).unwrap();
290 }
291 }
292 ValueRef::Constant(id) => self.write_const_value(out, id),
293 ValueRef::Global(id) => {
294 write!(out, "@g{}", id.0).unwrap();
295 }
296 }
297 }
298
299 fn type_of_vref(&self, vref: ValueRef, func: &Function) -> TypeId {
300 match vref {
301 ValueRef::Instruction(id) => func.instr(id).ty,
302 ValueRef::Argument(id) => func.arg(id).ty,
303 ValueRef::Constant(id) => self.ctx.type_of_const(id),
304 ValueRef::Global(_) => self.ctx.ptr_ty,
305 }
306 }
307
308 fn write_function(&self, out: &mut String, func: &Function) {
313 if func.is_declaration {
314 out.push_str("declare ");
315 } else {
316 out.push_str("define ");
317 }
318 let lk = func.linkage.as_str();
320 if !lk.is_empty() {
321 write!(out, "{} ", lk).unwrap();
322 }
323
324 if let crate::types::TypeData::Function(ft) = self.ctx.get_type(func.ty) {
326 let ret = ft.ret;
327 let params = ft.params.clone();
328 let variadic = ft.variadic;
329 self.write_type(out, ret);
330 write!(out, " @{}(", func.name).unwrap();
331 for (i, arg) in func.args.iter().enumerate() {
332 if i > 0 {
333 out.push_str(", ");
334 }
335 self.write_type(out, arg.ty);
336 if !arg.name.is_empty() {
337 write!(out, " %{}", arg.name).unwrap();
338 }
339 }
340 let n_printed = func.args.len();
342 if n_printed < params.len() {
343 for (i, ¶m_ty) in params.iter().enumerate().skip(n_printed) {
344 if i > 0 {
345 out.push_str(", ");
346 }
347 self.write_type(out, param_ty);
348 }
349 }
350 if variadic {
351 if !func.args.is_empty() || !params.is_empty() {
352 out.push_str(", ");
353 }
354 out.push_str("...");
355 }
356 } else {
357 panic!(
358 "printer: function '{}' has non-function type {:?}",
359 func.name,
360 self.ctx.get_type(func.ty)
361 );
362 }
363 out.push(')');
364
365 if func.is_declaration {
366 writeln!(out).unwrap();
367 return;
368 }
369
370 writeln!(out, " {{").unwrap();
371
372 for (bi, bb) in func.blocks.iter().enumerate() {
373 self.write_block(out, bb, func, BlockId(bi as u32));
374 }
375
376 writeln!(out, "}}").unwrap();
377 }
378
379 fn write_block(&self, out: &mut String, bb: &BasicBlock, func: &Function, _bid: BlockId) {
380 writeln!(out, "{}:", bb.name).unwrap();
381 for id in bb.instrs() {
382 self.write_instr(out, id, func);
383 }
384 }
385
386 fn write_instr(&self, out: &mut String, id: InstrId, func: &Function) {
387 let instr = func.instr(id);
388 out.push_str(" ");
389
390 if let Some(ref name) = instr.name {
392 if !name.is_empty() {
393 write!(out, "%{} = ", name).unwrap();
394 }
395 }
396
397 fn fmf_str(f: &FastMathFlags) -> String {
399 let mut s = String::new();
400 if f.fast {
401 s.push_str("fast ");
402 return s;
403 }
404 if f.nnan {
405 s.push_str("nnan ");
406 }
407 if f.ninf {
408 s.push_str("ninf ");
409 }
410 if f.nsz {
411 s.push_str("nsz ");
412 }
413 if f.arcp {
414 s.push_str("arcp ");
415 }
416 if f.contract {
417 s.push_str("contract ");
418 }
419 if f.afn {
420 s.push_str("afn ");
421 }
422 if f.reassoc {
423 s.push_str("reassoc ");
424 }
425 s
426 }
427
428 match &instr.kind {
429 InstrKind::Add { flags, lhs, rhs } => {
430 out.push_str("add ");
431 if flags.nuw {
432 out.push_str("nuw ");
433 }
434 if flags.nsw {
435 out.push_str("nsw ");
436 }
437 self.write_typed_value(out, *lhs, func);
438 out.push_str(", ");
439 self.write_value(out, *rhs, func);
440 }
441 InstrKind::Sub { flags, lhs, rhs } => {
442 out.push_str("sub ");
443 if flags.nuw {
444 out.push_str("nuw ");
445 }
446 if flags.nsw {
447 out.push_str("nsw ");
448 }
449 self.write_typed_value(out, *lhs, func);
450 out.push_str(", ");
451 self.write_value(out, *rhs, func);
452 }
453 InstrKind::Mul { flags, lhs, rhs } => {
454 out.push_str("mul ");
455 if flags.nuw {
456 out.push_str("nuw ");
457 }
458 if flags.nsw {
459 out.push_str("nsw ");
460 }
461 self.write_typed_value(out, *lhs, func);
462 out.push_str(", ");
463 self.write_value(out, *rhs, func);
464 }
465 InstrKind::UDiv { exact, lhs, rhs } => {
466 out.push_str("udiv ");
467 if *exact {
468 out.push_str("exact ");
469 }
470 self.write_typed_value(out, *lhs, func);
471 out.push_str(", ");
472 self.write_value(out, *rhs, func);
473 }
474 InstrKind::SDiv { exact, lhs, rhs } => {
475 out.push_str("sdiv ");
476 if *exact {
477 out.push_str("exact ");
478 }
479 self.write_typed_value(out, *lhs, func);
480 out.push_str(", ");
481 self.write_value(out, *rhs, func);
482 }
483 InstrKind::URem { lhs, rhs } => {
484 out.push_str("urem ");
485 self.write_typed_value(out, *lhs, func);
486 out.push_str(", ");
487 self.write_value(out, *rhs, func);
488 }
489 InstrKind::SRem { lhs, rhs } => {
490 out.push_str("srem ");
491 self.write_typed_value(out, *lhs, func);
492 out.push_str(", ");
493 self.write_value(out, *rhs, func);
494 }
495 InstrKind::And { lhs, rhs } => {
496 out.push_str("and ");
497 self.write_typed_value(out, *lhs, func);
498 out.push_str(", ");
499 self.write_value(out, *rhs, func);
500 }
501 InstrKind::Or { lhs, rhs } => {
502 out.push_str("or ");
503 self.write_typed_value(out, *lhs, func);
504 out.push_str(", ");
505 self.write_value(out, *rhs, func);
506 }
507 InstrKind::Xor { lhs, rhs } => {
508 out.push_str("xor ");
509 self.write_typed_value(out, *lhs, func);
510 out.push_str(", ");
511 self.write_value(out, *rhs, func);
512 }
513 InstrKind::Shl { flags, lhs, rhs } => {
514 out.push_str("shl ");
515 if flags.nuw {
516 out.push_str("nuw ");
517 }
518 if flags.nsw {
519 out.push_str("nsw ");
520 }
521 self.write_typed_value(out, *lhs, func);
522 out.push_str(", ");
523 self.write_value(out, *rhs, func);
524 }
525 InstrKind::LShr { exact, lhs, rhs } => {
526 out.push_str("lshr ");
527 if *exact {
528 out.push_str("exact ");
529 }
530 self.write_typed_value(out, *lhs, func);
531 out.push_str(", ");
532 self.write_value(out, *rhs, func);
533 }
534 InstrKind::AShr { exact, lhs, rhs } => {
535 out.push_str("ashr ");
536 if *exact {
537 out.push_str("exact ");
538 }
539 self.write_typed_value(out, *lhs, func);
540 out.push_str(", ");
541 self.write_value(out, *rhs, func);
542 }
543 InstrKind::FAdd { flags, lhs, rhs } => {
544 write!(out, "fadd {}", fmf_str(flags)).unwrap();
545 self.write_typed_value(out, *lhs, func);
546 out.push_str(", ");
547 self.write_value(out, *rhs, func);
548 }
549 InstrKind::FSub { flags, lhs, rhs } => {
550 write!(out, "fsub {}", fmf_str(flags)).unwrap();
551 self.write_typed_value(out, *lhs, func);
552 out.push_str(", ");
553 self.write_value(out, *rhs, func);
554 }
555 InstrKind::FMul { flags, lhs, rhs } => {
556 write!(out, "fmul {}", fmf_str(flags)).unwrap();
557 self.write_typed_value(out, *lhs, func);
558 out.push_str(", ");
559 self.write_value(out, *rhs, func);
560 }
561 InstrKind::FDiv { flags, lhs, rhs } => {
562 write!(out, "fdiv {}", fmf_str(flags)).unwrap();
563 self.write_typed_value(out, *lhs, func);
564 out.push_str(", ");
565 self.write_value(out, *rhs, func);
566 }
567 InstrKind::FRem { flags, lhs, rhs } => {
568 write!(out, "frem {}", fmf_str(flags)).unwrap();
569 self.write_typed_value(out, *lhs, func);
570 out.push_str(", ");
571 self.write_value(out, *rhs, func);
572 }
573 InstrKind::FNeg { flags, operand } => {
574 write!(out, "fneg {}", fmf_str(flags)).unwrap();
575 self.write_typed_value(out, *operand, func);
576 }
577 InstrKind::ICmp { pred, lhs, rhs } => {
578 write!(out, "icmp {} ", pred.as_str()).unwrap();
579 self.write_typed_value(out, *lhs, func);
580 out.push_str(", ");
581 self.write_value(out, *rhs, func);
582 }
583 InstrKind::FCmp {
584 flags,
585 pred,
586 lhs,
587 rhs,
588 } => {
589 write!(out, "fcmp {}{} ", fmf_str(flags), pred.as_str()).unwrap();
590 self.write_typed_value(out, *lhs, func);
591 out.push_str(", ");
592 self.write_value(out, *rhs, func);
593 }
594 InstrKind::Alloca {
595 alloc_ty,
596 num_elements,
597 align,
598 } => {
599 out.push_str("alloca ");
600 self.write_type(out, *alloc_ty);
601 if let Some(ne) = num_elements {
602 out.push_str(", ");
603 self.write_typed_value(out, *ne, func);
604 }
605 if let Some(a) = align {
606 write!(out, ", align {}", a).unwrap();
607 }
608 }
609 InstrKind::Load {
610 ty,
611 ptr,
612 align,
613 volatile,
614 } => {
615 out.push_str("load ");
616 if *volatile {
617 out.push_str("volatile ");
618 }
619 self.write_type(out, *ty);
620 out.push_str(", ");
621 self.write_typed_value(out, *ptr, func);
622 if let Some(a) = align {
623 write!(out, ", align {}", a).unwrap();
624 }
625 }
626 InstrKind::Store {
627 val,
628 ptr,
629 align,
630 volatile,
631 } => {
632 out.push_str("store ");
633 if *volatile {
634 out.push_str("volatile ");
635 }
636 self.write_typed_value(out, *val, func);
637 out.push_str(", ");
638 self.write_typed_value(out, *ptr, func);
639 if let Some(a) = align {
640 write!(out, ", align {}", a).unwrap();
641 }
642 }
643 InstrKind::GetElementPtr {
644 inbounds,
645 base_ty,
646 ptr,
647 indices,
648 } => {
649 out.push_str("getelementptr ");
650 if *inbounds {
651 out.push_str("inbounds ");
652 }
653 self.write_type(out, *base_ty);
654 out.push_str(", ");
655 self.write_typed_value(out, *ptr, func);
656 for idx in indices {
657 out.push_str(", ");
658 self.write_typed_value(out, *idx, func);
659 }
660 }
661 InstrKind::Trunc { val, to }
662 | InstrKind::ZExt { val, to }
663 | InstrKind::SExt { val, to }
664 | InstrKind::FPTrunc { val, to }
665 | InstrKind::FPExt { val, to }
666 | InstrKind::FPToUI { val, to }
667 | InstrKind::FPToSI { val, to }
668 | InstrKind::UIToFP { val, to }
669 | InstrKind::SIToFP { val, to }
670 | InstrKind::PtrToInt { val, to }
671 | InstrKind::IntToPtr { val, to }
672 | InstrKind::BitCast { val, to }
673 | InstrKind::AddrSpaceCast { val, to } => {
674 out.push_str(instr.kind.opcode());
675 out.push(' ');
676 self.write_typed_value(out, *val, func);
677 out.push_str(" to ");
678 self.write_type(out, *to);
679 }
680 InstrKind::Freeze { val } => {
681 out.push_str("freeze ");
682 self.write_typed_value(out, *val, func);
683 }
684 InstrKind::Select {
685 cond,
686 then_val,
687 else_val,
688 } => {
689 out.push_str("select ");
690 self.write_typed_value(out, *cond, func);
691 out.push_str(", ");
692 self.write_typed_value(out, *then_val, func);
693 out.push_str(", ");
694 self.write_typed_value(out, *else_val, func);
695 }
696 InstrKind::Phi { ty, incoming } => {
697 out.push_str("phi ");
698 self.write_type(out, *ty);
699 let inc = incoming.clone();
700 for (i, (val, block)) in inc.iter().enumerate() {
701 if i > 0 {
702 out.push_str(", ");
703 } else {
704 out.push(' ');
705 }
706 out.push_str("[ ");
707 self.write_value(out, *val, func);
708 out.push_str(", %");
709 out.push_str(&func.block(*block).name);
710 out.push_str(" ]");
711 }
712 }
713 InstrKind::ExtractValue { aggregate, indices } => {
714 out.push_str("extractvalue ");
715 self.write_typed_value(out, *aggregate, func);
716 for &i in indices {
717 write!(out, ", {}", i).unwrap();
718 }
719 }
720 InstrKind::InsertValue {
721 aggregate,
722 val,
723 indices,
724 } => {
725 out.push_str("insertvalue ");
726 self.write_typed_value(out, *aggregate, func);
727 out.push_str(", ");
728 self.write_typed_value(out, *val, func);
729 for &i in indices {
730 write!(out, ", {}", i).unwrap();
731 }
732 }
733 InstrKind::ExtractElement { vec, idx } => {
734 out.push_str("extractelement ");
735 self.write_typed_value(out, *vec, func);
736 out.push_str(", ");
737 self.write_typed_value(out, *idx, func);
738 }
739 InstrKind::InsertElement { vec, val, idx } => {
740 out.push_str("insertelement ");
741 self.write_typed_value(out, *vec, func);
742 out.push_str(", ");
743 self.write_typed_value(out, *val, func);
744 out.push_str(", ");
745 self.write_typed_value(out, *idx, func);
746 }
747 InstrKind::ShuffleVector { v1, v2, mask } => {
748 out.push_str("shufflevector ");
749 self.write_typed_value(out, *v1, func);
750 out.push_str(", ");
751 self.write_typed_value(out, *v2, func);
752 write!(out, ", <{} x i32> <", mask.len()).unwrap();
754 for (i, &m) in mask.iter().enumerate() {
755 if i > 0 {
756 out.push_str(", ");
757 }
758 write!(out, "i32 {}", m).unwrap();
759 }
760 out.push('>');
761 }
762 InstrKind::Call {
763 tail,
764 callee_ty,
765 callee,
766 args,
767 } => {
768 match tail {
769 crate::instruction::TailCallKind::Tail => out.push_str("tail "),
770 crate::instruction::TailCallKind::MustTail => out.push_str("musttail "),
771 crate::instruction::TailCallKind::NoTail => out.push_str("notail "),
772 crate::instruction::TailCallKind::None => {}
773 }
774 out.push_str("call ");
775 if let crate::types::TypeData::Function(ft) = self.ctx.get_type(*callee_ty) {
777 let ret = ft.ret;
778 self.write_type(out, ret);
779 out.push(' ');
780 }
781 self.write_value(out, *callee, func);
782 out.push('(');
783 let call_args = args.clone();
784 for (i, &arg) in call_args.iter().enumerate() {
785 if i > 0 {
786 out.push_str(", ");
787 }
788 self.write_typed_value(out, arg, func);
789 }
790 out.push(')');
791 }
792 InstrKind::Ret { val: None } => {
793 out.push_str("ret void");
794 }
795 InstrKind::Ret { val: Some(v) } => {
796 out.push_str("ret ");
797 self.write_typed_value(out, *v, func);
798 }
799 InstrKind::Br { dest } => {
800 write!(out, "br label %{}", func.block(*dest).name).unwrap();
801 }
802 InstrKind::CondBr {
803 cond,
804 then_dest,
805 else_dest,
806 } => {
807 out.push_str("br ");
808 self.write_typed_value(out, *cond, func);
809 write!(
810 out,
811 ", label %{}, label %{}",
812 func.block(*then_dest).name,
813 func.block(*else_dest).name
814 )
815 .unwrap();
816 }
817 InstrKind::Switch {
818 val,
819 default,
820 cases,
821 } => {
822 out.push_str("switch ");
823 self.write_typed_value(out, *val, func);
824 writeln!(out, ", label %{} [", func.block(*default).name).unwrap();
825 let sw_cases = cases.clone();
826 for (case_val, dest) in &sw_cases {
827 out.push_str(" ");
828 self.write_typed_value(out, *case_val, func);
829 writeln!(out, ", label %{}", func.block(*dest).name).unwrap();
830 }
831 out.push_str(" ]");
832 }
833 InstrKind::Unreachable => {
834 out.push_str("unreachable");
835 }
836 }
837
838 if let Some(attachments) = func.instr_metadata(id) {
839 for (key, value) in attachments {
840 write!(out, ", !{} {}", key, value).unwrap();
841 }
842 } else if let Some(loc_id) = func.instr_dbg_loc(id) {
843 write!(out, ", !dbg !{}", loc_id).unwrap();
844 }
845 writeln!(out).unwrap();
846 }
847}
848
849fn float_kind_str(kind: FloatKind) -> &'static str {
850 match kind {
851 FloatKind::Half => "half",
852 FloatKind::BFloat => "bfloat",
853 FloatKind::Single => "float",
854 FloatKind::Double => "double",
855 FloatKind::Fp128 => "fp128",
856 FloatKind::X86Fp80 => "x86_fp80",
857 }
858}
859
860#[cfg(test)]
861mod tests {
862 use super::*;
863 use crate::basic_block::BasicBlock;
864 use crate::context::Context;
865 use crate::function::Function;
866 use crate::instruction::{InstrKind, Instruction, IntArithFlags};
867 use crate::module::Module;
868 use crate::value::Linkage;
869
870 #[test]
871 fn print_simple_function() {
872 let mut ctx = Context::new();
873 let fn_ty = ctx.mk_fn_type(ctx.i32_ty, vec![ctx.i32_ty, ctx.i32_ty], false);
874 let args = vec![
875 crate::value::Argument {
876 name: "a".into(),
877 ty: ctx.i32_ty,
878 index: 0,
879 },
880 crate::value::Argument {
881 name: "b".into(),
882 ty: ctx.i32_ty,
883 index: 1,
884 },
885 ];
886 let mut func = Function::new("add", fn_ty, args, Linkage::External);
887
888 let a_ref = ValueRef::Argument(crate::context::ArgId(0));
889 let b_ref = ValueRef::Argument(crate::context::ArgId(1));
890
891 let mut bb = BasicBlock::new("entry");
892 let add_instr = Instruction::new(
893 Some("result".into()),
894 ctx.i32_ty,
895 InstrKind::Add {
896 flags: IntArithFlags::default(),
897 lhs: a_ref,
898 rhs: b_ref,
899 },
900 );
901 let iid = func.alloc_instr(add_instr);
902 bb.append_instr(iid);
903
904 let ret_instr = Instruction::new(
905 None,
906 ctx.void_ty,
907 InstrKind::Ret {
908 val: Some(ValueRef::Instruction(iid)),
909 },
910 );
911 let rid = func.alloc_instr(ret_instr);
912 bb.set_terminator(rid);
913
914 let _bid = func.add_block(bb);
915
916 let mut module = Module::new("test");
917 module.add_function(func);
918
919 let printer = Printer::new(&ctx);
920 let output = printer.print_module(&module);
921 assert!(output.contains("define i32 @add("));
922 assert!(output.contains("%result = add i32 %a, %b"));
923 assert!(output.contains("ret i32 %result"));
924 }
925}