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