Implement a poor man's jump table.
We will eventually support real jump tables, but for now just expand br_table into a sequence of conditional branches.
This commit is contained in:
@@ -48,3 +48,18 @@ function %undefined() {
|
|||||||
ebb0:
|
ebb0:
|
||||||
trap user0
|
trap user0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function %br_table(i32) {
|
||||||
|
jt0 = jump_table ebb3, ebb1, 0, ebb2
|
||||||
|
|
||||||
|
ebb0(v0: i32):
|
||||||
|
br_table v0, jt0
|
||||||
|
trap oob
|
||||||
|
|
||||||
|
ebb1:
|
||||||
|
return
|
||||||
|
ebb2:
|
||||||
|
return
|
||||||
|
ebb3:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ expand.custom_legalize(insts.heap_addr, 'expand_heap_addr')
|
|||||||
# TODO: Add sufficient XForm syntax that we don't need to hand-code these.
|
# TODO: Add sufficient XForm syntax that we don't need to hand-code these.
|
||||||
expand.custom_legalize(insts.trapz, 'expand_cond_trap')
|
expand.custom_legalize(insts.trapz, 'expand_cond_trap')
|
||||||
expand.custom_legalize(insts.trapnz, 'expand_cond_trap')
|
expand.custom_legalize(insts.trapnz, 'expand_cond_trap')
|
||||||
|
expand.custom_legalize(insts.br_table, 'expand_br_table')
|
||||||
|
|
||||||
# Custom expansions for floating point constants.
|
# Custom expansions for floating point constants.
|
||||||
# These expansions require bit-casting or creating constant pool entries.
|
# These expansions require bit-casting or creating constant pool entries.
|
||||||
|
|||||||
@@ -39,6 +39,11 @@ impl JumpTableData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the number of table entries.
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.table.len()
|
||||||
|
}
|
||||||
|
|
||||||
/// Set a table entry.
|
/// Set a table entry.
|
||||||
///
|
///
|
||||||
/// The table will grow as needed to fit `idx`.
|
/// The table will grow as needed to fit `idx`.
|
||||||
|
|||||||
@@ -147,6 +147,38 @@ fn expand_cond_trap(inst: ir::Inst, func: &mut ir::Function, cfg: &mut ControlFl
|
|||||||
cfg.recompute_ebb(pos.func, new_ebb);
|
cfg.recompute_ebb(pos.func, new_ebb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Jump tables.
|
||||||
|
fn expand_br_table(inst: ir::Inst, func: &mut ir::Function, cfg: &mut ControlFlowGraph) {
|
||||||
|
use ir::condcodes::IntCC;
|
||||||
|
|
||||||
|
let (arg, table) = match func.dfg[inst] {
|
||||||
|
ir::InstructionData::BranchTable {
|
||||||
|
opcode: ir::Opcode::BrTable,
|
||||||
|
arg,
|
||||||
|
table,
|
||||||
|
} => (arg, table),
|
||||||
|
_ => panic!("Expected br_table: {}", func.dfg.display_inst(inst, None)),
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is a poor man's jump table using just a sequence of conditional branches.
|
||||||
|
// TODO: Lower into a jump table load and indirect branch.
|
||||||
|
let table_size = func.jump_tables[table].len();
|
||||||
|
let mut pos = FuncCursor::new(func).at_inst(inst);
|
||||||
|
pos.use_srcloc(inst);
|
||||||
|
|
||||||
|
for i in 0..table_size {
|
||||||
|
if let Some(dest) = pos.func.jump_tables[table].get_entry(i) {
|
||||||
|
let t = pos.ins().icmp_imm(IntCC::Equal, arg, i as i64);
|
||||||
|
pos.ins().brnz(t, dest, &[]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// `br_table` falls through when nothing matches.
|
||||||
|
let ebb = pos.current_ebb().unwrap();
|
||||||
|
pos.remove_inst();
|
||||||
|
cfg.recompute_ebb(pos.func, ebb);
|
||||||
|
}
|
||||||
|
|
||||||
/// Expand illegal `f32const` and `f64const` instructions.
|
/// Expand illegal `f32const` and `f64const` instructions.
|
||||||
fn expand_fconst(inst: ir::Inst, func: &mut ir::Function, _cfg: &mut ControlFlowGraph) {
|
fn expand_fconst(inst: ir::Inst, func: &mut ir::Function, _cfg: &mut ControlFlowGraph) {
|
||||||
let ty = func.dfg.value_type(func.dfg.first_result(inst));
|
let ty = func.dfg.value_type(func.dfg.first_result(inst));
|
||||||
|
|||||||
Reference in New Issue
Block a user