/rust/registry/src/index.crates.io-1949cf8c6b5b557f/cranelift-codegen-0.128.3/src/ir/function.rs
Line | Count | Source |
1 | | //! Intermediate representation of a function. |
2 | | //! |
3 | | //! The `Function` struct defined in this module owns all of its basic blocks and |
4 | | //! instructions. |
5 | | |
6 | | use crate::HashMap; |
7 | | use crate::entity::{PrimaryMap, SecondaryMap}; |
8 | | use crate::ir::DebugTags; |
9 | | use crate::ir::{ |
10 | | self, Block, DataFlowGraph, DynamicStackSlot, DynamicStackSlotData, DynamicStackSlots, |
11 | | DynamicType, ExtFuncData, FuncRef, GlobalValue, GlobalValueData, Inst, JumpTable, |
12 | | JumpTableData, Layout, MemoryType, MemoryTypeData, SigRef, Signature, SourceLocs, StackSlot, |
13 | | StackSlotData, StackSlots, Type, pcc::Fact, |
14 | | }; |
15 | | use crate::isa::CallConv; |
16 | | use crate::write::{write_function, write_function_spec}; |
17 | | #[cfg(feature = "enable-serde")] |
18 | | use alloc::string::String; |
19 | | use core::fmt; |
20 | | |
21 | | #[cfg(feature = "enable-serde")] |
22 | | use serde::de::{Deserializer, Error}; |
23 | | #[cfg(feature = "enable-serde")] |
24 | | use serde::ser::Serializer; |
25 | | #[cfg(feature = "enable-serde")] |
26 | | use serde::{Deserialize, Serialize}; |
27 | | |
28 | | use super::entities::UserExternalNameRef; |
29 | | use super::extname::UserFuncName; |
30 | | use super::{RelSourceLoc, SourceLoc, UserExternalName}; |
31 | | |
32 | | /// A version marker used to ensure that serialized clif ir is never deserialized with a |
33 | | /// different version of Cranelift. |
34 | | #[derive(Default, Copy, Clone, Debug, PartialEq, Hash)] |
35 | | pub struct VersionMarker; |
36 | | |
37 | | #[cfg(feature = "enable-serde")] |
38 | | impl Serialize for VersionMarker { |
39 | | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
40 | | where |
41 | | S: Serializer, |
42 | | { |
43 | | crate::VERSION.serialize(serializer) |
44 | | } |
45 | | } |
46 | | |
47 | | #[cfg(feature = "enable-serde")] |
48 | | impl<'de> Deserialize<'de> for VersionMarker { |
49 | | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
50 | | where |
51 | | D: Deserializer<'de>, |
52 | | { |
53 | | let version = String::deserialize(deserializer)?; |
54 | | if version != crate::VERSION { |
55 | | return Err(D::Error::custom(&format!( |
56 | | "Expected a clif ir function for version {}, found one for version {}", |
57 | | crate::VERSION, |
58 | | version, |
59 | | ))); |
60 | | } |
61 | | Ok(VersionMarker) |
62 | | } |
63 | | } |
64 | | |
65 | | /// Function parameters used when creating this function, and that will become applied after |
66 | | /// compilation to materialize the final `CompiledCode`. |
67 | | #[derive(Clone, PartialEq)] |
68 | | #[cfg_attr( |
69 | | feature = "enable-serde", |
70 | | derive(serde_derive::Serialize, serde_derive::Deserialize) |
71 | | )] |
72 | | pub struct FunctionParameters { |
73 | | /// The first `SourceLoc` appearing in the function, serving as a base for every relative |
74 | | /// source loc in the function. |
75 | | base_srcloc: Option<SourceLoc>, |
76 | | |
77 | | /// External user-defined function references. |
78 | | user_named_funcs: PrimaryMap<UserExternalNameRef, UserExternalName>, |
79 | | |
80 | | /// Inverted mapping of `user_named_funcs`, to deduplicate internally. |
81 | | user_ext_name_to_ref: HashMap<UserExternalName, UserExternalNameRef>, |
82 | | } |
83 | | |
84 | | impl FunctionParameters { |
85 | | /// Creates a new `FunctionParameters` with the given name. |
86 | 629k | pub fn new() -> Self { |
87 | 629k | Self { |
88 | 629k | base_srcloc: None, |
89 | 629k | user_named_funcs: Default::default(), |
90 | 629k | user_ext_name_to_ref: Default::default(), |
91 | 629k | } |
92 | 629k | } <cranelift_codegen::ir::function::FunctionParameters>::new Line | Count | Source | 86 | 157k | pub fn new() -> Self { | 87 | 157k | Self { | 88 | 157k | base_srcloc: None, | 89 | 157k | user_named_funcs: Default::default(), | 90 | 157k | user_ext_name_to_ref: Default::default(), | 91 | 157k | } | 92 | 157k | } |
<cranelift_codegen::ir::function::FunctionParameters>::new Line | Count | Source | 86 | 472k | pub fn new() -> Self { | 87 | 472k | Self { | 88 | 472k | base_srcloc: None, | 89 | 472k | user_named_funcs: Default::default(), | 90 | 472k | user_ext_name_to_ref: Default::default(), | 91 | 472k | } | 92 | 472k | } |
|
93 | | |
94 | | /// Returns the base `SourceLoc`. |
95 | | /// |
96 | | /// If it was never explicitly set with `ensure_base_srcloc`, will return an invalid |
97 | | /// `SourceLoc`. |
98 | 2.04M | pub fn base_srcloc(&self) -> SourceLoc { |
99 | 2.04M | self.base_srcloc.unwrap_or_default() |
100 | 2.04M | } <cranelift_codegen::ir::function::FunctionParameters>::base_srcloc Line | Count | Source | 98 | 209k | pub fn base_srcloc(&self) -> SourceLoc { | 99 | 209k | self.base_srcloc.unwrap_or_default() | 100 | 209k | } |
<cranelift_codegen::ir::function::FunctionParameters>::base_srcloc Line | Count | Source | 98 | 1.83M | pub fn base_srcloc(&self) -> SourceLoc { | 99 | 1.83M | self.base_srcloc.unwrap_or_default() | 100 | 1.83M | } |
|
101 | | |
102 | | /// Sets the base `SourceLoc`, if not set yet, and returns the base value. |
103 | 19.2M | pub fn ensure_base_srcloc(&mut self, srcloc: SourceLoc) -> SourceLoc { |
104 | 19.2M | match self.base_srcloc { |
105 | 19.0M | Some(val) => val, |
106 | | None => { |
107 | 231k | self.base_srcloc = Some(srcloc); |
108 | 231k | srcloc |
109 | | } |
110 | | } |
111 | 19.2M | } <cranelift_codegen::ir::function::FunctionParameters>::ensure_base_srcloc Line | Count | Source | 103 | 1.78M | pub fn ensure_base_srcloc(&mut self, srcloc: SourceLoc) -> SourceLoc { | 104 | 1.78M | match self.base_srcloc { | 105 | 1.74M | Some(val) => val, | 106 | | None => { | 107 | 35.6k | self.base_srcloc = Some(srcloc); | 108 | 35.6k | srcloc | 109 | | } | 110 | | } | 111 | 1.78M | } |
<cranelift_codegen::ir::function::FunctionParameters>::ensure_base_srcloc Line | Count | Source | 103 | 17.4M | pub fn ensure_base_srcloc(&mut self, srcloc: SourceLoc) -> SourceLoc { | 104 | 17.4M | match self.base_srcloc { | 105 | 17.2M | Some(val) => val, | 106 | | None => { | 107 | 195k | self.base_srcloc = Some(srcloc); | 108 | 195k | srcloc | 109 | | } | 110 | | } | 111 | 17.4M | } |
|
112 | | |
113 | | /// Retrieve a `UserExternalNameRef` for the given name, or add a new one. |
114 | | /// |
115 | | /// This method internally deduplicates same `UserExternalName` so they map to the same |
116 | | /// reference. |
117 | 236k | pub fn ensure_user_func_name(&mut self, name: UserExternalName) -> UserExternalNameRef { |
118 | 236k | if let Some(reff) = self.user_ext_name_to_ref.get(&name) { |
119 | 1.18k | *reff |
120 | | } else { |
121 | 235k | let reff = self.user_named_funcs.push(name.clone()); |
122 | 235k | self.user_ext_name_to_ref.insert(name, reff); |
123 | 235k | reff |
124 | | } |
125 | 236k | } <cranelift_codegen::ir::function::FunctionParameters>::ensure_user_func_name Line | Count | Source | 117 | 36.5k | pub fn ensure_user_func_name(&mut self, name: UserExternalName) -> UserExternalNameRef { | 118 | 36.5k | if let Some(reff) = self.user_ext_name_to_ref.get(&name) { | 119 | 472 | *reff | 120 | | } else { | 121 | 36.0k | let reff = self.user_named_funcs.push(name.clone()); | 122 | 36.0k | self.user_ext_name_to_ref.insert(name, reff); | 123 | 36.0k | reff | 124 | | } | 125 | 36.5k | } |
<cranelift_codegen::ir::function::FunctionParameters>::ensure_user_func_name Line | Count | Source | 117 | 200k | pub fn ensure_user_func_name(&mut self, name: UserExternalName) -> UserExternalNameRef { | 118 | 200k | if let Some(reff) = self.user_ext_name_to_ref.get(&name) { | 119 | 712 | *reff | 120 | | } else { | 121 | 199k | let reff = self.user_named_funcs.push(name.clone()); | 122 | 199k | self.user_ext_name_to_ref.insert(name, reff); | 123 | 199k | reff | 124 | | } | 125 | 200k | } |
|
126 | | |
127 | | /// Resets an already existing user function name to a new value. |
128 | 0 | pub fn reset_user_func_name(&mut self, index: UserExternalNameRef, name: UserExternalName) { |
129 | 0 | if let Some(prev_name) = self.user_named_funcs.get_mut(index) { |
130 | 0 | self.user_ext_name_to_ref.remove(prev_name); |
131 | 0 | *prev_name = name.clone(); |
132 | 0 | self.user_ext_name_to_ref.insert(name, index); |
133 | 0 | } |
134 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionParameters>::reset_user_func_name Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionParameters>::reset_user_func_name |
135 | | |
136 | | /// Returns the internal mapping of `UserExternalNameRef` to `UserExternalName`. |
137 | 693k | pub fn user_named_funcs(&self) -> &PrimaryMap<UserExternalNameRef, UserExternalName> { |
138 | 693k | &self.user_named_funcs |
139 | 693k | } <cranelift_codegen::ir::function::FunctionParameters>::user_named_funcs Line | Count | Source | 137 | 107k | pub fn user_named_funcs(&self) -> &PrimaryMap<UserExternalNameRef, UserExternalName> { | 138 | 107k | &self.user_named_funcs | 139 | 107k | } |
<cranelift_codegen::ir::function::FunctionParameters>::user_named_funcs Line | Count | Source | 137 | 586k | pub fn user_named_funcs(&self) -> &PrimaryMap<UserExternalNameRef, UserExternalName> { | 138 | 586k | &self.user_named_funcs | 139 | 586k | } |
|
140 | | |
141 | 0 | fn clear(&mut self) { |
142 | 0 | self.base_srcloc = None; |
143 | 0 | self.user_named_funcs.clear(); |
144 | 0 | self.user_ext_name_to_ref.clear(); |
145 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionParameters>::clear Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionParameters>::clear |
146 | | } |
147 | | |
148 | | /// Function fields needed when compiling a function. |
149 | | /// |
150 | | /// Additionally, these fields can be the same for two functions that would be compiled the same |
151 | | /// way, and finalized by applying `FunctionParameters` onto their `CompiledCodeStencil`. |
152 | | #[derive(Clone, PartialEq, Hash)] |
153 | | #[cfg_attr( |
154 | | feature = "enable-serde", |
155 | | derive(serde_derive::Serialize, serde_derive::Deserialize) |
156 | | )] |
157 | | pub struct FunctionStencil { |
158 | | /// A version marker used to ensure that serialized clif ir is never deserialized with a |
159 | | /// different version of Cranelift. |
160 | | // Note: This must be the first field to ensure that Serde will deserialize it before |
161 | | // attempting to deserialize other fields that are potentially changed between versions. |
162 | | pub version_marker: VersionMarker, |
163 | | |
164 | | /// Signature of this function. |
165 | | pub signature: Signature, |
166 | | |
167 | | /// Sized stack slots allocated in this function. |
168 | | pub sized_stack_slots: StackSlots, |
169 | | |
170 | | /// Dynamic stack slots allocated in this function. |
171 | | pub dynamic_stack_slots: DynamicStackSlots, |
172 | | |
173 | | /// Global values referenced. |
174 | | pub global_values: PrimaryMap<ir::GlobalValue, ir::GlobalValueData>, |
175 | | |
176 | | /// Global value proof-carrying-code facts. |
177 | | pub global_value_facts: SecondaryMap<ir::GlobalValue, Option<Fact>>, |
178 | | |
179 | | /// Memory types for proof-carrying code. |
180 | | pub memory_types: PrimaryMap<ir::MemoryType, ir::MemoryTypeData>, |
181 | | |
182 | | /// Data flow graph containing the primary definition of all instructions, blocks and values. |
183 | | pub dfg: DataFlowGraph, |
184 | | |
185 | | /// Layout of blocks and instructions in the function body. |
186 | | pub layout: Layout, |
187 | | |
188 | | /// Source locations. |
189 | | /// |
190 | | /// Track the original source location for each instruction. The source locations are not |
191 | | /// interpreted by Cranelift, only preserved. |
192 | | pub srclocs: SourceLocs, |
193 | | |
194 | | /// Opaque debug-info tags on sequence-point and call |
195 | | /// instructions. |
196 | | /// |
197 | | /// These tags are not interpreted by Cranelift, and are passed |
198 | | /// through to compilation-result metadata. The only semantic |
199 | | /// structure that Cranelift imposes is that when inlining, it |
200 | | /// prepends the callsite call instruction's tags to the tags on |
201 | | /// inlined instructions. |
202 | | /// |
203 | | /// In order to ensure clarity around guaranteed compiler |
204 | | /// behavior, tags are only permitted on instructions whose |
205 | | /// presence and sequence will remain the same in the compiled |
206 | | /// output: namely, `sequence_point` instructions and ordinary |
207 | | /// call instructions. |
208 | | pub debug_tags: DebugTags, |
209 | | |
210 | | /// An optional global value which represents an expression evaluating to |
211 | | /// the stack limit for this function. This `GlobalValue` will be |
212 | | /// interpreted in the prologue, if necessary, to insert a stack check to |
213 | | /// ensure that a trap happens if the stack pointer goes below the |
214 | | /// threshold specified here. |
215 | | pub stack_limit: Option<ir::GlobalValue>, |
216 | | } |
217 | | |
218 | | impl FunctionStencil { |
219 | 0 | fn clear(&mut self) { |
220 | 0 | self.signature.clear(CallConv::Fast); |
221 | 0 | self.sized_stack_slots.clear(); |
222 | 0 | self.dynamic_stack_slots.clear(); |
223 | 0 | self.global_values.clear(); |
224 | 0 | self.global_value_facts.clear(); |
225 | 0 | self.memory_types.clear(); |
226 | 0 | self.dfg.clear(); |
227 | 0 | self.layout.clear(); |
228 | 0 | self.srclocs.clear(); |
229 | 0 | self.debug_tags.clear(); |
230 | 0 | self.stack_limit = None; |
231 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::clear Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::clear |
232 | | |
233 | | /// Creates a jump table in the function, to be used by `br_table` instructions. |
234 | 1.22k | pub fn create_jump_table(&mut self, data: JumpTableData) -> JumpTable { |
235 | 1.22k | self.dfg.jump_tables.push(data) |
236 | 1.22k | } <cranelift_codegen::ir::function::FunctionStencil>::create_jump_table Line | Count | Source | 234 | 106 | pub fn create_jump_table(&mut self, data: JumpTableData) -> JumpTable { | 235 | 106 | self.dfg.jump_tables.push(data) | 236 | 106 | } |
<cranelift_codegen::ir::function::FunctionStencil>::create_jump_table Line | Count | Source | 234 | 1.12k | pub fn create_jump_table(&mut self, data: JumpTableData) -> JumpTable { | 235 | 1.12k | self.dfg.jump_tables.push(data) | 236 | 1.12k | } |
|
237 | | |
238 | | /// Creates a sized stack slot in the function, to be used by `stack_load`, `stack_store` |
239 | | /// and `stack_addr` instructions. |
240 | 0 | pub fn create_sized_stack_slot(&mut self, data: StackSlotData) -> StackSlot { |
241 | 0 | self.sized_stack_slots.push(data) |
242 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::create_sized_stack_slot Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::create_sized_stack_slot |
243 | | |
244 | | /// Creates a dynamic stack slot in the function, to be used by `dynamic_stack_load`, |
245 | | /// `dynamic_stack_store` and `dynamic_stack_addr` instructions. |
246 | 0 | pub fn create_dynamic_stack_slot(&mut self, data: DynamicStackSlotData) -> DynamicStackSlot { |
247 | 0 | self.dynamic_stack_slots.push(data) |
248 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::create_dynamic_stack_slot Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::create_dynamic_stack_slot |
249 | | |
250 | | /// Adds a signature which can later be used to declare an external function import. |
251 | 247k | pub fn import_signature(&mut self, signature: Signature) -> SigRef { |
252 | 247k | self.dfg.signatures.push(signature) |
253 | 247k | } <cranelift_codegen::ir::function::FunctionStencil>::import_signature Line | Count | Source | 251 | 65.1k | pub fn import_signature(&mut self, signature: Signature) -> SigRef { | 252 | 65.1k | self.dfg.signatures.push(signature) | 253 | 65.1k | } |
<cranelift_codegen::ir::function::FunctionStencil>::import_signature Line | Count | Source | 251 | 182k | pub fn import_signature(&mut self, signature: Signature) -> SigRef { | 252 | 182k | self.dfg.signatures.push(signature) | 253 | 182k | } |
|
254 | | |
255 | | /// Declares a global value accessible to the function. |
256 | 160k | pub fn create_global_value(&mut self, data: GlobalValueData) -> GlobalValue { |
257 | 160k | self.global_values.push(data) |
258 | 160k | } <cranelift_codegen::ir::function::FunctionStencil>::create_global_value Line | Count | Source | 256 | 11.4k | pub fn create_global_value(&mut self, data: GlobalValueData) -> GlobalValue { | 257 | 11.4k | self.global_values.push(data) | 258 | 11.4k | } |
<cranelift_codegen::ir::function::FunctionStencil>::create_global_value Line | Count | Source | 256 | 148k | pub fn create_global_value(&mut self, data: GlobalValueData) -> GlobalValue { | 257 | 148k | self.global_values.push(data) | 258 | 148k | } |
|
259 | | |
260 | | /// Declares a memory type for use by the function. |
261 | 0 | pub fn create_memory_type(&mut self, data: MemoryTypeData) -> MemoryType { |
262 | 0 | self.memory_types.push(data) |
263 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::create_memory_type Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::create_memory_type |
264 | | |
265 | | /// Find the global dyn_scale value associated with given DynamicType. |
266 | 0 | pub fn get_dyn_scale(&self, ty: DynamicType) -> GlobalValue { |
267 | 0 | self.dfg.dynamic_types.get(ty).unwrap().dynamic_scale |
268 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::get_dyn_scale Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::get_dyn_scale |
269 | | |
270 | | /// Find the global dyn_scale for the given stack slot. |
271 | 0 | pub fn get_dynamic_slot_scale(&self, dss: DynamicStackSlot) -> GlobalValue { |
272 | 0 | let dyn_ty = self.dynamic_stack_slots.get(dss).unwrap().dyn_ty; |
273 | 0 | self.get_dyn_scale(dyn_ty) |
274 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::get_dynamic_slot_scale Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::get_dynamic_slot_scale |
275 | | |
276 | | /// Get a concrete `Type` from a user defined `DynamicType`. |
277 | 0 | pub fn get_concrete_dynamic_ty(&self, ty: DynamicType) -> Option<Type> { |
278 | 0 | self.dfg |
279 | 0 | .dynamic_types |
280 | 0 | .get(ty) |
281 | 0 | .unwrap_or_else(|| panic!("Undeclared dynamic vector type: {ty}"))Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::get_concrete_dynamic_ty::{closure#0}Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::get_concrete_dynamic_ty::{closure#0} |
282 | 0 | .concrete() |
283 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::get_concrete_dynamic_ty Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::get_concrete_dynamic_ty |
284 | | |
285 | | /// Find a presumed unique special-purpose function parameter value. |
286 | | /// |
287 | | /// Returns the value of the last `purpose` parameter, or `None` if no such parameter exists. |
288 | 2.30M | pub fn special_param(&self, purpose: ir::ArgumentPurpose) -> Option<ir::Value> { |
289 | 2.30M | let entry = self.layout.entry_block().expect("Function is empty"); |
290 | 2.30M | self.signature |
291 | 2.30M | .special_param_index(purpose) |
292 | 2.30M | .map(|i| self.dfg.block_params(entry)[i]) <cranelift_codegen::ir::function::FunctionStencil>::special_param::{closure#0}Line | Count | Source | 292 | 172k | .map(|i| self.dfg.block_params(entry)[i]) |
<cranelift_codegen::ir::function::FunctionStencil>::special_param::{closure#0}Line | Count | Source | 292 | 2.12M | .map(|i| self.dfg.block_params(entry)[i]) |
|
293 | 2.30M | } <cranelift_codegen::ir::function::FunctionStencil>::special_param Line | Count | Source | 288 | 172k | pub fn special_param(&self, purpose: ir::ArgumentPurpose) -> Option<ir::Value> { | 289 | 172k | let entry = self.layout.entry_block().expect("Function is empty"); | 290 | 172k | self.signature | 291 | 172k | .special_param_index(purpose) | 292 | 172k | .map(|i| self.dfg.block_params(entry)[i]) | 293 | 172k | } |
<cranelift_codegen::ir::function::FunctionStencil>::special_param Line | Count | Source | 288 | 2.12M | pub fn special_param(&self, purpose: ir::ArgumentPurpose) -> Option<ir::Value> { | 289 | 2.12M | let entry = self.layout.entry_block().expect("Function is empty"); | 290 | 2.12M | self.signature | 291 | 2.12M | .special_param_index(purpose) | 292 | 2.12M | .map(|i| self.dfg.block_params(entry)[i]) | 293 | 2.12M | } |
|
294 | | |
295 | | /// Starts collection of debug information. |
296 | 0 | pub fn collect_debug_info(&mut self) { |
297 | 0 | self.dfg.collect_debug_info(); |
298 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::collect_debug_info Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::collect_debug_info |
299 | | |
300 | | /// Rewrite the branch destination to `new_dest` if the destination matches `old_dest`. |
301 | | /// Does nothing if called with a non-jump or non-branch instruction. |
302 | 0 | pub fn rewrite_branch_destination(&mut self, inst: Inst, old_dest: Block, new_dest: Block) { |
303 | 0 | for dest in self.dfg.insts[inst] |
304 | 0 | .branch_destination_mut(&mut self.dfg.jump_tables, &mut self.dfg.exception_tables) |
305 | | { |
306 | 0 | if dest.block(&self.dfg.value_lists) == old_dest { |
307 | 0 | dest.set_block(new_dest, &mut self.dfg.value_lists) |
308 | 0 | } |
309 | | } |
310 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::rewrite_branch_destination Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::rewrite_branch_destination |
311 | | |
312 | | /// Checks that the specified block can be encoded as a basic block. |
313 | | /// |
314 | | /// On error, returns the first invalid instruction and an error message. |
315 | 13.0M | pub fn is_block_basic(&self, block: Block) -> Result<(), (Inst, &'static str)> { |
316 | 13.0M | let dfg = &self.dfg; |
317 | 13.0M | let inst_iter = self.layout.block_insts(block); |
318 | | |
319 | | // Ignore all instructions prior to the first branch. |
320 | 115M | let mut inst_iter = inst_iter.skip_while(|&inst| !dfg.insts[inst].opcode().is_branch()); <cranelift_codegen::ir::function::FunctionStencil>::is_block_basic::{closure#0}Line | Count | Source | 320 | 15.7M | let mut inst_iter = inst_iter.skip_while(|&inst| !dfg.insts[inst].opcode().is_branch()); |
<cranelift_codegen::ir::function::FunctionStencil>::is_block_basic::{closure#0}Line | Count | Source | 320 | 100M | let mut inst_iter = inst_iter.skip_while(|&inst| !dfg.insts[inst].opcode().is_branch()); |
|
321 | | |
322 | 13.0M | if let Some(_branch) = inst_iter.next() { |
323 | 9.67M | if let Some(next) = inst_iter.next() { |
324 | 0 | return Err((next, "post-terminator instruction")); |
325 | 9.67M | } |
326 | 3.37M | } |
327 | | |
328 | 13.0M | Ok(()) |
329 | 13.0M | } <cranelift_codegen::ir::function::FunctionStencil>::is_block_basic Line | Count | Source | 315 | 1.33M | pub fn is_block_basic(&self, block: Block) -> Result<(), (Inst, &'static str)> { | 316 | 1.33M | let dfg = &self.dfg; | 317 | 1.33M | let inst_iter = self.layout.block_insts(block); | 318 | | | 319 | | // Ignore all instructions prior to the first branch. | 320 | 1.33M | let mut inst_iter = inst_iter.skip_while(|&inst| !dfg.insts[inst].opcode().is_branch()); | 321 | | | 322 | 1.33M | if let Some(_branch) = inst_iter.next() { | 323 | 754k | if let Some(next) = inst_iter.next() { | 324 | 0 | return Err((next, "post-terminator instruction")); | 325 | 754k | } | 326 | 577k | } | 327 | | | 328 | 1.33M | Ok(()) | 329 | 1.33M | } |
<cranelift_codegen::ir::function::FunctionStencil>::is_block_basic Line | Count | Source | 315 | 11.7M | pub fn is_block_basic(&self, block: Block) -> Result<(), (Inst, &'static str)> { | 316 | 11.7M | let dfg = &self.dfg; | 317 | 11.7M | let inst_iter = self.layout.block_insts(block); | 318 | | | 319 | | // Ignore all instructions prior to the first branch. | 320 | 11.7M | let mut inst_iter = inst_iter.skip_while(|&inst| !dfg.insts[inst].opcode().is_branch()); | 321 | | | 322 | 11.7M | if let Some(_branch) = inst_iter.next() { | 323 | 8.92M | if let Some(next) = inst_iter.next() { | 324 | 0 | return Err((next, "post-terminator instruction")); | 325 | 8.92M | } | 326 | 2.79M | } | 327 | | | 328 | 11.7M | Ok(()) | 329 | 11.7M | } |
|
330 | | |
331 | | /// Returns an iterator over the blocks succeeding the given block. |
332 | 16.2M | pub fn block_successors(&self, block: Block) -> impl DoubleEndedIterator<Item = Block> + '_ { |
333 | 16.2M | self.layout.last_inst(block).into_iter().flat_map(|inst| { |
334 | 16.2M | self.dfg.insts[inst] |
335 | 16.2M | .branch_destination(&self.dfg.jump_tables, &self.dfg.exception_tables) |
336 | 16.2M | .iter() |
337 | 16.2M | .map(|block| block.block(&self.dfg.value_lists)) Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::block_successors::{closure#0}::{closure#0}<cranelift_codegen::ir::function::FunctionStencil>::block_successors::{closure#0}::{closure#0}Line | Count | Source | 337 | 1.26M | .map(|block| block.block(&self.dfg.value_lists)) |
Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::block_successors::{closure#0}::{closure#0}<cranelift_codegen::ir::function::FunctionStencil>::block_successors::{closure#0}::{closure#0}Line | Count | Source | 337 | 13.6M | .map(|block| block.block(&self.dfg.value_lists)) |
|
338 | 16.2M | }) Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::block_successors::{closure#0}<cranelift_codegen::ir::function::FunctionStencil>::block_successors::{closure#0}Line | Count | Source | 333 | 1.77M | self.layout.last_inst(block).into_iter().flat_map(|inst| { | 334 | 1.77M | self.dfg.insts[inst] | 335 | 1.77M | .branch_destination(&self.dfg.jump_tables, &self.dfg.exception_tables) | 336 | 1.77M | .iter() | 337 | 1.77M | .map(|block| block.block(&self.dfg.value_lists)) | 338 | 1.77M | }) |
Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::block_successors::{closure#0}<cranelift_codegen::ir::function::FunctionStencil>::block_successors::{closure#0}Line | Count | Source | 333 | 14.5M | self.layout.last_inst(block).into_iter().flat_map(|inst| { | 334 | 14.5M | self.dfg.insts[inst] | 335 | 14.5M | .branch_destination(&self.dfg.jump_tables, &self.dfg.exception_tables) | 336 | 14.5M | .iter() | 337 | 14.5M | .map(|block| block.block(&self.dfg.value_lists)) | 338 | 14.5M | }) |
|
339 | 16.2M | } <cranelift_codegen::ir::function::FunctionStencil>::block_successors Line | Count | Source | 332 | 1.77M | pub fn block_successors(&self, block: Block) -> impl DoubleEndedIterator<Item = Block> + '_ { | 333 | 1.77M | self.layout.last_inst(block).into_iter().flat_map(|inst| { | 334 | | self.dfg.insts[inst] | 335 | | .branch_destination(&self.dfg.jump_tables, &self.dfg.exception_tables) | 336 | | .iter() | 337 | | .map(|block| block.block(&self.dfg.value_lists)) | 338 | | }) | 339 | 1.77M | } |
<cranelift_codegen::ir::function::FunctionStencil>::block_successors Line | Count | Source | 332 | 14.5M | pub fn block_successors(&self, block: Block) -> impl DoubleEndedIterator<Item = Block> + '_ { | 333 | 14.5M | self.layout.last_inst(block).into_iter().flat_map(|inst| { | 334 | | self.dfg.insts[inst] | 335 | | .branch_destination(&self.dfg.jump_tables, &self.dfg.exception_tables) | 336 | | .iter() | 337 | | .map(|block| block.block(&self.dfg.value_lists)) | 338 | | }) | 339 | 14.5M | } |
|
340 | | |
341 | | /// Replace the `dst` instruction's data with the `src` instruction's data |
342 | | /// and then remove `src`. |
343 | | /// |
344 | | /// `src` and its result values should not be used at all, as any uses would |
345 | | /// be left dangling after calling this method. |
346 | | /// |
347 | | /// `src` and `dst` must have the same number of resulting values, and |
348 | | /// `src`'s i^th value must have the same type as `dst`'s i^th value. |
349 | 0 | pub fn transplant_inst(&mut self, dst: Inst, src: Inst) { |
350 | 0 | debug_assert_eq!( |
351 | 0 | self.dfg.inst_results(dst).len(), |
352 | 0 | self.dfg.inst_results(src).len() |
353 | | ); |
354 | 0 | debug_assert!( |
355 | 0 | self.dfg |
356 | 0 | .inst_results(dst) |
357 | 0 | .iter() |
358 | 0 | .zip(self.dfg.inst_results(src)) |
359 | 0 | .all(|(a, b)| self.dfg.value_type(*a) == self.dfg.value_type(*b)) Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::transplant_inst::{closure#0}Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::transplant_inst::{closure#0} |
360 | | ); |
361 | | |
362 | 0 | self.dfg.insts[dst] = self.dfg.insts[src]; |
363 | 0 | self.layout.remove_inst(src); |
364 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::transplant_inst Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::transplant_inst |
365 | | |
366 | | /// Size occupied by all stack slots associated with this function. |
367 | | /// |
368 | | /// Does not include any padding necessary due to offsets |
369 | 0 | pub fn fixed_stack_size(&self) -> u32 { |
370 | 0 | self.sized_stack_slots.values().map(|ss| ss.size).sum() |
371 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::fixed_stack_size Unexecuted instantiation: <cranelift_codegen::ir::function::FunctionStencil>::fixed_stack_size |
372 | | |
373 | | /// Returns the list of relative source locations for this function. |
374 | 14.3M | pub(crate) fn rel_srclocs(&self) -> &SecondaryMap<Inst, RelSourceLoc> { |
375 | 14.3M | &self.srclocs |
376 | 14.3M | } <cranelift_codegen::ir::function::FunctionStencil>::rel_srclocs Line | Count | Source | 374 | 2.10M | pub(crate) fn rel_srclocs(&self) -> &SecondaryMap<Inst, RelSourceLoc> { | 375 | 2.10M | &self.srclocs | 376 | 2.10M | } |
<cranelift_codegen::ir::function::FunctionStencil>::rel_srclocs Line | Count | Source | 374 | 12.2M | pub(crate) fn rel_srclocs(&self) -> &SecondaryMap<Inst, RelSourceLoc> { | 375 | 12.2M | &self.srclocs | 376 | 12.2M | } |
|
377 | | } |
378 | | |
379 | | /// Functions can be cloned, but it is not a very fast operation. |
380 | | /// The clone will have all the same entity numbers as the original. |
381 | | #[derive(Clone, PartialEq)] |
382 | | #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] |
383 | | pub struct Function { |
384 | | /// Name of this function. |
385 | | /// |
386 | | /// Mostly used by `.clif` files, only there for debugging / naming purposes. |
387 | | pub name: UserFuncName, |
388 | | |
389 | | /// All the fields required for compiling a function, independently of details irrelevant to |
390 | | /// compilation and that are stored in the `FunctionParameters` `params` field instead. |
391 | | pub stencil: FunctionStencil, |
392 | | |
393 | | /// All the parameters that can be applied onto the function stencil, that is, that don't |
394 | | /// matter when caching compilation artifacts. |
395 | | pub params: FunctionParameters, |
396 | | } |
397 | | |
398 | | impl core::ops::Deref for Function { |
399 | | type Target = FunctionStencil; |
400 | | |
401 | 6.42G | fn deref(&self) -> &Self::Target { |
402 | 6.42G | &self.stencil |
403 | 6.42G | } <cranelift_codegen::ir::function::Function as core::ops::deref::Deref>::deref Line | Count | Source | 401 | 892M | fn deref(&self) -> &Self::Target { | 402 | 892M | &self.stencil | 403 | 892M | } |
<cranelift_codegen::ir::function::Function as core::ops::deref::Deref>::deref Line | Count | Source | 401 | 5.53G | fn deref(&self) -> &Self::Target { | 402 | 5.53G | &self.stencil | 403 | 5.53G | } |
|
404 | | } |
405 | | |
406 | | impl core::ops::DerefMut for Function { |
407 | 175M | fn deref_mut(&mut self) -> &mut Self::Target { |
408 | 175M | &mut self.stencil |
409 | 175M | } <cranelift_codegen::ir::function::Function as core::ops::deref::DerefMut>::deref_mut Line | Count | Source | 407 | 21.0M | fn deref_mut(&mut self) -> &mut Self::Target { | 408 | 21.0M | &mut self.stencil | 409 | 21.0M | } |
<cranelift_codegen::ir::function::Function as core::ops::deref::DerefMut>::deref_mut Line | Count | Source | 407 | 154M | fn deref_mut(&mut self) -> &mut Self::Target { | 408 | 154M | &mut self.stencil | 409 | 154M | } |
|
410 | | } |
411 | | |
412 | | impl Function { |
413 | | /// Create a function with the given name and signature. |
414 | 629k | pub fn with_name_signature(name: UserFuncName, sig: Signature) -> Self { |
415 | 629k | Self { |
416 | 629k | name, |
417 | 629k | stencil: FunctionStencil { |
418 | 629k | version_marker: VersionMarker, |
419 | 629k | signature: sig, |
420 | 629k | sized_stack_slots: StackSlots::new(), |
421 | 629k | dynamic_stack_slots: DynamicStackSlots::new(), |
422 | 629k | global_values: PrimaryMap::new(), |
423 | 629k | global_value_facts: SecondaryMap::new(), |
424 | 629k | memory_types: PrimaryMap::new(), |
425 | 629k | dfg: DataFlowGraph::new(), |
426 | 629k | layout: Layout::new(), |
427 | 629k | srclocs: SecondaryMap::new(), |
428 | 629k | stack_limit: None, |
429 | 629k | debug_tags: DebugTags::default(), |
430 | 629k | }, |
431 | 629k | params: FunctionParameters::new(), |
432 | 629k | } |
433 | 629k | } <cranelift_codegen::ir::function::Function>::with_name_signature Line | Count | Source | 414 | 157k | pub fn with_name_signature(name: UserFuncName, sig: Signature) -> Self { | 415 | 157k | Self { | 416 | 157k | name, | 417 | 157k | stencil: FunctionStencil { | 418 | 157k | version_marker: VersionMarker, | 419 | 157k | signature: sig, | 420 | 157k | sized_stack_slots: StackSlots::new(), | 421 | 157k | dynamic_stack_slots: DynamicStackSlots::new(), | 422 | 157k | global_values: PrimaryMap::new(), | 423 | 157k | global_value_facts: SecondaryMap::new(), | 424 | 157k | memory_types: PrimaryMap::new(), | 425 | 157k | dfg: DataFlowGraph::new(), | 426 | 157k | layout: Layout::new(), | 427 | 157k | srclocs: SecondaryMap::new(), | 428 | 157k | stack_limit: None, | 429 | 157k | debug_tags: DebugTags::default(), | 430 | 157k | }, | 431 | 157k | params: FunctionParameters::new(), | 432 | 157k | } | 433 | 157k | } |
<cranelift_codegen::ir::function::Function>::with_name_signature Line | Count | Source | 414 | 472k | pub fn with_name_signature(name: UserFuncName, sig: Signature) -> Self { | 415 | 472k | Self { | 416 | 472k | name, | 417 | 472k | stencil: FunctionStencil { | 418 | 472k | version_marker: VersionMarker, | 419 | 472k | signature: sig, | 420 | 472k | sized_stack_slots: StackSlots::new(), | 421 | 472k | dynamic_stack_slots: DynamicStackSlots::new(), | 422 | 472k | global_values: PrimaryMap::new(), | 423 | 472k | global_value_facts: SecondaryMap::new(), | 424 | 472k | memory_types: PrimaryMap::new(), | 425 | 472k | dfg: DataFlowGraph::new(), | 426 | 472k | layout: Layout::new(), | 427 | 472k | srclocs: SecondaryMap::new(), | 428 | 472k | stack_limit: None, | 429 | 472k | debug_tags: DebugTags::default(), | 430 | 472k | }, | 431 | 472k | params: FunctionParameters::new(), | 432 | 472k | } | 433 | 472k | } |
|
434 | | |
435 | | /// Clear all data structures in this function. |
436 | 0 | pub fn clear(&mut self) { |
437 | 0 | self.stencil.clear(); |
438 | 0 | self.params.clear(); |
439 | 0 | self.name = UserFuncName::default(); |
440 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::function::Function>::clear Unexecuted instantiation: <cranelift_codegen::ir::function::Function>::clear |
441 | | |
442 | | /// Create a new empty, anonymous function with a Fast calling convention. |
443 | 430k | pub fn new() -> Self { |
444 | 430k | Self::with_name_signature(Default::default(), Signature::new(CallConv::Fast)) |
445 | 430k | } <cranelift_codegen::ir::function::Function>::new Line | Count | Source | 443 | 96.6k | pub fn new() -> Self { | 444 | 96.6k | Self::with_name_signature(Default::default(), Signature::new(CallConv::Fast)) | 445 | 96.6k | } |
<cranelift_codegen::ir::function::Function>::new Line | Count | Source | 443 | 333k | pub fn new() -> Self { | 444 | 333k | Self::with_name_signature(Default::default(), Signature::new(CallConv::Fast)) | 445 | 333k | } |
|
446 | | |
447 | | /// Return an object that can display this function with correct ISA-specific annotations. |
448 | 0 | pub fn display(&self) -> DisplayFunction<'_> { |
449 | 0 | DisplayFunction(self) |
450 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::function::Function>::display Unexecuted instantiation: <cranelift_codegen::ir::function::Function>::display |
451 | | |
452 | | /// Return an object that can display this function's name and signature. |
453 | 0 | pub fn display_spec(&self) -> DisplayFunctionSpec<'_> { |
454 | 0 | DisplayFunctionSpec(self) |
455 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::function::Function>::display_spec Unexecuted instantiation: <cranelift_codegen::ir::function::Function>::display_spec |
456 | | |
457 | | /// Sets an absolute source location for the given instruction. |
458 | | /// |
459 | | /// If no base source location has been set yet, records it at the same time. |
460 | 17.7M | pub fn set_srcloc(&mut self, inst: Inst, srcloc: SourceLoc) { |
461 | 17.7M | let base = self.params.ensure_base_srcloc(srcloc); |
462 | 17.7M | self.stencil.srclocs[inst] = RelSourceLoc::from_base_offset(base, srcloc); |
463 | 17.7M | } <cranelift_codegen::ir::function::Function>::set_srcloc Line | Count | Source | 460 | 1.64M | pub fn set_srcloc(&mut self, inst: Inst, srcloc: SourceLoc) { | 461 | 1.64M | let base = self.params.ensure_base_srcloc(srcloc); | 462 | 1.64M | self.stencil.srclocs[inst] = RelSourceLoc::from_base_offset(base, srcloc); | 463 | 1.64M | } |
<cranelift_codegen::ir::function::Function>::set_srcloc Line | Count | Source | 460 | 16.1M | pub fn set_srcloc(&mut self, inst: Inst, srcloc: SourceLoc) { | 461 | 16.1M | let base = self.params.ensure_base_srcloc(srcloc); | 462 | 16.1M | self.stencil.srclocs[inst] = RelSourceLoc::from_base_offset(base, srcloc); | 463 | 16.1M | } |
|
464 | | |
465 | | /// Returns an absolute source location for the given instruction. |
466 | 1.39M | pub fn srcloc(&self, inst: Inst) -> SourceLoc { |
467 | 1.39M | let base = self.params.base_srcloc(); |
468 | 1.39M | self.stencil.srclocs[inst].expand(base) |
469 | 1.39M | } <cranelift_codegen::ir::function::Function>::srcloc Line | Count | Source | 466 | 85.9k | pub fn srcloc(&self, inst: Inst) -> SourceLoc { | 467 | 85.9k | let base = self.params.base_srcloc(); | 468 | 85.9k | self.stencil.srclocs[inst].expand(base) | 469 | 85.9k | } |
<cranelift_codegen::ir::function::Function>::srcloc Line | Count | Source | 466 | 1.31M | pub fn srcloc(&self, inst: Inst) -> SourceLoc { | 467 | 1.31M | let base = self.params.base_srcloc(); | 468 | 1.31M | self.stencil.srclocs[inst].expand(base) | 469 | 1.31M | } |
|
470 | | |
471 | | /// Declare a user-defined external function import, to be referenced in `ExtFuncData::User` later. |
472 | 0 | pub fn declare_imported_user_function( |
473 | 0 | &mut self, |
474 | 0 | name: UserExternalName, |
475 | 0 | ) -> UserExternalNameRef { |
476 | 0 | self.params.ensure_user_func_name(name) |
477 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::function::Function>::declare_imported_user_function Unexecuted instantiation: <cranelift_codegen::ir::function::Function>::declare_imported_user_function |
478 | | |
479 | | /// Declare an external function import. |
480 | 5.45k | pub fn import_function(&mut self, data: ExtFuncData) -> FuncRef { |
481 | 5.45k | self.stencil.dfg.ext_funcs.push(data) |
482 | 5.45k | } <cranelift_codegen::ir::function::Function>::import_function Line | Count | Source | 480 | 866 | pub fn import_function(&mut self, data: ExtFuncData) -> FuncRef { | 481 | 866 | self.stencil.dfg.ext_funcs.push(data) | 482 | 866 | } |
<cranelift_codegen::ir::function::Function>::import_function Line | Count | Source | 480 | 4.58k | pub fn import_function(&mut self, data: ExtFuncData) -> FuncRef { | 481 | 4.58k | self.stencil.dfg.ext_funcs.push(data) | 482 | 4.58k | } |
|
483 | | } |
484 | | |
485 | | /// Wrapper type capable of displaying a `Function`. |
486 | | pub struct DisplayFunction<'a>(&'a Function); |
487 | | |
488 | | impl<'a> fmt::Display for DisplayFunction<'a> { |
489 | 0 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
490 | 0 | write_function(fmt, self.0) |
491 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::function::DisplayFunction as core::fmt::Display>::fmt Unexecuted instantiation: <cranelift_codegen::ir::function::DisplayFunction as core::fmt::Display>::fmt |
492 | | } |
493 | | |
494 | | impl fmt::Display for Function { |
495 | 0 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
496 | 0 | write_function(fmt, self) |
497 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::function::Function as core::fmt::Display>::fmt Unexecuted instantiation: <cranelift_codegen::ir::function::Function as core::fmt::Display>::fmt |
498 | | } |
499 | | |
500 | | impl fmt::Debug for Function { |
501 | 0 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
502 | 0 | write_function(fmt, self) |
503 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::function::Function as core::fmt::Debug>::fmt Unexecuted instantiation: <cranelift_codegen::ir::function::Function as core::fmt::Debug>::fmt |
504 | | } |
505 | | |
506 | | /// Wrapper type capable of displaying a 'Function's name and signature. |
507 | | pub struct DisplayFunctionSpec<'a>(&'a Function); |
508 | | |
509 | | impl<'a> fmt::Display for DisplayFunctionSpec<'a> { |
510 | 0 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
511 | 0 | write_function_spec(fmt, self.0) |
512 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::function::DisplayFunctionSpec as core::fmt::Display>::fmt Unexecuted instantiation: <cranelift_codegen::ir::function::DisplayFunctionSpec as core::fmt::Display>::fmt |
513 | | } |
514 | | |
515 | | impl<'a> fmt::Debug for DisplayFunctionSpec<'a> { |
516 | 0 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
517 | 0 | write_function_spec(fmt, self.0) |
518 | 0 | } Unexecuted instantiation: <cranelift_codegen::ir::function::DisplayFunctionSpec as core::fmt::Debug>::fmt Unexecuted instantiation: <cranelift_codegen::ir::function::DisplayFunctionSpec as core::fmt::Debug>::fmt |
519 | | } |