[arm] Handle backward jumps properly with TBH (PR#5623).

The Thumb-2 TBH instruction supports only forward jumps, which is what is
usually generated for Lswitch. But in some rare cases, the compiler can
generate backward jumps for Lswitch. To properly support these cases, we
emit appropriate trampolines (following the TBH) for these backward jumps
as necessary.



git-svn-id: http://caml.inria.fr/svn/ocaml/trunk@12548 f963ae5c-01c2-4b8c-9fe0-0dff7051ff02
master
Benedikt Meurer 2012-06-02 18:01:06 +00:00
parent 5b19f3e5be
commit deb410085d
1 changed files with 32 additions and 23 deletions

View File

@ -747,31 +747,40 @@ let emit_instr i =
4
| Lswitch jumptbl ->
if !arch > ARMv6 && !thumb then begin
let lbl = new_label() in
` tbh [pc, {emit_reg i.arg.(0)}]\n`;
`{emit_label lbl}:`;
for i = 0 to Array.length jumptbl - 1 do
` .short ({emit_label jumptbl.(i)}-{emit_label lbl})/2\n`;
(* The Thumb-2 TBH instruction supports only forward branches,
so we need to generate appropriate trampolines for all labels
that appear before this switch instruction (PR#5623) *)
let tramtbl = Array.copy jumptbl in
` tbh [pc, {emit_reg i.arg.(0)}, lsl #1]\n`;
for j = 0 to Array.length tramtbl - 1 do
let rec label i =
match i.desc with
Lend -> new_label()
| Llabel lbl when lbl = tramtbl.(j) -> lbl
| _ -> label i.next in
tramtbl.(j) <- label i.next;
` .short ({emit_label tramtbl.(j)}-.)/2+{emit_int j}\n`
done;
` .align 1\n`;
2 + Array.length jumptbl / 2
(* Generate the necessary trampolines *)
for j = 0 to Array.length tramtbl - 1 do
if tramtbl.(j) <> jumptbl.(j) then
`{emit_label tramtbl.(j)}: b {emit_label jumptbl.(j)}\n`
done
end else if not !pic_code then begin
` ldr pc, [pc, {emit_reg i.arg.(0)}, lsl #2]\n`;
` nop\n`;
for j = 0 to Array.length jumptbl - 1 do
` .word {emit_label jumptbl.(j)}\n`
done
end else begin
if not !pic_code then begin
` ldr pc, [pc, {emit_reg i.arg.(0)}, lsl #2]\n`;
` nop\n`;
for i = 0 to Array.length jumptbl - 1 do
` .word {emit_label jumptbl.(i)}\n`
done
end else begin
(* Slightly slower, but position-independent *)
` add pc, pc, {emit_reg i.arg.(0)}, lsl #2\n`;
` nop\n`;
for i = 0 to Array.length jumptbl - 1 do
` b {emit_label jumptbl.(i)}\n`
done
end;
2 + Array.length jumptbl
end
(* Slightly slower, but position-independent *)
` add pc, pc, {emit_reg i.arg.(0)}, lsl #2\n`;
` nop\n`;
for j = 0 to Array.length jumptbl - 1 do
` b {emit_label jumptbl.(j)}\n`
done
end;
2 + Array.length jumptbl
| Lsetuptrap lbl ->
` bl {emit_label lbl}\n`; 1
| Lpushtrap ->