Make vreg constrs per-quad, regfence on nontrivial constrs, back out workaround to _uint, add regression test. Closes #152.
This commit is contained in:
parent
a7eeeb596a
commit
7cfa7bdd23
4 changed files with 73 additions and 49 deletions
|
@ -510,6 +510,7 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \
|
||||||
obj-with-vec.rs \
|
obj-with-vec.rs \
|
||||||
operator-associativity.rs \
|
operator-associativity.rs \
|
||||||
output-slot-variants.rs \
|
output-slot-variants.rs \
|
||||||
|
over-constrained-vregs.rs \
|
||||||
pred.rs \
|
pred.rs \
|
||||||
preempt.rs \
|
preempt.rs \
|
||||||
readalias.rs \
|
readalias.rs \
|
||||||
|
|
|
@ -322,38 +322,34 @@ let dump_quads cx =
|
||||||
done
|
done
|
||||||
;;
|
;;
|
||||||
|
|
||||||
let calculate_vreg_constraints (cx:ctxt) : Bits.t array =
|
let calculate_vreg_constraints
|
||||||
|
(cx:ctxt)
|
||||||
|
(constraints:Bits.t array)
|
||||||
|
(q:quad)
|
||||||
|
: unit =
|
||||||
let abi = cx.ctxt_abi in
|
let abi = cx.ctxt_abi in
|
||||||
let n_vregs = cx.ctxt_n_vregs in
|
Array.iter (fun c -> Bits.clear c; Bits.invert c) constraints;
|
||||||
let n_hregs = abi.Abi.abi_n_hardregs in
|
abi.Abi.abi_constrain_vregs q constraints;
|
||||||
let constraints = Array.init n_vregs (fun _ -> Bits.create n_hregs true) in
|
iflog cx
|
||||||
Array.iteri
|
|
||||||
begin
|
begin
|
||||||
fun i q ->
|
fun _ ->
|
||||||
abi.Abi.abi_constrain_vregs q constraints;
|
let hr_str = cx.ctxt_abi.Abi.abi_str_of_hardreg in
|
||||||
iflog cx
|
log cx "constraints for quad %s"
|
||||||
begin
|
(string_of_quad hr_str q);
|
||||||
fun _ ->
|
let qp_reg _ r =
|
||||||
let hr_str = cx.ctxt_abi.Abi.abi_str_of_hardreg in
|
begin
|
||||||
log cx "constraints for quad %d = %s"
|
match r with
|
||||||
i (string_of_quad hr_str q);
|
Il.Hreg _ -> ()
|
||||||
let qp_reg _ r =
|
| Il.Vreg v ->
|
||||||
begin
|
let hregs = Bits.to_list constraints.(v) in
|
||||||
match r with
|
log cx "<v%d> constrained to hregs: [%s]"
|
||||||
Il.Hreg _ -> ()
|
v (list_to_str hregs hr_str)
|
||||||
| Il.Vreg v ->
|
end;
|
||||||
let hregs = Bits.to_list constraints.(v) in
|
r
|
||||||
log cx "<v%d> constrained to hregs: [%s]"
|
in
|
||||||
v (list_to_str hregs hr_str)
|
ignore (Il.process_quad { Il.identity_processor with
|
||||||
end;
|
Il.qp_reg = qp_reg } q)
|
||||||
r
|
|
||||||
in
|
|
||||||
ignore (Il.process_quad { Il.identity_processor with
|
|
||||||
Il.qp_reg = qp_reg } q)
|
|
||||||
end;
|
|
||||||
end
|
end
|
||||||
cx.ctxt_quads;
|
|
||||||
constraints
|
|
||||||
;;
|
;;
|
||||||
|
|
||||||
(* Simple local register allocator. Nothing fancy. *)
|
(* Simple local register allocator. Nothing fancy. *)
|
||||||
|
@ -380,8 +376,10 @@ let reg_alloc
|
||||||
let (live_in_vregs, live_out_vregs) =
|
let (live_in_vregs, live_out_vregs) =
|
||||||
calculate_live_bitvectors cx
|
calculate_live_bitvectors cx
|
||||||
in
|
in
|
||||||
|
let n_vregs = cx.ctxt_n_vregs in
|
||||||
|
let n_hregs = abi.Abi.abi_n_hardregs in
|
||||||
let (vreg_constraints:Bits.t array) = (* vreg idx -> hreg bits.t *)
|
let (vreg_constraints:Bits.t array) = (* vreg idx -> hreg bits.t *)
|
||||||
calculate_vreg_constraints cx
|
Array.init n_vregs (fun _ -> Bits.create n_hregs true)
|
||||||
in
|
in
|
||||||
let inactive_hregs = ref [] in (* [hreg] *)
|
let inactive_hregs = ref [] in (* [hreg] *)
|
||||||
let active_hregs = ref [] in (* [hreg] *)
|
let active_hregs = ref [] in (* [hreg] *)
|
||||||
|
@ -560,23 +558,40 @@ let reg_alloc
|
||||||
for i = 0 to (Array.length cx.ctxt_quads) - 1
|
for i = 0 to (Array.length cx.ctxt_quads) - 1
|
||||||
do
|
do
|
||||||
let quad = cx.ctxt_quads.(i) in
|
let quad = cx.ctxt_quads.(i) in
|
||||||
|
let _ = calculate_vreg_constraints cx vreg_constraints quad in
|
||||||
let clobbers = cx.ctxt_abi.Abi.abi_clobbers quad in
|
let clobbers = cx.ctxt_abi.Abi.abi_clobbers quad in
|
||||||
let used = quad_used_vregs quad in
|
let used = quad_used_vregs quad in
|
||||||
let defined = quad_defined_vregs quad in
|
let defined = quad_defined_vregs quad in
|
||||||
|
|
||||||
let vreg_constrs v = (v, Bits.to_list (vreg_constraints.(v))) in
|
|
||||||
let used_constrs = List.map vreg_constrs used in
|
|
||||||
let constrs_collide (v1,c1) =
|
|
||||||
if List.length c1 <> 1
|
|
||||||
then false
|
|
||||||
else
|
|
||||||
List.exists
|
|
||||||
(fun (v2,c2) -> if v1 = v2 then false else c1 = c2)
|
|
||||||
used_constrs
|
|
||||||
in
|
|
||||||
begin
|
begin
|
||||||
if List.exists constrs_collide used_constrs
|
|
||||||
then raise (Ra_error ("over-constrained vregs"));
|
(* If the quad has any nontrivial vreg constraints, regfence.
|
||||||
|
* This is awful but it saves us from cached/constrained
|
||||||
|
* interference as was found in issue #152. *)
|
||||||
|
if List.exists
|
||||||
|
(fun v -> not (Bits.equal vreg_constraints.(v) all_hregs))
|
||||||
|
used
|
||||||
|
then
|
||||||
|
begin
|
||||||
|
(* Regfence. *)
|
||||||
|
spill_all_regs i;
|
||||||
|
(* Check for over-constrained-ness after any such regfence. *)
|
||||||
|
let vreg_constrs v =
|
||||||
|
(v, Bits.to_list (vreg_constraints.(v)))
|
||||||
|
in
|
||||||
|
let constrs = List.map vreg_constrs (used @ defined) in
|
||||||
|
let constrs_collide (v1,c1) =
|
||||||
|
if List.length c1 <> 1
|
||||||
|
then false
|
||||||
|
else
|
||||||
|
List.exists
|
||||||
|
(fun (v2,c2) -> if v1 = v2 then false else c1 = c2)
|
||||||
|
constrs
|
||||||
|
in
|
||||||
|
if List.exists constrs_collide constrs
|
||||||
|
then raise (Ra_error ("over-constrained vregs"));
|
||||||
|
end;
|
||||||
|
|
||||||
if List.exists (fun def -> List.mem def clobbers) defined
|
if List.exists (fun def -> List.mem def clobbers) defined
|
||||||
then raise (Ra_error ("clobber and defined sets overlap"));
|
then raise (Ra_error ("clobber and defined sets overlap"));
|
||||||
iflog cx
|
iflog cx
|
||||||
|
@ -640,10 +655,10 @@ let reg_alloc
|
||||||
end;
|
end;
|
||||||
(cx.ctxt_quads, cx.ctxt_next_spill)
|
(cx.ctxt_quads, cx.ctxt_next_spill)
|
||||||
|
|
||||||
with
|
with
|
||||||
Ra_error s ->
|
Ra_error s ->
|
||||||
Session.fail sess "RA error: %s\n" s;
|
Session.fail sess "RA error: %s\n" s;
|
||||||
(quads, 0)
|
(quads, 0)
|
||||||
|
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
|
|
@ -28,9 +28,7 @@ fn next_power_of_two(uint n) -> uint {
|
||||||
let uint shift = 1u;
|
let uint shift = 1u;
|
||||||
while (shift <= halfbits) {
|
while (shift <= halfbits) {
|
||||||
tmp |= tmp >> shift;
|
tmp |= tmp >> shift;
|
||||||
// FIXME (issue #152): This would be just a tad cuter if it were
|
shift <<= 1u;
|
||||||
// shift <<= 1u
|
|
||||||
shift = shift << 1u;
|
|
||||||
}
|
}
|
||||||
ret tmp + 1u;
|
ret tmp + 1u;
|
||||||
}
|
}
|
||||||
|
|
10
src/test/run-pass/over-constrained-vregs.rs
Normal file
10
src/test/run-pass/over-constrained-vregs.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// Regression test for issue #152.
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let uint b = 1u;
|
||||||
|
while (b <= 32u) {
|
||||||
|
0u << b;
|
||||||
|
b <<= 1u;
|
||||||
|
log b;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue