summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/nativeGen/RegAlloc/Linear/Main.hs91
1 files changed, 59 insertions, 32 deletions
diff --git a/compiler/nativeGen/RegAlloc/Linear/Main.hs b/compiler/nativeGen/RegAlloc/Linear/Main.hs
index 44fc8ef896..1b6810ed07 100644
--- a/compiler/nativeGen/RegAlloc/Linear/Main.hs
+++ b/compiler/nativeGen/RegAlloc/Linear/Main.hs
@@ -23,16 +23,7 @@ The algorithm is roughly:
we fill in its entry in this table with the current mapping.
For each instruction:
- (a) For each real register clobbered by this instruction:
- If a temporary resides in it,
- If the temporary is live after this instruction,
- Move the temporary to another (non-clobbered & free) reg,
- or spill it to memory. Mark the temporary as residing
- in both memory and a register if it was spilled (it might
- need to be read by this instruction).
- (ToDo: this is wrong for jump instructions?)
-
- (b) For each temporary *read* by the instruction:
+ (a) For each temporary *read* by the instruction:
If the temporary does not have a real register allocation:
- Allocate a real register from the free list. If
the list is empty:
@@ -45,6 +36,26 @@ The algorithm is roughly:
(optimisation: if we can see that a real register is going to
be used soon, then don't use it for allocation).
+ (b) For each real register clobbered by this instruction:
+ If a temporary resides in it,
+ If the temporary is live after this instruction,
+ Move the temporary to another (non-clobbered & free) reg,
+ or spill it to memory. Mark the temporary as residing
+ in both memory and a register if it was spilled (it might
+ need to be read by this instruction).
+
+ (ToDo: this is wrong for jump instructions?)
+
+ We do this after step (a), because if we start with
+ movq v1, %rsi
+ which is an instruction that clobbers %rsi, if v1 currently resides
+ in %rsi we want to get
+ movq %rsi, %freereg
+ movq %rsi, %rsi -- will disappear
+ instead of
+ movq %rsi, %freereg
+ movq %freereg, %rsi
+
(c) Update the current assignment
(d) If the instruction is a branch:
@@ -446,9 +457,6 @@ genRaInsn platform block_live new_instrs block_id instr r_dying w_dying =
-- so using nub isn't a problem).
let virt_read = nub [ vr | (RegVirtual vr) <- read ]
- -- (a) save any temporaries which will be clobbered by this instruction
- clobber_saves <- saveClobberedTemps platform real_written r_dying
-
-- debugging
{- freeregs <- getFreeRegsR
assig <- getAssigR
@@ -463,10 +471,13 @@ genRaInsn platform block_live new_instrs block_id instr r_dying w_dying =
$ do
-}
- -- (b), (c) allocate real regs for all regs read by this instruction.
+ -- (a), (b) allocate real regs for all regs read by this instruction.
(r_spills, r_allocd) <-
allocateRegsAndSpill platform True{-reading-} virt_read [] [] virt_read
+ -- (a) save any temporaries which will be clobbered by this instruction
+ clobber_saves <- saveClobberedTemps platform real_written r_dying
+
-- (d) Update block map for new destinations
-- NB. do this before removing dead regs from the assignment, because
-- these dead regs might in fact be live in the jump targets (they're
@@ -559,13 +570,9 @@ releaseRegs regs = do
-- for allocateRegs on the temps *written*,
-- - clobbered regs are not allocatable.
--
--- TODO: instead of spilling, try to copy clobbered
--- temps to another register if possible.
---
-
saveClobberedTemps
- :: (Outputable instr, Instruction instr)
+ :: (Outputable instr, Instruction instr, FR freeRegs)
=> Platform
-> [RealReg] -- real registers clobbered by this instruction
-> [Reg] -- registers which are no longer live after this insn
@@ -589,19 +596,39 @@ saveClobberedTemps platform clobbered dying
return instrs
where
- clobber assig instrs []
- = return (instrs, assig)
-
- clobber assig instrs ((temp, reg) : rest)
- = do
- (spill, slot) <- spillR platform (RegReal reg) temp
-
- -- record why this reg was spilled for profiling
- recordSpill (SpillClobber temp)
-
- let new_assign = addToUFM assig temp (InBoth reg slot)
-
- clobber new_assign (spill : instrs) rest
+ clobber assig instrs []
+ = return (instrs, assig)
+
+ clobber assig instrs ((temp, reg) : rest)
+ = do
+ freeRegs <- getFreeRegsR
+ let regclass = targetClassOfRealReg platform reg
+ freeRegs_thisClass = frGetFreeRegs regclass freeRegs
+
+ case filter (`notElem` clobbered) freeRegs_thisClass of
+
+ -- (1) we have a free reg of the right class that isn't
+ -- clobbered by this instruction; use it to save the
+ -- clobbered value.
+ (my_reg : _) -> do
+ setFreeRegsR (frAllocateReg my_reg freeRegs)
+
+ let new_assign = addToUFM assig temp (InReg my_reg)
+ let instr = mkRegRegMoveInstr platform
+ (RegReal reg) (RegReal my_reg)
+
+ clobber new_assign (instr : instrs) rest
+
+ -- (2) no free registers: spill the value
+ [] -> do
+ (spill, slot) <- spillR platform (RegReal reg) temp
+
+ -- record why this reg was spilled for profiling
+ recordSpill (SpillClobber temp)
+
+ let new_assign = addToUFM assig temp (InBoth reg slot)
+
+ clobber new_assign (spill : instrs) rest