Skip to content
Open
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
8 changes: 8 additions & 0 deletions changes/01-feature/1439-regalloc-hints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
- Experimental register-allocation hints. These hints are best-effort: they are
not part of the compiler correctness of Jasmin. The annotation is
case-sensitive and uses architecture-specific register names: e.g., `RAX` on
x86-64, `r0` on arm-m4, `x10`, `ra` on risc-v. `#[force_regalloc=REG]`
forces a `reg` variable to the named register. For example, on x86-64:
```
#[force_regalloc=RAX] reg u64 x;
```
39 changes: 39 additions & 0 deletions compiler/src/regalloc.ml
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,43 @@ module Regalloc (Arch : Arch_full.Arch)
let cnf = List.fold_left2 (force_constraint var_of_expr) cnf id.i_in es in
cnf

let force_regalloc_name = "force_regalloc"

let parse_force_regalloc x =
let on_name loc _ s =
try List.find (fun r -> r.v_name = s) Arch.all_registers
with Not_found ->
hierror_reg ~loc:(Lone loc)
"unknown register “%s” in %s annotation on variable %a"
s force_regalloc_name (Printer.pp_var ~debug:true) x
in
let on_error loc _ =
hierror_reg ~loc:(Lone loc)
"the “%s” annotation on variable %a requires a register name"
force_regalloc_name (Printer.pp_var ~debug:true) x
in
let on_attr =
Annot.on_attribute ~on_id:on_name ~on_string:on_name on_error
in
Annot.ensure_uniq1 force_regalloc_name on_attr x.v_annot

let allocate_hints nv vars a cnf =
let allocate_one x i y =
if types_cannot_conflict Arch.reg_size x.v_kind x.v_ty y.v_kind y.v_ty
then hierror_reg ~loc:Lnone
"variable %a (declared at %a with type \"%a\") must be allocated \
to register %a with an incompatible type"
(Printer.pp_var ~debug:true) x
L.pp_sloc x.v_dloc
PrintCommon.pp_ty x.v_ty
(Printer.pp_var ~debug:false) y;
allocate_one nv vars L.i_dummy cnf x i y a
in
let apply_force_regalloc x i =
parse_force_regalloc x |> Option.may (allocate_one x i)
in
Hv.iter apply_force_regalloc vars;
cnf

let stable_call_conv = "stable_call_conv"

Expand Down Expand Up @@ -1451,6 +1488,8 @@ let global_allocation return_addresses (funcs: ('info, 'asm) func list) :
funcs
in

let conflicts = allocate_hints nv vars a conflicts in

if !Glob_options.print_liveness then pp_liveness vars liveness_per_callsite liveness_table a;

greedy_allocation vars nv conflicts fr a;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export fn main(reg u32 a) -> reg u32 {
#[force_regalloc=r4, force_regalloc=r5] reg u32 x;
reg u32 r;
x = 1;
x += a;
r = x;
return r;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export fn main(reg u32 a) -> reg u32 {
#[force_regalloc=x18, force_regalloc=x19] reg u32 x;
reg u32 r;
x = 1;
x += a;
r = x;
return r;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export fn main(reg u64 a) -> reg u64 {
#[force_regalloc=RAX, force_regalloc=RCX] reg u64 x;
reg u64 r;
x = 1;
x += a;
r = x;
return r;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export fn main() -> reg u64 {
reg u64 hi lo d;
hi = 0;
lo = 7;
d = 2;
#[force_regalloc=RCX] reg u64 q;
reg u64 r;
?{RAX=q, RDX=r} = #DIV(hi, lo, d);
q ^= r;
return q;
}
19 changes: 15 additions & 4 deletions compiler/tests/negative.expected
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,9 @@ fail/register_allocation/arm-m4/bug_201.jazz:
compilation error in function main:
register allocation: too many large parameters according to the ABI (only 0 available on this architecture)

fail/register_allocation/arm-m4/no_mmx.jazz:
fail/register_allocation/arm-m4/force_regalloc_dup.jazz:

"fail/register_allocation/arm-m4/force_regalloc_dup.jazz", line 2 (4-18): only one of the attribute force_regalloc, force_regalloc is expectedfail/register_allocation/arm-m4/no_mmx.jazz:

compilation error:
register allocation: unable to allocate tmp (defined at "fail/register_allocation/arm-m4/no_mmx.jazz", line 6 (2-5)): bank “extra (aka mmx)” is empty on this architecture
Expand Down Expand Up @@ -800,7 +802,9 @@ fail/register_allocation/arm-m4/too_many_ret.jazz:
compilation error in function too_many_ret:
register allocation: too many return values according to the ABI (only 2 available on this architecture)

fail/register_allocation/x86-64/already_allocated.jazz:
fail/register_allocation/risc-v/force_regalloc_dup.jazz:

"fail/register_allocation/risc-v/force_regalloc_dup.jazz", line 2 (4-18): only one of the attribute force_regalloc, force_regalloc is expectedfail/register_allocation/x86-64/already_allocated.jazz:

"fail/register_allocation/x86-64/already_allocated.jazz", line 10 (0-22):
compilation error:
Expand Down Expand Up @@ -861,6 +865,13 @@ register allocation: conflicting variables “z” and “res” must be merged
at "fail/register_allocation/x86-64/conflicting_variables.jazz", line 11 (2-14):
res = f(z);

fail/register_allocation/x86-64/force_regalloc_dup.jazz:

"fail/register_allocation/x86-64/force_regalloc_dup.jazz", line 2 (4-18): only one of the attribute force_regalloc, force_regalloc is expectedfail/register_allocation/x86-64/force_regalloc_vs_arch.jazz:

compilation error:
register allocation: cannot allocate q into RCX, the variable is already allocated in RAX

fail/register_allocation/x86-64/merge_across_banks.jazz:

"fail/register_allocation/x86-64/merge_across_banks.jazz", line 3 (2-12):
Expand Down Expand Up @@ -1572,8 +1583,8 @@ Allowed args are:
[[reg]; [reg; mem (glob allowed)]]

Statistics:
Annots: 0
Annots: 3
Pretyping: 51
Parsing: 4
Typing: 1
Compile: 194
Compile: 195
8 changes: 8 additions & 0 deletions compiler/tests/success/arm-m4/force_regalloc.jazz
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export fn main(reg u32 a) -> reg u32 {
#[force_regalloc=r4] reg u32 x;
reg u32 r;
x = 1;
x += a;
r = x;
return r;
}
8 changes: 8 additions & 0 deletions compiler/tests/success/risc-v/force_regalloc.jazz
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export fn main(reg u32 a) -> reg u32 {
#[force_regalloc=x18] reg u32 x;
reg u32 r;
x = 1;
x += a;
r = x;
return r;
}
10 changes: 10 additions & 0 deletions compiler/tests/success/x86-64/force_regalloc.jazz
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// The compiler inserts self-assignments before and after the body of the
// export function, but they inherit the annotations, so we must pick RAX
// here.

export fn main(reg u64 a) -> reg u64 {
#[force_regalloc=RAX] reg u64 x;
x = a;
x += 1;
return x;
}