1use crate::entity::{PrimaryMap, SecondaryMap};
7use crate::ir::{
8 self, Block, DataFlowGraph, DynamicStackSlot, DynamicStackSlotData, DynamicStackSlots,
9 DynamicType, ExtFuncData, FuncRef, GlobalValue, GlobalValueData, Inst, JumpTable,
10 JumpTableData, Layout, Opcode, SigRef, Signature, SourceLocs, StackSlot, StackSlotData,
11 StackSlots, Table, TableData, Type,
12};
13use crate::isa::CallConv;
14use crate::value_label::ValueLabelsRanges;
15use crate::write::write_function;
16use crate::HashMap;
17#[cfg(feature = "enable-serde")]
18use alloc::string::String;
19use core::fmt;
20
21#[cfg(feature = "enable-serde")]
22use serde::de::{Deserializer, Error};
23#[cfg(feature = "enable-serde")]
24use serde::ser::Serializer;
25#[cfg(feature = "enable-serde")]
26use serde::{Deserialize, Serialize};
27
28use super::entities::UserExternalNameRef;
29use super::extname::UserFuncName;
30use super::{RelSourceLoc, SourceLoc, UserExternalName};
31
32#[derive(Copy, Clone, Debug, PartialEq, Hash)]
35pub struct VersionMarker;
36
37#[cfg(feature = "enable-serde")]
38impl 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")]
48impl<'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#[derive(Clone)]
68#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
69pub struct FunctionParameters {
70 base_srcloc: Option<SourceLoc>,
73
74 user_named_funcs: PrimaryMap<UserExternalNameRef, UserExternalName>,
76
77 user_ext_name_to_ref: HashMap<UserExternalName, UserExternalNameRef>,
79}
80
81impl FunctionParameters {
82 pub fn new() -> Self {
84 Self {
85 base_srcloc: None,
86 user_named_funcs: Default::default(),
87 user_ext_name_to_ref: Default::default(),
88 }
89 }
90
91 pub fn base_srcloc(&self) -> SourceLoc {
96 self.base_srcloc.unwrap_or_default()
97 }
98
99 pub fn ensure_base_srcloc(&mut self, srcloc: SourceLoc) -> SourceLoc {
101 match self.base_srcloc {
102 Some(val) => val,
103 None => {
104 self.base_srcloc = Some(srcloc);
105 srcloc
106 }
107 }
108 }
109
110 pub fn ensure_user_func_name(&mut self, name: UserExternalName) -> UserExternalNameRef {
115 if let Some(reff) = self.user_ext_name_to_ref.get(&name) {
116 *reff
117 } else {
118 let reff = self.user_named_funcs.push(name.clone());
119 self.user_ext_name_to_ref.insert(name, reff);
120 reff
121 }
122 }
123
124 pub fn reset_user_func_name(&mut self, index: UserExternalNameRef, name: UserExternalName) {
126 if let Some(prev_name) = self.user_named_funcs.get_mut(index) {
127 self.user_ext_name_to_ref.remove(prev_name);
128 *prev_name = name.clone();
129 self.user_ext_name_to_ref.insert(name, index);
130 }
131 }
132
133 pub fn user_named_funcs(&self) -> &PrimaryMap<UserExternalNameRef, UserExternalName> {
135 &self.user_named_funcs
136 }
137
138 fn clear(&mut self) {
139 self.base_srcloc = None;
140 self.user_named_funcs.clear();
141 self.user_ext_name_to_ref.clear();
142 }
143}
144
145#[derive(Clone, PartialEq, Hash)]
150#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
151pub struct FunctionStencil {
152 pub version_marker: VersionMarker,
157
158 pub signature: Signature,
160
161 pub sized_stack_slots: StackSlots,
163
164 pub dynamic_stack_slots: DynamicStackSlots,
166
167 pub global_values: PrimaryMap<ir::GlobalValue, ir::GlobalValueData>,
169
170 pub tables: PrimaryMap<ir::Table, ir::TableData>,
172
173 pub dfg: DataFlowGraph,
175
176 pub layout: Layout,
178
179 pub srclocs: SourceLocs,
184
185 pub stack_limit: Option<ir::GlobalValue>,
191}
192
193impl FunctionStencil {
194 fn clear(&mut self) {
195 self.signature.clear(CallConv::Fast);
196 self.sized_stack_slots.clear();
197 self.dynamic_stack_slots.clear();
198 self.global_values.clear();
199 self.tables.clear();
200 self.dfg.clear();
201 self.layout.clear();
202 self.srclocs.clear();
203 self.stack_limit = None;
204 }
205
206 pub fn create_jump_table(&mut self, data: JumpTableData) -> JumpTable {
208 self.dfg.jump_tables.push(data)
209 }
210
211 pub fn create_sized_stack_slot(&mut self, data: StackSlotData) -> StackSlot {
214 self.sized_stack_slots.push(data)
215 }
216
217 pub fn create_dynamic_stack_slot(&mut self, data: DynamicStackSlotData) -> DynamicStackSlot {
220 self.dynamic_stack_slots.push(data)
221 }
222
223 pub fn import_signature(&mut self, signature: Signature) -> SigRef {
225 self.dfg.signatures.push(signature)
226 }
227
228 pub fn create_global_value(&mut self, data: GlobalValueData) -> GlobalValue {
230 self.global_values.push(data)
231 }
232
233 pub fn get_dyn_scale(&self, ty: DynamicType) -> GlobalValue {
235 self.dfg.dynamic_types.get(ty).unwrap().dynamic_scale
236 }
237
238 pub fn get_dynamic_slot_scale(&self, dss: DynamicStackSlot) -> GlobalValue {
240 let dyn_ty = self.dynamic_stack_slots.get(dss).unwrap().dyn_ty;
241 self.get_dyn_scale(dyn_ty)
242 }
243
244 pub fn get_concrete_dynamic_ty(&self, ty: DynamicType) -> Option<Type> {
246 self.dfg
247 .dynamic_types
248 .get(ty)
249 .unwrap_or_else(|| panic!("Undeclared dynamic vector type: {}", ty))
250 .concrete()
251 }
252
253 pub fn create_table(&mut self, data: TableData) -> Table {
255 self.tables.push(data)
256 }
257
258 pub fn special_param(&self, purpose: ir::ArgumentPurpose) -> Option<ir::Value> {
262 let entry = self.layout.entry_block().expect("Function is empty");
263 self.signature
264 .special_param_index(purpose)
265 .map(|i| self.dfg.block_params(entry)[i])
266 }
267
268 pub fn collect_debug_info(&mut self) {
270 self.dfg.collect_debug_info();
271 }
272
273 pub fn rewrite_branch_destination(&mut self, inst: Inst, old_dest: Block, new_dest: Block) {
276 for dest in self.dfg.insts[inst].branch_destination_mut(&mut self.dfg.jump_tables) {
277 if dest.block(&self.dfg.value_lists) == old_dest {
278 dest.set_block(new_dest, &mut self.dfg.value_lists)
279 }
280 }
281 }
282
283 pub fn is_block_basic(&self, block: Block) -> Result<(), (Inst, &'static str)> {
287 let dfg = &self.dfg;
288 let inst_iter = self.layout.block_insts(block);
289
290 let mut inst_iter = inst_iter.skip_while(|&inst| !dfg.insts[inst].opcode().is_branch());
292
293 if let Some(_branch) = inst_iter.next() {
296 if let Some(next) = inst_iter.next() {
297 match dfg.insts[next].opcode() {
298 Opcode::Jump => (),
299 _ => return Err((next, "post-branch instruction not jump")),
300 }
301 }
302 }
303
304 Ok(())
305 }
306
307 pub fn is_leaf(&self) -> bool {
310 self.dfg.signatures.is_empty()
313 }
314
315 pub fn transplant_inst(&mut self, dst: Inst, src: Inst) {
324 debug_assert_eq!(
325 self.dfg.inst_results(dst).len(),
326 self.dfg.inst_results(src).len()
327 );
328 debug_assert!(self
329 .dfg
330 .inst_results(dst)
331 .iter()
332 .zip(self.dfg.inst_results(src))
333 .all(|(a, b)| self.dfg.value_type(*a) == self.dfg.value_type(*b)));
334
335 self.dfg.insts[dst] = self.dfg.insts[src];
336 self.layout.remove_inst(src);
337 }
338
339 pub fn fixed_stack_size(&self) -> u32 {
343 self.sized_stack_slots.values().map(|ss| ss.size).sum()
344 }
345
346 pub(crate) fn rel_srclocs(&self) -> &SecondaryMap<Inst, RelSourceLoc> {
348 &self.srclocs
349 }
350}
351
352#[derive(Clone)]
355#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
356pub struct Function {
357 pub name: UserFuncName,
361
362 pub stencil: FunctionStencil,
365
366 pub params: FunctionParameters,
369}
370
371impl core::ops::Deref for Function {
372 type Target = FunctionStencil;
373
374 fn deref(&self) -> &Self::Target {
375 &self.stencil
376 }
377}
378
379impl core::ops::DerefMut for Function {
380 fn deref_mut(&mut self) -> &mut Self::Target {
381 &mut self.stencil
382 }
383}
384
385impl Function {
386 pub fn with_name_signature(name: UserFuncName, sig: Signature) -> Self {
388 Self {
389 name,
390 stencil: FunctionStencil {
391 version_marker: VersionMarker,
392 signature: sig,
393 sized_stack_slots: StackSlots::new(),
394 dynamic_stack_slots: DynamicStackSlots::new(),
395 global_values: PrimaryMap::new(),
396 tables: PrimaryMap::new(),
397 dfg: DataFlowGraph::new(),
398 layout: Layout::new(),
399 srclocs: SecondaryMap::new(),
400 stack_limit: None,
401 },
402 params: FunctionParameters::new(),
403 }
404 }
405
406 pub fn clear(&mut self) {
408 self.stencil.clear();
409 self.params.clear();
410 self.name = UserFuncName::default();
411 }
412
413 pub fn new() -> Self {
415 Self::with_name_signature(Default::default(), Signature::new(CallConv::Fast))
416 }
417
418 pub fn display(&self) -> DisplayFunction<'_> {
420 DisplayFunction(self, Default::default())
421 }
422
423 pub fn display_with<'a>(
425 &'a self,
426 annotations: DisplayFunctionAnnotations<'a>,
427 ) -> DisplayFunction<'a> {
428 DisplayFunction(self, annotations)
429 }
430
431 pub fn set_srcloc(&mut self, inst: Inst, srcloc: SourceLoc) {
435 let base = self.params.ensure_base_srcloc(srcloc);
436 self.stencil.srclocs[inst] = RelSourceLoc::from_base_offset(base, srcloc);
437 }
438
439 pub fn srcloc(&self, inst: Inst) -> SourceLoc {
441 let base = self.params.base_srcloc();
442 self.stencil.srclocs[inst].expand(base)
443 }
444
445 pub fn declare_imported_user_function(
447 &mut self,
448 name: UserExternalName,
449 ) -> UserExternalNameRef {
450 self.params.ensure_user_func_name(name)
451 }
452
453 pub fn import_function(&mut self, data: ExtFuncData) -> FuncRef {
455 self.stencil.dfg.ext_funcs.push(data)
456 }
457}
458
459#[derive(Default)]
461pub struct DisplayFunctionAnnotations<'a> {
462 pub value_ranges: Option<&'a ValueLabelsRanges>,
464}
465
466pub struct DisplayFunction<'a>(&'a Function, DisplayFunctionAnnotations<'a>);
468
469impl<'a> fmt::Display for DisplayFunction<'a> {
470 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
471 write_function(fmt, self.0)
472 }
473}
474
475impl fmt::Display for Function {
476 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
477 write_function(fmt, self)
478 }
479}
480
481impl fmt::Debug for Function {
482 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
483 write_function(fmt, self)
484 }
485}