Define a "table" concept.
"Table" is to WebAssembly tables as "Heap" is to WebAssembly linear memories.
This commit is contained in:
@@ -82,7 +82,7 @@ fn dynamic_addr(
|
||||
}
|
||||
pos.ins().trapnz(oob, ir::TrapCode::HeapOutOfBounds);
|
||||
|
||||
offset_addr(inst, heap, addr_ty, offset, offset_ty, pos.func);
|
||||
compute_addr(inst, heap, addr_ty, offset, offset_ty, pos.func);
|
||||
}
|
||||
|
||||
/// Expand a `heap_addr` for a static heap.
|
||||
@@ -134,13 +134,11 @@ fn static_addr(
|
||||
pos.ins().trapnz(oob, ir::TrapCode::HeapOutOfBounds);
|
||||
}
|
||||
|
||||
offset_addr(inst, heap, addr_ty, offset, offset_ty, pos.func);
|
||||
compute_addr(inst, heap, addr_ty, offset, offset_ty, pos.func);
|
||||
}
|
||||
|
||||
/// Emit code for the base address computation of a `heap_addr` instruction.
|
||||
///
|
||||
///
|
||||
fn offset_addr(
|
||||
fn compute_addr(
|
||||
inst: ir::Inst,
|
||||
heap: ir::Heap,
|
||||
addr_ty: ir::Type,
|
||||
|
||||
@@ -26,11 +26,13 @@ mod globalvalue;
|
||||
mod heap;
|
||||
mod libcall;
|
||||
mod split;
|
||||
mod table;
|
||||
|
||||
use self::call::expand_call;
|
||||
use self::globalvalue::expand_global_value;
|
||||
use self::heap::expand_heap_addr;
|
||||
use self::libcall::expand_as_libcall;
|
||||
use self::table::expand_table_addr;
|
||||
|
||||
/// Legalize `inst` for `isa`. Return true if any changes to the code were
|
||||
/// made; return false if the instruction was successfully encoded as is.
|
||||
|
||||
115
lib/codegen/src/legalizer/table.rs
Normal file
115
lib/codegen/src/legalizer/table.rs
Normal file
@@ -0,0 +1,115 @@
|
||||
//! Legalization of tables.
|
||||
//!
|
||||
//! This module exports the `expand_table_addr` function which transforms a `table_addr`
|
||||
//! instruction into code that depends on the kind of table referenced.
|
||||
|
||||
use cursor::{Cursor, FuncCursor};
|
||||
use flowgraph::ControlFlowGraph;
|
||||
use ir::condcodes::IntCC;
|
||||
use ir::immediates::Offset32;
|
||||
use ir::{self, InstBuilder};
|
||||
use isa::TargetIsa;
|
||||
|
||||
/// Expand a `table_addr` instruction according to the definition of the table.
|
||||
pub fn expand_table_addr(
|
||||
inst: ir::Inst,
|
||||
func: &mut ir::Function,
|
||||
_cfg: &mut ControlFlowGraph,
|
||||
_isa: &TargetIsa,
|
||||
) {
|
||||
// Unpack the instruction.
|
||||
let (table, index, element_offset) = match func.dfg[inst] {
|
||||
ir::InstructionData::TableAddr {
|
||||
opcode,
|
||||
table,
|
||||
arg,
|
||||
offset,
|
||||
} => {
|
||||
debug_assert_eq!(opcode, ir::Opcode::TableAddr);
|
||||
(table, arg, offset)
|
||||
}
|
||||
_ => panic!("Wanted table_addr: {}", func.dfg.display_inst(inst, None)),
|
||||
};
|
||||
|
||||
dynamic_addr(inst, table, index, element_offset, func);
|
||||
}
|
||||
|
||||
/// Expand a `table_addr` for a dynamic table.
|
||||
fn dynamic_addr(
|
||||
inst: ir::Inst,
|
||||
table: ir::Table,
|
||||
index: ir::Value,
|
||||
element_offset: Offset32,
|
||||
func: &mut ir::Function,
|
||||
) {
|
||||
let bound_gv = func.tables[table].bound_gv;
|
||||
let index_ty = func.dfg.value_type(index);
|
||||
let addr_ty = func.dfg.value_type(func.dfg.first_result(inst));
|
||||
let mut pos = FuncCursor::new(func).at_inst(inst);
|
||||
pos.use_srcloc(inst);
|
||||
|
||||
// Start with the bounds check. Trap if `index + 1 > bound`.
|
||||
let bound = pos.ins().global_value(addr_ty, bound_gv);
|
||||
|
||||
// `index > bound - 1` is the same as `index >= bound`.
|
||||
let oob = pos
|
||||
.ins()
|
||||
.icmp(IntCC::UnsignedGreaterThanOrEqual, index, bound);
|
||||
pos.ins().trapnz(oob, ir::TrapCode::TableOutOfBounds);
|
||||
|
||||
compute_addr(
|
||||
inst,
|
||||
table,
|
||||
addr_ty,
|
||||
index,
|
||||
index_ty,
|
||||
element_offset,
|
||||
pos.func,
|
||||
);
|
||||
}
|
||||
|
||||
/// Emit code for the base address computation of a `table_addr` instruction.
|
||||
fn compute_addr(
|
||||
inst: ir::Inst,
|
||||
table: ir::Table,
|
||||
addr_ty: ir::Type,
|
||||
mut index: ir::Value,
|
||||
index_ty: ir::Type,
|
||||
element_offset: Offset32,
|
||||
func: &mut ir::Function,
|
||||
) {
|
||||
let mut pos = FuncCursor::new(func).at_inst(inst);
|
||||
pos.use_srcloc(inst);
|
||||
|
||||
// Convert `index` to `addr_ty`.
|
||||
if index_ty != addr_ty {
|
||||
index = pos.ins().uextend(addr_ty, index);
|
||||
}
|
||||
|
||||
// Add the table base address base
|
||||
let base_gv = pos.func.tables[table].base_gv;
|
||||
let base = pos.ins().global_value(addr_ty, base_gv);
|
||||
|
||||
let element_size = pos.func.tables[table].element_size;
|
||||
let mut offset;
|
||||
let element_size_i64: i64 = element_size.into();
|
||||
debug_assert!(element_size_i64 >= 0);
|
||||
let element_size_u64 = element_size_i64 as u64;
|
||||
if element_size_u64 == 1 {
|
||||
offset = index;
|
||||
} else if element_size_u64.is_power_of_two() {
|
||||
offset = pos
|
||||
.ins()
|
||||
.ishl_imm(index, i64::from(element_size_u64.trailing_zeros()));
|
||||
} else {
|
||||
offset = pos.ins().imul_imm(index, element_size);
|
||||
}
|
||||
|
||||
if element_offset == Offset32::new(0) {
|
||||
pos.func.dfg.replace(inst).iadd(base, offset);
|
||||
} else {
|
||||
let imm: i64 = element_offset.into();
|
||||
offset = pos.ins().iadd(base, offset);
|
||||
pos.func.dfg.replace(inst).iadd_imm(offset, imm);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user