on f869396 help sign in
Idris-dev/src/IRTS/CodegenLLVM.hs
1206 lines 49 kB history raw
1{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2module IRTS.CodegenLLVM (codegenLLVM) where
4import IRTS.CodegenCommon
5import IRTS.Lang
6import IRTS.Simplified
7import qualified Core.TT as TT
8import Core.TT (ArithTy(..), IntTy(..), NativeTy(..), nativeTyWidth)
10import Util.System
11import Paths_idris
13import LLVM.General.Context
14import LLVM.General.Diagnostic
15import LLVM.General.AST
16import LLVM.General.AST.AddrSpace
17import LLVM.General.Target ( TargetMachine
18 , withTargetOptions, withTargetMachine, getTargetMachineDataLayout
19 , initializeAllTargets, lookupTarget
20 )
21import LLVM.General.AST.DataLayout
22import qualified LLVM.General.PassManager as PM
23import qualified LLVM.General.Module as MO
24import qualified LLVM.General.AST.IntegerPredicate as IPred
25import qualified LLVM.General.AST.Linkage as L
26import qualified LLVM.General.AST.Visibility as V
27import qualified LLVM.General.AST.CallingConvention as CC
28import qualified LLVM.General.AST.Attribute as A
29import qualified LLVM.General.AST.Global as G
30import qualified LLVM.General.AST.Constant as C
31import qualified LLVM.General.AST.Float as F
32import qualified LLVM.General.Relocation as R
33import qualified LLVM.General.CodeModel as CM
34import qualified LLVM.General.CodeGenOpt as CGO
36import Data.List
37import Data.Maybe
38import Data.Word
39import Data.Map (Map)
40import qualified Data.Map as M
41import qualified Data.Set as S
42import qualified Data.Vector.Unboxed as V
43import Control.Applicative
44import Control.Monad.RWS
45import Control.Monad.Writer
46import Control.Monad.State
47import Control.Monad.Error
49import qualified System.Info as SI (arch, os)
50import System.IO
51import System.Directory (removeFile)
52import System.FilePath ((</>))
53import System.Process (rawSystem)
54import System.Exit (ExitCode(..))
55import Debug.Trace
57data Target = Target { triple :: String, dataLayout :: DataLayout }
59codegenLLVM :: [(TT.Name, SDecl)] ->
60 String -> -- target triple
61 String -> -- target CPU
62 Word -> -- Optimization degree
63 FilePath -> -- output file name
64 OutputType ->
65 IO ()
66codegenLLVM defs triple cpu optimize file outty = withContext $ \context -> do
67 initializeAllTargets
68 (target, _) <- failInIO $ lookupTarget Nothing triple
69 withTargetOptions $ \options ->
70 withTargetMachine target triple cpu S.empty options R.Default CM.Default CGO.Default $ \tm ->
71 do layout <- getTargetMachineDataLayout tm
72 let ast = codegen (Target triple layout) (map snd defs)
73 result <- runErrorT . MO.withModuleFromAST context ast $ \m ->
74 do let opts = PM.defaultCuratedPassSetSpec
75 { PM.optLevel = Just optimize
76 , PM.simplifyLibCalls = Just True
77 , PM.useInlinerWithThreshold = Just 225
78 }
79 when (optimize /= 0) $ PM.withPassManager opts $ void . flip PM.runPassManager m
80 outputModule tm file outty m
81 case result of
82 Right _ -> return ()
83 Left msg -> ierror msg
85failInIO :: ErrorT String IO a -> IO a
86failInIO = either fail return <=< runErrorT
88outputModule :: TargetMachine -> FilePath -> OutputType -> MO.Module -> IO ()
89outputModule _ file Raw m = failInIO $ MO.writeBitcodeToFile file m
90outputModule tm file Object m = failInIO $ MO.writeObjectToFile tm file m
91outputModule tm file Executable m = withTmpFile $ \obj -> do
92 outputModule tm obj Object m
93 cc <- getCC
94 defs <- (</> "llvm" </> "libidris_rts.a") <$> getDataDir
95 exit <- rawSystem cc [obj, defs, "-lm", "-lgmp", "-lgc", "-o", file]
96 when (exit /= ExitSuccess) $ ierror "FAILURE: Linking"
97outputModule _ _ MavenProject _ = ierror "FAILURE: unsupported output type"
99withTmpFile :: (FilePath -> IO a) -> IO a
100withTmpFile f = do
101 (path, handle) <- tempfile
102 hClose handle
103 result <- f path
104 removeFile path
105 return result
107ierror :: String -> a
108ierror msg = error $ "INTERNAL ERROR: IRTS.CodegenLLVM: " ++ msg
110mainDef :: Global
111mainDef =
112 functionDefaults
113 { G.returnType = IntegerType 32
114 , G.parameters =
115 ([ Parameter (IntegerType 32) (Name "argc") []
116 , Parameter (PointerType (PointerType (IntegerType 8) (AddrSpace 0)) (AddrSpace 0)) (Name "argv") []
117 ], False)
118 , G.name = Name "main"
119 , G.basicBlocks =
120 [ BasicBlock (UnName 0)
121 [ Do $ simpleCall "GC_init" [] -- Initialize Boehm GC
122 , Do $ simpleCall "__gmp_set_memory_functions"
123 [ ConstantOperand . C.GlobalReference . Name $ "__idris_gmpMalloc"
124 , ConstantOperand . C.GlobalReference . Name $ "__idris_gmpRealloc"
125 , ConstantOperand . C.GlobalReference . Name $ "__idris_gmpFree"
126 ]
127 , UnName 1 := idrCall "{runMain0}" [] ]
128 (Do $ Ret (Just (ConstantOperand (C.Int 32 0))) [])
129 ]}
131initDefs :: Target -> [Definition]
132initDefs tgt =
133 [ TypeDefinition (Name "valTy")
134 (Just $ StructureType False
135 [ IntegerType 32
136 , ArrayType 0 (PointerType valueType (AddrSpace 0))
137 ])
138 , TypeDefinition (Name "mpz")
139 (Just $ StructureType False
140 [ IntegerType 32
141 , IntegerType 32
142 , PointerType intPtr (AddrSpace 0)
143 ])
144 , GlobalDefinition $ globalVariableDefaults
145 { G.name = Name "__idris_intFmtStr"
146 , G.linkage = L.Internal
147 , G.isConstant = True
148 , G.hasUnnamedAddr = True
149 , G.type' = ArrayType 5 (IntegerType 8)
150 , G.initializer = Just $ C.Array (IntegerType 8) (map (C.Int 8 . fromIntegral . fromEnum) "%lld" ++ [C.Int 8 0])
151 }
152 , rtsFun "intStr" ptrI8 [IntegerType 64]
153 [ BasicBlock (UnName 0)
154 [ UnName 1 := simpleCall "GC_malloc_atomic" [ConstantOperand (C.Int (tgtWordSize tgt) 21)]
155 , UnName 2 := simpleCall "snprintf"
156 [ LocalReference (UnName 1)
157 , ConstantOperand (C.Int (tgtWordSize tgt) 21)
158 , ConstantOperand $ C.GetElementPtr True (C.GlobalReference . Name $ "__idris_intFmtStr") [C.Int 32 0, C.Int 32 0]
159 , LocalReference (UnName 0)
160 ]
161 ]
162 (Do $ Ret (Just (LocalReference (UnName 1))) [])
163 ]
164 , exfun "llvm.trap" VoidType [] False
165 -- , exfun "llvm.llvm.memcpy.p0i8.p0i8.i32" VoidType [ptrI8, ptrI8, IntegerType 32, IntegerType 32, IntegerType 1] False
166 -- , exfun "llvm.llvm.memcpy.p0i8.p0i8.i64" VoidType [ptrI8, ptrI8, IntegerType 64, IntegerType 32, IntegerType 1] False
167 , exfun "memcpy" ptrI8 [ptrI8, ptrI8, intPtr] False
168 , exfun "llvm.invariant.start" (PointerType (StructureType False []) (AddrSpace 0)) [IntegerType 64, ptrI8] False
169 , exfun "snprintf" (IntegerType 32) [ptrI8, intPtr, ptrI8] True
170 , exfun "strcmp" (IntegerType 32) [ptrI8, ptrI8] False
171 , exfun "strlen" intPtr [ptrI8] False
172 , exfun "GC_init" VoidType [] False
173 , exfun "GC_malloc" ptrI8 [intPtr] False
174 , exfun "GC_malloc_atomic" ptrI8 [intPtr] False
175 , exfun "__gmp_set_memory_functions" VoidType
176 [ PointerType (FunctionType ptrI8 [intPtr] False) (AddrSpace 0)
177 , PointerType (FunctionType ptrI8 [ptrI8, intPtr, intPtr] False) (AddrSpace 0)
178 , PointerType (FunctionType VoidType [ptrI8, intPtr] False) (AddrSpace 0)
179 ] False
180 , exfun "__gmpz_init" VoidType [pmpz] False
181 , exfun "__gmpz_init_set_str" (IntegerType 32) [pmpz, ptrI8, IntegerType 32] False
182 , exfun "__gmpz_get_str" ptrI8 [ptrI8, IntegerType 32, pmpz] False
183 , exfun "__gmpz_get_ui" intPtr [pmpz] False
184 , exfun "__gmpz_cmp" (IntegerType 32) [pmpz, pmpz] False
185 , exfun "__gmpz_fdiv_q_2exp" VoidType [pmpz, pmpz, intPtr] False
186 , exfun "__gmpz_mul_2exp" VoidType [pmpz, pmpz, intPtr] False
187 , exfun "mpz_get_ull" (IntegerType 64) [pmpz] False
188 , exfun "mpz_init_set_ull" VoidType [pmpz, IntegerType 64] False
189 , exfun "mpz_init_set_sll" VoidType [pmpz, IntegerType 64] False
190 , exfun "__idris_strCons" ptrI8 [IntegerType 8, ptrI8] False
191 , exfun "__idris_readStr" ptrI8 [ptrI8] False -- Actually pointer to FILE, but it's opaque anyway
192 , exfun "__idris_gmpMalloc" ptrI8 [intPtr] False
193 , exfun "__idris_gmpRealloc" ptrI8 [ptrI8, intPtr, intPtr] False
194 , exfun "__idris_gmpFree" VoidType [ptrI8, intPtr] False
195 , exfun "__idris_strRev" ptrI8 [ptrI8] False
196 , exfun "strtoll" (IntegerType 64) [ptrI8, PointerType ptrI8 (AddrSpace 0), IntegerType 32] False
197 , exfun "putErr" VoidType [ptrI8] False
198 , exVar (stdinName tgt) ptrI8
199 , exVar (stdoutName tgt) ptrI8
200 , exVar (stderrName tgt) ptrI8
201 , GlobalDefinition mainDef
202 ] ++ map mpzBinFun ["add", "sub", "mul", "fdiv_q", "fdiv_r", "and", "ior", "xor"]
203 where
204 intPtr = IntegerType (tgtWordSize tgt)
205 ptrI8 = PointerType (IntegerType 8) (AddrSpace 0)
206 pmpz = PointerType mpzTy (AddrSpace 0)
208 mpzBinFun n = exfun ("__gmpz_" ++ n) VoidType [pmpz, pmpz, pmpz] False
210 rtsFun :: String -> Type -> [Type] -> [BasicBlock] -> Definition
211 rtsFun name rty argtys def =
212 GlobalDefinition $ functionDefaults
213 { G.linkage = L.Internal
214 , G.returnType = rty
215 , G.parameters = (flip map argtys $ \ty -> Parameter ty (UnName 0) [], False)
216 , G.name = Name $ "__idris_" ++ name
217 , G.basicBlocks = def
218 }
220 exfun :: String -> Type -> [Type] -> Bool -> Definition
221 exfun name rty argtys vari =
222 GlobalDefinition $ functionDefaults
223 { G.returnType = rty
224 , G.name = Name name
225 , G.parameters = (flip map argtys $ \ty -> Parameter ty (UnName 0) [], vari)
226 }
227 exVar :: String -> Type -> Definition
228 exVar name ty = GlobalDefinition $ globalVariableDefaults { G.name = Name name, G.type' = ty }
230isApple :: Target -> Bool
231isApple (Target { triple = t }) = isJust . stripPrefix "-apple" $ dropWhile (/= '-') t
233stdinName, stdoutName, stderrName :: Target -> String
234stdinName t | isApple t = "__stdinp"
235stdinName _ = "stdin"
236stdoutName t | isApple t = "__stdoutp"
237stdoutName _ = "stdout"
238stderrName t | isApple t = "__stderrp"
239stderrName _ = "stderr"
241getStdIn, getStdOut, getStdErr :: Codegen Operand
242getStdIn = ConstantOperand . C.GlobalReference . Name . stdinName <$> asks target
243getStdOut = ConstantOperand . C.GlobalReference . Name . stdoutName <$> asks target
244getStdErr = ConstantOperand . C.GlobalReference . Name . stderrName <$> asks target
246codegen :: Target -> [SDecl] -> Module
247codegen tgt defs = Module "idris" (Just . dataLayout $ tgt) (Just . triple $ tgt) (initDefs tgt ++ globals ++ gendefs)
248 where
249 (gendefs, _, globals) = runRWS (mapM cgDef defs) tgt initialMGS
251valueType :: Type
252valueType = NamedTypeReference (Name "valTy")
254nullValue :: C.Constant
255nullValue = C.Null (PointerType valueType (AddrSpace 0))
257primTy :: Type -> Type
258primTy inner = StructureType False [IntegerType 32, inner]
260mpzTy :: Type
261mpzTy = NamedTypeReference (Name "mpz")
263conType :: Word64 -> Type
264conType nargs = StructureType False
265 [ IntegerType 32
266 , ArrayType nargs (PointerType valueType (AddrSpace 0))
267 ]
269data MGS = MGS { mgsNextGlobalName :: Word
270 , mgsForeignSyms :: Map String (FType, [FType])
271 }
273type Modgen = RWS Target [Definition] MGS
275initialMGS :: MGS
276initialMGS = MGS { mgsNextGlobalName = 0
277 , mgsForeignSyms = M.empty
278 }
280cgDef :: SDecl -> Modgen Definition
281cgDef (SFun name argNames _ expr) = do
282 nextGlobal <- gets mgsNextGlobalName
283 existingForeignSyms <- gets mgsForeignSyms
284 tgt <- ask
285 let (_, CGS { nextGlobalName = nextGlobal', foreignSyms = foreignSyms' }, (allocas, bbs, globals)) =
286 runRWS (do r <- cgExpr expr
287 case r of
288 Nothing -> terminate $ Unreachable []
289 Just r' -> terminate $ Ret (Just r') [])
290 (CGR tgt (show name))
291 (CGS 0 nextGlobal (Name "begin") [] (map (Just . LocalReference . Name . show) argNames) existingForeignSyms)
292 entryTerm = case bbs of
293 [] -> Do $ Ret Nothing []
294 BasicBlock n _ _:_ -> Do $ Br n []
295 tell globals
296 put (MGS { mgsNextGlobalName = nextGlobal', mgsForeignSyms = foreignSyms' })
297 return . GlobalDefinition $ functionDefaults
298 { G.linkage = L.Internal
299 , G.callingConvention = CC.Fast
300 , G.name = Name (show name)
301 , G.returnType = PointerType valueType (AddrSpace 0)
302 , G.parameters = (flip map argNames $ \argName ->
303 Parameter (PointerType valueType (AddrSpace 0)) (Name (show argName)) []
304 , False)
305 , G.basicBlocks =
306 BasicBlock (Name "entry")
307 (map (\(n, t) -> n := Alloca t Nothing 0 []) allocas)
308 entryTerm
309 : bbs
310 }
312type CGW = ([(Name, Type)], [BasicBlock], [Definition])
314type Env = [Maybe Operand]
316data CGS = CGS { nextName :: Word
317 , nextGlobalName :: Word
318 , currentBlockName :: Name
319 , instAccum :: [Named Instruction]
320 , lexenv :: Env
321 , foreignSyms :: Map String (FType, [FType])
322 }
324data CGR = CGR { target :: Target
325 , funcName :: String }
327type Codegen = RWS CGR CGW CGS
329getFuncName :: Codegen String
330getFuncName = asks funcName
332getGlobalUnName :: Codegen Name
333getGlobalUnName = do
334 i <- gets nextGlobalName
335 modify $ \s -> s { nextGlobalName = 1 + i }
336 return (UnName i)
338getUnName :: Codegen Name
339getUnName = do
340 i <- gets nextName
341 modify $ \s -> s { nextName = 1 + i }
342 return (UnName i)
344getName :: String -> Codegen Name
345getName n = do
346 i <- gets nextName
347 modify $ \s -> s { nextName = 1 + i }
348 return (Name $ n ++ show i)
350alloca :: Name -> Type -> Codegen ()
351alloca n t = tell ([(n, t)], [], [])
353terminate :: Terminator -> Codegen ()
354terminate term = do
355 name <- gets currentBlockName
356 insts <- gets instAccum
357 modify $ \s -> s { instAccum = ierror "Not in a block"
358 , currentBlockName = ierror "Not in a block" }
359 tell ([], [BasicBlock name insts (Do term)], [])
361newBlock :: Name -> Codegen ()
362newBlock name = modify $ \s -> s { instAccum = []
363 , currentBlockName = name
364 }
366inst :: Instruction -> Codegen Operand
367inst i = do
368 n <- getUnName
369 modify $ \s -> s { instAccum = instAccum s ++ [n := i] }
370 return $ LocalReference n
372ninst :: String -> Instruction -> Codegen Operand
373ninst name i = do
374 n <- getName name
375 modify $ \s -> s { instAccum = instAccum s ++ [n := i] }
376 return $ LocalReference n
378inst' :: Instruction -> Codegen ()
379inst' i = modify $ \s -> s { instAccum = instAccum s ++ [Do i] }
381insts :: [Named Instruction] -> Codegen ()
382insts is = modify $ \s -> s { instAccum = instAccum s ++ is }
384var :: LVar -> Codegen (Maybe Operand)
385var (Loc level) = (!! level) <$> gets lexenv
386var (Glob n) = return . Just . ConstantOperand . C.GlobalReference . Name $ show n
388binds :: Env -> Codegen (Maybe Operand) -> Codegen (Maybe Operand)
389binds vals cg = do
390 envLen <- length <$> gets lexenv
391 modify $ \s -> s { lexenv = lexenv s ++ vals }
392 value <- cg
393 modify $ \s -> s { lexenv = take envLen $ lexenv s }
394 return value
396replaceElt :: Int -> a -> [a] -> [a]
397replaceElt _ val [] = error "replaceElt: Ran out of list"
398replaceElt 0 val (x:xs) = val:xs
399replaceElt n val (x:xs) = x : replaceElt (n-1) val xs
401alloc' :: Operand -> Codegen Operand
402alloc' size = inst $ simpleCall "GC_malloc" [size]
404allocAtomic' :: Operand -> Codegen Operand
405allocAtomic' size = inst $ simpleCall "GC_malloc_atomic" [size]
407alloc :: Type -> Codegen Operand
408alloc ty = do
409 size <- sizeOf ty
410 mem <- alloc' size
411 inst $ BitCast mem (PointerType ty (AddrSpace 0)) []
413allocAtomic :: Type -> Codegen Operand
414allocAtomic ty = do
415 size <- sizeOf ty
416 mem <- allocAtomic' size
417 inst $ BitCast mem (PointerType ty (AddrSpace 0)) []
419sizeOf :: Type -> Codegen Operand
420sizeOf ty = ConstantOperand . C.PtrToInt
421 (C.GetElementPtr True (C.Null (PointerType ty (AddrSpace 0))) [C.Int 32 1])
422 . IntegerType <$> getWordSize
424loadInv :: Operand -> Instruction
425loadInv ptr = Load False ptr Nothing 0 [("invariant.load", MetadataNode [])]
427tgtWordSize :: Target -> Word32
428tgtWordSize (Target { dataLayout = DataLayout { pointerLayouts = l } }) =
429 fst . fromJust $ M.lookup (AddrSpace 0) l
431getWordSize :: Codegen Word32
432getWordSize = tgtWordSize <$> asks target
434cgExpr :: SExp -> Codegen (Maybe Operand)
435cgExpr (SV v) = var v
436cgExpr (SApp tailcall fname args) = do
437 argSlots <- mapM var args
438 case sequence argSlots of
439 Nothing -> return Nothing
440 Just argVals -> do
441 fn <- var (Glob fname)
442 Just <$> inst ((idrCall (show fname) argVals) { isTailCall = tailcall })
443cgExpr (SLet _ varExpr bodyExpr) = do
444 val <- cgExpr varExpr
445 binds [val] $ cgExpr bodyExpr
446cgExpr (SUpdate (Loc level) expr) = do
447 val <- cgExpr expr
448 modify $ \s -> s { lexenv = replaceElt level val (lexenv s) }
449 return val
450cgExpr (SCon tag name args) = do
451 argSlots <- mapM var args
452 case sequence argSlots of
453 Nothing -> return Nothing
454 Just argVals -> do
455 let ty = conType . fromIntegral . length $ argVals
456 con <- alloc ty
457 tagPtr <- inst $ GetElementPtr True con [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 0)] []
458 inst' $ Store False tagPtr (ConstantOperand (C.Int 32 (fromIntegral tag))) Nothing 0 []
459 forM_ (zip argVals [0..]) $ \(arg, i) -> do
460 ptr <- inst $ GetElementPtr True con [ ConstantOperand (C.Int 32 0)
461 , ConstantOperand (C.Int 32 1)
462 , ConstantOperand (C.Int 32 i)] []
463 inst' $ Store False ptr arg Nothing 0 []
464 ptrI8 <- inst $ BitCast con (PointerType (IntegerType 8) (AddrSpace 0)) []
465 inst' $ simpleCall "llvm.invariant.start" [ConstantOperand $ C.Int 64 (-1), ptrI8]
466 Just <$> inst (BitCast con (PointerType valueType (AddrSpace 0)) [])
467cgExpr (SCase inspect alts) = do
468 val <- var inspect
469 case val of
470 Nothing -> return Nothing
471 Just v -> cgCase v alts
472cgExpr (SChkCase inspect alts) = do
473 mval <- var inspect
474 case mval of
475 Nothing -> return Nothing
476 Just val ->
477 do endBBN <- getName "endChkCase"
478 notNullBBN <- getName "notNull"
479 originBlock <- gets currentBlockName
480 isNull <- inst $ ICmp IPred.EQ val (ConstantOperand nullValue) []
481 terminate $ CondBr isNull endBBN notNullBBN []
482 newBlock notNullBBN
483 ptr <- inst $ BitCast val (PointerType (IntegerType 32) (AddrSpace 0)) []
484 flag <- inst $ loadInv ptr
485 isVal <- inst $ ICmp IPred.EQ flag (ConstantOperand (C.Int 32 (-1))) []
486 conBBN <- getName "constructor"
487 terminate $ CondBr isVal endBBN conBBN []
488 newBlock conBBN
489 result <- cgCase val alts
490 caseExitBlock <- gets currentBlockName
491 case result of
492 Nothing -> do
493 terminate $ Unreachable []
494 newBlock endBBN
495 return $ Just val
496 Just caseVal -> do
497 terminate $ Br endBBN []
498 newBlock endBBN
499 Just <$> inst (Phi (PointerType valueType (AddrSpace 0))
500 [(val, originBlock), (val, notNullBBN), (caseVal, caseExitBlock)] [])
501cgExpr (SProj conVar idx) = do
502 val <- var conVar
503 case val of
504 Nothing -> return Nothing
505 Just v ->
506 do ptr <- inst $ GetElementPtr True v
507 [ ConstantOperand (C.Int 32 0)
508 , ConstantOperand (C.Int 32 1)
509 , ConstantOperand (C.Int 32 (fromIntegral idx))
510 ] []
511 Just <$> inst (loadInv ptr)
512cgExpr (SConst c) = Just <$> cgConst c
513cgExpr (SForeign LANG_C rty fname args) = do
514 func <- ensureCDecl fname rty (map fst args)
515 argVals <- forM args $ \(fty, v) -> do
516 v' <- var v
517 case v' of
518 Just val -> return $ Just (fty, val)
519 Nothing -> return Nothing
520 case sequence argVals of
521 Nothing -> return Nothing
522 Just argVals' -> do
523 argUVals <- mapM (uncurry unbox) argVals'
524 result <- inst Call { isTailCall = False
525 , callingConvention = CC.C
526 , returnAttributes = []
527 , function = Right func
528 , arguments = map (\v -> (v, [])) argUVals
529 , functionAttributes = []
530 , metadata = []
531 }
532 Just <$> box rty result
533cgExpr (SOp fn args) = do
534 argVals <- mapM var args
535 case sequence argVals of
536 Just ops -> Just <$> cgOp fn ops
537 Nothing -> return Nothing
538cgExpr SNothing = return . Just . ConstantOperand $ nullValue
539cgExpr (SError msg) = do
540 str <- addGlobal' (ArrayType (2 + fromIntegral (length msg)) (IntegerType 8))
541 (cgConst' (TT.Str (msg ++ "\n")))
542 inst' $ simpleCall "putErr" [ConstantOperand $ C.GetElementPtr True str [ C.Int 32 0
543 , C.Int 32 0]]
544 inst' Call { isTailCall = True
545 , callingConvention = CC.C
546 , returnAttributes = []
547 , function = Right . ConstantOperand . C.GlobalReference . Name $ "llvm.trap"
548 , arguments = []
549 , functionAttributes = [A.NoReturn]
550 , metadata = []
551 }
552 return Nothing
554cgCase :: Operand -> [SAlt] -> Codegen (Maybe Operand)
555cgCase val alts =
556 case find isConstCase alts of
557 Just (SConstCase (TT.BI _) _) -> cgChainCase val defExp constAlts
558 Just (SConstCase (TT.Str _) _) -> cgChainCase val defExp constAlts
559 Just (SConstCase _ _) -> cgPrimCase val defExp constAlts
560 Nothing -> cgConCase val defExp conAlts
561 where
562 defExp = getDefExp =<< find isDefCase alts
563 constAlts = filter isConstCase alts
564 conAlts = filter isConCase alts
566 isConstCase (SConstCase {}) = True
567 isConstCase _ = False
569 isConCase (SConCase {}) = True
570 isConCase _ = False
572 isDefCase (SDefaultCase _) = True
573 isDefCase _ = False
575 getDefExp (SDefaultCase e) = Just e
576 getDefExp _ = Nothing
578cgPrimCase :: Operand -> Maybe SExp -> [SAlt] -> Codegen (Maybe Operand)
579cgPrimCase caseValPtr defExp alts = do
580 let caseTy = case head alts of
581 SConstCase (TT.I _) _ -> IntegerType 32
582 SConstCase (TT.B8 _) _ -> IntegerType 8
583 SConstCase (TT.B16 _) _ -> IntegerType 16
584 SConstCase (TT.B32 _) _ -> IntegerType 32
585 SConstCase (TT.B64 _) _ -> IntegerType 64
586 SConstCase (TT.Fl _) _ -> FloatingPointType 64 IEEE
587 SConstCase (TT.Ch _) _ -> IntegerType 32
588 realPtr <- inst $ BitCast caseValPtr (PointerType (primTy caseTy) (AddrSpace 0)) []
589 valPtr <- inst $ GetElementPtr True realPtr [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 1)] []
590 caseVal <- inst $ loadInv valPtr
591 defBlockName <- getName "default"
592 exitBlockName <- getName "caseExit"
593 namedAlts <- mapM (\a -> do n <- nameAlt defBlockName a; return (n, a)) alts
594 terminate $ Switch caseVal defBlockName (map (\(n, SConstCase c _) -> (cgConst' c, n)) namedAlts) []
595 initEnv <- gets lexenv
596 defResult <- cgDefaultAlt exitBlockName defBlockName defExp
597 results <- forM namedAlts $ \(name, SConstCase _ exp) -> cgAlt initEnv exitBlockName name Nothing exp
598 finishCase initEnv exitBlockName (defResult:results)
600cgConCase :: Operand -> Maybe SExp -> [SAlt] -> Codegen (Maybe Operand)
601cgConCase con defExp alts = do
602 tagPtr <- inst $ GetElementPtr True con [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 0)] []
603 tag <- inst $ loadInv tagPtr
604 defBlockName <- getName "default"
605 exitBlockName <- getName "caseExit"
606 namedAlts <- mapM (\a -> do n <- nameAlt defBlockName a; return (n, a)) alts
607 terminate $ Switch tag defBlockName (map (\(n, SConCase _ tag _ _ _) ->
608 (C.Int 32 (fromIntegral tag), n)) namedAlts) []
609 initEnv <- gets lexenv
610 defResult <- cgDefaultAlt exitBlockName defBlockName defExp
611 results <- forM namedAlts $ \(name, SConCase _ _ _ argns exp) ->
612 cgAlt initEnv exitBlockName name (Just (con, map show argns)) exp
613 finishCase initEnv exitBlockName (defResult:results)
615cgChainCase :: Operand -> Maybe SExp -> [SAlt] -> Codegen (Maybe Operand)
616cgChainCase caseValPtr defExp alts = do
617 let (caseTy, comparator) =
618 case head alts of
619 SConstCase (TT.BI _) _ -> (FArith (ATInt ITBig), "__gmpz_cmp")
620 SConstCase (TT.Str _) _ -> (FString, "strcmp")
621 caseVal <- unbox caseTy caseValPtr
622 defBlockName <- getName "default"
623 exitBlockName <- getName "caseExit"
624 namedAlts <- mapM (\a -> do n <- nameAlt defBlockName a; return (n, a)) alts
625 initEnv <- gets lexenv
626 results <- forM namedAlts $ \(name, SConstCase c e) ->
627 do const <- unbox caseTy =<< cgConst c
628 cmp <- inst $ simpleCall comparator [const, caseVal]
629 cmpResult <- inst $ ICmp IPred.EQ cmp (ConstantOperand (C.Int 32 0)) []
630 elseName <- getName "else"
631 terminate $ CondBr cmpResult name elseName []
632 result <- cgAlt initEnv exitBlockName name Nothing e
633 newBlock elseName
634 return result
635 modify $ \s -> s { lexenv = initEnv }
636 fname <- getFuncName
637 defaultVal <- cgExpr (fromMaybe (SError $ "Inexhaustive case failure in " ++ fname) defExp)
638 defaultBlock <- gets currentBlockName
639 defaultEnv <- gets lexenv
640 defResult <- case defaultVal of
641 Just v -> do
642 terminate $ Br exitBlockName []
643 return $ Just (v, defaultBlock, defaultEnv)
644 Nothing -> do
645 terminate $ Unreachable []
646 return Nothing
647 finishCase initEnv exitBlockName (defResult:results)
649finishCase :: Env -> Name -> [Maybe (Operand, Name, Env)] -> Codegen (Maybe Operand)
650finishCase initEnv exitBlockName results = do
651 let definedResults = mapMaybe id results
652 case definedResults of
653 [] -> do modify $ \s -> s { lexenv = initEnv }
654 return Nothing
655 xs -> do
656 newBlock exitBlockName
657 mergeEnvs $ map (\(_, altBlock, altEnv) -> (altBlock, altEnv)) xs
658 Just <$> inst (Phi (PointerType valueType (AddrSpace 0))
659 (map (\(altVal, altBlock, _) -> (altVal, altBlock)) xs) [])
662cgDefaultAlt :: Name -> Name -> Maybe SExp -> Codegen (Maybe (Operand, Name, Env))
663cgDefaultAlt exitName name exp = do
664 newBlock name
665 fname <- getFuncName
666 val <- cgExpr (fromMaybe (SError $ "Inexhaustive case failure in " ++ fname) exp)
667 env <- gets lexenv
668 block <- gets currentBlockName
669 case val of
670 Just v ->
671 do terminate $ Br exitName []
672 return $ Just (v, block, env)
673 Nothing ->
674 do terminate $ Unreachable []
675 return Nothing
677cgAlt :: Env -> Name -> Name -> Maybe (Operand, [String]) -> SExp
678 -> Codegen (Maybe (Operand, Name, Env))
679cgAlt initEnv exitBlockName name destr exp = do
680 modify $ \s -> s { lexenv = initEnv }
681 newBlock name
682 locals <- case destr of
683 Nothing -> return []
684 Just (con, argns) ->
685 forM (zip argns [0..]) $ \(argName, i) ->
686 do ptr <- inst $ GetElementPtr True con [ ConstantOperand (C.Int 32 0)
687 , ConstantOperand (C.Int 32 1)
688 , ConstantOperand (C.Int 32 i)] []
689 Just <$> ninst argName (loadInv ptr)
690 altVal <- binds locals $ cgExpr exp
691 altEnv <- gets lexenv
692 altBlock <- gets currentBlockName
693 case altVal of
694 Just v -> do
695 terminate $ Br exitBlockName []
696 return $ Just (v, altBlock, altEnv)
697 Nothing -> do
698 terminate $ Unreachable []
699 return Nothing
701mergeEnvs :: [(Name, Env)] -> Codegen ()
702mergeEnvs es = do
703 let vars = transpose
704 . map (\(block, env) -> map (\x -> (x, block)) env)
705 $ es
706 env <- forM vars $ \var ->
707 case var of
708 [] -> ierror "mergeEnvs: impossible"
709 [(v, _)] -> return v
710 vs@((v, _):_)
711 | all (== v) (map fst vs) -> return v
712 | otherwise ->
713 let valid = map (\(a, b) -> (fromJust a, b)) . filter (isJust . fst) $ vs in
714 Just <$> inst (Phi (PointerType valueType (AddrSpace 0)) valid [])
715 modify $ \s -> s { lexenv = env }
717nameAlt :: Name -> SAlt -> Codegen Name
718nameAlt d (SDefaultCase _) = return d
719nameAlt _ (SConCase _ _ name _ _) = getName (show name)
720nameAlt _ (SConstCase const _) = getName (show const)
722isHeapFTy :: FType -> Bool
723isHeapFTy f = elem f [FString, FPtr, FAny, FArith (ATInt ITBig)]
725box :: FType -> Operand -> Codegen Operand
726box FUnit _ = return $ ConstantOperand nullValue
727box fty fval = do
728 let ty = primTy (ftyToTy fty)
729 val <- if isHeapFTy fty then alloc ty else allocAtomic ty
730 tagptr <- inst $ GetElementPtr True val [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 0)] []
731 valptr <- inst $ GetElementPtr True val [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 1)] []
732 inst' $ Store False tagptr (ConstantOperand (C.Int 32 (-1))) Nothing 0 []
733 inst' $ Store False valptr fval Nothing 0 []
734 ptrI8 <- inst $ BitCast val (PointerType (IntegerType 8) (AddrSpace 0)) []
735 inst' $ simpleCall "llvm.invariant.start" [ConstantOperand $ C.Int 64 (-1), ptrI8]
736 inst $ BitCast val (PointerType valueType (AddrSpace 0)) []
738unbox :: FType -> Operand -> Codegen Operand
739unbox FUnit x = return x
740unbox fty bval = do
741 val <- inst $ BitCast bval (PointerType (primTy (ftyToTy fty)) (AddrSpace 0)) []
742 fvalptr <- inst $ GetElementPtr True val [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 1)] []
743 inst $ loadInv fvalptr
745cgConst' :: TT.Const -> C.Constant
746cgConst' (TT.I i) = C.Int 32 (fromIntegral i)
747cgConst' (TT.B8 i) = C.Int 8 (fromIntegral i)
748cgConst' (TT.B16 i) = C.Int 16 (fromIntegral i)
749cgConst' (TT.B32 i) = C.Int 32 (fromIntegral i)
750cgConst' (TT.B64 i) = C.Int 64 (fromIntegral i)
751cgConst' (TT.B8V v) = C.Vector (map ((C.Int 8) . fromIntegral) . V.toList $ v)
752cgConst' (TT.B16V v) = C.Vector (map ((C.Int 16) . fromIntegral) . V.toList $ v)
753cgConst' (TT.B32V v) = C.Vector (map ((C.Int 32) . fromIntegral) . V.toList $ v)
754cgConst' (TT.B64V v) = C.Vector (map ((C.Int 64) . fromIntegral) . V.toList $ v)
756cgConst' (TT.BI i) = C.Array (IntegerType 8) (map (C.Int 8 . fromIntegral . fromEnum) (show i) ++ [C.Int 8 0])
757cgConst' (TT.Fl f) = C.Float (F.Double f)
758cgConst' (TT.Ch c) = C.Int 32 . fromIntegral . fromEnum $ c
759cgConst' (TT.Str s) = C.Array (IntegerType 8) (map (C.Int 8 . fromIntegral . fromEnum) s ++ [C.Int 8 0])
760cgConst' x = ierror $ "Unsupported constant: " ++ show x
762cgConst :: TT.Const -> Codegen Operand
763cgConst c@(TT.I _) = box (FArith (ATInt ITNative)) (ConstantOperand $ cgConst' c)
764cgConst c@(TT.B8 _) = box (FArith (ATInt (ITFixed IT8))) (ConstantOperand $ cgConst' c)
765cgConst c@(TT.B16 _) = box (FArith (ATInt (ITFixed IT16))) (ConstantOperand $ cgConst' c)
766cgConst c@(TT.B32 _) = box (FArith (ATInt (ITFixed IT32))) (ConstantOperand $ cgConst' c)
767cgConst c@(TT.B64 _) = box (FArith (ATInt (ITFixed IT64))) (ConstantOperand $ cgConst' c)
768cgConst c@(TT.B8V v) = box (FArith (ATInt (ITVec IT8 (V.length v)))) (ConstantOperand $ cgConst' c)
769cgConst c@(TT.B16V v) = box (FArith (ATInt (ITVec IT16 (V.length v)))) (ConstantOperand $ cgConst' c)
770cgConst c@(TT.B32V v) = box (FArith (ATInt (ITVec IT32 (V.length v)))) (ConstantOperand $ cgConst' c)
771cgConst c@(TT.B64V v) = box (FArith (ATInt (ITVec IT64 (V.length v)))) (ConstantOperand $ cgConst' c)
772cgConst c@(TT.Fl _) = box (FArith ATFloat) (ConstantOperand $ cgConst' c)
773cgConst c@(TT.Ch _) = box (FArith (ATInt ITChar)) (ConstantOperand $ cgConst' c)
774cgConst c@(TT.Str s) = do
775 str <- addGlobal' (ArrayType (1 + fromIntegral (length s)) (IntegerType 8)) (cgConst' c)
776 box FString (ConstantOperand $ C.GetElementPtr True str [C.Int 32 0, C.Int 32 0])
777cgConst c@(TT.BI i) = do
778 str <- addGlobal' (ArrayType (1 + fromInteger (numDigits 10 i)) (IntegerType 8)) (cgConst' c)
779 mpz <- alloc mpzTy
780 inst $ simpleCall "__gmpz_init_set_str" [mpz
781 , ConstantOperand $ C.GetElementPtr True str [ C.Int 32 0, C.Int 32 0]
782 , ConstantOperand $ C.Int 32 10
783 ]
784 box (FArith (ATInt ITBig)) mpz
785cgConst x = return $ ConstantOperand nullValue
787numDigits :: Integer -> Integer -> Integer
788numDigits b n = 1 + fst (ilog b n) where
789 ilog b n
790 | n < b = (0, n)
791 | otherwise = let (e, r) = ilog (b*b) n
792 in if r < b then (2*e, r) else (2*e+1, r `div` b)
794addGlobal :: Global -> Codegen ()
795addGlobal def = tell ([], [], [GlobalDefinition def])
797addGlobal' :: Type -> C.Constant -> Codegen C.Constant
798addGlobal' ty val = do
799 name <- getGlobalUnName
800 addGlobal $ globalVariableDefaults
801 { G.name = name
802 , G.linkage = L.Internal
803 , G.hasUnnamedAddr = True
804 , G.isConstant = True
805 , G.type' = ty
806 , G.initializer = Just val
807 }
808 return . C.GlobalReference $ name
811ensureCDecl :: String -> FType -> [FType] -> Codegen Operand
812ensureCDecl name rty argtys = do
813 syms <- gets foreignSyms
814 case M.lookup name syms of
815 Nothing -> do addGlobal (ffunDecl name rty argtys)
816 modify $ \s -> s { foreignSyms = M.insert name (rty, argtys) (foreignSyms s) }
817 Just (rty', argtys') -> unless (rty == rty' && argtys == argtys') . fail $
818 "Mismatched type declarations for foreign symbol \"" ++ name ++ "\": " ++ show (rty, argtys) ++ " vs " ++ show (rty', argtys')
819 return $ ConstantOperand (C.GlobalReference (Name name))
821ffunDecl :: String -> FType -> [FType] -> Global
822ffunDecl name rty argtys =
823 functionDefaults
824 { G.returnType = ftyToTy rty
825 , G.name = Name name
826 , G.parameters = (flip map argtys $ \fty ->
827 Parameter (ftyToTy fty) (UnName 0) []
828 , False)
829 }
831ftyToTy :: FType -> Type
832ftyToTy (FArith (ATInt ITNative)) = IntegerType 32
833ftyToTy (FArith (ATInt ITBig)) = PointerType mpzTy (AddrSpace 0)
834ftyToTy (FArith (ATInt (ITFixed ty))) = IntegerType (fromIntegral $ nativeTyWidth ty)
835ftyToTy (FArith (ATInt (ITVec e c)))
836 = VectorType (fromIntegral c) (IntegerType (fromIntegral $ nativeTyWidth e))
837ftyToTy (FArith (ATInt ITChar)) = IntegerType 32
838ftyToTy FString = PointerType (IntegerType 8) (AddrSpace 0)
839ftyToTy FUnit = VoidType
840ftyToTy FPtr = PointerType (IntegerType 8) (AddrSpace 0)
841ftyToTy (FArith ATFloat) = FloatingPointType 64 IEEE
842ftyToTy FAny = valueType
844-- Only use when known not to be ITBig
845itWidth :: IntTy -> Word32
846itWidth ITNative = 32
847itWidth ITChar = 32
848itWidth (ITFixed x) = fromIntegral $ nativeTyWidth x
849itWidth x = ierror $ "itWidth: " ++ show x
851itConst :: IntTy -> Integer -> C.Constant
852itConst (ITFixed n) x = C.Int (fromIntegral $ nativeTyWidth n) x
853itConst ITNative x = itConst (ITFixed IT32) x
854itConst ITChar x = itConst (ITFixed IT32) x
855itConst (ITVec elts size) x = C.Vector (replicate size (itConst (ITFixed elts) x))
857cgOp :: PrimFn -> [Operand] -> Codegen Operand
858cgOp (LTrunc ITBig ity) [x] = do
859 nx <- unbox (FArith (ATInt ITBig)) x
860 val <- inst $ simpleCall "mpz_get_ull" [nx]
861 v <- case ity of
862 (ITFixed IT64) -> return val
863 _ -> inst $ Trunc val (ftyToTy (FArith (ATInt ity))) []
864 box (FArith (ATInt ity)) v
865cgOp (LZExt from ITBig) [x] = do
866 nx <- unbox (FArith (ATInt from)) x
867 nx' <- case from of
868 (ITFixed IT64) -> return nx
869 _ -> inst $ ZExt nx (IntegerType 64) []
870 mpz <- alloc mpzTy
871 inst' $ simpleCall "mpz_init_set_ull" [mpz, nx']
872 box (FArith (ATInt ITBig)) mpz
873cgOp (LSExt from ITBig) [x] = do
874 nx <- unbox (FArith (ATInt from)) x
875 nx' <- case from of
876 (ITFixed IT64) -> return nx
877 _ -> inst $ SExt nx (IntegerType 64) []
878 mpz <- alloc mpzTy
879 inst' $ simpleCall "mpz_init_set_sll" [mpz, nx']
880 box (FArith (ATInt ITBig)) mpz
882-- ITChar, ITNative, and IT32 all share representation
883cgOp (LChInt ITNative) [x] = return x
884cgOp (LIntCh ITNative) [x] = return x
886cgOp (LSLt (ATInt ITBig)) [x,y] = mpzCmp IPred.SLT x y
887cgOp (LSLe (ATInt ITBig)) [x,y] = mpzCmp IPred.SLE x y
888cgOp (LEq (ATInt ITBig)) [x,y] = mpzCmp IPred.EQ x y
889cgOp (LSGe (ATInt ITBig)) [x,y] = mpzCmp IPred.SGE x y
890cgOp (LSGt (ATInt ITBig)) [x,y] = mpzCmp IPred.SGT x y
891cgOp (LPlus (ATInt ITBig)) [x,y] = mpzBin "add" x y
892cgOp (LMinus (ATInt ITBig)) [x,y] = mpzBin "sub" x y
893cgOp (LTimes (ATInt ITBig)) [x,y] = mpzBin "mul" x y
894cgOp (LSDiv (ATInt ITBig)) [x,y] = mpzBin "fdiv_q" x y
895cgOp (LSRem (ATInt ITBig)) [x,y] = mpzBin "fdiv_r" x y
896cgOp (LAnd ITBig) [x,y] = mpzBin "and" x y
897cgOp (LOr ITBig) [x,y] = mpzBin "ior" x y
898cgOp (LXOr ITBig) [x,y] = mpzBin "xor" x y
899cgOp (LCompl ITBig) [x] = mpzUn "com" x
900cgOp (LSHL ITBig) [x,y] = mpzBit "mul_2exp" x y
901cgOp (LASHR ITBig) [x,y] = mpzBit "fdiv_q_2exp" x y
903cgOp (LTrunc ITNative (ITFixed to)) [x]
904 | 32 >= nativeTyWidth to = iCoerce Trunc IT32 to x
905cgOp (LZExt ITNative (ITFixed to)) [x]
906 | 32 <= nativeTyWidth to = iCoerce ZExt IT32 to x
907cgOp (LSExt ITNative (ITFixed to)) [x]
908 | 32 <= nativeTyWidth to = iCoerce SExt IT32 to x
910cgOp (LTrunc (ITFixed from) ITNative) [x]
911 | nativeTyWidth from >= 32 = iCoerce Trunc from IT32 x
912cgOp (LZExt (ITFixed from) ITNative) [x]
913 | nativeTyWidth from <= 32 = iCoerce ZExt from IT32 x
914cgOp (LSExt (ITFixed from) ITNative) [x]
915 | nativeTyWidth from <= 32 = iCoerce SExt from IT32 x
917cgOp (LTrunc (ITFixed from) (ITFixed to)) [x]
918 | nativeTyWidth from > nativeTyWidth to = iCoerce Trunc from to x
919cgOp (LZExt (ITFixed from) (ITFixed to)) [x]
920 | nativeTyWidth from < nativeTyWidth to = iCoerce ZExt from to x
921cgOp (LSExt (ITFixed from) (ITFixed to)) [x]
922 | nativeTyWidth from < nativeTyWidth to = iCoerce SExt from to x
924cgOp (LSLt (ATInt ity)) [x,y] = iCmp ity IPred.SLT x y
925cgOp (LSLe (ATInt ity)) [x,y] = iCmp ity IPred.SLE x y
926cgOp (LLt ity) [x,y] = iCmp ity IPred.ULT x y
927cgOp (LLe ity) [x,y] = iCmp ity IPred.ULE x y
928cgOp (LEq (ATInt ity)) [x,y] = iCmp ity IPred.EQ x y
929cgOp (LSGe (ATInt ity)) [x,y] = iCmp ity IPred.SGE x y
930cgOp (LSGt (ATInt ity)) [x,y] = iCmp ity IPred.SGT x y
931cgOp (LGe ity) [x,y] = iCmp ity IPred.UGE x y
932cgOp (LGt ity) [x,y] = iCmp ity IPred.UGT x y
933cgOp (LPlus (ATInt ity)) [x,y] = ibin ity x y (Add False False)
934cgOp (LMinus (ATInt ity)) [x,y] = ibin ity x y (Sub False False)
935cgOp (LTimes (ATInt ity)) [x,y] = ibin ity x y (Mul False False)
936cgOp (LSDiv (ATInt ity)) [x,y] = ibin ity x y (SDiv False)
937cgOp (LSRem (ATInt ity)) [x,y] = ibin ity x y SRem
938cgOp (LUDiv ity) [x,y] = ibin ity x y (UDiv False)
939cgOp (LURem ity) [x,y] = ibin ity x y URem
940cgOp (LAnd ity) [x,y] = ibin ity x y And
941cgOp (LOr ity) [x,y] = ibin ity x y Or
942cgOp (LXOr ity) [x,y] = ibin ity x y Xor
943cgOp (LCompl ity) [x] = iun ity x (Xor . ConstantOperand $ itConst ity (-1))
944cgOp (LSHL ity) [x,y] = ibin ity x y (Shl False False)
945cgOp (LLSHR ity) [x,y] = ibin ity x y (LShr False)
946cgOp (LASHR ity) [x,y] = ibin ity x y (AShr False)
948cgOp LNoOp xs = return $ last xs
950cgOp (LMkVec ety c) xs | c == length xs = do
951 nxs <- mapM (unbox (FArith (ATInt (ITFixed ety)))) xs
952 vec <- foldM (\v (e, i) -> inst $ InsertElement v e (ConstantOperand (C.Int 32 i)) [])
953 (ConstantOperand $ C.Vector (replicate c (C.Undef (IntegerType . fromIntegral $ nativeTyWidth ety))))
954 (zip nxs [0..])
955 box (FArith (ATInt (ITVec ety c))) vec
957cgOp (LIdxVec ety c) [v,i] = do
958 nv <- unbox (FArith (ATInt (ITVec ety c))) v
959 ni <- unbox (FArith (ATInt (ITFixed IT32))) i
960 elt <- inst $ ExtractElement nv ni []
961 box (FArith (ATInt (ITFixed ety))) elt
963cgOp (LUpdateVec ety c) [v,i,e] = do
964 let fty = FArith (ATInt (ITVec ety c))
965 nv <- unbox fty v
966 ni <- unbox (FArith (ATInt (ITFixed IT32))) i
967 ne <- unbox (FArith (ATInt (ITFixed ety))) e
968 nv' <- inst $ InsertElement nv ne ni []
969 box fty nv'
971cgOp (LBitCast from to) [x] = do
972 nx <- unbox (FArith from) x
973 nx' <- inst $ BitCast nx (ftyToTy (FArith to)) []
974 box (FArith to) nx'
976cgOp LStrEq [x,y] = do
977 x' <- unbox FString x
978 y' <- unbox FString y
979 cmp <- inst $ simpleCall "strcmp" [x', y']
980 flag <- inst $ ICmp IPred.EQ cmp (ConstantOperand (C.Int 32 0)) []
981 val <- inst $ ZExt flag (IntegerType 32) []
982 box (FArith (ATInt (ITFixed IT32))) val
984cgOp LStrLt [x,y] = do
985 nx <- unbox FString x
986 ny <- unbox FString y
987 cmp <- inst $ simpleCall "strcmp" [nx, ny]
988 flag <- inst $ ICmp IPred.ULT cmp (ConstantOperand (C.Int 32 0)) []
989 val <- inst $ ZExt flag (IntegerType 32) []
990 box (FArith (ATInt (ITFixed IT32))) val
992cgOp (LIntStr ITBig) [x] = do
993 x' <- unbox (FArith (ATInt ITBig)) x
994 ustr <- inst $ simpleCall "__gmpz_get_str"
995 [ ConstantOperand (C.Null (PointerType (IntegerType 8) (AddrSpace 0)))
996 , ConstantOperand (C.Int 32 10)
997 , x'
998 ]
999 box FString ustr
1000cgOp (LIntStr ity) [x] = do
1001 x' <- unbox (FArith (ATInt ity)) x
1002 x'' <- if itWidth ity < 64
1003 then inst $ SExt x' (IntegerType 64) []
1004 else return x'
1005 box FString =<< inst (idrCall "__idris_intStr" [x''])
1006cgOp (LStrInt ITBig) [s] = do
1007 ns <- unbox FString s
1008 mpz <- alloc mpzTy
1009 inst $ simpleCall "__gmpz_init_set_str" [mpz, ns, ConstantOperand $ C.Int 32 10]
1010 box (FArith (ATInt ITBig)) mpz
1011cgOp (LStrInt ity) [s] = do
1012 ns <- unbox FString s
1013 nx <- inst $ simpleCall "strtoll"
1014 [ns
1015 , ConstantOperand $ C.Null (PointerType (PointerType (IntegerType 8) (AddrSpace 0)) (AddrSpace 0))
1016 , ConstantOperand $ C.Int 32 10
1018 nx' <- case ity of
1019 (ITFixed IT64) -> return nx
1020 _ -> inst $ Trunc nx (IntegerType (itWidth ity)) []
1021 box (FArith (ATInt ity)) nx'
1023cgOp LStrConcat [x,y] = cgStrCat x y
1025cgOp LStrCons [c,s] = do
1026 nc <- unbox (FArith (ATInt ITChar)) c
1027 ns <- unbox FString s
1028 nc' <- inst $ Trunc nc (IntegerType 8) []
1029 r <- inst $ simpleCall "__idris_strCons" [nc', ns]
1030 box FString r
1032cgOp LStrHead [c] = do
1033 s <- unbox FString c
1034 c <- inst $ loadInv s
1035 c' <- inst $ ZExt c (IntegerType 32) []
1036 box (FArith (ATInt ITChar)) c'
1038cgOp LStrIndex [s, i] = do
1039 ns <- unbox FString s
1040 ni <- unbox (FArith (ATInt (ITFixed IT32))) i
1041 p <- inst $ GetElementPtr True ns [ni] []
1042 c <- inst $ loadInv p
1043 c' <- inst $ ZExt c (IntegerType 32) []
1044 box (FArith (ATInt ITChar)) c'
1046cgOp LStrTail [c] = do
1047 s <- unbox FString c
1048 c <- inst $ GetElementPtr True s [ConstantOperand $ C.Int 32 1] []
1049 box FString c
1051cgOp LStrLen [s] = do
1052 ns <- unbox FString s
1053 len <- inst $ simpleCall "strlen" [ns]
1054 ws <- getWordSize
1055 len' <- case ws of
1056 32 -> return len
1057 x | x > 32 -> inst $ Trunc len (IntegerType 32) []
1058 | x < 32 -> inst $ ZExt len (IntegerType 32) []
1059 box (FArith (ATInt (ITFixed IT32))) len'
1061cgOp LStrRev [s] = do
1062 ns <- unbox FString s
1063 box FString =<< inst (simpleCall "__idris_strRev" [ns])
1065cgOp LReadStr [p] = do
1066 np <- unbox FPtr p
1067 s <- inst $ simpleCall "__idris_readStr" [np]
1068 box FString s
1070cgOp LStdIn [] = do
1071 stdin <- getStdIn
1072 ptr <- inst $ loadInv stdin
1073 box FPtr ptr
1074cgOp LStdOut [] = do
1075 stdout <- getStdOut
1076 ptr <- inst $ loadInv stdout
1077 box FPtr ptr
1078cgOp LStdErr [] = do
1079 stdErr <- getStdErr
1080 ptr <- inst $ loadInv stdErr
1081 box FPtr ptr
1083cgOp prim args = ierror $ "Unimplemented primitive: <" ++ show prim ++ ">("
1084 ++ intersperse ',' (take (length args) ['a'..]) ++ ")"
1086iCoerce :: (Operand -> Type -> InstructionMetadata -> Instruction) -> NativeTy -> NativeTy -> Operand -> Codegen Operand
1087iCoerce _ from to x | from == to = return x
1088iCoerce operator from to x = do
1089 x' <- unbox (FArith (ATInt (ITFixed from))) x
1090 x'' <- inst $ operator x' (ftyToTy (FArith (ATInt (ITFixed to)))) []
1091 box (FArith (ATInt (ITFixed to))) x''
1093cgStrCat :: Operand -> Operand -> Codegen Operand
1094cgStrCat x y = do
1095 x' <- unbox FString x
1096 y' <- unbox FString y
1097 xlen <- inst $ simpleCall "strlen" [x']
1098 ylen <- inst $ simpleCall "strlen" [y']
1099 zlen <- inst $ Add False True xlen ylen []
1100 ws <- getWordSize
1101 total <- inst $ Add False True zlen (ConstantOperand (C.Int ws 1)) []
1102 mem <- allocAtomic' total
1103 inst $ simpleCall "memcpy" [mem, x', xlen]
1104 i <- inst $ PtrToInt mem (IntegerType ws) []
1105 offi <- inst $ Add False True i xlen []
1106 offp <- inst $ IntToPtr offi (PointerType (IntegerType 8) (AddrSpace 0)) []
1107 inst $ simpleCall "memcpy" [offp, y', ylen]
1108 j <- inst $ PtrToInt offp (IntegerType ws) []
1109 offj <- inst $ Add False True j ylen []
1110 end <- inst $ IntToPtr offj (PointerType (IntegerType 8) (AddrSpace 0)) []
1111 inst' $ Store False end (ConstantOperand (C.Int 8 0)) Nothing 0 []
1112 box FString mem
1114ibin :: IntTy -> Operand -> Operand
1115 -> (Operand -> Operand -> InstructionMetadata -> Instruction) -> Codegen Operand
1116ibin ity x y instCon = do
1117 nx <- unbox (FArith (ATInt ity)) x
1118 ny <- unbox (FArith (ATInt ity)) y
1119 nr <- inst $ instCon nx ny []
1120 box (FArith (ATInt ity)) nr
1122iun :: IntTy -> Operand -> (Operand -> InstructionMetadata -> Instruction) -> Codegen Operand
1123iun ity x instCon = do
1124 nx <- unbox (FArith (ATInt ity)) x
1125 nr <- inst $ instCon nx []
1126 box (FArith (ATInt ity)) nr
1128iCmp :: IntTy -> IPred.IntegerPredicate -> Operand -> Operand -> Codegen Operand
1129iCmp ity pred x y = do
1130 nx <- unbox (FArith (ATInt ity)) x
1131 ny <- unbox (FArith (ATInt ity)) y
1132 nr <- inst $ ICmp pred nx ny []
1133 nr' <- inst $ SExt nr (ftyToTy $ cmpResultTy ity) []
1134 box (cmpResultTy ity) nr'
1136cmpResultTy :: IntTy -> FType
1137cmpResultTy v@(ITVec _ _) = FArith (ATInt v)
1138cmpResultTy _ = FArith (ATInt (ITFixed IT32))
1140mpzBin :: String -> Operand -> Operand -> Codegen Operand
1141mpzBin name x y = do
1142 nx <- unbox (FArith (ATInt ITBig)) x
1143 ny <- unbox (FArith (ATInt ITBig)) y
1144 nz <- alloc mpzTy
1145 inst' $ simpleCall "__gmpz_init" [nz]
1146 inst' $ simpleCall ("__gmpz_" ++ name) [nz, nx, ny]
1147 box (FArith (ATInt ITBig)) nz
1149mpzBit :: String -> Operand -> Operand -> Codegen Operand
1150mpzBit name x y = do
1151 nx <- unbox (FArith (ATInt ITBig)) x
1152 ny <- unbox (FArith (ATInt ITBig)) y
1153 bitcnt <- inst $ simpleCall "__gmpz_get_ui" [ny]
1154 nz <- alloc mpzTy
1155 inst' $ simpleCall "__gmpz_init" [nz]
1156 inst' $ simpleCall ("__gmpz_" ++ name) [nz, nx, bitcnt]
1157 box (FArith (ATInt ITBig)) nz
1159mpzUn :: String -> Operand -> Codegen Operand
1160mpzUn name x = do
1161 nx <- unbox (FArith (ATInt ITBig)) x
1162 nz <- alloc mpzTy
1163 inst' $ simpleCall "__gmpz_init" [nz]
1164 inst' $ simpleCall ("__gmpz_" ++ name) [nz, nx]
1165 box (FArith (ATInt ITBig)) nz
1167mpzCmp :: IPred.IntegerPredicate -> Operand -> Operand -> Codegen Operand
1168mpzCmp pred x y = do
1169 nx <- unbox (FArith (ATInt ITBig)) x
1170 ny <- unbox (FArith (ATInt ITBig)) y
1171 cmp <- inst $ simpleCall "__gmpz_cmp" [nx, ny]
1172 result <- inst $ ICmp pred cmp (ConstantOperand (C.Int 32 0)) []
1173 i <- inst $ ZExt result (IntegerType 32) []
1174 box (FArith (ATInt (ITFixed IT32))) i
1176simpleCall :: String -> [Operand] -> Instruction
1177simpleCall name args =
1178 Call { isTailCall = False
1179 , callingConvention = CC.C
1180 , returnAttributes = []
1181 , function = Right . ConstantOperand . C.GlobalReference . Name $ name
1182 , arguments = map (\x -> (x, [])) args
1183 , functionAttributes = []
1184 , metadata = []
1187idrCall :: String -> [Operand] -> Instruction
1188idrCall name args =
1189 Call { isTailCall = False
1190 , callingConvention = CC.Fast
1191 , returnAttributes = []
1192 , function = Right . ConstantOperand . C.GlobalReference . Name $ name
1193 , arguments = map (\x -> (x, [])) args
1194 , functionAttributes = []
1195 , metadata = []
1198assert :: Operand -> String -> Codegen ()
1199assert condition message = do
1200 passed <- getName "assertPassed"
1201 failed <- getName "assertFailed"
1202 terminate $ CondBr condition passed failed []
1203 newBlock failed
1204 cgExpr (SError message)
1205 terminate $ Unreachable []
1206 newBlock passed