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
18import LLVM.General.AST.DataLayout
19import LLVM.General.PassManager
20import qualified LLVM.General.Module as M
21import qualified LLVM.General.AST.IntegerPredicate as IPred
22import qualified LLVM.General.AST.Linkage as L
23import qualified LLVM.General.AST.Visibility as V
24import qualified LLVM.General.AST.CallingConvention as CC
25import qualified LLVM.General.AST.Attribute as A
26import qualified LLVM.General.AST.Global as G
27import qualified LLVM.General.AST.Constant as C
28import qualified LLVM.General.AST.Float as F
29import qualified LLVM.General.Relocation as R
30import qualified LLVM.General.CodeModel as CM
31import qualified LLVM.General.CodeGenOpt as CGO
37import qualified Data.Set as S
38import qualified Data.Map as M
39import qualified Data.Vector.Unboxed as V
40import Control.Applicative
41import Control.Monad.RWS
42import Control.Monad.Writer
43import Control.Monad.State
44import Control.Monad.Error
46import qualified System.Info as SI (arch, os)
48import System.Directory (removeFile)
49import System.FilePath ((</>))
50import System.Process (rawSystem)
51import System.Exit (ExitCode(..))
54data Target = Target { triple :: String, dataLayout :: DataLayout }
56codegenLLVM :: [(TT.Name, SDecl)] ->
57 String -> -- target triple
58 String -> -- target CPU
59 Int -> -- Optimization degree
60 FilePath -> -- output file name
63codegenLLVM defs triple cpu optimize file outty = withContext $ \context -> do
65 (target, _) <- failInIO $ lookupTarget Nothing triple
66 withTargetOptions $ \options ->
67 withTargetMachine target triple cpu S.empty options R.Default CM.Default CGO.Default $ \tm ->
68 do layout <- getTargetMachineDataLayout tm
69 let ast = codegen (Target triple layout) (map snd defs)
70 result <- runErrorT . M.withModuleFromAST context ast $ \m ->
71 do let opts = defaultCuratedPassSetSpec
72 { optLevel = Just optimize
73 , simplifyLibCalls = Just True
74 , useInlinerWithThreshold = Just 225
76 when (optimize /= 0) $ withPassManager opts $ void . flip runPassManager m
77 outputModule tm file outty m
80 Left msg -> ierror msg
82failInIO :: ErrorT String IO a -> IO a
83failInIO = either fail return <=< runErrorT
85outputModule :: TargetMachine -> FilePath -> OutputType -> M.Module -> IO ()
86outputModule _ file Raw m = failInIO $ M.writeBitcodeToFile file m
87outputModule tm file Object m = failInIO $ M.writeObjectToFile tm file m
88outputModule tm file Executable m = withTmpFile $ \obj -> do
89 outputModule tm obj Object m
91 defs <- (</> "llvm" </> "libidris_rts.a") <$> getDataDir
92 exit <- rawSystem cc [obj, defs, "-lm", "-lgmp", "-lgc", "-o", file]
93 when (exit /= ExitSuccess) $ ierror "FAILURE: Linking"
95withTmpFile :: (FilePath -> IO a) -> IO a
97 (path, handle) <- tempfile
104ierror msg = error $ "INTERNAL ERROR: IRTS.CodegenLLVM: " ++ msg
109 { G.returnType = IntegerType 32
111 ([ Parameter (IntegerType 32) (Name "argc") []
112 , Parameter (PointerType (PointerType (IntegerType 8) (AddrSpace 0)) (AddrSpace 0)) (Name "argv") []
114 , G.name = Name "main"
116 [ BasicBlock (UnName 0)
117 [ Do $ simpleCall "GC_init" [] -- Initialize Boehm GC
118 , Do $ simpleCall "__gmp_set_memory_functions"
119 [ ConstantOperand . C.GlobalReference . Name $ "__idris_gmpMalloc"
120 , ConstantOperand . C.GlobalReference . Name $ "__idris_gmpRealloc"
121 , ConstantOperand . C.GlobalReference . Name $ "__idris_gmpFree"
123 , UnName 1 := idrCall "{runMain0}" [] ]
124 (Do $ Ret (Just (ConstantOperand (C.Int 32 0))) [])
127initDefs :: Target -> [Definition]
129 [ TypeDefinition (Name "valTy")
130 (Just $ StructureType False
132 , ArrayType 0 (PointerType valueType (AddrSpace 0))
134 , TypeDefinition (Name "mpz")
135 (Just $ StructureType False
138 , PointerType intPtr (AddrSpace 0)
140 , GlobalDefinition $ globalVariableDefaults
141 { G.name = Name "__idris_intFmtStr"
142 , G.linkage = L.Internal
143 , G.isConstant = True
144 , G.hasUnnamedAddr = True
145 , G.type' = ArrayType 5 (IntegerType 8)
146 , G.initializer = Just $ C.Array (IntegerType 8) (map (C.Int 8 . fromIntegral . fromEnum) "%lld" ++ [C.Int 8 0])
148 , rtsFun "intStr" ptrI8 [IntegerType 64]
149 [ BasicBlock (UnName 0)
150 [ UnName 1 := simpleCall "GC_malloc_atomic" [ConstantOperand (C.Int (tgtWordSize tgt) 21)]
151 , UnName 2 := simpleCall "snprintf"
152 [ LocalReference (UnName 1)
153 , ConstantOperand (C.Int (tgtWordSize tgt) 21)
154 , ConstantOperand $ C.GetElementPtr True (C.GlobalReference . Name $ "__idris_intFmtStr") [C.Int 32 0, C.Int 32 0]
155 , LocalReference (UnName 0)
158 (Do $ Ret (Just (LocalReference (UnName 1))) [])
160 , exfun "llvm.trap" VoidType [] False
161 -- , exfun "llvm.llvm.memcpy.p0i8.p0i8.i32" VoidType [ptrI8, ptrI8, IntegerType 32, IntegerType 32, IntegerType 1] False
162 -- , exfun "llvm.llvm.memcpy.p0i8.p0i8.i64" VoidType [ptrI8, ptrI8, IntegerType 64, IntegerType 32, IntegerType 1] False
163 , exfun "memcpy" ptrI8 [ptrI8, ptrI8, intPtr] False
164 , exfun "llvm.invariant.start" (PointerType (StructureType False []) (AddrSpace 0)) [IntegerType 64, ptrI8] False
165 , exfun "snprintf" (IntegerType 32) [ptrI8, intPtr, ptrI8] True
166 , exfun "strcmp" (IntegerType 32) [ptrI8, ptrI8] False
167 , exfun "strlen" intPtr [ptrI8] False
168 , exfun "GC_init" VoidType [] False
169 , exfun "GC_malloc" ptrI8 [intPtr] False
170 , exfun "GC_malloc_atomic" ptrI8 [intPtr] False
171 , exfun "__gmp_set_memory_functions" VoidType
172 [ PointerType (FunctionType ptrI8 [intPtr] False) (AddrSpace 0)
173 , PointerType (FunctionType ptrI8 [ptrI8, intPtr, intPtr] False) (AddrSpace 0)
174 , PointerType (FunctionType VoidType [ptrI8, intPtr] False) (AddrSpace 0)
176 , exfun "__gmpz_init" VoidType [pmpz] False
177 , exfun "__gmpz_init_set_str" (IntegerType 32) [pmpz, ptrI8, IntegerType 32] False
178 , exfun "__gmpz_get_str" ptrI8 [ptrI8, IntegerType 32, pmpz] False
179 , exfun "__gmpz_cmp" (IntegerType 32) [pmpz, pmpz] False
180 , exfun "mpz_get_ull" (IntegerType 64) [pmpz] False
181 , exfun "mpz_init_set_ull" VoidType [pmpz, IntegerType 64] False
182 , exfun "mpz_init_set_sll" VoidType [pmpz, IntegerType 64] False
183 , exfun "__idris_strCons" ptrI8 [IntegerType 8, ptrI8] False
184 , exfun "__idris_readStr" ptrI8 [ptrI8] False -- Actually pointer to FILE, but it's opaque anyway
185 , exfun "__idris_gmpMalloc" ptrI8 [intPtr] False
186 , exfun "__idris_gmpRealloc" ptrI8 [ptrI8, intPtr, intPtr] False
187 , exfun "__idris_gmpFree" VoidType [ptrI8, intPtr] False
188 , exfun "strtoll" (IntegerType 64) [ptrI8, PointerType ptrI8 (AddrSpace 0), IntegerType 32] False
189 , exVar (stdinName tgt) ptrI8
190 , exVar (stdoutName tgt) ptrI8
191 , exVar (stderrName tgt) ptrI8
192 , GlobalDefinition mainDef
193 ] ++ map mpzBinFun ["add", "sub", "mul", "fdiv_q", "fdiv_r", "and", "ior", "xor"]
195 intPtr = IntegerType (tgtWordSize tgt)
196 ptrI8 = PointerType (IntegerType 8) (AddrSpace 0)
197 pmpz = PointerType mpzTy (AddrSpace 0)
199 mpzBinFun n = exfun ("__gmpz_" ++ n) VoidType [pmpz, pmpz, pmpz] False
201 rtsFun :: String -> Type -> [Type] -> [BasicBlock] -> Definition
202 rtsFun name rty argtys def =
203 GlobalDefinition $ functionDefaults
204 { G.linkage = L.Internal
206 , G.parameters = (flip map argtys $ \ty -> Parameter ty (UnName 0) [], False)
207 , G.name = Name $ "__idris_" ++ name
208 , G.basicBlocks = def
211 exfun :: String -> Type -> [Type] -> Bool -> Definition
212 exfun name rty argtys vari =
213 GlobalDefinition $ functionDefaults
216 , G.parameters = (flip map argtys $ \ty -> Parameter ty (UnName 0) [], vari)
218 exVar :: String -> Type -> Definition
219 exVar name ty = GlobalDefinition $ globalVariableDefaults { G.name = Name name, G.type' = ty }
221isApple :: Target -> Bool
222isApple (Target { triple = t }) = isJust . stripPrefix "-apple" $ dropWhile (/= '-') t
224stdinName, stdoutName, stderrName :: Target -> String
225stdinName t | isApple t = "__stdinp"
227stdoutName t | isApple t = "__stdoutp"
228stdoutName _ = "stdout"
229stderrName t | isApple t = "__stderrp"
230stderrName _ = "stderr"
232getStdIn, getStdOut, getStdErr :: Codegen Operand
233getStdIn = ConstantOperand . C.GlobalReference . Name . stdinName <$> asks target
234getStdOut = ConstantOperand . C.GlobalReference . Name . stdoutName <$> asks target
235getStdErr = ConstantOperand . C.GlobalReference . Name . stderrName <$> asks target
237codegen :: Target -> [SDecl] -> Module
238codegen tgt defs = Module "idris" (Just . dataLayout $ tgt) (Just . triple $ tgt) (initDefs tgt ++ globals ++ gendefs)
240 (gendefs, _, globals) = runRWS (mapM cgDef defs) tgt 0
243valueType = NamedTypeReference (Name "valTy")
245nullValue :: C.Constant
246nullValue = C.Null (PointerType valueType (AddrSpace 0))
248primTy :: Type -> Type
249primTy inner = StructureType False [IntegerType 32, inner]
252mpzTy = NamedTypeReference (Name "mpz")
254conType :: Word64 -> Type
255conType nargs = StructureType False
257 , ArrayType nargs (PointerType valueType (AddrSpace 0))
260type Modgen = RWS Target [Definition] Word
262cgDef :: SDecl -> Modgen Definition
263cgDef (SFun name argNames _ expr) = do
266 let (_, CGS { nextGlobalName = nextGlobal' }, (allocas, bbs, globals)) =
267 runRWS (do r <- cgExpr expr
269 Nothing -> terminate $ Unreachable []
270 Just r' -> terminate $ Ret (Just r') [])
271 (CGR tgt (show name))
272 (CGS 0 nextGlobal (Name "begin") [] (map (Just . LocalReference . Name . show) argNames) S.empty)
273 entryTerm = case bbs of
274 [] -> Do $ Ret Nothing []
275 BasicBlock n _ _:_ -> Do $ Br n []
278 return . GlobalDefinition $ functionDefaults
279 { G.linkage = L.Internal
280 , G.callingConvention = CC.Fast
281 , G.name = Name (show name)
282 , G.returnType = PointerType valueType (AddrSpace 0)
283 , G.parameters = (flip map argNames $ \argName ->
284 Parameter (PointerType valueType (AddrSpace 0)) (Name (show argName)) []
287 BasicBlock (Name "entry")
288 (map (\(n, t) -> n := Alloca t Nothing 0 []) allocas)
293type CGW = ([(Name, Type)], [BasicBlock], [Definition])
295type Env = [Maybe Operand]
297data CGS = CGS { nextName :: Word
298 , nextGlobalName :: Word
299 , currentBlockName :: Name
300 , instAccum :: [Named Instruction]
302 , foreignSyms :: Set String
305data CGR = CGR { target :: Target
306 , funcName :: String }
308type Codegen = RWS CGR CGW CGS
310getFuncName :: Codegen String
311getFuncName = asks funcName
313getGlobalUnName :: Codegen Name
315 i <- gets nextGlobalName
316 modify $ \s -> s { nextGlobalName = 1 + i }
319getUnName :: Codegen Name
322 modify $ \s -> s { nextName = 1 + i }
325getName :: String -> Codegen Name
328 modify $ \s -> s { nextName = 1 + i }
329 return (Name $ n ++ show i)
331alloca :: Name -> Type -> Codegen ()
332alloca n t = tell ([(n, t)], [], [])
334terminate :: Terminator -> Codegen ()
336 name <- gets currentBlockName
337 insts <- gets instAccum
338 modify $ \s -> s { instAccum = ierror "Not in a block"
339 , currentBlockName = ierror "Not in a block" }
340 tell ([], [BasicBlock name insts (Do term)], [])
342newBlock :: Name -> Codegen ()
343newBlock name = modify $ \s -> s { instAccum = []
344 , currentBlockName = name
347inst :: Instruction -> Codegen Operand
350 modify $ \s -> s { instAccum = instAccum s ++ [n := i] }
351 return $ LocalReference n
353ninst :: String -> Instruction -> Codegen Operand
356 modify $ \s -> s { instAccum = instAccum s ++ [n := i] }
357 return $ LocalReference n
359inst' :: Instruction -> Codegen ()
360inst' i = modify $ \s -> s { instAccum = instAccum s ++ [Do i] }
362insts :: [Named Instruction] -> Codegen ()
363insts is = modify $ \s -> s { instAccum = instAccum s ++ is }
365var :: LVar -> Codegen (Maybe Operand)
366var (Loc level) = (!! level) <$> gets lexenv
367var (Glob n) = return . Just . ConstantOperand . C.GlobalReference . Name $ show n
369binds :: Env -> Codegen (Maybe Operand) -> Codegen (Maybe Operand)
371 envLen <- length <$> gets lexenv
372 modify $ \s -> s { lexenv = lexenv s ++ vals }
374 modify $ \s -> s { lexenv = take envLen $ lexenv s }
377replaceElt :: Int -> a -> [a] -> [a]
378replaceElt _ val [] = error "replaceElt: Ran out of list"
379replaceElt 0 val (x:xs) = val:xs
380replaceElt n val (x:xs) = x : replaceElt (n-1) val xs
382alloc' :: Operand -> Codegen Operand
383alloc' size = inst $ simpleCall "GC_malloc" [size]
385allocAtomic :: Operand -> Codegen Operand
386allocAtomic size = inst $ simpleCall "GC_malloc_atomic" [size]
388alloc :: Type -> Codegen Operand
392 inst $ BitCast mem (PointerType ty (AddrSpace 0)) []
394sizeOf :: Type -> Codegen Operand
395sizeOf ty = ConstantOperand . C.PtrToInt
396 (C.GetElementPtr True (C.Null (PointerType ty (AddrSpace 0))) [C.Int 32 1])
397 . IntegerType <$> getWordSize
399loadInv :: Operand -> Instruction
400loadInv ptr = Load False ptr Nothing 0 [("invariant.load", MetadataNode [])]
402tgtWordSize :: Target -> Word32
403tgtWordSize (Target { dataLayout = DataLayout { pointerLayouts = l } }) =
404 fst . fromJust $ M.lookup (AddrSpace 0) l
406getWordSize :: Codegen Word32
407getWordSize = tgtWordSize <$> asks target
409cgExpr :: SExp -> Codegen (Maybe Operand)
411cgExpr (SApp tailcall fname args) = do
412 argSlots <- mapM var args
413 case sequence argSlots of
414 Nothing -> return Nothing
416 fn <- var (Glob fname)
417 Just <$> inst ((idrCall (show fname) argVals) { isTailCall = tailcall })
418cgExpr (SLet _ varExpr bodyExpr) = do
419 val <- cgExpr varExpr
420 binds [val] $ cgExpr bodyExpr
421cgExpr (SUpdate (Loc level) expr) = do
423 modify $ \s -> s { lexenv = replaceElt level val (lexenv s) }
425cgExpr (SCon tag name args) = do
426 argSlots <- mapM var args
427 case sequence argSlots of
428 Nothing -> return Nothing
430 let ty = conType . fromIntegral . length $ argVals
432 tagPtr <- inst $ GetElementPtr True con [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 0)] []
433 inst' $ Store False tagPtr (ConstantOperand (C.Int 32 (fromIntegral tag))) Nothing 0 []
434 forM_ (zip argVals [0..]) $ \(arg, i) -> do
435 ptr <- inst $ GetElementPtr True con [ ConstantOperand (C.Int 32 0)
436 , ConstantOperand (C.Int 32 1)
437 , ConstantOperand (C.Int 32 i)] []
438 inst' $ Store False ptr arg Nothing 0 []
439 ptrI8 <- inst $ BitCast con (PointerType (IntegerType 8) (AddrSpace 0)) []
440 inst' $ simpleCall "llvm.invariant.start" [ConstantOperand $ C.Int 64 (-1), ptrI8]
441 Just <$> inst (BitCast con (PointerType valueType (AddrSpace 0)) [])
442cgExpr (SCase inspect alts) = do
445 Nothing -> return Nothing
446 Just v -> cgCase v alts
447cgExpr (SChkCase inspect alts) = do
450 Nothing -> return Nothing
452 do endBBN <- getName "endChkCase"
453 notNullBBN <- getName "notNull"
454 originBlock <- gets currentBlockName
455 isNull <- inst $ ICmp IPred.EQ val (ConstantOperand nullValue) []
456 terminate $ CondBr isNull endBBN notNullBBN []
458 ptr <- inst $ BitCast val (PointerType (IntegerType 32) (AddrSpace 0)) []
459 flag <- inst $ loadInv ptr
460 isVal <- inst $ ICmp IPred.EQ flag (ConstantOperand (C.Int 32 (-1))) []
461 conBBN <- getName "constructor"
462 terminate $ CondBr isVal endBBN conBBN []
464 result <- cgCase val alts
465 caseExitBlock <- gets currentBlockName
468 terminate $ Unreachable []
472 terminate $ Br endBBN []
474 Just <$> inst (Phi (PointerType valueType (AddrSpace 0))
475 [(val, originBlock), (val, notNullBBN), (caseVal, caseExitBlock)] [])
476cgExpr (SProj conVar idx) = do
479 Nothing -> return Nothing
481 do ptr <- inst $ GetElementPtr True v
482 [ ConstantOperand (C.Int 32 0)
483 , ConstantOperand (C.Int 32 1)
484 , ConstantOperand (C.Int 32 (fromIntegral idx))
486 Just <$> inst (loadInv ptr)
487cgExpr (SConst c) = Just <$> cgConst c
488cgExpr (SForeign LANG_C rty fname args) = do
489 func <- ensureCDecl fname rty (map fst args)
490 argVals <- forM args $ \(fty, v) -> do
493 Just val -> return $ Just (fty, val)
494 Nothing -> return Nothing
495 case sequence argVals of
496 Nothing -> return Nothing
498 argUVals <- mapM (uncurry unbox) argVals'
499 result <- inst Call { isTailCall = False
500 , callingConvention = CC.C
501 , returnAttributes = []
502 , function = Right func
503 , arguments = map (\v -> (v, [])) argUVals
504 , functionAttributes = []
507 Just <$> box rty result
508cgExpr (SOp fn args) = do
509 argVals <- mapM var args
510 case sequence argVals of
511 Just ops -> Just <$> cgOp fn ops
512 Nothing -> return Nothing
513cgExpr SNothing = return . Just . ConstantOperand $ nullValue
514cgExpr (SError msg) = do -- TODO: Print message
515 str <- addGlobal' (ArrayType (2 + fromIntegral (length msg)) (IntegerType 8))
516 (cgConst' (TT.Str (msg ++ "\n")))
517 inst' $ simpleCall "putStr" [ConstantOperand $ C.GetElementPtr True str [ C.Int 32 0
519 inst' Call { isTailCall = True
520 , callingConvention = CC.C
521 , returnAttributes = []
522 , function = Right . ConstantOperand . C.GlobalReference . Name $ "llvm.trap"
524 , functionAttributes = [A.NoReturn]
529cgCase :: Operand -> [SAlt] -> Codegen (Maybe Operand)
531 case find isConstCase alts of
532 Just (SConstCase (TT.BI _) _) -> cgChainCase val defExp constAlts
533 Just (SConstCase (TT.Str _) _) -> cgChainCase val defExp constAlts
534 Just (SConstCase _ _) -> cgPrimCase val defExp constAlts
535 Nothing -> cgConCase val defExp conAlts
537 defExp = getDefExp =<< find isDefCase alts
538 constAlts = filter isConstCase alts
539 conAlts = filter isConCase alts
541 isConstCase (SConstCase {}) = True
542 isConstCase _ = False
544 isConCase (SConCase {}) = True
547 isDefCase (SDefaultCase _) = True
550 getDefExp (SDefaultCase e) = Just e
551 getDefExp _ = Nothing
553cgPrimCase :: Operand -> Maybe SExp -> [SAlt] -> Codegen (Maybe Operand)
554cgPrimCase caseValPtr defExp alts = do
555 let caseTy = case head alts of
556 SConstCase (TT.I _) _ -> IntegerType 32
557 SConstCase (TT.B8 _) _ -> IntegerType 8
558 SConstCase (TT.B16 _) _ -> IntegerType 16
559 SConstCase (TT.B32 _) _ -> IntegerType 32
560 SConstCase (TT.B64 _) _ -> IntegerType 64
561 SConstCase (TT.Fl _) _ -> FloatingPointType 64 IEEE
562 SConstCase (TT.Ch _) _ -> IntegerType 32
563 realPtr <- inst $ BitCast caseValPtr (PointerType (primTy caseTy) (AddrSpace 0)) []
564 valPtr <- inst $ GetElementPtr True realPtr [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 1)] []
565 caseVal <- inst $ loadInv valPtr
566 defBlockName <- getName "default"
567 exitBlockName <- getName "caseExit"
568 namedAlts <- mapM (\a -> do n <- nameAlt defBlockName a; return (n, a)) alts
569 terminate $ Switch caseVal defBlockName (map (\(n, SConstCase c _) -> (cgConst' c, n)) namedAlts) []
570 initEnv <- gets lexenv
571 defResult <- cgDefaultAlt exitBlockName defBlockName defExp
572 results <- forM namedAlts $ \(name, SConstCase _ exp) -> cgAlt initEnv exitBlockName name Nothing exp
573 finishCase initEnv exitBlockName (defResult:results)
575cgConCase :: Operand -> Maybe SExp -> [SAlt] -> Codegen (Maybe Operand)
576cgConCase con defExp alts = do
577 tagPtr <- inst $ GetElementPtr True con [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 0)] []
578 tag <- inst $ loadInv tagPtr
579 defBlockName <- getName "default"
580 exitBlockName <- getName "caseExit"
581 namedAlts <- mapM (\a -> do n <- nameAlt defBlockName a; return (n, a)) alts
582 terminate $ Switch tag defBlockName (map (\(n, SConCase _ tag _ _ _) ->
583 (C.Int 32 (fromIntegral tag), n)) namedAlts) []
584 initEnv <- gets lexenv
585 defResult <- cgDefaultAlt exitBlockName defBlockName defExp
586 results <- forM namedAlts $ \(name, SConCase _ _ _ argns exp) ->
587 cgAlt initEnv exitBlockName name (Just (con, map show argns)) exp
588 finishCase initEnv exitBlockName (defResult:results)
590cgChainCase :: Operand -> Maybe SExp -> [SAlt] -> Codegen (Maybe Operand)
591cgChainCase caseValPtr defExp alts = do
592 let (caseTy, comparator) =
594 SConstCase (TT.BI _) _ -> (FArith (ATInt ITBig), "__gmpz_cmp")
595 SConstCase (TT.Str _) _ -> (FString, "strcmp")
596 caseVal <- unbox caseTy caseValPtr
597 defBlockName <- getName "default"
598 exitBlockName <- getName "caseExit"
599 namedAlts <- mapM (\a -> do n <- nameAlt defBlockName a; return (n, a)) alts
600 initEnv <- gets lexenv
601 results <- forM namedAlts $ \(name, SConstCase c e) ->
602 do const <- unbox caseTy =<< cgConst c
603 cmp <- inst $ simpleCall comparator [const, caseVal]
604 cmpResult <- inst $ ICmp IPred.EQ cmp (ConstantOperand (C.Int 32 0)) []
605 elseName <- getName "else"
606 terminate $ CondBr cmpResult name elseName []
607 result <- cgAlt initEnv exitBlockName name Nothing e
610 modify $ \s -> s { lexenv = initEnv }
612 defaultVal <- cgExpr (fromMaybe (SError $ "Inexhaustive case failure in " ++ fname) defExp)
613 defaultBlock <- gets currentBlockName
614 defaultEnv <- gets lexenv
615 defResult <- case defaultVal of
617 terminate $ Br exitBlockName []
618 return $ Just (v, defaultBlock, defaultEnv)
620 terminate $ Unreachable []
622 finishCase initEnv exitBlockName (defResult:results)
624finishCase :: Env -> Name -> [Maybe (Operand, Name, Env)] -> Codegen (Maybe Operand)
625finishCase initEnv exitBlockName results = do
626 let definedResults = mapMaybe id results
627 case definedResults of
628 [] -> do modify $ \s -> s { lexenv = initEnv }
631 newBlock exitBlockName
632 mergeEnvs $ map (\(_, altBlock, altEnv) -> (altBlock, altEnv)) xs
633 Just <$> inst (Phi (PointerType valueType (AddrSpace 0))
634 (map (\(altVal, altBlock, _) -> (altVal, altBlock)) xs) [])
637cgDefaultAlt :: Name -> Name -> Maybe SExp -> Codegen (Maybe (Operand, Name, Env))
638cgDefaultAlt exitName name exp = do
641 val <- cgExpr (fromMaybe (SError $ "Inexhaustive case failure in " ++ fname) exp)
643 block <- gets currentBlockName
646 do terminate $ Br exitName []
647 return $ Just (v, block, env)
649 do terminate $ Unreachable []
652cgAlt :: Env -> Name -> Name -> Maybe (Operand, [String]) -> SExp
653 -> Codegen (Maybe (Operand, Name, Env))
654cgAlt initEnv exitBlockName name destr exp = do
655 modify $ \s -> s { lexenv = initEnv }
657 locals <- case destr of
660 forM (zip argns [0..]) $ \(argName, i) ->
661 do ptr <- inst $ GetElementPtr True con [ ConstantOperand (C.Int 32 0)
662 , ConstantOperand (C.Int 32 1)
663 , ConstantOperand (C.Int 32 i)] []
664 Just <$> ninst argName (loadInv ptr)
665 altVal <- binds locals $ cgExpr exp
666 altEnv <- gets lexenv
667 altBlock <- gets currentBlockName
670 terminate $ Br exitBlockName []
671 return $ Just (v, altBlock, altEnv)
673 terminate $ Unreachable []
676mergeEnvs :: [(Name, Env)] -> Codegen ()
679 . map (\(block, env) -> map (\x -> (x, block)) env)
681 env <- forM vars $ \var ->
683 [] -> ierror "mergeEnvs: impossible"
686 | all (== v) (map fst vs) -> return v
688 let valid = map (\(a, b) -> (fromJust a, b)) . filter (isJust . fst) $ vs in
689 Just <$> inst (Phi (PointerType valueType (AddrSpace 0)) valid [])
690 modify $ \s -> s { lexenv = env }
692nameAlt :: Name -> SAlt -> Codegen Name
693nameAlt d (SDefaultCase _) = return d
694nameAlt _ (SConCase _ _ name _ _) = getName (show name)
695nameAlt _ (SConstCase const _) = getName (show const)
697box :: FType -> Operand -> Codegen Operand
698box FUnit _ = return $ ConstantOperand nullValue
700 let ty = primTy (ftyToTy fty)
702 tagptr <- inst $ GetElementPtr True val [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 0)] []
703 valptr <- inst $ GetElementPtr True val [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 1)] []
704 inst' $ Store False tagptr (ConstantOperand (C.Int 32 (-1))) Nothing 0 []
705 inst' $ Store False valptr fval Nothing 0 []
706 ptrI8 <- inst $ BitCast val (PointerType (IntegerType 8) (AddrSpace 0)) []
707 inst' $ simpleCall "llvm.invariant.start" [ConstantOperand $ C.Int 64 (-1), ptrI8]
708 inst $ BitCast val (PointerType valueType (AddrSpace 0)) []
710unbox :: FType -> Operand -> Codegen Operand
711unbox FUnit x = return x
713 val <- inst $ BitCast bval (PointerType (primTy (ftyToTy fty)) (AddrSpace 0)) []
714 fvalptr <- inst $ GetElementPtr True val [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 1)] []
715 inst $ loadInv fvalptr
717cgConst' :: TT.Const -> C.Constant
718cgConst' (TT.I i) = C.Int 32 (fromIntegral i)
719cgConst' (TT.B8 i) = C.Int 8 (fromIntegral i)
720cgConst' (TT.B16 i) = C.Int 16 (fromIntegral i)
721cgConst' (TT.B32 i) = C.Int 32 (fromIntegral i)
722cgConst' (TT.B64 i) = C.Int 64 (fromIntegral i)
723cgConst' (TT.B8V v) = C.Vector (map ((C.Int 8) . fromIntegral) . V.toList $ v)
724cgConst' (TT.B16V v) = C.Vector (map ((C.Int 16) . fromIntegral) . V.toList $ v)
725cgConst' (TT.B32V v) = C.Vector (map ((C.Int 32) . fromIntegral) . V.toList $ v)
726cgConst' (TT.B64V v) = C.Vector (map ((C.Int 64) . fromIntegral) . V.toList $ v)
728cgConst' (TT.BI i) = C.Array (IntegerType 8) (map (C.Int 8 . fromIntegral . fromEnum) (show i) ++ [C.Int 8 0])
729cgConst' (TT.Fl f) = C.Float (F.Double f)
730cgConst' (TT.Ch c) = C.Int 32 . fromIntegral . fromEnum $ c
731cgConst' (TT.Str s) = C.Array (IntegerType 8) (map (C.Int 8 . fromIntegral . fromEnum) s ++ [C.Int 8 0])
732cgConst' x = ierror $ "Unsupported constant: " ++ show x
734cgConst :: TT.Const -> Codegen Operand
735cgConst c@(TT.I _) = box (FArith (ATInt ITNative)) (ConstantOperand $ cgConst' c)
736cgConst c@(TT.B8 _) = box (FArith (ATInt (ITFixed IT8))) (ConstantOperand $ cgConst' c)
737cgConst c@(TT.B16 _) = box (FArith (ATInt (ITFixed IT16))) (ConstantOperand $ cgConst' c)
738cgConst c@(TT.B32 _) = box (FArith (ATInt (ITFixed IT32))) (ConstantOperand $ cgConst' c)
739cgConst c@(TT.B64 _) = box (FArith (ATInt (ITFixed IT64))) (ConstantOperand $ cgConst' c)
740cgConst c@(TT.B8V v) = box (FArith (ATInt (ITVec IT8 (V.length v)))) (ConstantOperand $ cgConst' c)
741cgConst c@(TT.B16V v) = box (FArith (ATInt (ITVec IT16 (V.length v)))) (ConstantOperand $ cgConst' c)
742cgConst c@(TT.B32V v) = box (FArith (ATInt (ITVec IT32 (V.length v)))) (ConstantOperand $ cgConst' c)
743cgConst c@(TT.B64V v) = box (FArith (ATInt (ITVec IT64 (V.length v)))) (ConstantOperand $ cgConst' c)
744cgConst c@(TT.Fl _) = box (FArith ATFloat) (ConstantOperand $ cgConst' c)
745cgConst c@(TT.Ch _) = box (FArith (ATInt ITChar)) (ConstantOperand $ cgConst' c)
746cgConst c@(TT.Str s) = do
747 str <- addGlobal' (ArrayType (1 + fromIntegral (length s)) (IntegerType 8)) (cgConst' c)
748 box FString (ConstantOperand $ C.GetElementPtr True str [C.Int 32 0, C.Int 32 0])
749cgConst c@(TT.BI i) = do
750 str <- addGlobal' (ArrayType (1 + fromInteger (numDigits 10 i)) (IntegerType 8)) (cgConst' c)
752 inst $ simpleCall "__gmpz_init_set_str" [mpz
753 , ConstantOperand $ C.GetElementPtr True str [ C.Int 32 0, C.Int 32 0]
754 , ConstantOperand $ C.Int 32 10
756 box (FArith (ATInt ITBig)) mpz
757cgConst x = return $ ConstantOperand nullValue
759numDigits :: Integer -> Integer -> Integer
760numDigits b n = 1 + fst (ilog b n) where
763 | otherwise = let (e, r) = ilog (b*b) n
764 in if r < b then (2*e, r) else (2*e+1, r `div` b)
766addGlobal :: Global -> Codegen ()
767addGlobal def = tell ([], [], [GlobalDefinition def])
769addGlobal' :: Type -> C.Constant -> Codegen C.Constant
770addGlobal' ty val = do
771 name <- getGlobalUnName
772 addGlobal $ globalVariableDefaults
774 , G.linkage = L.Internal
775 , G.hasUnnamedAddr = True
776 , G.isConstant = True
778 , G.initializer = Just val
780 return . C.GlobalReference $ name
783ensureCDecl :: String -> FType -> [FType] -> Codegen Operand
784ensureCDecl name rty argtys = do
785 syms <- gets foreignSyms
786 unless (S.member name syms) $
787 do addGlobal (ffunDecl name rty argtys)
788 modify $ \s -> s { foreignSyms = S.insert name (foreignSyms s) }
789 return $ ConstantOperand (C.GlobalReference (Name name))
791ffunDecl :: String -> FType -> [FType] -> Global
792ffunDecl name rty argtys =
794 { G.returnType = ftyToTy rty
796 , G.parameters = (flip map argtys $ \fty ->
797 Parameter (ftyToTy fty) (UnName 0) []
801ftyToTy :: FType -> Type
802ftyToTy (FArith (ATInt ITNative)) = IntegerType 32
803ftyToTy (FArith (ATInt ITBig)) = PointerType mpzTy (AddrSpace 0)
804ftyToTy (FArith (ATInt (ITFixed ty))) = IntegerType (fromIntegral $ nativeTyWidth ty)
805ftyToTy (FArith (ATInt (ITVec e c)))
806 = VectorType (fromIntegral c) (IntegerType (fromIntegral $ nativeTyWidth e))
807ftyToTy (FArith (ATInt ITChar)) = IntegerType 32
808ftyToTy FString = PointerType (IntegerType 8) (AddrSpace 0)
809ftyToTy FUnit = VoidType
810ftyToTy FPtr = PointerType (IntegerType 8) (AddrSpace 0)
811ftyToTy (FArith ATFloat) = FloatingPointType 64 IEEE
812ftyToTy FAny = valueType
814-- Only use when known not to be ITBig
815itWidth :: IntTy -> Word32
818itWidth (ITFixed x) = fromIntegral $ nativeTyWidth x
820cgOp :: PrimFn -> [Operand] -> Codegen Operand
821cgOp (LTrunc ITBig ity) [x] = do
822 nx <- unbox (FArith (ATInt ITBig)) x
823 val <- inst $ simpleCall "mpz_get_ull" [nx]
825 (ITFixed IT64) -> return val
826 _ -> inst $ Trunc val (ftyToTy (FArith (ATInt ity))) []
827 box (FArith (ATInt ity)) v
828cgOp (LZExt from ITBig) [x] = do
829 nx <- unbox (FArith (ATInt from)) x
831 (ITFixed IT64) -> return nx
832 _ -> inst $ ZExt nx (IntegerType 64) []
834 inst' $ simpleCall "mpz_init_set_ull" [mpz, nx']
835 box (FArith (ATInt ITBig)) mpz
836cgOp (LSExt from ITBig) [x] = do
837 nx <- unbox (FArith (ATInt from)) x
839 (ITFixed IT64) -> return nx
840 _ -> inst $ SExt nx (IntegerType 64) []
842 inst' $ simpleCall "mpz_init_set_sll" [mpz, nx']
843 box (FArith (ATInt ITBig)) mpz
845cgOp (LLt (ATInt ITBig)) [x,y] = mpzCmp IPred.SLT x y
846cgOp (LLe (ATInt ITBig)) [x,y] = mpzCmp IPred.SLE x y
847cgOp (LEq (ATInt ITBig)) [x,y] = mpzCmp IPred.EQ x y
848cgOp (LGe (ATInt ITBig)) [x,y] = mpzCmp IPred.SGE x y
849cgOp (LGt (ATInt ITBig)) [x,y] = mpzCmp IPred.SGT x y
850cgOp (LPlus (ATInt ITBig)) [x,y] = mpzBin "add" x y
851cgOp (LMinus (ATInt ITBig)) [x,y] = mpzBin "sub" x y
852cgOp (LTimes (ATInt ITBig)) [x,y] = mpzBin "mul" x y
853cgOp (LSDiv (ATInt ITBig)) [x,y] = mpzBin "fdiv_q" x y
854cgOp (LSRem (ATInt ITBig)) [x,y] = mpzBin "fdiv_r" x y
855cgOp (LAnd ITBig) [x,y] = mpzBin "and" x y
856cgOp (LOr ITBig) [x,y] = mpzBin "ior" x y
857cgOp (LXOr ITBig) [x,y] = mpzBin "xor" x y
858cgOp (LCompl ITBig) [x] = mpzUn "com" x
860cgOp (LTrunc ITNative (ITFixed to)) [x]
861 | 32 >= nativeTyWidth to = iCoerce Trunc IT32 to x
862cgOp (LZExt ITNative (ITFixed to)) [x]
863 | 32 <= nativeTyWidth to = iCoerce ZExt IT32 to x
864cgOp (LSExt ITNative (ITFixed to)) [x]
865 | 32 <= nativeTyWidth to = iCoerce SExt IT32 to x
867cgOp (LTrunc (ITFixed from) ITNative) [x]
868 | nativeTyWidth from >= 32 = iCoerce Trunc from IT32 x
869cgOp (LZExt (ITFixed from) ITNative) [x]
870 | nativeTyWidth from <= 32 = iCoerce ZExt from IT32 x
871cgOp (LSExt (ITFixed from) ITNative) [x]
872 | nativeTyWidth from <= 32 = iCoerce SExt from IT32 x
874cgOp (LTrunc (ITFixed from) (ITFixed to)) [x]
875 | nativeTyWidth from > nativeTyWidth to = iCoerce Trunc from to x
876cgOp (LZExt (ITFixed from) (ITFixed to)) [x]
877 | nativeTyWidth from < nativeTyWidth to = iCoerce ZExt from to x
878cgOp (LSExt (ITFixed from) (ITFixed to)) [x]
879 | nativeTyWidth from < nativeTyWidth to = iCoerce SExt from to x
881cgOp (LLt (ATInt ity)) [x,y] = iCmp ity IPred.SLT x y
882cgOp (LLe (ATInt ity)) [x,y] = iCmp ity IPred.SLE x y
883cgOp (LEq (ATInt ity)) [x,y] = iCmp ity IPred.EQ x y
884cgOp (LGe (ATInt ity)) [x,y] = iCmp ity IPred.SGE x y
885cgOp (LGt (ATInt ity)) [x,y] = iCmp ity IPred.SGT x y
886cgOp (LPlus (ATInt ity)) [x,y] = ibin ity x y (Add False False)
887cgOp (LMinus (ATInt ity)) [x,y] = ibin ity x y (Sub False False)
888cgOp (LTimes (ATInt ity)) [x,y] = ibin ity x y (Mul False False)
889cgOp (LSDiv (ATInt ity)) [x,y] = ibin ity x y (SDiv False)
890cgOp (LSRem (ATInt ity)) [x,y] = ibin ity x y SRem
891cgOp (LUDiv ity) [x,y] = ibin ity x y (UDiv False)
892cgOp (LURem ity) [x,y] = ibin ity x y URem
893cgOp (LAnd ity) [x,y] = ibin ity x y And
894cgOp (LOr ity) [x,y] = ibin ity x y Or
895cgOp (LXOr ity) [x,y] = ibin ity x y Xor
896cgOp (LCompl ity) [x] = iun ity x (Xor (ConstantOperand (C.Int (itWidth ity) (-1))))
897cgOp (LSHL ity) [x,y] = ibin ity x y (Shl False False)
898cgOp (LLSHR ity) [x,y] = ibin ity x y (LShr False)
899cgOp (LASHR ity) [x,y] = ibin ity x y (AShr False)
901cgOp LNoOp xs = return $ last xs
903cgOp (LMkVec ety c) xs | c == length xs = do
904 nxs <- mapM (unbox (FArith (ATInt (ITFixed ety)))) xs
905 vec <- foldM (\v (e, i) -> inst $ InsertElement v e (ConstantOperand (C.Int 32 i)) [])
906 (ConstantOperand $ C.Vector (replicate c (C.Undef (IntegerType . fromIntegral $ nativeTyWidth ety))))
908 box (FArith (ATInt (ITVec ety c))) vec
910cgOp (LIdxVec ety c) [v,i] = do
911 nv <- unbox (FArith (ATInt (ITVec ety c))) v
912 ni <- unbox (FArith (ATInt (ITFixed IT32))) i
913 elt <- inst $ ExtractElement nv ni []
914 box (FArith (ATInt (ITFixed ety))) elt
916cgOp (LUpdateVec ety c) [v,i,e] = do
917 let fty = FArith (ATInt (ITVec ety c))
919 ni <- unbox (FArith (ATInt (ITFixed IT32))) i
920 ne <- unbox (FArith (ATInt (ITFixed ety))) e
921 nv' <- inst $ InsertElement nv ne ni []
924cgOp (LBitCast from to) [x] = do
925 nx <- unbox (FArith from) x
926 nx' <- inst $ BitCast nx (ftyToTy (FArith to)) []
929cgOp LStrEq [x,y] = do
930 x' <- unbox FString x
931 y' <- unbox FString y
932 cmp <- inst $ simpleCall "strcmp" [x', y']
933 flag <- inst $ ICmp IPred.EQ cmp (ConstantOperand (C.Int 32 0)) []
934 val <- inst $ ZExt flag (IntegerType 32) []
935 box (FArith (ATInt (ITFixed IT32))) val
937cgOp LStrLt [x,y] = do
938 nx <- unbox FString x
939 ny <- unbox FString y
940 cmp <- inst $ simpleCall "strcmp" [nx, ny]
941 flag <- inst $ ICmp IPred.ULT cmp (ConstantOperand (C.Int 32 0)) []
942 val <- inst $ ZExt flag (IntegerType 32) []
943 box (FArith (ATInt (ITFixed IT32))) val
945cgOp (LIntStr ITBig) [x] = do
946 x' <- unbox (FArith (ATInt ITBig)) x
947 ustr <- inst $ simpleCall "__gmpz_get_str"
948 [ ConstantOperand (C.Null (PointerType (IntegerType 8) (AddrSpace 0)))
949 , ConstantOperand (C.Int 32 10)
953cgOp (LIntStr ity) [x] = do
954 x' <- unbox (FArith (ATInt ity)) x
955 x'' <- if itWidth ity < 64
956 then inst $ SExt x' (IntegerType 64) []
958 box FString =<< inst (idrCall "__idris_intStr" [x''])
959cgOp (LStrInt ITBig) [s] = do
960 ns <- unbox FString s
962 inst $ simpleCall "__gmpz_init_set_str" [mpz, ns, ConstantOperand $ C.Int 32 10]
963 box (FArith (ATInt ITBig)) mpz
964cgOp (LStrInt ity) [s] = do
965 ns <- unbox FString s
966 nx <- inst $ simpleCall "strtoll"
968 , ConstantOperand $ C.Null (PointerType (PointerType (IntegerType 8) (AddrSpace 0)) (AddrSpace 0))
969 , ConstantOperand $ C.Int 32 10
972 (ITFixed IT64) -> return nx
973 _ -> inst $ Trunc nx (IntegerType (itWidth ity)) []
974 box (FArith (ATInt ity)) nx'
976cgOp LStrConcat [x,y] = cgStrCat x y
978cgOp LStrCons [c,s] = do
979 nc <- unbox (FArith (ATInt ITChar)) c
980 ns <- unbox FString s
981 nc' <- inst $ Trunc nc (IntegerType 8) []
982 r <- inst $ simpleCall "__idris_strCons" [nc', ns]
985cgOp LStrHead [c] = do
987 c <- inst $ loadInv s
988 c' <- inst $ ZExt c (IntegerType 32) []
989 box (FArith (ATInt ITChar)) c'
991cgOp LStrIndex [s, i] = do
992 ns <- unbox FString s
993 ni <- unbox (FArith (ATInt (ITFixed IT32))) i
994 p <- inst $ GetElementPtr True ns [ni] []
995 c <- inst $ loadInv p
996 c' <- inst $ ZExt c (IntegerType 32) []
997 box (FArith (ATInt ITChar)) c'
999cgOp LStrTail [c] = do
1000 s <- unbox FString c
1001 c <- inst $ GetElementPtr True s [ConstantOperand $ C.Int 32 1] []
1004cgOp LStrLen [s] = do
1005 ns <- unbox FString s
1006 len <- inst $ simpleCall "strlen" [ns]
1010 x | x > 32 -> inst $ Trunc len (IntegerType 32) []
1011 | x < 32 -> inst $ ZExt len (IntegerType 32) []
1012 box (FArith (ATInt (ITFixed IT32))) len'
1014cgOp LReadStr [p] = do
1016 s <- inst $ simpleCall "__idris_readStr" [np]
1021 ptr <- inst $ loadInv stdin
1025 ptr <- inst $ loadInv stdout
1029 ptr <- inst $ loadInv stdErr
1032cgOp prim args = ierror $ "Unimplemented primitive: [" ++ show prim ++ "]("
1033 ++ intersperse ',' (take (length args) ['a'..]) ++ ")"
1035iCoerce :: (Operand -> Type -> InstructionMetadata -> Instruction) -> NativeTy -> NativeTy -> Operand -> Codegen Operand
1036iCoerce operator from to x = do
1037 x' <- unbox (FArith (ATInt (ITFixed from))) x
1038 x'' <- inst $ operator x' (ftyToTy (FArith (ATInt (ITFixed from)))) []
1039 box (FArith (ATInt (ITFixed to))) x''
1041cgStrCat :: Operand -> Operand -> Codegen Operand
1043 x' <- unbox FString x
1044 y' <- unbox FString y
1045 xlen <- inst $ simpleCall "strlen" [x']
1046 ylen <- inst $ simpleCall "strlen" [y']
1047 zlen <- inst $ Add False True xlen ylen []
1049 total <- inst $ Add False True zlen (ConstantOperand (C.Int ws 1)) []
1050 mem <- allocAtomic total
1051 inst $ simpleCall "memcpy" [mem, x', xlen]
1052 i <- inst $ PtrToInt mem (IntegerType ws) []
1053 offi <- inst $ Add False True i xlen []
1054 offp <- inst $ IntToPtr offi (PointerType (IntegerType 8) (AddrSpace 0)) []
1055 inst $ simpleCall "memcpy" [offp, y', ylen]
1056 j <- inst $ PtrToInt offp (IntegerType ws) []
1057 offj <- inst $ Add False True j ylen []
1058 end <- inst $ IntToPtr offj (PointerType (IntegerType 8) (AddrSpace 0)) []
1059 inst' $ Store False end (ConstantOperand (C.Int 8 0)) Nothing 0 []
1062ibin :: IntTy -> Operand -> Operand
1063 -> (Operand -> Operand -> InstructionMetadata -> Instruction) -> Codegen Operand
1064ibin ity x y instCon = do
1065 nx <- unbox (FArith (ATInt ity)) x
1066 ny <- unbox (FArith (ATInt ity)) y
1067 nr <- inst $ instCon nx ny []
1068 box (FArith (ATInt ity)) nr
1070iun :: IntTy -> Operand -> (Operand -> InstructionMetadata -> Instruction) -> Codegen Operand
1071iun ity x instCon = do
1072 nx <- unbox (FArith (ATInt ity)) x
1073 nr <- inst $ instCon nx []
1074 box (FArith (ATInt ity)) nr
1076iCmp :: IntTy -> IPred.IntegerPredicate -> Operand -> Operand -> Codegen Operand
1077iCmp ity pred x y = do
1078 nx <- unbox (FArith (ATInt ity)) x
1079 ny <- unbox (FArith (ATInt ity)) y
1080 nr <- inst $ ICmp pred nx ny []
1081 nr' <- inst $ SExt nr (ftyToTy $ cmpResultTy ity) []
1082 box (cmpResultTy ity) nr'
1084cmpResultTy :: IntTy -> FType
1085cmpResultTy v@(ITVec _ _) = FArith (ATInt v)
1086cmpResultTy _ = FArith (ATInt (ITFixed IT32))
1088mpzBin :: String -> Operand -> Operand -> Codegen Operand
1090 nx <- unbox (FArith (ATInt ITBig)) x
1091 ny <- unbox (FArith (ATInt ITBig)) y
1093 inst' $ simpleCall "__gmpz_init" [nz]
1094 inst' $ simpleCall ("__gmpz_" ++ name) [nz, nx, ny]
1095 box (FArith (ATInt ITBig)) nz
1097mpzUn :: String -> Operand -> Codegen Operand
1099 nx <- unbox (FArith (ATInt ITBig)) x
1101 inst' $ simpleCall "__gmpz_init" [nz]
1102 inst' $ simpleCall ("__gmpz_" ++ name) [nz, nx]
1103 box (FArith (ATInt ITBig)) nz
1105mpzCmp :: IPred.IntegerPredicate -> Operand -> Operand -> Codegen Operand
1107 nx <- unbox (FArith (ATInt ITBig)) x
1108 ny <- unbox (FArith (ATInt ITBig)) y
1109 cmp <- inst $ simpleCall "__gmpz_cmp" [nx, ny]
1110 result <- inst $ ICmp pred cmp (ConstantOperand (C.Int 32 0)) []
1111 i <- inst $ ZExt result (IntegerType 32) []
1112 box (FArith (ATInt (ITFixed IT32))) i
1114simpleCall :: String -> [Operand] -> Instruction
1115simpleCall name args =
1116 Call { isTailCall = False
1117 , callingConvention = CC.C
1118 , returnAttributes = []
1119 , function = Right . ConstantOperand . C.GlobalReference . Name $ name
1120 , arguments = map (\x -> (x, [])) args
1121 , functionAttributes = []
1125idrCall :: String -> [Operand] -> Instruction
1127 Call { isTailCall = False
1128 , callingConvention = CC.Fast
1129 , returnAttributes = []
1130 , function = Right . ConstantOperand . C.GlobalReference . Name $ name
1131 , arguments = map (\x -> (x, [])) args
1132 , functionAttributes = []
1136assert :: Operand -> String -> Codegen ()
1137assert condition message = do
1138 passed <- getName "assertPassed"
1139 failed <- getName "assertFailed"
1140 terminate $ CondBr condition passed failed []
1142 cgExpr (SError message)
1143 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