-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathGen.hs
More file actions
140 lines (106 loc) · 4.77 KB
/
Gen.hs
File metadata and controls
140 lines (106 loc) · 4.77 KB
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
{-# LANGUAGE TypeFamilies #-}
module Gen where
import Control.Monad.State
import Control.Monad.Writer
import Control.Monad.RWS
import Data.List
import Expr
showProg :: Gen () -> IO ()
showProg prog = putStr $ unlines $ pre' ++ initfunc ++ proch ++ host ++ post' ++ kern'
where (_,w) = evalRWS prog () emptyEnv
pre' = pre w
proch = procHead w
post' = post w
host = hostCode w
kern = kernelFunctions ++ kernCode w
kern' = if null kern then [] else ["\n//Kernel code"] ++ kern
initfunc = ["void init() {\n"] ++ initBlock w ++ ["\n}"]
toFile :: FilePath -> String -> Gen () -> IO ()
toFile path fileName prog = do writeFile (path ++ "/" ++ fileName ++ ".c") $ pre' ++ initfunc ++ proch ++ host ++ post'
unless (null $ kernCode w) $ writeFile kernPath kern
where (_,s,w) = runRWS prog () emptyEnv
pre' = unlines $ pre w
proch = unlines $ procHead w
post' = unlines $ post w
host = unlines $ hostCode w
kernPath = path ++ "/" ++ kernelFile s
kern = unlines $ kernelFunctions ++ kernCode w
initfunc = unlines $ ["void init() {\n"] ++ initBlock w ++ ["\n}"]
--writeFile path (unlines $ extractCode prog emptyEnv) >>
-- writeFile (kernelFile emptyEnv) (unlines $ extractCodeK prog emptyEnv)
kernelFunctions :: [String]
kernelFunctions = ["int testBit_fun_int32_t( int x, int i ) {\n" ++
" return (x & 1 << i) != 0;\n" ++
"}"]
class GenCode a where
gen :: a -> Gen ()
type Gen = RWS () Writers Env -- Reader is currently unused, hence Unit.
data Writers = Writers
{ hostCode :: [String]
, decls :: [String]
, kernCode :: [String]
, initBlock :: [String]
, pre :: [String]
, procHead :: [String]
, post :: [String] -- trailing "}" etc.
}
instance Monoid Writers where
mempty = Writers mempty mempty mempty mempty mempty mempty mempty
mappend a b = Writers { hostCode = mappend (hostCode a) (hostCode b)
, decls = mappend (decls a) (decls b)
, kernCode = mappend (kernCode a) (kernCode b)
, initBlock = mappend (initBlock a) (initBlock b)
, pre = mappend (pre a) (pre b)
, procHead = mappend (procHead a) (procHead b)
, post = mappend (post a) (post b)
}
data Env = Env { varCount :: Int -- Variable counter
, iDepth :: Int -- Host code indent depth
, kernelFile :: FilePath -- Name of the file containing kernels
, kiDepth :: Int -- Kernel indent depth
, kernelCounter :: Int -- Number of kernels generated "so far"
, kernelNames :: [String] -- Names of kernels used
, usedVars :: [String] -- Which "memory" objects have already been declared (to avoid redecl)
, params :: [String] -- Parameters for the Procedure head
}
line :: String -> Gen ()
line s = do d <- gets iDepth
let ind = concat $ replicate d " "
tell $ mempty {hostCode = [ind ++ s]}
decl :: String -> Gen ()
decl s = tell $ mempty {procHead = [" " ++ s]}
addParam :: String -> Gen ()
addParam s = modify $ \env -> env{params = params env ++ [s]}
indent :: Int -> Gen ()
indent i = modify $ \env -> env{iDepth = iDepth env + i}
unindent :: Int -> Gen ()
unindent i = modify $ \env -> env{iDepth = iDepth env - i}
-- kernel indent
kindent :: Int -> Gen ()
kindent i = modify $ \env -> env{kiDepth = kiDepth env + i}
kunindent :: Int -> Gen ()
kunindent i = modify $ \env -> env{kiDepth = kiDepth env - i}
-- | Generate a fresh name and increase the counter.
incVar :: Gen Int
incVar = do
d <- gets varCount
modify $ \env -> env{varCount = varCount env + 1}
return d
-- | Generate a new loop variable (based on the variable counter from incVar).
newLoopVar :: Gen String
newLoopVar = do v <- incVar
return $ (map concat
(group (group ['i' .. 'z' ])) ++
[ 'i' : show i | i <- [0..] ]) !! v
nameExists :: Name -> Gen Bool
nameExists n = fmap (elem n) (gets usedVars)
addUsedVar :: Name -> Gen ()
addUsedVar n = modify $ \env -> env {usedVars = n : usedVars env}
getKernelFile :: Gen String
getKernelFile = gets kernelFile
lineK :: String -> Gen ()
lineK s = do d <- gets kiDepth
let ind = concat $ replicate d " "
tell $ mempty {kernCode = [ind ++ s]}
emptyEnv :: Env
emptyEnv = Env 0 0 "kernels.cl" 0 0 [] [] []