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