-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathStgLoopback.hs
208 lines (172 loc) · 6.19 KB
/
StgLoopback.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
module StgLoopback where
-- Compiler
import GHC
import DynFlags
import ErrUtils
import Platform ( platformOS, osSubsectionsViaSymbols )
import HscTypes
import Outputable
import GHC.Paths ( libdir )
import DriverPipeline
import DriverPhases
-- Stg Types
import Module
import Stream (Stream)
import qualified Stream
import StgSyn
import CostCentre
import CodeOutput
import StgLint
-- Core Passes
import StgCmm (codeGen)
import Cmm
import CmmInfo (cmmToRawCmm )
import CmmPipeline (cmmPipeline)
import CmmBuildInfoTables (emptySRT)
import UniqSupply ( mkSplitUniqSupply, initUs_ )
import Control.Monad.Trans
import Control.Monad
-------------------------------------------------------------------------------
-- Module
-------------------------------------------------------------------------------
modl :: Module
modl = mkModule mainUnitId (mkModuleName ":Main")
modloc :: ModLocation
modloc = ModLocation
{ ml_hs_file = Nothing
, ml_hi_file = "Example.hi"
, ml_obj_file = "Example.o"
}
-------------------------------------------------------------------------------
-- Compilation
-------------------------------------------------------------------------------
data Backend = NCG | LLVM
compileProgram :: Backend -> [TyCon] -> [StgTopBinding] -> IO ()
compileProgram backend tyCons topBinds = runGhc (Just libdir) $ do
dflags <- getSessionDynFlags
liftIO $ do
putStrLn "==== STG ===="
putStrLn $ showSDoc dflags $ pprStgTopBindings topBinds
putStrLn "==== Lint STG ===="
lintStgTopBindings dflags True "Manual" topBinds
-- construct STG program manually
-- TODO: specify the following properly
{-
type CollectedCCs
= ( [CostCentre] -- local cost-centres that need to be decl'd
, [CostCentreStack] -- pre-defined "singleton" cost centre stacks
)
-}
let ccs = emptyCollectedCCs :: CollectedCCs
hpc = emptyHpcInfo False
-- backend
let
outFname = "out.ll"
(target, link) = case backend of
LLVM -> (HscLlvm, LlvmOpt)
NCG -> (HscAsm, As False)
-- Compile & Link
dflags <- getSessionDynFlags
setSessionDynFlags $
dflags { hscTarget = target, ghcLink = LinkBinary }
`gopt_set` Opt_KeepSFiles
`gopt_set` Opt_KeepLlvmFiles
-- `dopt_set` Opt_D_dump_cmm
`dopt_set` Opt_D_dump_cmm_raw
-- `dopt_set` Opt_D_dump_cmm_from_stg
`dopt_set` Opt_D_dump_timings
`gopt_set` Opt_DoStgLinting
`gopt_set` Opt_DoCmmLinting
dflags <- getSessionDynFlags
env <- getSession
liftIO $ do
newGen dflags env outFname modl tyCons ccs topBinds hpc
oneShot env StopLn [(outFname, Just link), ("my_lib.c", Nothing)]
pure ()
{-
TODO:
prevent linking haskell libraries i.e. base, integer-gmp, ghc-prim
-}
-------------
-- from GHC
-------------
newGen :: DynFlags
-> HscEnv
-> FilePath
-> Module
-> [TyCon]
-> CollectedCCs
-> [StgTopBinding]
-> HpcInfo
-> IO (FilePath, Maybe FilePath, [(ForeignSrcLang, FilePath)])
newGen dflags hsc_env output_filename this_mod data_tycons cost_centre_info stg_binds hpc_info = do
-- TODO: add these to parameters
let location = modloc
foreign_stubs = NoStubs
foreign_files = []
dependencies = []
cmms <- {-# SCC "StgCmm" #-}
doCodeGen hsc_env this_mod data_tycons
cost_centre_info
stg_binds hpc_info
------------------ Code output -----------------------
rawcmms0 <- {-# SCC "cmmToRawCmm" #-}
cmmToRawCmm dflags cmms
let dump a = do dumpIfSet_dyn dflags Opt_D_dump_cmm_raw "Raw Cmm"
(ppr a)
return a
rawcmms1 = Stream.mapM dump rawcmms0
(output_filename, (_stub_h_exists, stub_c_exists), foreign_fps)
<- {-# SCC "codeOutput" #-}
codeOutput dflags this_mod output_filename location
foreign_stubs foreign_files dependencies rawcmms1
return (output_filename, stub_c_exists, foreign_fps)
doCodeGen :: HscEnv -> Module -> [TyCon]
-> CollectedCCs
-> [StgTopBinding]
-> HpcInfo
-> IO (Stream IO CmmGroup ())
-- Note we produce a 'Stream' of CmmGroups, so that the
-- backend can be run incrementally. Otherwise it generates all
-- the C-- up front, which has a significant space cost.
doCodeGen hsc_env this_mod data_tycons
cost_centre_info stg_binds hpc_info = do
let dflags = hsc_dflags hsc_env
let cmm_stream :: Stream IO CmmGroup ()
cmm_stream = {-# SCC "StgCmm" #-}
StgCmm.codeGen dflags this_mod data_tycons
cost_centre_info stg_binds hpc_info
-- codegen consumes a stream of CmmGroup, and produces a new
-- stream of CmmGroup (not necessarily synchronised: one
-- CmmGroup on input may produce many CmmGroups on output due
-- to proc-point splitting).
let dump1 a = do dumpIfSet_dyn dflags Opt_D_dump_cmm_from_stg
"Cmm produced by codegen" (ppr a)
return a
ppr_stream1 = Stream.mapM dump1 cmm_stream
-- We are building a single SRT for the entire module, so
-- we must thread it through all the procedures as we cps-convert them.
us <- mkSplitUniqSupply 'S'
-- When splitting, we generate one SRT per split chunk, otherwise
-- we generate one SRT for the whole module.
let
pipeline_stream
| gopt Opt_SplitObjs dflags || gopt Opt_SplitSections dflags ||
osSubsectionsViaSymbols (platformOS (targetPlatform dflags))
= {-# SCC "cmmPipeline" #-}
let run_pipeline us cmmgroup = do
(_topSRT, cmmgroup) <-
cmmPipeline hsc_env (emptySRT this_mod) cmmgroup
return (us, cmmgroup)
in do _ <- Stream.mapAccumL run_pipeline us ppr_stream1
return ()
| otherwise
= {-# SCC "cmmPipeline" #-}
let run_pipeline = cmmPipeline hsc_env
in void $ Stream.mapAccumL run_pipeline (emptySRT this_mod) ppr_stream1
let
dump2 a = do dumpIfSet_dyn dflags Opt_D_dump_cmm
"Output Cmm" (ppr a)
return a
ppr_stream2 = Stream.mapM dump2 pipeline_stream
return ppr_stream2