machinst x64: use a sign-extension when loading jump table offsets;
The jump table offset that's loaded out of the jump table could be signed (if it's an offset to before the jump table itself), so we should use a signed extension there, not an unsigned extension.
This commit is contained in:
@@ -1462,7 +1462,7 @@ pub(crate) fn emit(
|
|||||||
// jnb $default_target
|
// jnb $default_target
|
||||||
// movl %idx, %tmp2
|
// movl %idx, %tmp2
|
||||||
// lea start_of_jump_table_offset(%rip), %tmp1
|
// lea start_of_jump_table_offset(%rip), %tmp1
|
||||||
// movzlq [%tmp1, %tmp2], %tmp2
|
// movslq [%tmp1, %tmp2, 4], %tmp2 ;; shift of 2, viz. multiply index by 4
|
||||||
// addq %tmp2, %tmp1
|
// addq %tmp2, %tmp1
|
||||||
// j *%tmp1
|
// j *%tmp1
|
||||||
// $start_of_jump_table:
|
// $start_of_jump_table:
|
||||||
@@ -1485,8 +1485,9 @@ pub(crate) fn emit(
|
|||||||
);
|
);
|
||||||
inst.emit(sink, flags, state);
|
inst.emit(sink, flags, state);
|
||||||
|
|
||||||
// Load value out of jump table.
|
// Load value out of the jump table. It's a relative offset to the target block, so it
|
||||||
let inst = Inst::movzx_rm_r(
|
// might be negative; use a sign-extension.
|
||||||
|
let inst = Inst::movsx_rm_r(
|
||||||
ExtMode::LQ,
|
ExtMode::LQ,
|
||||||
RegMem::mem(Amode::imm_reg_reg_shift(0, tmp1.to_reg(), tmp2.to_reg(), 2)),
|
RegMem::mem(Amode::imm_reg_reg_shift(0, tmp1.to_reg(), tmp2.to_reg(), 2)),
|
||||||
*tmp2,
|
*tmp2,
|
||||||
|
|||||||
@@ -350,6 +350,7 @@ pub enum Inst {
|
|||||||
/// Jump-table sequence, as one compound instruction (see note in lower.rs for rationale).
|
/// Jump-table sequence, as one compound instruction (see note in lower.rs for rationale).
|
||||||
/// The generated code sequence is described in the emit's function match arm for this
|
/// The generated code sequence is described in the emit's function match arm for this
|
||||||
/// instruction.
|
/// instruction.
|
||||||
|
/// See comment in lowering about the temporaries signedness.
|
||||||
JmpTableSeq {
|
JmpTableSeq {
|
||||||
idx: Reg,
|
idx: Reg,
|
||||||
tmp1: Writable<Reg>,
|
tmp1: Writable<Reg>,
|
||||||
|
|||||||
@@ -1989,8 +1989,13 @@ impl LowerBackend for X64Backend {
|
|||||||
// is to introduce a relocation pass for inlined jumptables, which is much
|
// is to introduce a relocation pass for inlined jumptables, which is much
|
||||||
// worse.)
|
// worse.)
|
||||||
|
|
||||||
let tmp1 = ctx.alloc_tmp(RegClass::I64, I32);
|
// This temporary is used as a signed integer of 64-bits (to hold addresses).
|
||||||
let tmp2 = ctx.alloc_tmp(RegClass::I64, I32);
|
let tmp1 = ctx.alloc_tmp(RegClass::I64, I64);
|
||||||
|
// This temporary is used as a signed integer of 32-bits (for the wasm-table
|
||||||
|
// index) and then 64-bits (address addend). The small lie about the I64 type
|
||||||
|
// is benign, since the temporary is dead after this instruction (and its
|
||||||
|
// Cranelift type is thus unused).
|
||||||
|
let tmp2 = ctx.alloc_tmp(RegClass::I64, I64);
|
||||||
|
|
||||||
let targets_for_term: Vec<MachLabel> = targets.to_vec();
|
let targets_for_term: Vec<MachLabel> = targets.to_vec();
|
||||||
let default_target = BranchTarget::Label(targets[0]);
|
let default_target = BranchTarget::Label(targets[0]);
|
||||||
|
|||||||
Reference in New Issue
Block a user