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