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