]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_codegen_cranelift/src/pretty_clif.rs
New upstream version 1.51.0+dfsg1
[rustc.git] / compiler / rustc_codegen_cranelift / src / pretty_clif.rs
CommitLineData
29967ef6
XL
1//! This module provides the [CommentWriter] which makes it possible
2//! to add comments to the written cranelift ir.
3//!
4//! # Example
5//!
6//! ```clif
7//! test compile
8//! target x86_64
9//!
10//! function u0:0(i64, i64, i64) system_v {
11//! ; symbol _ZN119_$LT$example..IsNotEmpty$u20$as$u20$mini_core..FnOnce$LT$$LP$$RF$$u27$a$u20$$RF$$u27$b$u20$$u5b$u16$u5d$$C$$RP$$GT$$GT$9call_once17he85059d5e6a760a0E
12//! ; instance Instance { def: Item(DefId(0/0:29 ~ example[8787]::{{impl}}[0]::call_once[0])), substs: [ReErased, ReErased] }
13//! ; sig ([IsNotEmpty, (&&[u16],)]; c_variadic: false)->(u8, u8)
14//!
15//! ; ssa {_2: NOT_SSA, _4: NOT_SSA, _0: NOT_SSA, _3: (empty), _1: NOT_SSA}
16//! ; msg loc.idx param pass mode ssa flags ty
17//! ; ret _0 = v0 ByRef NOT_SSA (u8, u8)
18//! ; arg _1 = v1 ByRef NOT_SSA IsNotEmpty
19//! ; arg _2.0 = v2 ByVal(types::I64) NOT_SSA &&[u16]
20//!
21//! ss0 = explicit_slot 0 ; _1: IsNotEmpty size=0 align=1,8
22//! ss1 = explicit_slot 8 ; _2: (&&[u16],) size=8 align=8,8
23//! ss2 = explicit_slot 8 ; _4: (&&[u16],) size=8 align=8,8
24//! sig0 = (i64, i64, i64) system_v
25//! sig1 = (i64, i64, i64) system_v
26//! fn0 = colocated u0:6 sig1 ; Instance { def: Item(DefId(0/0:31 ~ example[8787]::{{impl}}[1]::call_mut[0])), substs: [ReErased, ReErased] }
27//!
28//! block0(v0: i64, v1: i64, v2: i64):
29//! v3 = stack_addr.i64 ss0
30//! v4 = stack_addr.i64 ss1
31//! store v2, v4
32//! v5 = stack_addr.i64 ss2
33//! jump block1
34//!
35//! block1:
36//! nop
37//! ; _3 = &mut _1
38//! ; _4 = _2
39//! v6 = load.i64 v4
40//! store v6, v5
41//! ;
42//! ; _0 = const mini_core::FnMut::call_mut(move _3, move _4)
43//! v7 = load.i64 v5
44//! call fn0(v0, v3, v7)
45//! jump block2
46//!
47//! block2:
48//! nop
49//! ;
50//! ; return
51//! return
52//! }
53//! ```
54
55use std::fmt;
5869c6ff 56use std::io::Write;
29967ef6
XL
57
58use cranelift_codegen::{
59 entity::SecondaryMap,
60 ir::{entities::AnyEntity, function::DisplayFunctionAnnotations},
61 write::{FuncWriter, PlainWriter},
62};
63
5869c6ff 64use rustc_middle::ty::layout::FnAbiExt;
29967ef6 65use rustc_session::config::OutputType;
5869c6ff 66use rustc_target::abi::call::FnAbi;
29967ef6
XL
67
68use crate::prelude::*;
69
70#[derive(Debug)]
71pub(crate) struct CommentWriter {
72 global_comments: Vec<String>,
73 entity_comments: FxHashMap<AnyEntity, String>,
74}
75
76impl CommentWriter {
77 pub(crate) fn new<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self {
78 let global_comments = if cfg!(debug_assertions) {
79 vec![
80 format!("symbol {}", tcx.symbol_name(instance).name),
81 format!("instance {:?}", instance),
82 format!(
5869c6ff
XL
83 "abi {:?}",
84 FnAbi::of_instance(&RevealAllLayoutCx(tcx), instance, &[])
29967ef6
XL
85 ),
86 String::new(),
87 ]
88 } else {
89 vec![]
90 };
91
92 CommentWriter {
93 global_comments,
94 entity_comments: FxHashMap::default(),
95 }
96 }
97}
98
99#[cfg(debug_assertions)]
100impl CommentWriter {
101 pub(crate) fn add_global_comment<S: Into<String>>(&mut self, comment: S) {
102 self.global_comments.push(comment.into());
103 }
104
105 pub(crate) fn add_comment<S: Into<String> + AsRef<str>, E: Into<AnyEntity>>(
106 &mut self,
107 entity: E,
108 comment: S,
109 ) {
110 use std::collections::hash_map::Entry;
111 match self.entity_comments.entry(entity.into()) {
112 Entry::Occupied(mut occ) => {
113 occ.get_mut().push('\n');
114 occ.get_mut().push_str(comment.as_ref());
115 }
116 Entry::Vacant(vac) => {
117 vac.insert(comment.into());
118 }
119 }
120 }
121}
122
123impl FuncWriter for &'_ CommentWriter {
124 fn write_preamble(
125 &mut self,
126 w: &mut dyn fmt::Write,
127 func: &Function,
128 reg_info: Option<&isa::RegInfo>,
129 ) -> Result<bool, fmt::Error> {
130 for comment in &self.global_comments {
131 if !comment.is_empty() {
132 writeln!(w, "; {}", comment)?;
133 } else {
134 writeln!(w)?;
135 }
136 }
137 if !self.global_comments.is_empty() {
138 writeln!(w)?;
139 }
140
141 self.super_preamble(w, func, reg_info)
142 }
143
144 fn write_entity_definition(
145 &mut self,
146 w: &mut dyn fmt::Write,
147 _func: &Function,
148 entity: AnyEntity,
149 value: &dyn fmt::Display,
150 ) -> fmt::Result {
151 write!(w, " {} = {}", entity, value)?;
152
153 if let Some(comment) = self.entity_comments.get(&entity) {
154 writeln!(w, " ; {}", comment.replace('\n', "\n; "))
155 } else {
156 writeln!(w)
157 }
158 }
159
160 fn write_block_header(
161 &mut self,
162 w: &mut dyn fmt::Write,
163 func: &Function,
164 isa: Option<&dyn isa::TargetIsa>,
165 block: Block,
166 indent: usize,
167 ) -> fmt::Result {
168 PlainWriter.write_block_header(w, func, isa, block, indent)
169 }
170
171 fn write_instruction(
172 &mut self,
173 w: &mut dyn fmt::Write,
174 func: &Function,
175 aliases: &SecondaryMap<Value, Vec<Value>>,
176 isa: Option<&dyn isa::TargetIsa>,
177 inst: Inst,
178 indent: usize,
179 ) -> fmt::Result {
180 PlainWriter.write_instruction(w, func, aliases, isa, inst, indent)?;
181 if let Some(comment) = self.entity_comments.get(&inst.into()) {
182 writeln!(w, "; {}", comment.replace('\n', "\n; "))?;
183 }
184 Ok(())
185 }
186}
187
188#[cfg(debug_assertions)]
189impl<M: Module> FunctionCx<'_, '_, M> {
190 pub(crate) fn add_global_comment<S: Into<String>>(&mut self, comment: S) {
191 self.clif_comments.add_global_comment(comment);
192 }
193
194 pub(crate) fn add_comment<S: Into<String> + AsRef<str>, E: Into<AnyEntity>>(
195 &mut self,
196 entity: E,
197 comment: S,
198 ) {
199 self.clif_comments.add_comment(entity, comment);
200 }
201}
202
5869c6ff
XL
203pub(crate) fn should_write_ir(tcx: TyCtxt<'_>) -> bool {
204 cfg!(debug_assertions)
205 || tcx
29967ef6
XL
206 .sess
207 .opts
208 .output_types
209 .contains_key(&OutputType::LlvmAssembly)
5869c6ff
XL
210}
211
212pub(crate) fn write_ir_file<'tcx>(
213 tcx: TyCtxt<'tcx>,
214 name: &str,
215 write: impl FnOnce(&mut dyn Write) -> std::io::Result<()>,
216) {
217 if !should_write_ir(tcx) {
29967ef6
XL
218 return;
219 }
220
29967ef6
XL
221 let clif_output_dir = tcx.output_filenames(LOCAL_CRATE).with_extension("clif");
222
223 match std::fs::create_dir(&clif_output_dir) {
224 Ok(()) => {}
225 Err(err) if err.kind() == std::io::ErrorKind::AlreadyExists => {}
226 res @ Err(_) => res.unwrap(),
227 }
228
5869c6ff 229 let clif_file_name = clif_output_dir.join(name);
29967ef6
XL
230
231 let res: std::io::Result<()> = try {
232 let mut file = std::fs::File::create(clif_file_name)?;
5869c6ff 233 write(&mut file)?;
29967ef6
XL
234 };
235 if let Err(err) = res {
5869c6ff 236 tcx.sess.warn(&format!("error writing ir file: {}", err));
29967ef6
XL
237 }
238}
239
5869c6ff
XL
240pub(crate) fn write_clif_file<'tcx>(
241 tcx: TyCtxt<'tcx>,
242 postfix: &str,
243 isa: Option<&dyn cranelift_codegen::isa::TargetIsa>,
244 instance: Instance<'tcx>,
245 context: &cranelift_codegen::Context,
246 mut clif_comments: &CommentWriter,
247) {
248 write_ir_file(
249 tcx,
250 &format!("{}.{}.clif", tcx.symbol_name(instance).name, postfix),
251 |file| {
252 let value_ranges = isa.map(|isa| {
253 context
254 .build_value_labels_ranges(isa)
255 .expect("value location ranges")
256 });
257
258 let mut clif = String::new();
259 cranelift_codegen::write::decorate_function(
260 &mut clif_comments,
261 &mut clif,
262 &context.func,
263 &DisplayFunctionAnnotations {
264 isa: Some(&*crate::build_isa(tcx.sess)),
265 value_ranges: value_ranges.as_ref(),
266 },
267 )
268 .unwrap();
269
270 writeln!(file, "test compile")?;
271 writeln!(file, "set is_pic")?;
272 writeln!(file, "set enable_simd")?;
273 writeln!(file, "target {} haswell", crate::target_triple(tcx.sess))?;
274 writeln!(file)?;
275 file.write_all(clif.as_bytes())?;
276 Ok(())
277 },
278 );
279}
280
29967ef6
XL
281impl<M: Module> fmt::Debug for FunctionCx<'_, '_, M> {
282 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
283 writeln!(f, "{:?}", self.instance.substs)?;
284 writeln!(f, "{:?}", self.local_map)?;
285
286 let mut clif = String::new();
287 ::cranelift_codegen::write::decorate_function(
288 &mut &self.clif_comments,
289 &mut clif,
290 &self.bcx.func,
291 &DisplayFunctionAnnotations::default(),
292 )
293 .unwrap();
294 writeln!(f, "\n{}", clif)
295 }
296}