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:
Jakob Stoklund Olesen
2017-09-25 10:56:14 -07:00
parent 29dfcf5dfb
commit fdb97da21b
4 changed files with 53 additions and 0 deletions

View File

@@ -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
}

View File

@@ -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.

View File

@@ -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`.

View File

@@ -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));