Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions libs/jit/src/jit_arm32_asm.erl
Original file line number Diff line number Diff line change
Expand Up @@ -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,
<<Instr:32/little>>;
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),
<<Instr:32/little>>;
push(RegList) ->
RegMask = reglist_to_mask(RegList),
%% STMDB SP!: cond=AL 1001 0010 1101 reglist
Expand All @@ -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,
<<Instr:32/little>>;
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),
<<Instr:32/little>>;
pop(RegList) ->
RegMask = reglist_to_mask(RegList),
%% LDMIA SP!: cond=AL 1000 1011 1101 reglist
Expand Down
18 changes: 12 additions & 6 deletions tests/libs/jit/jit_arm32_asm_tests.erl
Original file line number Diff line number Diff line change
Expand Up @@ -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])
),
Expand All @@ -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])
),
Expand Down
Loading