From 7cfa7bdd23c1fed92a5e52f33437fbaeec4c235b Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Thu, 26 Aug 2010 16:26:51 -0700 Subject: [PATCH] Make vreg constrs per-quad, regfence on nontrivial constrs, back out workaround to _uint, add regression test. Closes #152. --- src/Makefile | 1 + src/boot/be/ra.ml | 107 +++++++++++--------- src/lib/_uint.rs | 4 +- src/test/run-pass/over-constrained-vregs.rs | 10 ++ 4 files changed, 73 insertions(+), 49 deletions(-) create mode 100644 src/test/run-pass/over-constrained-vregs.rs diff --git a/src/Makefile b/src/Makefile index 22dd0c56baf..77045777b9c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -510,6 +510,7 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \ obj-with-vec.rs \ operator-associativity.rs \ output-slot-variants.rs \ + over-constrained-vregs.rs \ pred.rs \ preempt.rs \ readalias.rs \ diff --git a/src/boot/be/ra.ml b/src/boot/be/ra.ml index 244bfcc4645..ddcc32fab75 100644 --- a/src/boot/be/ra.ml +++ b/src/boot/be/ra.ml @@ -322,38 +322,34 @@ let dump_quads cx = 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 n_vregs = cx.ctxt_n_vregs in - let n_hregs = abi.Abi.abi_n_hardregs in - let constraints = Array.init n_vregs (fun _ -> Bits.create n_hregs true) in - Array.iteri + Array.iter (fun c -> Bits.clear c; Bits.invert c) constraints; + abi.Abi.abi_constrain_vregs q constraints; + iflog cx begin - fun i q -> - abi.Abi.abi_constrain_vregs q constraints; - iflog cx - begin - fun _ -> - let hr_str = cx.ctxt_abi.Abi.abi_str_of_hardreg in - log cx "constraints for quad %d = %s" - i (string_of_quad hr_str q); - let qp_reg _ r = - begin - match r with - Il.Hreg _ -> () - | Il.Vreg v -> - let hregs = Bits.to_list constraints.(v) in - log cx " constrained to hregs: [%s]" - v (list_to_str hregs hr_str) - end; - r - in - ignore (Il.process_quad { Il.identity_processor with - Il.qp_reg = qp_reg } q) - end; + fun _ -> + let hr_str = cx.ctxt_abi.Abi.abi_str_of_hardreg in + log cx "constraints for quad %s" + (string_of_quad hr_str q); + let qp_reg _ r = + begin + match r with + Il.Hreg _ -> () + | Il.Vreg v -> + let hregs = Bits.to_list constraints.(v) in + log cx " constrained to hregs: [%s]" + v (list_to_str hregs hr_str) + end; + r + in + ignore (Il.process_quad { Il.identity_processor with + Il.qp_reg = qp_reg } q) end - cx.ctxt_quads; - constraints ;; (* Simple local register allocator. Nothing fancy. *) @@ -380,8 +376,10 @@ let reg_alloc let (live_in_vregs, live_out_vregs) = calculate_live_bitvectors cx 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 *) - calculate_vreg_constraints cx + Array.init n_vregs (fun _ -> Bits.create n_hregs true) in let inactive_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 do 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 used = quad_used_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 - 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 then raise (Ra_error ("clobber and defined sets overlap")); iflog cx @@ -640,10 +655,10 @@ let reg_alloc end; (cx.ctxt_quads, cx.ctxt_next_spill) - with - Ra_error s -> - Session.fail sess "RA error: %s\n" s; - (quads, 0) + with + Ra_error s -> + Session.fail sess "RA error: %s\n" s; + (quads, 0) ;; diff --git a/src/lib/_uint.rs b/src/lib/_uint.rs index 2c2629c92da..f3a6f935706 100644 --- a/src/lib/_uint.rs +++ b/src/lib/_uint.rs @@ -28,9 +28,7 @@ fn next_power_of_two(uint n) -> uint { let uint shift = 1u; while (shift <= halfbits) { tmp |= tmp >> shift; - // FIXME (issue #152): This would be just a tad cuter if it were - // shift <<= 1u - shift = shift << 1u; + shift <<= 1u; } ret tmp + 1u; } diff --git a/src/test/run-pass/over-constrained-vregs.rs b/src/test/run-pass/over-constrained-vregs.rs new file mode 100644 index 00000000000..914373f03dc --- /dev/null +++ b/src/test/run-pass/over-constrained-vregs.rs @@ -0,0 +1,10 @@ +// Regression test for issue #152. + +fn main() { + let uint b = 1u; + while (b <= 32u) { + 0u << b; + b <<= 1u; + log b; + } +}