1{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2module IRTS.CodegenLLVM (codegenLLVM) where
4import IRTS.CodegenCommon
7import qualified Core.TT as TT
8import Core.TT (ArithTy(..), IntTy(..), NativeTy(..), nativeTyWidth)
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
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
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)
51import System.Directory (removeFile)
52import System.FilePath ((</>))
53import System.Process (rawSystem)
54import System.Exit (ExitCode(..))
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
66codegenLLVM defs triple cpu optimize file outty = withContext $ \context -> do
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
79 when (optimize /= 0) $ PM.withPassManager opts $ void . flip PM.runPassManager m
80 outputModule tm file outty m
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
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
101 (path, handle) <- tempfile
108ierror msg = error $ "INTERNAL ERROR: IRTS.CodegenLLVM: " ++ msg
113 { G.returnType = IntegerType 32
115 ([ Parameter (IntegerType 32) (Name "argc") []
116 , Parameter (PointerType (PointerType (IntegerType 8) (AddrSpace 0)) (AddrSpace 0)) (Name "argv") []
118 , G.name = Name "main"
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"
127 , UnName 1 := idrCall "{runMain0}" [] ]
128 (Do $ Ret (Just (ConstantOperand (C.Int 32 0))) [])
131initDefs :: Target -> [Definition]
133 [ TypeDefinition (Name "valTy")
134 (Just $ StructureType False
136 , ArrayType 0 (PointerType valueType (AddrSpace 0))
138 , TypeDefinition (Name "mpz")
139 (Just $ StructureType False
142 , PointerType intPtr (AddrSpace 0)
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])
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)
162 (Do $ Ret (Just (LocalReference (UnName 1))) [])
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)
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"]
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
215 , G.parameters = (flip map argtys $ \ty -> Parameter ty (UnName 0) [], False)
216 , G.name = Name $ "__idris_" ++ name
217 , G.basicBlocks = def
220 exfun :: String -> Type -> [Type] -> Bool -> Definition
221 exfun name rty argtys vari =
222 GlobalDefinition $ functionDefaults
225 , G.parameters = (flip map argtys $ \ty -> Parameter ty (UnName 0) [], vari)
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"
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)
249 (gendefs, _, globals) = runRWS (mapM cgDef defs) tgt initialMGS
252valueType = NamedTypeReference (Name "valTy")
254nullValue :: C.Constant
255nullValue = C.Null (PointerType valueType (AddrSpace 0))
257primTy :: Type -> Type
258primTy inner = StructureType False [IntegerType 32, inner]
261mpzTy = NamedTypeReference (Name "mpz")
263conType :: Word64 -> Type
264conType nargs = StructureType False
266 , ArrayType nargs (PointerType valueType (AddrSpace 0))
269data MGS = MGS { mgsNextGlobalName :: Word
270 , mgsForeignSyms :: Map String (FType, [FType])
273type Modgen = RWS Target [Definition] MGS
276initialMGS = MGS { mgsNextGlobalName = 0
277 , mgsForeignSyms = M.empty
280cgDef :: SDecl -> Modgen Definition
281cgDef (SFun name argNames _ expr) = do
282 nextGlobal <- gets mgsNextGlobalName
283 existingForeignSyms <- gets mgsForeignSyms
285 let (_, CGS { nextGlobalName = nextGlobal', foreignSyms = foreignSyms' }, (allocas, bbs, globals)) =
286 runRWS (do r <- cgExpr expr
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 []
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)) []
306 BasicBlock (Name "entry")
307 (map (\(n, t) -> n := Alloca t Nothing 0 []) allocas)
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]
321 , foreignSyms :: Map String (FType, [FType])
324data CGR = CGR { target :: Target
325 , funcName :: String }
327type Codegen = RWS CGR CGW CGS
329getFuncName :: Codegen String
330getFuncName = asks funcName
332getGlobalUnName :: Codegen Name
334 i <- gets nextGlobalName
335 modify $ \s -> s { nextGlobalName = 1 + i }
338getUnName :: Codegen Name
341 modify $ \s -> s { nextName = 1 + i }
344getName :: String -> Codegen Name
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 ()
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
366inst :: Instruction -> Codegen Operand
369 modify $ \s -> s { instAccum = instAccum s ++ [n := i] }
370 return $ LocalReference n
372ninst :: String -> Instruction -> Codegen Operand
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)
390 envLen <- length <$> gets lexenv
391 modify $ \s -> s { lexenv = lexenv s ++ vals }
393 modify $ \s -> s { lexenv = take envLen $ lexenv s }
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
411 inst $ BitCast mem (PointerType ty (AddrSpace 0)) []
413allocAtomic :: Type -> Codegen Operand
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)
436cgExpr (SApp tailcall fname args) = do
437 argSlots <- mapM var args
438 case sequence argSlots of
439 Nothing -> return Nothing
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
448 modify $ \s -> s { lexenv = replaceElt level val (lexenv s) }
450cgExpr (SUpdate x expr) = cgExpr expr
451cgExpr (SCon tag name args) = do
452 argSlots <- mapM var args
453 case sequence argSlots of
454 Nothing -> return Nothing
456 let ty = conType . fromIntegral . length $ argVals
458 tagPtr <- inst $ GetElementPtr True con [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 0)] []
459 inst' $ Store False tagPtr (ConstantOperand (C.Int 32 (fromIntegral tag))) Nothing 0 []
460 forM_ (zip argVals [0..]) $ \(arg, i) -> do
461 ptr <- inst $ GetElementPtr True con [ ConstantOperand (C.Int 32 0)
462 , ConstantOperand (C.Int 32 1)
463 , ConstantOperand (C.Int 32 i)] []
464 inst' $ Store False ptr arg Nothing 0 []
465 ptrI8 <- inst $ BitCast con (PointerType (IntegerType 8) (AddrSpace 0)) []
466 inst' $ simpleCall "llvm.invariant.start" [ConstantOperand $ C.Int 64 (-1), ptrI8]
467 Just <$> inst (BitCast con (PointerType valueType (AddrSpace 0)) [])
468cgExpr (SCase inspect alts) = do
471 Nothing -> return Nothing
472 Just v -> cgCase v alts
473cgExpr (SChkCase inspect alts) = do
476 Nothing -> return Nothing
478 do endBBN <- getName "endChkCase"
479 notNullBBN <- getName "notNull"
480 originBlock <- gets currentBlockName
481 isNull <- inst $ ICmp IPred.EQ val (ConstantOperand nullValue) []
482 terminate $ CondBr isNull endBBN notNullBBN []
484 ptr <- inst $ BitCast val (PointerType (IntegerType 32) (AddrSpace 0)) []
485 flag <- inst $ loadInv ptr
486 isVal <- inst $ ICmp IPred.EQ flag (ConstantOperand (C.Int 32 (-1))) []
487 conBBN <- getName "constructor"
488 terminate $ CondBr isVal endBBN conBBN []
490 result <- cgCase val alts
491 caseExitBlock <- gets currentBlockName
494 terminate $ Unreachable []
498 terminate $ Br endBBN []
500 Just <$> inst (Phi (PointerType valueType (AddrSpace 0))
501 [(val, originBlock), (val, notNullBBN), (caseVal, caseExitBlock)] [])
502cgExpr (SProj conVar idx) = do
505 Nothing -> return Nothing
507 do ptr <- inst $ GetElementPtr True v
508 [ ConstantOperand (C.Int 32 0)
509 , ConstantOperand (C.Int 32 1)
510 , ConstantOperand (C.Int 32 (fromIntegral idx))
512 Just <$> inst (loadInv ptr)
513cgExpr (SConst c) = Just <$> cgConst c
514cgExpr (SForeign LANG_C rty fname args) = do
515 func <- ensureCDecl fname rty (map fst args)
516 argVals <- forM args $ \(fty, v) -> do
519 Just val -> return $ Just (fty, val)
520 Nothing -> return Nothing
521 case sequence argVals of
522 Nothing -> return Nothing
524 argUVals <- mapM (uncurry unbox) argVals'
525 result <- inst Call { isTailCall = False
526 , callingConvention = CC.C
527 , returnAttributes = []
528 , function = Right func
529 , arguments = map (\v -> (v, [])) argUVals
530 , functionAttributes = []
533 Just <$> box rty result
534cgExpr (SOp fn args) = do
535 argVals <- mapM var args
536 case sequence argVals of
537 Just ops -> Just <$> cgOp fn ops
538 Nothing -> return Nothing
539cgExpr SNothing = return . Just . ConstantOperand $ nullValue
540cgExpr (SError msg) = do
541 str <- addGlobal' (ArrayType (2 + fromIntegral (length msg)) (IntegerType 8))
542 (cgConst' (TT.Str (msg ++ "\n")))
543 inst' $ simpleCall "putErr" [ConstantOperand $ C.GetElementPtr True str [ C.Int 32 0
545 inst' Call { isTailCall = True
546 , callingConvention = CC.C
547 , returnAttributes = []
548 , function = Right . ConstantOperand . C.GlobalReference . Name $ "llvm.trap"
550 , functionAttributes = [A.NoReturn]
555cgCase :: Operand -> [SAlt] -> Codegen (Maybe Operand)
557 case find isConstCase alts of
558 Just (SConstCase (TT.BI _) _) -> cgChainCase val defExp constAlts
559 Just (SConstCase (TT.Str _) _) -> cgChainCase val defExp constAlts
560 Just (SConstCase _ _) -> cgPrimCase val defExp constAlts
561 Nothing -> cgConCase val defExp conAlts
563 defExp = getDefExp =<< find isDefCase alts
564 constAlts = filter isConstCase alts
565 conAlts = filter isConCase alts
567 isConstCase (SConstCase {}) = True
568 isConstCase _ = False
570 isConCase (SConCase {}) = True
573 isDefCase (SDefaultCase _) = True
576 getDefExp (SDefaultCase e) = Just e
577 getDefExp _ = Nothing
579cgPrimCase :: Operand -> Maybe SExp -> [SAlt] -> Codegen (Maybe Operand)
580cgPrimCase caseValPtr defExp alts = do
581 let caseTy = case head alts of
582 SConstCase (TT.I _) _ -> IntegerType 32
583 SConstCase (TT.B8 _) _ -> IntegerType 8
584 SConstCase (TT.B16 _) _ -> IntegerType 16
585 SConstCase (TT.B32 _) _ -> IntegerType 32
586 SConstCase (TT.B64 _) _ -> IntegerType 64
587 SConstCase (TT.Fl _) _ -> FloatingPointType 64 IEEE
588 SConstCase (TT.Ch _) _ -> IntegerType 32
589 realPtr <- inst $ BitCast caseValPtr (PointerType (primTy caseTy) (AddrSpace 0)) []
590 valPtr <- inst $ GetElementPtr True realPtr [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 1)] []
591 caseVal <- inst $ loadInv valPtr
592 defBlockName <- getName "default"
593 exitBlockName <- getName "caseExit"
594 namedAlts <- mapM (\a -> do n <- nameAlt defBlockName a; return (n, a)) alts
595 terminate $ Switch caseVal defBlockName (map (\(n, SConstCase c _) -> (cgConst' c, n)) namedAlts) []
596 initEnv <- gets lexenv
597 defResult <- cgDefaultAlt exitBlockName defBlockName defExp
598 results <- forM namedAlts $ \(name, SConstCase _ exp) -> cgAlt initEnv exitBlockName name Nothing exp
599 finishCase initEnv exitBlockName (defResult:results)
601cgConCase :: Operand -> Maybe SExp -> [SAlt] -> Codegen (Maybe Operand)
602cgConCase con defExp alts = do
603 tagPtr <- inst $ GetElementPtr True con [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 0)] []
604 tag <- inst $ loadInv tagPtr
605 defBlockName <- getName "default"
606 exitBlockName <- getName "caseExit"
607 namedAlts <- mapM (\a -> do n <- nameAlt defBlockName a; return (n, a)) alts
608 terminate $ Switch tag defBlockName (map (\(n, SConCase _ tag _ _ _) ->
609 (C.Int 32 (fromIntegral tag), n)) namedAlts) []
610 initEnv <- gets lexenv
611 defResult <- cgDefaultAlt exitBlockName defBlockName defExp
612 results <- forM namedAlts $ \(name, SConCase _ _ _ argns exp) ->
613 cgAlt initEnv exitBlockName name (Just (con, map show argns)) exp
614 finishCase initEnv exitBlockName (defResult:results)
616cgChainCase :: Operand -> Maybe SExp -> [SAlt] -> Codegen (Maybe Operand)
617cgChainCase caseValPtr defExp alts = do
618 let (caseTy, comparator) =
620 SConstCase (TT.BI _) _ -> (FArith (ATInt ITBig), "__gmpz_cmp")
621 SConstCase (TT.Str _) _ -> (FString, "strcmp")
622 caseVal <- unbox caseTy caseValPtr
623 defBlockName <- getName "default"
624 exitBlockName <- getName "caseExit"
625 namedAlts <- mapM (\a -> do n <- nameAlt defBlockName a; return (n, a)) alts
626 initEnv <- gets lexenv
627 results <- forM namedAlts $ \(name, SConstCase c e) ->
628 do const <- unbox caseTy =<< cgConst c
629 cmp <- inst $ simpleCall comparator [const, caseVal]
630 cmpResult <- inst $ ICmp IPred.EQ cmp (ConstantOperand (C.Int 32 0)) []
631 elseName <- getName "else"
632 terminate $ CondBr cmpResult name elseName []
633 result <- cgAlt initEnv exitBlockName name Nothing e
636 modify $ \s -> s { lexenv = initEnv }
638 defaultVal <- cgExpr (fromMaybe (SError $ "Inexhaustive case failure in " ++ fname) defExp)
639 defaultBlock <- gets currentBlockName
640 defaultEnv <- gets lexenv
641 defResult <- case defaultVal of
643 terminate $ Br exitBlockName []
644 return $ Just (v, defaultBlock, defaultEnv)
646 terminate $ Unreachable []
648 finishCase initEnv exitBlockName (defResult:results)
650finishCase :: Env -> Name -> [Maybe (Operand, Name, Env)] -> Codegen (Maybe Operand)
651finishCase initEnv exitBlockName results = do
652 let definedResults = mapMaybe id results
653 case definedResults of
654 [] -> do modify $ \s -> s { lexenv = initEnv }
657 newBlock exitBlockName
658 mergeEnvs $ map (\(_, altBlock, altEnv) -> (altBlock, altEnv)) xs
659 Just <$> inst (Phi (PointerType valueType (AddrSpace 0))
660 (map (\(altVal, altBlock, _) -> (altVal, altBlock)) xs) [])
663cgDefaultAlt :: Name -> Name -> Maybe SExp -> Codegen (Maybe (Operand, Name, Env))
664cgDefaultAlt exitName name exp = do
667 val <- cgExpr (fromMaybe (SError $ "Inexhaustive case failure in " ++ fname) exp)
669 block <- gets currentBlockName
672 do terminate $ Br exitName []
673 return $ Just (v, block, env)
675 do terminate $ Unreachable []
678cgAlt :: Env -> Name -> Name -> Maybe (Operand, [String]) -> SExp
679 -> Codegen (Maybe (Operand, Name, Env))
680cgAlt initEnv exitBlockName name destr exp = do
681 modify $ \s -> s { lexenv = initEnv }
683 locals <- case destr of
686 forM (zip argns [0..]) $ \(argName, i) ->
687 do ptr <- inst $ GetElementPtr True con [ ConstantOperand (C.Int 32 0)
688 , ConstantOperand (C.Int 32 1)
689 , ConstantOperand (C.Int 32 i)] []
690 Just <$> ninst argName (loadInv ptr)
691 altVal <- binds locals $ cgExpr exp
692 altEnv <- gets lexenv
693 altBlock <- gets currentBlockName
696 terminate $ Br exitBlockName []
697 return $ Just (v, altBlock, altEnv)
699 terminate $ Unreachable []
702mergeEnvs :: [(Name, Env)] -> Codegen ()
705 . map (\(block, env) -> map (\x -> (x, block)) env)
707 env <- forM vars $ \var ->
709 [] -> ierror "mergeEnvs: impossible"
712 | all (== v) (map fst vs) -> return v
714 let valid = map (\(a, b) -> (fromJust a, b)) . filter (isJust . fst) $ vs in
715 Just <$> inst (Phi (PointerType valueType (AddrSpace 0)) valid [])
716 modify $ \s -> s { lexenv = env }
718nameAlt :: Name -> SAlt -> Codegen Name
719nameAlt d (SDefaultCase _) = return d
720nameAlt _ (SConCase _ _ name _ _) = getName (show name)
721nameAlt _ (SConstCase const _) = getName (show const)
723isHeapFTy :: FType -> Bool
724isHeapFTy f = elem f [FString, FPtr, FAny, FArith (ATInt ITBig)]
726box :: FType -> Operand -> Codegen Operand
727box FUnit _ = return $ ConstantOperand nullValue
729 let ty = primTy (ftyToTy fty)
730 val <- if isHeapFTy fty then alloc ty else allocAtomic ty
731 tagptr <- inst $ GetElementPtr True val [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 0)] []
732 valptr <- inst $ GetElementPtr True val [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 1)] []
733 inst' $ Store False tagptr (ConstantOperand (C.Int 32 (-1))) Nothing 0 []
734 inst' $ Store False valptr fval Nothing 0 []
735 ptrI8 <- inst $ BitCast val (PointerType (IntegerType 8) (AddrSpace 0)) []
736 inst' $ simpleCall "llvm.invariant.start" [ConstantOperand $ C.Int 64 (-1), ptrI8]
737 inst $ BitCast val (PointerType valueType (AddrSpace 0)) []
739unbox :: FType -> Operand -> Codegen Operand
740unbox FUnit x = return x
742 val <- inst $ BitCast bval (PointerType (primTy (ftyToTy fty)) (AddrSpace 0)) []
743 fvalptr <- inst $ GetElementPtr True val [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 1)] []
744 inst $ loadInv fvalptr
746cgConst' :: TT.Const -> C.Constant
747cgConst' (TT.I i) = C.Int 32 (fromIntegral i)
748cgConst' (TT.B8 i) = C.Int 8 (fromIntegral i)
749cgConst' (TT.B16 i) = C.Int 16 (fromIntegral i)
750cgConst' (TT.B32 i) = C.Int 32 (fromIntegral i)
751cgConst' (TT.B64 i) = C.Int 64 (fromIntegral i)
752cgConst' (TT.B8V v) = C.Vector (map ((C.Int 8) . fromIntegral) . V.toList $ v)
753cgConst' (TT.B16V v) = C.Vector (map ((C.Int 16) . fromIntegral) . V.toList $ v)
754cgConst' (TT.B32V v) = C.Vector (map ((C.Int 32) . fromIntegral) . V.toList $ v)
755cgConst' (TT.B64V v) = C.Vector (map ((C.Int 64) . fromIntegral) . V.toList $ v)
757cgConst' (TT.BI i) = C.Array (IntegerType 8) (map (C.Int 8 . fromIntegral . fromEnum) (show i) ++ [C.Int 8 0])
758cgConst' (TT.Fl f) = C.Float (F.Double f)
759cgConst' (TT.Ch c) = C.Int 32 . fromIntegral . fromEnum $ c
760cgConst' (TT.Str s) = C.Array (IntegerType 8) (map (C.Int 8 . fromIntegral . fromEnum) s ++ [C.Int 8 0])
761cgConst' x = ierror $ "Unsupported constant: " ++ show x
763cgConst :: TT.Const -> Codegen Operand
764cgConst c@(TT.I _) = box (FArith (ATInt ITNative)) (ConstantOperand $ cgConst' c)
765cgConst c@(TT.B8 _) = box (FArith (ATInt (ITFixed IT8))) (ConstantOperand $ cgConst' c)
766cgConst c@(TT.B16 _) = box (FArith (ATInt (ITFixed IT16))) (ConstantOperand $ cgConst' c)
767cgConst c@(TT.B32 _) = box (FArith (ATInt (ITFixed IT32))) (ConstantOperand $ cgConst' c)
768cgConst c@(TT.B64 _) = box (FArith (ATInt (ITFixed IT64))) (ConstantOperand $ cgConst' c)
769cgConst c@(TT.B8V v) = box (FArith (ATInt (ITVec IT8 (V.length v)))) (ConstantOperand $ cgConst' c)
770cgConst c@(TT.B16V v) = box (FArith (ATInt (ITVec IT16 (V.length v)))) (ConstantOperand $ cgConst' c)
771cgConst c@(TT.B32V v) = box (FArith (ATInt (ITVec IT32 (V.length v)))) (ConstantOperand $ cgConst' c)
772cgConst c@(TT.B64V v) = box (FArith (ATInt (ITVec IT64 (V.length v)))) (ConstantOperand $ cgConst' c)
773cgConst c@(TT.Fl _) = box (FArith ATFloat) (ConstantOperand $ cgConst' c)
774cgConst c@(TT.Ch _) = box (FArith (ATInt ITChar)) (ConstantOperand $ cgConst' c)
775cgConst c@(TT.Str s) = do
776 str <- addGlobal' (ArrayType (1 + fromIntegral (length s)) (IntegerType 8)) (cgConst' c)
777 box FString (ConstantOperand $ C.GetElementPtr True str [C.Int 32 0, C.Int 32 0])
778cgConst c@(TT.BI i) = do
779 let stringRepLen = (if i < 0 then 2 else 1) + fromInteger (numDigits 10 i)
780 str <- addGlobal' (ArrayType stringRepLen (IntegerType 8)) (cgConst' c)
782 inst $ simpleCall "__gmpz_init_set_str" [mpz
783 , ConstantOperand $ C.GetElementPtr True str [ C.Int 32 0, C.Int 32 0]
784 , ConstantOperand $ C.Int 32 10
786 box (FArith (ATInt ITBig)) mpz
787cgConst x = return $ ConstantOperand nullValue
789numDigits :: Integer -> Integer -> Integer
790numDigits b n = 1 + fst (ilog b n) where
793 | otherwise = let (e, r) = ilog (b*b) n
794 in if r < b then (2*e, r) else (2*e+1, r `div` b)
796addGlobal :: Global -> Codegen ()
797addGlobal def = tell ([], [], [GlobalDefinition def])
799addGlobal' :: Type -> C.Constant -> Codegen C.Constant
800addGlobal' ty val = do
801 name <- getGlobalUnName
802 addGlobal $ globalVariableDefaults
804 , G.linkage = L.Internal
805 , G.hasUnnamedAddr = True
806 , G.isConstant = True
808 , G.initializer = Just val
810 return . C.GlobalReference $ name
813ensureCDecl :: String -> FType -> [FType] -> Codegen Operand
814ensureCDecl name rty argtys = do
815 syms <- gets foreignSyms
816 case M.lookup name syms of
817 Nothing -> do addGlobal (ffunDecl name rty argtys)
818 modify $ \s -> s { foreignSyms = M.insert name (rty, argtys) (foreignSyms s) }
819 Just (rty', argtys') -> unless (rty == rty' && argtys == argtys') . fail $
820 "Mismatched type declarations for foreign symbol \"" ++ name ++ "\": " ++ show (rty, argtys) ++ " vs " ++ show (rty', argtys')
821 return $ ConstantOperand (C.GlobalReference (Name name))
823ffunDecl :: String -> FType -> [FType] -> Global
824ffunDecl name rty argtys =
826 { G.returnType = ftyToTy rty
828 , G.parameters = (flip map argtys $ \fty ->
829 Parameter (ftyToTy fty) (UnName 0) []
833ftyToTy :: FType -> Type
834ftyToTy (FArith (ATInt ITNative)) = IntegerType 32
835ftyToTy (FArith (ATInt ITBig)) = PointerType mpzTy (AddrSpace 0)
836ftyToTy (FArith (ATInt (ITFixed ty))) = IntegerType (fromIntegral $ nativeTyWidth ty)
837ftyToTy (FArith (ATInt (ITVec e c)))
838 = VectorType (fromIntegral c) (IntegerType (fromIntegral $ nativeTyWidth e))
839ftyToTy (FArith (ATInt ITChar)) = IntegerType 32
840ftyToTy FString = PointerType (IntegerType 8) (AddrSpace 0)
841ftyToTy FUnit = VoidType
842ftyToTy FPtr = PointerType (IntegerType 8) (AddrSpace 0)
843ftyToTy (FArith ATFloat) = FloatingPointType 64 IEEE
844ftyToTy FAny = valueType
846-- Only use when known not to be ITBig
847itWidth :: IntTy -> Word32
850itWidth (ITFixed x) = fromIntegral $ nativeTyWidth x
851itWidth x = ierror $ "itWidth: " ++ show x
853itConst :: IntTy -> Integer -> C.Constant
854itConst (ITFixed n) x = C.Int (fromIntegral $ nativeTyWidth n) x
855itConst ITNative x = itConst (ITFixed IT32) x
856itConst ITChar x = itConst (ITFixed IT32) x
857itConst (ITVec elts size) x = C.Vector (replicate size (itConst (ITFixed elts) x))
859cgOp :: PrimFn -> [Operand] -> Codegen Operand
860cgOp (LTrunc ITBig ity) [x] = do
861 nx <- unbox (FArith (ATInt ITBig)) x
862 val <- inst $ simpleCall "mpz_get_ull" [nx]
864 (ITFixed IT64) -> return val
865 _ -> inst $ Trunc val (ftyToTy (FArith (ATInt ity))) []
866 box (FArith (ATInt ity)) v
867cgOp (LZExt from ITBig) [x] = do
868 nx <- unbox (FArith (ATInt from)) x
870 (ITFixed IT64) -> return nx
871 _ -> inst $ ZExt nx (IntegerType 64) []
873 inst' $ simpleCall "mpz_init_set_ull" [mpz, nx']
874 box (FArith (ATInt ITBig)) mpz
875cgOp (LSExt from ITBig) [x] = do
876 nx <- unbox (FArith (ATInt from)) x
878 (ITFixed IT64) -> return nx
879 _ -> inst $ SExt nx (IntegerType 64) []
881 inst' $ simpleCall "mpz_init_set_sll" [mpz, nx']
882 box (FArith (ATInt ITBig)) mpz
884-- ITChar, ITNative, and IT32 all share representation
885cgOp (LChInt ITNative) [x] = return x
886cgOp (LIntCh ITNative) [x] = return x
888cgOp (LSLt (ATInt ITBig)) [x,y] = mpzCmp IPred.SLT x y
889cgOp (LSLe (ATInt ITBig)) [x,y] = mpzCmp IPred.SLE x y
890cgOp (LEq (ATInt ITBig)) [x,y] = mpzCmp IPred.EQ x y
891cgOp (LSGe (ATInt ITBig)) [x,y] = mpzCmp IPred.SGE x y
892cgOp (LSGt (ATInt ITBig)) [x,y] = mpzCmp IPred.SGT x y
893cgOp (LPlus (ATInt ITBig)) [x,y] = mpzBin "add" x y
894cgOp (LMinus (ATInt ITBig)) [x,y] = mpzBin "sub" x y
895cgOp (LTimes (ATInt ITBig)) [x,y] = mpzBin "mul" x y
896cgOp (LSDiv (ATInt ITBig)) [x,y] = mpzBin "fdiv_q" x y
897cgOp (LSRem (ATInt ITBig)) [x,y] = mpzBin "fdiv_r" x y
898cgOp (LAnd ITBig) [x,y] = mpzBin "and" x y
899cgOp (LOr ITBig) [x,y] = mpzBin "ior" x y
900cgOp (LXOr ITBig) [x,y] = mpzBin "xor" x y
901cgOp (LCompl ITBig) [x] = mpzUn "com" x
902cgOp (LSHL ITBig) [x,y] = mpzBit "mul_2exp" x y
903cgOp (LASHR ITBig) [x,y] = mpzBit "fdiv_q_2exp" x y
905cgOp (LTrunc ITNative (ITFixed to)) [x]
906 | 32 >= nativeTyWidth to = iCoerce Trunc IT32 to x
907cgOp (LZExt ITNative (ITFixed to)) [x]
908 | 32 <= nativeTyWidth to = iCoerce ZExt IT32 to x
909cgOp (LSExt ITNative (ITFixed to)) [x]
910 | 32 <= nativeTyWidth to = iCoerce SExt IT32 to x
912cgOp (LTrunc (ITFixed from) ITNative) [x]
913 | nativeTyWidth from >= 32 = iCoerce Trunc from IT32 x
914cgOp (LZExt (ITFixed from) ITNative) [x]
915 | nativeTyWidth from <= 32 = iCoerce ZExt from IT32 x
916cgOp (LSExt (ITFixed from) ITNative) [x]
917 | nativeTyWidth from <= 32 = iCoerce SExt from IT32 x
919cgOp (LTrunc (ITFixed from) (ITFixed to)) [x]
920 | nativeTyWidth from > nativeTyWidth to = iCoerce Trunc from to x
921cgOp (LZExt (ITFixed from) (ITFixed to)) [x]
922 | nativeTyWidth from < nativeTyWidth to = iCoerce ZExt from to x
923cgOp (LSExt (ITFixed from) (ITFixed to)) [x]
924 | nativeTyWidth from < nativeTyWidth to = iCoerce SExt from to x
926cgOp (LSLt (ATInt ity)) [x,y] = iCmp ity IPred.SLT x y
927cgOp (LSLe (ATInt ity)) [x,y] = iCmp ity IPred.SLE x y
928cgOp (LLt ity) [x,y] = iCmp ity IPred.ULT x y
929cgOp (LLe ity) [x,y] = iCmp ity IPred.ULE x y
930cgOp (LEq (ATInt ity)) [x,y] = iCmp ity IPred.EQ x y
931cgOp (LSGe (ATInt ity)) [x,y] = iCmp ity IPred.SGE x y
932cgOp (LSGt (ATInt ity)) [x,y] = iCmp ity IPred.SGT x y
933cgOp (LGe ity) [x,y] = iCmp ity IPred.UGE x y
934cgOp (LGt ity) [x,y] = iCmp ity IPred.UGT x y
935cgOp (LPlus (ATInt ity)) [x,y] = ibin ity x y (Add False False)
936cgOp (LMinus (ATInt ity)) [x,y] = ibin ity x y (Sub False False)
937cgOp (LTimes (ATInt ity)) [x,y] = ibin ity x y (Mul False False)
938cgOp (LSDiv (ATInt ity)) [x,y] = ibin ity x y (SDiv False)
939cgOp (LSRem (ATInt ity)) [x,y] = ibin ity x y SRem
940cgOp (LUDiv ity) [x,y] = ibin ity x y (UDiv False)
941cgOp (LURem ity) [x,y] = ibin ity x y URem
942cgOp (LAnd ity) [x,y] = ibin ity x y And
943cgOp (LOr ity) [x,y] = ibin ity x y Or
944cgOp (LXOr ity) [x,y] = ibin ity x y Xor
945cgOp (LCompl ity) [x] = iun ity x (Xor . ConstantOperand $ itConst ity (-1))
946cgOp (LSHL ity) [x,y] = ibin ity x y (Shl False False)
947cgOp (LLSHR ity) [x,y] = ibin ity x y (LShr False)
948cgOp (LASHR ity) [x,y] = ibin ity x y (AShr False)
950cgOp LNoOp xs = return $ last xs
952cgOp (LMkVec ety c) xs | c == length xs = do
953 nxs <- mapM (unbox (FArith (ATInt (ITFixed ety)))) xs
954 vec <- foldM (\v (e, i) -> inst $ InsertElement v e (ConstantOperand (C.Int 32 i)) [])
955 (ConstantOperand $ C.Vector (replicate c (C.Undef (IntegerType . fromIntegral $ nativeTyWidth ety))))
957 box (FArith (ATInt (ITVec ety c))) vec
959cgOp (LIdxVec ety c) [v,i] = do
960 nv <- unbox (FArith (ATInt (ITVec ety c))) v
961 ni <- unbox (FArith (ATInt (ITFixed IT32))) i
962 elt <- inst $ ExtractElement nv ni []
963 box (FArith (ATInt (ITFixed ety))) elt
965cgOp (LUpdateVec ety c) [v,i,e] = do
966 let fty = FArith (ATInt (ITVec ety c))
968 ni <- unbox (FArith (ATInt (ITFixed IT32))) i
969 ne <- unbox (FArith (ATInt (ITFixed ety))) e
970 nv' <- inst $ InsertElement nv ne ni []
973cgOp (LBitCast from to) [x] = do
974 nx <- unbox (FArith from) x
975 nx' <- inst $ BitCast nx (ftyToTy (FArith to)) []
978cgOp LStrEq [x,y] = do
979 x' <- unbox FString x
980 y' <- unbox FString y
981 cmp <- inst $ simpleCall "strcmp" [x', y']
982 flag <- inst $ ICmp IPred.EQ cmp (ConstantOperand (C.Int 32 0)) []
983 val <- inst $ ZExt flag (IntegerType 32) []
984 box (FArith (ATInt (ITFixed IT32))) val
986cgOp LStrLt [x,y] = do
987 nx <- unbox FString x
988 ny <- unbox FString y
989 cmp <- inst $ simpleCall "strcmp" [nx, ny]
990 flag <- inst $ ICmp IPred.ULT cmp (ConstantOperand (C.Int 32 0)) []
991 val <- inst $ ZExt flag (IntegerType 32) []
992 box (FArith (ATInt (ITFixed IT32))) val
994cgOp (LIntStr ITBig) [x] = do
995 x' <- unbox (FArith (ATInt ITBig)) x
996 ustr <- inst $ simpleCall "__gmpz_get_str"
997 [ ConstantOperand (C.Null (PointerType (IntegerType 8) (AddrSpace 0)))
998 , ConstantOperand (C.Int 32 10)
1002cgOp (LIntStr ity) [x] = do
1003 x' <- unbox (FArith (ATInt ity)) x
1004 x'' <- if itWidth ity < 64
1005 then inst $ SExt x' (IntegerType 64) []
1007 box FString =<< inst (idrCall "__idris_intStr" [x''])
1008cgOp (LStrInt ITBig) [s] = do
1009 ns <- unbox FString s
1011 inst $ simpleCall "__gmpz_init_set_str" [mpz, ns, ConstantOperand $ C.Int 32 10]
1012 box (FArith (ATInt ITBig)) mpz
1013cgOp (LStrInt ity) [s] = do
1014 ns <- unbox FString s
1015 nx <- inst $ simpleCall "strtoll"
1017 , ConstantOperand $ C.Null (PointerType (PointerType (IntegerType 8) (AddrSpace 0)) (AddrSpace 0))
1018 , ConstantOperand $ C.Int 32 10
1021 (ITFixed IT64) -> return nx
1022 _ -> inst $ Trunc nx (IntegerType (itWidth ity)) []
1023 box (FArith (ATInt ity)) nx'
1025cgOp LStrConcat [x,y] = cgStrCat x y
1027cgOp LStrCons [c,s] = do
1028 nc <- unbox (FArith (ATInt ITChar)) c
1029 ns <- unbox FString s
1030 nc' <- inst $ Trunc nc (IntegerType 8) []
1031 r <- inst $ simpleCall "__idris_strCons" [nc', ns]
1034cgOp LStrHead [c] = do
1035 s <- unbox FString c
1036 c <- inst $ loadInv s
1037 c' <- inst $ ZExt c (IntegerType 32) []
1038 box (FArith (ATInt ITChar)) c'
1040cgOp LStrIndex [s, i] = do
1041 ns <- unbox FString s
1042 ni <- unbox (FArith (ATInt (ITFixed IT32))) i
1043 p <- inst $ GetElementPtr True ns [ni] []
1044 c <- inst $ loadInv p
1045 c' <- inst $ ZExt c (IntegerType 32) []
1046 box (FArith (ATInt ITChar)) c'
1048cgOp LStrTail [c] = do
1049 s <- unbox FString c
1050 c <- inst $ GetElementPtr True s [ConstantOperand $ C.Int 32 1] []
1053cgOp LStrLen [s] = do
1054 ns <- unbox FString s
1055 len <- inst $ simpleCall "strlen" [ns]
1059 x | x > 32 -> inst $ Trunc len (IntegerType 32) []
1060 | x < 32 -> inst $ ZExt len (IntegerType 32) []
1061 box (FArith (ATInt (ITFixed IT32))) len'
1063cgOp LStrRev [s] = do
1064 ns <- unbox FString s
1065 box FString =<< inst (simpleCall "__idris_strRev" [ns])
1067cgOp LReadStr [p] = do
1069 s <- inst $ simpleCall "__idris_readStr" [np]
1074 ptr <- inst $ loadInv stdin
1078 ptr <- inst $ loadInv stdout
1082 ptr <- inst $ loadInv stdErr
1085cgOp prim args = ierror $ "Unimplemented primitive: <" ++ show prim ++ ">("
1086 ++ intersperse ',' (take (length args) ['a'..]) ++ ")"
1088iCoerce :: (Operand -> Type -> InstructionMetadata -> Instruction) -> NativeTy -> NativeTy -> Operand -> Codegen Operand
1089iCoerce _ from to x | from == to = return x
1090iCoerce operator from to x = do
1091 x' <- unbox (FArith (ATInt (ITFixed from))) x
1092 x'' <- inst $ operator x' (ftyToTy (FArith (ATInt (ITFixed to)))) []
1093 box (FArith (ATInt (ITFixed to))) x''
1095cgStrCat :: Operand -> Operand -> Codegen Operand
1097 x' <- unbox FString x
1098 y' <- unbox FString y
1099 xlen <- inst $ simpleCall "strlen" [x']
1100 ylen <- inst $ simpleCall "strlen" [y']
1101 zlen <- inst $ Add False True xlen ylen []
1103 total <- inst $ Add False True zlen (ConstantOperand (C.Int ws 1)) []
1104 mem <- allocAtomic' total
1105 inst $ simpleCall "memcpy" [mem, x', xlen]
1106 i <- inst $ PtrToInt mem (IntegerType ws) []
1107 offi <- inst $ Add False True i xlen []
1108 offp <- inst $ IntToPtr offi (PointerType (IntegerType 8) (AddrSpace 0)) []
1109 inst $ simpleCall "memcpy" [offp, y', ylen]
1110 j <- inst $ PtrToInt offp (IntegerType ws) []
1111 offj <- inst $ Add False True j ylen []
1112 end <- inst $ IntToPtr offj (PointerType (IntegerType 8) (AddrSpace 0)) []
1113 inst' $ Store False end (ConstantOperand (C.Int 8 0)) Nothing 0 []
1116ibin :: IntTy -> Operand -> Operand
1117 -> (Operand -> Operand -> InstructionMetadata -> Instruction) -> Codegen Operand
1118ibin ity x y instCon = do
1119 nx <- unbox (FArith (ATInt ity)) x
1120 ny <- unbox (FArith (ATInt ity)) y
1121 nr <- inst $ instCon nx ny []
1122 box (FArith (ATInt ity)) nr
1124iun :: IntTy -> Operand -> (Operand -> InstructionMetadata -> Instruction) -> Codegen Operand
1125iun ity x instCon = do
1126 nx <- unbox (FArith (ATInt ity)) x
1127 nr <- inst $ instCon nx []
1128 box (FArith (ATInt ity)) nr
1130iCmp :: IntTy -> IPred.IntegerPredicate -> Operand -> Operand -> Codegen Operand
1131iCmp ity pred x y = do
1132 nx <- unbox (FArith (ATInt ity)) x
1133 ny <- unbox (FArith (ATInt ity)) y
1134 nr <- inst $ ICmp pred nx ny []
1135 nr' <- inst $ SExt nr (ftyToTy $ cmpResultTy ity) []
1136 box (cmpResultTy ity) nr'
1138cmpResultTy :: IntTy -> FType
1139cmpResultTy v@(ITVec _ _) = FArith (ATInt v)
1140cmpResultTy _ = FArith (ATInt (ITFixed IT32))
1142mpzBin :: String -> Operand -> Operand -> Codegen Operand
1144 nx <- unbox (FArith (ATInt ITBig)) x
1145 ny <- unbox (FArith (ATInt ITBig)) y
1147 inst' $ simpleCall "__gmpz_init" [nz]
1148 inst' $ simpleCall ("__gmpz_" ++ name) [nz, nx, ny]
1149 box (FArith (ATInt ITBig)) nz
1151mpzBit :: String -> Operand -> Operand -> Codegen Operand
1153 nx <- unbox (FArith (ATInt ITBig)) x
1154 ny <- unbox (FArith (ATInt ITBig)) y
1155 bitcnt <- inst $ simpleCall "__gmpz_get_ui" [ny]
1157 inst' $ simpleCall "__gmpz_init" [nz]
1158 inst' $ simpleCall ("__gmpz_" ++ name) [nz, nx, bitcnt]
1159 box (FArith (ATInt ITBig)) nz
1161mpzUn :: String -> Operand -> Codegen Operand
1163 nx <- unbox (FArith (ATInt ITBig)) x
1165 inst' $ simpleCall "__gmpz_init" [nz]
1166 inst' $ simpleCall ("__gmpz_" ++ name) [nz, nx]
1167 box (FArith (ATInt ITBig)) nz
1169mpzCmp :: IPred.IntegerPredicate -> Operand -> Operand -> Codegen Operand
1171 nx <- unbox (FArith (ATInt ITBig)) x
1172 ny <- unbox (FArith (ATInt ITBig)) y
1173 cmp <- inst $ simpleCall "__gmpz_cmp" [nx, ny]
1174 result <- inst $ ICmp pred cmp (ConstantOperand (C.Int 32 0)) []
1175 i <- inst $ ZExt result (IntegerType 32) []
1176 box (FArith (ATInt (ITFixed IT32))) i
1178simpleCall :: String -> [Operand] -> Instruction
1179simpleCall name args =
1180 Call { isTailCall = False
1181 , callingConvention = CC.C
1182 , returnAttributes = []
1183 , function = Right . ConstantOperand . C.GlobalReference . Name $ name
1184 , arguments = map (\x -> (x, [])) args
1185 , functionAttributes = []
1189idrCall :: String -> [Operand] -> Instruction
1191 Call { isTailCall = False
1192 , callingConvention = CC.Fast
1193 , returnAttributes = []
1194 , function = Right . ConstantOperand . C.GlobalReference . Name $ name
1195 , arguments = map (\x -> (x, [])) args
1196 , functionAttributes = []
1200assert :: Operand -> String -> Codegen ()
1201assert condition message = do
1202 passed <- getName "assertPassed"
1203 failed <- getName "assertFailed"
1204 terminate $ CondBr condition passed failed []
1206 cgExpr (SError message)
1207 terminate $ Unreachable []
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list