Simplify jump table instructions and add missing conversion;

This makes non-legalized jump table instructions operate on operands with
pointer-sized types. This means we need to extend smaller types into the
pointer-sized operand, when the two don't match.
This commit is contained in:
Benjamin Bouvier
2019-08-01 17:05:38 +02:00
parent f0d7438728
commit 627ba24b59
5 changed files with 27 additions and 27 deletions

View File

@@ -1224,13 +1224,10 @@ pub fn define(
// Jump tables. // Jump tables.
e.enc64( e.enc64(
jump_table_entry.bind(I64).bind_any().bind_any(), jump_table_entry.bind(I64),
rec_jt_entry.opcodes(vec![0x63]).rex().w(), rec_jt_entry.opcodes(vec![0x63]).rex().w(),
); );
e.enc32( e.enc32(jump_table_entry.bind(I32), rec_jt_entry.opcodes(vec![0x8b]));
jump_table_entry.bind(I32).bind_any().bind_any(),
rec_jt_entry.opcodes(vec![0x8b]),
);
e.enc64( e.enc64(
jump_table_base.bind(I64), jump_table_base.bind(I64),

View File

@@ -269,15 +269,9 @@ pub fn define(
.is_branch(true), .is_branch(true),
); );
// The index into the br_table can be any type; legalizer will convert it to the right type.
let x = &operand_doc("x", iB, "index into jump table"); let x = &operand_doc("x", iB, "index into jump table");
let entry = &operand_doc("entry", iAddr, "entry of jump table");
let Entry = &TypeVar::new(
"Entry",
"A scalar integer type",
TypeSetBuilder::new().ints(Interval::All).build(),
);
let entry = &operand_doc("entry", Entry, "entry of jump table");
let JT = &operand("JT", jump_table); let JT = &operand("JT", jump_table);
ig.push( ig.push(
@@ -305,6 +299,9 @@ pub fn define(
.is_branch(true), .is_branch(true),
); );
// These are the instructions which br_table legalizes to: they perform address computations,
// using pointer-sized integers, so their type variables are more constrained.
let x = &operand_doc("x", iAddr, "index into jump table");
let Size = &operand_doc("Size", uimm8, "Size in bytes"); let Size = &operand_doc("Size", uimm8, "Size in bytes");
ig.push( ig.push(
@@ -2644,11 +2641,11 @@ pub fn define(
Cast the bits in `x` as a different type of the same bit width. Cast the bits in `x` as a different type of the same bit width.
This instruction does not change the data's representation but allows This instruction does not change the data's representation but allows
data in registers to be used as different types, e.g. an i32x4 as a data in registers to be used as different types, e.g. an i32x4 as a
b8x16. The only constraint on the result `a` is that it can be b8x16. The only constraint on the result `a` is that it can be
`raw_bitcast` back to the original type. Also, in a raw_bitcast between `raw_bitcast` back to the original type. Also, in a raw_bitcast between
vector types with the same number of lanes, the value of each result vector types with the same number of lanes, the value of each result
lane is a raw_bitcast of the corresponding operand lane. TODO there is lane is a raw_bitcast of the corresponding operand lane. TODO there is
currently no mechanism for enforcing the bit width constraint. currently no mechanism for enforcing the bit width constraint.
"#, "#,
) )

View File

@@ -240,29 +240,34 @@ fn expand_br_table_jt(
// $addr = iadd $base, $rel_addr // $addr = iadd $base, $rel_addr
// indirect_jump_table_br $addr, $jt // indirect_jump_table_br $addr, $jt
let table_size = func.jump_tables[table].len();
let addr_ty = isa.pointer_type();
let entry_ty = I32;
let ebb = func.layout.pp_ebb(inst); let ebb = func.layout.pp_ebb(inst);
let jump_table_ebb = func.dfg.make_ebb(); let jump_table_ebb = func.dfg.make_ebb();
let mut pos = FuncCursor::new(func).at_inst(inst); let mut pos = FuncCursor::new(func).at_inst(inst);
pos.use_srcloc(inst); pos.use_srcloc(inst);
// Bounds check // Bounds check.
let table_size = pos.func.jump_tables[table].len() as i64;
let oob = pos let oob = pos
.ins() .ins()
.icmp_imm(IntCC::UnsignedGreaterThanOrEqual, arg, table_size as i64); .icmp_imm(IntCC::UnsignedGreaterThanOrEqual, arg, table_size);
pos.ins().brnz(oob, default_ebb, &[]); pos.ins().brnz(oob, default_ebb, &[]);
pos.ins().jump(jump_table_ebb, &[]); pos.ins().jump(jump_table_ebb, &[]);
pos.insert_ebb(jump_table_ebb); pos.insert_ebb(jump_table_ebb);
let addr_ty = isa.pointer_type();
let arg = if pos.func.dfg.value_type(arg) == addr_ty {
arg
} else {
pos.ins().uextend(addr_ty, arg)
};
let base_addr = pos.ins().jump_table_base(addr_ty, table); let base_addr = pos.ins().jump_table_base(addr_ty, table);
let entry = pos let entry = pos
.ins() .ins()
.jump_table_entry(addr_ty, arg, base_addr, entry_ty.bytes() as u8, table); .jump_table_entry(arg, base_addr, I32.bytes() as u8, table);
let addr = pos.ins().iadd(base_addr, entry); let addr = pos.ins().iadd(base_addr, entry);
pos.ins().indirect_jump_table_br(addr, table); pos.ins().indirect_jump_table_br(addr, table);

View File

@@ -16,8 +16,9 @@ ebb0(v0: i64):
; nextln: brif uge $oob, ebb2 ; nextln: brif uge $oob, ebb2
; nextln: fallthrough $(inb=$EBB) ; nextln: fallthrough $(inb=$EBB)
; check: $inb: ; check: $inb:
; nextln: $(final_idx=$V) = uextend.i64 $idx
; nextln: $(base=$V) = jump_table_base.i64 jt0 ; nextln: $(base=$V) = jump_table_base.i64 jt0
; nextln: $(rel_addr=$V) = jump_table_entry.i64 $idx, $base, 4, jt0 ; nextln: $(rel_addr=$V) = jump_table_entry $final_idx, $base, 4, jt0
; nextln: $(addr=$V) = iadd $base, $rel_addr ; nextln: $(addr=$V) = iadd $base, $rel_addr
; nextln: indirect_jump_table_br $addr, jt0 ; nextln: indirect_jump_table_br $addr, jt0

View File

@@ -14,7 +14,7 @@ ebb1: ; the loop!
fallthrough ebb2 fallthrough ebb2
ebb2: ebb2:
v1 = iconst.i32 -14 v1 = iconst.i64 -14
v8 = ifcmp_imm v1, 2 v8 = ifcmp_imm v1, 2
brif uge v8, ebb1 brif uge v8, ebb1
jump ebb3 jump ebb3
@@ -25,7 +25,7 @@ ebb3:
v7 = iadd v5, v6 v7 = iadd v5, v6
indirect_jump_table_br v7, jt0 indirect_jump_table_br v7, jt0
; check: ebb2: ; check: ebb2:
; nextln: v8 = ifcmp_imm.i32 v1, 2 ; nextln: v8 = ifcmp_imm.i64 v1, 2
; nextln: brif uge v8, ebb1 ; nextln: brif uge v8, ebb1
; nextln: jump ebb3 ; nextln: jump ebb3
; check: ebb3: ; check: ebb3: