diff --git a/libs/jit/src/jit_arm32_asm.erl b/libs/jit/src/jit_arm32_asm.erl index 41535d4675..aa38fd4d5f 100644 --- a/libs/jit/src/jit_arm32_asm.erl +++ b/libs/jit/src/jit_arm32_asm.erl @@ -506,6 +506,16 @@ blx(Cond, Rm) -> %% PUSH {reglist} = STMDB SP!, {reglist} %% Encoding: cond[31:28] 100 1 0 0 1 0 1101 reglist[15:0] -spec push([arm_gpr_register()]) -> binary(). +push([sp]) -> + %% GNU as uses STMDB for push {sp} (STR SP,[SP,#-4]! has undefined behavior) + RegMask = 1 bsl 13, + Instr = (14 bsl 28) bor (2#100100101101 bsl 16) bor RegMask, + <>; +push([Reg]) -> + %% STR Rd, [SP, #-4]!: single-register push (matches GNU as encoding) + RegNum = reg_to_num(Reg), + Instr = 16#E52D0004 bor (RegNum bsl 12), + <>; push(RegList) -> RegMask = reglist_to_mask(RegList), %% STMDB SP!: cond=AL 1001 0010 1101 reglist @@ -515,6 +525,16 @@ push(RegList) -> %% POP {reglist} = LDMIA SP!, {reglist} %% Encoding: cond[31:28] 100 0 1 0 1 1 1101 reglist[15:0] -spec pop([arm_gpr_register()]) -> binary(). +pop([sp]) -> + %% GNU as uses LDMIA for pop {sp} (LDR SP,[SP],#4 has undefined behavior) + RegMask = 1 bsl 13, + Instr = (14 bsl 28) bor (2#100010111101 bsl 16) bor RegMask, + <>; +pop([Reg]) -> + %% LDR Rd, [SP], #4: single-register pop (matches GNU as encoding) + RegNum = reg_to_num(Reg), + Instr = 16#E49D0004 bor (RegNum bsl 12), + <>; pop(RegList) -> RegMask = reglist_to_mask(RegList), %% LDMIA SP!: cond=AL 1000 1011 1101 reglist diff --git a/tests/libs/jit/jit_arm32_asm_tests.erl b/tests/libs/jit/jit_arm32_asm_tests.erl index d6b7e4d562..06af5e1b96 100644 --- a/tests/libs/jit/jit_arm32_asm_tests.erl +++ b/tests/libs/jit/jit_arm32_asm_tests.erl @@ -280,12 +280,15 @@ blx_test_() -> push_test_() -> [ - %% PUSH (STMDB SP!) - ?_assertAsmEqual(<<16#E92D0001:32/little>>, "push {r0}", jit_arm32_asm:push([r0])), + %% single-register PUSH = STR Rd, [SP, #-4]! + ?_assertAsmEqual(<<16#E52D0004:32/little>>, "push {r0}", jit_arm32_asm:push([r0])), + %% gcc as accepts to encode this, even if behavior is undefined + ?_assertAsmEqual(<<16#E92D2000:32/little>>, "push {sp}", jit_arm32_asm:push([sp])), + %% multi-register PUSH = STMDB SP! ?_assertAsmEqual( <<16#E92D0007:32/little>>, "push {r0, r1, r2}", jit_arm32_asm:push([r0, r1, r2]) ), - ?_assertAsmEqual(<<16#E92D4000:32/little>>, "push {lr}", jit_arm32_asm:push([lr])), + ?_assertAsmEqual(<<16#E52DE004:32/little>>, "push {lr}", jit_arm32_asm:push([lr])), ?_assertAsmEqual( <<16#E92D4007:32/little>>, "push {r0, r1, r2, lr}", jit_arm32_asm:push([r0, r1, r2, lr]) ), @@ -298,12 +301,15 @@ push_test_() -> pop_test_() -> [ - %% POP (LDMIA SP!) - ?_assertAsmEqual(<<16#E8BD0001:32/little>>, "pop {r0}", jit_arm32_asm:pop([r0])), + %% single-register POP = LDR Rd, [SP], #4 + ?_assertAsmEqual(<<16#E49D0004:32/little>>, "pop {r0}", jit_arm32_asm:pop([r0])), + %% gcc as accepts to encode this, even if behavior is undefined + ?_assertAsmEqual(<<16#E8BD2000:32/little>>, "pop {sp}", jit_arm32_asm:pop([sp])), + %% multi-register POP = LDMIA SP! ?_assertAsmEqual( <<16#E8BD0007:32/little>>, "pop {r0, r1, r2}", jit_arm32_asm:pop([r0, r1, r2]) ), - ?_assertAsmEqual(<<16#E8BD8000:32/little>>, "pop {pc}", jit_arm32_asm:pop([pc])), + ?_assertAsmEqual(<<16#E49DF004:32/little>>, "pop {pc}", jit_arm32_asm:pop([pc])), ?_assertAsmEqual( <<16#E8BD8007:32/little>>, "pop {r0, r1, r2, pc}", jit_arm32_asm:pop([r0, r1, r2, pc]) ),