2 % (c) The AQUA Project, Glasgow University, 1993-1998
6 module AsmCodeGen ( nativeCodeGen ) where
8 #include "HsVersions.h"
9 #include "nativeGen/NCG.h"
12 import List ( intersperse )
19 import AbsCStixGen ( genCodeAbstractC )
20 import AbsCSyn ( AbstractC, MagicId )
21 import AsmRegAlloc ( runRegAllocate )
22 import OrdList ( OrdList, flattenOrdList )
23 import PrimOp ( commutableOp, PrimOp(..) )
24 import RegAllocInfo ( mkMRegsState, MRegsState, findReservedRegs )
25 import Stix ( StixTree(..), StixReg(..),
26 pprStixTrees, CodeSegment(..) )
27 import PrimRep ( isFloatingRep, PrimRep(..) )
28 import UniqSupply ( returnUs, thenUs, mapUs, initUs,
29 initUs_, UniqSM, UniqSupply )
30 import UniqFM ( UniqFM, emptyUFM, addToUFM, lookupUFM )
31 import MachMisc ( IF_ARCH_i386(i386_insert_ffrees,) )
37 The 96/03 native-code generator has machine-independent and
38 machine-dependent modules (those \tr{#include}'ing \tr{NCG.h}).
40 This module (@AsmCodeGen@) is the top-level machine-independent
41 module. It uses @AbsCStixGen.genCodeAbstractC@ to produce @StixTree@s
42 (defined in module @Stix@), using support code from @StixInfo@ (info
43 tables), @StixPrim@ (primitive operations), @StixMacro@ (Abstract C
44 macros), and @StixInteger@ (GMP arbitrary-precision operations).
46 Before entering machine-dependent land, we do some machine-independent
47 @genericOpt@imisations (defined below) on the @StixTree@s.
49 We convert to the machine-specific @Instr@ datatype with
50 @stmt2Instrs@, assuming an ``infinite'' supply of registers. We then
51 use a machine-independent register allocator (@runRegAllocate@) to
52 rejoin reality. Obviously, @runRegAllocate@ has machine-specific
53 helper functions (see about @RegAllocInfo@ below).
55 The machine-dependent bits break down as follows:
57 \item[@MachRegs@:] Everything about the target platform's machine
58 registers (and immediate operands, and addresses, which tend to
59 intermingle/interact with registers).
61 \item[@MachMisc@:] Includes the @Instr@ datatype (possibly should
62 have a module of its own), plus a miscellany of other things
63 (e.g., @targetDoubleSize@, @smStablePtrTable@, ...)
65 \item[@MachCode@:] @stmt2Instrs@ is where @Stix@ stuff turns into
68 \item[@PprMach@:] @pprInstr@ turns an @Instr@ into text (well, really
71 \item[@RegAllocInfo@:] In the register allocator, we manipulate
72 @MRegsState@s, which are @BitSet@s, one bit per machine register.
73 When we want to say something about a specific machine register
74 (e.g., ``it gets clobbered by this instruction''), we set/unset
75 its bit. Obviously, we do this @BitSet@ thing for efficiency
78 The @RegAllocInfo@ module collects together the machine-specific
79 info needed to do register allocation.
85 nativeCodeGen :: AbstractC -> UniqSupply -> (SDoc, SDoc)
87 = let (stixRaw, us1) = initUs us (genCodeAbstractC absC)
88 stixOpt = map (map genericOpt) stixRaw
89 insns = initUs_ us1 (codeGen stixOpt)
90 debug_stix = vcat (map pprStixTrees stixOpt)
92 trace "--------- native code generator ---------"
96 @codeGen@ is the top-level code-generation function:
98 codeGen :: [[StixTree]] -> UniqSM SDoc
101 = mapUs genMachCode stixFinal `thenUs` \ dynamic_codes ->
103 fp_kludge :: [Instr] -> [Instr]
104 fp_kludge = IF_ARCH_i386(i386_insert_ffrees,id)
106 static_instrss :: [[Instr]]
107 static_instrss = map fp_kludge (scheduleMachCode dynamic_codes)
108 docs = map (vcat . map pprInstr) static_instrss
110 -- for debugging only
111 docs_prealloc = map (vcat . map pprInstr . flattenOrdList)
113 text_prealloc = vcat (intersperse (char ' ' $$ char ' ') docs_prealloc)
115 -- trace (showSDoc text_prealloc) (
116 returnUs (vcat (intersperse (char ' '
117 $$ text "# ___stg_split_marker"
123 Top level code generator for a chunk of stix code:
125 genMachCode :: [StixTree] -> UniqSM InstrList
128 = mapUs stmt2Instrs stmts `thenUs` \ blocks ->
129 returnUs (foldr (.) id blocks asmVoid)
132 The next bit does the code scheduling. The scheduler must also deal
133 with register allocation of temporaries. Much parallelism can be
134 exposed via the OrdList, but more might occur, so further analysis
138 scheduleMachCode :: [InstrList] -> [[Instr]]
141 = map (runRegAllocate freeRegsState findReservedRegs)
143 freeRegsState = mkMRegsState (extractMappedRegNos freeRegs)
146 %************************************************************************
148 \subsection[NCOpt]{The Generic Optimiser}
150 %************************************************************************
152 This is called between translating Abstract C to its Tree and actually
153 using the Native Code Generator to generate the annotations. It's a
154 chance to do some strength reductions.
156 ** Remember these all have to be machine independent ***
158 Note that constant-folding should have already happened, but we might
159 have introduced some new opportunities for constant-folding wrt
160 address manipulations.
163 genericOpt :: StixTree -> StixTree
166 For most nodes, just optimize the children.
169 genericOpt (StInd pk addr) = StInd pk (genericOpt addr)
171 genericOpt (StAssign pk dst src)
172 = StAssign pk (genericOpt dst) (genericOpt src)
174 genericOpt (StJump addr) = StJump (genericOpt addr)
176 genericOpt (StCondJump addr test)
177 = StCondJump addr (genericOpt test)
179 genericOpt (StCall fn cconv pk args)
180 = StCall fn cconv pk (map genericOpt args)
183 Fold indices together when the types match:
185 genericOpt (StIndex pk (StIndex pk' base off) off')
187 = StIndex pk (genericOpt base)
188 (genericOpt (StPrim IntAddOp [off, off']))
190 genericOpt (StIndex pk base off)
191 = StIndex pk (genericOpt base) (genericOpt off)
194 For PrimOps, we first optimize the children, and then we try our hand
195 at some constant-folding.
198 genericOpt (StPrim op args) = primOpt op (map genericOpt args)
201 Replace register leaves with appropriate StixTrees for the given
205 genericOpt leaf@(StReg (StixMagicId id))
206 = case (stgReg id) of
207 Always tree -> genericOpt tree
210 genericOpt other = other
213 Now, try to constant-fold the PrimOps. The arguments have already
214 been optimized and folded.
218 :: PrimOp -- The operation from an StPrim
219 -> [StixTree] -- The optimized arguments
222 primOpt op arg@[StInt x]
224 IntNegOp -> StInt (-x)
227 primOpt op args@[StInt x, StInt y]
229 CharGtOp -> StInt (if x > y then 1 else 0)
230 CharGeOp -> StInt (if x >= y then 1 else 0)
231 CharEqOp -> StInt (if x == y then 1 else 0)
232 CharNeOp -> StInt (if x /= y then 1 else 0)
233 CharLtOp -> StInt (if x < y then 1 else 0)
234 CharLeOp -> StInt (if x <= y then 1 else 0)
235 IntAddOp -> StInt (x + y)
236 IntSubOp -> StInt (x - y)
237 IntMulOp -> StInt (x * y)
238 IntQuotOp -> StInt (x `quot` y)
239 IntRemOp -> StInt (x `rem` y)
240 IntGtOp -> StInt (if x > y then 1 else 0)
241 IntGeOp -> StInt (if x >= y then 1 else 0)
242 IntEqOp -> StInt (if x == y then 1 else 0)
243 IntNeOp -> StInt (if x /= y then 1 else 0)
244 IntLtOp -> StInt (if x < y then 1 else 0)
245 IntLeOp -> StInt (if x <= y then 1 else 0)
246 -- ToDo: WordQuotOp, WordRemOp.
250 When possible, shift the constants to the right-hand side, so that we
251 can match for strength reductions. Note that the code generator will
252 also assume that constants have been shifted to the right when
256 primOpt op [x@(StInt _), y] | commutableOp op = primOpt op [y, x]
259 We can often do something with constants of 0 and 1 ...
262 primOpt op args@[x, y@(StInt 0)]
277 primOpt op args@[x, y@(StInt 1)]
285 Now look for multiplication/division by powers of 2 (integers).
288 primOpt op args@[x, y@(StInt n)]
290 IntMulOp -> case exactLog2 n of
291 Nothing -> StPrim op args
292 Just p -> StPrim ISllOp [x, StInt p]
293 IntQuotOp -> case exactLog2 n of
294 Nothing -> StPrim op args
295 Just p -> StPrim ISrlOp [x, StInt p]
299 Anything else is just too hard.
302 primOpt op args = StPrim op args