/rust/registry/src/index.crates.io-6f17d22bba15001f/cranelift-codegen-0.91.1/src/legalizer/globalvalue.rs
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | //! Legalization of global values. | 
| 2 |  | //! | 
| 3 |  | //! This module exports the `expand_global_value` function which transforms a `global_value` | 
| 4 |  | //! instruction into code that depends on the kind of global value referenced. | 
| 5 |  |  | 
| 6 |  | use crate::cursor::{Cursor, FuncCursor}; | 
| 7 |  | use crate::ir::{self, InstBuilder}; | 
| 8 |  | use crate::isa::TargetIsa; | 
| 9 |  |  | 
| 10 |  | /// Expand a `global_value` instruction according to the definition of the global value. | 
| 11 | 108k | pub fn expand_global_value( | 
| 12 | 108k |     inst: ir::Inst, | 
| 13 | 108k |     func: &mut ir::Function, | 
| 14 | 108k |     isa: &dyn TargetIsa, | 
| 15 | 108k |     global_value: ir::GlobalValue, | 
| 16 | 108k | ) { | 
| 17 | 108k |     crate::trace!( | 
| 18 | 0 |         "expanding global value: {:?}: {}", | 
| 19 | 0 |         inst, | 
| 20 | 0 |         func.dfg.display_inst(inst) | 
| 21 |  |     ); | 
| 22 |  |  | 
| 23 | 108k |     match func.global_values[global_value] { | 
| 24 | 26.4k |         ir::GlobalValueData::VMContext => vmctx_addr(inst, func), | 
| 25 |  |         ir::GlobalValueData::IAddImm { | 
| 26 | 0 |             base, | 
| 27 | 0 |             offset, | 
| 28 | 0 |             global_type, | 
| 29 | 0 |         } => iadd_imm_addr(inst, func, base, offset.into(), global_type), | 
| 30 |  |         ir::GlobalValueData::Load { | 
| 31 | 81.7k |             base, | 
| 32 | 81.7k |             offset, | 
| 33 | 81.7k |             global_type, | 
| 34 | 81.7k |             readonly, | 
| 35 | 81.7k |         } => load_addr(inst, func, base, offset, global_type, readonly, isa), | 
| 36 | 0 |         ir::GlobalValueData::Symbol { tls, .. } => symbol(inst, func, global_value, isa, tls), | 
| 37 | 0 |         ir::GlobalValueData::DynScaleTargetConst { vector_type } => { | 
| 38 | 0 |             const_vector_scale(inst, func, vector_type, isa) | 
| 39 |  |         } | 
| 40 |  |     } | 
| 41 | 108k | } | 
| 42 |  |  | 
| 43 | 0 | fn const_vector_scale(inst: ir::Inst, func: &mut ir::Function, ty: ir::Type, isa: &dyn TargetIsa) { | 
| 44 | 0 |     assert!(ty.bytes() <= 16); | 
| 45 |  |  | 
| 46 |  |     // Use a minimum of 128-bits for the base type. | 
| 47 | 0 |     let base_bytes = std::cmp::max(ty.bytes(), 16); | 
| 48 | 0 |     let scale = (isa.dynamic_vector_bytes(ty) / base_bytes) as i64; | 
| 49 | 0 |     assert!(scale > 0); | 
| 50 | 0 |     let pos = FuncCursor::new(func).at_inst(inst); | 
| 51 | 0 |     pos.func.dfg.replace(inst).iconst(isa.pointer_type(), scale); | 
| 52 | 0 | } | 
| 53 |  |  | 
| 54 |  | /// Expand a `global_value` instruction for a vmctx global. | 
| 55 | 26.4k | fn vmctx_addr(inst: ir::Inst, func: &mut ir::Function) { | 
| 56 | 26.4k |     // Get the value representing the `vmctx` argument. | 
| 57 | 26.4k |     let vmctx = func | 
| 58 | 26.4k |         .special_param(ir::ArgumentPurpose::VMContext) | 
| 59 | 26.4k |         .expect("Missing vmctx parameter"); | 
| 60 | 26.4k |  | 
| 61 | 26.4k |     // Replace the `global_value` instruction's value with an alias to the vmctx arg. | 
| 62 | 26.4k |     let result = func.dfg.first_result(inst); | 
| 63 | 26.4k |     func.dfg.clear_results(inst); | 
| 64 | 26.4k |     func.dfg.change_to_alias(result, vmctx); | 
| 65 | 26.4k |     func.layout.remove_inst(inst); | 
| 66 | 26.4k | } | 
| 67 |  |  | 
| 68 |  | /// Expand a `global_value` instruction for an iadd_imm global. | 
| 69 | 0 | fn iadd_imm_addr( | 
| 70 | 0 |     inst: ir::Inst, | 
| 71 | 0 |     func: &mut ir::Function, | 
| 72 | 0 |     base: ir::GlobalValue, | 
| 73 | 0 |     offset: i64, | 
| 74 | 0 |     global_type: ir::Type, | 
| 75 | 0 | ) { | 
| 76 | 0 |     let mut pos = FuncCursor::new(func).at_inst(inst); | 
| 77 |  |  | 
| 78 |  |     // Get the value for the lhs. For tidiness, expand VMContext here so that we avoid | 
| 79 |  |     // `vmctx_addr` which creates an otherwise unneeded value alias. | 
| 80 | 0 |     let lhs = if let ir::GlobalValueData::VMContext = pos.func.global_values[base] { | 
| 81 | 0 |         pos.func | 
| 82 | 0 |             .special_param(ir::ArgumentPurpose::VMContext) | 
| 83 | 0 |             .expect("Missing vmctx parameter") | 
| 84 |  |     } else { | 
| 85 | 0 |         pos.ins().global_value(global_type, base) | 
| 86 |  |     }; | 
| 87 |  |  | 
| 88 |  |     // Simply replace the `global_value` instruction with an `iadd_imm`, reusing the result value. | 
| 89 | 0 |     pos.func.dfg.replace(inst).iadd_imm(lhs, offset); | 
| 90 | 0 | } | 
| 91 |  |  | 
| 92 |  | /// Expand a `global_value` instruction for a load global. | 
| 93 | 81.7k | fn load_addr( | 
| 94 | 81.7k |     inst: ir::Inst, | 
| 95 | 81.7k |     func: &mut ir::Function, | 
| 96 | 81.7k |     base: ir::GlobalValue, | 
| 97 | 81.7k |     offset: ir::immediates::Offset32, | 
| 98 | 81.7k |     global_type: ir::Type, | 
| 99 | 81.7k |     readonly: bool, | 
| 100 | 81.7k |     isa: &dyn TargetIsa, | 
| 101 | 81.7k | ) { | 
| 102 | 81.7k |     // We need to load a pointer from the `base` global value, so insert a new `global_value` | 
| 103 | 81.7k |     // instruction. This depends on the iterative legalization loop. Note that the IR verifier | 
| 104 | 81.7k |     // detects any cycles in the `load` globals. | 
| 105 | 81.7k |     let ptr_ty = isa.pointer_type(); | 
| 106 | 81.7k |     let mut pos = FuncCursor::new(func).at_inst(inst); | 
| 107 | 81.7k |     pos.use_srcloc(inst); | 
| 108 |  |  | 
| 109 |  |     // Get the value for the base. For tidiness, expand VMContext here so that we avoid | 
| 110 |  |     // `vmctx_addr` which creates an otherwise unneeded value alias. | 
| 111 | 81.7k |     let base_addr = if let ir::GlobalValueData::VMContext = pos.func.global_values[base] { | 
| 112 | 81.7k |         pos.func | 
| 113 | 81.7k |             .special_param(ir::ArgumentPurpose::VMContext) | 
| 114 | 81.7k |             .expect("Missing vmctx parameter") | 
| 115 |  |     } else { | 
| 116 | 0 |         pos.ins().global_value(ptr_ty, base) | 
| 117 |  |     }; | 
| 118 |  |  | 
| 119 |  |     // Global-value loads are always notrap and aligned. They may be readonly. | 
| 120 | 81.7k |     let mut mflags = ir::MemFlags::trusted(); | 
| 121 | 81.7k |     if readonly { | 
| 122 | 69.9k |         mflags.set_readonly(); | 
| 123 | 69.9k |     } | 
| 124 |  |  | 
| 125 |  |     // Perform the load. | 
| 126 | 81.7k |     pos.func | 
| 127 | 81.7k |         .dfg | 
| 128 | 81.7k |         .replace(inst) | 
| 129 | 81.7k |         .load(global_type, mflags, base_addr, offset); | 
| 130 | 81.7k | } | 
| 131 |  |  | 
| 132 |  | /// Expand a `global_value` instruction for a symbolic name global. | 
| 133 | 0 | fn symbol( | 
| 134 | 0 |     inst: ir::Inst, | 
| 135 | 0 |     func: &mut ir::Function, | 
| 136 | 0 |     gv: ir::GlobalValue, | 
| 137 | 0 |     isa: &dyn TargetIsa, | 
| 138 | 0 |     tls: bool, | 
| 139 | 0 | ) { | 
| 140 | 0 |     let ptr_ty = isa.pointer_type(); | 
| 141 | 0 | 
 | 
| 142 | 0 |     if tls { | 
| 143 | 0 |         func.dfg.replace(inst).tls_value(ptr_ty, gv); | 
| 144 | 0 |     } else { | 
| 145 | 0 |         func.dfg.replace(inst).symbol_value(ptr_ty, gv); | 
| 146 | 0 |     } | 
| 147 | 0 | } |