1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
{-# LANGUAGE CPP, PatternSynonyms, DeriveFunctor #-}
#if !defined(GHC_LOADED_INTO_GHCI)
{-# LANGUAGE UnboxedTuples #-}
#endif
-- | State monad for the linear register allocator.
-- Here we keep all the state that the register allocator keeps track
-- of as it walks the instructions in a basic block.
module GHC.CmmToAsm.Reg.Linear.State (
RA_State(..),
RegM,
runR,
spillR,
loadR,
getFreeRegsR,
setFreeRegsR,
getAssigR,
setAssigR,
getBlockAssigR,
setBlockAssigR,
setDeltaR,
getDeltaR,
getUniqueR,
getConfig,
getPlatform,
recordSpill,
recordFixupBlock
)
where
import GHC.Prelude
import GHC.CmmToAsm.Reg.Linear.Stats
import GHC.CmmToAsm.Reg.Linear.StackMap
import GHC.CmmToAsm.Reg.Linear.Base
import GHC.CmmToAsm.Reg.Liveness
import GHC.CmmToAsm.Instr
import GHC.CmmToAsm.Config
import GHC.Platform.Reg
import GHC.Cmm.BlockId
import GHC.Platform
import GHC.Types.Unique
import GHC.Types.Unique.Supply
import Control.Monad (ap)
-- Avoids using unboxed tuples when loading into GHCi
#if !defined(GHC_LOADED_INTO_GHCI)
type RA_Result freeRegs a = (# RA_State freeRegs, a #)
pattern RA_Result :: a -> b -> (# a, b #)
pattern RA_Result a b = (# a, b #)
{-# COMPLETE RA_Result #-}
#else
data RA_Result freeRegs a = RA_Result {-# UNPACK #-} !(RA_State freeRegs) !a
deriving (Functor)
#endif
-- | The register allocator monad type.
newtype RegM freeRegs a
= RegM { unReg :: RA_State freeRegs -> RA_Result freeRegs a }
deriving (Functor)
instance Applicative (RegM freeRegs) where
pure a = RegM $ \s -> RA_Result s a
(<*>) = ap
instance Monad (RegM freeRegs) where
m >>= k = RegM $ \s -> case unReg m s of { RA_Result s a -> unReg (k a) s }
-- | Get native code generator configuration
getConfig :: RegM a NCGConfig
getConfig = RegM $ \s -> RA_Result s (ra_config s)
-- | Get target platform from native code generator configuration
getPlatform :: RegM a Platform
getPlatform = ncgPlatform <$> getConfig
-- | Run a computation in the RegM register allocator monad.
runR :: NCGConfig
-> BlockAssignment freeRegs
-> freeRegs
-> RegMap Loc
-> StackMap
-> UniqSupply
-> RegM freeRegs a
-> (BlockAssignment freeRegs, StackMap, RegAllocStats, a)
runR config block_assig freeregs assig stack us thing =
case unReg thing
(RA_State
{ ra_blockassig = block_assig
, ra_freeregs = freeregs
, ra_assig = assig
, ra_delta = 0{-???-}
, ra_stack = stack
, ra_us = us
, ra_spills = []
, ra_config = config
, ra_fixups = [] })
of
RA_Result state returned_thing
-> (ra_blockassig state, ra_stack state, makeRAStats state, returned_thing)
-- | Make register allocator stats from its final state.
makeRAStats :: RA_State freeRegs -> RegAllocStats
makeRAStats state
= RegAllocStats
{ ra_spillInstrs = binSpillReasons (ra_spills state)
, ra_fixupList = ra_fixups state }
spillR :: Instruction instr
=> Reg -> Unique -> RegM freeRegs (instr, Int)
spillR reg temp = RegM $ \s ->
let (stack1,slot) = getStackSlotFor (ra_stack s) temp
instr = mkSpillInstr (ra_config s) reg (ra_delta s) slot
in
RA_Result s{ra_stack=stack1} (instr,slot)
loadR :: Instruction instr
=> Reg -> Int -> RegM freeRegs instr
loadR reg slot = RegM $ \s ->
RA_Result s (mkLoadInstr (ra_config s) reg (ra_delta s) slot)
getFreeRegsR :: RegM freeRegs freeRegs
getFreeRegsR = RegM $ \ s@RA_State{ra_freeregs = freeregs} ->
RA_Result s freeregs
setFreeRegsR :: freeRegs -> RegM freeRegs ()
setFreeRegsR regs = RegM $ \ s ->
RA_Result s{ra_freeregs = regs} ()
getAssigR :: RegM freeRegs (RegMap Loc)
getAssigR = RegM $ \ s@RA_State{ra_assig = assig} ->
RA_Result s assig
setAssigR :: RegMap Loc -> RegM freeRegs ()
setAssigR assig = RegM $ \ s ->
RA_Result s{ra_assig=assig} ()
getBlockAssigR :: RegM freeRegs (BlockAssignment freeRegs)
getBlockAssigR = RegM $ \ s@RA_State{ra_blockassig = assig} ->
RA_Result s assig
setBlockAssigR :: BlockAssignment freeRegs -> RegM freeRegs ()
setBlockAssigR assig = RegM $ \ s ->
RA_Result s{ra_blockassig = assig} ()
setDeltaR :: Int -> RegM freeRegs ()
setDeltaR n = RegM $ \ s ->
RA_Result s{ra_delta = n} ()
getDeltaR :: RegM freeRegs Int
getDeltaR = RegM $ \s -> RA_Result s (ra_delta s)
getUniqueR :: RegM freeRegs Unique
getUniqueR = RegM $ \s ->
case takeUniqFromSupply (ra_us s) of
(uniq, us) -> RA_Result s{ra_us = us} uniq
-- | Record that a spill instruction was inserted, for profiling.
recordSpill :: SpillReason -> RegM freeRegs ()
recordSpill spill
= RegM $ \s -> RA_Result (s { ra_spills = spill : ra_spills s }) ()
-- | Record a created fixup block
recordFixupBlock :: BlockId -> BlockId -> BlockId -> RegM freeRegs ()
recordFixupBlock from between to
= RegM $ \s -> RA_Result (s { ra_fixups = (from,between,to) : ra_fixups s }) ()
|