cf861df77a727d4d1fb9ee67e223242c6b03dff8
[ghc.git] / compiler / nativeGen / SPARC / CodeGen / Expand.hs
1 -- | Expand out synthetic instructions into single machine instrs.
2 module SPARC.CodeGen.Expand (
3 expandTop
4 )
5
6 where
7
8 import GhcPrelude
9
10 import SPARC.Instr
11 import SPARC.Imm
12 import SPARC.AddrMode
13 import SPARC.Regs
14 import SPARC.Ppr ()
15 import Instruction
16 import Reg
17 import Format
18 import Cmm
19
20
21 import Outputable
22 import OrdList
23
24 -- | Expand out synthetic instructions in this top level thing
25 expandTop :: NatCmmDecl CmmStatics Instr -> NatCmmDecl CmmStatics Instr
26 expandTop top@(CmmData{})
27 = top
28
29 expandTop (CmmProc info lbl live (ListGraph blocks))
30 = CmmProc info lbl live (ListGraph $ map expandBlock blocks)
31
32
33 -- | Expand out synthetic instructions in this block
34 expandBlock :: NatBasicBlock Instr -> NatBasicBlock Instr
35
36 expandBlock (BasicBlock label instrs)
37 = let instrs_ol = expandBlockInstrs instrs
38 instrs' = fromOL instrs_ol
39 in BasicBlock label instrs'
40
41
42 -- | Expand out some instructions
43 expandBlockInstrs :: [Instr] -> OrdList Instr
44 expandBlockInstrs [] = nilOL
45
46 expandBlockInstrs (ii:is)
47 = let ii_doubleRegs = remapRegPair ii
48 is_misaligned = expandMisalignedDoubles ii_doubleRegs
49
50 in is_misaligned `appOL` expandBlockInstrs is
51
52
53
54 -- | In the SPARC instruction set the FP register pairs that are used
55 -- to hold 64 bit floats are refered to by just the first reg
56 -- of the pair. Remap our internal reg pairs to the appropriate reg.
57 --
58 -- For example:
59 -- ldd [%l1], (%f0 | %f1)
60 --
61 -- gets mapped to
62 -- ldd [$l1], %f0
63 --
64 remapRegPair :: Instr -> Instr
65 remapRegPair instr
66 = let patchF reg
67 = case reg of
68 RegReal (RealRegSingle _)
69 -> reg
70
71 RegReal (RealRegPair r1 r2)
72
73 -- sanity checking
74 | r1 >= 32
75 , r1 <= 63
76 , r1 `mod` 2 == 0
77 , r2 == r1 + 1
78 -> RegReal (RealRegSingle r1)
79
80 | otherwise
81 -> pprPanic "SPARC.CodeGen.Expand: not remapping dodgy looking reg pair " (ppr reg)
82
83 RegVirtual _
84 -> pprPanic "SPARC.CodeGen.Expand: not remapping virtual reg " (ppr reg)
85
86 in patchRegsOfInstr instr patchF
87
88
89
90
91 -- Expand out 64 bit load/stores into individual instructions to handle
92 -- possible double alignment problems.
93 --
94 -- TODO: It'd be better to use a scratch reg instead of the add/sub thing.
95 -- We might be able to do this faster if we use the UA2007 instr set
96 -- instead of restricting ourselves to SPARC V9.
97 --
98 expandMisalignedDoubles :: Instr -> OrdList Instr
99 expandMisalignedDoubles instr
100
101 -- Translate to:
102 -- add g1,g2,g1
103 -- ld [g1],%fn
104 -- ld [g1+4],%f(n+1)
105 -- sub g1,g2,g1 -- to restore g1
106 | LD FF64 (AddrRegReg r1 r2) fReg <- instr
107 = toOL [ ADD False False r1 (RIReg r2) r1
108 , LD FF32 (AddrRegReg r1 g0) fReg
109 , LD FF32 (AddrRegImm r1 (ImmInt 4)) (fRegHi fReg)
110 , SUB False False r1 (RIReg r2) r1 ]
111
112 -- Translate to
113 -- ld [addr],%fn
114 -- ld [addr+4],%f(n+1)
115 | LD FF64 addr fReg <- instr
116 = let Just addr' = addrOffset addr 4
117 in toOL [ LD FF32 addr fReg
118 , LD FF32 addr' (fRegHi fReg) ]
119
120 -- Translate to:
121 -- add g1,g2,g1
122 -- st %fn,[g1]
123 -- st %f(n+1),[g1+4]
124 -- sub g1,g2,g1 -- to restore g1
125 | ST FF64 fReg (AddrRegReg r1 r2) <- instr
126 = toOL [ ADD False False r1 (RIReg r2) r1
127 , ST FF32 fReg (AddrRegReg r1 g0)
128 , ST FF32 (fRegHi fReg) (AddrRegImm r1 (ImmInt 4))
129 , SUB False False r1 (RIReg r2) r1 ]
130
131 -- Translate to
132 -- ld [addr],%fn
133 -- ld [addr+4],%f(n+1)
134 | ST FF64 fReg addr <- instr
135 = let Just addr' = addrOffset addr 4
136 in toOL [ ST FF32 fReg addr
137 , ST FF32 (fRegHi fReg) addr' ]
138
139 -- some other instr
140 | otherwise
141 = unitOL instr
142
143
144
145 -- | The the high partner for this float reg.
146 fRegHi :: Reg -> Reg
147 fRegHi (RegReal (RealRegSingle r1))
148 | r1 >= 32
149 , r1 <= 63
150 , r1 `mod` 2 == 0
151 = (RegReal $ RealRegSingle (r1 + 1))
152
153 -- Can't take high partner for non-low reg.
154 fRegHi reg
155 = pprPanic "SPARC.CodeGen.Expand: can't take fRegHi from " (ppr reg)