Files
wasmtime/lib/cretonne/src/legalizer/globalvar.rs
Dan Gohman 30f8daa9d6 Replace assert! with debug_assert! in production code paths.
This allows the assertions to be disabled in release builds, so that
the code is faster and smaller, at the expense of not performing the
checks. Assertions can be re-enabled in release builds with the
debug-assertions flag in Cargo.toml, as the top-level Cargo.toml
file does.
2018-03-12 12:38:30 -07:00

65 lines
2.7 KiB
Rust

//! Legalization of global variables.
//!
//! This module exports the `expand_global_addr` function which transforms a `global_addr`
//! instruction into code that depends on the kind of global variable referenced.
use cursor::{Cursor, FuncCursor};
use flowgraph::ControlFlowGraph;
use ir::{self, InstBuilder};
use isa::TargetIsa;
/// Expand a `global_addr` instruction according to the definition of the global variable.
pub fn expand_global_addr(
inst: ir::Inst,
func: &mut ir::Function,
_cfg: &mut ControlFlowGraph,
_isa: &TargetIsa,
) {
// Unpack the instruction.
let gv = match func.dfg[inst] {
ir::InstructionData::UnaryGlobalVar { opcode, global_var } => {
debug_assert_eq!(opcode, ir::Opcode::GlobalAddr);
global_var
}
_ => panic!("Wanted global_addr: {}", func.dfg.display_inst(inst, None)),
};
match func.global_vars[gv] {
ir::GlobalVarData::VmCtx { offset } => vmctx_addr(inst, func, offset.into()),
ir::GlobalVarData::Deref { base, offset } => deref_addr(inst, func, base, offset.into()),
ir::GlobalVarData::Sym { .. } => globalsym(inst, func, gv),
}
}
/// Expand a `global_addr` instruction for a vmctx global.
fn vmctx_addr(inst: ir::Inst, func: &mut ir::Function, offset: i64) {
// Get the value representing the `vmctx` argument.
let vmctx = func.special_param(ir::ArgumentPurpose::VMContext).expect(
"Missing vmctx parameter",
);
// Simply replace the `global_addr` instruction with an `iadd_imm`, reusing the result value.
func.dfg.replace(inst).iadd_imm(vmctx, offset);
}
/// Expand a `global_addr` instruction for a deref global.
fn deref_addr(inst: ir::Inst, func: &mut ir::Function, base: ir::GlobalVar, offset: i64) {
// We need to load a pointer from the `base` global variable, so insert a new `global_addr`
// instruction. This depends on the iterative legalization loop. Note that the IL verifier
// detects any cycles in the `deref` globals.
let ptr_ty = func.dfg.value_type(func.dfg.first_result(inst));
let mut pos = FuncCursor::new(func).at_inst(inst);
pos.use_srcloc(inst);
let base_addr = pos.ins().global_addr(ptr_ty, base);
// TODO: We could probably set both `notrap` and `aligned` on this load instruction.
let base_ptr = pos.ins().load(ptr_ty, ir::MemFlags::new(), base_addr, 0);
pos.func.dfg.replace(inst).iadd_imm(base_ptr, offset);
}
/// Expand a `global_addr` instruction for a symbolic name global.
fn globalsym(inst: ir::Inst, func: &mut ir::Function, gv: ir::GlobalVar) {
let ptr_ty = func.dfg.value_type(func.dfg.first_result(inst));
func.dfg.replace(inst).globalsym_addr(ptr_ty, gv);
}