Add custom legalization for conditional traps.

The expansion of these instructions requires the CFG to be modified,
something the Python XForms can't yet do.
This commit is contained in:
Jakob Stoklund Olesen
2017-08-25 12:40:43 -07:00
parent 6d9198d55f
commit 217434b474
3 changed files with 82 additions and 1 deletions

View File

@@ -0,0 +1,30 @@
; Test the custom legalizations.
test legalizer
isa intel
set is_64bit
isa intel
; regex: V=v\d+
; regex: EBB=ebb\d+
function %cond_trap(i32) {
ebb0(v1: i32):
trapz v1
return
; check: $ebb0($v1: i32):
; nextln: brnz $v1, $(new=$EBB)
; nextln: trap
; check: $new:
; nextln: return
}
function %cond_trap2(i32) {
ebb0(v1: i32):
trapnz v1
return
; check: $ebb0($v1: i32):
; nextln: brz $v1, $(new=$EBB)
; nextln: trap
; check: $new:
; nextln: return
}

View File

@@ -48,6 +48,11 @@ expand = XFormGroup('expand', """
expand.custom_legalize(insts.global_addr, 'expand_global_addr')
expand.custom_legalize(insts.heap_addr, 'expand_heap_addr')
# Custom expansions that need to change the CFG.
# 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.trapnz, 'expand_cond_trap')
x = Var('x')
y = Var('y')
a = Var('a')

View File

@@ -15,7 +15,7 @@
use cursor::{Cursor, FuncCursor};
use flowgraph::ControlFlowGraph;
use ir;
use ir::{self, InstBuilder};
use isa::TargetIsa;
use bitset::BitSet;
@@ -96,3 +96,49 @@ pub fn legalize_function(func: &mut ir::Function, cfg: &mut ControlFlowGraph, is
//
// Concretely, this defines private functions `narrow()`, and `expand()`.
include!(concat!(env!("OUT_DIR"), "/legalizer.rs"));
/// Custom expansion for conditional trap instructions.
/// TODO: Add CFG support to the Python patterns so we won't have to do this.
fn expand_cond_trap(inst: ir::Inst, func: &mut ir::Function, cfg: &mut ControlFlowGraph) {
// Parse the instruction.
let trapz;
let arg = match func.dfg[inst] {
ir::InstructionData::Unary { opcode, arg } => {
// We want to branch *over* an unconditional trap.
trapz = match opcode {
ir::Opcode::Trapz => true,
ir::Opcode::Trapnz => false,
_ => panic!("Expected cond trap: {}", func.dfg.display_inst(inst, None)),
};
arg
}
_ => panic!("Expected cond trap: {}", func.dfg.display_inst(inst, None)),
};
// Split the EBB after `inst`:
//
// trapnz arg
//
// Becomes:
//
// brz arg, new_ebb
// trap
// new_ebb:
//
let old_ebb = func.layout.pp_ebb(inst);
let new_ebb = func.dfg.make_ebb();
if trapz {
func.dfg.replace(inst).brnz(arg, new_ebb, &[]);
} else {
func.dfg.replace(inst).brz(arg, new_ebb, &[]);
}
let mut pos = FuncCursor::new(func).at_inst(inst);
pos.next_inst();
pos.ins().trap();
pos.insert_ebb(new_ebb);
// Finally update the CFG.
cfg.recompute_ebb(pos.func, old_ebb);
cfg.recompute_ebb(pos.func, new_ebb);
}