x86_32: fix stack_addr encoding.

Consider this testcase:

    target i686
    function u0:0() -> i32 system_v {
        ss0 = explicit_slot 0
    block0:
        v2 = stack_addr.i32 ss0
        return v2
    }

Before this commit, in 32-bit mode the x86 backend would generate
incorrect code for stack addresses:

     0:   55                      push    ebp
     1:   89 e5                   mov     ebp, esp
     3:   83 ec 08                sub     esp, 8
     6:   8d 44 24 00             lea     eax, [esp]
     a:   00 00                   add     byte ptr [eax], al
     c:   00 83 c4 08 5d c3       add     byte ptr [ebx - 0x3ca2f73c], al

This happened because the ModRM byte indicated a disp8 encoding, but
the instruction actually used a disp32 encoding. After this commit,
correct code is generated:

     0:   55                      push    ebp
     1:   89 e5                   mov     ebp, esp
     3:   83 ec 08                sub     esp, 8
     6:   8d 84 24 00 00 00 00    lea     eax, [esp]
     d:   83 c4 08                add     esp, 8
    10:   5d                      pop     ebp
    11:   c3                      ret
This commit is contained in:
whitequark
2020-05-29 15:27:34 +00:00
committed by iximeow
parent 09ccdc9285
commit a180b5b393
3 changed files with 37 additions and 21 deletions

View File

@@ -2270,8 +2270,7 @@ fn define_entity_ref(
let rec_gvaddr8 = r.template("gvaddr8");
let rec_pcrel_fnaddr8 = r.template("pcrel_fnaddr8");
let rec_pcrel_gvaddr8 = r.template("pcrel_gvaddr8");
let rec_spaddr4_id = r.template("spaddr4_id");
let rec_spaddr8_id = r.template("spaddr8_id");
let rec_spaddr_id = r.template("spaddr_id");
// Predicates shorthands.
let all_ones_funcaddrs_and_not_is_pic =
@@ -2359,8 +2358,8 @@ fn define_entity_ref(
//
// TODO: Add encoding rules for stack_load and stack_store, so that they
// don't get legalized to stack_addr + load/store.
e.enc32(stack_addr.bind(I32), rec_spaddr4_id.opcodes(&LEA));
e.enc64(stack_addr.bind(I64), rec_spaddr8_id.opcodes(&LEA).rex().w());
e.enc64(stack_addr.bind(I64), rec_spaddr_id.opcodes(&LEA).rex().w());
e.enc32(stack_addr.bind(I32), rec_spaddr_id.opcodes(&LEA));
// Constant addresses (PIC).
e.enc64(const_addr.bind(I64), rec_const_addr.opcodes(&LEA).rex().w());

View File

@@ -1432,23 +1432,7 @@ pub(crate) fn define<'shared>(
// TODO Alternative forms for 8-bit immediates, when applicable.
recipes.add_template_recipe(
EncodingRecipeBuilder::new("spaddr4_id", &formats.stack_load, 6)
.operands_out(vec![gpr])
.emit(
r#"
let sp = StackRef::sp(stack_slot, &func.stack_slots);
let base = stk_base(sp.base);
{{PUT_OP}}(bits, rex2(out_reg0, base), sink);
modrm_sib_disp8(out_reg0, sink);
sib_noindex(base, sink);
let imm : i32 = offset.into();
sink.put4(sp.offset.checked_add(imm).unwrap() as u32);
"#,
),
);
recipes.add_template_recipe(
EncodingRecipeBuilder::new("spaddr8_id", &formats.stack_load, 6)
EncodingRecipeBuilder::new("spaddr_id", &formats.stack_load, 6)
.operands_out(vec![gpr])
.emit(
r#"