ARM64: revised generation of ADD/SUB/CMP immediate
- Support a wider range of immediate values for ADD and SUB, using two instructions when needed (add/sub middle 12 bits then low 12 bits). - Do not rely on the assembler to convert CMP immediate negative to CMN immediate.master
parent
65544ffd1f
commit
cc25ceaaec
|
@ -321,6 +321,37 @@ let output_epilogue f =
|
|||
(* reset CFA back because function body may continue *)
|
||||
if n > 0 then cfi_adjust_cfa_offset n
|
||||
|
||||
(* Output add-immediate / sub-immediate / cmp-immediate instructions *)
|
||||
|
||||
let rec emit_addimm rd rs n =
|
||||
if n < 0 then emit_subimm rd rs (-n)
|
||||
else if n <= 0xFFF then
|
||||
` add {emit_reg rd}, {emit_reg rs}, #{emit_int n}\n`
|
||||
else begin
|
||||
assert (n <= 0xFFF_FFF);
|
||||
let nl = n land 0xFFF and nh = n land 0xFFF_000 in
|
||||
` add {emit_reg rd}, {emit_reg rs}, #{emit_int nh}\n`;
|
||||
if nl <> 0 then
|
||||
` add {emit_reg rd}, {emit_reg rd}, #{emit_int nl}\n`
|
||||
end
|
||||
|
||||
and emit_subimm rd rs n =
|
||||
if n < 0 then emit_addimm rd rs (-n)
|
||||
else if n <= 0xFFF then
|
||||
` sub {emit_reg rd}, {emit_reg rs}, #{emit_int n}\n`
|
||||
else begin
|
||||
assert (n <= 0xFFF_FFF);
|
||||
let nl = n land 0xFFF and nh = n land 0xFFF_000 in
|
||||
` sub {emit_reg rd}, {emit_reg rs}, #{emit_int nh}\n`;
|
||||
if nl <> 0 then
|
||||
` sub {emit_reg rd}, {emit_reg rd}, #{emit_int nl}\n`
|
||||
end
|
||||
|
||||
let emit_cmpimm rs n =
|
||||
if n >= 0
|
||||
then ` cmp {emit_reg rs}, #{emit_int n}\n`
|
||||
else ` cmn {emit_reg rs}, #{emit_int (-n)}\n`
|
||||
|
||||
(* Name of current function *)
|
||||
let function_name = ref ""
|
||||
(* Entry point for tail recursive calls *)
|
||||
|
@ -746,11 +777,15 @@ let emit_instr i =
|
|||
assembly_code_for_allocation i ~n ~far:false ~label_after_call_gc ~dbginfo
|
||||
| Lop(Ispecific (Ifar_alloc { bytes = n; label_after_call_gc; dbginfo })) ->
|
||||
assembly_code_for_allocation i ~n ~far:true ~label_after_call_gc ~dbginfo
|
||||
| Lop(Iintop_imm(Iadd, n)) ->
|
||||
emit_addimm i.res.(0) i.arg.(0) n
|
||||
| Lop(Iintop_imm(Isub, n)) ->
|
||||
emit_subimm i.res.(0) i.arg.(0) n
|
||||
| Lop(Iintop(Icomp cmp)) ->
|
||||
` cmp {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`;
|
||||
` cset {emit_reg i.res.(0)}, {emit_string (name_for_comparison cmp)}\n`
|
||||
| Lop(Iintop_imm(Icomp cmp, n)) ->
|
||||
` cmp {emit_reg i.arg.(0)}, #{emit_int n}\n`;
|
||||
emit_cmpimm i.arg.(0) n;
|
||||
` cset {emit_reg i.res.(0)}, {emit_string (name_for_comparison cmp)}\n`
|
||||
| Lop(Iintop (Icheckbound { label_after_error; })) ->
|
||||
let lbl = bound_error_label i.dbg ?label:label_after_error in
|
||||
|
@ -765,7 +800,7 @@ let emit_instr i =
|
|||
`{emit_label lbl2}:\n`;
|
||||
| Lop(Iintop_imm(Icheckbound { label_after_error; }, n)) ->
|
||||
let lbl = bound_error_label i.dbg ?label:label_after_error in
|
||||
` cmp {emit_reg i.arg.(0)}, #{emit_int n}\n`;
|
||||
emit_cmpimm i.arg.(0) n;
|
||||
` b.ls {emit_label lbl}\n`
|
||||
| Lop(Ispecific(
|
||||
Ifar_intop_imm_checkbound { bound; label_after_error; })) ->
|
||||
|
@ -869,7 +904,7 @@ let emit_instr i =
|
|||
let comp = name_for_comparison cmp in
|
||||
` b.{emit_string comp} {emit_label lbl}\n`
|
||||
| Iinttest_imm(cmp, n) ->
|
||||
` cmp {emit_reg i.arg.(0)}, #{emit_int n}\n`;
|
||||
emit_cmpimm i.arg.(0) n;
|
||||
let comp = name_for_comparison cmp in
|
||||
` b.{emit_string comp} {emit_label lbl}\n`
|
||||
| Ifloattest cmp ->
|
||||
|
|
|
@ -108,7 +108,7 @@ method is_immediate_test _cmp n =
|
|||
|
||||
method is_immediate op n =
|
||||
match op with
|
||||
| Iadd | Isub -> is_immediate n
|
||||
| Iadd | Isub -> n <= 0xFFF_FFF && n >= -0xFFF_FFF
|
||||
| Imul | Imulh -> false (* no mul immediate instruction *)
|
||||
| Iand | Ior | Ixor -> is_logical_immediate n
|
||||
| Icomp _ | Icheckbound _ -> is_immediate n
|
||||
|
|
Loading…
Reference in New Issue