Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
Glasgow Haskell Compiler
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Michal Terepeta
Glasgow Haskell Compiler
Commits
f3ebc895
Commit
f3ebc895
authored
17 years ago
by
benl
Browse files
Options
Downloads
Patches
Plain Diff
Better handling of join points in spill cleaner
parent
cdddb069
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
compiler/nativeGen/RegSpillClean.hs
+256
-24
256 additions, 24 deletions
compiler/nativeGen/RegSpillClean.hs
with
256 additions
and
24 deletions
compiler/nativeGen/RegSpillClean.hs
+
256
−
24
View file @
f3ebc895
-- | Clean out unneeded spill/reload instrs
--
-- * Handling of join points
--
-- B1: B2:
-- ... ...
-- RELOAD SLOT(0), %r1 RELOAD SLOT(0), %r1
-- ... A ... ... B ...
-- jump B3 jump B3
--
-- B3: ... C ...
-- RELOAD SLOT(0), %r1
-- ...
--
-- the plan:
-- So long as %r1 hasn't been written to in A, B or C then we don't need the
-- reload in B3.
--
-- What we really care about here is that on the entry to B3, %r1 will always
-- have the same value that is in SLOT(0) (ie, %r1 is _valid_)
--
-- This also works if the reloads in B1/B2 were spills instead, because
-- spilling %r1 to a slot makes that slot have the same value as %r1.
--
--
module
RegSpillClean
(
cleanSpills
)
...
...
@@ -12,45 +35,126 @@ import MachInstrs
import
Cmm
import
UniqSet
import
UniqFM
import
State
import
Outputable
import
Data.Maybe
import
Data.List
type
Slot
=
Int
-- | Clean out unneeded spill/reloads from this top level thing.
cleanSpills
::
LiveCmmTop
->
LiveCmmTop
cleanSpills
cmm
=
mapBlockTop
cleanBlock
cmm
where
cleanBlock
(
BasicBlock
id
instrs
)
=
BasicBlock
id
$
cleanSpill
emptyUniqSet
[]
$
cleanReload
emptyUniqSet
[]
$
instrs
=
evalState
(
cleanSpin
0
cmm
)
initCleanS
-- | do one pass of cleaning
cleanSpin
::
Int
->
LiveCmmTop
->
CleanM
LiveCmmTop
{-
cleanSpin spinCount code
= do jumpValid <- gets sJumpValid
pprTrace "cleanSpin"
( int spinCount
$$ text "--- code"
$$ ppr code
$$ text "--- joins"
$$ ppr jumpValid)
$ cleanSpin' spinCount code
-}
cleanSpin
spinCount
code
=
do
-- init count of cleaned spills/reloads
modify
$
\
s
->
s
{
sCleanedSpillsAcc
=
0
,
sCleanedReloadsAcc
=
0
}
code'
<-
mapBlockTopM
cleanBlock
code
-- During the cleaning of each block we collected information about what regs
-- were valid across each jump. Based on this, work out whether it will be
-- safe to erase reloads after join points for the next pass.
collateJoinPoints
-- remember how many spills/reloads we cleaned in this pass
spills
<-
gets
sCleanedSpillsAcc
reloads
<-
gets
sCleanedReloadsAcc
modify
$
\
s
->
s
{
sCleanedCount
=
(
spills
,
reloads
)
:
sCleanedCount
s
}
-- if nothing was cleaned in this pass or the last one
-- then we're done and it's time to bail out
cleanedCount
<-
gets
sCleanedCount
if
take
2
cleanedCount
==
[(
0
,
0
),
(
0
,
0
)]
then
return
code
-- otherwise go around again
else
cleanSpin
(
spinCount
+
1
)
code'
-- | Clean one basic block
cleanBlock
::
LiveBasicBlock
->
CleanM
LiveBasicBlock
cleanBlock
(
BasicBlock
id
instrs
)
=
do
jumpValid
<-
gets
sJumpValid
let
assoc
=
case
lookupUFM
jumpValid
id
of
Just
assoc
->
assoc
Nothing
->
emptyAssoc
instrs_reload
<-
cleanReload
assoc
[]
instrs
instrs_spill
<-
cleanSpill
emptyUniqSet
[]
instrs_reload
return
$
BasicBlock
id
instrs_spill
-- | Clean out unneeded reload instructions.
-- Walking forwards across the code
--
If there
are
no writes to a reg between a reload and the
--
last spill or reload
then we don't need the reload.
--
On
a
re
load, if we know a reg already has the same value as a slot
-- then we don't need
to do
the reload.
--
cleanReload
::
UniqSet
Reg
-- ^
h
reg
s that were reloaded but not written to yet
::
Assoc
Reg
Slot
-- ^
a
reg
and slot are associated when they have the same value.
->
[
LiveInstr
]
-- ^ acc
->
[
LiveInstr
]
-- ^ instrs to clean (in backwards order)
->
[
LiveInstr
]
-- ^ cleaned instrs (in forward order)
->
CleanM
[
LiveInstr
]
-- ^ cleaned instrs (in forward order)
cleanReload
assoc
acc
[]
=
return
acc
cleanReload
assoc
acc
(
li
@
(
Instr
instr
live
)
:
instrs
)
cleanReload
valid
acc
[]
=
acc
cleanReload
valid
acc
(
li
@
(
Instr
instr
live
)
:
instrs
)
|
SPILL
reg
slot
<-
instr
,
valid'
<-
addOneToUniqSet
valid
reg
=
cleanReload
valid'
(
li
:
acc
)
instrs
=
let
assoc'
=
addAssoc
reg
slot
-- doing the spill makes reg and slot the same value
$
deleteBAssoc
slot
-- slot value changes on spill
$
assoc
in
cleanReload
assoc'
(
li
:
acc
)
instrs
|
RELOAD
slot
reg
<-
instr
=
if
elementOfUniqSet
reg
valid
then
cleanReload
valid
acc
instrs
else
cleanReload
(
addOneToUniqSet
valid
reg
)
(
li
:
acc
)
instrs
=
if
elemAssoc
reg
slot
assoc
-- reg and slot had the same value before reload
-- we don't need the reload.
then
do
modify
$
\
s
->
s
{
sCleanedReloadsAcc
=
sCleanedReloadsAcc
s
+
1
}
cleanReload
assoc
acc
instrs
-- reg and slot had different values before reload
else
let
assoc'
=
addAssoc
reg
slot
-- doing the reload makes reg and slot the same value
$
deleteAAssoc
reg
-- reg value changes on reload
$
assoc
in
cleanReload
assoc'
(
li
:
acc
)
instrs
-- on a jump, remember the reg/slot association.
|
targets
<-
jumpDests
instr
[]
,
not
$
null
targets
=
do
mapM_
(
accJumpValid
assoc
)
targets
cleanReload
assoc
(
li
:
acc
)
instrs
-- writing to a reg changes its value.
|
RU
read
written
<-
regUsage
instr
,
valid'
<-
minusUniqSet
valid
(
mkUniqSet
written
)
=
cleanReload
valid
'
(
li
:
acc
)
instrs
=
let
assoc'
=
foldr
deleteAAssoc
assoc
written
in
cleanReload
assoc
'
(
li
:
acc
)
instrs
-- | Clean out unneeded spill instructions.
...
...
@@ -62,19 +166,147 @@ cleanSpill
::
UniqSet
Int
-- ^ slots that have been spilled, but not reload from
->
[
LiveInstr
]
-- ^ acc
->
[
LiveInstr
]
-- ^ instrs to clean (in forwards order)
->
[
LiveInstr
]
-- ^ cleaned instrs (in backwards order)
->
CleanM
[
LiveInstr
]
-- ^ cleaned instrs (in backwards order)
cleanSpill
unused
acc
[]
=
return
acc
cleanSpill
unused
acc
[]
=
acc
cleanSpill
unused
acc
(
li
@
(
Instr
instr
live
)
:
instrs
)
|
SPILL
reg
slot
<-
instr
=
if
elementOfUniqSet
slot
unused
then
cleanSpill
unused
acc
instrs
else
cleanSpill
(
addOneToUniqSet
unused
slot
)
(
li
:
acc
)
instrs
-- we can erase this spill because the slot won't be read until after the next one
then
do
modify
$
\
s
->
s
{
sCleanedSpillsAcc
=
sCleanedSpillsAcc
s
+
1
}
cleanSpill
unused
acc
instrs
else
do
-- slots start off unused
let
unused'
=
addOneToUniqSet
unused
slot
cleanSpill
unused'
(
li
:
acc
)
instrs
-- if we reload from a slot then it's no longer unused
|
RELOAD
slot
reg
<-
instr
,
unused'
<-
delOneFromUniqSet
unused
slot
=
cleanSpill
unused'
(
li
:
acc
)
instrs
-- some other instruction
|
otherwise
=
cleanSpill
unused
(
li
:
acc
)
instrs
-- collateJoinPoints:
--
-- | Look at information about what regs were valid across jumps and work out
-- whether it's safe to avoid reloads after join points.
--
collateJoinPoints
::
CleanM
()
collateJoinPoints
=
modify
$
\
s
->
s
{
sJumpValid
=
mapUFM
intersects
(
sJumpValidAcc
s
)
,
sJumpValidAcc
=
emptyUFM
}
intersects
::
[
Assoc
Reg
Slot
]
->
Assoc
Reg
Slot
intersects
[]
=
emptyAssoc
intersects
assocs
=
foldl1'
intersectAssoc
assocs
---------------
type
CleanM
=
State
CleanS
data
CleanS
=
CleanS
{
-- regs which are valid at the start of each block.
sJumpValid
::
UniqFM
(
Assoc
Reg
Slot
)
-- collecting up what regs were valid across each jump.
-- in the next pass we can collate these and write the results
-- to sJumpValid.
,
sJumpValidAcc
::
UniqFM
[
Assoc
Reg
Slot
]
-- spills/reloads cleaned each pass (latest at front)
,
sCleanedCount
::
[(
Int
,
Int
)]
-- spills/reloads that have been cleaned in this pass so far.
,
sCleanedSpillsAcc
::
Int
,
sCleanedReloadsAcc
::
Int
}
initCleanS
=
CleanS
{
sJumpValid
=
emptyUFM
,
sJumpValidAcc
=
emptyUFM
,
sCleanedCount
=
[]
,
sCleanedSpillsAcc
=
0
,
sCleanedReloadsAcc
=
0
}
-- | Remember that these regs were valid before a jump to this block
accJumpValid
::
Assoc
Reg
Slot
->
BlockId
->
CleanM
()
accJumpValid
regs
target
=
modify
$
\
s
->
s
{
sJumpValidAcc
=
addToUFM_C
(
++
)
(
sJumpValidAcc
s
)
target
[
regs
]
}
--------------
-- An association table / many to many mapping.
-- TODO: implement this better than a simple association list.
-- two maps of sets, one for each direction would be better
--
data
Assoc
a
b
=
Assoc
{
aList
::
[(
a
,
b
)]
}
-- | an empty association
emptyAssoc
::
Assoc
a
b
emptyAssoc
=
Assoc
{
aList
=
[]
}
-- | add an association to the table.
addAssoc
::
(
Eq
a
,
Eq
b
)
=>
a
->
b
->
Assoc
a
b
->
Assoc
a
b
addAssoc
a
b
m
=
m
{
aList
=
(
a
,
b
)
:
aList
m
}
-- | check if these two things are associated
elemAssoc
::
(
Eq
a
,
Eq
b
)
=>
a
->
b
->
Assoc
a
b
->
Bool
elemAssoc
a
b
m
=
elem
(
a
,
b
)
$
aList
m
-- | delete all associations with this A element
deleteAAssoc
::
Eq
a
=>
a
->
Assoc
a
b
->
Assoc
a
b
deleteAAssoc
x
m
=
m
{
aList
=
[
(
a
,
b
)
|
(
a
,
b
)
<-
aList
m
,
a
/=
x
]
}
-- | delete all associations with this B element
deleteBAssoc
::
Eq
b
=>
b
->
Assoc
a
b
->
Assoc
a
b
deleteBAssoc
x
m
=
m
{
aList
=
[
(
a
,
b
)
|
(
a
,
b
)
<-
aList
m
,
b
/=
x
]
}
-- | intersect two associations
intersectAssoc
::
(
Eq
a
,
Eq
b
)
=>
Assoc
a
b
->
Assoc
a
b
->
Assoc
a
b
intersectAssoc
a1
a2
=
emptyAssoc
{
aList
=
intersect
(
aList
a1
)
(
aList
a2
)
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment