diff --git a/src/AST.hs b/src/AST.hs index c889a885..54a27dbf 100644 --- a/src/AST.hs +++ b/src/AST.hs @@ -72,7 +72,7 @@ module AST ( expOutputs, pexpListOutputs, expInputs, pexpListInputs, setExpTypeFlow, setPExpTypeFlow, Prim(..), primArgs, replacePrimArgs, argIsVar, argIsConst, argIntegerValue, - varsInPrims, varsInPrim, varsInPrimArgs, varsInPrimArg, + varsInPrims, varsInPrims', varsInPrim, varsInPrim', varsInPrimArgs, varsInPrimArg, ProcSpec(..), PrimVarName(..), PrimArg(..), PrimFlow(..), ArgFlowType(..), CallSiteID, SuperprocSpec(..), initSuperprocSpec, -- addSuperprocSpec, maybeGetClosureOf, isClosureProc, isClosureVariant, @@ -116,7 +116,7 @@ module AST ( maybeShow, showMessages, stopOnError, logMsg, whenLogging2, whenLogging, -- *Helper functions - defaultBlock, moduleIsPackage, + moduleIsPackage, -- *LPVM Encoding types EncodedLPVM(..), makeEncodedLPVM ) where @@ -911,7 +911,7 @@ lookupType :: String -> OptPos -> TypeSpec -> Compiler TypeSpec lookupType context pos ty = do (msgs, ty') <- lookupType' context pos ty mapM_ queueMessage msgs - return ty' + return ty' -- |Find the definition of the specified type visible from the current module. @@ -923,7 +923,7 @@ lookupType' _ _ ty@TypeVariable{} = return ([], ty) lookupType' _ _ ty@Representation{} = return ([], ty) lookupType' context pos ty@HigherOrderType{higherTypeParams=typeFlows} = do (msgs, types) <- unzip <$> mapM (lookupType' context pos . typeFlowType) typeFlows - return (concat msgs, + return (concat msgs, ty{higherTypeParams=zipWith TypeFlow types (typeFlowMode <$> typeFlows)}) lookupType' context pos ty@(TypeSpec [] typename args) | typename == currentModuleAlias = do @@ -2358,33 +2358,10 @@ data PrimFork = } deriving (Eq, Show, Generic) - -data LLBlock = LLBlock { - llInstrs::[LLInstr], - llTerm::LLTerm - } deriving (Eq, Show) - - -data LLInstr = LLNop - -- LLInstr { - -- llTarget::Maybe PrimVarName, - -- llOpr::[String], - -- llOperands::[(PrimVar,PrimType)] - deriving (Eq, Show) - - -data LLTerm = TermNop - deriving (Eq, Show) - -- |The variable name for the temporary variable whose number is given. mkTempName :: Int -> String mkTempName ctr = specialName2 "tmp" $ show ctr --- |Make a default LLBlock -defaultBlock :: LLBlock -defaultBlock = LLBlock { llInstrs = [], llTerm = TermNop } - - -- |Fold over a list of statements in a pre-order left-to-right traversal. -- Takes two folding functions, one for statements and one for expressions. foldStmts :: (a -> Stmt -> OptPos -> a) -> (a -> Exp -> OptPos -> a) -> a @@ -3468,22 +3445,29 @@ setPExpTypeFlow typeflow pexpr = setExpTypeFlow typeflow <$> pexpr -- or definitions. ---------------------------------------------------------------- -varsInPrims :: PrimFlow -> [Prim] -> Set PrimVarName -varsInPrims dir = - List.foldr (Set.union . (varsInPrim dir)) Set.empty +varsInPrims :: (PrimFlow -> Bool) -> [Prim] -> Set PrimVarName +varsInPrims tst = + List.foldr (Set.union . varsInPrim' (\flow final -> tst flow)) Set.empty + +varsInPrim :: (PrimFlow -> Bool) -> Prim -> Set PrimVarName +varsInPrim tst = varsInPrim' (\flow final -> tst flow) + +varsInPrims' :: (PrimFlow -> Bool -> Bool) -> [Prim] -> Set PrimVarName +varsInPrims' tst = + List.foldr (Set.union . varsInPrim' tst) Set.empty -varsInPrim :: PrimFlow -> Prim -> Set PrimVarName -varsInPrim dir prim = let (args, globals) = primArgs prim in varsInPrimArgs dir args +varsInPrim' :: (PrimFlow -> Bool -> Bool) -> Prim -> Set PrimVarName +varsInPrim' tst prim = let (args, globals) = primArgs prim in varsInPrimArgs tst args -varsInPrimArgs :: PrimFlow -> [PrimArg] -> Set PrimVarName -varsInPrimArgs dir = - List.foldr (Set.union . varsInPrimArg dir) Set.empty +varsInPrimArgs :: (PrimFlow -> Bool -> Bool) -> [PrimArg] -> Set PrimVarName +varsInPrimArgs tst = + List.foldr (Set.union . varsInPrimArg tst) Set.empty -varsInPrimArg :: PrimFlow -> PrimArg -> Set PrimVarName -varsInPrimArg dir ArgVar{argVarName=var,argVarFlow=dir'} - = if dir == dir' then Set.singleton var else Set.empty -varsInPrimArg dir (ArgClosure _ as _) - = Set.unions $ Set.fromList (varsInPrimArg dir <$> as) +varsInPrimArg :: (PrimFlow -> Bool -> Bool) -> PrimArg -> Set PrimVarName +varsInPrimArg tst ArgVar{argVarName=var,argVarFlow=dir, argVarFinal=final} + = if tst dir final then Set.singleton var else Set.empty +varsInPrimArg tst (ArgClosure _ as _) + = Set.unions $ Set.fromList (varsInPrimArg tst <$> as) varsInPrimArg _ ArgInt{} = Set.empty varsInPrimArg _ ArgFloat{} = Set.empty varsInPrimArg _ ArgString{} = Set.empty diff --git a/src/AliasAnalysis.hs b/src/AliasAnalysis.hs index bdc4b70a..127d6308 100644 --- a/src/AliasAnalysis.hs +++ b/src/AliasAnalysis.hs @@ -278,11 +278,11 @@ updateAliasedByPrim aliasMap prim = logAlias $ "args: " ++ show args logAlias $ "paramArgMap: " ++ show paramArgMap let calleeArgsAliases = - mapDS (\x -> Map.lookup x paramArgMap) calleeParamAliases + mapDS (`Map.lookup` paramArgMap) calleeParamAliases -- filter out aliases of constant args -- (caused by constant constructor) |> filterDS isJust - |> mapDS (\x -> LiveVar (fromJust x)) + |> mapDS (LiveVar . fromJust) combined <- aliasedArgsInPrimCall calleeArgsAliases aliasMap args logAlias $ "calleeParamAliases: " ++ show calleeParamAliases logAlias $ "calleeArgsAliases: " ++ show calleeArgsAliases @@ -538,8 +538,8 @@ isArgVarUsedOnceInArgs _ _ _ = True -- we don't care about constant value addInterestingUnaliasedParams :: PrimProto -> Set InterestingCallProperty -> [PrimVarName] -> Set InterestingCallProperty addInterestingUnaliasedParams proto properties params = - List.map (InterestingUnaliased . (parameterVarNameToID proto)) params - |> (List.foldr Set.insert) properties + List.map (InterestingUnaliased . parameterVarNameToID proto) params + |> List.foldr Set.insert properties -- adding new specz version dependency diff --git a/src/Blocks.hs b/src/Blocks.hs index 640793c6..166ff9e8 100644 --- a/src/Blocks.hs +++ b/src/Blocks.hs @@ -58,8 +58,9 @@ import Options (LogSelection (Blocks)) import Unsafe.Coerce import System.FilePath import qualified UnivSet -import Control.Exception (assert) -import Data.Set (Set) +import Control.Exception (assert) +import Data.Set (Set) +import LastCallAnalysis (inseparablePrims) -- | Holds information on the LLVM representation of the LPVM procedure. data ProcDefBlock = @@ -308,7 +309,7 @@ makeGlobalDefinition pname proto bls = do makeFnArg :: PrimParam -> Compiler (Type, LLVMAST.Name) makeFnArg param = do ty <- primParamLLVMType param - let nm = LLVMAST.Name $ toSBString $ show $ primParamName param + let nm = LLVMAST.Name $ toSBString $ show $ primParamLLVMName param return (ty, nm) type LLVMCallSignature = ([Type], Type) @@ -370,15 +371,15 @@ assignParam p@PrimParam{primParamType=ty, primParamFlow = paramFlow } = do ++ " (" ++ show trep ++ ")" unless (repIsPhantom trep || paramInfoUnneeded (primParamInfo p)) $ do - let nm = show (primParamName p) + let nm = primParamLLVMName p llty <- lift2 $ primParamLLVMType p - modifySymtab nm (localVar llty nm) + modifySymtab (show nm) (localVar llty $ show nm) -- | Convert a PrimParam to an Operand value and reference this value by the -- param's name on the symbol table. Don't assign if phantom preassignOutput :: PrimParam -> Codegen () preassignOutput p = do - let nm = show (primParamName p) + let nm = show (primParamLLVMName p) llty <- lift2 $ primParamLLVMType p modifySymtab nm (cons $ C.Undef llty) @@ -393,7 +394,7 @@ buildOutputOp = do proto <- gets cgProto outParams <- lift2 $ protoRealParamsWhere paramGoesOut proto logCodegen $ "OutParams: " ++ show outParams - outputs <- mapM (liftM3 castVar primParamName primParamType primParamFlow) outParams + outputs <- mapM (liftM3 castVar primParamLLVMName primParamType primParamFlow) outParams logCodegen $ "Built outputs from symbol table: " ++ show outputs case outputs of -- No valid output @@ -507,7 +508,9 @@ cgen (prim@(PrimCall callSiteID pspec args _):nextPrims) isLeaf = do -- If this call was marked with `tail`, then we generate the remaining prims -- *before* the call instruction. - nextPrims' <- cgenTakeReferences nextPrims + let (takeReferences, nextPrims') = inseparablePrims prim nextPrims + cgenTakeReferences True takeReferences + logCodegen "--> Finished cgenTakeReferences" let isTailPosition = List.null nextPrims' && isLeaf -- if the call is to an external module, declare it @@ -519,9 +522,12 @@ cgen (prim@(PrimCall callSiteID pspec args _):nextPrims) isLeaf = do (inops, allocaTracking) <- cgenArgsFull inArgs outTy <- lift2 $ primReturnType outArgs + let outArgNames = Set.fromList $ pullName <$> outArgs + outByRefs <- Set.fromList <$> outByRefParamNames + let noOutByRefsToWrite = Set.null (Set.intersection outArgNames outByRefs) callerSignature <- lift2 $ getLLVMSignature callerProto calleeSignature <- lift2 $ getLLVMSignature calleeProto - let tailCall = getTailCallHint isTailPosition allocaTracking outTy callerSignature calleeSignature + let tailCall = getTailCallHint isTailPosition allocaTracking outTy noOutByRefsToWrite callerSignature calleeSignature logCodegen $ "Tail call kind = " ++ show tailCall ++ " (isTailPosition=" ++ show isTailPosition ++ " allocaTracking=" ++ show allocaTracking ++ " outTy=" ++ show outTy ++ " callerSignature=" ++ show callerSignature ++ " calleeSignature=" ++ show calleeSignature ++ ")" logCodegen $ "Translated inputs = " ++ show inops @@ -613,27 +619,31 @@ cgenPrim prim@PrimCall {} = shouldnt "calls should be handled by `cgen`" -- `tail` is just a hint that LLVM "can" tail-call optimize but doesn't have to. -- However there are certain restrictions on when these hints. LLVM may optimize -- our code incorrectly (or crash) if we get this wrong. -getTailCallHint :: Bool -> AllocaTracking -> LLVMAST.Type -> LLVMCallSignature -> LLVMCallSignature -> Maybe LLVMAST.TailCallKind +getTailCallHint :: Bool -> AllocaTracking -> LLVMAST.Type -> Bool -> LLVMCallSignature -> LLVMCallSignature -> Maybe LLVMAST.TailCallKind -- Oh no! There is an `outByReference` argument which points to an `alloca`. -- The LLVM language reference dictates that we are not allowed to add -- `tail` or `musttail` in this case -getTailCallHint _ DoesAlloca _ _ _ = Nothing +getTailCallHint _ DoesAlloca _ _ _ _ = Nothing -- Although this call is in LPVM tail position, we'll need to add some -- `extractvalue` instrs after this call, so it won't be in LLVM -- tail position, thus we cannot use `musttail` -getTailCallHint True NoAlloca StructureType {} _ _ = Just LLVMAST.Tail +getTailCallHint True NoAlloca StructureType {} _ _ _ = Just LLVMAST.Tail +-- Although this call is in LPVM tail position, we'll need to add at least one +-- store() instr after this call, so it won't be in LLVM tail position, +-- thus we cannot use `musttail` +getTailCallHint True NoAlloca _ False _ _ = Just LLVMAST.Tail -- Although this call is in LPVM tail position, the signatures of the -- the caller and callee may not match , thus according to LLVM -- language reference we aren't allowed to use `musttail`. -- XXX: LLVM version >= 13.0.0 relaxes this restriction -getTailCallHint True NoAlloca _ callerSignature calleeSignature | callerSignature /= calleeSignature = Just LLVMAST.Tail +getTailCallHint True NoAlloca _ _ callerSignature calleeSignature | callerSignature /= calleeSignature = Just LLVMAST.Tail -- We know this LLVM call will be in LLVM tail position (since scalar/void -- return type), and also we don't refer to any allocas to in the caller. -getTailCallHint True NoAlloca _ _ _ = Just LLVMAST.MustTail +getTailCallHint True NoAlloca _ _ _ _ = Just LLVMAST.MustTail -- This function isn't in LPVM tail position, -- but we know it doesn't take any arguments which were created by allocas -- in the caller. -getTailCallHint False NoAlloca _ _ _ = Just LLVMAST.Tail +getTailCallHint False NoAlloca _ _ _ _ = Just LLVMAST.Tail -- | Translate a Binary primitive procedure into a binary llvm instruction, -- add the instruction to the current BasicBlock's instruction stack and emit @@ -702,18 +712,14 @@ cgenMaybeLoadReference callIsTailPosition arg@ArgVar { argVarName = name, argVar -- or the output was one of the outputs of the overall proc. -- In this case, we need to perform the load op <- maybeGetVar $ show (getRefName name) - op' <- maybeGetVar $ show name - var <- case (op, op') of - -- the corresponding shadow variable `[name]#ref` exists - (Just var, _) -> return var - -- the shadow `[name]#ref` variable wasn't created, so instead - -- we load `[name]` directly - (Nothing, Just var) -> return var + case op of + -- the `[name]#ref` shadow variable should contain the destination to load + (Just var) -> do + logCodegen $ "doing `load` after call: " ++ show var + outTy <- lift2 $ argLLVMType arg { argVarFlow = FlowOut } + loadOp <- doLoad outTy var + modifySymtab (show name) loadOp _ -> shouldnt $ show name ++ "not defined - when loading reference after call" - logCodegen $ "doing `load` after call: " ++ show var - outTy <- lift2 $ argLLVMType arg { argVarFlow = FlowOut } - loadOp <- doLoad outTy var - modifySymtab (show name) loadOp cgenMaybeLoadReference _ _ = return () filterPhantomArgs :: [PrimArg] -> Codegen [PrimArg] @@ -836,7 +842,7 @@ cgenLPVM "load" _ args = do ty' <- llvmType' ty FlowIn global <- getGlobalResource res ty' op' <- doLoad ty' global - assign (show nm) op' + assign nm op' ([],[]) -> return () _ -> @@ -849,23 +855,34 @@ cgenLPVM pname flags args = do -- | Codegen all `foreign lpvm mutate(..., takeReference xyz)` calls which occur -- immediately after a PrimCall. --- Returns the remaining prims which didn't match the above pattern. -cgenTakeReferences :: [Prim] -> Codegen [Prim] -cgenTakeReferences (prim@(PrimForeign "lpvm" "mutate" _ [inArg, outArg, offsetArg, ArgInt 1 _, sizeArg, startOffsetArg, +-- Returns the remaining prims which (didn't match the above pattern. +cgenTakeReferences :: Bool -> [Prim] -> Codegen [Prim] +cgenTakeReferences genAll (prim@(PrimForeign "lpvm" "mutate" _ [inArg, outArg@ArgVar { argVarFlow = outArgFlow }, offsetArg, ArgInt 1 _, sizeArg, startOffsetArg, refArg@ArgVar { argVarName = refArgName, argVarFlow = FlowTakeReference }]):nextPrims) = do - logCodegen $ "--> Compiling " ++ show prim - baseAddr <- cgenArg inArg - outTy <- lift2 $ argLLVMType refArg - finalAddr <- offsetAddr baseAddr iadd offsetArg - finalAddrPtr <- doCast finalAddr outTy - -- take a reference to the field that we're interested in - assign (show refArgName) finalAddrPtr - -- assign outArg to be the same address as inArg - -- This may implicitly write to a pointer (through a `store` - -- instruction) if outArg is an `outByReference` param + logCodegen $ "--> Compiling " ++ show prim + nextPrims <- if outArgFlow == FlowOutByReference + then do cgenTakeReferences False nextPrims + else return nextPrims + baseAddr <- cgenArg inArg + outTy <- lift2 $ argLLVMType refArg + finalAddr <- offsetAddr baseAddr iadd offsetArg + finalAddrPtr <- doCast finalAddr outTy + -- take a reference to the field that we're interested in + -- and store it in the shadow variable `[name]#ref` + assign (getRefName refArgName) finalAddrPtr + -- assign outArg to be the same address as inArg + -- This may implicitly write to a pointer (through a `store` + -- instruction) if outArg is an `outByReference` param + if outArgFlow == FlowOut then do assign (pullName outArg) baseAddr - cgenTakeReferences nextPrims -cgenTakeReferences prims = return prims + else do + outAddrOp <- cgenArg outArg + store outAddrOp baseAddr + if genAll + then do cgenTakeReferences genAll nextPrims + else return nextPrims +cgenTakeReferences _ (_:nextPrims) = shouldnt "not a mutate(..., takeReference) instruction" +cgenTakeReferences _ [] = return [] -- | Generate code to add an offset to an address offsetAddr :: Operand -> (Operand -> Operand -> Instruction) -> PrimArg @@ -969,8 +986,8 @@ addInstruction ins outArgs = do zipWithM_ assign (pullName <$> outArgs) fields -pullName :: PrimArg -> String -pullName ArgVar{argVarName=var} = show var +pullName :: PrimArg -> PrimVarName +pullName ArgVar{argVarName=var} = var pullName _ = shouldnt "Expected variable as output." -- | Generate an expanding instruction name using the passed flags. This is @@ -1021,13 +1038,17 @@ paramGoesIn = isLLVMInput . primParamFlow paramGoesOut :: PrimParam -> Bool paramGoesOut = not . paramGoesIn --- | 'cgenArg' makes an Operand of the input argument. --- * Variables return a casted version of their respective symbol table operand --- * Constants are generated with cgenArgConst, then wrapped in `cons` --- --- Also returns `AllocaTracking`, which specifies if any of these arguments will --- point to allocas from the current proc. --- The presence of such allocas breaks core assumptions of the LLVM `tail` +isReferenceFlow :: PrimFlow -> Bool +isReferenceFlow FlowTakeReference = True +isReferenceFlow FlowOutByReference = True +isReferenceFlow _ = False + +-- outByReference or takeReference parameters use a shadow variable `[name]#ref` +-- instead of the actual parameter name. +primParamLLVMName :: PrimParam -> PrimVarName +primParamLLVMName PrimParam {primParamName=name, primParamFlow=flow} | isReferenceFlow flow = getRefName name +primParamLLVMName PrimParam {primParamName=name} = name + -- attribute, so we need to carefully handle this case. cgenArgFull :: PrimArg -> Codegen (LLVMAST.Operand, AllocaTracking) cgenArgFull arg = do @@ -1063,7 +1084,8 @@ cgenArgsFull args = do cgenArg' :: PrimArg -> Codegen (LLVMAST.Operand, AllocaTracking) cgenArg' var@ArgVar{argVarName=name, argVarType=ty, argVarFlow=flow@FlowOutByReference} = do - op <- maybeGetVar (show name) + let refName = getRefName name + op <- maybeGetVar (show refName) proto <- gets cgProto outParams <- lift2 $ protoRealParamsWhere paramGoesOut proto let outParamNames = List.map primParamName outParams @@ -1075,12 +1097,11 @@ cgenArg' var@ArgVar{argVarName=name, argVarType=ty, argVarFlow=flow@FlowOutByRef allocaTy <- llvmType' ty FlowOut alloca <- doAlloca allocaTy logCodegen $ "Performing %" ++ show name ++ " = alloca " ++ show allocaTy - let refName = getRefName name - assign (show refName) alloca + assign refName alloca -- Supply the shadow reference variable as argument to this proc. op <- castVar refName ty flow return (op,DoesAlloca) - else noAlloca $ castVar name ty flow + else noAlloca $ castVar refName ty flow cgenArg' var@ArgVar{argVarName=nm, argVarType=ty, argVarFlow=flow} = noAlloca $ castVar nm ty flow cgenArg' (ArgUnneeded _ _) = shouldnt "Trying to generate LLVM for unneeded arg" cgenArg' arg@(ArgClosure ps args ty) = do @@ -1257,24 +1278,28 @@ integerOrd = toInteger . ord -- Symbol Table -- ---------------------------------------------------------------------------- +outByRefParamNames :: Codegen [PrimVarName] +outByRefParamNames = do + params <- gets (primProtoParams . cgProto) + return $ List.map primParamName $ List.filter (\param -> FlowOutByReference == primParamFlow param) params + -- | Store a local variable on the front of the symbol table. -- | -- | If the local variable happens to be an outByReference parameter of the -- | current function we're generating, then we instead "write" the variable -- | using a store instruction. -assign :: String -> Operand -> Codegen () +assign :: PrimVarName -> Operand -> Codegen () assign var op = do - params <- gets (primProtoParams . cgProto) - let outByRefParamNames = List.map (show . primParamName) $ List.filter (\param -> FlowOutByReference == primParamFlow param) params - if var `elem` outByRefParamNames then do - logCodegen $ "assign outByReference " ++ var ++ " = " ++ show op ++ ":" ++ show (typeOf op) - locOp <- getVar var + outByRefs <- outByRefParamNames + if var `elem` outByRefs then do + logCodegen $ "assign outByReference " ++ show var ++ " = " ++ show op ++ ":" ++ show (typeOf op) + locOp <- getVar (show (getRefName var)) locOp' <- doCast locOp (ptr_t (typeOf op)) store locOp' op -- also store this operand in the symtab, for the case where -- we access this outByReference param later on in the proc - modifySymtab var op - else modifySymtab var op + modifySymtab (show var) op + else modifySymtab (show var) op ---------------------------------------------------------------------------- -- Instruction maps -- diff --git a/src/Builder.hs b/src/Builder.hs index 99d67dd6..d7f44942 100644 --- a/src/Builder.hs +++ b/src/Builder.hs @@ -858,7 +858,7 @@ compileModSCC mspecs = do logMsg Transform $ "mspecs: " ++ show mspecs logMsg Transform $ replicate 70 '=' mapM_ (transformModuleProcs transformProc) mspecs - logDump Transform Transform "TRANSFORM" + logDump Transform LastCallAnalysis "TRANSFORM -> LAST CALL ANALYSIS" ---------------------------------- -- LAST CALL ANALYSIS @@ -868,7 +868,7 @@ compileModSCC mspecs = do logMsg LastCallAnalysis $ "mspecs: " ++ show mspecs logMsg LastCallAnalysis $ replicate 70 '=' mapM_ lastCallAnalyseMod mspecs - logDump LastCallAnalysis LastCallAnalysis "LAST CALL ANALYSIS" + logDump LastCallAnalysis LastCallAnalysis "AFTER LAST CALL ANALYSIS" -- mods <- mapM getLoadedModule mods -- callgraph <- mapM (\m -> getSpecModule m @@ -971,6 +971,7 @@ transformModuleProcs trans thisMod = do -- (names, procs) <- :: StateT CompilerState IO ([Ident], [[ProcDef]]) (names,procs) <- unzip <$> getModuleImplementationField (Map.toList . modProcs) + logBuild $ show (names, List.map procName $ concat procs) -- for each name we have a list of procdefs, so we must double map procs' <- mapM (zipWithM (flip trans) [0..]) procs updateImplementation diff --git a/src/LastCallAnalysis.hs b/src/LastCallAnalysis.hs index 29695d16..6b5b8bb0 100644 --- a/src/LastCallAnalysis.hs +++ b/src/LastCallAnalysis.hs @@ -6,24 +6,32 @@ -- License : Licensed under terms of the MIT license. See the file -- : LICENSE in the root directory of this project. {-# OPTIONS_GHC -Wno-unrecognised-pragmas #-} +{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE LambdaCase #-} -module LastCallAnalysis (lastCallAnalyseMod, lastCallAnalyseProc) where +module LastCallAnalysis (lastCallAnalyseMod, lastCallAnalyseProc, inseparablePrims) where import AST import qualified Data.List as List import qualified UnivSet import Options (LogSelection(LastCallAnalysis), optimisationEnabled, OptFlag(TailCallModCons)) import Util (sccElts, lift2) -import Data.Foldable (foldrM) +import Data.Foldable (foldrM, foldlM) import Data.List.Predicate (allUnique) import Callers (getSccProcs) import Data.Graph (SCC (AcyclicSCC, CyclicSCC)) -import Control.Monad.State (StateT (runStateT), MonadTrans (lift), execStateT, execState, runState, MonadState (get, put), gets, modify, unless, MonadPlus (mzero)) +import Control.Monad.State (StateT (runStateT), MonadTrans (lift), execStateT, execState, runState, MonadState (get, put), gets, modify, unless, MonadPlus (mzero), MonadIO (liftIO)) import Control.Monad ( liftM, (>=>), when ) import Data.Set (Set) import qualified Data.Set as Set import Control.Monad.Trans.Maybe (MaybeT (runMaybeT)) +import qualified Data.Map as Map +import Data.Map (Map) +import Data.Maybe (listToMaybe, fromJust) +import Data.List (intercalate) +import System.IO (hPutStrLn, stderr) +import qualified Data.Text as T +import Control.Monad.Except (ExceptT, MonadError (throwError), runExceptT) -- | Perform last call analysis on a single module. -- Internally, we perform analysis bottom-up on proc SCCs. @@ -37,9 +45,12 @@ lastCallAnalyseMod thisMod = do unlines (List.map ((++) " " . show . sccElts) orderedProcs) tcmcOpt <- gets (optimisationEnabled TailCallModCons . options) when tcmcOpt $ mapM_ (updateEachProcM lastCallAnalyseProc) orderedProcs - -- we need to fixup calls regardless whether tcmc is enabled or not, + -- We need to fixup calls regardless whether tcmc is enabled or not, -- as there could be modified calls to e.g.: standard library functions - mapM_ (updateEachProcM fixupCallsInProc) orderedProcs + -- Also, we try where possible to write outByReference outputs from other + -- calls directly into a destination structure, rather than first `load` + -- then `mutate`. + mapM_ (updateEachProcM fixupProc) orderedProcs reexitModule -- | Apply a mapping function to each proc in an SCC @@ -65,229 +76,599 @@ lastCallAnalyseProc def = do return def _ -> do (maybeBody', finalState) <- runStateT (runMaybeT (mapProcLeavesM transformLeaf body)) - LeafTransformState { procSpec = spec, originalProto = proto, transformedProto = Nothing } - case (maybeBody', transformedProto finalState) of - (Just body', Just proto') -> do - logLastCallAnalysis $ "new proto: " ++ show proto' + LeafTransformState { procSpec = spec, originalProto = proto, outByReferenceArguments = Set.empty } + case maybeBody' of + Just body' -> do + let outByRefArgs = outByReferenceArguments finalState + unless (null outByRefArgs) $ logLastCallAnalysis $ "out by reference arguments: " ++ show outByRefArgs + proto' <- modifyProto proto (outByReferenceArguments finalState) + unless (null outByRefArgs) $ logLastCallAnalysis $ "new proto: " ++ show proto' return def {procImpln = impln{procImplnProto = proto', procImplnBody = body'}} _ -> return def data LeafTransformState = LeafTransformState { procSpec :: ProcSpec, originalProto :: PrimProto, - transformedProto :: Maybe PrimProto + outByReferenceArguments :: Set ParameterID } type LeafTransformer = MaybeT (StateT LeafTransformState Compiler) -- | Run our analysis on a single leaf of the function body, -- collecting state inside the LeafTransformer monad. +-- +-- XXX: we should relax the assumption that last calls must be in the +-- leaves of a proc body, as there are real-world examples which defy this +-- assumption, e.g.: see test-cases/final-dump/tcmc_partition.wybe. transformLeaf :: [Placed Prim] -> LeafTransformer [Placed Prim] transformLeaf lastBlock = do spec <- gets procSpec case partitionLastCall lastBlock of - -- TODO: use multiple specialization to relax the restriction that - -- the last call is a directly-recursive call... + -- XXX: we currently only consider directly-recursive calls, + -- it would be nice to handle mutual recursion too. (Just (beforeCall, lastCall), afterLastCall@(_:_)) | primIsCallToProcSpec lastCall spec -> do logLeaf $ "identified a directly-recursive last-call: " ++ show lastCall - logLeaf $ "before: " ++ show beforeCall ++ "\nafter: " ++ show afterLastCall - -- First we identify all the prims which can be trivially moved before the last call - -- i.e.: the prim doesn't depend on any values produced by the last call (or subsequent prims) - let moveResult = tryMovePrimsBeforeLastCall lastCall afterLastCall MovePrimsResult { remaining = [], succeeded = [] } - let remainingAfterLastCall = reverse $ remaining moveResult - let movedBeforeLastCall = reverse $ succeeded moveResult - logLeaf $ "prims still remaining after last call: " ++ show remainingAfterLastCall + logLeaf $ "before: " ++ showPrims beforeCall ++ "\nafter: " ++ showPrims afterLastCall + -- First we identify whether we can move this last call below some of the prims + -- i.e.: the prims don't depend on any values produced by the last call + (lastCall', movedAboveCall, remainingBelowCall) <- lift2 $ tryMovePrimBelowPrims lastCall afterLastCall -- Next, we look at the remaining prims which couldn't be simply moved before the last call, - -- to see if they are just "filling in the fields" of struct(s) with outputs from the last call. - case foldrM (analyzePrimAfterLastCall lastCall) [] remainingAfterLastCall of - Right mutateChains -> do - proto <- gets originalProto - proto'' <- lift2 $ modifyProto proto mutateChains - -- attempts to modify this proc's proto. - -- will abort if we already tried to modify it - -- incompatibly in a different leaf. - trySetProto proto'' - - -- We apply the transformation to mark the final call as - -- a `tail` call - body' <- lift2 $ buildTailCallLeaf (beforeCall ++ movedBeforeLastCall) lastCall mutateChains - - logLeaf "remaining prims meet requirements tail call transformation" - logLeaf $ "identified mutate chains: " ++ show mutateChains - logLeaf $ "modified proto: " ++ show proto'' - logLeaf $ "modified body: " ++ show body' + -- to see if they are just "filling in the fields" of struct(s) with + -- outputs from the last call. + (movedAboveCall2, mutateGraph, remainingBelowCall') <- lift2 $ buildMutateGraph lastCall' isOutputFlow remainingBelowCall + case remainingBelowCall' of + [] -> do + let outByRefArgs = [name | (name, node) <- Map.assocs mutateGraph, callOutputIsOutByRef node] + let outByRefIndices = Set.fromList [fromJust $ List.findIndex (\case + ArgVar {argVarName=name'} -> name == name' + _ -> False) (fst . primArgs $ content lastCall) | name <- outByRefArgs] + + -- The output parameters which we want to convert to be + -- `FlowOutByReference` are the union of parameters we want to + -- convert for each leaf in the proc body. + modify (\state@LeafTransformState{outByReferenceArguments=params} -> + state { outByReferenceArguments = Set.union params outByRefIndices } + ) + + -- We annotate the final call + remaining mutates with appropriate + -- `FlowOutByReference` and `FlowTakeReference` flows. + let body' = beforeCall ++ movedAboveCall ++ movedAboveCall2 ++ + [contentApply (transformCall outByRefArgs) lastCall] ++ mutateGraphPrims mutateGraph + + logLeaf $ "modified body: " ++ showPrims body' return body' - Left error -> do - logLeaf $ "remaining prims didn't satisfy constraints: " ++ error + _ -> do + logLeaf $ "error: there were leftover prims which didn't fit into a mutate chain:\n" ++ showPrims remainingBelowCall' return lastBlock (Just (_, call), []) | primIsCallToProcSpec call spec -> do logLeaf "directly-recursive last call is already in tail position" - logLeaf "in the future, we will mark this call with the LPVM `tail` attribute" - logLeaf "to ensure it gets tail-call-optimised by LLVM" + return lastBlock + (Just (_, call), _) -> do + logLeaf $ "leaf didn't qualify for last-call transformation\n last call: " ++ show call ++ "\n pspec: " ++ show spec return lastBlock _ -> do - logLeaf "leaf didn't qualify for last-call transformation" + logLeaf "leaf didn't qualify for last-call transformation - didn't find a tail call" return lastBlock -- Returns true if this prim is calling proc spec primIsCallToProcSpec :: Placed Prim -> ProcSpec -> Bool primIsCallToProcSpec p spec = case content p of - (PrimCall _ spec' _ _) | spec == spec' -> True + (PrimCall _ spec' _ _) | procSpecMod spec == procSpecMod spec' && + procSpecName spec == procSpecName spec' && + procSpecID spec == procSpecID spec' -> True _ -> False --- | We don't want two different leaves to each try to update the proc's --- proto to something incompatible. Afterall, there is only a single proto for --- the proc, so all leaves must agree on a compatible definition. --- --- XXX: could probably take the union of all `outByReference` parameters, --- in the case of multiple branches wanting to modify the proc. -trySetProto :: PrimProto -> LeafTransformer () -trySetProto proto'' = do - proto <- gets originalProto - proto' <- gets transformedProto - case proto' of - Just proto' | proto' /= proto'' -> do - logLeaf $ "conflicting protos" ++ show proto' ++ "\n" ++ show proto'' - mzero - _ -> do - logLeaf $ "setting transformed proto: " ++ show proto'' - modify $ \s -> s { transformedProto = Just proto'' } - -- | Returns true if `prim` uses any of the outputs generated by `otherPrims` -- If this is the case, then it is not possible to move `prim` before the last call. -primUsesOutputsOfOtherPrims :: Placed Prim -> [Placed Prim] -> Bool -primUsesOutputsOfOtherPrims p ps = - let prim = content p - otherPrims = List.map content ps - (args, globals) = primArgs prim - vars = varsInPrimArgs FlowIn args - otherPrimOutputs = varsInPrims FlowOut otherPrims +primsUseOutputsOfPrims :: [Prim] -> [Prim] -> Bool +primsUseOutputsOfPrims prims otherPrims = + let + primInputs = varsInPrims isInputFlow prims + anyGlobals = all (\prim -> let globals = snd $ primArgs prim + in not (UnivSet.isEmpty (globalFlowsIn globals)) || not (UnivSet.isEmpty (globalFlowsOut globals)) + ) prims + otherPrimOutputs = varsInPrims isOutputFlow otherPrims in -- if the prim refers to any global variables, then skip reordering (conservative approximation for now) -- otherwise, check it doesn't refer to any outputs from `otherPrims` - not (UnivSet.isEmpty (globalFlowsIn globals) && UnivSet.isEmpty (globalFlowsOut globals)) || any (`elem` otherPrimOutputs) vars - --- | Finds outputs which are the final result of a mutate chain --- and modifies them to be `FlowOutByReference` instead of `FlowOut` -modifyProto :: PrimProto -> [MutateChain] -> Compiler PrimProto -modifyProto proto [] = return proto -modifyProto proto (mutateChain:xs) = do - proto' <- modifyProto proto xs - let output = outputName (last mutateChain) - let params = primProtoParams proto' - let params' = map (\param@PrimParam{primParamName = name, primParamFlow=flow } -> - if name /= output then + anyGlobals || Set.size (Set.intersection primInputs otherPrimOutputs) > 0 + +-- | Converts a subset of proc outputs to be +-- `FlowOutByReference` instead of `FlowOut` +modifyProto :: PrimProto -> Set ParameterID -> Compiler PrimProto +modifyProto proto outByRefOutputs = do + let params = primProtoParams proto + let makeParamsOutByReference = (\i param@PrimParam{primParamFlow=flow } -> + if i `notElem` outByRefOutputs then param else case flow of - FlowOutByReference -> shouldnt "multiple mutate chains writing to same output" - FlowTakeReference -> shouldnt "takeReference arg should only appear as the last argument to a mutate() instruction" - FlowIn -> shouldnt $ "attempting to convert FlowIn -> FlowOutByReference.\nproto: " ++ show proto ++ "\nmutate chain: " ++ show mutateChain - -- XXX: change name of param too? FlowOut -> param { primParamFlow = FlowOutByReference } - ) params - return proto' { primProtoParams = params' } - --- | Instead of a series of mutates *after* the last call, we instead --- perform some extra setup *before* the last call, allowing the last call --- of this block to be in tail-position. -buildTailCallLeaf :: [Placed Prim] -> Placed Prim -> [MutateChain] -> Compiler [Placed Prim] -buildTailCallLeaf beforeCall call mutateChains = do - let modifiedMutates = concatMap annotateFinalMutates mutateChains - let call' = contentApply (transformIntoTailCall mutateChains) call - return $ beforeCall ++ [call'] ++ modifiedMutates - --- | Annotates mutates which remain after the tail call with FlowTakeReference --- This indicates that the mutation will not actually occur after the call, --- instead, we take a reference to the memory location the mutate would have --- written to, and pass that reference into the tail call as an `outByReference` --- parameter. -annotateFinalMutates :: MutateChain -> [Placed Prim] -annotateFinalMutates = map $ - contentApply (\case { - PrimForeign "lpvm" "mutate" [] [input, output, offset, destructive, size, startOffset, val] -> - PrimForeign "lpvm" "mutate" [] [input, output, offset, destructive, size, startOffset, setArgFlow FlowTakeReference val ]; - _ -> shouldnt "must be mutate instr" - }) . prim - --- | Given a set of mutate chains (which are linear sequences of mutations --- occuring after the call), decorate this call with appropriate --- `outByReference` args. -transformIntoTailCall :: [MutateChain] -> Prim -> Prim -transformIntoTailCall mutateChains (PrimCall siteId spec args globalFlows) = - let mutates = concat mutateChains in + _ -> shouldnt "can only convert FlowOut -> FlowOutByReference" + ) + return proto { primProtoParams = zipWith makeParamsOutByReference [0..] params } + +-- | Turn the specified set of arguments into FlowOutByReference arguments. +transformCall :: [PrimVarName] -> Prim -> Prim +transformCall outByRefArgs call@(PrimCall siteId spec args globalFlows) = PrimCall siteId spec (map (\arg -> case arg of - var@ArgVar { argVarName = name } | name `elem` List.map valueName mutates + var@ArgVar { argVarName = name } | name `elem` outByRefArgs -> var { argVarFlow = FlowOutByReference } _ -> arg ) args) globalFlows -transformIntoTailCall mutateChains _ = shouldnt "not a call" +transformCall _ _ = shouldnt "not a call" + +newtype MutateInstr a = MutateInstr a + +instance HasPrim a => Show (MutateInstr a) where + show (MutateInstr p) = show (getPrim p) + +data Source a = + -- a mutate() call + ResultFromMutate (MutateInstr a) + -- a value which was available *before* the last call (e.g.: the head of the + -- list in append) + | ResultFromBeforeCall + -- a value which is one of the outputs of the last call. + | ResultFromCall { callResultFlow :: PrimFlow } + deriving (Show) + +type MutateGraph a = Map PrimVarName (Source a) + +data MutateGraphArc = Member | Input deriving (Show, Eq, Ord) + +class (Show a, Eq a) => HasPrim a where + getPrim :: a -> Prim + setPrim :: Prim -> a -> a + +instance HasPrim (Placed Prim) where + getPrim = content + setPrim p' = contentApply (const p') + +instance HasPrim Prim where + getPrim = id + setPrim p _ = p + +instance HasPrim (Bool, Placed Prim) where + getPrim (_, p) = content p + setPrim p' (x, p) = (x, contentApply (const p') p) + +sourceIsBeforeCall :: Source a -> Bool +sourceIsBeforeCall ResultFromBeforeCall = True +sourceIsBeforeCall _ = False + +showPrims :: HasPrim a => [a] -> String +showPrims ps = show (getPrim <$> ps) + +tryMovePrimBelowPrims :: HasPrim a => a -> [a] -> Compiler (a, [a], [a]) +tryMovePrimBelowPrims prim otherPrims = do + (prim, above, below) <- tryMovePrimBelowPrims' otherPrims (prim, [], []) + logLastCallAnalysis $ "moved below: " ++ showPrims above + logLastCallAnalysis $ "remaining below: " ++ showPrims below + return (prim, above, below) + +-- when optimizing writes directly into structures, +-- we need to treat "a call plus subseqent takeReference mutate()s" as an atomic +-- statement that is not allowed to be split up. +tryMovePrimBelowPrims' :: HasPrim a => [a] -> (a, [a], [a]) -> Compiler (a, [a], [a]) +tryMovePrimBelowPrims' [] state = return state +tryMovePrimBelowPrims' (nextPrim:remainingPrims) (prim, above, below) = + let (takeReferences, remainingPrims') = inseparablePrims nextPrim remainingPrims + nextPrims = nextPrim:takeReferences + in + if primsUseOutputsOfPrims (getPrim <$> nextPrims) (getPrim <$> (prim:below)) + then do + logLastCallAnalysis $ "cannot move " ++ showPrims (prim:below) ++ " below " ++ showPrims nextPrims + tryMovePrimBelowPrims' remainingPrims' (prim, above, below ++ nextPrims) + else do + logLastCallAnalysis $ "can move " ++ showPrims (prim:below) ++ " below " ++ showPrims nextPrims + let lastUseVarsToSwap = varsInPrims' (\flow isFinalUse -> isFinalUse) (getPrim <$> nextPrims) + unless (null lastUseVarsToSwap) $ logLastCallAnalysis $ "potentially swapping last use annotations `~` on " ++ show lastUseVarsToSwap + let (nextPrims', prim':below') = swapLastUsed lastUseVarsToSwap (nextPrims, prim:below) + unless (null lastUseVarsToSwap) $ logLastCallAnalysis $ "above=" ++ show nextPrims' ++ " below=" ++ show (prim':below') + tryMovePrimBelowPrims' remainingPrims' (prim', above ++ nextPrims', below') + +-- `var` is last used in list of prims `from`, we want to swap the last used +-- flag to the last prim arg in `to`, which references `var`. +swapLastUsed :: HasPrim a => Set PrimVarName -> ([a], [a]) -> ([a], [a]) +swapLastUsed vars (from, to) = + -- foldr works through `to` in reverse-order, so we mark the *final* + -- occurence of each var as "final". + let (to', varsNotFound) = List.foldr (setLastUse True) ([], vars) to + (from', varsNotFound1) = List.foldr (setLastUse False) ([], Set.difference vars varsNotFound) from + in + if null varsNotFound1 + then (from', to') + else shouldnt "expected to swap last use flag for all vars" + +setLastUse :: HasPrim a => Bool -> a -> ([a], Set PrimVarName) -> ([a], Set PrimVarName) +setLastUse newFinalValue p (prims, vars) = + let prim = getPrim p + (args, gFlows) = primArgs prim + (args', vars') = foldr (\arg (args, vars) -> case arg of + arg@ArgVar {argVarName = var, argVarFinal=_ } | var `elem` vars -> (arg { argVarFinal = newFinalValue }:args, Set.delete var vars) + _ -> (arg:args, vars) + ) ([], vars) args + in + (setPrim (replacePrimArgs prim args' gFlows) p : prims, vars') + +-- | Given a prim and some subsequent prims, collects any prims that should +-- never be separated from the first prim. +-- +-- For example, it's very important that we treat the following prims as an inseparable unit. +-- +-- call_foo(..., outByReference x, outByReference) +-- mutate(..., takeReference x) +-- mutate(..., takeReference y) +-- +-- Since codegen requires the mutate()'s to appear immediately after the call. +inseparablePrims :: HasPrim a => a -> [a] -> ([a], [a]) +inseparablePrims prim prims = case getPrim prim of + PrimCall callSiteId pSpec args gFlows -> + let (takeReferenceMutates, rest) = span (\p -> + case getPrim p of + PrimForeign "lpvm" "mutate" _ [_, _, _, ArgInt 1 _, _, _, ArgVar { argVarFlow = FlowTakeReference }] + -> True + _ -> False + ) prims + in + (takeReferenceMutates, rest) + _ -> ([], prims) -data MovePrimsResult = MovePrimsResult { - succeeded :: [Placed Prim], - remaining :: [Placed Prim] -} +-- | The only prims allowed after a "would-be tail call" are `foreign lpvm mutate` +-- instructions, with specific conditions (e.g.: all the mutates have the +-- "destructive" flag set, and the fields they are writing +-- into don't alias) +buildMutateGraph :: HasPrim a => a -> (PrimFlow -> Bool) -> [a] -> Compiler ([a], MutateGraph a, [a]) +buildMutateGraph call allowedOutputFlows prims = do + (graph, remainingBelowCall) <- buildMutateGraph' call allowedOutputFlows prims Map.empty + logLastCallAnalysis $ "built mutate graph: " ++ show graph + logLastCallAnalysis $ graphvizOutput graph + -- There may be some mutates in a chain which could be swapped such that + -- some of them can be done before the last call. + -- This allows us to handle the case of e.g.: snoc(tail: list(T), head: T) + -- where the the `head` is written to after the tail. + (pushedAboveCall, graph') <- slideMutatesOffGraph graph + graph'' <- tcmcOptimizeGraph graph' + logLastCallAnalysis $ "mutate graph v2: " ++ show graph'' + logLastCallAnalysis $ graphvizOutput graph'' + + let validGraph = all (\(var, node) -> + -- any variable in the graph may be used at most once + List.length (varReferences graph var) <= 1 && + case node of + -- last argument to mutate() must be marked as `final` + (ResultFromMutate instr) -> let (_, _, final) = mutateInstrMember' instr in final + _ -> True) (Map.assocs graph'') + + if validGraph then + return (pushedAboveCall, graph'', remainingBelowCall) + else + return ([], Map.empty, prims) + +buildMutateGraph' :: HasPrim a => a -> (PrimFlow -> Bool) -> [a] -> MutateGraph a -> Compiler (MutateGraph a, [a]) +buildMutateGraph' lastCall allowedOutputFlows (prim:prims) graph = do + result <- runExceptT (addMutateGraphVertex lastCall allowedOutputFlows prim graph) + case result of + Left msg -> do + logLastCallAnalysis $ "failed to add " ++ show prim ++ " to mutate graph: " ++ msg + return (graph, prim:prims) + Right graph' -> do + logLastCallAnalysis $ "added " ++ show prim ++ " to graph.\ngraph' = " ++ show graph' + buildMutateGraph' lastCall allowedOutputFlows prims graph' +buildMutateGraph' _ _ [] graph = return (graph, []) + +argVarHasName :: PrimArg -> PrimVarName -> Bool +argVarHasName ArgVar {argVarName=name} name' | name == name' = True +argVarHasName _ _ = False + +callOutputIsOutByRef :: Source a -> Bool +callOutputIsOutByRef ResultFromCall { callResultFlow = FlowOutByReference } = True +callOutputIsOutByRef _ = False + +addVarToMutateGraph :: HasPrim a => PrimVarName -> Prim -> (PrimFlow -> Bool) -> Bool -> MutateGraph a -> ExceptT String Compiler (Source a, MutateGraph a) +addVarToMutateGraph var lastCall allowedOutputFlows fromCallAllowed graph = do + case Map.lookup var graph of + (Just node) -> return (node, graph) + Nothing -> do + let callOutputs = varsInPrim isOutputFlow lastCall + let (args, _) = primArgs lastCall + let argFlow = [argFlowDirection arg | arg <- args, argVarHasName arg var] + case listToMaybe argFlow of + Nothing -> do + -- this var was created *before* the call + let node = ResultFromBeforeCall + let graph' = Map.insert var node graph + return (node, graph') + (Just _) | not fromCallAllowed -> throwError "can't use an output from the last call in this context" + (Just flow) | allowedOutputFlows flow -> do + let node = ResultFromCall { callResultFlow = flow } + let graph' = Map.insert var node graph + return (node, graph') + -- Corner-case: + -- When we are analyzing prims for the purposes of *deciding* + -- whether or not we can make this call a tail call, + -- we allow any FlowOut or FlowOutByReference output, since + -- we will transform those outputs to be FlowOutByReference later on. + -- However when we are analyzing prims for the purposes of writing + -- directly into structures from an existing tail call, + -- then we consider only outputs which are already + -- FlowOutByReference, since we won't change the call signature + -- anymore. + (Just flow) -> throwError $ show var ++ " was created in last call with disallowed flow. Cannot add to mutate graph" + +addMutateGraphVertex :: HasPrim a => a -> (PrimFlow -> Bool) -> a -> MutateGraph a -> ExceptT String Compiler (MutateGraph a) +addMutateGraphVertex lastCall allowedOutputFlows prim graph = do + case getPrim prim of + PrimForeign "lpvm" "mutate" _ [ + ArgVar { argVarName = input, argVarFlow = FlowIn }, + ArgVar { argVarName = output, argVarFlow = FlowOut }, + -- mutate() must be destructive + ArgInt offsetArg _, ArgInt 1 _, _, _, + ArgVar { argVarName = member, argVarFlow = FlowIn, argVarFinal = final }] -> do + -- make sure `input` exists in the graph + (inputNode, graph') <- addVarToMutateGraph input (getPrim lastCall) allowedOutputFlows False graph + -- make sure `member` exists in the graph + (memberNode, graph'') <- addVarToMutateGraph member (getPrim lastCall) allowedOutputFlows True graph' + let mutateInstr = ResultFromMutate $ MutateInstr prim + -- Check some conditions before adding this "mutate()" to the graph + when (offsetArg `elem` getOffsetList graph'' inputNode) $ + throwError "mutate()s in a single chain write to overlapping fields" + let graph''' = Map.insert output mutateInstr graph'' + return graph''' + _ -> + throwError "not a mutate instr satisfying constraints" + +-- Returns a list of offsets written to in a single mutate chain. +-- +-- XXX: Consider both offset and size to determine if writes alias. +getOffsetList :: HasPrim a => MutateGraph a -> Source a -> [Integer] +getOffsetList graph ResultFromBeforeCall = [] +getOffsetList graph ResultFromCall { } = shouldnt "mutate() shouldn't use result from call as it's input" +getOffsetList graph (ResultFromMutate instr) = let input = mutateInstrInput instr in + case Map.lookup input graph of + (Just inputNode) -> mutateInstrOffset instr : getOffsetList graph inputNode + Nothing -> shouldnt $ show input ++ " not found in mutate graph" + +-- Returns `True` if the given variable is currently +-- referred to in the mutate graph. We only allow each value to be +-- referenced *once* in the graph. +varReferences :: HasPrim a => MutateGraph a -> PrimVarName -> [MutateGraphArc] +varReferences graph var = foldr (\(name, node) arcs -> + case node of + ResultFromMutate instr | mutateInstrMember instr == var -> Input:arcs + ResultFromMutate instr | mutateInstrMember instr == var -> Member:arcs + _ -> arcs) + [] (Map.assocs graph) + +slideMutatesOffGraph :: HasPrim a => MutateGraph a -> Compiler ([a], MutateGraph a) +slideMutatesOffGraph graph = foldrM slideMutatesOffGraph' ([], graph) (Map.keys graph) + +slideMutatesOffGraph' :: HasPrim a => PrimVarName -> ([a], MutateGraph a) -> Compiler ([a], MutateGraph a) +slideMutatesOffGraph' name state@(pushedOut, graph) + = case Map.lookup name graph of + Just (ResultFromMutate mutateInstr@(MutateInstr prim)) -> + let member = mutateInstrMember mutateInstr + input = mutateInstrInput mutateInstr in + case (Map.lookup member graph, Map.lookup input graph) of + -- The two inputs to this mutate are available before this call. + -- Therefore we can move the mutate above the call. + (Just ResultFromBeforeCall, Just ResultFromBeforeCall) -> do + logLastCallAnalysis $ "popping " ++ show mutateInstr ++ " out of graph." + let deleteMemberIfUnused = if List.length (varReferences graph member) > 1 then id else Map.delete member + let graph' = deleteMemberIfUnused . Map.delete input . Map.insert name ResultFromBeforeCall $ graph + logLastCallAnalysis $ "new graph: " ++ show graph' + return (pushedOut ++ [prim], graph') + -- we can swap the two mutate()'s in the chain, in order to push the + -- first mutate closer to a "sink" vertex (at which point we can then + -- "pop" it out of the graph) + (Just ResultFromBeforeCall, Just (ResultFromMutate mutateInstr0)) -> do + logLastCallAnalysis $ "swapping " ++ show mutateInstr + let (mutateInstr', mutateInstr0') = mutateInstrSwap mutateInstr mutateInstr0 + let graph' = Map.insert name (ResultFromMutate mutateInstr0') . Map.insert input (ResultFromMutate mutateInstr') $ graph + logLastCallAnalysis $ "mutate graph after swap: " ++ show graph' + -- make sure we continue doing swaps + slideMutatesOffGraph' input (pushedOut, graph') + (Nothing, _) -> shouldnt $ show member ++ " not found in graph" + (_, Nothing) -> shouldnt $ show input ++ " not found in graph" + _ -> return state + Nothing -> do + logLastCallAnalysis $ show name ++ " not found in graph - must have been removed already. Skipping..." + return state + _ -> return state + +-- Annotate the graph with `outByReference` and `takeReference` as required +tcmcOptimizeGraph :: HasPrim a => MutateGraph a -> Compiler (MutateGraph a) +tcmcOptimizeGraph graph = foldrM tcmcOptimizeGraph' graph (Map.assocs graph) + +tcmcOptimizeGraph' :: HasPrim a => (PrimVarName, Source a) -> MutateGraph a -> Compiler (MutateGraph a) +tcmcOptimizeGraph' (name, ResultFromMutate mutateInstr@(MutateInstr prim)) graph = + let member = mutateInstrMember mutateInstr in + case Map.lookup member graph of + -- Turns the FlowOut argument of the call into FlowOutByReference, + -- and also switches mutate(..., member) to mutate(..., takeReference member) + (Just ResultFromCall { }) -> do + let graph' = Map.insert name (ResultFromMutate $ mutateInstrTakeReference mutateInstr) . Map.insert member ResultFromCall { callResultFlow = FlowOutByReference } $ graph + return graph' + -- Turns mutate(x, ?y, ...) into mutate(x, outByReference y , ...) + -- and mutate(..., y) to mutate(..., takeReference y) + (Just (ResultFromMutate memberMutate)) -> do + let graph' = Map.insert name (ResultFromMutate $ mutateInstrTakeReference mutateInstr) . Map.insert member (ResultFromMutate $ mutateInstrOutputByReference memberMutate) $ graph + return graph' + (Just ResultFromBeforeCall) -> shouldnt $ show member ++ " ResultFromBeforeCall should have already been removed" + Nothing -> shouldnt $ show member ++ " not found in graph" +tcmcOptimizeGraph' (name, _) graph = return graph + +-- | Returns the mutate() prims in a mutate graph, in order of appearance in the +-- LPVM IR. +-- Our mutate graph is essentially a directed-rooted-forest. So for each root +-- (proc output) there is exactly one path to each vertex. +mutateGraphPrims :: HasPrim a => MutateGraph a -> [a] +mutateGraphPrims graph = let sources = List.filter (null . varReferences graph) (Map.keys graph) in + concatMap (mutateGraphPrims' graph) sources + +-- | Returns the mutate() prims for a given node and it's descendents. +mutateGraphPrims' :: HasPrim a => MutateGraph a -> PrimVarName -> [a] +mutateGraphPrims' graph name = case Map.lookup name graph of + (Just ResultFromCall {}) -> [] + (Just ResultFromBeforeCall) -> [] + (Just (ResultFromMutate mutateInstr@(MutateInstr prim))) -> + mutateGraphPrims' graph (mutateInstrInput mutateInstr) ++ + mutateGraphPrims' graph (mutateInstrMember mutateInstr) ++ + [prim] + Nothing -> shouldnt "source not found in graph" + +mutateInstrMember :: HasPrim a => MutateInstr a -> PrimVarName +mutateInstrMember m = let (name, _, _) = mutateInstrMember' m in name + +mutateInstrMember' :: HasPrim a => MutateInstr a -> (PrimVarName, PrimFlow, Bool) +mutateInstrMember' (MutateInstr p) = case getPrim p of + PrimForeign _ _ _ [_, _, _, _, _, _, ArgVar { argVarName = member, argVarFlow = flow, argVarFinal = final }] -> (member, flow, final) + _ -> shouldnt "not a mutate instr" + +mutateInstrInput :: HasPrim a => MutateInstr a -> PrimVarName +mutateInstrInput (MutateInstr p) = case getPrim p of + PrimForeign _ _ _ (ArgVar { argVarName = input }:_) -> input + _ -> shouldnt "not a mutate instr" + +mutateInstrOutput' :: HasPrim a => MutateInstr a -> (PrimVarName, PrimFlow) +mutateInstrOutput' (MutateInstr p) = case getPrim p of + PrimForeign _ _ _ (_:ArgVar { argVarName = name, argVarFlow = flow }:_) -> (name, flow) + _ -> shouldnt "not a mutate instr" + +mutateInstrOutput :: HasPrim a => MutateInstr a -> PrimVarName +mutateInstrOutput = fst . mutateInstrOutput' + +mutateInstrOffset :: HasPrim a => MutateInstr a -> Integer +mutateInstrOffset (MutateInstr p) = case getPrim p of + PrimForeign _ _ _ (_:_:(ArgInt offset _):_) -> offset + _ -> shouldnt "not a mutate instr" + +mutateInstrTakeReference :: HasPrim a => MutateInstr a -> MutateInstr a +mutateInstrTakeReference (MutateInstr p) = case getPrim p of + PrimForeign mode name flags [input, output, offset, destructive, size, startOffset, member] -> + MutateInstr $ setPrim (PrimForeign mode name flags [input, output, offset, destructive, size, startOffset, setArgFlow FlowTakeReference member]) p + _ -> shouldnt "not a mutate instr" + +mutateInstrOutputByReference :: HasPrim a => MutateInstr a -> MutateInstr a +mutateInstrOutputByReference (MutateInstr p) = case getPrim p of + PrimForeign mode name flags (input:output:rest) -> + MutateInstr $ setPrim (PrimForeign mode name flags (input:setArgFlow FlowOutByReference output:rest)) p + _ -> shouldnt "not a mutate instr" + +-- XXX: may need to update last use flags here? +mutateInstrSwap :: HasPrim a => MutateInstr a -> MutateInstr a -> (MutateInstr a, MutateInstr a) +mutateInstrSwap (MutateInstr p1) (MutateInstr p2) = case (getPrim p1, getPrim p2) of + (PrimForeign "lpvm" "mutate" flags1 (input1:output1:rest1), + PrimForeign "lpvm" "mutate" flags2 (input2:output2:rest2)) + -> let p1' = PrimForeign "lpvm" "mutate" flags1 (input2:output2:rest1) + p2' = PrimForeign "lpvm" "mutate" flags2 (input1:output1:rest2) + in + (MutateInstr $ setPrim p1' p1, MutateInstr $ setPrim p2' p2) + _ -> shouldnt "tried to swap two prims which aren't mutate() instrs" -data MutateInstr = MutateInstr { - prim :: Placed Prim, - inputName :: PrimVarName, - outputName :: PrimVarName, - valueName :: PrimVarName, - offset :: Integer -} deriving(Show) +---------------------------------------------------------------------------- +-- Visualize mutate graphs -- +---------------------------------------------------------------------------- -type MutateChain = [MutateInstr] -type LastCall = Placed Prim +graphvizOutput :: HasPrim a => MutateGraph a -> String +graphvizOutput graph = "digraph D {\n" ++ + " rankdir=\"BT\"\n" ++ + " node [ordering=out]\n" ++ + intercalate "\n"[" " ++ varLabel name ++ " [style=\"filled\",fillcolor=\"" ++ graphvizVertexColor node ++ "\", label=\"" ++ varLabel name ++ "\\n" ++ graphvizVertexLabel name node ++ " \"]" | (name, node) <- Map.assocs graph] ++ + "\n" ++ intercalate "" [graphvizArcs name node | (name, node) <- Map.assocs graph] ++ + "\n}\n" + +varLabel :: PrimVarName -> String +varLabel var = filter (/= '#') $ T.unpack $ T.replace (T.pack "##0") (T.pack "") (T.pack $ show var) + +graphvizVertexColor :: HasPrim a => Source a -> String +graphvizVertexColor ResultFromMutate {} = "lightblue" +graphvizVertexColor ResultFromBeforeCall {} = "gray" +graphvizVertexColor ResultFromCall { callResultFlow = FlowOutByReference } = "lightgreen" +graphvizVertexColor ResultFromCall { callResultFlow = _ } = "salmon" + +graphvizVertexLabel :: HasPrim a => PrimVarName -> Source a -> String +graphvizVertexLabel name (ResultFromMutate instr) = "mutate(_, " ++ outByRef ++ ", offset=" ++ show (mutateInstrOffset instr) ++ ", ...," ++ takeReference ++ ")" + where takeReference = case mutateInstrMember' instr of + (name, FlowTakeReference, _) -> "takeReference " ++ varLabel name + _ -> "_" + outByRef = case mutateInstrOutput' instr of + (name, FlowOutByReference) -> "outByReference " ++ varLabel name + _ -> "_" +graphvizVertexLabel name ResultFromBeforeCall = "(before call)" +graphvizVertexLabel name ResultFromCall {callResultFlow=flow} = "(" ++ show flow ++ " from call)" + +graphvizArcs :: HasPrim a => PrimVarName -> Source a -> String +graphvizArcs name (ResultFromMutate instr) = + " " ++ varLabel name ++ " -> " ++ varLabel (mutateInstrMember instr) ++ " [label=\"member\"]\n" ++ + " " ++ varLabel name ++ " -> " ++ varLabel (mutateInstrInput instr) ++ " [label=\"input\"]\n" +graphvizArcs _ _ = "" -tryMovePrimsBeforeLastCall :: LastCall -> [Placed Prim] -> MovePrimsResult -> MovePrimsResult -tryMovePrimsBeforeLastCall lastCall [] state = state -tryMovePrimsBeforeLastCall lastCall (prim:nextPrims) state = if primUsesOutputsOfOtherPrims prim (lastCall : remaining state ++ nextPrims) - then tryMovePrimsBeforeLastCall lastCall nextPrims state { remaining = prim : remaining state } - else tryMovePrimsBeforeLastCall lastCall nextPrims state { succeeded = prim : succeeded state } +---------------------------------------------------------------------------- +-- Write outByReference outputs directly into structures -- +---------------------------------------------------------------------------- --- | The only prims allowed after a "would-be tail call" are `foreign lpvm mutate` --- instructions, which specific conditions (i.e.: the fields they are writing --- into don't alias) -analyzePrimAfterLastCall :: LastCall -> Placed Prim -> [MutateChain] -> Either String [MutateChain] -analyzePrimAfterLastCall lastCall prim state = case content prim of - PrimForeign "lpvm" "mutate" _ mutateInstr@[ - ArgVar { argVarName = inputName, argVarFlow = FlowIn }, - ArgVar { argVarName = outputName, argVarFlow = FlowOut }, - offsetArg, - ArgInt 1 _, - _, - _, - ArgVar { argVarName = valueName, argVarFlow = FlowIn, argVarFinal = final }] - | valueName `elem` varsInPrim FlowOut (content lastCall) -> if not final - then Left $ show valueName ++ " is used in more than one place" - else tryAddToMutateChain lastCall state MutateInstr { prim = prim, inputName = inputName, outputName = outputName, offset = trustArgInt offsetArg, valueName = valueName } state - prim -> Left "not a mutate instr or doesn't satisfy constraints" - --- | We build up these "mutate-chains" incrementally, aborting early if --- the conditions aren't satisfied. --- This analysis makes sure that mutations for (zero or more) linear sequences --- where each mutate in a sequence writes to a non-overlapping field. -tryAddToMutateChain :: LastCall -> [MutateChain] -> MutateInstr -> [MutateChain] -> Either String [MutateChain] -tryAddToMutateChain lastCall chains0 mut1 (chain@(mut:muts):chains) = - if outputName mut == inputName mut1 - -- We check that writes in a single mutate-chain don't alias fields. - -- Aliasing could be bad, since we cannot guarantee that the - -- callee will write it's outByReference arguments in any particular order. - -- - -- XXX: take into account size as well as offset when determining aliasing? - then if offset mut `notElem` List.map offset chain then - Right $ (mut1:chain):chains - else Left "offsets alias" - else do - chains' <- tryAddToMutateChain lastCall chains0 mut1 chains - return $ chain:chains' -tryAddToMutateChain lastCall chains0 mut' [] = let inputArg = inputName mut' in - if inputArg `elem` varsInPrim FlowOut (content lastCall) || any ((==inputArg) . outputName) (concat chains0) - then - Left "Input arg is either generated by the last call, or by reusing an intermediate output from an existing mutate-chain." - else - Right [[mut']] -tryAddToMutateChain _ _ _ ([]:_) = Left "a mutate chain shouldnt be empty" +data ProcBodyAnnot = ProcBodyAnnot { + bodyPrims' ::[(Bool, Placed Prim)], + bodyFork' ::PrimForkAnnot} + deriving (Eq, Show) + +data PrimForkAnnot = + NoForkAnnot | + PrimForkAnnot { + forkVar' :: PrimVarName, -- ^The variable that selects branch to take + forkVarType' :: TypeSpec, -- ^The Wybe type of the forkVar + forkVarLast' :: Bool, -- ^Is this the last occurrence of forkVar + forkBodies' :: [ProcBodyAnnot] -- ^one branch for each value of forkVar + } + deriving (Eq, Show) + +allUnvisited :: ProcBody -> ProcBodyAnnot +allUnvisited body@ProcBody { bodyPrims=prims, bodyFork=fork} = ProcBodyAnnot { bodyPrims' = map (\p -> (False, p)) prims, bodyFork' =allUnvisitedFork fork} +allUnvisitedFork :: PrimFork -> PrimForkAnnot +allUnvisitedFork NoFork = NoForkAnnot +allUnvisitedFork PrimFork{forkVar=var, forkVarType=varTy, forkVarLast=varLast, forkBodies=bodies} = PrimForkAnnot{forkVar'=var, forkVarType'=varTy, forkVarLast'=varLast, forkBodies'=allUnvisited <$> bodies} + +stripVisited :: ProcBodyAnnot -> ProcBody +stripVisited body@ProcBodyAnnot { bodyPrims'=prims, bodyFork'=fork} = ProcBody { bodyPrims = List.map snd prims, bodyFork = stripVisitedFork fork} +stripVisitedFork :: PrimForkAnnot -> PrimFork +stripVisitedFork NoForkAnnot = NoFork +stripVisitedFork PrimForkAnnot{forkVar'=var, forkVarType'=varTy, forkVarLast'=varLast, forkBodies'=bodies} = PrimFork {forkVar=var, forkVarType=varTy, forkVarLast=varLast, forkBodies=stripVisited <$> bodies} + +markVisited :: (Bool, Placed Prim) -> (Bool, Placed Prim) +markVisited (_, p) = (True, p) + +writeOutputsDirectlyIntoStructures :: ProcBodyAnnot -> Compiler ProcBodyAnnot +writeOutputsDirectlyIntoStructures procBody@ProcBodyAnnot{bodyPrims'=[], bodyFork'=NoForkAnnot} = return procBody +writeOutputsDirectlyIntoStructures procBody@ProcBodyAnnot{bodyPrims'=[], bodyFork'=fork@PrimForkAnnot{forkBodies'=bodies}} = do + bodies' <- mapM writeOutputsDirectlyIntoStructures bodies + return procBody{bodyFork'=fork{forkBodies'=bodies'}} +writeOutputsDirectlyIntoStructures procBody@ProcBodyAnnot{bodyPrims'=call@(False, _):prims} = do + let argFlows = argFlowDirection <$> (fst . primArgs . getPrim $ call) + newBody <- if FlowOutByReference `elem` argFlows then do + logLastCallAnalysis $ "call " ++ show call ++ " has outByReference outputs" + logLastCallAnalysis $ "trying to move call " ++ show call ++ " down right before outputs are needed" + (call', above, below) <- tryMovePrimBelowPrims call prims + -- For each FlowOutByReference output, we want to know if it + -- appears as the last argument to exactly 1 mutate(). + -- In this case, we believe it is safe to turn that mutate into a + -- `FlowTakeReference`-style mutate. + (above2, mutateGraph, below') <- buildMutateGraph call' (==FlowOutByReference) below + + if null mutateGraph + then do + logLastCallAnalysis "keeping existing body" + return procBody{bodyPrims'=markVisited call : prims} + else do + let body' = procBody{bodyPrims'=above ++ above2 ++ [markVisited call'] ++ mutateGraphPrims mutateGraph ++ below'} + logLastCallAnalysis $ "new body: " ++ show (stripVisited body') + return body' + else return procBody{bodyPrims'=markVisited call:prims} + writeOutputsDirectlyIntoStructures newBody +writeOutputsDirectlyIntoStructures procBody@ProcBodyAnnot{bodyPrims'=(_, prim):prims} = do + body' <- writeOutputsDirectlyIntoStructures procBody{bodyPrims'=prims} + return $ body'{bodyPrims'=(True, prim):bodyPrims' body'} ---------------------------------------------------------------------------- -- Coerce FlowOut into FlowOutByReference -- @@ -295,21 +676,24 @@ tryAddToMutateChain _ _ _ ([]:_) = Left "a mutate chain shouldnt be empty" -- | Check the proc protos of all callees, and coerce FlowOut into -- FlowOutByReference where needed. -fixupCallsInProc :: ProcDef -> Compiler ProcDef -fixupCallsInProc def@ProcDef { procImpln = impln@ProcDefPrim { procImplnBody = body}} = do +fixupProc :: ProcDef -> Compiler ProcDef +fixupProc def@ProcDef { procImpln = impln@ProcDefPrim { procImplnBody = body}} = do logLastCallAnalysis $ ">>> Fix up calls in proc: " ++ show (procName def) - body' <- mapProcPrimsM (updatePlacedM fixupCallsInPrim) body - return $ def { procImpln = impln { procImplnBody = body' } } -fixupCallsInProc _ = shouldnt "uncompiled" - -fixupCallsInPrim :: Prim -> Compiler Prim -fixupCallsInPrim p@(PrimCall siteId pspec args gFlows) = do - logLastCallAnalysis $ "checking call " ++ show p + body' <- mapProcPrimsM (updatePlacedM fixupPrim) body + logLastCallAnalysis $ ">>> Write outputs directly into structures: " ++ show (procName def) + body'' <- writeOutputsDirectlyIntoStructures (allUnvisited body') + let body''' = stripVisited body'' + return $ def { procImpln = impln { procImplnBody = body''' } } +fixupProc _ = shouldnt "uncompiled" + +fixupPrim :: Prim -> Compiler Prim +fixupPrim p@(PrimCall siteId pspec args gFlows) = do proto <- getProcPrimProto pspec let args' = coerceArgs args (primProtoParams proto) - when (args /= args') $ logLastCallAnalysis $ "coerced args: " ++ show args ++ " " ++ show args' - return $ PrimCall siteId pspec args' gFlows -fixupCallsInPrim p = return p + let call' = PrimCall siteId pspec args' gFlows + when (args /= args') $ logLastCallAnalysis $ "coerced call: " ++ show p ++ "\n to: " ++ show call' + return call' +fixupPrim p = return p -- | Coerce FlowOut arguments into FlowOutByReference where needed coerceArgs :: [PrimArg] -> [PrimParam] -> [PrimArg] @@ -329,6 +713,7 @@ partitionLastCall :: [Placed Prim] -> (Maybe ([Placed Prim], Placed Prim), [Plac partitionLastCall prims = let (lastCall, after) = _partitionLastCall $ reverse prims in (lastCall, reverse after) +-- XXX: rewrite to use `List.span` _partitionLastCall :: [Placed Prim] -> (Maybe ([Placed Prim], Placed Prim), [Placed Prim]) _partitionLastCall [] = (Nothing, []) _partitionLastCall (x:xs) = diff --git a/src/Transform.hs b/src/Transform.hs index f849965e..b4161f18 100644 --- a/src/Transform.hs +++ b/src/Transform.hs @@ -24,7 +24,7 @@ import Data.Map as Map import Data.Maybe as Maybe import Data.Set as Set import Flow ((|>)) -import Options (LogSelection (Transform), +import Options (LogSelection (Transform), OptFlag(MultiSpecz), optimisationEnabled) import Util @@ -42,8 +42,9 @@ transformProc def _ let body = procImplnBody impln body' <- transformProcBody def generalVersion return def {procImpln = impln{procImplnBody = body'}} - -transformProc def _ = return def +transformProc def _ = do + logTransform $ "skipping " ++ show (procName def) ++ " since it's inline" + return def -- init aliasMap based on the given "nonAliasedParams", @@ -117,7 +118,7 @@ transformPrims :: PrimProto -> ProcBody -> (AliasMapLocal, DeadCells) transformPrims caller body (aliasMap, deadCells) callSiteMap = do let prims = bodyPrims body -- Transform simple prims: - lift $ logTransform "\nTransform prims (transformPrims): " + lift $ logTransform $ "\nTransform prims (transformPrims): " ++ show caller ++ "\n" ++ show body foldM (transformPrim callSiteMap) (aliasMap, deadCells) prims @@ -150,7 +151,7 @@ transformPrim :: Map CallSiteID ProcSpec -> (AliasMapLocal, DeadCells) -> Placed Prim -> BodyBuilder (AliasMapLocal, DeadCells) transformPrim callSiteMap (aliasMap, deadCells) prim = do - -- XXX Redundent work here. We should change the current design. + -- XXX Redundant work here. We should change the current design. aliasMap' <- lift $ updateAliasedByPrim aliasMap prim lift $ logTransform $ "\n--- prim: " ++ show prim let primc = content prim @@ -163,6 +164,7 @@ transformPrim callSiteMap (aliasMap, deadCells) prim = do else spec return (PrimCall id spec' args gFlows, deadCells) PrimForeign "lpvm" "mutate" flags args -> do + lift $ logTransform $ "alias map: " ++ show aliasMap let args' = _updateMutateForAlias aliasMap args return (PrimForeign "lpvm" "mutate" flags args', deadCells) -- dead cell transform diff --git a/test-cases/complex/exp/testcase_multi_specz-int_list.exp b/test-cases/complex/exp/testcase_multi_specz-int_list.exp index c0a9b4bd..af03edfd 100644 --- a/test-cases/complex/exp/testcase_multi_specz-int_list.exp +++ b/test-cases/complex/exp/testcase_multi_specz-int_list.exp @@ -1825,7 +1825,7 @@ if.else1: } -define external fastcc void @"int_list.extend<0>"(i64 %"lst1##0", i64 %"lst2##0", i64* %"#result##0") { +define external fastcc void @"int_list.extend<0>"(i64 %"lst1##0", i64 %"lst2##0", i64* %"#result#ref##0") { entry: %0 = icmp ne i64 %"lst1##0", 0 br i1 %0, label %if.then, label %if.else @@ -1842,16 +1842,16 @@ if.then: store i64 %2, i64* %9 %10 = add i64 %8, 8 %11 = inttoptr i64 %10 to i64* - store i64 %8, i64* %"#result##0" + store i64 %8, i64* %"#result#ref##0" musttail call fastcc void @"int_list.extend<0>"(i64 %5, i64 %"lst2##0", i64* %11) ret void if.else: - store i64 %"lst2##0", i64* %"#result##0" + store i64 %"lst2##0", i64* %"#result#ref##0" ret void } -define external fastcc void @"int_list.extend<0>[410bae77d3]"(i64 %"lst1##0", i64 %"lst2##0", i64* %"#result##0") { +define external fastcc void @"int_list.extend<0>[410bae77d3]"(i64 %"lst1##0", i64 %"lst2##0", i64* %"#result#ref##0") { entry: %0 = icmp ne i64 %"lst1##0", 0 br i1 %0, label %if.then, label %if.else @@ -1861,11 +1861,11 @@ if.then: %3 = load i64, i64* %2 %4 = add i64 %"lst1##0", 8 %5 = inttoptr i64 %4 to i64* - store i64 %"lst1##0", i64* %"#result##0" + store i64 %"lst1##0", i64* %"#result#ref##0" musttail call fastcc void @"int_list.extend<0>[410bae77d3]"(i64 %3, i64 %"lst2##0", i64* %5) ret void if.else: - store i64 %"lst2##0", i64* %"#result##0" + store i64 %"lst2##0", i64* %"#result#ref##0" ret void } @@ -1937,7 +1937,7 @@ entry: } -define external fastcc void @"int_list.greater<0>"(i64 %"lst##0", i64 %"v##0", i64* %"#result##0") { +define external fastcc void @"int_list.greater<0>"(i64 %"lst##0", i64 %"v##0", i64* %"#result#ref##0") { entry: %0 = icmp ne i64 %"lst##0", 0 br i1 %0, label %if.then, label %if.else @@ -1950,7 +1950,7 @@ if.then: %6 = icmp sge i64 %2, %"v##0" br i1 %6, label %if.then1, label %if.else1 if.else: - store i64 0, i64* %"#result##0" + store i64 0, i64* %"#result#ref##0" ret void if.then1: %7 = trunc i64 16 to i32 @@ -1960,16 +1960,16 @@ if.then1: store i64 %2, i64* %10 %11 = add i64 %9, 8 %12 = inttoptr i64 %11 to i64* - store i64 %9, i64* %"#result##0" + store i64 %9, i64* %"#result#ref##0" musttail call fastcc void @"int_list.greater<0>"(i64 %5, i64 %"v##0", i64* %12) ret void if.else1: - musttail call fastcc void @"int_list.greater<0>"(i64 %5, i64 %"v##0", i64* %"#result##0") + musttail call fastcc void @"int_list.greater<0>"(i64 %5, i64 %"v##0", i64* %"#result#ref##0") ret void } -define external fastcc void @"int_list.greater<0>[410bae77d3]"(i64 %"lst##0", i64 %"v##0", i64* %"#result##0") { +define external fastcc void @"int_list.greater<0>[410bae77d3]"(i64 %"lst##0", i64 %"v##0", i64* %"#result#ref##0") { entry: %0 = icmp ne i64 %"lst##0", 0 br i1 %0, label %if.then, label %if.else @@ -1982,16 +1982,16 @@ if.then: %6 = icmp sge i64 %2, %"v##0" br i1 %6, label %if.then1, label %if.else1 if.else: - store i64 0, i64* %"#result##0" + store i64 0, i64* %"#result#ref##0" ret void if.then1: %7 = add i64 %"lst##0", 8 %8 = inttoptr i64 %7 to i64* - store i64 %"lst##0", i64* %"#result##0" + store i64 %"lst##0", i64* %"#result#ref##0" musttail call fastcc void @"int_list.greater<0>[410bae77d3]"(i64 %5, i64 %"v##0", i64* %8) ret void if.else1: - musttail call fastcc void @"int_list.greater<0>[410bae77d3]"(i64 %5, i64 %"v##0", i64* %"#result##0") + musttail call fastcc void @"int_list.greater<0>[410bae77d3]"(i64 %5, i64 %"v##0", i64* %"#result#ref##0") ret void } @@ -2026,7 +2026,7 @@ if.else1: } -define external fastcc void @"int_list.insert<0>"(i64 %"lst##0", i64 %"idx##0", i64 %"v##0", i64* %"#result##0") { +define external fastcc void @"int_list.insert<0>"(i64 %"lst##0", i64 %"idx##0", i64 %"v##0", i64* %"#result#ref##0") { entry: %0 = icmp eq i64 %"idx##0", 0 br i1 %0, label %if.then, label %if.else @@ -2039,7 +2039,7 @@ if.then: %5 = add i64 %3, 8 %6 = inttoptr i64 %5 to i64* store i64 %"lst##0", i64* %6 - store i64 %3, i64* %"#result##0" + store i64 %3, i64* %"#result#ref##0" ret void if.else: %7 = icmp ne i64 %"lst##0", 0 @@ -2058,17 +2058,17 @@ if.then1: store i64 %9, i64* %17 %18 = add i64 %16, 8 %19 = inttoptr i64 %18 to i64* - store i64 %16, i64* %"#result##0" + store i64 %16, i64* %"#result#ref##0" musttail call fastcc void @"int_list.insert<0>"(i64 %12, i64 %13, i64 %"v##0", i64* %19) ret void if.else1: %20 = sub i64 %"idx##0", 1 - musttail call fastcc void @"int_list.insert<0>"(i64 %"lst##0", i64 %20, i64 %"v##0", i64* %"#result##0") + musttail call fastcc void @"int_list.insert<0>"(i64 %"lst##0", i64 %20, i64 %"v##0", i64* %"#result#ref##0") ret void } -define external fastcc void @"int_list.insert<0>[410bae77d3]"(i64 %"lst##0", i64 %"idx##0", i64 %"v##0", i64* %"#result##0") { +define external fastcc void @"int_list.insert<0>[410bae77d3]"(i64 %"lst##0", i64 %"idx##0", i64 %"v##0", i64* %"#result#ref##0") { entry: %0 = icmp eq i64 %"idx##0", 0 br i1 %0, label %if.then, label %if.else @@ -2081,7 +2081,7 @@ if.then: %5 = add i64 %3, 8 %6 = inttoptr i64 %5 to i64* store i64 %"lst##0", i64* %6 - store i64 %3, i64* %"#result##0" + store i64 %3, i64* %"#result#ref##0" ret void if.else: %7 = icmp ne i64 %"lst##0", 0 @@ -2093,17 +2093,17 @@ if.then1: %11 = sub i64 %"idx##0", 1 %12 = add i64 %"lst##0", 8 %13 = inttoptr i64 %12 to i64* - store i64 %"lst##0", i64* %"#result##0" + store i64 %"lst##0", i64* %"#result#ref##0" musttail call fastcc void @"int_list.insert<0>[410bae77d3]"(i64 %10, i64 %11, i64 %"v##0", i64* %13) ret void if.else1: %14 = sub i64 %"idx##0", 1 - musttail call fastcc void @"int_list.insert<0>[410bae77d3]"(i64 %"lst##0", i64 %14, i64 %"v##0", i64* %"#result##0") + musttail call fastcc void @"int_list.insert<0>[410bae77d3]"(i64 %"lst##0", i64 %14, i64 %"v##0", i64* %"#result#ref##0") ret void } -define external fastcc void @"int_list.lesser<0>"(i64 %"lst##0", i64 %"v##0", i64* %"#result##0") { +define external fastcc void @"int_list.lesser<0>"(i64 %"lst##0", i64 %"v##0", i64* %"#result#ref##0") { entry: %0 = icmp ne i64 %"lst##0", 0 br i1 %0, label %if.then, label %if.else @@ -2116,7 +2116,7 @@ if.then: %6 = icmp slt i64 %2, %"v##0" br i1 %6, label %if.then1, label %if.else1 if.else: - store i64 0, i64* %"#result##0" + store i64 0, i64* %"#result#ref##0" ret void if.then1: %7 = trunc i64 16 to i32 @@ -2126,16 +2126,16 @@ if.then1: store i64 %2, i64* %10 %11 = add i64 %9, 8 %12 = inttoptr i64 %11 to i64* - store i64 %9, i64* %"#result##0" + store i64 %9, i64* %"#result#ref##0" musttail call fastcc void @"int_list.lesser<0>"(i64 %5, i64 %"v##0", i64* %12) ret void if.else1: - musttail call fastcc void @"int_list.lesser<0>"(i64 %5, i64 %"v##0", i64* %"#result##0") + musttail call fastcc void @"int_list.lesser<0>"(i64 %5, i64 %"v##0", i64* %"#result#ref##0") ret void } -define external fastcc void @"int_list.pop<0>"(i64 %"lst##0", i64 %"idx##0", i64* %"#result##0") { +define external fastcc void @"int_list.pop<0>"(i64 %"lst##0", i64 %"idx##0", i64* %"#result#ref##0") { entry: %0 = icmp ne i64 %"lst##0", 0 br i1 %0, label %if.then, label %if.else @@ -2148,10 +2148,10 @@ if.then: %6 = icmp eq i64 %"idx##0", 0 br i1 %6, label %if.then1, label %if.else1 if.else: - store i64 0, i64* %"#result##0" + store i64 0, i64* %"#result#ref##0" ret void if.then1: - store i64 %5, i64* %"#result##0" + store i64 %5, i64* %"#result#ref##0" ret void if.else1: %7 = sub i64 %"idx##0", 1 @@ -2162,13 +2162,13 @@ if.else1: store i64 %2, i64* %11 %12 = add i64 %10, 8 %13 = inttoptr i64 %12 to i64* - store i64 %10, i64* %"#result##0" + store i64 %10, i64* %"#result#ref##0" musttail call fastcc void @"int_list.pop<0>"(i64 %5, i64 %7, i64* %13) ret void } -define external fastcc void @"int_list.pop<0>[410bae77d3]"(i64 %"lst##0", i64 %"idx##0", i64* %"#result##0") { +define external fastcc void @"int_list.pop<0>[410bae77d3]"(i64 %"lst##0", i64 %"idx##0", i64* %"#result#ref##0") { entry: %0 = icmp ne i64 %"lst##0", 0 br i1 %0, label %if.then, label %if.else @@ -2179,16 +2179,16 @@ if.then: %4 = icmp eq i64 %"idx##0", 0 br i1 %4, label %if.then1, label %if.else1 if.else: - store i64 0, i64* %"#result##0" + store i64 0, i64* %"#result#ref##0" ret void if.then1: - store i64 %3, i64* %"#result##0" + store i64 %3, i64* %"#result#ref##0" ret void if.else1: %5 = sub i64 %"idx##0", 1 %6 = add i64 %"lst##0", 8 %7 = inttoptr i64 %6 to i64* - store i64 %"lst##0", i64* %"#result##0" + store i64 %"lst##0", i64* %"#result#ref##0" musttail call fastcc void @"int_list.pop<0>[410bae77d3]"(i64 %3, i64 %5, i64* %7) ret void } @@ -2228,7 +2228,7 @@ entry: } -define external fastcc void @"int_list.remove<0>"(i64 %"lst##0", i64 %"v##0", i64* %"#result##0") { +define external fastcc void @"int_list.remove<0>"(i64 %"lst##0", i64 %"v##0", i64* %"#result#ref##0") { entry: %0 = icmp ne i64 %"lst##0", 0 br i1 %0, label %if.then, label %if.else @@ -2241,10 +2241,10 @@ if.then: %6 = icmp eq i64 %2, %"v##0" br i1 %6, label %if.then1, label %if.else1 if.else: - store i64 0, i64* %"#result##0" + store i64 0, i64* %"#result#ref##0" ret void if.then1: - store i64 %5, i64* %"#result##0" + store i64 %5, i64* %"#result#ref##0" ret void if.else1: %7 = trunc i64 16 to i32 @@ -2254,13 +2254,13 @@ if.else1: store i64 %2, i64* %10 %11 = add i64 %9, 8 %12 = inttoptr i64 %11 to i64* - store i64 %9, i64* %"#result##0" + store i64 %9, i64* %"#result#ref##0" musttail call fastcc void @"int_list.remove<0>"(i64 %5, i64 %"v##0", i64* %12) ret void } -define external fastcc void @"int_list.remove<0>[410bae77d3]"(i64 %"lst##0", i64 %"v##0", i64* %"#result##0") { +define external fastcc void @"int_list.remove<0>[410bae77d3]"(i64 %"lst##0", i64 %"v##0", i64* %"#result#ref##0") { entry: %0 = icmp ne i64 %"lst##0", 0 br i1 %0, label %if.then, label %if.else @@ -2273,15 +2273,15 @@ if.then: %6 = icmp eq i64 %2, %"v##0" br i1 %6, label %if.then1, label %if.else1 if.else: - store i64 0, i64* %"#result##0" + store i64 0, i64* %"#result#ref##0" ret void if.then1: - store i64 %5, i64* %"#result##0" + store i64 %5, i64* %"#result#ref##0" ret void if.else1: %7 = add i64 %"lst##0", 8 %8 = inttoptr i64 %7 to i64* - store i64 %"lst##0", i64* %"#result##0" + store i64 %"lst##0", i64* %"#result#ref##0" musttail call fastcc void @"int_list.remove<0>[410bae77d3]"(i64 %5, i64 %"v##0", i64* %8) ret void } diff --git a/test-cases/final-dump/generic_list.exp b/test-cases/final-dump/generic_list.exp index 5fbaee06..39e928a5 100644 --- a/test-cases/final-dump/generic_list.exp +++ b/test-cases/final-dump/generic_list.exp @@ -175,7 +175,7 @@ declare external ccc i8* @wybe_malloc(i32) declare external ccc void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1) -define external fastcc void @"generic_list.append<0>"(i64 %"x##0", i64 %"y##0", i64* %"#result##0") { +define external fastcc void @"generic_list.append<0>"(i64 %"x##0", i64 %"y##0", i64* %"#result#ref##0") { entry: %0 = icmp ne i64 %"x##0", 0 br i1 %0, label %if.then, label %if.else @@ -192,11 +192,11 @@ if.then: store i64 %2, i64* %9 %10 = add i64 %8, 8 %11 = inttoptr i64 %10 to i64* - store i64 %8, i64* %"#result##0" + store i64 %8, i64* %"#result#ref##0" musttail call fastcc void @"generic_list.append<0>"(i64 %5, i64 %"y##0", i64* %11) ret void if.else: - store i64 %"y##0", i64* %"#result##0" + store i64 %"y##0", i64* %"#result#ref##0" ret void } diff --git a/test-cases/final-dump/generic_use.exp b/test-cases/final-dump/generic_use.exp index 1250cdc7..e6e51db0 100644 --- a/test-cases/final-dump/generic_use.exp +++ b/test-cases/final-dump/generic_use.exp @@ -175,7 +175,7 @@ declare external ccc i8* @wybe_malloc(i32) declare external ccc void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1) -define external fastcc void @"generic_list.append<0>"(i64 %"x##0", i64 %"y##0", i64* %"#result##0") { +define external fastcc void @"generic_list.append<0>"(i64 %"x##0", i64 %"y##0", i64* %"#result#ref##0") { entry: %0 = icmp ne i64 %"x##0", 0 br i1 %0, label %if.then, label %if.else @@ -192,11 +192,11 @@ if.then: store i64 %2, i64* %9 %10 = add i64 %8, 8 %11 = inttoptr i64 %10 to i64* - store i64 %8, i64* %"#result##0" + store i64 %8, i64* %"#result#ref##0" musttail call fastcc void @"generic_list.append<0>"(i64 %5, i64 %"y##0", i64* %11) ret void if.else: - store i64 %"y##0", i64* %"#result##0" + store i64 %"y##0", i64* %"#result#ref##0" ret void } @@ -646,7 +646,7 @@ entry: } -define external fastcc void @"generic_use.concat<0>"(i64 %"l1##0", i64 %"l2##0", i64* %"#result##0") { +define external fastcc void @"generic_use.concat<0>"(i64 %"l1##0", i64 %"l2##0", i64* %"#result#ref##0") { entry: %0 = icmp ne i64 %"l1##0", 0 br i1 %0, label %if.then, label %if.else @@ -663,16 +663,16 @@ if.then: store i64 %2, i64* %9 %10 = add i64 %8, 8 %11 = inttoptr i64 %10 to i64* - store i64 %8, i64* %"#result##0" + store i64 %8, i64* %"#result#ref##0" musttail call fastcc void @"generic_use.concat<0>"(i64 %5, i64 %"l2##0", i64* %11) ret void if.else: - store i64 %"l2##0", i64* %"#result##0" + store i64 %"l2##0", i64* %"#result#ref##0" ret void } -define external fastcc void @"generic_use.concat<0>[410bae77d3]"(i64 %"l1##0", i64 %"l2##0", i64* %"#result##0") { +define external fastcc void @"generic_use.concat<0>[410bae77d3]"(i64 %"l1##0", i64 %"l2##0", i64* %"#result#ref##0") { entry: %0 = icmp ne i64 %"l1##0", 0 br i1 %0, label %if.then, label %if.else @@ -682,11 +682,11 @@ if.then: %3 = load i64, i64* %2 %4 = add i64 %"l1##0", 8 %5 = inttoptr i64 %4 to i64* - store i64 %"l1##0", i64* %"#result##0" + store i64 %"l1##0", i64* %"#result#ref##0" musttail call fastcc void @"generic_use.concat<0>[410bae77d3]"(i64 %3, i64 %"l2##0", i64* %5) ret void if.else: - store i64 %"l2##0", i64* %"#result##0" + store i64 %"l2##0", i64* %"#result#ref##0" ret void } diff --git a/test-cases/final-dump/higher_order_append.exp b/test-cases/final-dump/higher_order_append.exp index bdbc5e6d..391c9cab 100644 --- a/test-cases/final-dump/higher_order_append.exp +++ b/test-cases/final-dump/higher_order_append.exp @@ -226,7 +226,7 @@ entry: } -define external fastcc void @"higher_order_append.append<0>"(i64 %"front##0", i64 %"back##0", i64* %"result##0") { +define external fastcc void @"higher_order_append.append<0>"(i64 %"front##0", i64 %"back##0", i64* %"result#ref##0") { entry: %0 = icmp ne i64 %"front##0", 0 br i1 %0, label %if.then, label %if.else @@ -243,11 +243,11 @@ if.then: store i64 %2, i64* %9 %10 = add i64 %8, 8 %11 = inttoptr i64 %10 to i64* - store i64 %8, i64* %"result##0" + store i64 %8, i64* %"result#ref##0" musttail call fastcc void @"higher_order_append.append<0>"(i64 %5, i64 %"back##0", i64* %11) ret void if.else: - store i64 %"back##0", i64* %"result##0" + store i64 %"back##0", i64* %"result#ref##0" ret void } diff --git a/test-cases/final-dump/higher_order_sort.exp b/test-cases/final-dump/higher_order_sort.exp index 934a0670..e9a3e3bc 100644 --- a/test-cases/final-dump/higher_order_sort.exp +++ b/test-cases/final-dump/higher_order_sort.exp @@ -99,7 +99,7 @@ if.else: } -define external fastcc void @"higher_order_sort.insert<0>"(i64 %"<=##0", i64 %"x##0", i64 %"xs##0", i64* %"xs##1") { +define external fastcc void @"higher_order_sort.insert<0>"(i64 %"<=##0", i64 %"x##0", i64 %"xs##0", i64* %"xs#ref##1") { entry: %0 = icmp ne i64 %"xs##0", 0 br i1 %0, label %if.then, label %if.else @@ -124,7 +124,7 @@ if.else: %27 = add i64 %25, 8 %28 = inttoptr i64 %27 to i64* store i64 0, i64* %28 - store i64 %25, i64* %"xs##1" + store i64 %25, i64* %"xs#ref##1" ret void if.then1: %11 = trunc i64 16 to i32 @@ -135,7 +135,7 @@ if.then1: %15 = add i64 %13, 8 %16 = inttoptr i64 %15 to i64* store i64 %"xs##0", i64* %16 - store i64 %13, i64* %"xs##1" + store i64 %13, i64* %"xs#ref##1" ret void if.else1: %17 = trunc i64 16 to i32 @@ -145,7 +145,7 @@ if.else1: store i64 %2, i64* %20 %21 = add i64 %19, 8 %22 = inttoptr i64 %21 to i64* - store i64 %19, i64* %"xs##1" + store i64 %19, i64* %"xs#ref##1" musttail call fastcc void @"higher_order_sort.insert<0>"(i64 %"<=##0", i64 %"x##0", i64 %5, i64* %22) ret void } diff --git a/test-cases/final-dump/list_this.exp b/test-cases/final-dump/list_this.exp index 9dd25445..25856242 100644 --- a/test-cases/final-dump/list_this.exp +++ b/test-cases/final-dump/list_this.exp @@ -175,7 +175,7 @@ declare external ccc i8* @wybe_malloc(i32) declare external ccc void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1) -define external fastcc void @"list_this.append<0>"(i64 %"x##0", i64 %"y##0", i64* %"#result##0") { +define external fastcc void @"list_this.append<0>"(i64 %"x##0", i64 %"y##0", i64* %"#result#ref##0") { entry: %0 = icmp ne i64 %"x##0", 0 br i1 %0, label %if.then, label %if.else @@ -192,11 +192,11 @@ if.then: store i64 %2, i64* %9 %10 = add i64 %8, 8 %11 = inttoptr i64 %10 to i64* - store i64 %8, i64* %"#result##0" + store i64 %8, i64* %"#result#ref##0" musttail call fastcc void @"list_this.append<0>"(i64 %5, i64 %"y##0", i64* %11) ret void if.else: - store i64 %"y##0", i64* %"#result##0" + store i64 %"y##0", i64* %"#result#ref##0" ret void } diff --git a/test-cases/final-dump/tcmc_fields_alias.exp b/test-cases/final-dump/tcmc_fields_alias.exp new file mode 100644 index 00000000..c7854907 --- /dev/null +++ b/test-cases/final-dump/tcmc_fields_alias.exp @@ -0,0 +1,378 @@ +====================================================================== +AFTER EVERYTHING: + Module tcmc_fields_alias + representation : (not a type) + public submods : + public resources: + public procs : tcmc_fields_alias.<0> + imports : use wybe + resources : + procs : + +module top-level code > public {impure} (0 calls) +0: tcmc_fields_alias.<0> +()<{<>}; {<>}>: + AliasPairs: [] + InterestingCallProperties: [] + MultiSpeczDepInfo: [(10,(tcmc_fields_alias.partition<0>,fromList [NonAliasedParamCond 1 []]))] + foreign lpvm alloc(16:wybe.int, ?tmp#14##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#14##0:wybe.list(T), ?tmp#15##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 7:T) @list:nn:nn + foreign lpvm mutate(~tmp#15##0:wybe.list(T), ?tmp#7##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#18##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#18##0:wybe.list(T), ?tmp#19##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 6:T) @list:nn:nn + foreign lpvm mutate(~tmp#19##0:wybe.list(T), ?tmp#6##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#7##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#22##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#22##0:wybe.list(T), ?tmp#23##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 5:T) @list:nn:nn + foreign lpvm mutate(~tmp#23##0:wybe.list(T), ?tmp#5##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#6##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#26##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#26##0:wybe.list(T), ?tmp#27##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 4:T) @list:nn:nn + foreign lpvm mutate(~tmp#27##0:wybe.list(T), ?tmp#4##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#5##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#30##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#30##0:wybe.list(T), ?tmp#31##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 3:T) @list:nn:nn + foreign lpvm mutate(~tmp#31##0:wybe.list(T), ?tmp#3##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#4##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#34##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#34##0:wybe.list(T), ?tmp#35##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 9:T) @list:nn:nn + foreign lpvm mutate(~tmp#35##0:wybe.list(T), ?tmp#2##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#3##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#38##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#38##0:wybe.list(T), ?tmp#39##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 2:T) @list:nn:nn + foreign lpvm mutate(~tmp#39##0:wybe.list(T), ?tmp#1##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#2##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#42##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#42##0:wybe.list(T), ?tmp#43##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 1:T) @list:nn:nn + foreign lpvm mutate(~tmp#43##0:wybe.list(T), ?tmp#0##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#1##0:wybe.list(T)) @list:nn:nn + wybe.list.print<0>(tcmc_fields_alias.gen#1<0><>:{resource}(T), tmp#0##0:wybe.list(T)) #15 @list:nn:nn + foreign lpvm load(<>:wybe.phantom, ?%tmp#46##0:wybe.phantom) @io:nn:nn + foreign c putchar('\n':wybe.char, ~tmp#46##0:wybe.phantom, ?tmp#47##0:wybe.phantom) @io:nn:nn + foreign lpvm store(~%tmp#47##0:wybe.phantom, <>:wybe.phantom) @io:nn:nn + tcmc_fields_alias.partition<0>[6dacb8fd25](tcmc_fields_alias.gen#2<1><>:(wybe.int, ?wybe.bool), ~tmp#0##0:wybe.list(wybe.int), ?yes##0:wybe.list(wybe.int), outByReference no##0:wybe.list(wybe.int)) #10 @tcmc_fields_alias:nn:nn + wybe.list.print<0>(tcmc_fields_alias.gen#1<0><>:{resource}(wybe.int), ~yes##0:wybe.list(wybe.int)) #11 @tcmc_fields_alias:nn:nn + wybe.string.print<0>(", ":wybe.string)<{<>}; {<>}> #12 @tcmc_fields_alias:nn:nn + wybe.list.print<0>(tcmc_fields_alias.gen#1<0><>:{resource}(wybe.int), ~no##0:wybe.list(wybe.int)) #13 @tcmc_fields_alias:nn:nn + foreign lpvm load(<>:wybe.phantom, ?%tmp#48##0:wybe.phantom) @io:nn:nn + foreign c putchar('\n':wybe.char, ~tmp#48##0:wybe.phantom, ?tmp#49##0:wybe.phantom) @io:nn:nn + foreign lpvm store(~%tmp#49##0:wybe.phantom, <>:wybe.phantom) @io:nn:nn + + +gen#1 > {inline} (3 calls) +0: tcmc_fields_alias.gen#1<0> +gen#1(x##0:wybe.int)<{<>}; {<>}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign lpvm load(<>:wybe.phantom, ?%tmp#1##0:wybe.phantom) @int:nn:nn + foreign c print_int(~x##0:wybe.int, ~tmp#1##0:wybe.phantom, ?tmp#2##0:wybe.phantom) @int:nn:nn + foreign lpvm store(~%tmp#2##0:wybe.phantom, <>:wybe.phantom) @int:nn:nn + + +gen#2 > {inline} (1 calls) +0: tcmc_fields_alias.gen#2<0> +gen#2(anon#1#1##0:wybe.int, ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_sge(~anon#1#1##0:wybe.int, 3:wybe.int, ?#success##0:wybe.bool) @int:nn:nn +gen#2 > {inline} (1 calls) +1: tcmc_fields_alias.gen#2<1> +gen#2(anon#1#1##0:wybe.int, ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_sge(~anon#1#1##0:wybe.int, 3:wybe.int, ?#success##0:wybe.bool) @int:nn:nn + + +partition > (3 calls) +0: tcmc_fields_alias.partition<0>[6dacb8fd25] +partition(p##0:(T, ?wybe.bool), l##0:wybe.list(T), ?yes##1:wybe.list(T), outByReference no##0:wybe.list(T))<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [InterestingUnaliased 1] + MultiSpeczDepInfo: [(2,(tcmc_fields_alias.partition<0>,fromList [NonAliasedParamCond 1 [1]])),(6,(tcmc_fields_alias.partition<0>,fromList [NonAliasedParamCond 1 [1]]))] + foreign llvm icmp_ne(l##0:wybe.int, 0:wybe.int, ?tmp#8##0:wybe.bool) + case ~tmp#8##0:wybe.bool of + 0: + foreign llvm move(0:wybe.list(T), ?no##0:wybe.list(T)) @tcmc_fields_alias:nn:nn + foreign llvm move(0:wybe.list(T), ?yes##1:wybe.list(T)) + + 1: + foreign lpvm access(l##0:wybe.list(T), 0:wybe.int, 16:wybe.int, 0:wybe.int, ?h##0:T) @list:nn:nn + foreign lpvm access(~l##0:wybe.list(T), 8:wybe.int, 16:wybe.int, 0:wybe.int, ?t##0:wybe.list(T)) @list:nn:nn + p##0:(T, ?wybe.bool)(h##0:T, ?tmp#5##0:wybe.bool) #1 @tcmc_fields_alias:nn:nn + case ~tmp#5##0:wybe.bool of + 0: + foreign lpvm alloc(16:wybe.int, ?tmp#11##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#11##0:wybe.list(T), ?tmp#12##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~h##0:T) @list:nn:nn + tcmc_fields_alias.partition<0>(~p##0:(T, ?wybe.bool), ~t##0:wybe.list(T), ?yes##1:wybe.list(T), outByReference no0##0:wybe.list(T)) #6 @tcmc_fields_alias:nn:nn + foreign lpvm mutate(~tmp#12##0:wybe.list(T), ?no##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference no0##0:wybe.list(T)) @list:nn:nn + + 1: + tcmc_fields_alias.partition<0>(~p##0:(T, ?wybe.bool), ~t##0:wybe.list(T), ?yes0##0:wybe.list(T), outByReference no0##0:wybe.list(T)) #2 @tcmc_fields_alias:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#11##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#11##0:wybe.list(T), ?tmp#12##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~h##0:T) @list:nn:nn + foreign lpvm mutate(~tmp#12##0:wybe.list(T), ?tmp#0##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~yes0##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#0##0:wybe.list(T), ?yes##1:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~no0##0:wybe.list(T)) @tcmc_fields_alias:nn:nn + foreign llvm move(0:wybe.list(T), ?no##0:wybe.list(T)) @tcmc_fields_alias:nn:nn + + + [6dacb8fd25] [NonAliasedParam 1] : + foreign llvm icmp_ne(l##0:wybe.int, 0:wybe.int, ?tmp#8##0:wybe.bool) + case ~tmp#8##0:wybe.bool of + 0: + foreign llvm move(0:wybe.list(T), ?no##0:wybe.list(T)) @tcmc_fields_alias:nn:nn + foreign llvm move(0:wybe.list(T), ?yes##1:wybe.list(T)) + + 1: + foreign lpvm access(l##0:wybe.list(T), 0:wybe.int, 16:wybe.int, 0:wybe.int, ?h##0:T) @list:nn:nn + foreign lpvm access(l##0:wybe.list(T), 8:wybe.int, 16:wybe.int, 0:wybe.int, ?t##0:wybe.list(T)) @list:nn:nn + p##0:(T, ?wybe.bool)(~h##0:T, ?tmp#5##0:wybe.bool) #1 @tcmc_fields_alias:nn:nn + case ~tmp#5##0:wybe.bool of + 0: + tcmc_fields_alias.partition<0>[6dacb8fd25](~p##0:(T, ?wybe.bool), ~t##0:wybe.list(T), ?yes##1:wybe.list(T), outByReference no0##0:wybe.list(T)) #6 @tcmc_fields_alias:nn:nn + foreign lpvm mutate(~l##0:wybe.list(T), ?no##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference no0##0:wybe.list(T)) @list:nn:nn + + 1: + tcmc_fields_alias.partition<0>[6dacb8fd25](~p##0:(T, ?wybe.bool), ~t##0:wybe.list(T), ?yes0##0:wybe.list(T), outByReference no0##0:wybe.list(T)) #2 @tcmc_fields_alias:nn:nn + foreign lpvm mutate(~l##0:wybe.list(T), ?tmp#0##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~yes0##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#0##0:wybe.list(T), ?yes##1:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~no0##0:wybe.list(T)) @tcmc_fields_alias:nn:nn + foreign llvm move(0:wybe.list(T), ?no##0:wybe.list(T)) @tcmc_fields_alias:nn:nn + + + + +unsafe_update_tail > {inline} (1 calls) +0: tcmc_fields_alias.unsafe_update_tail<0> +unsafe_update_tail(x##0:wybe.list(T), ?x##1:wybe.list(T), field##0:wybe.list(T))<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign lpvm mutate(~x##0:wybe.list(T), ?x##1:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~field##0:wybe.list(T)) @tcmc_fields_alias:nn:nn + + LLVM code : + +; ModuleID = 'tcmc_fields_alias' + + + + + +@tcmc_fields_alias.3 = constant {i64, i64} { i64 2, i64 ptrtoint ([?? x i8]* @tcmc_fields_alias.2 to i64) } + + +@tcmc_fields_alias.2 = constant [?? x i8] c", \00" + + +@tcmc_fields_alias.0 = constant [1 x i64] [i64 ptrtoint (void (i64, i64)* @"tcmc_fields_alias.gen#1<0>" to i64)] + + +@tcmc_fields_alias.1 = constant [1 x i64] [i64 ptrtoint (i64 (i64, i64)* @"tcmc_fields_alias.gen#2<1>" to i64)] + + +declare external ccc void @print_int(i64) + + +declare external ccc void @putchar(i8) + + +declare external fastcc void @"wybe.list.print<0>"(i64, i64) + + +declare external fastcc void @"wybe.string.print<0>"(i64) + + +declare external ccc i8* @wybe_malloc(i32) + + +declare external ccc void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1) + + +define external fastcc void @"tcmc_fields_alias.<0>"() { +entry: + %0 = trunc i64 16 to i32 + %1 = tail call ccc i8* @wybe_malloc(i32 %0) + %2 = ptrtoint i8* %1 to i64 + %3 = inttoptr i64 %2 to i64* + store i64 7, i64* %3 + %4 = add i64 %2, 8 + %5 = inttoptr i64 %4 to i64* + store i64 0, i64* %5 + %6 = trunc i64 16 to i32 + %7 = tail call ccc i8* @wybe_malloc(i32 %6) + %8 = ptrtoint i8* %7 to i64 + %9 = inttoptr i64 %8 to i64* + store i64 6, i64* %9 + %10 = add i64 %8, 8 + %11 = inttoptr i64 %10 to i64* + store i64 %2, i64* %11 + %12 = trunc i64 16 to i32 + %13 = tail call ccc i8* @wybe_malloc(i32 %12) + %14 = ptrtoint i8* %13 to i64 + %15 = inttoptr i64 %14 to i64* + store i64 5, i64* %15 + %16 = add i64 %14, 8 + %17 = inttoptr i64 %16 to i64* + store i64 %8, i64* %17 + %18 = trunc i64 16 to i32 + %19 = tail call ccc i8* @wybe_malloc(i32 %18) + %20 = ptrtoint i8* %19 to i64 + %21 = inttoptr i64 %20 to i64* + store i64 4, i64* %21 + %22 = add i64 %20, 8 + %23 = inttoptr i64 %22 to i64* + store i64 %14, i64* %23 + %24 = trunc i64 16 to i32 + %25 = tail call ccc i8* @wybe_malloc(i32 %24) + %26 = ptrtoint i8* %25 to i64 + %27 = inttoptr i64 %26 to i64* + store i64 3, i64* %27 + %28 = add i64 %26, 8 + %29 = inttoptr i64 %28 to i64* + store i64 %20, i64* %29 + %30 = trunc i64 16 to i32 + %31 = tail call ccc i8* @wybe_malloc(i32 %30) + %32 = ptrtoint i8* %31 to i64 + %33 = inttoptr i64 %32 to i64* + store i64 9, i64* %33 + %34 = add i64 %32, 8 + %35 = inttoptr i64 %34 to i64* + store i64 %26, i64* %35 + %36 = trunc i64 16 to i32 + %37 = tail call ccc i8* @wybe_malloc(i32 %36) + %38 = ptrtoint i8* %37 to i64 + %39 = inttoptr i64 %38 to i64* + store i64 2, i64* %39 + %40 = add i64 %38, 8 + %41 = inttoptr i64 %40 to i64* + store i64 %32, i64* %41 + %42 = trunc i64 16 to i32 + %43 = tail call ccc i8* @wybe_malloc(i32 %42) + %44 = ptrtoint i8* %43 to i64 + %45 = inttoptr i64 %44 to i64* + store i64 1, i64* %45 + %46 = add i64 %44, 8 + %47 = inttoptr i64 %46 to i64* + store i64 %38, i64* %47 + tail call fastcc void @"wybe.list.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ([1 x i64], [1 x i64]* @tcmc_fields_alias.0, i32 0, i32 0) to i64), i64 %44) + tail call ccc void @putchar(i8 10) + %48 = alloca i64 + %49 = call fastcc i64 @"tcmc_fields_alias.partition<0>[6dacb8fd25]"(i64 ptrtoint (i64* getelementptr inbounds ([1 x i64], [1 x i64]* @tcmc_fields_alias.1, i32 0, i32 0) to i64), i64 %44, i64* %48) + %50 = load i64, i64* %48 + tail call fastcc void @"wybe.list.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ([1 x i64], [1 x i64]* @tcmc_fields_alias.0, i32 0, i32 0) to i64), i64 %49) + tail call fastcc void @"wybe.string.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ({i64, i64}, {i64, i64}* @tcmc_fields_alias.3, i32 0, i32 0) to i64)) + tail call fastcc void @"wybe.list.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ([1 x i64], [1 x i64]* @tcmc_fields_alias.0, i32 0, i32 0) to i64), i64 %50) + tail call ccc void @putchar(i8 10) + ret void +} + + +define external fastcc void @"tcmc_fields_alias.gen#1<0>"(i64 %"#env##0", i64 %"x##0") { +entry: + tail call ccc void @print_int(i64 %"x##0") + ret void +} + + +define external fastcc i1 @"tcmc_fields_alias.gen#2<0>"(i64 %"anon#1#1##0") { +entry: + %0 = icmp sge i64 %"anon#1#1##0", 3 + ret i1 %0 +} + + +define external fastcc i64 @"tcmc_fields_alias.gen#2<1>"(i64 %"#env##0", i64 %"anon#1#1##0") { +entry: + %0 = icmp sge i64 %"anon#1#1##0", 3 + %1 = zext i1 %0 to i64 + ret i64 %1 +} + + +define external fastcc i64 @"tcmc_fields_alias.partition<0>"(i64 %"p##0", i64 %"l##0", i64* %"no#ref##0") { +entry: + %0 = icmp ne i64 %"l##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = inttoptr i64 %"l##0" to i64* + %2 = load i64, i64* %1 + %3 = add i64 %"l##0", 8 + %4 = inttoptr i64 %3 to i64* + %5 = load i64, i64* %4 + %6 = inttoptr i64 %"p##0" to i64* + %7 = load i64, i64* %6 + %8 = inttoptr i64 %7 to i64 (i64, i64)* + %9 = tail call fastcc i64 %8(i64 %"p##0", i64 %2) + %10 = trunc i64 %9 to i1 + br i1 %10, label %if.then1, label %if.else1 +if.else: + store i64 0, i64* %"no#ref##0" + ret i64 0 +if.then1: + %11 = alloca i64 + %12 = call fastcc i64 @"tcmc_fields_alias.partition<0>"(i64 %"p##0", i64 %5, i64* %11) + %13 = load i64, i64* %11 + %14 = trunc i64 16 to i32 + %15 = tail call ccc i8* @wybe_malloc(i32 %14) + %16 = ptrtoint i8* %15 to i64 + %17 = inttoptr i64 %16 to i64* + store i64 %2, i64* %17 + %18 = add i64 %16, 8 + %19 = inttoptr i64 %18 to i64* + store i64 %12, i64* %19 + %20 = add i64 %16, 8 + %21 = inttoptr i64 %20 to i64* + store i64 %13, i64* %21 + store i64 0, i64* %"no#ref##0" + ret i64 %16 +if.else1: + %22 = trunc i64 16 to i32 + %23 = tail call ccc i8* @wybe_malloc(i32 %22) + %24 = ptrtoint i8* %23 to i64 + %25 = inttoptr i64 %24 to i64* + store i64 %2, i64* %25 + %26 = add i64 %24, 8 + %27 = inttoptr i64 %26 to i64* + store i64 %24, i64* %"no#ref##0" + %28 = musttail call fastcc i64 @"tcmc_fields_alias.partition<0>"(i64 %"p##0", i64 %5, i64* %27) + ret i64 %28 +} + + +define external fastcc i64 @"tcmc_fields_alias.partition<0>[6dacb8fd25]"(i64 %"p##0", i64 %"l##0", i64* %"no#ref##0") { +entry: + %0 = icmp ne i64 %"l##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = inttoptr i64 %"l##0" to i64* + %2 = load i64, i64* %1 + %3 = add i64 %"l##0", 8 + %4 = inttoptr i64 %3 to i64* + %5 = load i64, i64* %4 + %6 = inttoptr i64 %"p##0" to i64* + %7 = load i64, i64* %6 + %8 = inttoptr i64 %7 to i64 (i64, i64)* + %9 = tail call fastcc i64 %8(i64 %"p##0", i64 %2) + %10 = trunc i64 %9 to i1 + br i1 %10, label %if.then1, label %if.else1 +if.else: + store i64 0, i64* %"no#ref##0" + ret i64 0 +if.then1: + %11 = alloca i64 + %12 = call fastcc i64 @"tcmc_fields_alias.partition<0>[6dacb8fd25]"(i64 %"p##0", i64 %5, i64* %11) + %13 = load i64, i64* %11 + %14 = add i64 %"l##0", 8 + %15 = inttoptr i64 %14 to i64* + store i64 %12, i64* %15 + %16 = add i64 %"l##0", 8 + %17 = inttoptr i64 %16 to i64* + store i64 %13, i64* %17 + store i64 0, i64* %"no#ref##0" + ret i64 %"l##0" +if.else1: + %18 = add i64 %"l##0", 8 + %19 = inttoptr i64 %18 to i64* + store i64 %"l##0", i64* %"no#ref##0" + %20 = musttail call fastcc i64 @"tcmc_fields_alias.partition<0>[6dacb8fd25]"(i64 %"p##0", i64 %5, i64* %19) + ret i64 %20 +} + + +define external fastcc i64 @"tcmc_fields_alias.unsafe_update_tail<0>"(i64 %"x##0", i64 %"field##0") { +entry: + %0 = add i64 %"x##0", 8 + %1 = inttoptr i64 %0 to i64* + store i64 %"field##0", i64* %1 + ret i64 %"x##0" +} diff --git a/test-cases/final-dump/tcmc_fields_alias.wybe b/test-cases/final-dump/tcmc_fields_alias.wybe new file mode 100644 index 00000000..67c6013f --- /dev/null +++ b/test-cases/final-dump/tcmc_fields_alias.wybe @@ -0,0 +1,35 @@ +# UNSAFE +# this forcibly writes without checking whether it is the correct variant or not +def {inline} unsafe_update_tail(!x:list(T), field:list(T)) { + foreign lpvm mutate(x, ?x, 8, 1, 16, 0, field) +} + +def partition(p: {test}(T), l: list(T), ?yes: list(T), ?no: list(T)) { + if { [?h | ?t] = l :: + if { p(h) :: + partition(p, t, ?yes0, ?no0) + # the idea here is that we write *both* yes0 and no0 to the tail + # of the list + # this should *not* be TCMC-optimizable, since it may not be + # deterministic which order yes0 or no0 are written (only the + # last one remains) + ?yes = [h|yes0] + unsafe_update_tail(!yes, no0) + ?no = [] + | else :: + partition(p, t, ?yes0, ?no0) + ?yes = yes0 + ?no = [h|no0] + } + | else :: + ?yes = [] + ?no = [] + } +} +?l: list(int) = [1,2,9,3,4,5,6,7] +!println(print, l) +partition({test} { @1 >= 3}, l, ?yes, ?no) +!print(print, yes) +!print(", ") +!print(print, no) +!nl \ No newline at end of file diff --git a/test-cases/final-dump/tcmc_multiple_outputs.exp b/test-cases/final-dump/tcmc_multiple_outputs.exp new file mode 100644 index 00000000..91bb34eb --- /dev/null +++ b/test-cases/final-dump/tcmc_multiple_outputs.exp @@ -0,0 +1,641 @@ +====================================================================== +AFTER EVERYTHING: + Module tcmc_multiple_outputs + representation : (not a type) + public submods : + public resources: + public procs : tcmc_multiple_outputs.<0> + imports : use wybe + resources : + procs : + +module top-level code > public {impure} (0 calls) +0: tcmc_multiple_outputs.<0> +()<{<>}; {<>}>: + AliasPairs: [] + InterestingCallProperties: [] + MultiSpeczDepInfo: [(15,(tcmc_multiple_outputs.appendtwice<0>,fromList [NonAliasedParamCond 0 [],NonAliasedParamCond 3 []]))] + foreign lpvm alloc(16:wybe.int, ?tmp#19##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#19##0:wybe.list(T), ?tmp#20##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 3:T) @list:nn:nn + foreign lpvm mutate(~tmp#20##0:wybe.list(T), ?tmp#2##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#23##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#23##0:wybe.list(T), ?tmp#24##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 2:T) @list:nn:nn + foreign lpvm mutate(~tmp#24##0:wybe.list(T), ?tmp#1##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#2##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#27##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#27##0:wybe.list(T), ?tmp#28##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 1:T) @list:nn:nn + foreign lpvm mutate(~tmp#28##0:wybe.list(T), ?tmp#0##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#1##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#31##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#31##0:wybe.list(T), ?tmp#32##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 6:T) @list:nn:nn + foreign lpvm mutate(~tmp#32##0:wybe.list(T), ?tmp#6##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#35##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#35##0:wybe.list(T), ?tmp#36##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 5:T) @list:nn:nn + foreign lpvm mutate(~tmp#36##0:wybe.list(T), ?tmp#5##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#6##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#39##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#39##0:wybe.list(T), ?tmp#40##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 4:T) @list:nn:nn + foreign lpvm mutate(~tmp#40##0:wybe.list(T), ?tmp#4##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#5##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#43##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#43##0:wybe.list(T), ?tmp#44##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 8:T) @list:nn:nn + foreign lpvm mutate(~tmp#44##0:wybe.list(T), ?tmp#9##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#47##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#47##0:wybe.list(T), ?tmp#48##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 7:T) @list:nn:nn + foreign lpvm mutate(~tmp#48##0:wybe.list(T), ?tmp#8##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#9##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#51##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#51##0:wybe.list(T), ?tmp#52##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 11:T) @list:nn:nn + foreign lpvm mutate(~tmp#52##0:wybe.list(T), ?tmp#13##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#55##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#55##0:wybe.list(T), ?tmp#56##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 10:T) @list:nn:nn + foreign lpvm mutate(~tmp#56##0:wybe.list(T), ?tmp#12##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#13##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#59##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#59##0:wybe.list(T), ?tmp#60##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 9:T) @list:nn:nn + foreign lpvm mutate(~tmp#60##0:wybe.list(T), ?tmp#11##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#12##0:wybe.list(T)) @list:nn:nn + tcmc_multiple_outputs.appendtwice<0>[d4b0b4930c](~tmp#0##0:wybe.list(wybe.int), ~tmp#4##0:wybe.list(wybe.int), outByReference result1##0:wybe.list(wybe.int), ~tmp#8##0:wybe.list(wybe.int), ~tmp#11##0:wybe.list(wybe.int), outByReference result2##0:wybe.list(wybe.int)) #15 @tcmc_multiple_outputs:nn:nn + wybe.list.print<0>(tcmc_multiple_outputs.gen#1<0><>:{resource}(T), ~result1##0:wybe.list(T)) #18 @list:nn:nn + foreign lpvm load(<>:wybe.phantom, ?%tmp#63##0:wybe.phantom) @io:nn:nn + foreign c putchar('\n':wybe.char, ~tmp#63##0:wybe.phantom, ?tmp#64##0:wybe.phantom) @io:nn:nn + foreign lpvm store(~%tmp#64##0:wybe.phantom, <>:wybe.phantom) @io:nn:nn + wybe.list.print<0>(tcmc_multiple_outputs.gen#1<0><>:{resource}(T), ~result2##0:wybe.list(T)) #19 @list:nn:nn + foreign lpvm load(<>:wybe.phantom, ?%tmp#67##0:wybe.phantom) @io:nn:nn + foreign c putchar('\n':wybe.char, ~tmp#67##0:wybe.phantom, ?tmp#68##0:wybe.phantom) @io:nn:nn + foreign lpvm store(~%tmp#68##0:wybe.phantom, <>:wybe.phantom) @io:nn:nn + + +appendtwice > (4 calls) +0: tcmc_multiple_outputs.appendtwice<0>[d4b0b4930c] +appendtwice(front1##0:wybe.list(T), back1##0:wybe.list(T), outByReference result1##0:wybe.list(T), front2##0:wybe.list(T), back2##0:wybe.list(T), outByReference result2##0:wybe.list(T))<{}; {}>: + AliasPairs: [(back1##0,result1##0),(back2##0,result2##0)] + InterestingCallProperties: [InterestingUnaliased 0,InterestingUnaliased 3] + MultiSpeczDepInfo: [(2,(tcmc_multiple_outputs.appendtwice<0>,fromList [NonAliasedParamCond 0 [0],NonAliasedParamCond 3 [3]])),(7,(tcmc_multiple_outputs.appendtwice<0>,fromList [NonAliasedParamCond 0 [0],NonAliasedParamCond 3 []])),(12,(tcmc_multiple_outputs.appendtwice<0>,fromList [NonAliasedParamCond 0 [],NonAliasedParamCond 3 [3]]))] + foreign llvm icmp_ne(front1##0:wybe.int, 0:wybe.int, ?tmp#14##0:wybe.bool) + case ~tmp#14##0:wybe.bool of + 0: + foreign llvm icmp_ne(front2##0:wybe.int, 0:wybe.int, ?tmp#16##0:wybe.bool) + case ~tmp#16##0:wybe.bool of + 0: + foreign llvm move(~back1##0:wybe.list(T), ?result1##0:wybe.list(T)) @tcmc_multiple_outputs:nn:nn + foreign llvm move(~back2##0:wybe.list(T), ?result2##0:wybe.list(T)) @tcmc_multiple_outputs:nn:nn + + 1: + foreign lpvm access(front2##0:wybe.list(T), 0:wybe.int, 16:wybe.int, 0:wybe.int, ?h2##0:T) @list:nn:nn + foreign lpvm access(~front2##0:wybe.list(T), 8:wybe.int, 16:wybe.int, 0:wybe.int, ?t2##0:wybe.list(T)) @list:nn:nn + foreign llvm move(~back1##0:wybe.list(T), ?result1##0:wybe.list(T)) @tcmc_multiple_outputs:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#19##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#19##0:wybe.list(T), ?tmp#20##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~h2##0:T) @list:nn:nn + tcmc_multiple_outputs.appendtwice<0>[410bae77d3](0:wybe.list(T), 0:wybe.list(T), outByReference tmp#8##0:wybe.list(T), ~t2##0:wybe.list(T), ~back2##0:wybe.list(T), outByReference tail2##0:wybe.list(T)) #12 @tcmc_multiple_outputs:nn:nn + foreign lpvm mutate(~tmp#20##0:wybe.list(T), ?result2##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference tail2##0:wybe.list(T)) @list:nn:nn + + + 1: + foreign lpvm access(front1##0:wybe.list(T), 0:wybe.int, 16:wybe.int, 0:wybe.int, ?h1##0:T) @list:nn:nn + foreign lpvm access(~front1##0:wybe.list(T), 8:wybe.int, 16:wybe.int, 0:wybe.int, ?t1##0:wybe.list(T)) @list:nn:nn + foreign llvm icmp_ne(front2##0:wybe.int, 0:wybe.int, ?tmp#16##0:wybe.bool) + case ~tmp#16##0:wybe.bool of + 0: + foreign lpvm alloc(16:wybe.int, ?tmp#19##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#19##0:wybe.list(T), ?tmp#20##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~h1##0:T) @list:nn:nn + foreign llvm move(~back2##0:wybe.list(T), ?result2##0:wybe.list(T)) @tcmc_multiple_outputs:nn:nn + tcmc_multiple_outputs.appendtwice<0>[3869c8b78e](~t1##0:wybe.list(T), ~back1##0:wybe.list(T), outByReference tail1##0:wybe.list(T), 0:wybe.list(T), 0:wybe.list(T), outByReference tmp#4##0:wybe.list(T)) #7 @tcmc_multiple_outputs:nn:nn + foreign lpvm mutate(~tmp#20##0:wybe.list(T), ?result1##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference tail1##0:wybe.list(T)) @list:nn:nn + + 1: + foreign lpvm access(front2##0:wybe.list(T), 0:wybe.int, 16:wybe.int, 0:wybe.int, ?h2##0:T) @list:nn:nn + foreign lpvm access(~front2##0:wybe.list(T), 8:wybe.int, 16:wybe.int, 0:wybe.int, ?t2##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#19##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#19##0:wybe.list(T), ?tmp#20##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~h1##0:T) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#23##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#23##0:wybe.list(T), ?tmp#24##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~h2##0:T) @list:nn:nn + tcmc_multiple_outputs.appendtwice<0>(~t1##0:wybe.list(T), ~back1##0:wybe.list(T), outByReference tail1##0:wybe.list(T), ~t2##0:wybe.list(T), ~back2##0:wybe.list(T), outByReference tail2##0:wybe.list(T)) #2 @tcmc_multiple_outputs:nn:nn + foreign lpvm mutate(~tmp#20##0:wybe.list(T), ?result1##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference tail1##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#24##0:wybe.list(T), ?result2##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference tail2##0:wybe.list(T)) @list:nn:nn + + + [410bae77d3] [NonAliasedParam 0] : + foreign llvm icmp_ne(front1##0:wybe.int, 0:wybe.int, ?tmp#14##0:wybe.bool) + case ~tmp#14##0:wybe.bool of + 0: + foreign llvm icmp_ne(front2##0:wybe.int, 0:wybe.int, ?tmp#16##0:wybe.bool) + case ~tmp#16##0:wybe.bool of + 0: + foreign llvm move(~back1##0:wybe.list(T), ?result1##0:wybe.list(T)) @tcmc_multiple_outputs:nn:nn + foreign llvm move(~back2##0:wybe.list(T), ?result2##0:wybe.list(T)) @tcmc_multiple_outputs:nn:nn + + 1: + foreign lpvm access(front2##0:wybe.list(T), 0:wybe.int, 16:wybe.int, 0:wybe.int, ?h2##0:T) @list:nn:nn + foreign lpvm access(~front2##0:wybe.list(T), 8:wybe.int, 16:wybe.int, 0:wybe.int, ?t2##0:wybe.list(T)) @list:nn:nn + foreign llvm move(~back1##0:wybe.list(T), ?result1##0:wybe.list(T)) @tcmc_multiple_outputs:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#19##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#19##0:wybe.list(T), ?tmp#20##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~h2##0:T) @list:nn:nn + tcmc_multiple_outputs.appendtwice<0>[410bae77d3](0:wybe.list(T), 0:wybe.list(T), outByReference tmp#8##0:wybe.list(T), ~t2##0:wybe.list(T), ~back2##0:wybe.list(T), outByReference tail2##0:wybe.list(T)) #12 @tcmc_multiple_outputs:nn:nn + foreign lpvm mutate(~tmp#20##0:wybe.list(T), ?result2##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference tail2##0:wybe.list(T)) @list:nn:nn + + + 1: + foreign lpvm access(front1##0:wybe.list(T), 8:wybe.int, 16:wybe.int, 0:wybe.int, ?t1##0:wybe.list(T)) @list:nn:nn + foreign llvm icmp_ne(front2##0:wybe.int, 0:wybe.int, ?tmp#16##0:wybe.bool) + case ~tmp#16##0:wybe.bool of + 0: + foreign llvm move(~back2##0:wybe.list(T), ?result2##0:wybe.list(T)) @tcmc_multiple_outputs:nn:nn + tcmc_multiple_outputs.appendtwice<0>[d4b0b4930c](~t1##0:wybe.list(T), ~back1##0:wybe.list(T), outByReference tail1##0:wybe.list(T), 0:wybe.list(T), 0:wybe.list(T), outByReference tmp#4##0:wybe.list(T)) #7 @tcmc_multiple_outputs:nn:nn + foreign lpvm mutate(~front1##0:wybe.list(T), ?result1##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference tail1##0:wybe.list(T)) @list:nn:nn + + 1: + foreign lpvm access(front2##0:wybe.list(T), 0:wybe.int, 16:wybe.int, 0:wybe.int, ?h2##0:T) @list:nn:nn + foreign lpvm access(~front2##0:wybe.list(T), 8:wybe.int, 16:wybe.int, 0:wybe.int, ?t2##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#23##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#23##0:wybe.list(T), ?tmp#24##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~h2##0:T) @list:nn:nn + tcmc_multiple_outputs.appendtwice<0>[410bae77d3](~t1##0:wybe.list(T), ~back1##0:wybe.list(T), outByReference tail1##0:wybe.list(T), ~t2##0:wybe.list(T), ~back2##0:wybe.list(T), outByReference tail2##0:wybe.list(T)) #2 @tcmc_multiple_outputs:nn:nn + foreign lpvm mutate(~front1##0:wybe.list(T), ?result1##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference tail1##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#24##0:wybe.list(T), ?result2##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference tail2##0:wybe.list(T)) @list:nn:nn + + + + [d4b0b4930c] [NonAliasedParam 0,NonAliasedParam 3] : + foreign llvm icmp_ne(front1##0:wybe.int, 0:wybe.int, ?tmp#14##0:wybe.bool) + case ~tmp#14##0:wybe.bool of + 0: + foreign llvm icmp_ne(front2##0:wybe.int, 0:wybe.int, ?tmp#16##0:wybe.bool) + case ~tmp#16##0:wybe.bool of + 0: + foreign llvm move(~back1##0:wybe.list(T), ?result1##0:wybe.list(T)) @tcmc_multiple_outputs:nn:nn + foreign llvm move(~back2##0:wybe.list(T), ?result2##0:wybe.list(T)) @tcmc_multiple_outputs:nn:nn + + 1: + foreign lpvm access(front2##0:wybe.list(T), 8:wybe.int, 16:wybe.int, 0:wybe.int, ?t2##0:wybe.list(T)) @list:nn:nn + foreign llvm move(~back1##0:wybe.list(T), ?result1##0:wybe.list(T)) @tcmc_multiple_outputs:nn:nn + tcmc_multiple_outputs.appendtwice<0>[d4b0b4930c](0:wybe.list(T), 0:wybe.list(T), outByReference tmp#8##0:wybe.list(T), ~t2##0:wybe.list(T), ~back2##0:wybe.list(T), outByReference tail2##0:wybe.list(T)) #12 @tcmc_multiple_outputs:nn:nn + foreign lpvm mutate(~front2##0:wybe.list(T), ?result2##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference tail2##0:wybe.list(T)) @list:nn:nn + + + 1: + foreign lpvm access(front1##0:wybe.list(T), 0:wybe.int, 16:wybe.int, 0:wybe.int, ?h1##0:T) @list:nn:nn + foreign lpvm access(front1##0:wybe.list(T), 8:wybe.int, 16:wybe.int, 0:wybe.int, ?t1##0:wybe.list(T)) @list:nn:nn + foreign llvm icmp_ne(front2##0:wybe.int, 0:wybe.int, ?tmp#16##0:wybe.bool) + case ~tmp#16##0:wybe.bool of + 0: + foreign llvm move(~back2##0:wybe.list(T), ?result2##0:wybe.list(T)) @tcmc_multiple_outputs:nn:nn + tcmc_multiple_outputs.appendtwice<0>[d4b0b4930c](~t1##0:wybe.list(T), ~back1##0:wybe.list(T), outByReference tail1##0:wybe.list(T), 0:wybe.list(T), 0:wybe.list(T), outByReference tmp#4##0:wybe.list(T)) #7 @tcmc_multiple_outputs:nn:nn + foreign lpvm mutate(~front1##0:wybe.list(T), ?result1##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference tail1##0:wybe.list(T)) @list:nn:nn + + 1: + foreign lpvm access(front2##0:wybe.list(T), 0:wybe.int, 16:wybe.int, 0:wybe.int, ?h2##0:T) @list:nn:nn + foreign lpvm access(front2##0:wybe.list(T), 8:wybe.int, 16:wybe.int, 0:wybe.int, ?t2##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~front2##0:wybe.list(T), ?tmp#20##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~h1##0:T) @list:nn:nn + foreign lpvm mutate(~front1##0:wybe.list(T), ?tmp#24##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~h2##0:T) @list:nn:nn + tcmc_multiple_outputs.appendtwice<0>[d4b0b4930c](~t1##0:wybe.list(T), ~back1##0:wybe.list(T), outByReference tail1##0:wybe.list(T), ~t2##0:wybe.list(T), ~back2##0:wybe.list(T), outByReference tail2##0:wybe.list(T)) #2 @tcmc_multiple_outputs:nn:nn + foreign lpvm mutate(~tmp#20##0:wybe.list(T), ?result1##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference tail1##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#24##0:wybe.list(T), ?result2##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference tail2##0:wybe.list(T)) @list:nn:nn + + + + [3869c8b78e] [NonAliasedParam 3] : + foreign llvm icmp_ne(front1##0:wybe.int, 0:wybe.int, ?tmp#14##0:wybe.bool) + case ~tmp#14##0:wybe.bool of + 0: + foreign llvm icmp_ne(front2##0:wybe.int, 0:wybe.int, ?tmp#16##0:wybe.bool) + case ~tmp#16##0:wybe.bool of + 0: + foreign llvm move(~back1##0:wybe.list(T), ?result1##0:wybe.list(T)) @tcmc_multiple_outputs:nn:nn + foreign llvm move(~back2##0:wybe.list(T), ?result2##0:wybe.list(T)) @tcmc_multiple_outputs:nn:nn + + 1: + foreign lpvm access(front2##0:wybe.list(T), 8:wybe.int, 16:wybe.int, 0:wybe.int, ?t2##0:wybe.list(T)) @list:nn:nn + foreign llvm move(~back1##0:wybe.list(T), ?result1##0:wybe.list(T)) @tcmc_multiple_outputs:nn:nn + tcmc_multiple_outputs.appendtwice<0>[d4b0b4930c](0:wybe.list(T), 0:wybe.list(T), outByReference tmp#8##0:wybe.list(T), ~t2##0:wybe.list(T), ~back2##0:wybe.list(T), outByReference tail2##0:wybe.list(T)) #12 @tcmc_multiple_outputs:nn:nn + foreign lpvm mutate(~front2##0:wybe.list(T), ?result2##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference tail2##0:wybe.list(T)) @list:nn:nn + + + 1: + foreign lpvm access(front1##0:wybe.list(T), 0:wybe.int, 16:wybe.int, 0:wybe.int, ?h1##0:T) @list:nn:nn + foreign lpvm access(~front1##0:wybe.list(T), 8:wybe.int, 16:wybe.int, 0:wybe.int, ?t1##0:wybe.list(T)) @list:nn:nn + foreign llvm icmp_ne(front2##0:wybe.int, 0:wybe.int, ?tmp#16##0:wybe.bool) + case ~tmp#16##0:wybe.bool of + 0: + foreign lpvm alloc(16:wybe.int, ?tmp#19##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#19##0:wybe.list(T), ?tmp#20##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~h1##0:T) @list:nn:nn + foreign llvm move(~back2##0:wybe.list(T), ?result2##0:wybe.list(T)) @tcmc_multiple_outputs:nn:nn + tcmc_multiple_outputs.appendtwice<0>[3869c8b78e](~t1##0:wybe.list(T), ~back1##0:wybe.list(T), outByReference tail1##0:wybe.list(T), 0:wybe.list(T), 0:wybe.list(T), outByReference tmp#4##0:wybe.list(T)) #7 @tcmc_multiple_outputs:nn:nn + foreign lpvm mutate(~tmp#20##0:wybe.list(T), ?result1##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference tail1##0:wybe.list(T)) @list:nn:nn + + 1: + foreign lpvm access(front2##0:wybe.list(T), 0:wybe.int, 16:wybe.int, 0:wybe.int, ?h2##0:T) @list:nn:nn + foreign lpvm access(front2##0:wybe.list(T), 8:wybe.int, 16:wybe.int, 0:wybe.int, ?t2##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~front2##0:wybe.list(T), ?tmp#20##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~h1##0:T) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#23##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#23##0:wybe.list(T), ?tmp#24##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~h2##0:T) @list:nn:nn + tcmc_multiple_outputs.appendtwice<0>[3869c8b78e](~t1##0:wybe.list(T), ~back1##0:wybe.list(T), outByReference tail1##0:wybe.list(T), ~t2##0:wybe.list(T), ~back2##0:wybe.list(T), outByReference tail2##0:wybe.list(T)) #2 @tcmc_multiple_outputs:nn:nn + foreign lpvm mutate(~tmp#20##0:wybe.list(T), ?result1##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference tail1##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#24##0:wybe.list(T), ?result2##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference tail2##0:wybe.list(T)) @list:nn:nn + + + + +gen#1 > {inline} (2 calls) +0: tcmc_multiple_outputs.gen#1<0> +gen#1(x##0:wybe.int)<{<>}; {<>}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign lpvm load(<>:wybe.phantom, ?%tmp#1##0:wybe.phantom) @int:nn:nn + foreign c print_int(~x##0:wybe.int, ~tmp#1##0:wybe.phantom, ?tmp#2##0:wybe.phantom) @int:nn:nn + foreign lpvm store(~%tmp#2##0:wybe.phantom, <>:wybe.phantom) @int:nn:nn + + LLVM code : + +; ModuleID = 'tcmc_multiple_outputs' + + + + + +@tcmc_multiple_outputs.0 = constant [1 x i64] [i64 ptrtoint (void (i64, i64)* @"tcmc_multiple_outputs.gen#1<0>" to i64)] + + +declare external ccc void @print_int(i64) + + +declare external ccc void @putchar(i8) + + +declare external fastcc void @"wybe.list.print<0>"(i64, i64) + + +declare external ccc i8* @wybe_malloc(i32) + + +declare external ccc void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1) + + +define external fastcc void @"tcmc_multiple_outputs.<0>"() { +entry: + %0 = trunc i64 16 to i32 + %1 = tail call ccc i8* @wybe_malloc(i32 %0) + %2 = ptrtoint i8* %1 to i64 + %3 = inttoptr i64 %2 to i64* + store i64 3, i64* %3 + %4 = add i64 %2, 8 + %5 = inttoptr i64 %4 to i64* + store i64 0, i64* %5 + %6 = trunc i64 16 to i32 + %7 = tail call ccc i8* @wybe_malloc(i32 %6) + %8 = ptrtoint i8* %7 to i64 + %9 = inttoptr i64 %8 to i64* + store i64 2, i64* %9 + %10 = add i64 %8, 8 + %11 = inttoptr i64 %10 to i64* + store i64 %2, i64* %11 + %12 = trunc i64 16 to i32 + %13 = tail call ccc i8* @wybe_malloc(i32 %12) + %14 = ptrtoint i8* %13 to i64 + %15 = inttoptr i64 %14 to i64* + store i64 1, i64* %15 + %16 = add i64 %14, 8 + %17 = inttoptr i64 %16 to i64* + store i64 %8, i64* %17 + %18 = trunc i64 16 to i32 + %19 = tail call ccc i8* @wybe_malloc(i32 %18) + %20 = ptrtoint i8* %19 to i64 + %21 = inttoptr i64 %20 to i64* + store i64 6, i64* %21 + %22 = add i64 %20, 8 + %23 = inttoptr i64 %22 to i64* + store i64 0, i64* %23 + %24 = trunc i64 16 to i32 + %25 = tail call ccc i8* @wybe_malloc(i32 %24) + %26 = ptrtoint i8* %25 to i64 + %27 = inttoptr i64 %26 to i64* + store i64 5, i64* %27 + %28 = add i64 %26, 8 + %29 = inttoptr i64 %28 to i64* + store i64 %20, i64* %29 + %30 = trunc i64 16 to i32 + %31 = tail call ccc i8* @wybe_malloc(i32 %30) + %32 = ptrtoint i8* %31 to i64 + %33 = inttoptr i64 %32 to i64* + store i64 4, i64* %33 + %34 = add i64 %32, 8 + %35 = inttoptr i64 %34 to i64* + store i64 %26, i64* %35 + %36 = trunc i64 16 to i32 + %37 = tail call ccc i8* @wybe_malloc(i32 %36) + %38 = ptrtoint i8* %37 to i64 + %39 = inttoptr i64 %38 to i64* + store i64 8, i64* %39 + %40 = add i64 %38, 8 + %41 = inttoptr i64 %40 to i64* + store i64 0, i64* %41 + %42 = trunc i64 16 to i32 + %43 = tail call ccc i8* @wybe_malloc(i32 %42) + %44 = ptrtoint i8* %43 to i64 + %45 = inttoptr i64 %44 to i64* + store i64 7, i64* %45 + %46 = add i64 %44, 8 + %47 = inttoptr i64 %46 to i64* + store i64 %38, i64* %47 + %48 = trunc i64 16 to i32 + %49 = tail call ccc i8* @wybe_malloc(i32 %48) + %50 = ptrtoint i8* %49 to i64 + %51 = inttoptr i64 %50 to i64* + store i64 11, i64* %51 + %52 = add i64 %50, 8 + %53 = inttoptr i64 %52 to i64* + store i64 0, i64* %53 + %54 = trunc i64 16 to i32 + %55 = tail call ccc i8* @wybe_malloc(i32 %54) + %56 = ptrtoint i8* %55 to i64 + %57 = inttoptr i64 %56 to i64* + store i64 10, i64* %57 + %58 = add i64 %56, 8 + %59 = inttoptr i64 %58 to i64* + store i64 %50, i64* %59 + %60 = trunc i64 16 to i32 + %61 = tail call ccc i8* @wybe_malloc(i32 %60) + %62 = ptrtoint i8* %61 to i64 + %63 = inttoptr i64 %62 to i64* + store i64 9, i64* %63 + %64 = add i64 %62, 8 + %65 = inttoptr i64 %64 to i64* + store i64 %56, i64* %65 + %66 = alloca i64 + %67 = alloca i64 + call fastcc void @"tcmc_multiple_outputs.appendtwice<0>[d4b0b4930c]"(i64 %14, i64 %32, i64* %66, i64 %44, i64 %62, i64* %67) + %68 = load i64, i64* %66 + %69 = load i64, i64* %67 + tail call fastcc void @"wybe.list.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ([1 x i64], [1 x i64]* @tcmc_multiple_outputs.0, i32 0, i32 0) to i64), i64 %68) + tail call ccc void @putchar(i8 10) + tail call fastcc void @"wybe.list.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ([1 x i64], [1 x i64]* @tcmc_multiple_outputs.0, i32 0, i32 0) to i64), i64 %69) + tail call ccc void @putchar(i8 10) + ret void +} + + +define external fastcc void @"tcmc_multiple_outputs.appendtwice<0>"(i64 %"front1##0", i64 %"back1##0", i64* %"result1#ref##0", i64 %"front2##0", i64 %"back2##0", i64* %"result2#ref##0") { +entry: + %0 = icmp ne i64 %"front1##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = inttoptr i64 %"front1##0" to i64* + %2 = load i64, i64* %1 + %3 = add i64 %"front1##0", 8 + %4 = inttoptr i64 %3 to i64* + %5 = load i64, i64* %4 + %6 = icmp ne i64 %"front2##0", 0 + br i1 %6, label %if.then1, label %if.else1 +if.else: + %31 = icmp ne i64 %"front2##0", 0 + br i1 %31, label %if.then2, label %if.else2 +if.then1: + %7 = inttoptr i64 %"front2##0" to i64* + %8 = load i64, i64* %7 + %9 = add i64 %"front2##0", 8 + %10 = inttoptr i64 %9 to i64* + %11 = load i64, i64* %10 + %12 = trunc i64 16 to i32 + %13 = tail call ccc i8* @wybe_malloc(i32 %12) + %14 = ptrtoint i8* %13 to i64 + %15 = inttoptr i64 %14 to i64* + store i64 %2, i64* %15 + %16 = trunc i64 16 to i32 + %17 = tail call ccc i8* @wybe_malloc(i32 %16) + %18 = ptrtoint i8* %17 to i64 + %19 = inttoptr i64 %18 to i64* + store i64 %8, i64* %19 + %20 = add i64 %14, 8 + %21 = inttoptr i64 %20 to i64* + store i64 %14, i64* %"result1#ref##0" + %22 = add i64 %18, 8 + %23 = inttoptr i64 %22 to i64* + store i64 %18, i64* %"result2#ref##0" + musttail call fastcc void @"tcmc_multiple_outputs.appendtwice<0>"(i64 %5, i64 %"back1##0", i64* %21, i64 %11, i64 %"back2##0", i64* %23) + ret void +if.else1: + %24 = trunc i64 16 to i32 + %25 = tail call ccc i8* @wybe_malloc(i32 %24) + %26 = ptrtoint i8* %25 to i64 + %27 = inttoptr i64 %26 to i64* + store i64 %2, i64* %27 + store i64 %"back2##0", i64* %"result2#ref##0" + %28 = add i64 %26, 8 + %29 = inttoptr i64 %28 to i64* + store i64 %26, i64* %"result1#ref##0" + %30 = alloca i64 + call fastcc void @"tcmc_multiple_outputs.appendtwice<0>[3869c8b78e]"(i64 %5, i64 %"back1##0", i64* %29, i64 0, i64 0, i64* %30) + ret void +if.then2: + %32 = inttoptr i64 %"front2##0" to i64* + %33 = load i64, i64* %32 + %34 = add i64 %"front2##0", 8 + %35 = inttoptr i64 %34 to i64* + %36 = load i64, i64* %35 + store i64 %"back1##0", i64* %"result1#ref##0" + %37 = trunc i64 16 to i32 + %38 = tail call ccc i8* @wybe_malloc(i32 %37) + %39 = ptrtoint i8* %38 to i64 + %40 = inttoptr i64 %39 to i64* + store i64 %33, i64* %40 + %41 = add i64 %39, 8 + %42 = inttoptr i64 %41 to i64* + store i64 %39, i64* %"result2#ref##0" + %43 = alloca i64 + call fastcc void @"tcmc_multiple_outputs.appendtwice<0>[410bae77d3]"(i64 0, i64 0, i64* %43, i64 %36, i64 %"back2##0", i64* %42) + ret void +if.else2: + store i64 %"back1##0", i64* %"result1#ref##0" + store i64 %"back2##0", i64* %"result2#ref##0" + ret void +} + + +define external fastcc void @"tcmc_multiple_outputs.appendtwice<0>[410bae77d3]"(i64 %"front1##0", i64 %"back1##0", i64* %"result1#ref##0", i64 %"front2##0", i64 %"back2##0", i64* %"result2#ref##0") { +entry: + %0 = icmp ne i64 %"front1##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = add i64 %"front1##0", 8 + %2 = inttoptr i64 %1 to i64* + %3 = load i64, i64* %2 + %4 = icmp ne i64 %"front2##0", 0 + br i1 %4, label %if.then1, label %if.else1 +if.else: + %21 = icmp ne i64 %"front2##0", 0 + br i1 %21, label %if.then2, label %if.else2 +if.then1: + %5 = inttoptr i64 %"front2##0" to i64* + %6 = load i64, i64* %5 + %7 = add i64 %"front2##0", 8 + %8 = inttoptr i64 %7 to i64* + %9 = load i64, i64* %8 + %10 = trunc i64 16 to i32 + %11 = tail call ccc i8* @wybe_malloc(i32 %10) + %12 = ptrtoint i8* %11 to i64 + %13 = inttoptr i64 %12 to i64* + store i64 %6, i64* %13 + %14 = add i64 %"front1##0", 8 + %15 = inttoptr i64 %14 to i64* + store i64 %"front1##0", i64* %"result1#ref##0" + %16 = add i64 %12, 8 + %17 = inttoptr i64 %16 to i64* + store i64 %12, i64* %"result2#ref##0" + musttail call fastcc void @"tcmc_multiple_outputs.appendtwice<0>[410bae77d3]"(i64 %3, i64 %"back1##0", i64* %15, i64 %9, i64 %"back2##0", i64* %17) + ret void +if.else1: + store i64 %"back2##0", i64* %"result2#ref##0" + %18 = add i64 %"front1##0", 8 + %19 = inttoptr i64 %18 to i64* + store i64 %"front1##0", i64* %"result1#ref##0" + %20 = alloca i64 + call fastcc void @"tcmc_multiple_outputs.appendtwice<0>[d4b0b4930c]"(i64 %3, i64 %"back1##0", i64* %19, i64 0, i64 0, i64* %20) + ret void +if.then2: + %22 = inttoptr i64 %"front2##0" to i64* + %23 = load i64, i64* %22 + %24 = add i64 %"front2##0", 8 + %25 = inttoptr i64 %24 to i64* + %26 = load i64, i64* %25 + store i64 %"back1##0", i64* %"result1#ref##0" + %27 = trunc i64 16 to i32 + %28 = tail call ccc i8* @wybe_malloc(i32 %27) + %29 = ptrtoint i8* %28 to i64 + %30 = inttoptr i64 %29 to i64* + store i64 %23, i64* %30 + %31 = add i64 %29, 8 + %32 = inttoptr i64 %31 to i64* + store i64 %29, i64* %"result2#ref##0" + %33 = alloca i64 + call fastcc void @"tcmc_multiple_outputs.appendtwice<0>[410bae77d3]"(i64 0, i64 0, i64* %33, i64 %26, i64 %"back2##0", i64* %32) + ret void +if.else2: + store i64 %"back1##0", i64* %"result1#ref##0" + store i64 %"back2##0", i64* %"result2#ref##0" + ret void +} + + +define external fastcc void @"tcmc_multiple_outputs.appendtwice<0>[d4b0b4930c]"(i64 %"front1##0", i64 %"back1##0", i64* %"result1#ref##0", i64 %"front2##0", i64 %"back2##0", i64* %"result2#ref##0") { +entry: + %0 = icmp ne i64 %"front1##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = inttoptr i64 %"front1##0" to i64* + %2 = load i64, i64* %1 + %3 = add i64 %"front1##0", 8 + %4 = inttoptr i64 %3 to i64* + %5 = load i64, i64* %4 + %6 = icmp ne i64 %"front2##0", 0 + br i1 %6, label %if.then1, label %if.else1 +if.else: + %21 = icmp ne i64 %"front2##0", 0 + br i1 %21, label %if.then2, label %if.else2 +if.then1: + %7 = inttoptr i64 %"front2##0" to i64* + %8 = load i64, i64* %7 + %9 = add i64 %"front2##0", 8 + %10 = inttoptr i64 %9 to i64* + %11 = load i64, i64* %10 + %12 = inttoptr i64 %"front2##0" to i64* + store i64 %2, i64* %12 + %13 = inttoptr i64 %"front1##0" to i64* + store i64 %8, i64* %13 + %14 = add i64 %"front2##0", 8 + %15 = inttoptr i64 %14 to i64* + store i64 %"front2##0", i64* %"result1#ref##0" + %16 = add i64 %"front1##0", 8 + %17 = inttoptr i64 %16 to i64* + store i64 %"front1##0", i64* %"result2#ref##0" + musttail call fastcc void @"tcmc_multiple_outputs.appendtwice<0>[d4b0b4930c]"(i64 %5, i64 %"back1##0", i64* %15, i64 %11, i64 %"back2##0", i64* %17) + ret void +if.else1: + store i64 %"back2##0", i64* %"result2#ref##0" + %18 = add i64 %"front1##0", 8 + %19 = inttoptr i64 %18 to i64* + store i64 %"front1##0", i64* %"result1#ref##0" + %20 = alloca i64 + call fastcc void @"tcmc_multiple_outputs.appendtwice<0>[d4b0b4930c]"(i64 %5, i64 %"back1##0", i64* %19, i64 0, i64 0, i64* %20) + ret void +if.then2: + %22 = add i64 %"front2##0", 8 + %23 = inttoptr i64 %22 to i64* + %24 = load i64, i64* %23 + store i64 %"back1##0", i64* %"result1#ref##0" + %25 = add i64 %"front2##0", 8 + %26 = inttoptr i64 %25 to i64* + store i64 %"front2##0", i64* %"result2#ref##0" + %27 = alloca i64 + call fastcc void @"tcmc_multiple_outputs.appendtwice<0>[d4b0b4930c]"(i64 0, i64 0, i64* %27, i64 %24, i64 %"back2##0", i64* %26) + ret void +if.else2: + store i64 %"back1##0", i64* %"result1#ref##0" + store i64 %"back2##0", i64* %"result2#ref##0" + ret void +} + + +define external fastcc void @"tcmc_multiple_outputs.appendtwice<0>[3869c8b78e]"(i64 %"front1##0", i64 %"back1##0", i64* %"result1#ref##0", i64 %"front2##0", i64 %"back2##0", i64* %"result2#ref##0") { +entry: + %0 = icmp ne i64 %"front1##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = inttoptr i64 %"front1##0" to i64* + %2 = load i64, i64* %1 + %3 = add i64 %"front1##0", 8 + %4 = inttoptr i64 %3 to i64* + %5 = load i64, i64* %4 + %6 = icmp ne i64 %"front2##0", 0 + br i1 %6, label %if.then1, label %if.else1 +if.else: + %28 = icmp ne i64 %"front2##0", 0 + br i1 %28, label %if.then2, label %if.else2 +if.then1: + %7 = inttoptr i64 %"front2##0" to i64* + %8 = load i64, i64* %7 + %9 = add i64 %"front2##0", 8 + %10 = inttoptr i64 %9 to i64* + %11 = load i64, i64* %10 + %12 = inttoptr i64 %"front2##0" to i64* + store i64 %2, i64* %12 + %13 = trunc i64 16 to i32 + %14 = tail call ccc i8* @wybe_malloc(i32 %13) + %15 = ptrtoint i8* %14 to i64 + %16 = inttoptr i64 %15 to i64* + store i64 %8, i64* %16 + %17 = add i64 %"front2##0", 8 + %18 = inttoptr i64 %17 to i64* + store i64 %"front2##0", i64* %"result1#ref##0" + %19 = add i64 %15, 8 + %20 = inttoptr i64 %19 to i64* + store i64 %15, i64* %"result2#ref##0" + musttail call fastcc void @"tcmc_multiple_outputs.appendtwice<0>[3869c8b78e]"(i64 %5, i64 %"back1##0", i64* %18, i64 %11, i64 %"back2##0", i64* %20) + ret void +if.else1: + %21 = trunc i64 16 to i32 + %22 = tail call ccc i8* @wybe_malloc(i32 %21) + %23 = ptrtoint i8* %22 to i64 + %24 = inttoptr i64 %23 to i64* + store i64 %2, i64* %24 + store i64 %"back2##0", i64* %"result2#ref##0" + %25 = add i64 %23, 8 + %26 = inttoptr i64 %25 to i64* + store i64 %23, i64* %"result1#ref##0" + %27 = alloca i64 + call fastcc void @"tcmc_multiple_outputs.appendtwice<0>[3869c8b78e]"(i64 %5, i64 %"back1##0", i64* %26, i64 0, i64 0, i64* %27) + ret void +if.then2: + %29 = add i64 %"front2##0", 8 + %30 = inttoptr i64 %29 to i64* + %31 = load i64, i64* %30 + store i64 %"back1##0", i64* %"result1#ref##0" + %32 = add i64 %"front2##0", 8 + %33 = inttoptr i64 %32 to i64* + store i64 %"front2##0", i64* %"result2#ref##0" + %34 = alloca i64 + call fastcc void @"tcmc_multiple_outputs.appendtwice<0>[d4b0b4930c]"(i64 0, i64 0, i64* %34, i64 %31, i64 %"back2##0", i64* %33) + ret void +if.else2: + store i64 %"back1##0", i64* %"result1#ref##0" + store i64 %"back2##0", i64* %"result2#ref##0" + ret void +} + + +define external fastcc void @"tcmc_multiple_outputs.gen#1<0>"(i64 %"#env##0", i64 %"x##0") { +entry: + tail call ccc void @print_int(i64 %"x##0") + ret void +} diff --git a/test-cases/final-dump/tcmc_multiple_outputs.wybe b/test-cases/final-dump/tcmc_multiple_outputs.wybe new file mode 100644 index 00000000..44dea437 --- /dev/null +++ b/test-cases/final-dump/tcmc_multiple_outputs.wybe @@ -0,0 +1,28 @@ +def appendtwice(front1: list(T), back1: list(T), ?result1: list(T), front2: list(T), back2: list(T), ?result2: list(T)) { + if { [?h1 | ?t1] = front1 :: + if { [?h2 | ?t2] = front2 :: + # this should still be eligible for the optimisation, even though we + # are constructing two separate lists + appendtwice(t1, back1, ?tail1, t2, back2, ?tail2) + ?result1 = [h1 | tail1] + ?result2 = [h2 | tail2] + | else :: + appendtwice(t1, back1, ?tail1, [], [], _) + ?result1 = [h1 | tail1] + ?result2 = back2 + } + | else :: + if { [?h2 | ?t2] = front2 :: + appendtwice([], [], _, t2, back2, ?tail2) + ?result1 = back1 + ?result2 = [h2 | tail2] + | else :: + ?result1 = back1 + ?result2 = back2 + } + } +} + +appendtwice([1,2,3], [4,5,6], ?result1, [7,8], [9, 10, 11], ?result2) +!println(print, result1) +!println(print, result2) diff --git a/test-cases/final-dump/tcmc_mutate_struct_directly.exp b/test-cases/final-dump/tcmc_mutate_struct_directly.exp new file mode 100644 index 00000000..35ca7c8e --- /dev/null +++ b/test-cases/final-dump/tcmc_mutate_struct_directly.exp @@ -0,0 +1,404 @@ +====================================================================== +AFTER EVERYTHING: + Module tcmc_mutate_struct_directly + representation : (not a type) + public submods : + public resources: + public procs : tcmc_mutate_struct_directly.<0> + tcmc_mutate_struct_directly.appendstuff<0> + imports : use tcmc_mutate_struct_directly.combined + use wybe + resources : + submodules : tcmc_mutate_struct_directly.combined + procs : + +module top-level code > public {impure} (0 calls) +0: tcmc_mutate_struct_directly.<0> +()<{<>}; {<>}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign lpvm alloc(16:wybe.int, ?tmp#15##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#15##0:wybe.list(T), ?tmp#16##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 3:T) @list:nn:nn + foreign lpvm mutate(~tmp#16##0:wybe.list(T), ?tmp#2##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#19##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#19##0:wybe.list(T), ?tmp#20##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 2:T) @list:nn:nn + foreign lpvm mutate(~tmp#20##0:wybe.list(T), ?tmp#1##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#2##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#23##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#23##0:wybe.list(T), ?tmp#24##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 1:T) @list:nn:nn + foreign lpvm mutate(~tmp#24##0:wybe.list(T), ?tmp#0##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#1##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#27##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#27##0:wybe.list(T), ?tmp#28##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 6:T) @list:nn:nn + foreign lpvm mutate(~tmp#28##0:wybe.list(T), ?tmp#6##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#31##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#31##0:wybe.list(T), ?tmp#32##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 5:T) @list:nn:nn + foreign lpvm mutate(~tmp#32##0:wybe.list(T), ?tmp#5##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#6##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#35##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#35##0:wybe.list(T), ?tmp#36##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 4:T) @list:nn:nn + foreign lpvm mutate(~tmp#36##0:wybe.list(T), ?tmp#4##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#5##0:wybe.list(T)) @list:nn:nn + tcmc_mutate_struct_directly.appendstuff<0>(~tmp#0##0:wybe.list(wybe.int), ~tmp#4##0:wybe.list(wybe.int), ?l2##0:tcmc_mutate_struct_directly.combined(wybe.int)) #8 @tcmc_mutate_struct_directly:nn:nn + foreign lpvm access(l2##0:tcmc_mutate_struct_directly.combined(T), 0:wybe.int, 24:wybe.int, 0:wybe.int, ?tmp#8##0:wybe.int) @tcmc_mutate_struct_directly:nn:nn + foreign lpvm load(<>:wybe.phantom, ?%tmp#39##0:wybe.phantom) @int:nn:nn + foreign c print_int(~tmp#8##0:wybe.int, ~tmp#39##0:wybe.phantom, ?tmp#40##0:wybe.phantom) @int:nn:nn + foreign c putchar('\n':wybe.char, ~tmp#40##0:wybe.phantom, ?tmp#41##0:wybe.phantom) @io:nn:nn + foreign lpvm store(~%tmp#41##0:wybe.phantom, <>:wybe.phantom) @io:nn:nn + foreign lpvm access(l2##0:tcmc_mutate_struct_directly.combined(T), 8:wybe.int, 24:wybe.int, 0:wybe.int, ?tmp#10##0:wybe.list(wybe.int)) @tcmc_mutate_struct_directly:nn:nn + wybe.list.print<0>(tcmc_mutate_struct_directly.gen#1<0><>:{resource}(T), ~tmp#10##0:wybe.list(T)) #15 @list:nn:nn + foreign lpvm load(<>:wybe.phantom, ?%tmp#45##0:wybe.phantom) @io:nn:nn + foreign c putchar('\n':wybe.char, ~tmp#45##0:wybe.phantom, ?tmp#46##0:wybe.phantom) @io:nn:nn + foreign lpvm store(~%tmp#46##0:wybe.phantom, <>:wybe.phantom) @io:nn:nn + foreign lpvm access(~l2##0:tcmc_mutate_struct_directly.combined(T), 16:wybe.int, 24:wybe.int, 0:wybe.int, ?tmp#12##0:wybe.list(wybe.int)) @tcmc_mutate_struct_directly:nn:nn + wybe.list.print<0>(tcmc_mutate_struct_directly.gen#1<0><>:{resource}(T), ~tmp#12##0:wybe.list(T)) #16 @list:nn:nn + foreign lpvm load(<>:wybe.phantom, ?%tmp#50##0:wybe.phantom) @io:nn:nn + foreign c putchar('\n':wybe.char, ~tmp#50##0:wybe.phantom, ?tmp#51##0:wybe.phantom) @io:nn:nn + foreign lpvm store(~%tmp#51##0:wybe.phantom, <>:wybe.phantom) @io:nn:nn + + +appendstuff > public (1 calls) +0: tcmc_mutate_struct_directly.appendstuff<0> +appendstuff(l##0:wybe.list(wybe.int), l2##0:wybe.list(wybe.int), ?result##0:tcmc_mutate_struct_directly.combined(wybe.int))<{}; {}>: + AliasPairs: [(l##0,l2##0),(l##0,result##0),(l2##0,result##0)] + InterestingCallProperties: [] + wybe.list.length1<0>(l##0:wybe.list(T), 0:wybe.int, ?tmp#3##0:wybe.int) #6 @list:nn:nn + wybe.list.length1<0>(l2##0:wybe.list(T), 0:wybe.int, ?tmp#4##0:wybe.int) #7 @list:nn:nn + foreign llvm add(~tmp#3##0:wybe.int, ~tmp#4##0:wybe.int, ?tmp#2##0:wybe.int) @int:nn:nn + foreign lpvm alloc(24:wybe.int, ?tmp#13##0:tcmc_mutate_struct_directly.combined(T)) @tcmc_mutate_struct_directly:nn:nn + foreign lpvm mutate(~tmp#13##0:tcmc_mutate_struct_directly.combined(T), ?tmp#14##0:tcmc_mutate_struct_directly.combined(T), 0:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, ~tmp#2##0:T) @tcmc_mutate_struct_directly:nn:nn + wybe.list.,,<0>(l2##0:wybe.list(wybe.int), l##0:wybe.list(wybe.int), outByReference tmp#1##0:wybe.list(wybe.int)) #1 @tcmc_mutate_struct_directly:nn:nn + foreign lpvm mutate(~tmp#14##0:tcmc_mutate_struct_directly.combined(T), ?tmp#15##0:tcmc_mutate_struct_directly.combined(T), 16:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, ~takeReference tmp#1##0:wybe.list(T)) @tcmc_mutate_struct_directly:nn:nn + wybe.list.,,<0>(~l##0:wybe.list(wybe.int), ~l2##0:wybe.list(wybe.int), outByReference tmp#0##0:wybe.list(wybe.int)) #0 @tcmc_mutate_struct_directly:nn:nn + foreign lpvm mutate(~tmp#15##0:tcmc_mutate_struct_directly.combined(T), ?result##0:tcmc_mutate_struct_directly.combined(T), 8:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, ~takeReference tmp#0##0:wybe.list(T)) @tcmc_mutate_struct_directly:nn:nn + + +gen#1 > {inline} (2 calls) +0: tcmc_mutate_struct_directly.gen#1<0> +gen#1(x##0:wybe.int)<{<>}; {<>}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign lpvm load(<>:wybe.phantom, ?%tmp#1##0:wybe.phantom) @int:nn:nn + foreign c print_int(~x##0:wybe.int, ~tmp#1##0:wybe.phantom, ?tmp#2##0:wybe.phantom) @int:nn:nn + foreign lpvm store(~%tmp#2##0:wybe.phantom, <>:wybe.phantom) @int:nn:nn + + LLVM code : + +; ModuleID = 'tcmc_mutate_struct_directly' + + + + + +@tcmc_mutate_struct_directly.0 = constant [1 x i64] [i64 ptrtoint (void (i64, i64)* @"tcmc_mutate_struct_directly.gen#1<0>" to i64)] + + +declare external ccc void @print_int(i64) + + +declare external fastcc void @"wybe.list.,,<0>"(i64, i64, i64*) + + +declare external fastcc i64 @"wybe.list.length1<0>"(i64, i64) + + +declare external ccc void @putchar(i8) + + +declare external fastcc void @"wybe.list.print<0>"(i64, i64) + + +declare external ccc i8* @wybe_malloc(i32) + + +declare external ccc void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1) + + +define external fastcc void @"tcmc_mutate_struct_directly.<0>"() { +entry: + %0 = trunc i64 16 to i32 + %1 = tail call ccc i8* @wybe_malloc(i32 %0) + %2 = ptrtoint i8* %1 to i64 + %3 = inttoptr i64 %2 to i64* + store i64 3, i64* %3 + %4 = add i64 %2, 8 + %5 = inttoptr i64 %4 to i64* + store i64 0, i64* %5 + %6 = trunc i64 16 to i32 + %7 = tail call ccc i8* @wybe_malloc(i32 %6) + %8 = ptrtoint i8* %7 to i64 + %9 = inttoptr i64 %8 to i64* + store i64 2, i64* %9 + %10 = add i64 %8, 8 + %11 = inttoptr i64 %10 to i64* + store i64 %2, i64* %11 + %12 = trunc i64 16 to i32 + %13 = tail call ccc i8* @wybe_malloc(i32 %12) + %14 = ptrtoint i8* %13 to i64 + %15 = inttoptr i64 %14 to i64* + store i64 1, i64* %15 + %16 = add i64 %14, 8 + %17 = inttoptr i64 %16 to i64* + store i64 %8, i64* %17 + %18 = trunc i64 16 to i32 + %19 = tail call ccc i8* @wybe_malloc(i32 %18) + %20 = ptrtoint i8* %19 to i64 + %21 = inttoptr i64 %20 to i64* + store i64 6, i64* %21 + %22 = add i64 %20, 8 + %23 = inttoptr i64 %22 to i64* + store i64 0, i64* %23 + %24 = trunc i64 16 to i32 + %25 = tail call ccc i8* @wybe_malloc(i32 %24) + %26 = ptrtoint i8* %25 to i64 + %27 = inttoptr i64 %26 to i64* + store i64 5, i64* %27 + %28 = add i64 %26, 8 + %29 = inttoptr i64 %28 to i64* + store i64 %20, i64* %29 + %30 = trunc i64 16 to i32 + %31 = tail call ccc i8* @wybe_malloc(i32 %30) + %32 = ptrtoint i8* %31 to i64 + %33 = inttoptr i64 %32 to i64* + store i64 4, i64* %33 + %34 = add i64 %32, 8 + %35 = inttoptr i64 %34 to i64* + store i64 %26, i64* %35 + %36 = tail call fastcc i64 @"tcmc_mutate_struct_directly.appendstuff<0>"(i64 %14, i64 %32) + %37 = inttoptr i64 %36 to i64* + %38 = load i64, i64* %37 + tail call ccc void @print_int(i64 %38) + tail call ccc void @putchar(i8 10) + %39 = add i64 %36, 8 + %40 = inttoptr i64 %39 to i64* + %41 = load i64, i64* %40 + tail call fastcc void @"wybe.list.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ([1 x i64], [1 x i64]* @tcmc_mutate_struct_directly.0, i32 0, i32 0) to i64), i64 %41) + tail call ccc void @putchar(i8 10) + %42 = add i64 %36, 16 + %43 = inttoptr i64 %42 to i64* + %44 = load i64, i64* %43 + tail call fastcc void @"wybe.list.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ([1 x i64], [1 x i64]* @tcmc_mutate_struct_directly.0, i32 0, i32 0) to i64), i64 %44) + tail call ccc void @putchar(i8 10) + ret void +} + + +define external fastcc i64 @"tcmc_mutate_struct_directly.appendstuff<0>"(i64 %"l##0", i64 %"l2##0") { +entry: + %0 = tail call fastcc i64 @"wybe.list.length1<0>"(i64 %"l##0", i64 0) + %1 = tail call fastcc i64 @"wybe.list.length1<0>"(i64 %"l2##0", i64 0) + %2 = add i64 %0, %1 + %3 = trunc i64 24 to i32 + %4 = tail call ccc i8* @wybe_malloc(i32 %3) + %5 = ptrtoint i8* %4 to i64 + %6 = inttoptr i64 %5 to i64* + store i64 %2, i64* %6 + %7 = add i64 %5, 16 + %8 = inttoptr i64 %7 to i64* + tail call fastcc void @"wybe.list.,,<0>"(i64 %"l2##0", i64 %"l##0", i64* %8) + %9 = load i64, i64* %8 + %10 = add i64 %5, 8 + %11 = inttoptr i64 %10 to i64* + tail call fastcc void @"wybe.list.,,<0>"(i64 %"l##0", i64 %"l2##0", i64* %11) + ret i64 %5 +} + + +define external fastcc void @"tcmc_mutate_struct_directly.gen#1<0>"(i64 %"#env##0", i64 %"x##0") { +entry: + tail call ccc void @print_int(i64 %"x##0") + ret void +} +-------------------------------------------------- + Module tcmc_mutate_struct_directly.combined(T) + representation : address + public submods : + public resources: + public procs : tcmc_mutate_struct_directly.combined.combined<0> + tcmc_mutate_struct_directly.combined.combined<1> + tcmc_mutate_struct_directly.combined.x<0> + tcmc_mutate_struct_directly.combined.x<1> + tcmc_mutate_struct_directly.combined.y<0> + tcmc_mutate_struct_directly.combined.y<1> + tcmc_mutate_struct_directly.combined.z<0> + tcmc_mutate_struct_directly.combined.z<1> + imports : use tcmc_mutate_struct_directly + use wybe + resources : + procs : + +combined > public {inline} (0 calls) +0: tcmc_mutate_struct_directly.combined.combined<0> +combined(x##0:T, y##0:wybe.list(T), z##0:wybe.list(T), ?#result##0:tcmc_mutate_struct_directly.combined(T))<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign lpvm alloc(24:wybe.int, ?#rec##0:tcmc_mutate_struct_directly.combined(T)) @tcmc_mutate_struct_directly:nn:nn + foreign lpvm mutate(~#rec##0:tcmc_mutate_struct_directly.combined(T), ?#rec##1:tcmc_mutate_struct_directly.combined(T), 0:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, ~x##0:T) @tcmc_mutate_struct_directly:nn:nn + foreign lpvm mutate(~#rec##1:tcmc_mutate_struct_directly.combined(T), ?#rec##2:tcmc_mutate_struct_directly.combined(T), 8:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, ~y##0:wybe.list(T)) @tcmc_mutate_struct_directly:nn:nn + foreign lpvm mutate(~#rec##2:tcmc_mutate_struct_directly.combined(T), ?#result##0:tcmc_mutate_struct_directly.combined(T), 16:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, ~z##0:wybe.list(T)) @tcmc_mutate_struct_directly:nn:nn +combined > public {inline} (0 calls) +1: tcmc_mutate_struct_directly.combined.combined<1> +combined(?x##0:T, ?y##0:wybe.list(T), ?z##0:wybe.list(T), #result##0:tcmc_mutate_struct_directly.combined(T))<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign lpvm access(#result##0:tcmc_mutate_struct_directly.combined(T), 0:wybe.int, 24:wybe.int, 0:wybe.int, ?x##0:T) @tcmc_mutate_struct_directly:nn:nn + foreign lpvm access(#result##0:tcmc_mutate_struct_directly.combined(T), 8:wybe.int, 24:wybe.int, 0:wybe.int, ?y##0:wybe.list(T)) @tcmc_mutate_struct_directly:nn:nn + foreign lpvm access(~#result##0:tcmc_mutate_struct_directly.combined(T), 16:wybe.int, 24:wybe.int, 0:wybe.int, ?z##0:wybe.list(T)) @tcmc_mutate_struct_directly:nn:nn + + +x > public {inline} (0 calls) +0: tcmc_mutate_struct_directly.combined.x<0> +x(#rec##0:tcmc_mutate_struct_directly.combined(T), ?#result##0:T)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign lpvm access(~#rec##0:tcmc_mutate_struct_directly.combined(T), 0:wybe.int, 24:wybe.int, 0:wybe.int, ?#result##0:T) @tcmc_mutate_struct_directly:nn:nn +x > public {inline} (0 calls) +1: tcmc_mutate_struct_directly.combined.x<1> +x(#rec##0:tcmc_mutate_struct_directly.combined(T), ?#rec##1:tcmc_mutate_struct_directly.combined(T), #field##0:T)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign lpvm mutate(~#rec##0:tcmc_mutate_struct_directly.combined(T), ?#rec##1:tcmc_mutate_struct_directly.combined(T), 0:wybe.int, 0:wybe.int, 24:wybe.int, 0:wybe.int, ~#field##0:T) @tcmc_mutate_struct_directly:nn:nn + + +y > public {inline} (0 calls) +0: tcmc_mutate_struct_directly.combined.y<0> +y(#rec##0:tcmc_mutate_struct_directly.combined(T), ?#result##0:wybe.list(T))<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign lpvm access(~#rec##0:tcmc_mutate_struct_directly.combined(T), 8:wybe.int, 24:wybe.int, 0:wybe.int, ?#result##0:wybe.list(T)) @tcmc_mutate_struct_directly:nn:nn +y > public {inline} (0 calls) +1: tcmc_mutate_struct_directly.combined.y<1> +y(#rec##0:tcmc_mutate_struct_directly.combined(T), ?#rec##1:tcmc_mutate_struct_directly.combined(T), #field##0:wybe.list(T))<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign lpvm mutate(~#rec##0:tcmc_mutate_struct_directly.combined(T), ?#rec##1:tcmc_mutate_struct_directly.combined(T), 8:wybe.int, 0:wybe.int, 24:wybe.int, 0:wybe.int, ~#field##0:wybe.list(T)) @tcmc_mutate_struct_directly:nn:nn + + +z > public {inline} (0 calls) +0: tcmc_mutate_struct_directly.combined.z<0> +z(#rec##0:tcmc_mutate_struct_directly.combined(T), ?#result##0:wybe.list(T))<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign lpvm access(~#rec##0:tcmc_mutate_struct_directly.combined(T), 16:wybe.int, 24:wybe.int, 0:wybe.int, ?#result##0:wybe.list(T)) @tcmc_mutate_struct_directly:nn:nn +z > public {inline} (0 calls) +1: tcmc_mutate_struct_directly.combined.z<1> +z(#rec##0:tcmc_mutate_struct_directly.combined(T), ?#rec##1:tcmc_mutate_struct_directly.combined(T), #field##0:wybe.list(T))<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign lpvm mutate(~#rec##0:tcmc_mutate_struct_directly.combined(T), ?#rec##1:tcmc_mutate_struct_directly.combined(T), 16:wybe.int, 0:wybe.int, 24:wybe.int, 0:wybe.int, ~#field##0:wybe.list(T)) @tcmc_mutate_struct_directly:nn:nn + + LLVM code : + +; ModuleID = 'tcmc_mutate_struct_directly.combined' + + + + + +declare external ccc i8* @wybe_malloc(i32) + + +declare external ccc void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1) + + +define external fastcc i64 @"tcmc_mutate_struct_directly.combined.combined<0>"(i64 %"x##0", i64 %"y##0", i64 %"z##0") { +entry: + %0 = trunc i64 24 to i32 + %1 = tail call ccc i8* @wybe_malloc(i32 %0) + %2 = ptrtoint i8* %1 to i64 + %3 = inttoptr i64 %2 to i64* + store i64 %"x##0", i64* %3 + %4 = add i64 %2, 8 + %5 = inttoptr i64 %4 to i64* + store i64 %"y##0", i64* %5 + %6 = add i64 %2, 16 + %7 = inttoptr i64 %6 to i64* + store i64 %"z##0", i64* %7 + ret i64 %2 +} + + +define external fastcc {i64, i64, i64} @"tcmc_mutate_struct_directly.combined.combined<1>"(i64 %"#result##0") { +entry: + %0 = inttoptr i64 %"#result##0" to i64* + %1 = load i64, i64* %0 + %2 = add i64 %"#result##0", 8 + %3 = inttoptr i64 %2 to i64* + %4 = load i64, i64* %3 + %5 = add i64 %"#result##0", 16 + %6 = inttoptr i64 %5 to i64* + %7 = load i64, i64* %6 + %8 = insertvalue {i64, i64, i64} undef, i64 %1, 0 + %9 = insertvalue {i64, i64, i64} %8, i64 %4, 1 + %10 = insertvalue {i64, i64, i64} %9, i64 %7, 2 + ret {i64, i64, i64} %10 +} + + +define external fastcc i64 @"tcmc_mutate_struct_directly.combined.x<0>"(i64 %"#rec##0") { +entry: + %0 = inttoptr i64 %"#rec##0" to i64* + %1 = load i64, i64* %0 + ret i64 %1 +} + + +define external fastcc i64 @"tcmc_mutate_struct_directly.combined.x<1>"(i64 %"#rec##0", i64 %"#field##0") { +entry: + %0 = trunc i64 24 to i32 + %1 = tail call ccc i8* @wybe_malloc(i32 %0) + %2 = ptrtoint i8* %1 to i64 + %3 = inttoptr i64 %2 to i8* + %4 = inttoptr i64 %"#rec##0" to i8* + %5 = trunc i64 24 to i32 + tail call ccc void @llvm.memcpy.p0i8.p0i8.i32(i8* %3, i8* %4, i32 %5, i1 0) + %6 = inttoptr i64 %2 to i64* + store i64 %"#field##0", i64* %6 + ret i64 %2 +} + + +define external fastcc i64 @"tcmc_mutate_struct_directly.combined.y<0>"(i64 %"#rec##0") { +entry: + %0 = add i64 %"#rec##0", 8 + %1 = inttoptr i64 %0 to i64* + %2 = load i64, i64* %1 + ret i64 %2 +} + + +define external fastcc i64 @"tcmc_mutate_struct_directly.combined.y<1>"(i64 %"#rec##0", i64 %"#field##0") { +entry: + %0 = trunc i64 24 to i32 + %1 = tail call ccc i8* @wybe_malloc(i32 %0) + %2 = ptrtoint i8* %1 to i64 + %3 = inttoptr i64 %2 to i8* + %4 = inttoptr i64 %"#rec##0" to i8* + %5 = trunc i64 24 to i32 + tail call ccc void @llvm.memcpy.p0i8.p0i8.i32(i8* %3, i8* %4, i32 %5, i1 0) + %6 = add i64 %2, 8 + %7 = inttoptr i64 %6 to i64* + store i64 %"#field##0", i64* %7 + ret i64 %2 +} + + +define external fastcc i64 @"tcmc_mutate_struct_directly.combined.z<0>"(i64 %"#rec##0") { +entry: + %0 = add i64 %"#rec##0", 16 + %1 = inttoptr i64 %0 to i64* + %2 = load i64, i64* %1 + ret i64 %2 +} + + +define external fastcc i64 @"tcmc_mutate_struct_directly.combined.z<1>"(i64 %"#rec##0", i64 %"#field##0") { +entry: + %0 = trunc i64 24 to i32 + %1 = tail call ccc i8* @wybe_malloc(i32 %0) + %2 = ptrtoint i8* %1 to i64 + %3 = inttoptr i64 %2 to i8* + %4 = inttoptr i64 %"#rec##0" to i8* + %5 = trunc i64 24 to i32 + tail call ccc void @llvm.memcpy.p0i8.p0i8.i32(i8* %3, i8* %4, i32 %5, i1 0) + %6 = add i64 %2, 16 + %7 = inttoptr i64 %6 to i64* + store i64 %"#field##0", i64* %7 + ret i64 %2 +} diff --git a/test-cases/final-dump/tcmc_mutate_struct_directly.wybe b/test-cases/final-dump/tcmc_mutate_struct_directly.wybe new file mode 100644 index 00000000..ec320da0 --- /dev/null +++ b/test-cases/final-dump/tcmc_mutate_struct_directly.wybe @@ -0,0 +1,17 @@ +type combined(T) { + pub combined(x: T, y: list(T), z: list(T)) +} + +# we expect that after optimization, the appends should write +# *directly* into the combined structure +pub def appendstuff(l: list(int), l2: list(int), ?result: combined(int)) { + ?l3 = l ,, l2 + ?l4 = l2 ,, l + ?len = length(l) + length(l2) + ?result = combined(len, l3, l4) +} + +appendstuff([1,2,3], [4,5,6], ?l2) +!println(combined.x(l2)) +!println(print, combined.y(l2)) +!println(print, combined.z(l2)) \ No newline at end of file diff --git a/test-cases/final-dump/tcmc_mutates_in_wrong_order.exp b/test-cases/final-dump/tcmc_mutates_in_wrong_order.exp new file mode 100644 index 00000000..3a73f2a8 --- /dev/null +++ b/test-cases/final-dump/tcmc_mutates_in_wrong_order.exp @@ -0,0 +1,509 @@ +====================================================================== +AFTER EVERYTHING: + Module tcmc_mutates_in_wrong_order + representation : address + public submods : + public resources: + public procs : tcmc_mutates_in_wrong_order.<0> + tcmc_mutates_in_wrong_order.=<0> + tcmc_mutates_in_wrong_order.snoc<0> + tcmc_mutates_in_wrong_order.snoc<1> + tcmc_mutates_in_wrong_order.~=<0> + imports : use wybe + resources : + procs : + +module top-level code > public {impure} (0 calls) +0: tcmc_mutates_in_wrong_order.<0> +()<{<>}; {<>}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign lpvm alloc(16:wybe.int, ?tmp#6##0:tcmc_mutates_in_wrong_order) @tcmc_mutates_in_wrong_order:nn:nn + foreign lpvm mutate(~tmp#6##0:tcmc_mutates_in_wrong_order, ?tmp#7##0:tcmc_mutates_in_wrong_order, 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 0:tcmc_mutates_in_wrong_order) @tcmc_mutates_in_wrong_order:nn:nn + foreign lpvm mutate(~tmp#7##0:tcmc_mutates_in_wrong_order, ?tmp#0##0:tcmc_mutates_in_wrong_order, 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 1:wybe.int) @tcmc_mutates_in_wrong_order:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#10##0:tcmc_mutates_in_wrong_order) @tcmc_mutates_in_wrong_order:nn:nn + foreign lpvm mutate(~tmp#10##0:tcmc_mutates_in_wrong_order, ?tmp#11##0:tcmc_mutates_in_wrong_order, 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 0:tcmc_mutates_in_wrong_order) @tcmc_mutates_in_wrong_order:nn:nn + foreign lpvm mutate(~tmp#11##0:tcmc_mutates_in_wrong_order, ?tmp#2##0:tcmc_mutates_in_wrong_order, 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 2:wybe.int) @tcmc_mutates_in_wrong_order:nn:nn + tcmc_mutates_in_wrong_order.append<0>(~tmp#0##0:tcmc_mutates_in_wrong_order, tmp#2##0:tcmc_mutates_in_wrong_order, outByReference x3##0:tcmc_mutates_in_wrong_order) #4 @tcmc_mutates_in_wrong_order:nn:nn + tcmc_mutates_in_wrong_order.print_list<0>(~tmp#2##0:tcmc_mutates_in_wrong_order)<{<>}; {<>}> #5 @tcmc_mutates_in_wrong_order:nn:nn + foreign lpvm load(<>:wybe.phantom, ?%tmp#12##0:wybe.phantom) @io:nn:nn + foreign c putchar('\n':wybe.char, ~tmp#12##0:wybe.phantom, ?tmp#13##0:wybe.phantom) @io:nn:nn + foreign lpvm store(~%tmp#13##0:wybe.phantom, <>:wybe.phantom) @io:nn:nn + tcmc_mutates_in_wrong_order.print_list<0>(~x3##0:tcmc_mutates_in_wrong_order)<{<>}; {<>}> #7 @tcmc_mutates_in_wrong_order:nn:nn + foreign lpvm load(<>:wybe.phantom, ?%tmp#14##0:wybe.phantom) @io:nn:nn + foreign c putchar('\n':wybe.char, ~tmp#14##0:wybe.phantom, ?tmp#15##0:wybe.phantom) @io:nn:nn + foreign lpvm store(~%tmp#15##0:wybe.phantom, <>:wybe.phantom) @io:nn:nn + + += > public (4 calls) +0: tcmc_mutates_in_wrong_order.=<0> +=(#left##0:tcmc_mutates_in_wrong_order, #right##0:tcmc_mutates_in_wrong_order, ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_ne(#left##0:wybe.int, 0:wybe.int, ?tmp#0##0:wybe.bool) + case ~tmp#0##0:wybe.bool of + 0: + foreign llvm icmp_eq(~#left##0:tcmc_mutates_in_wrong_order, ~#right##0:tcmc_mutates_in_wrong_order, ?#success##0:wybe.bool) + + 1: + foreign lpvm access(#left##0:tcmc_mutates_in_wrong_order, 0:wybe.int, 16:wybe.int, 0:wybe.int, ?#left#tail##0:tcmc_mutates_in_wrong_order) @tcmc_mutates_in_wrong_order:nn:nn + foreign lpvm access(~#left##0:tcmc_mutates_in_wrong_order, 8:wybe.int, 16:wybe.int, 0:wybe.int, ?#left#head##0:wybe.int) @tcmc_mutates_in_wrong_order:nn:nn + foreign llvm icmp_ne(#right##0:wybe.int, 0:wybe.int, ?tmp#9##0:wybe.bool) + case ~tmp#9##0:wybe.bool of + 0: + foreign llvm move(0:wybe.bool, ?#success##0:wybe.bool) + + 1: + foreign lpvm access(#right##0:tcmc_mutates_in_wrong_order, 0:wybe.int, 16:wybe.int, 0:wybe.int, ?#right#tail##0:tcmc_mutates_in_wrong_order) @tcmc_mutates_in_wrong_order:nn:nn + foreign lpvm access(~#right##0:tcmc_mutates_in_wrong_order, 8:wybe.int, 16:wybe.int, 0:wybe.int, ?#right#head##0:wybe.int) @tcmc_mutates_in_wrong_order:nn:nn + tcmc_mutates_in_wrong_order.=<0>(~#left#tail##0:tcmc_mutates_in_wrong_order, ~#right#tail##0:tcmc_mutates_in_wrong_order, ?tmp#4##0:wybe.bool) #2 + case ~tmp#4##0:wybe.bool of + 0: + foreign llvm move(0:wybe.bool, ?#success##0:wybe.bool) + + 1: + foreign llvm icmp_eq(~#left#head##0:wybe.int, ~#right#head##0:wybe.int, ?#success##0:wybe.bool) @int:nn:nn + + + + + +append > (2 calls) +0: tcmc_mutates_in_wrong_order.append<0> +append(a##0:tcmc_mutates_in_wrong_order, b##0:tcmc_mutates_in_wrong_order, outByReference result##0:tcmc_mutates_in_wrong_order)<{}; {}>: + AliasPairs: [(a##0,b##0),(a##0,result##0),(b##0,result##0)] + InterestingCallProperties: [] + foreign llvm icmp_ne(a##0:wybe.int, 0:wybe.int, ?tmp#3##0:wybe.bool) + case ~tmp#3##0:wybe.bool of + 0: + foreign llvm move(~b##0:tcmc_mutates_in_wrong_order, ?result##0:tcmc_mutates_in_wrong_order) @tcmc_mutates_in_wrong_order:nn:nn + + 1: + foreign lpvm access(a##0:tcmc_mutates_in_wrong_order, 0:wybe.int, 16:wybe.int, 0:wybe.int, ?t##0:tcmc_mutates_in_wrong_order) @tcmc_mutates_in_wrong_order:nn:nn + foreign lpvm access(~a##0:tcmc_mutates_in_wrong_order, 8:wybe.int, 16:wybe.int, 0:wybe.int, ?h##0:wybe.int) @tcmc_mutates_in_wrong_order:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#6##0:tcmc_mutates_in_wrong_order) @tcmc_mutates_in_wrong_order:nn:nn + foreign lpvm mutate(~tmp#6##0:tcmc_mutates_in_wrong_order, ?tmp#7##0:tcmc_mutates_in_wrong_order, 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~h##0:wybe.int) @tcmc_mutates_in_wrong_order:nn:nn + tcmc_mutates_in_wrong_order.append<0>(~b##0:tcmc_mutates_in_wrong_order, ~t##0:tcmc_mutates_in_wrong_order, outByReference t2##0:tcmc_mutates_in_wrong_order) #1 @tcmc_mutates_in_wrong_order:nn:nn + foreign lpvm mutate(~tmp#7##0:tcmc_mutates_in_wrong_order, ?result##0:tcmc_mutates_in_wrong_order, 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference t2##0:tcmc_mutates_in_wrong_order) @tcmc_mutates_in_wrong_order:nn:nn + + + +head > {inline} (0 calls) +0: tcmc_mutates_in_wrong_order.head<0> +head(#rec##0:tcmc_mutates_in_wrong_order, ?#result##0:wybe.int, ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_ne(#rec##0:wybe.int, 0:wybe.int, ?tmp#0##0:wybe.bool) + case ~tmp#0##0:wybe.bool of + 0: + foreign llvm move(0:wybe.bool, ?#success##0:wybe.bool) + foreign llvm move(undef:wybe.int, ?#result##0:wybe.int) + + 1: + foreign lpvm access(~#rec##0:tcmc_mutates_in_wrong_order, 8:wybe.int, 16:wybe.int, 0:wybe.int, ?#result##0:wybe.int) @tcmc_mutates_in_wrong_order:nn:nn + foreign llvm move(1:wybe.bool, ?#success##0:wybe.bool) + +head > {inline} (0 calls) +1: tcmc_mutates_in_wrong_order.head<1> +head(#rec##0:tcmc_mutates_in_wrong_order, ?#rec##1:tcmc_mutates_in_wrong_order, #field##0:wybe.int, ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_ne(#rec##0:wybe.int, 0:wybe.int, ?tmp#0##0:wybe.bool) + case ~tmp#0##0:wybe.bool of + 0: + foreign llvm move(0:wybe.bool, ?#success##0:wybe.bool) + foreign llvm move(~#rec##0:tcmc_mutates_in_wrong_order, ?#rec##1:tcmc_mutates_in_wrong_order) + + 1: + foreign lpvm mutate(~#rec##0:tcmc_mutates_in_wrong_order, ?#rec##1:tcmc_mutates_in_wrong_order, 8:wybe.int, 0:wybe.int, 16:wybe.int, 0:wybe.int, ~#field##0:wybe.int) @tcmc_mutates_in_wrong_order:nn:nn + foreign llvm move(1:wybe.bool, ?#success##0:wybe.bool) + + + +null > {inline} (2 calls) +0: tcmc_mutates_in_wrong_order.null<0> +null(?#result##0:tcmc_mutates_in_wrong_order)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm move(0:tcmc_mutates_in_wrong_order, ?#result##0:tcmc_mutates_in_wrong_order) + + +print_list > (3 calls) +0: tcmc_mutates_in_wrong_order.print_list<0> +print_list(a##0:tcmc_mutates_in_wrong_order)<{<>}; {<>}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_ne(a##0:wybe.int, 0:wybe.int, ?tmp#2##0:wybe.bool) + case ~tmp#2##0:wybe.bool of + 0: + wybe.string.print<0>("null":wybe.string)<{<>}; {<>}> #6 @tcmc_mutates_in_wrong_order:nn:nn + + 1: + foreign lpvm access(a##0:tcmc_mutates_in_wrong_order, 0:wybe.int, 16:wybe.int, 0:wybe.int, ?tail##0:tcmc_mutates_in_wrong_order) @tcmc_mutates_in_wrong_order:nn:nn + foreign lpvm access(~a##0:tcmc_mutates_in_wrong_order, 8:wybe.int, 16:wybe.int, 0:wybe.int, ?head##0:wybe.int) @tcmc_mutates_in_wrong_order:nn:nn + wybe.string.print<0>("node(":wybe.string)<{<>}; {<>}> #1 @tcmc_mutates_in_wrong_order:nn:nn + foreign lpvm load(<>:wybe.phantom, ?%tmp#4##0:wybe.phantom) @int:nn:nn + foreign c print_int(~head##0:wybe.int, ~tmp#4##0:wybe.phantom, ?tmp#5##0:wybe.phantom) @int:nn:nn + foreign lpvm store(~%tmp#5##0:wybe.phantom, <>:wybe.phantom) @int:nn:nn + wybe.string.print<0>(",":wybe.string)<{<>}; {<>}> #3 @tcmc_mutates_in_wrong_order:nn:nn + tcmc_mutates_in_wrong_order.print_list<0>(~tail##0:tcmc_mutates_in_wrong_order)<{<>}; {<>}> #4 @tcmc_mutates_in_wrong_order:nn:nn + wybe.string.print<0>(")":wybe.string)<{<>}; {<>}> #5 @tcmc_mutates_in_wrong_order:nn:nn + + + +snoc > public {inline} (3 calls) +0: tcmc_mutates_in_wrong_order.snoc<0> +snoc(tail##0:tcmc_mutates_in_wrong_order, head##0:wybe.int, ?#result##0:tcmc_mutates_in_wrong_order)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign lpvm alloc(16:wybe.int, ?#rec##0:tcmc_mutates_in_wrong_order) @tcmc_mutates_in_wrong_order:nn:nn + foreign lpvm mutate(~#rec##0:tcmc_mutates_in_wrong_order, ?#rec##1:tcmc_mutates_in_wrong_order, 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tail##0:tcmc_mutates_in_wrong_order) @tcmc_mutates_in_wrong_order:nn:nn + foreign lpvm mutate(~#rec##1:tcmc_mutates_in_wrong_order, ?#result##0:tcmc_mutates_in_wrong_order, 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~head##0:wybe.int) @tcmc_mutates_in_wrong_order:nn:nn +snoc > public {inline} (18 calls) +1: tcmc_mutates_in_wrong_order.snoc<1> +snoc(?tail##0:tcmc_mutates_in_wrong_order, ?head##0:wybe.int, #result##0:tcmc_mutates_in_wrong_order, ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_ne(#result##0:wybe.int, 0:wybe.int, ?tmp#0##0:wybe.bool) + case ~tmp#0##0:wybe.bool of + 0: + foreign llvm move(0:wybe.bool, ?#success##0:wybe.bool) + foreign llvm move(undef:tcmc_mutates_in_wrong_order, ?tail##0:tcmc_mutates_in_wrong_order) + foreign llvm move(undef:wybe.int, ?head##0:wybe.int) + + 1: + foreign lpvm access(#result##0:tcmc_mutates_in_wrong_order, 0:wybe.int, 16:wybe.int, 0:wybe.int, ?tail##0:tcmc_mutates_in_wrong_order) @tcmc_mutates_in_wrong_order:nn:nn + foreign lpvm access(~#result##0:tcmc_mutates_in_wrong_order, 8:wybe.int, 16:wybe.int, 0:wybe.int, ?head##0:wybe.int) @tcmc_mutates_in_wrong_order:nn:nn + foreign llvm move(1:wybe.bool, ?#success##0:wybe.bool) + + + +tail > {inline} (0 calls) +0: tcmc_mutates_in_wrong_order.tail<0> +tail(#rec##0:tcmc_mutates_in_wrong_order, ?#result##0:tcmc_mutates_in_wrong_order, ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_ne(#rec##0:wybe.int, 0:wybe.int, ?tmp#0##0:wybe.bool) + case ~tmp#0##0:wybe.bool of + 0: + foreign llvm move(0:wybe.bool, ?#success##0:wybe.bool) + foreign llvm move(undef:tcmc_mutates_in_wrong_order, ?#result##0:tcmc_mutates_in_wrong_order) + + 1: + foreign lpvm access(~#rec##0:tcmc_mutates_in_wrong_order, 0:wybe.int, 16:wybe.int, 0:wybe.int, ?#result##0:tcmc_mutates_in_wrong_order) @tcmc_mutates_in_wrong_order:nn:nn + foreign llvm move(1:wybe.bool, ?#success##0:wybe.bool) + +tail > {inline} (0 calls) +1: tcmc_mutates_in_wrong_order.tail<1> +tail(#rec##0:tcmc_mutates_in_wrong_order, ?#rec##1:tcmc_mutates_in_wrong_order, #field##0:tcmc_mutates_in_wrong_order, ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_ne(#rec##0:wybe.int, 0:wybe.int, ?tmp#0##0:wybe.bool) + case ~tmp#0##0:wybe.bool of + 0: + foreign llvm move(0:wybe.bool, ?#success##0:wybe.bool) + foreign llvm move(~#rec##0:tcmc_mutates_in_wrong_order, ?#rec##1:tcmc_mutates_in_wrong_order) + + 1: + foreign lpvm {noalias} mutate(~#rec##0:tcmc_mutates_in_wrong_order, ?#rec##1:tcmc_mutates_in_wrong_order, 0:wybe.int, 0:wybe.int, 16:wybe.int, 0:wybe.int, ~#field##0:tcmc_mutates_in_wrong_order) @tcmc_mutates_in_wrong_order:nn:nn + foreign llvm move(1:wybe.bool, ?#success##0:wybe.bool) + + + +~= > public {inline} (0 calls) +0: tcmc_mutates_in_wrong_order.~=<0> +~=(#left##0:tcmc_mutates_in_wrong_order, #right##0:tcmc_mutates_in_wrong_order, ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + tcmc_mutates_in_wrong_order.=<0>(~#left##0:tcmc_mutates_in_wrong_order, ~#right##0:tcmc_mutates_in_wrong_order, ?tmp#0##0:wybe.bool) #0 + foreign llvm xor(~tmp#0##0:wybe.bool, 1:wybe.bool, ?#success##0:wybe.bool) + + LLVM code : + +; ModuleID = 'tcmc_mutates_in_wrong_order' + + + + + +@tcmc_mutates_in_wrong_order.3 = constant {i64, i64} { i64 1, i64 ptrtoint ([?? x i8]* @tcmc_mutates_in_wrong_order.2 to i64) } + + +@tcmc_mutates_in_wrong_order.5 = constant {i64, i64} { i64 1, i64 ptrtoint ([?? x i8]* @tcmc_mutates_in_wrong_order.4 to i64) } + + +@tcmc_mutates_in_wrong_order.7 = constant {i64, i64} { i64 4, i64 ptrtoint ([?? x i8]* @tcmc_mutates_in_wrong_order.6 to i64) } + + +@tcmc_mutates_in_wrong_order.1 = constant {i64, i64} { i64 5, i64 ptrtoint ([?? x i8]* @tcmc_mutates_in_wrong_order.0 to i64) } + + +@tcmc_mutates_in_wrong_order.4 = constant [?? x i8] c")\00" + + +@tcmc_mutates_in_wrong_order.2 = constant [?? x i8] c",\00" + + +@tcmc_mutates_in_wrong_order.0 = constant [?? x i8] c"node(\00" + + +@tcmc_mutates_in_wrong_order.6 = constant [?? x i8] c"null\00" + + +declare external fastcc void @"wybe.string.print<0>"(i64) + + +declare external ccc void @print_int(i64) + + +declare external ccc void @putchar(i8) + + +declare external ccc i8* @wybe_malloc(i32) + + +declare external ccc void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1) + + +define external fastcc void @"tcmc_mutates_in_wrong_order.<0>"() { +entry: + %0 = trunc i64 16 to i32 + %1 = tail call ccc i8* @wybe_malloc(i32 %0) + %2 = ptrtoint i8* %1 to i64 + %3 = inttoptr i64 %2 to i64* + store i64 0, i64* %3 + %4 = add i64 %2, 8 + %5 = inttoptr i64 %4 to i64* + store i64 1, i64* %5 + %6 = trunc i64 16 to i32 + %7 = tail call ccc i8* @wybe_malloc(i32 %6) + %8 = ptrtoint i8* %7 to i64 + %9 = inttoptr i64 %8 to i64* + store i64 0, i64* %9 + %10 = add i64 %8, 8 + %11 = inttoptr i64 %10 to i64* + store i64 2, i64* %11 + %12 = alloca i64 + call fastcc void @"tcmc_mutates_in_wrong_order.append<0>"(i64 %2, i64 %8, i64* %12) + %13 = load i64, i64* %12 + tail call fastcc void @"tcmc_mutates_in_wrong_order.print_list<0>"(i64 %8) + tail call ccc void @putchar(i8 10) + tail call fastcc void @"tcmc_mutates_in_wrong_order.print_list<0>"(i64 %13) + tail call ccc void @putchar(i8 10) + ret void +} + + +define external fastcc i1 @"tcmc_mutates_in_wrong_order.=<0>"(i64 %"#left##0", i64 %"#right##0") { +entry: + %0 = icmp ne i64 %"#left##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = inttoptr i64 %"#left##0" to i64* + %2 = load i64, i64* %1 + %3 = add i64 %"#left##0", 8 + %4 = inttoptr i64 %3 to i64* + %5 = load i64, i64* %4 + %6 = icmp ne i64 %"#right##0", 0 + br i1 %6, label %if.then1, label %if.else1 +if.else: + %14 = icmp eq i64 %"#left##0", %"#right##0" + ret i1 %14 +if.then1: + %7 = inttoptr i64 %"#right##0" to i64* + %8 = load i64, i64* %7 + %9 = add i64 %"#right##0", 8 + %10 = inttoptr i64 %9 to i64* + %11 = load i64, i64* %10 + %12 = tail call fastcc i1 @"tcmc_mutates_in_wrong_order.=<0>"(i64 %2, i64 %8) + br i1 %12, label %if.then2, label %if.else2 +if.else1: + ret i1 0 +if.then2: + %13 = icmp eq i64 %5, %11 + ret i1 %13 +if.else2: + ret i1 0 +} + + +define external fastcc void @"tcmc_mutates_in_wrong_order.append<0>"(i64 %"a##0", i64 %"b##0", i64* %"result#ref##0") { +entry: + %0 = icmp ne i64 %"a##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = inttoptr i64 %"a##0" to i64* + %2 = load i64, i64* %1 + %3 = add i64 %"a##0", 8 + %4 = inttoptr i64 %3 to i64* + %5 = load i64, i64* %4 + %6 = trunc i64 16 to i32 + %7 = tail call ccc i8* @wybe_malloc(i32 %6) + %8 = ptrtoint i8* %7 to i64 + %9 = add i64 %8, 8 + %10 = inttoptr i64 %9 to i64* + store i64 %5, i64* %10 + %11 = inttoptr i64 %8 to i64* + store i64 %8, i64* %"result#ref##0" + musttail call fastcc void @"tcmc_mutates_in_wrong_order.append<0>"(i64 %"b##0", i64 %2, i64* %11) + ret void +if.else: + store i64 %"b##0", i64* %"result#ref##0" + ret void +} + + +define external fastcc {i64, i1} @"tcmc_mutates_in_wrong_order.head<0>"(i64 %"#rec##0") { +entry: + %0 = icmp ne i64 %"#rec##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = add i64 %"#rec##0", 8 + %2 = inttoptr i64 %1 to i64* + %3 = load i64, i64* %2 + %4 = insertvalue {i64, i1} undef, i64 %3, 0 + %5 = insertvalue {i64, i1} %4, i1 1, 1 + ret {i64, i1} %5 +if.else: + %6 = insertvalue {i64, i1} undef, i64 undef, 0 + %7 = insertvalue {i64, i1} %6, i1 0, 1 + ret {i64, i1} %7 +} + + +define external fastcc {i64, i1} @"tcmc_mutates_in_wrong_order.head<1>"(i64 %"#rec##0", i64 %"#field##0") { +entry: + %0 = icmp ne i64 %"#rec##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = trunc i64 16 to i32 + %2 = tail call ccc i8* @wybe_malloc(i32 %1) + %3 = ptrtoint i8* %2 to i64 + %4 = inttoptr i64 %3 to i8* + %5 = inttoptr i64 %"#rec##0" to i8* + %6 = trunc i64 16 to i32 + tail call ccc void @llvm.memcpy.p0i8.p0i8.i32(i8* %4, i8* %5, i32 %6, i1 0) + %7 = add i64 %3, 8 + %8 = inttoptr i64 %7 to i64* + store i64 %"#field##0", i64* %8 + %9 = insertvalue {i64, i1} undef, i64 %3, 0 + %10 = insertvalue {i64, i1} %9, i1 1, 1 + ret {i64, i1} %10 +if.else: + %11 = insertvalue {i64, i1} undef, i64 %"#rec##0", 0 + %12 = insertvalue {i64, i1} %11, i1 0, 1 + ret {i64, i1} %12 +} + + +define external fastcc i64 @"tcmc_mutates_in_wrong_order.null<0>"() { +entry: + ret i64 0 +} + + +define external fastcc void @"tcmc_mutates_in_wrong_order.print_list<0>"(i64 %"a##0") { +entry: + %0 = icmp ne i64 %"a##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = inttoptr i64 %"a##0" to i64* + %2 = load i64, i64* %1 + %3 = add i64 %"a##0", 8 + %4 = inttoptr i64 %3 to i64* + %5 = load i64, i64* %4 + tail call fastcc void @"wybe.string.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ({i64, i64}, {i64, i64}* @tcmc_mutates_in_wrong_order.1, i32 0, i32 0) to i64)) + tail call ccc void @print_int(i64 %5) + tail call fastcc void @"wybe.string.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ({i64, i64}, {i64, i64}* @tcmc_mutates_in_wrong_order.3, i32 0, i32 0) to i64)) + tail call fastcc void @"tcmc_mutates_in_wrong_order.print_list<0>"(i64 %2) + musttail call fastcc void @"wybe.string.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ({i64, i64}, {i64, i64}* @tcmc_mutates_in_wrong_order.5, i32 0, i32 0) to i64)) + ret void +if.else: + musttail call fastcc void @"wybe.string.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ({i64, i64}, {i64, i64}* @tcmc_mutates_in_wrong_order.7, i32 0, i32 0) to i64)) + ret void +} + + +define external fastcc i64 @"tcmc_mutates_in_wrong_order.snoc<0>"(i64 %"tail##0", i64 %"head##0") { +entry: + %0 = trunc i64 16 to i32 + %1 = tail call ccc i8* @wybe_malloc(i32 %0) + %2 = ptrtoint i8* %1 to i64 + %3 = inttoptr i64 %2 to i64* + store i64 %"tail##0", i64* %3 + %4 = add i64 %2, 8 + %5 = inttoptr i64 %4 to i64* + store i64 %"head##0", i64* %5 + ret i64 %2 +} + + +define external fastcc {i64, i64, i1} @"tcmc_mutates_in_wrong_order.snoc<1>"(i64 %"#result##0") { +entry: + %0 = icmp ne i64 %"#result##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = inttoptr i64 %"#result##0" to i64* + %2 = load i64, i64* %1 + %3 = add i64 %"#result##0", 8 + %4 = inttoptr i64 %3 to i64* + %5 = load i64, i64* %4 + %6 = insertvalue {i64, i64, i1} undef, i64 %2, 0 + %7 = insertvalue {i64, i64, i1} %6, i64 %5, 1 + %8 = insertvalue {i64, i64, i1} %7, i1 1, 2 + ret {i64, i64, i1} %8 +if.else: + %9 = insertvalue {i64, i64, i1} undef, i64 undef, 0 + %10 = insertvalue {i64, i64, i1} %9, i64 undef, 1 + %11 = insertvalue {i64, i64, i1} %10, i1 0, 2 + ret {i64, i64, i1} %11 +} + + +define external fastcc {i64, i1} @"tcmc_mutates_in_wrong_order.tail<0>"(i64 %"#rec##0") { +entry: + %0 = icmp ne i64 %"#rec##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = inttoptr i64 %"#rec##0" to i64* + %2 = load i64, i64* %1 + %3 = insertvalue {i64, i1} undef, i64 %2, 0 + %4 = insertvalue {i64, i1} %3, i1 1, 1 + ret {i64, i1} %4 +if.else: + %5 = insertvalue {i64, i1} undef, i64 undef, 0 + %6 = insertvalue {i64, i1} %5, i1 0, 1 + ret {i64, i1} %6 +} + + +define external fastcc {i64, i1} @"tcmc_mutates_in_wrong_order.tail<1>"(i64 %"#rec##0", i64 %"#field##0") { +entry: + %0 = icmp ne i64 %"#rec##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = trunc i64 16 to i32 + %2 = tail call ccc i8* @wybe_malloc(i32 %1) + %3 = ptrtoint i8* %2 to i64 + %4 = inttoptr i64 %3 to i8* + %5 = inttoptr i64 %"#rec##0" to i8* + %6 = trunc i64 16 to i32 + tail call ccc void @llvm.memcpy.p0i8.p0i8.i32(i8* %4, i8* %5, i32 %6, i1 0) + %7 = inttoptr i64 %3 to i64* + store i64 %"#field##0", i64* %7 + %8 = insertvalue {i64, i1} undef, i64 %3, 0 + %9 = insertvalue {i64, i1} %8, i1 1, 1 + ret {i64, i1} %9 +if.else: + %10 = insertvalue {i64, i1} undef, i64 %"#rec##0", 0 + %11 = insertvalue {i64, i1} %10, i1 0, 1 + ret {i64, i1} %11 +} + + +define external fastcc i1 @"tcmc_mutates_in_wrong_order.~=<0>"(i64 %"#left##0", i64 %"#right##0") { +entry: + %0 = tail call fastcc i1 @"tcmc_mutates_in_wrong_order.=<0>"(i64 %"#left##0", i64 %"#right##0") + %1 = xor i1 %0, 1 + ret i1 %1 +} diff --git a/test-cases/final-dump/tcmc_mutates_in_wrong_order.wybe b/test-cases/final-dump/tcmc_mutates_in_wrong_order.wybe new file mode 100644 index 00000000..372c79af --- /dev/null +++ b/test-cases/final-dump/tcmc_mutates_in_wrong_order.wybe @@ -0,0 +1,31 @@ +constructors null | snoc(tail: _, head: int) + +def append(a: _, b: _, ?result: _) { + if { snoc(?t, ?h) = a :: + append(b, t, ?t2) + # mutate for val happens at the end. This breaks this optimization :(( + ?result = snoc(t2, h) + | else :: + ?result = b + } +} + +def print_list(a: _) use !io { + if { snoc(?tail, ?head) = a :: + !print("node(") + !print(head) + !print(",") + !print_list(tail) + !print(")") + | else :: + !print("null") + } + +} +?x = snoc(null, 1) +?x2 = snoc(null, 2) +append(x, x2, ?x3) +!print_list(x2) +!nl +!print_list(x3) +!nl \ No newline at end of file diff --git a/test-cases/final-dump/tcmc_mutates_in_wrong_order2.exp b/test-cases/final-dump/tcmc_mutates_in_wrong_order2.exp new file mode 100644 index 00000000..3ab5bfd8 --- /dev/null +++ b/test-cases/final-dump/tcmc_mutates_in_wrong_order2.exp @@ -0,0 +1,637 @@ +====================================================================== +AFTER EVERYTHING: + Module tcmc_mutates_in_wrong_order2 + representation : address + public submods : + public resources: + public procs : tcmc_mutates_in_wrong_order2.<0> + tcmc_mutates_in_wrong_order2.=<0> + tcmc_mutates_in_wrong_order2.snoc<0> + tcmc_mutates_in_wrong_order2.snoc<1> + tcmc_mutates_in_wrong_order2.~=<0> + imports : use wybe + resources : + procs : + +module top-level code > public {impure} (0 calls) +0: tcmc_mutates_in_wrong_order2.<0> +()<{<>}; {<>}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign lpvm alloc(24:wybe.int, ?tmp#7##0:tcmc_mutates_in_wrong_order2) @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm mutate(~tmp#7##0:tcmc_mutates_in_wrong_order2, ?tmp#8##0:tcmc_mutates_in_wrong_order2, 0:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, 0:tcmc_mutates_in_wrong_order2) @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm mutate(~tmp#8##0:tcmc_mutates_in_wrong_order2, ?tmp#9##0:tcmc_mutates_in_wrong_order2, 8:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, 1:wybe.int) @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm mutate(~tmp#9##0:tcmc_mutates_in_wrong_order2, ?tmp#0##0:tcmc_mutates_in_wrong_order2, 16:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, 1:wybe.int) @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm alloc(24:wybe.int, ?tmp#13##0:tcmc_mutates_in_wrong_order2) @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm mutate(~tmp#13##0:tcmc_mutates_in_wrong_order2, ?tmp#14##0:tcmc_mutates_in_wrong_order2, 0:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, 0:tcmc_mutates_in_wrong_order2) @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm mutate(~tmp#14##0:tcmc_mutates_in_wrong_order2, ?tmp#15##0:tcmc_mutates_in_wrong_order2, 8:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, 2:wybe.int) @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm mutate(~tmp#15##0:tcmc_mutates_in_wrong_order2, ?tmp#2##0:tcmc_mutates_in_wrong_order2, 16:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, 3:wybe.int) @tcmc_mutates_in_wrong_order2:nn:nn + tcmc_mutates_in_wrong_order2.append<0>(~tmp#0##0:tcmc_mutates_in_wrong_order2, tmp#2##0:tcmc_mutates_in_wrong_order2, outByReference x3##0:tcmc_mutates_in_wrong_order2) #4 @tcmc_mutates_in_wrong_order2:nn:nn + tcmc_mutates_in_wrong_order2.print_list<0>(~tmp#2##0:tcmc_mutates_in_wrong_order2)<{<>}; {<>}> #5 @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm load(<>:wybe.phantom, ?%tmp#16##0:wybe.phantom) @io:nn:nn + foreign c putchar('\n':wybe.char, ~tmp#16##0:wybe.phantom, ?tmp#17##0:wybe.phantom) @io:nn:nn + foreign lpvm store(~%tmp#17##0:wybe.phantom, <>:wybe.phantom) @io:nn:nn + tcmc_mutates_in_wrong_order2.print_list<0>(~x3##0:tcmc_mutates_in_wrong_order2)<{<>}; {<>}> #7 @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm load(<>:wybe.phantom, ?%tmp#18##0:wybe.phantom) @io:nn:nn + foreign c putchar('\n':wybe.char, ~tmp#18##0:wybe.phantom, ?tmp#19##0:wybe.phantom) @io:nn:nn + foreign lpvm store(~%tmp#19##0:wybe.phantom, <>:wybe.phantom) @io:nn:nn + + += > public (6 calls) +0: tcmc_mutates_in_wrong_order2.=<0> +=(#left##0:tcmc_mutates_in_wrong_order2, #right##0:tcmc_mutates_in_wrong_order2, ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_ne(#left##0:wybe.int, 0:wybe.int, ?tmp#0##0:wybe.bool) + case ~tmp#0##0:wybe.bool of + 0: + foreign llvm icmp_eq(~#left##0:tcmc_mutates_in_wrong_order2, ~#right##0:tcmc_mutates_in_wrong_order2, ?#success##0:wybe.bool) + + 1: + foreign lpvm access(#left##0:tcmc_mutates_in_wrong_order2, 0:wybe.int, 24:wybe.int, 0:wybe.int, ?#left#tail##0:tcmc_mutates_in_wrong_order2) @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm access(#left##0:tcmc_mutates_in_wrong_order2, 8:wybe.int, 24:wybe.int, 0:wybe.int, ?#left#head1##0:wybe.int) @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm access(~#left##0:tcmc_mutates_in_wrong_order2, 16:wybe.int, 24:wybe.int, 0:wybe.int, ?#left#head2##0:wybe.int) @tcmc_mutates_in_wrong_order2:nn:nn + foreign llvm icmp_ne(#right##0:wybe.int, 0:wybe.int, ?tmp#10##0:wybe.bool) + case ~tmp#10##0:wybe.bool of + 0: + foreign llvm move(0:wybe.bool, ?#success##0:wybe.bool) + + 1: + foreign lpvm access(#right##0:tcmc_mutates_in_wrong_order2, 0:wybe.int, 24:wybe.int, 0:wybe.int, ?#right#tail##0:tcmc_mutates_in_wrong_order2) @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm access(#right##0:tcmc_mutates_in_wrong_order2, 8:wybe.int, 24:wybe.int, 0:wybe.int, ?#right#head1##0:wybe.int) @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm access(~#right##0:tcmc_mutates_in_wrong_order2, 16:wybe.int, 24:wybe.int, 0:wybe.int, ?#right#head2##0:wybe.int) @tcmc_mutates_in_wrong_order2:nn:nn + tcmc_mutates_in_wrong_order2.=<0>(~#left#tail##0:tcmc_mutates_in_wrong_order2, ~#right#tail##0:tcmc_mutates_in_wrong_order2, ?tmp#4##0:wybe.bool) #2 + case ~tmp#4##0:wybe.bool of + 0: + foreign llvm move(0:wybe.bool, ?#success##0:wybe.bool) + + 1: + foreign llvm icmp_eq(~#left#head1##0:wybe.int, ~#right#head1##0:wybe.int, ?tmp#5##0:wybe.bool) @int:nn:nn + case ~tmp#5##0:wybe.bool of + 0: + foreign llvm move(0:wybe.bool, ?#success##0:wybe.bool) + + 1: + foreign llvm icmp_eq(~#left#head2##0:wybe.int, ~#right#head2##0:wybe.int, ?#success##0:wybe.bool) @int:nn:nn + + + + + + +append > (2 calls) +0: tcmc_mutates_in_wrong_order2.append<0> +append(a##0:tcmc_mutates_in_wrong_order2, b##0:tcmc_mutates_in_wrong_order2, outByReference result##0:tcmc_mutates_in_wrong_order2)<{}; {}>: + AliasPairs: [(a##0,b##0),(a##0,result##0),(b##0,result##0)] + InterestingCallProperties: [] + foreign llvm icmp_ne(a##0:wybe.int, 0:wybe.int, ?tmp#3##0:wybe.bool) + case ~tmp#3##0:wybe.bool of + 0: + foreign llvm move(~b##0:tcmc_mutates_in_wrong_order2, ?result##0:tcmc_mutates_in_wrong_order2) @tcmc_mutates_in_wrong_order2:nn:nn + + 1: + foreign lpvm access(a##0:tcmc_mutates_in_wrong_order2, 0:wybe.int, 24:wybe.int, 0:wybe.int, ?t##0:tcmc_mutates_in_wrong_order2) @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm access(~a##0:tcmc_mutates_in_wrong_order2, 8:wybe.int, 24:wybe.int, 0:wybe.int, ?h##0:wybe.int) @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm alloc(24:wybe.int, ?tmp#7##0:tcmc_mutates_in_wrong_order2) @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm mutate(~tmp#7##0:tcmc_mutates_in_wrong_order2, ?tmp#8##0:tcmc_mutates_in_wrong_order2, 8:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, h##0:wybe.int) @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm mutate(~tmp#8##0:tcmc_mutates_in_wrong_order2, ?tmp#9##0:tcmc_mutates_in_wrong_order2, 16:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, ~h##0:wybe.int) @tcmc_mutates_in_wrong_order2:nn:nn + tcmc_mutates_in_wrong_order2.append<0>(~b##0:tcmc_mutates_in_wrong_order2, ~t##0:tcmc_mutates_in_wrong_order2, outByReference t2##0:tcmc_mutates_in_wrong_order2) #1 @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm mutate(~tmp#9##0:tcmc_mutates_in_wrong_order2, ?result##0:tcmc_mutates_in_wrong_order2, 0:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, ~takeReference t2##0:tcmc_mutates_in_wrong_order2) @tcmc_mutates_in_wrong_order2:nn:nn + + + +head1 > {inline} (0 calls) +0: tcmc_mutates_in_wrong_order2.head1<0> +head1(#rec##0:tcmc_mutates_in_wrong_order2, ?#result##0:wybe.int, ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_ne(#rec##0:wybe.int, 0:wybe.int, ?tmp#0##0:wybe.bool) + case ~tmp#0##0:wybe.bool of + 0: + foreign llvm move(0:wybe.bool, ?#success##0:wybe.bool) + foreign llvm move(undef:wybe.int, ?#result##0:wybe.int) + + 1: + foreign lpvm access(~#rec##0:tcmc_mutates_in_wrong_order2, 8:wybe.int, 24:wybe.int, 0:wybe.int, ?#result##0:wybe.int) @tcmc_mutates_in_wrong_order2:nn:nn + foreign llvm move(1:wybe.bool, ?#success##0:wybe.bool) + +head1 > {inline} (0 calls) +1: tcmc_mutates_in_wrong_order2.head1<1> +head1(#rec##0:tcmc_mutates_in_wrong_order2, ?#rec##1:tcmc_mutates_in_wrong_order2, #field##0:wybe.int, ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_ne(#rec##0:wybe.int, 0:wybe.int, ?tmp#0##0:wybe.bool) + case ~tmp#0##0:wybe.bool of + 0: + foreign llvm move(0:wybe.bool, ?#success##0:wybe.bool) + foreign llvm move(~#rec##0:tcmc_mutates_in_wrong_order2, ?#rec##1:tcmc_mutates_in_wrong_order2) + + 1: + foreign lpvm mutate(~#rec##0:tcmc_mutates_in_wrong_order2, ?#rec##1:tcmc_mutates_in_wrong_order2, 8:wybe.int, 0:wybe.int, 24:wybe.int, 0:wybe.int, ~#field##0:wybe.int) @tcmc_mutates_in_wrong_order2:nn:nn + foreign llvm move(1:wybe.bool, ?#success##0:wybe.bool) + + + +head2 > {inline} (0 calls) +0: tcmc_mutates_in_wrong_order2.head2<0> +head2(#rec##0:tcmc_mutates_in_wrong_order2, ?#result##0:wybe.int, ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_ne(#rec##0:wybe.int, 0:wybe.int, ?tmp#0##0:wybe.bool) + case ~tmp#0##0:wybe.bool of + 0: + foreign llvm move(0:wybe.bool, ?#success##0:wybe.bool) + foreign llvm move(undef:wybe.int, ?#result##0:wybe.int) + + 1: + foreign lpvm access(~#rec##0:tcmc_mutates_in_wrong_order2, 16:wybe.int, 24:wybe.int, 0:wybe.int, ?#result##0:wybe.int) @tcmc_mutates_in_wrong_order2:nn:nn + foreign llvm move(1:wybe.bool, ?#success##0:wybe.bool) + +head2 > {inline} (0 calls) +1: tcmc_mutates_in_wrong_order2.head2<1> +head2(#rec##0:tcmc_mutates_in_wrong_order2, ?#rec##1:tcmc_mutates_in_wrong_order2, #field##0:wybe.int, ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_ne(#rec##0:wybe.int, 0:wybe.int, ?tmp#0##0:wybe.bool) + case ~tmp#0##0:wybe.bool of + 0: + foreign llvm move(0:wybe.bool, ?#success##0:wybe.bool) + foreign llvm move(~#rec##0:tcmc_mutates_in_wrong_order2, ?#rec##1:tcmc_mutates_in_wrong_order2) + + 1: + foreign lpvm mutate(~#rec##0:tcmc_mutates_in_wrong_order2, ?#rec##1:tcmc_mutates_in_wrong_order2, 16:wybe.int, 0:wybe.int, 24:wybe.int, 0:wybe.int, ~#field##0:wybe.int) @tcmc_mutates_in_wrong_order2:nn:nn + foreign llvm move(1:wybe.bool, ?#success##0:wybe.bool) + + + +null > {inline} (2 calls) +0: tcmc_mutates_in_wrong_order2.null<0> +null(?#result##0:tcmc_mutates_in_wrong_order2)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm move(0:tcmc_mutates_in_wrong_order2, ?#result##0:tcmc_mutates_in_wrong_order2) + + +print_list > (3 calls) +0: tcmc_mutates_in_wrong_order2.print_list<0> +print_list(a##0:tcmc_mutates_in_wrong_order2)<{<>}; {<>}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_ne(a##0:wybe.int, 0:wybe.int, ?tmp#2##0:wybe.bool) + case ~tmp#2##0:wybe.bool of + 0: + wybe.string.print<0>("null":wybe.string)<{<>}; {<>}> #8 @tcmc_mutates_in_wrong_order2:nn:nn + + 1: + foreign lpvm access(a##0:tcmc_mutates_in_wrong_order2, 0:wybe.int, 24:wybe.int, 0:wybe.int, ?tail##0:tcmc_mutates_in_wrong_order2) @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm access(a##0:tcmc_mutates_in_wrong_order2, 8:wybe.int, 24:wybe.int, 0:wybe.int, ?head##0:wybe.int) @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm access(~a##0:tcmc_mutates_in_wrong_order2, 16:wybe.int, 24:wybe.int, 0:wybe.int, ?head2##0:wybe.int) @tcmc_mutates_in_wrong_order2:nn:nn + wybe.string.print<0>("node(":wybe.string)<{<>}; {<>}> #1 @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm load(<>:wybe.phantom, ?%tmp#4##0:wybe.phantom) @int:nn:nn + foreign c print_int(~head##0:wybe.int, ~tmp#4##0:wybe.phantom, ?tmp#5##0:wybe.phantom) @int:nn:nn + foreign lpvm store(~%tmp#5##0:wybe.phantom, <>:wybe.phantom) @int:nn:nn + wybe.string.print<0>(",":wybe.string)<{<>}; {<>}> #3 @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm load(<>:wybe.phantom, ?%tmp#7##0:wybe.phantom) @int:nn:nn + foreign c print_int(~head2##0:wybe.int, ~tmp#7##0:wybe.phantom, ?tmp#8##0:wybe.phantom) @int:nn:nn + foreign lpvm store(~%tmp#8##0:wybe.phantom, <>:wybe.phantom) @int:nn:nn + wybe.string.print<0>(",":wybe.string)<{<>}; {<>}> #5 @tcmc_mutates_in_wrong_order2:nn:nn + tcmc_mutates_in_wrong_order2.print_list<0>(~tail##0:tcmc_mutates_in_wrong_order2)<{<>}; {<>}> #6 @tcmc_mutates_in_wrong_order2:nn:nn + wybe.string.print<0>(")":wybe.string)<{<>}; {<>}> #7 @tcmc_mutates_in_wrong_order2:nn:nn + + + +snoc > public {inline} (3 calls) +0: tcmc_mutates_in_wrong_order2.snoc<0> +snoc(tail##0:tcmc_mutates_in_wrong_order2, head1##0:wybe.int, head2##0:wybe.int, ?#result##0:tcmc_mutates_in_wrong_order2)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign lpvm alloc(24:wybe.int, ?#rec##0:tcmc_mutates_in_wrong_order2) @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm mutate(~#rec##0:tcmc_mutates_in_wrong_order2, ?#rec##1:tcmc_mutates_in_wrong_order2, 0:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, ~tail##0:tcmc_mutates_in_wrong_order2) @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm mutate(~#rec##1:tcmc_mutates_in_wrong_order2, ?#rec##2:tcmc_mutates_in_wrong_order2, 8:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, ~head1##0:wybe.int) @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm mutate(~#rec##2:tcmc_mutates_in_wrong_order2, ?#result##0:tcmc_mutates_in_wrong_order2, 16:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, ~head2##0:wybe.int) @tcmc_mutates_in_wrong_order2:nn:nn +snoc > public {inline} (22 calls) +1: tcmc_mutates_in_wrong_order2.snoc<1> +snoc(?tail##0:tcmc_mutates_in_wrong_order2, ?head1##0:wybe.int, ?head2##0:wybe.int, #result##0:tcmc_mutates_in_wrong_order2, ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_ne(#result##0:wybe.int, 0:wybe.int, ?tmp#0##0:wybe.bool) + case ~tmp#0##0:wybe.bool of + 0: + foreign llvm move(0:wybe.bool, ?#success##0:wybe.bool) + foreign llvm move(undef:tcmc_mutates_in_wrong_order2, ?tail##0:tcmc_mutates_in_wrong_order2) + foreign llvm move(undef:wybe.int, ?head1##0:wybe.int) + foreign llvm move(undef:wybe.int, ?head2##0:wybe.int) + + 1: + foreign lpvm access(#result##0:tcmc_mutates_in_wrong_order2, 0:wybe.int, 24:wybe.int, 0:wybe.int, ?tail##0:tcmc_mutates_in_wrong_order2) @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm access(#result##0:tcmc_mutates_in_wrong_order2, 8:wybe.int, 24:wybe.int, 0:wybe.int, ?head1##0:wybe.int) @tcmc_mutates_in_wrong_order2:nn:nn + foreign lpvm access(~#result##0:tcmc_mutates_in_wrong_order2, 16:wybe.int, 24:wybe.int, 0:wybe.int, ?head2##0:wybe.int) @tcmc_mutates_in_wrong_order2:nn:nn + foreign llvm move(1:wybe.bool, ?#success##0:wybe.bool) + + + +tail > {inline} (0 calls) +0: tcmc_mutates_in_wrong_order2.tail<0> +tail(#rec##0:tcmc_mutates_in_wrong_order2, ?#result##0:tcmc_mutates_in_wrong_order2, ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_ne(#rec##0:wybe.int, 0:wybe.int, ?tmp#0##0:wybe.bool) + case ~tmp#0##0:wybe.bool of + 0: + foreign llvm move(0:wybe.bool, ?#success##0:wybe.bool) + foreign llvm move(undef:tcmc_mutates_in_wrong_order2, ?#result##0:tcmc_mutates_in_wrong_order2) + + 1: + foreign lpvm access(~#rec##0:tcmc_mutates_in_wrong_order2, 0:wybe.int, 24:wybe.int, 0:wybe.int, ?#result##0:tcmc_mutates_in_wrong_order2) @tcmc_mutates_in_wrong_order2:nn:nn + foreign llvm move(1:wybe.bool, ?#success##0:wybe.bool) + +tail > {inline} (0 calls) +1: tcmc_mutates_in_wrong_order2.tail<1> +tail(#rec##0:tcmc_mutates_in_wrong_order2, ?#rec##1:tcmc_mutates_in_wrong_order2, #field##0:tcmc_mutates_in_wrong_order2, ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_ne(#rec##0:wybe.int, 0:wybe.int, ?tmp#0##0:wybe.bool) + case ~tmp#0##0:wybe.bool of + 0: + foreign llvm move(0:wybe.bool, ?#success##0:wybe.bool) + foreign llvm move(~#rec##0:tcmc_mutates_in_wrong_order2, ?#rec##1:tcmc_mutates_in_wrong_order2) + + 1: + foreign lpvm {noalias} mutate(~#rec##0:tcmc_mutates_in_wrong_order2, ?#rec##1:tcmc_mutates_in_wrong_order2, 0:wybe.int, 0:wybe.int, 24:wybe.int, 0:wybe.int, ~#field##0:tcmc_mutates_in_wrong_order2) @tcmc_mutates_in_wrong_order2:nn:nn + foreign llvm move(1:wybe.bool, ?#success##0:wybe.bool) + + + +~= > public {inline} (0 calls) +0: tcmc_mutates_in_wrong_order2.~=<0> +~=(#left##0:tcmc_mutates_in_wrong_order2, #right##0:tcmc_mutates_in_wrong_order2, ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + tcmc_mutates_in_wrong_order2.=<0>(~#left##0:tcmc_mutates_in_wrong_order2, ~#right##0:tcmc_mutates_in_wrong_order2, ?tmp#0##0:wybe.bool) #0 + foreign llvm xor(~tmp#0##0:wybe.bool, 1:wybe.bool, ?#success##0:wybe.bool) + + LLVM code : + +; ModuleID = 'tcmc_mutates_in_wrong_order2' + + + + + +@tcmc_mutates_in_wrong_order2.3 = constant {i64, i64} { i64 1, i64 ptrtoint ([?? x i8]* @tcmc_mutates_in_wrong_order2.2 to i64) } + + +@tcmc_mutates_in_wrong_order2.5 = constant {i64, i64} { i64 1, i64 ptrtoint ([?? x i8]* @tcmc_mutates_in_wrong_order2.4 to i64) } + + +@tcmc_mutates_in_wrong_order2.7 = constant {i64, i64} { i64 4, i64 ptrtoint ([?? x i8]* @tcmc_mutates_in_wrong_order2.6 to i64) } + + +@tcmc_mutates_in_wrong_order2.1 = constant {i64, i64} { i64 5, i64 ptrtoint ([?? x i8]* @tcmc_mutates_in_wrong_order2.0 to i64) } + + +@tcmc_mutates_in_wrong_order2.4 = constant [?? x i8] c")\00" + + +@tcmc_mutates_in_wrong_order2.2 = constant [?? x i8] c",\00" + + +@tcmc_mutates_in_wrong_order2.0 = constant [?? x i8] c"node(\00" + + +@tcmc_mutates_in_wrong_order2.6 = constant [?? x i8] c"null\00" + + +declare external fastcc void @"wybe.string.print<0>"(i64) + + +declare external ccc void @print_int(i64) + + +declare external ccc void @putchar(i8) + + +declare external ccc i8* @wybe_malloc(i32) + + +declare external ccc void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1) + + +define external fastcc void @"tcmc_mutates_in_wrong_order2.<0>"() { +entry: + %0 = trunc i64 24 to i32 + %1 = tail call ccc i8* @wybe_malloc(i32 %0) + %2 = ptrtoint i8* %1 to i64 + %3 = inttoptr i64 %2 to i64* + store i64 0, i64* %3 + %4 = add i64 %2, 8 + %5 = inttoptr i64 %4 to i64* + store i64 1, i64* %5 + %6 = add i64 %2, 16 + %7 = inttoptr i64 %6 to i64* + store i64 1, i64* %7 + %8 = trunc i64 24 to i32 + %9 = tail call ccc i8* @wybe_malloc(i32 %8) + %10 = ptrtoint i8* %9 to i64 + %11 = inttoptr i64 %10 to i64* + store i64 0, i64* %11 + %12 = add i64 %10, 8 + %13 = inttoptr i64 %12 to i64* + store i64 2, i64* %13 + %14 = add i64 %10, 16 + %15 = inttoptr i64 %14 to i64* + store i64 3, i64* %15 + %16 = alloca i64 + call fastcc void @"tcmc_mutates_in_wrong_order2.append<0>"(i64 %2, i64 %10, i64* %16) + %17 = load i64, i64* %16 + tail call fastcc void @"tcmc_mutates_in_wrong_order2.print_list<0>"(i64 %10) + tail call ccc void @putchar(i8 10) + tail call fastcc void @"tcmc_mutates_in_wrong_order2.print_list<0>"(i64 %17) + tail call ccc void @putchar(i8 10) + ret void +} + + +define external fastcc i1 @"tcmc_mutates_in_wrong_order2.=<0>"(i64 %"#left##0", i64 %"#right##0") { +entry: + %0 = icmp ne i64 %"#left##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = inttoptr i64 %"#left##0" to i64* + %2 = load i64, i64* %1 + %3 = add i64 %"#left##0", 8 + %4 = inttoptr i64 %3 to i64* + %5 = load i64, i64* %4 + %6 = add i64 %"#left##0", 16 + %7 = inttoptr i64 %6 to i64* + %8 = load i64, i64* %7 + %9 = icmp ne i64 %"#right##0", 0 + br i1 %9, label %if.then1, label %if.else1 +if.else: + %21 = icmp eq i64 %"#left##0", %"#right##0" + ret i1 %21 +if.then1: + %10 = inttoptr i64 %"#right##0" to i64* + %11 = load i64, i64* %10 + %12 = add i64 %"#right##0", 8 + %13 = inttoptr i64 %12 to i64* + %14 = load i64, i64* %13 + %15 = add i64 %"#right##0", 16 + %16 = inttoptr i64 %15 to i64* + %17 = load i64, i64* %16 + %18 = tail call fastcc i1 @"tcmc_mutates_in_wrong_order2.=<0>"(i64 %2, i64 %11) + br i1 %18, label %if.then2, label %if.else2 +if.else1: + ret i1 0 +if.then2: + %19 = icmp eq i64 %5, %14 + br i1 %19, label %if.then3, label %if.else3 +if.else2: + ret i1 0 +if.then3: + %20 = icmp eq i64 %8, %17 + ret i1 %20 +if.else3: + ret i1 0 +} + + +define external fastcc void @"tcmc_mutates_in_wrong_order2.append<0>"(i64 %"a##0", i64 %"b##0", i64* %"result#ref##0") { +entry: + %0 = icmp ne i64 %"a##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = inttoptr i64 %"a##0" to i64* + %2 = load i64, i64* %1 + %3 = add i64 %"a##0", 8 + %4 = inttoptr i64 %3 to i64* + %5 = load i64, i64* %4 + %6 = trunc i64 24 to i32 + %7 = tail call ccc i8* @wybe_malloc(i32 %6) + %8 = ptrtoint i8* %7 to i64 + %9 = add i64 %8, 8 + %10 = inttoptr i64 %9 to i64* + store i64 %5, i64* %10 + %11 = add i64 %8, 16 + %12 = inttoptr i64 %11 to i64* + store i64 %5, i64* %12 + %13 = inttoptr i64 %8 to i64* + store i64 %8, i64* %"result#ref##0" + musttail call fastcc void @"tcmc_mutates_in_wrong_order2.append<0>"(i64 %"b##0", i64 %2, i64* %13) + ret void +if.else: + store i64 %"b##0", i64* %"result#ref##0" + ret void +} + + +define external fastcc {i64, i1} @"tcmc_mutates_in_wrong_order2.head1<0>"(i64 %"#rec##0") { +entry: + %0 = icmp ne i64 %"#rec##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = add i64 %"#rec##0", 8 + %2 = inttoptr i64 %1 to i64* + %3 = load i64, i64* %2 + %4 = insertvalue {i64, i1} undef, i64 %3, 0 + %5 = insertvalue {i64, i1} %4, i1 1, 1 + ret {i64, i1} %5 +if.else: + %6 = insertvalue {i64, i1} undef, i64 undef, 0 + %7 = insertvalue {i64, i1} %6, i1 0, 1 + ret {i64, i1} %7 +} + + +define external fastcc {i64, i1} @"tcmc_mutates_in_wrong_order2.head1<1>"(i64 %"#rec##0", i64 %"#field##0") { +entry: + %0 = icmp ne i64 %"#rec##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = trunc i64 24 to i32 + %2 = tail call ccc i8* @wybe_malloc(i32 %1) + %3 = ptrtoint i8* %2 to i64 + %4 = inttoptr i64 %3 to i8* + %5 = inttoptr i64 %"#rec##0" to i8* + %6 = trunc i64 24 to i32 + tail call ccc void @llvm.memcpy.p0i8.p0i8.i32(i8* %4, i8* %5, i32 %6, i1 0) + %7 = add i64 %3, 8 + %8 = inttoptr i64 %7 to i64* + store i64 %"#field##0", i64* %8 + %9 = insertvalue {i64, i1} undef, i64 %3, 0 + %10 = insertvalue {i64, i1} %9, i1 1, 1 + ret {i64, i1} %10 +if.else: + %11 = insertvalue {i64, i1} undef, i64 %"#rec##0", 0 + %12 = insertvalue {i64, i1} %11, i1 0, 1 + ret {i64, i1} %12 +} + + +define external fastcc {i64, i1} @"tcmc_mutates_in_wrong_order2.head2<0>"(i64 %"#rec##0") { +entry: + %0 = icmp ne i64 %"#rec##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = add i64 %"#rec##0", 16 + %2 = inttoptr i64 %1 to i64* + %3 = load i64, i64* %2 + %4 = insertvalue {i64, i1} undef, i64 %3, 0 + %5 = insertvalue {i64, i1} %4, i1 1, 1 + ret {i64, i1} %5 +if.else: + %6 = insertvalue {i64, i1} undef, i64 undef, 0 + %7 = insertvalue {i64, i1} %6, i1 0, 1 + ret {i64, i1} %7 +} + + +define external fastcc {i64, i1} @"tcmc_mutates_in_wrong_order2.head2<1>"(i64 %"#rec##0", i64 %"#field##0") { +entry: + %0 = icmp ne i64 %"#rec##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = trunc i64 24 to i32 + %2 = tail call ccc i8* @wybe_malloc(i32 %1) + %3 = ptrtoint i8* %2 to i64 + %4 = inttoptr i64 %3 to i8* + %5 = inttoptr i64 %"#rec##0" to i8* + %6 = trunc i64 24 to i32 + tail call ccc void @llvm.memcpy.p0i8.p0i8.i32(i8* %4, i8* %5, i32 %6, i1 0) + %7 = add i64 %3, 16 + %8 = inttoptr i64 %7 to i64* + store i64 %"#field##0", i64* %8 + %9 = insertvalue {i64, i1} undef, i64 %3, 0 + %10 = insertvalue {i64, i1} %9, i1 1, 1 + ret {i64, i1} %10 +if.else: + %11 = insertvalue {i64, i1} undef, i64 %"#rec##0", 0 + %12 = insertvalue {i64, i1} %11, i1 0, 1 + ret {i64, i1} %12 +} + + +define external fastcc i64 @"tcmc_mutates_in_wrong_order2.null<0>"() { +entry: + ret i64 0 +} + + +define external fastcc void @"tcmc_mutates_in_wrong_order2.print_list<0>"(i64 %"a##0") { +entry: + %0 = icmp ne i64 %"a##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = inttoptr i64 %"a##0" to i64* + %2 = load i64, i64* %1 + %3 = add i64 %"a##0", 8 + %4 = inttoptr i64 %3 to i64* + %5 = load i64, i64* %4 + %6 = add i64 %"a##0", 16 + %7 = inttoptr i64 %6 to i64* + %8 = load i64, i64* %7 + tail call fastcc void @"wybe.string.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ({i64, i64}, {i64, i64}* @tcmc_mutates_in_wrong_order2.1, i32 0, i32 0) to i64)) + tail call ccc void @print_int(i64 %5) + tail call fastcc void @"wybe.string.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ({i64, i64}, {i64, i64}* @tcmc_mutates_in_wrong_order2.3, i32 0, i32 0) to i64)) + tail call ccc void @print_int(i64 %8) + tail call fastcc void @"wybe.string.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ({i64, i64}, {i64, i64}* @tcmc_mutates_in_wrong_order2.3, i32 0, i32 0) to i64)) + tail call fastcc void @"tcmc_mutates_in_wrong_order2.print_list<0>"(i64 %2) + musttail call fastcc void @"wybe.string.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ({i64, i64}, {i64, i64}* @tcmc_mutates_in_wrong_order2.5, i32 0, i32 0) to i64)) + ret void +if.else: + musttail call fastcc void @"wybe.string.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ({i64, i64}, {i64, i64}* @tcmc_mutates_in_wrong_order2.7, i32 0, i32 0) to i64)) + ret void +} + + +define external fastcc i64 @"tcmc_mutates_in_wrong_order2.snoc<0>"(i64 %"tail##0", i64 %"head1##0", i64 %"head2##0") { +entry: + %0 = trunc i64 24 to i32 + %1 = tail call ccc i8* @wybe_malloc(i32 %0) + %2 = ptrtoint i8* %1 to i64 + %3 = inttoptr i64 %2 to i64* + store i64 %"tail##0", i64* %3 + %4 = add i64 %2, 8 + %5 = inttoptr i64 %4 to i64* + store i64 %"head1##0", i64* %5 + %6 = add i64 %2, 16 + %7 = inttoptr i64 %6 to i64* + store i64 %"head2##0", i64* %7 + ret i64 %2 +} + + +define external fastcc {i64, i64, i64, i1} @"tcmc_mutates_in_wrong_order2.snoc<1>"(i64 %"#result##0") { +entry: + %0 = icmp ne i64 %"#result##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = inttoptr i64 %"#result##0" to i64* + %2 = load i64, i64* %1 + %3 = add i64 %"#result##0", 8 + %4 = inttoptr i64 %3 to i64* + %5 = load i64, i64* %4 + %6 = add i64 %"#result##0", 16 + %7 = inttoptr i64 %6 to i64* + %8 = load i64, i64* %7 + %9 = insertvalue {i64, i64, i64, i1} undef, i64 %2, 0 + %10 = insertvalue {i64, i64, i64, i1} %9, i64 %5, 1 + %11 = insertvalue {i64, i64, i64, i1} %10, i64 %8, 2 + %12 = insertvalue {i64, i64, i64, i1} %11, i1 1, 3 + ret {i64, i64, i64, i1} %12 +if.else: + %13 = insertvalue {i64, i64, i64, i1} undef, i64 undef, 0 + %14 = insertvalue {i64, i64, i64, i1} %13, i64 undef, 1 + %15 = insertvalue {i64, i64, i64, i1} %14, i64 undef, 2 + %16 = insertvalue {i64, i64, i64, i1} %15, i1 0, 3 + ret {i64, i64, i64, i1} %16 +} + + +define external fastcc {i64, i1} @"tcmc_mutates_in_wrong_order2.tail<0>"(i64 %"#rec##0") { +entry: + %0 = icmp ne i64 %"#rec##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = inttoptr i64 %"#rec##0" to i64* + %2 = load i64, i64* %1 + %3 = insertvalue {i64, i1} undef, i64 %2, 0 + %4 = insertvalue {i64, i1} %3, i1 1, 1 + ret {i64, i1} %4 +if.else: + %5 = insertvalue {i64, i1} undef, i64 undef, 0 + %6 = insertvalue {i64, i1} %5, i1 0, 1 + ret {i64, i1} %6 +} + + +define external fastcc {i64, i1} @"tcmc_mutates_in_wrong_order2.tail<1>"(i64 %"#rec##0", i64 %"#field##0") { +entry: + %0 = icmp ne i64 %"#rec##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = trunc i64 24 to i32 + %2 = tail call ccc i8* @wybe_malloc(i32 %1) + %3 = ptrtoint i8* %2 to i64 + %4 = inttoptr i64 %3 to i8* + %5 = inttoptr i64 %"#rec##0" to i8* + %6 = trunc i64 24 to i32 + tail call ccc void @llvm.memcpy.p0i8.p0i8.i32(i8* %4, i8* %5, i32 %6, i1 0) + %7 = inttoptr i64 %3 to i64* + store i64 %"#field##0", i64* %7 + %8 = insertvalue {i64, i1} undef, i64 %3, 0 + %9 = insertvalue {i64, i1} %8, i1 1, 1 + ret {i64, i1} %9 +if.else: + %10 = insertvalue {i64, i1} undef, i64 %"#rec##0", 0 + %11 = insertvalue {i64, i1} %10, i1 0, 1 + ret {i64, i1} %11 +} + + +define external fastcc i1 @"tcmc_mutates_in_wrong_order2.~=<0>"(i64 %"#left##0", i64 %"#right##0") { +entry: + %0 = tail call fastcc i1 @"tcmc_mutates_in_wrong_order2.=<0>"(i64 %"#left##0", i64 %"#right##0") + %1 = xor i1 %0, 1 + ret i1 %1 +} diff --git a/test-cases/final-dump/tcmc_mutates_in_wrong_order2.wybe b/test-cases/final-dump/tcmc_mutates_in_wrong_order2.wybe new file mode 100644 index 00000000..110c9a05 --- /dev/null +++ b/test-cases/final-dump/tcmc_mutates_in_wrong_order2.wybe @@ -0,0 +1,33 @@ +constructors null | snoc(tail: _, head1: int, head2: int) + +def append(a: _, b: _, ?result: _) { + if { snoc(?t, ?h, ?h2) = a :: + append(b, t, ?t2) + # mutate for val happens at the end. This breaks this optimization :(( + ?result = snoc(t2, h, h) + | else :: + ?result = b + } +} + +def print_list(a: _) use !io { + if { snoc(?tail, ?head, ?head2) = a :: + !print("node(") + !print(head) + !print(",") + !print(head2) + !print(",") + !print_list(tail) + !print(")") + | else :: + !print("null") + } + +} +?x = snoc(null, 1, 1) +?x2 = snoc(null, 2, 3) +append(x, x2, ?x3) +!print_list(x2) +!nl +!print_list(x3) +!nl \ No newline at end of file diff --git a/test-cases/final-dump/tcmc_partition.exp b/test-cases/final-dump/tcmc_partition.exp new file mode 100644 index 00000000..58704c61 --- /dev/null +++ b/test-cases/final-dump/tcmc_partition.exp @@ -0,0 +1,349 @@ +====================================================================== +AFTER EVERYTHING: + Module tcmc_partition + representation : (not a type) + public submods : + public resources: + public procs : tcmc_partition.<0> + imports : use wybe + resources : + procs : + +module top-level code > public {impure} (0 calls) +0: tcmc_partition.<0> +()<{<>}; {<>}>: + AliasPairs: [] + InterestingCallProperties: [] + MultiSpeczDepInfo: [(10,(tcmc_partition.partition<0>,fromList [NonAliasedParamCond 1 []]))] + foreign lpvm alloc(16:wybe.int, ?tmp#14##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#14##0:wybe.list(T), ?tmp#15##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 7:T) @list:nn:nn + foreign lpvm mutate(~tmp#15##0:wybe.list(T), ?tmp#7##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#18##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#18##0:wybe.list(T), ?tmp#19##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 6:T) @list:nn:nn + foreign lpvm mutate(~tmp#19##0:wybe.list(T), ?tmp#6##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#7##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#22##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#22##0:wybe.list(T), ?tmp#23##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 5:T) @list:nn:nn + foreign lpvm mutate(~tmp#23##0:wybe.list(T), ?tmp#5##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#6##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#26##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#26##0:wybe.list(T), ?tmp#27##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 4:T) @list:nn:nn + foreign lpvm mutate(~tmp#27##0:wybe.list(T), ?tmp#4##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#5##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#30##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#30##0:wybe.list(T), ?tmp#31##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 3:T) @list:nn:nn + foreign lpvm mutate(~tmp#31##0:wybe.list(T), ?tmp#3##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#4##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#34##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#34##0:wybe.list(T), ?tmp#35##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 9:T) @list:nn:nn + foreign lpvm mutate(~tmp#35##0:wybe.list(T), ?tmp#2##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#3##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#38##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#38##0:wybe.list(T), ?tmp#39##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 2:T) @list:nn:nn + foreign lpvm mutate(~tmp#39##0:wybe.list(T), ?tmp#1##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#2##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#42##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#42##0:wybe.list(T), ?tmp#43##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 1:T) @list:nn:nn + foreign lpvm mutate(~tmp#43##0:wybe.list(T), ?tmp#0##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#1##0:wybe.list(T)) @list:nn:nn + wybe.list.print<0>(tcmc_partition.gen#1<0><>:{resource}(T), tmp#0##0:wybe.list(T)) #15 @list:nn:nn + foreign lpvm load(<>:wybe.phantom, ?%tmp#46##0:wybe.phantom) @io:nn:nn + foreign c putchar('\n':wybe.char, ~tmp#46##0:wybe.phantom, ?tmp#47##0:wybe.phantom) @io:nn:nn + foreign lpvm store(~%tmp#47##0:wybe.phantom, <>:wybe.phantom) @io:nn:nn + tcmc_partition.partition<0>[6dacb8fd25](tcmc_partition.gen#2<1><>:(wybe.int, ?wybe.bool), ~tmp#0##0:wybe.list(wybe.int), outByReference yes##0:wybe.list(wybe.int), outByReference no##0:wybe.list(wybe.int)) #10 @tcmc_partition:nn:nn + wybe.list.print<0>(tcmc_partition.gen#1<0><>:{resource}(wybe.int), ~yes##0:wybe.list(wybe.int)) #11 @tcmc_partition:nn:nn + wybe.string.print<0>(", ":wybe.string)<{<>}; {<>}> #12 @tcmc_partition:nn:nn + wybe.list.print<0>(tcmc_partition.gen#1<0><>:{resource}(wybe.int), ~no##0:wybe.list(wybe.int)) #13 @tcmc_partition:nn:nn + foreign lpvm load(<>:wybe.phantom, ?%tmp#48##0:wybe.phantom) @io:nn:nn + foreign c putchar('\n':wybe.char, ~tmp#48##0:wybe.phantom, ?tmp#49##0:wybe.phantom) @io:nn:nn + foreign lpvm store(~%tmp#49##0:wybe.phantom, <>:wybe.phantom) @io:nn:nn + + +gen#1 > {inline} (3 calls) +0: tcmc_partition.gen#1<0> +gen#1(x##0:wybe.int)<{<>}; {<>}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign lpvm load(<>:wybe.phantom, ?%tmp#1##0:wybe.phantom) @int:nn:nn + foreign c print_int(~x##0:wybe.int, ~tmp#1##0:wybe.phantom, ?tmp#2##0:wybe.phantom) @int:nn:nn + foreign lpvm store(~%tmp#2##0:wybe.phantom, <>:wybe.phantom) @int:nn:nn + + +gen#2 > {inline} (1 calls) +0: tcmc_partition.gen#2<0> +gen#2(anon#1#1##0:wybe.int, ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_sge(~anon#1#1##0:wybe.int, 3:wybe.int, ?#success##0:wybe.bool) @int:nn:nn +gen#2 > {inline} (1 calls) +1: tcmc_partition.gen#2<1> +gen#2(anon#1#1##0:wybe.int, ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_sge(~anon#1#1##0:wybe.int, 3:wybe.int, ?#success##0:wybe.bool) @int:nn:nn + + +partition > (3 calls) +0: tcmc_partition.partition<0>[6dacb8fd25] +partition(p##0:(T, ?wybe.bool), l##0:wybe.list(T), outByReference yes##0:wybe.list(T), outByReference no##0:wybe.list(T))<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [InterestingUnaliased 1] + MultiSpeczDepInfo: [(2,(tcmc_partition.partition<0>,fromList [NonAliasedParamCond 1 [1]])),(4,(tcmc_partition.partition<0>,fromList [NonAliasedParamCond 1 [1]]))] + foreign llvm icmp_ne(l##0:wybe.int, 0:wybe.int, ?tmp#7##0:wybe.bool) + case ~tmp#7##0:wybe.bool of + 0: + foreign llvm move(0:wybe.list(T), ?yes##0:wybe.list(T)) @tcmc_partition:nn:nn + foreign llvm move(0:wybe.list(T), ?no##0:wybe.list(T)) @tcmc_partition:nn:nn + + 1: + foreign lpvm access(l##0:wybe.list(T), 0:wybe.int, 16:wybe.int, 0:wybe.int, ?h##0:T) @list:nn:nn + foreign lpvm access(~l##0:wybe.list(T), 8:wybe.int, 16:wybe.int, 0:wybe.int, ?t##0:wybe.list(T)) @list:nn:nn + p##0:(T, ?wybe.bool)(h##0:T, ?tmp#4##0:wybe.bool) #1 @tcmc_partition:nn:nn + case ~tmp#4##0:wybe.bool of + 0: + foreign lpvm alloc(16:wybe.int, ?tmp#10##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#10##0:wybe.list(T), ?tmp#11##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~h##0:T) @list:nn:nn + tcmc_partition.partition<0>(~p##0:(T, ?wybe.bool), ~t##0:wybe.list(T), outByReference yes##0:wybe.list(T), outByReference no0##0:wybe.list(T)) #4 @tcmc_partition:nn:nn + foreign lpvm mutate(~tmp#11##0:wybe.list(T), ?no##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference no0##0:wybe.list(T)) @list:nn:nn + + 1: + foreign lpvm alloc(16:wybe.int, ?tmp#10##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#10##0:wybe.list(T), ?tmp#11##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~h##0:T) @list:nn:nn + tcmc_partition.partition<0>(~p##0:(T, ?wybe.bool), ~t##0:wybe.list(T), outByReference yes0##0:wybe.list(T), outByReference no##0:wybe.list(T)) #2 @tcmc_partition:nn:nn + foreign lpvm mutate(~tmp#11##0:wybe.list(T), ?yes##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference yes0##0:wybe.list(T)) @list:nn:nn + + + [6dacb8fd25] [NonAliasedParam 1] : + foreign llvm icmp_ne(l##0:wybe.int, 0:wybe.int, ?tmp#7##0:wybe.bool) + case ~tmp#7##0:wybe.bool of + 0: + foreign llvm move(0:wybe.list(T), ?yes##0:wybe.list(T)) @tcmc_partition:nn:nn + foreign llvm move(0:wybe.list(T), ?no##0:wybe.list(T)) @tcmc_partition:nn:nn + + 1: + foreign lpvm access(l##0:wybe.list(T), 0:wybe.int, 16:wybe.int, 0:wybe.int, ?h##0:T) @list:nn:nn + foreign lpvm access(l##0:wybe.list(T), 8:wybe.int, 16:wybe.int, 0:wybe.int, ?t##0:wybe.list(T)) @list:nn:nn + p##0:(T, ?wybe.bool)(~h##0:T, ?tmp#4##0:wybe.bool) #1 @tcmc_partition:nn:nn + case ~tmp#4##0:wybe.bool of + 0: + tcmc_partition.partition<0>[6dacb8fd25](~p##0:(T, ?wybe.bool), ~t##0:wybe.list(T), outByReference yes##0:wybe.list(T), outByReference no0##0:wybe.list(T)) #4 @tcmc_partition:nn:nn + foreign lpvm mutate(~l##0:wybe.list(T), ?no##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference no0##0:wybe.list(T)) @list:nn:nn + + 1: + tcmc_partition.partition<0>[6dacb8fd25](~p##0:(T, ?wybe.bool), ~t##0:wybe.list(T), outByReference yes0##0:wybe.list(T), outByReference no##0:wybe.list(T)) #2 @tcmc_partition:nn:nn + foreign lpvm mutate(~l##0:wybe.list(T), ?yes##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference yes0##0:wybe.list(T)) @list:nn:nn + + + + LLVM code : + +; ModuleID = 'tcmc_partition' + + + + + +@tcmc_partition.3 = constant {i64, i64} { i64 2, i64 ptrtoint ([?? x i8]* @tcmc_partition.2 to i64) } + + +@tcmc_partition.2 = constant [?? x i8] c", \00" + + +@tcmc_partition.0 = constant [1 x i64] [i64 ptrtoint (void (i64, i64)* @"tcmc_partition.gen#1<0>" to i64)] + + +@tcmc_partition.1 = constant [1 x i64] [i64 ptrtoint (i64 (i64, i64)* @"tcmc_partition.gen#2<1>" to i64)] + + +declare external ccc void @print_int(i64) + + +declare external ccc void @putchar(i8) + + +declare external fastcc void @"wybe.list.print<0>"(i64, i64) + + +declare external fastcc void @"wybe.string.print<0>"(i64) + + +declare external ccc i8* @wybe_malloc(i32) + + +declare external ccc void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1) + + +define external fastcc void @"tcmc_partition.<0>"() { +entry: + %0 = trunc i64 16 to i32 + %1 = tail call ccc i8* @wybe_malloc(i32 %0) + %2 = ptrtoint i8* %1 to i64 + %3 = inttoptr i64 %2 to i64* + store i64 7, i64* %3 + %4 = add i64 %2, 8 + %5 = inttoptr i64 %4 to i64* + store i64 0, i64* %5 + %6 = trunc i64 16 to i32 + %7 = tail call ccc i8* @wybe_malloc(i32 %6) + %8 = ptrtoint i8* %7 to i64 + %9 = inttoptr i64 %8 to i64* + store i64 6, i64* %9 + %10 = add i64 %8, 8 + %11 = inttoptr i64 %10 to i64* + store i64 %2, i64* %11 + %12 = trunc i64 16 to i32 + %13 = tail call ccc i8* @wybe_malloc(i32 %12) + %14 = ptrtoint i8* %13 to i64 + %15 = inttoptr i64 %14 to i64* + store i64 5, i64* %15 + %16 = add i64 %14, 8 + %17 = inttoptr i64 %16 to i64* + store i64 %8, i64* %17 + %18 = trunc i64 16 to i32 + %19 = tail call ccc i8* @wybe_malloc(i32 %18) + %20 = ptrtoint i8* %19 to i64 + %21 = inttoptr i64 %20 to i64* + store i64 4, i64* %21 + %22 = add i64 %20, 8 + %23 = inttoptr i64 %22 to i64* + store i64 %14, i64* %23 + %24 = trunc i64 16 to i32 + %25 = tail call ccc i8* @wybe_malloc(i32 %24) + %26 = ptrtoint i8* %25 to i64 + %27 = inttoptr i64 %26 to i64* + store i64 3, i64* %27 + %28 = add i64 %26, 8 + %29 = inttoptr i64 %28 to i64* + store i64 %20, i64* %29 + %30 = trunc i64 16 to i32 + %31 = tail call ccc i8* @wybe_malloc(i32 %30) + %32 = ptrtoint i8* %31 to i64 + %33 = inttoptr i64 %32 to i64* + store i64 9, i64* %33 + %34 = add i64 %32, 8 + %35 = inttoptr i64 %34 to i64* + store i64 %26, i64* %35 + %36 = trunc i64 16 to i32 + %37 = tail call ccc i8* @wybe_malloc(i32 %36) + %38 = ptrtoint i8* %37 to i64 + %39 = inttoptr i64 %38 to i64* + store i64 2, i64* %39 + %40 = add i64 %38, 8 + %41 = inttoptr i64 %40 to i64* + store i64 %32, i64* %41 + %42 = trunc i64 16 to i32 + %43 = tail call ccc i8* @wybe_malloc(i32 %42) + %44 = ptrtoint i8* %43 to i64 + %45 = inttoptr i64 %44 to i64* + store i64 1, i64* %45 + %46 = add i64 %44, 8 + %47 = inttoptr i64 %46 to i64* + store i64 %38, i64* %47 + tail call fastcc void @"wybe.list.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ([1 x i64], [1 x i64]* @tcmc_partition.0, i32 0, i32 0) to i64), i64 %44) + tail call ccc void @putchar(i8 10) + %48 = alloca i64 + %49 = alloca i64 + call fastcc void @"tcmc_partition.partition<0>[6dacb8fd25]"(i64 ptrtoint (i64* getelementptr inbounds ([1 x i64], [1 x i64]* @tcmc_partition.1, i32 0, i32 0) to i64), i64 %44, i64* %48, i64* %49) + %50 = load i64, i64* %48 + %51 = load i64, i64* %49 + tail call fastcc void @"wybe.list.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ([1 x i64], [1 x i64]* @tcmc_partition.0, i32 0, i32 0) to i64), i64 %50) + tail call fastcc void @"wybe.string.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ({i64, i64}, {i64, i64}* @tcmc_partition.3, i32 0, i32 0) to i64)) + tail call fastcc void @"wybe.list.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ([1 x i64], [1 x i64]* @tcmc_partition.0, i32 0, i32 0) to i64), i64 %51) + tail call ccc void @putchar(i8 10) + ret void +} + + +define external fastcc void @"tcmc_partition.gen#1<0>"(i64 %"#env##0", i64 %"x##0") { +entry: + tail call ccc void @print_int(i64 %"x##0") + ret void +} + + +define external fastcc i1 @"tcmc_partition.gen#2<0>"(i64 %"anon#1#1##0") { +entry: + %0 = icmp sge i64 %"anon#1#1##0", 3 + ret i1 %0 +} + + +define external fastcc i64 @"tcmc_partition.gen#2<1>"(i64 %"#env##0", i64 %"anon#1#1##0") { +entry: + %0 = icmp sge i64 %"anon#1#1##0", 3 + %1 = zext i1 %0 to i64 + ret i64 %1 +} + + +define external fastcc void @"tcmc_partition.partition<0>"(i64 %"p##0", i64 %"l##0", i64* %"yes#ref##0", i64* %"no#ref##0") { +entry: + %0 = icmp ne i64 %"l##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = inttoptr i64 %"l##0" to i64* + %2 = load i64, i64* %1 + %3 = add i64 %"l##0", 8 + %4 = inttoptr i64 %3 to i64* + %5 = load i64, i64* %4 + %6 = inttoptr i64 %"p##0" to i64* + %7 = load i64, i64* %6 + %8 = inttoptr i64 %7 to i64 (i64, i64)* + %9 = tail call fastcc i64 %8(i64 %"p##0", i64 %2) + %10 = trunc i64 %9 to i1 + br i1 %10, label %if.then1, label %if.else1 +if.else: + store i64 0, i64* %"yes#ref##0" + store i64 0, i64* %"no#ref##0" + ret void +if.then1: + %11 = trunc i64 16 to i32 + %12 = tail call ccc i8* @wybe_malloc(i32 %11) + %13 = ptrtoint i8* %12 to i64 + %14 = inttoptr i64 %13 to i64* + store i64 %2, i64* %14 + %15 = add i64 %13, 8 + %16 = inttoptr i64 %15 to i64* + store i64 %13, i64* %"yes#ref##0" + musttail call fastcc void @"tcmc_partition.partition<0>"(i64 %"p##0", i64 %5, i64* %16, i64* %"no#ref##0") + ret void +if.else1: + %17 = trunc i64 16 to i32 + %18 = tail call ccc i8* @wybe_malloc(i32 %17) + %19 = ptrtoint i8* %18 to i64 + %20 = inttoptr i64 %19 to i64* + store i64 %2, i64* %20 + %21 = add i64 %19, 8 + %22 = inttoptr i64 %21 to i64* + store i64 %19, i64* %"no#ref##0" + musttail call fastcc void @"tcmc_partition.partition<0>"(i64 %"p##0", i64 %5, i64* %"yes#ref##0", i64* %22) + ret void +} + + +define external fastcc void @"tcmc_partition.partition<0>[6dacb8fd25]"(i64 %"p##0", i64 %"l##0", i64* %"yes#ref##0", i64* %"no#ref##0") { +entry: + %0 = icmp ne i64 %"l##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = inttoptr i64 %"l##0" to i64* + %2 = load i64, i64* %1 + %3 = add i64 %"l##0", 8 + %4 = inttoptr i64 %3 to i64* + %5 = load i64, i64* %4 + %6 = inttoptr i64 %"p##0" to i64* + %7 = load i64, i64* %6 + %8 = inttoptr i64 %7 to i64 (i64, i64)* + %9 = tail call fastcc i64 %8(i64 %"p##0", i64 %2) + %10 = trunc i64 %9 to i1 + br i1 %10, label %if.then1, label %if.else1 +if.else: + store i64 0, i64* %"yes#ref##0" + store i64 0, i64* %"no#ref##0" + ret void +if.then1: + %11 = add i64 %"l##0", 8 + %12 = inttoptr i64 %11 to i64* + store i64 %"l##0", i64* %"yes#ref##0" + musttail call fastcc void @"tcmc_partition.partition<0>[6dacb8fd25]"(i64 %"p##0", i64 %5, i64* %12, i64* %"no#ref##0") + ret void +if.else1: + %13 = add i64 %"l##0", 8 + %14 = inttoptr i64 %13 to i64* + store i64 %"l##0", i64* %"no#ref##0" + musttail call fastcc void @"tcmc_partition.partition<0>[6dacb8fd25]"(i64 %"p##0", i64 %5, i64* %"yes#ref##0", i64* %14) + ret void +} diff --git a/test-cases/final-dump/tcmc_partition.wybe b/test-cases/final-dump/tcmc_partition.wybe new file mode 100644 index 00000000..b067a894 --- /dev/null +++ b/test-cases/final-dump/tcmc_partition.wybe @@ -0,0 +1,33 @@ +# tests that this implementation of `partition` gets TCMC-optimized. + +def partition(p: {test}(T), l: list(T), ?yes: list(T), ?no: list(T)) { + if { [?h | ?t] = l :: + # XXX: this doesn't optimize when `partition` + # is hoisted above the if/else: + # + # partition(p, t, ?yes0, ?no0) + # + # since the current implementation only looks for + # last-calls in "leaves" of the proc body + if { p(h) :: + partition(p, t, ?yes0, ?no0) + ?yes = [h|yes0] + ?no = no0 + | else :: + partition(p, t, ?yes0, ?no0) + ?yes = yes0 + ?no = [h|no0] + } + | else :: + ?yes = [] + ?no = [] + } +} + +?l = [1,2,9,3,4,5,6,7] +!println(print, l) +partition({test} { @1 >= 3}, l, ?yes, ?no) +!print(print, yes) +!print(", ") +!print(print, no) +!nl \ No newline at end of file diff --git a/test-cases/final-dump/tcmc_partition_params_args_mismatch.exp b/test-cases/final-dump/tcmc_partition_params_args_mismatch.exp new file mode 100644 index 00000000..5976d1f1 --- /dev/null +++ b/test-cases/final-dump/tcmc_partition_params_args_mismatch.exp @@ -0,0 +1,88 @@ +====================================================================== +AFTER EVERYTHING: + Module tcmc_partition_params_args_mismatch + representation : (not a type) + public submods : + public resources: + public procs : + imports : use wybe + resources : + procs : + +partition > (1 calls) +0: tcmc_partition_params_args_mismatch.partition<0> +partition(p##0:(T, ?wybe.bool), l##0:wybe.list(T), outByReference yes##0:wybe.list(T), ?no##0:wybe.list(T))<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [InterestingUnaliased 1] + MultiSpeczDepInfo: [(2,(tcmc_partition_params_args_mismatch.partition<0>,fromList [NonAliasedParamCond 1 [1]]))] + foreign llvm icmp_ne(l##0:wybe.int, 0:wybe.int, ?tmp#8##0:wybe.bool) + case ~tmp#8##0:wybe.bool of + 0: + foreign llvm move(0:wybe.list(T), ?yes##0:wybe.list(T)) @tcmc_partition_params_args_mismatch:nn:nn + foreign llvm move(0:wybe.list(T), ?no##0:wybe.list(T)) @tcmc_partition_params_args_mismatch:nn:nn + + 1: + foreign lpvm access(l##0:wybe.list(T), 0:wybe.int, 16:wybe.int, 0:wybe.int, ?h##0:T) @list:nn:nn + foreign lpvm access(~l##0:wybe.list(T), 8:wybe.int, 16:wybe.int, 0:wybe.int, ?t##0:wybe.list(T)) @list:nn:nn + p##0:(T, ?wybe.bool)(h##0:T, ?tmp#5##0:wybe.bool) #1 @tcmc_partition_params_args_mismatch:nn:nn + case ~tmp#5##0:wybe.bool of + 0: + foreign llvm move(0:wybe.list(T), ?yes##0:wybe.list(T)) @tcmc_partition_params_args_mismatch:nn:nn + foreign llvm move(0:wybe.list(T), ?no##0:wybe.list(T)) @tcmc_partition_params_args_mismatch:nn:nn + + 1: + foreign lpvm alloc(16:wybe.int, ?tmp#11##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#11##0:wybe.list(T), ?tmp#12##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~h##0:T) @list:nn:nn + tcmc_partition_params_args_mismatch.partition<0>(~p##0:(T, ?wybe.bool), ~t##0:wybe.list(T), outByReference yes0##0:wybe.list(T), ?yes##0:wybe.list(T)) #2 @tcmc_partition_params_args_mismatch:nn:nn + foreign lpvm mutate(~tmp#12##0:wybe.list(T), ?no##0:wybe.list(T), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference yes0##0:wybe.list(T)) @list:nn:nn + + + + LLVM code : + +; ModuleID = 'tcmc_partition_params_args_mismatch' + + + + + +declare external ccc i8* @wybe_malloc(i32) + + +declare external ccc void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1) + + +define external fastcc i64 @"tcmc_partition_params_args_mismatch.partition<0>"(i64 %"p##0", i64 %"l##0", i64* %"yes#ref##0") { +entry: + %0 = icmp ne i64 %"l##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = inttoptr i64 %"l##0" to i64* + %2 = load i64, i64* %1 + %3 = add i64 %"l##0", 8 + %4 = inttoptr i64 %3 to i64* + %5 = load i64, i64* %4 + %6 = inttoptr i64 %"p##0" to i64* + %7 = load i64, i64* %6 + %8 = inttoptr i64 %7 to i64 (i64, i64)* + %9 = tail call fastcc i64 %8(i64 %"p##0", i64 %2) + %10 = trunc i64 %9 to i1 + br i1 %10, label %if.then1, label %if.else1 +if.else: + store i64 0, i64* %"yes#ref##0" + ret i64 0 +if.then1: + %11 = trunc i64 16 to i32 + %12 = tail call ccc i8* @wybe_malloc(i32 %11) + %13 = ptrtoint i8* %12 to i64 + %14 = inttoptr i64 %13 to i64* + store i64 %2, i64* %14 + %15 = add i64 %13, 8 + %16 = inttoptr i64 %15 to i64* + %17 = tail call fastcc i64 @"tcmc_partition_params_args_mismatch.partition<0>"(i64 %"p##0", i64 %5, i64* %16) + store i64 %17, i64* %"yes#ref##0" + ret i64 %13 +if.else1: + store i64 0, i64* %"yes#ref##0" + ret i64 0 +} diff --git a/test-cases/final-dump/tcmc_partition_params_args_mismatch.wybe b/test-cases/final-dump/tcmc_partition_params_args_mismatch.wybe new file mode 100644 index 00000000..30bf66f4 --- /dev/null +++ b/test-cases/final-dump/tcmc_partition_params_args_mismatch.wybe @@ -0,0 +1,25 @@ +def partition(p: {test}(T), l: list(T), ?yes: list(T), ?no: list(T)) { + if { [?h | ?t] = l :: + if { p(h) :: + # here we expect the 2nd argument to become "outByReference" + # but that means that this call isn't actually tail recursive + # since we need to store `no` after the call. + # What can we do about this? + # 1. Could take the union of args + results from mutate graph, + # in this case that would mean we make both `yes` and `no` + # outByReference + # 2. Or we make codegen not mark this call with `musttail` (but + # then the function essentially doesn't get optimized) + # + # Currently I have implemented option #2 + partition(p, t, ?yes0, ?yes) + ?no = [h|yes0] + | else :: + ?yes = [] + ?no = [] + } + | else :: + ?yes = [] + ?no = [] + } +} \ No newline at end of file diff --git a/test-cases/final-dump/tcmc_unrolled_map.exp b/test-cases/final-dump/tcmc_unrolled_map.exp new file mode 100644 index 00000000..67c00bab --- /dev/null +++ b/test-cases/final-dump/tcmc_unrolled_map.exp @@ -0,0 +1,348 @@ +====================================================================== +AFTER EVERYTHING: + Module tcmc_unrolled_map + representation : (not a type) + public submods : + public resources: + public procs : tcmc_unrolled_map.<0> + imports : use wybe + resources : + procs : + +module top-level code > public {impure} (0 calls) +0: tcmc_unrolled_map.<0> +()<{<>}; {<>}>: + AliasPairs: [] + InterestingCallProperties: [] + MultiSpeczDepInfo: [(6,(tcmc_unrolled_map.map2<0>,fromList [NonAliasedParamCond 1 []]))] + foreign lpvm alloc(16:wybe.int, ?tmp#10##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#10##0:wybe.list(T), ?tmp#11##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 5:T) @list:nn:nn + foreign lpvm mutate(~tmp#11##0:wybe.list(T), ?tmp#5##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#14##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#14##0:wybe.list(T), ?tmp#15##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 4:T) @list:nn:nn + foreign lpvm mutate(~tmp#15##0:wybe.list(T), ?tmp#4##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#5##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#18##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#18##0:wybe.list(T), ?tmp#19##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 3:T) @list:nn:nn + foreign lpvm mutate(~tmp#19##0:wybe.list(T), ?tmp#3##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#4##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#22##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#22##0:wybe.list(T), ?tmp#23##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 2:T) @list:nn:nn + foreign lpvm mutate(~tmp#23##0:wybe.list(T), ?tmp#2##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#3##0:wybe.list(T)) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#26##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#26##0:wybe.list(T), ?tmp#27##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 1:T) @list:nn:nn + foreign lpvm mutate(~tmp#27##0:wybe.list(T), ?tmp#1##0:wybe.list(wybe.int), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#2##0:wybe.list(T)) @list:nn:nn + tcmc_unrolled_map.map2<0>[6dacb8fd25](tcmc_unrolled_map.gen#1<1><>:(wybe.int, ?wybe.int), ~tmp#1##0:wybe.list(wybe.int), outByReference y##0:wybe.list(wybe.int)) #6 @tcmc_unrolled_map:nn:nn + wybe.list.print<0>(tcmc_unrolled_map.gen#2<0><>:{resource}(T), ~y##0:wybe.list(T)) #8 @list:nn:nn + foreign lpvm load(<>:wybe.phantom, ?%tmp#30##0:wybe.phantom) @io:nn:nn + foreign c putchar('\n':wybe.char, ~tmp#30##0:wybe.phantom, ?tmp#31##0:wybe.phantom) @io:nn:nn + foreign lpvm store(~%tmp#31##0:wybe.phantom, <>:wybe.phantom) @io:nn:nn + + +gen#1 > {inline} (1 calls) +0: tcmc_unrolled_map.gen#1<0> +gen#1(anon#1#1##0:wybe.int, ?anon#1#2##0:wybe.int)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm add(~anon#1#1##0:wybe.int, 1:wybe.int, ?anon#1#2##0:wybe.int) @int:nn:nn +gen#1 > {inline} (1 calls) +1: tcmc_unrolled_map.gen#1<1> +gen#1(anon#1#1##0:wybe.int, ?anon#1#2##0:wybe.int)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm add(~anon#1#1##0:wybe.int, 1:wybe.int, ?anon#1#2##0:wybe.int) @int:nn:nn + + +gen#2 > {inline} (1 calls) +0: tcmc_unrolled_map.gen#2<0> +gen#2(x##0:wybe.int)<{<>}; {<>}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign lpvm load(<>:wybe.phantom, ?%tmp#1##0:wybe.phantom) @int:nn:nn + foreign c print_int(~x##0:wybe.int, ~tmp#1##0:wybe.phantom, ?tmp#2##0:wybe.phantom) @int:nn:nn + foreign lpvm store(~%tmp#2##0:wybe.phantom, <>:wybe.phantom) @int:nn:nn + + +map2 > (2 calls) +0: tcmc_unrolled_map.map2<0>[6dacb8fd25] +map2(f##0:(T, ?K), x##0:wybe.list(T), outByReference #result##0:wybe.list(K))<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [InterestingUnaliased 1] + MultiSpeczDepInfo: [(4,(tcmc_unrolled_map.map2<0>,fromList [NonAliasedParamCond 1 [1]]))] + foreign llvm icmp_ne(x##0:wybe.int, 0:wybe.int, ?tmp#14##0:wybe.bool) + case ~tmp#14##0:wybe.bool of + 0: + foreign llvm move(0:wybe.list(K), ?#result##0:wybe.list(K)) @tcmc_unrolled_map:nn:nn + + 1: + foreign lpvm access(x##0:wybe.list(T), 0:wybe.int, 16:wybe.int, 0:wybe.int, ?x0##0:T) @list:nn:nn + foreign lpvm access(~x##0:wybe.list(T), 8:wybe.int, 16:wybe.int, 0:wybe.int, ?xt1##0:wybe.list(T)) @list:nn:nn + foreign llvm icmp_ne(xt1##0:wybe.int, 0:wybe.int, ?tmp#16##0:wybe.bool) + case ~tmp#16##0:wybe.bool of + 0: + ~f##0:(T, ?K)(~x0##0:T, ?tmp#8##0:K) #7 @tcmc_unrolled_map:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#19##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#19##0:wybe.list(T), ?tmp#20##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#8##0:T) @list:nn:nn + foreign lpvm mutate(~tmp#20##0:wybe.list(T), ?#result##0:wybe.list(K), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 0:wybe.list(T)) @list:nn:nn + + 1: + foreign lpvm access(xt1##0:wybe.list(T), 0:wybe.int, 16:wybe.int, 0:wybe.int, ?x1##0:T) @list:nn:nn + foreign lpvm access(~xt1##0:wybe.list(T), 8:wybe.int, 16:wybe.int, 0:wybe.int, ?xt2##0:wybe.list(T)) @list:nn:nn + f##0:(T, ?K)(~x0##0:T, ?tmp#3##0:K) #2 @tcmc_unrolled_map:nn:nn + f##0:(T, ?K)(~x1##0:T, ?tmp#5##0:K) #3 @tcmc_unrolled_map:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#19##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#19##0:wybe.list(T), ?tmp#20##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#5##0:T) @list:nn:nn + foreign lpvm alloc(16:wybe.int, ?tmp#23##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#23##0:wybe.list(T), ?tmp#24##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#3##0:T) @list:nn:nn + tcmc_unrolled_map.map2<0>(~f##0:(T, ?K), ~xt2##0:wybe.list(T), outByReference tmp#6##0:wybe.list(K)) #4 @tcmc_unrolled_map:nn:nn + foreign lpvm mutate(~tmp#20##0:wybe.list(T), outByReference tmp#4##0:wybe.list(K), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference tmp#6##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#24##0:wybe.list(T), ?#result##0:wybe.list(K), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference tmp#4##0:wybe.list(T)) @list:nn:nn + + + [6dacb8fd25] [NonAliasedParam 1] : + foreign llvm icmp_ne(x##0:wybe.int, 0:wybe.int, ?tmp#14##0:wybe.bool) + case ~tmp#14##0:wybe.bool of + 0: + foreign llvm move(0:wybe.list(K), ?#result##0:wybe.list(K)) @tcmc_unrolled_map:nn:nn + + 1: + foreign lpvm access(x##0:wybe.list(T), 0:wybe.int, 16:wybe.int, 0:wybe.int, ?x0##0:T) @list:nn:nn + foreign lpvm access(x##0:wybe.list(T), 8:wybe.int, 16:wybe.int, 0:wybe.int, ?xt1##0:wybe.list(T)) @list:nn:nn + foreign llvm icmp_ne(xt1##0:wybe.int, 0:wybe.int, ?tmp#16##0:wybe.bool) + case ~tmp#16##0:wybe.bool of + 0: + ~f##0:(T, ?K)(~x0##0:T, ?tmp#8##0:K) #7 @tcmc_unrolled_map:nn:nn + foreign lpvm mutate(~x##0:wybe.list(T), ?tmp#20##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#8##0:T) @list:nn:nn + foreign lpvm mutate(~tmp#20##0:wybe.list(T), ?#result##0:wybe.list(K), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, 0:wybe.list(T)) @list:nn:nn + + 1: + foreign lpvm access(xt1##0:wybe.list(T), 0:wybe.int, 16:wybe.int, 0:wybe.int, ?x1##0:T) @list:nn:nn + foreign lpvm access(xt1##0:wybe.list(T), 8:wybe.int, 16:wybe.int, 0:wybe.int, ?xt2##0:wybe.list(T)) @list:nn:nn + f##0:(T, ?K)(~x0##0:T, ?tmp#3##0:K) #2 @tcmc_unrolled_map:nn:nn + f##0:(T, ?K)(~x1##0:T, ?tmp#5##0:K) #3 @tcmc_unrolled_map:nn:nn + foreign lpvm mutate(~xt1##0:wybe.list(T), ?tmp#20##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#5##0:T) @list:nn:nn + foreign lpvm mutate(~x##0:wybe.list(T), ?tmp#24##0:wybe.list(T), 0:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~tmp#3##0:T) @list:nn:nn + tcmc_unrolled_map.map2<0>[6dacb8fd25](~f##0:(T, ?K), ~xt2##0:wybe.list(T), outByReference tmp#6##0:wybe.list(K)) #4 @tcmc_unrolled_map:nn:nn + foreign lpvm mutate(~tmp#20##0:wybe.list(T), outByReference tmp#4##0:wybe.list(K), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference tmp#6##0:wybe.list(T)) @list:nn:nn + foreign lpvm mutate(~tmp#24##0:wybe.list(T), ?#result##0:wybe.list(K), 8:wybe.int, 1:wybe.int, 16:wybe.int, 0:wybe.int, ~takeReference tmp#4##0:wybe.list(T)) @list:nn:nn + + + + LLVM code : + +; ModuleID = 'tcmc_unrolled_map' + + + + + +@tcmc_unrolled_map.1 = constant [1 x i64] [i64 ptrtoint (void (i64, i64)* @"tcmc_unrolled_map.gen#2<0>" to i64)] + + +@tcmc_unrolled_map.0 = constant [1 x i64] [i64 ptrtoint (i64 (i64, i64)* @"tcmc_unrolled_map.gen#1<1>" to i64)] + + +declare external ccc void @print_int(i64) + + +declare external ccc void @putchar(i8) + + +declare external fastcc void @"wybe.list.print<0>"(i64, i64) + + +declare external ccc i8* @wybe_malloc(i32) + + +declare external ccc void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1) + + +define external fastcc void @"tcmc_unrolled_map.<0>"() { +entry: + %0 = trunc i64 16 to i32 + %1 = tail call ccc i8* @wybe_malloc(i32 %0) + %2 = ptrtoint i8* %1 to i64 + %3 = inttoptr i64 %2 to i64* + store i64 5, i64* %3 + %4 = add i64 %2, 8 + %5 = inttoptr i64 %4 to i64* + store i64 0, i64* %5 + %6 = trunc i64 16 to i32 + %7 = tail call ccc i8* @wybe_malloc(i32 %6) + %8 = ptrtoint i8* %7 to i64 + %9 = inttoptr i64 %8 to i64* + store i64 4, i64* %9 + %10 = add i64 %8, 8 + %11 = inttoptr i64 %10 to i64* + store i64 %2, i64* %11 + %12 = trunc i64 16 to i32 + %13 = tail call ccc i8* @wybe_malloc(i32 %12) + %14 = ptrtoint i8* %13 to i64 + %15 = inttoptr i64 %14 to i64* + store i64 3, i64* %15 + %16 = add i64 %14, 8 + %17 = inttoptr i64 %16 to i64* + store i64 %8, i64* %17 + %18 = trunc i64 16 to i32 + %19 = tail call ccc i8* @wybe_malloc(i32 %18) + %20 = ptrtoint i8* %19 to i64 + %21 = inttoptr i64 %20 to i64* + store i64 2, i64* %21 + %22 = add i64 %20, 8 + %23 = inttoptr i64 %22 to i64* + store i64 %14, i64* %23 + %24 = trunc i64 16 to i32 + %25 = tail call ccc i8* @wybe_malloc(i32 %24) + %26 = ptrtoint i8* %25 to i64 + %27 = inttoptr i64 %26 to i64* + store i64 1, i64* %27 + %28 = add i64 %26, 8 + %29 = inttoptr i64 %28 to i64* + store i64 %20, i64* %29 + %30 = alloca i64 + call fastcc void @"tcmc_unrolled_map.map2<0>[6dacb8fd25]"(i64 ptrtoint (i64* getelementptr inbounds ([1 x i64], [1 x i64]* @tcmc_unrolled_map.0, i32 0, i32 0) to i64), i64 %26, i64* %30) + %31 = load i64, i64* %30 + tail call fastcc void @"wybe.list.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ([1 x i64], [1 x i64]* @tcmc_unrolled_map.1, i32 0, i32 0) to i64), i64 %31) + tail call ccc void @putchar(i8 10) + ret void +} + + +define external fastcc i64 @"tcmc_unrolled_map.gen#1<0>"(i64 %"anon#1#1##0") { +entry: + %0 = add i64 %"anon#1#1##0", 1 + ret i64 %0 +} + + +define external fastcc i64 @"tcmc_unrolled_map.gen#1<1>"(i64 %"#env##0", i64 %"anon#1#1##0") { +entry: + %0 = add i64 %"anon#1#1##0", 1 + ret i64 %0 +} + + +define external fastcc void @"tcmc_unrolled_map.gen#2<0>"(i64 %"#env##0", i64 %"x##0") { +entry: + tail call ccc void @print_int(i64 %"x##0") + ret void +} + + +define external fastcc void @"tcmc_unrolled_map.map2<0>"(i64 %"f##0", i64 %"x##0", i64* %"#result#ref##0") { +entry: + %0 = icmp ne i64 %"x##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = inttoptr i64 %"x##0" to i64* + %2 = load i64, i64* %1 + %3 = add i64 %"x##0", 8 + %4 = inttoptr i64 %3 to i64* + %5 = load i64, i64* %4 + %6 = icmp ne i64 %5, 0 + br i1 %6, label %if.then1, label %if.else1 +if.else: + store i64 0, i64* %"#result#ref##0" + ret void +if.then1: + %7 = inttoptr i64 %5 to i64* + %8 = load i64, i64* %7 + %9 = add i64 %5, 8 + %10 = inttoptr i64 %9 to i64* + %11 = load i64, i64* %10 + %12 = inttoptr i64 %"f##0" to i64* + %13 = load i64, i64* %12 + %14 = inttoptr i64 %13 to i64 (i64, i64)* + %15 = tail call fastcc i64 %14(i64 %"f##0", i64 %2) + %16 = inttoptr i64 %"f##0" to i64* + %17 = load i64, i64* %16 + %18 = inttoptr i64 %17 to i64 (i64, i64)* + %19 = tail call fastcc i64 %18(i64 %"f##0", i64 %8) + %20 = trunc i64 16 to i32 + %21 = tail call ccc i8* @wybe_malloc(i32 %20) + %22 = ptrtoint i8* %21 to i64 + %23 = inttoptr i64 %22 to i64* + store i64 %19, i64* %23 + %24 = trunc i64 16 to i32 + %25 = tail call ccc i8* @wybe_malloc(i32 %24) + %26 = ptrtoint i8* %25 to i64 + %27 = inttoptr i64 %26 to i64* + store i64 %15, i64* %27 + %28 = add i64 %26, 8 + %29 = inttoptr i64 %28 to i64* + store i64 %26, i64* %"#result#ref##0" + %30 = add i64 %22, 8 + %31 = inttoptr i64 %30 to i64* + store i64 %22, i64* %29 + musttail call fastcc void @"tcmc_unrolled_map.map2<0>"(i64 %"f##0", i64 %11, i64* %31) + ret void +if.else1: + %32 = inttoptr i64 %"f##0" to i64* + %33 = load i64, i64* %32 + %34 = inttoptr i64 %33 to i64 (i64, i64)* + %35 = tail call fastcc i64 %34(i64 %"f##0", i64 %2) + %36 = trunc i64 16 to i32 + %37 = tail call ccc i8* @wybe_malloc(i32 %36) + %38 = ptrtoint i8* %37 to i64 + %39 = inttoptr i64 %38 to i64* + store i64 %35, i64* %39 + %40 = add i64 %38, 8 + %41 = inttoptr i64 %40 to i64* + store i64 0, i64* %41 + store i64 %38, i64* %"#result#ref##0" + ret void +} + + +define external fastcc void @"tcmc_unrolled_map.map2<0>[6dacb8fd25]"(i64 %"f##0", i64 %"x##0", i64* %"#result#ref##0") { +entry: + %0 = icmp ne i64 %"x##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = inttoptr i64 %"x##0" to i64* + %2 = load i64, i64* %1 + %3 = add i64 %"x##0", 8 + %4 = inttoptr i64 %3 to i64* + %5 = load i64, i64* %4 + %6 = icmp ne i64 %5, 0 + br i1 %6, label %if.then1, label %if.else1 +if.else: + store i64 0, i64* %"#result#ref##0" + ret void +if.then1: + %7 = inttoptr i64 %5 to i64* + %8 = load i64, i64* %7 + %9 = add i64 %5, 8 + %10 = inttoptr i64 %9 to i64* + %11 = load i64, i64* %10 + %12 = inttoptr i64 %"f##0" to i64* + %13 = load i64, i64* %12 + %14 = inttoptr i64 %13 to i64 (i64, i64)* + %15 = tail call fastcc i64 %14(i64 %"f##0", i64 %2) + %16 = inttoptr i64 %"f##0" to i64* + %17 = load i64, i64* %16 + %18 = inttoptr i64 %17 to i64 (i64, i64)* + %19 = tail call fastcc i64 %18(i64 %"f##0", i64 %8) + %20 = inttoptr i64 %5 to i64* + store i64 %19, i64* %20 + %21 = inttoptr i64 %"x##0" to i64* + store i64 %15, i64* %21 + %22 = add i64 %"x##0", 8 + %23 = inttoptr i64 %22 to i64* + store i64 %"x##0", i64* %"#result#ref##0" + %24 = add i64 %5, 8 + %25 = inttoptr i64 %24 to i64* + store i64 %5, i64* %23 + musttail call fastcc void @"tcmc_unrolled_map.map2<0>[6dacb8fd25]"(i64 %"f##0", i64 %11, i64* %25) + ret void +if.else1: + %26 = inttoptr i64 %"f##0" to i64* + %27 = load i64, i64* %26 + %28 = inttoptr i64 %27 to i64 (i64, i64)* + %29 = tail call fastcc i64 %28(i64 %"f##0", i64 %2) + %30 = inttoptr i64 %"x##0" to i64* + store i64 %29, i64* %30 + %31 = add i64 %"x##0", 8 + %32 = inttoptr i64 %31 to i64* + store i64 0, i64* %32 + store i64 %"x##0", i64* %"#result#ref##0" + ret void +} diff --git a/test-cases/final-dump/tcmc_unrolled_map.wybe b/test-cases/final-dump/tcmc_unrolled_map.wybe new file mode 100644 index 00000000..357a9241 --- /dev/null +++ b/test-cases/final-dump/tcmc_unrolled_map.wybe @@ -0,0 +1,17 @@ +# we expect this should TCMC-optimize +# however in order for this to happen, we need a generalisation of "mutate +# chains", which we name "mutate graphs" + +def map2(f: (T, ?K), x: list(T)): list(K) = + if { [?x0 | ?xt1] = x :: + if { [?x1 | ?xt2] = xt1 :: + [f(x0), f(x1) | map2(f, xt2)] + | else :: + [f(x0)] + } + | else :: + [] + } + +map2({?@2 = @1 + 1}, [1,2,3,4,5], ?y) +!println(print, y) \ No newline at end of file diff --git a/test-cases/final-dump/tcmc_use_output_twice.exp b/test-cases/final-dump/tcmc_use_output_twice.exp new file mode 100644 index 00000000..2ab89217 --- /dev/null +++ b/test-cases/final-dump/tcmc_use_output_twice.exp @@ -0,0 +1,568 @@ +====================================================================== +AFTER EVERYTHING: + Module tcmc_use_output_twice + representation : (not a type) + public submods : tree -> tcmc_use_output_twice.tree + public resources: + public procs : tcmc_use_output_twice.<0> + tcmc_use_output_twice.tree.empty<0> + tcmc_use_output_twice.tree.left<0> + tcmc_use_output_twice.tree.left<1> + tcmc_use_output_twice.tree.node<0> + tcmc_use_output_twice.tree.node<1> + tcmc_use_output_twice.tree.right<0> + tcmc_use_output_twice.tree.right<1> + tcmc_use_output_twice.tree.val<0> + tcmc_use_output_twice.tree.val<1> + imports : public use tcmc_use_output_twice.tree + use wybe + resources : + submodules : tcmc_use_output_twice.tree + procs : + +module top-level code > public {impure} (0 calls) +0: tcmc_use_output_twice.<0> +()<{<>}; {<>}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign lpvm cast(0:tcmc_use_output_twice.tree(T), ?tmp#1##0:tcmc_use_output_twice.tree(wybe.int)) + foreign lpvm alloc(24:wybe.int, ?tmp#9##0:tcmc_use_output_twice.tree(T)) @tcmc_use_output_twice:nn:nn + foreign lpvm mutate(~tmp#9##0:tcmc_use_output_twice.tree(T), ?tmp#10##0:tcmc_use_output_twice.tree(T), 0:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, 1:T) @tcmc_use_output_twice:nn:nn + foreign lpvm mutate(~tmp#10##0:tcmc_use_output_twice.tree(T), ?tmp#11##0:tcmc_use_output_twice.tree(T), 8:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, tmp#1##0:tcmc_use_output_twice.tree(T)) @tcmc_use_output_twice:nn:nn + foreign lpvm mutate(~tmp#11##0:tcmc_use_output_twice.tree(T), ?tmp#12##0:tcmc_use_output_twice.tree(T), 16:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, tmp#1##0:tcmc_use_output_twice.tree(T)) @tcmc_use_output_twice:nn:nn + foreign lpvm alloc(24:wybe.int, ?tmp#16##0:tcmc_use_output_twice.tree(T)) @tcmc_use_output_twice:nn:nn + foreign lpvm mutate(~tmp#16##0:tcmc_use_output_twice.tree(T), ?tmp#17##0:tcmc_use_output_twice.tree(T), 0:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, 2:T) @tcmc_use_output_twice:nn:nn + foreign lpvm mutate(~tmp#17##0:tcmc_use_output_twice.tree(T), ?tmp#18##0:tcmc_use_output_twice.tree(T), 8:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, tmp#1##0:tcmc_use_output_twice.tree(T)) @tcmc_use_output_twice:nn:nn + foreign lpvm mutate(~tmp#18##0:tcmc_use_output_twice.tree(T), ?tmp#19##0:tcmc_use_output_twice.tree(T), 16:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, ~tmp#1##0:tcmc_use_output_twice.tree(T)) @tcmc_use_output_twice:nn:nn + tcmc_use_output_twice.append_tree<0>(~tmp#12##0:tcmc_use_output_twice.tree(wybe.int), tmp#19##0:tcmc_use_output_twice.tree(wybe.int), ?x3##0:tcmc_use_output_twice.tree(wybe.int)) #6 @tcmc_use_output_twice:nn:nn + tcmc_use_output_twice.print_tree<0>(~tmp#19##0:tcmc_use_output_twice.tree(wybe.int))<{<>}; {<>}> #7 @tcmc_use_output_twice:nn:nn + foreign lpvm load(<>:wybe.phantom, ?%tmp#20##0:wybe.phantom) @io:nn:nn + foreign c putchar('\n':wybe.char, ~tmp#20##0:wybe.phantom, ?tmp#21##0:wybe.phantom) @io:nn:nn + foreign lpvm store(~%tmp#21##0:wybe.phantom, <>:wybe.phantom) @io:nn:nn + tcmc_use_output_twice.print_tree<0>(~x3##0:tcmc_use_output_twice.tree(wybe.int))<{<>}; {<>}> #9 @tcmc_use_output_twice:nn:nn + foreign lpvm load(<>:wybe.phantom, ?%tmp#22##0:wybe.phantom) @io:nn:nn + foreign c putchar('\n':wybe.char, ~tmp#22##0:wybe.phantom, ?tmp#23##0:wybe.phantom) @io:nn:nn + foreign lpvm store(~%tmp#23##0:wybe.phantom, <>:wybe.phantom) @io:nn:nn + + +append_tree > (2 calls) +0: tcmc_use_output_twice.append_tree<0> +append_tree(a##0:tcmc_use_output_twice.tree(wybe.int), b##0:tcmc_use_output_twice.tree(wybe.int), ?result##0:tcmc_use_output_twice.tree(wybe.int))<{}; {}>: + AliasPairs: [(a##0,b##0),(a##0,result##0),(b##0,result##0)] + InterestingCallProperties: [InterestingUnaliased 0,InterestingUnaliased 1] + MultiSpeczDepInfo: [(1,(tcmc_use_output_twice.append_tree<0>,fromList [NonAliasedParamCond 0 [1],NonAliasedParamCond 1 [0]]))] + foreign llvm icmp_ne(a##0:wybe.int, 0:wybe.int, ?tmp#3##0:wybe.bool) + case ~tmp#3##0:wybe.bool of + 0: + foreign llvm move(~b##0:tcmc_use_output_twice.tree(wybe.int), ?result##0:tcmc_use_output_twice.tree(wybe.int)) @tcmc_use_output_twice:nn:nn + + 1: + foreign lpvm access(a##0:tcmc_use_output_twice.tree(T), 0:wybe.int, 24:wybe.int, 0:wybe.int, ?val##0:wybe.int) @tcmc_use_output_twice:nn:nn + foreign lpvm access(~a##0:tcmc_use_output_twice.tree(T), 16:wybe.int, 24:wybe.int, 0:wybe.int, ?right##0:tcmc_use_output_twice.tree(wybe.int)) @tcmc_use_output_twice:nn:nn + tcmc_use_output_twice.append_tree<0>(~b##0:tcmc_use_output_twice.tree(wybe.int), ~right##0:tcmc_use_output_twice.tree(wybe.int), ?right2##0:tcmc_use_output_twice.tree(wybe.int)) #1 @tcmc_use_output_twice:nn:nn + foreign lpvm alloc(24:wybe.int, ?tmp#7##0:tcmc_use_output_twice.tree(T)) @tcmc_use_output_twice:nn:nn + foreign lpvm mutate(~tmp#7##0:tcmc_use_output_twice.tree(T), ?tmp#8##0:tcmc_use_output_twice.tree(T), 0:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, ~val##0:T) @tcmc_use_output_twice:nn:nn + foreign lpvm mutate(~tmp#8##0:tcmc_use_output_twice.tree(T), ?tmp#9##0:tcmc_use_output_twice.tree(T), 8:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, right2##0:tcmc_use_output_twice.tree(T)) @tcmc_use_output_twice:nn:nn + foreign lpvm mutate(~tmp#9##0:tcmc_use_output_twice.tree(T), ?result##0:tcmc_use_output_twice.tree(T), 16:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, ~right2##0:tcmc_use_output_twice.tree(T)) @tcmc_use_output_twice:nn:nn + + + +print_tree > (4 calls) +0: tcmc_use_output_twice.print_tree<0> +print_tree(a##0:tcmc_use_output_twice.tree(wybe.int))<{<>}; {<>}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_ne(a##0:wybe.int, 0:wybe.int, ?tmp#2##0:wybe.bool) + case ~tmp#2##0:wybe.bool of + 0: + wybe.string.print<0>("empty":wybe.string)<{<>}; {<>}> #8 @tcmc_use_output_twice:nn:nn + + 1: + foreign lpvm access(a##0:tcmc_use_output_twice.tree(T), 0:wybe.int, 24:wybe.int, 0:wybe.int, ?val##0:wybe.int) @tcmc_use_output_twice:nn:nn + foreign lpvm access(a##0:tcmc_use_output_twice.tree(T), 8:wybe.int, 24:wybe.int, 0:wybe.int, ?left##0:tcmc_use_output_twice.tree(wybe.int)) @tcmc_use_output_twice:nn:nn + foreign lpvm access(~a##0:tcmc_use_output_twice.tree(T), 16:wybe.int, 24:wybe.int, 0:wybe.int, ?right##0:tcmc_use_output_twice.tree(wybe.int)) @tcmc_use_output_twice:nn:nn + wybe.string.print<0>("node(":wybe.string)<{<>}; {<>}> #1 @tcmc_use_output_twice:nn:nn + foreign lpvm load(<>:wybe.phantom, ?%tmp#4##0:wybe.phantom) @int:nn:nn + foreign c print_int(~val##0:wybe.int, ~tmp#4##0:wybe.phantom, ?tmp#5##0:wybe.phantom) @int:nn:nn + foreign lpvm store(~%tmp#5##0:wybe.phantom, <>:wybe.phantom) @int:nn:nn + wybe.string.print<0>(",":wybe.string)<{<>}; {<>}> #3 @tcmc_use_output_twice:nn:nn + tcmc_use_output_twice.print_tree<0>(~left##0:tcmc_use_output_twice.tree(wybe.int))<{<>}; {<>}> #4 @tcmc_use_output_twice:nn:nn + wybe.string.print<0>(",":wybe.string)<{<>}; {<>}> #5 @tcmc_use_output_twice:nn:nn + tcmc_use_output_twice.print_tree<0>(~right##0:tcmc_use_output_twice.tree(wybe.int))<{<>}; {<>}> #6 @tcmc_use_output_twice:nn:nn + wybe.string.print<0>(")":wybe.string)<{<>}; {<>}> #7 @tcmc_use_output_twice:nn:nn + + + LLVM code : + +; ModuleID = 'tcmc_use_output_twice' + + + + + +@tcmc_use_output_twice.3 = constant {i64, i64} { i64 1, i64 ptrtoint ([?? x i8]* @tcmc_use_output_twice.2 to i64) } + + +@tcmc_use_output_twice.5 = constant {i64, i64} { i64 1, i64 ptrtoint ([?? x i8]* @tcmc_use_output_twice.4 to i64) } + + +@tcmc_use_output_twice.1 = constant {i64, i64} { i64 5, i64 ptrtoint ([?? x i8]* @tcmc_use_output_twice.0 to i64) } + + +@tcmc_use_output_twice.7 = constant {i64, i64} { i64 5, i64 ptrtoint ([?? x i8]* @tcmc_use_output_twice.6 to i64) } + + +@tcmc_use_output_twice.4 = constant [?? x i8] c")\00" + + +@tcmc_use_output_twice.2 = constant [?? x i8] c",\00" + + +@tcmc_use_output_twice.6 = constant [?? x i8] c"empty\00" + + +@tcmc_use_output_twice.0 = constant [?? x i8] c"node(\00" + + +declare external fastcc void @"wybe.string.print<0>"(i64) + + +declare external ccc void @print_int(i64) + + +declare external ccc void @putchar(i8) + + +declare external ccc i8* @wybe_malloc(i32) + + +declare external ccc void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1) + + +define external fastcc void @"tcmc_use_output_twice.<0>"() { +entry: + %0 = trunc i64 24 to i32 + %1 = tail call ccc i8* @wybe_malloc(i32 %0) + %2 = ptrtoint i8* %1 to i64 + %3 = inttoptr i64 %2 to i64* + store i64 1, i64* %3 + %4 = add i64 %2, 8 + %5 = inttoptr i64 %4 to i64* + store i64 0, i64* %5 + %6 = add i64 %2, 16 + %7 = inttoptr i64 %6 to i64* + store i64 0, i64* %7 + %8 = trunc i64 24 to i32 + %9 = tail call ccc i8* @wybe_malloc(i32 %8) + %10 = ptrtoint i8* %9 to i64 + %11 = inttoptr i64 %10 to i64* + store i64 2, i64* %11 + %12 = add i64 %10, 8 + %13 = inttoptr i64 %12 to i64* + store i64 0, i64* %13 + %14 = add i64 %10, 16 + %15 = inttoptr i64 %14 to i64* + store i64 0, i64* %15 + %16 = tail call fastcc i64 @"tcmc_use_output_twice.append_tree<0>"(i64 %2, i64 %10) + tail call fastcc void @"tcmc_use_output_twice.print_tree<0>"(i64 %10) + tail call ccc void @putchar(i8 10) + tail call fastcc void @"tcmc_use_output_twice.print_tree<0>"(i64 %16) + tail call ccc void @putchar(i8 10) + ret void +} + + +define external fastcc i64 @"tcmc_use_output_twice.append_tree<0>"(i64 %"a##0", i64 %"b##0") { +entry: + %0 = icmp ne i64 %"a##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = inttoptr i64 %"a##0" to i64* + %2 = load i64, i64* %1 + %3 = add i64 %"a##0", 16 + %4 = inttoptr i64 %3 to i64* + %5 = load i64, i64* %4 + %6 = tail call fastcc i64 @"tcmc_use_output_twice.append_tree<0>"(i64 %"b##0", i64 %5) + %7 = trunc i64 24 to i32 + %8 = tail call ccc i8* @wybe_malloc(i32 %7) + %9 = ptrtoint i8* %8 to i64 + %10 = inttoptr i64 %9 to i64* + store i64 %2, i64* %10 + %11 = add i64 %9, 8 + %12 = inttoptr i64 %11 to i64* + store i64 %6, i64* %12 + %13 = add i64 %9, 16 + %14 = inttoptr i64 %13 to i64* + store i64 %6, i64* %14 + ret i64 %9 +if.else: + ret i64 %"b##0" +} + + +define external fastcc void @"tcmc_use_output_twice.print_tree<0>"(i64 %"a##0") { +entry: + %0 = icmp ne i64 %"a##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = inttoptr i64 %"a##0" to i64* + %2 = load i64, i64* %1 + %3 = add i64 %"a##0", 8 + %4 = inttoptr i64 %3 to i64* + %5 = load i64, i64* %4 + %6 = add i64 %"a##0", 16 + %7 = inttoptr i64 %6 to i64* + %8 = load i64, i64* %7 + tail call fastcc void @"wybe.string.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ({i64, i64}, {i64, i64}* @tcmc_use_output_twice.1, i32 0, i32 0) to i64)) + tail call ccc void @print_int(i64 %2) + tail call fastcc void @"wybe.string.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ({i64, i64}, {i64, i64}* @tcmc_use_output_twice.3, i32 0, i32 0) to i64)) + tail call fastcc void @"tcmc_use_output_twice.print_tree<0>"(i64 %5) + tail call fastcc void @"wybe.string.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ({i64, i64}, {i64, i64}* @tcmc_use_output_twice.3, i32 0, i32 0) to i64)) + tail call fastcc void @"tcmc_use_output_twice.print_tree<0>"(i64 %8) + musttail call fastcc void @"wybe.string.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ({i64, i64}, {i64, i64}* @tcmc_use_output_twice.5, i32 0, i32 0) to i64)) + ret void +if.else: + musttail call fastcc void @"wybe.string.print<0>"(i64 ptrtoint (i64* getelementptr inbounds ({i64, i64}, {i64, i64}* @tcmc_use_output_twice.7, i32 0, i32 0) to i64)) + ret void +} +-------------------------------------------------- + Module tcmc_use_output_twice.tree(T) + representation : address + public submods : + public resources: + public procs : tcmc_use_output_twice.tree.empty<0> + tcmc_use_output_twice.tree.left<0> + tcmc_use_output_twice.tree.left<1> + tcmc_use_output_twice.tree.node<0> + tcmc_use_output_twice.tree.node<1> + tcmc_use_output_twice.tree.right<0> + tcmc_use_output_twice.tree.right<1> + tcmc_use_output_twice.tree.val<0> + tcmc_use_output_twice.tree.val<1> + imports : use tcmc_use_output_twice + use wybe + resources : + procs : + +empty > public {inline} (0 calls) +0: tcmc_use_output_twice.tree.empty<0> +empty(?#result##0:tcmc_use_output_twice.tree(T))<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm move(0:tcmc_use_output_twice.tree(T), ?#result##0:tcmc_use_output_twice.tree(T)) + + +left > public {inline} (0 calls) +0: tcmc_use_output_twice.tree.left<0> +left(#rec##0:tcmc_use_output_twice.tree(T), ?#result##0:tcmc_use_output_twice.tree(T), ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_ne(#rec##0:wybe.int, 0:wybe.int, ?tmp#0##0:wybe.bool) + case ~tmp#0##0:wybe.bool of + 0: + foreign llvm move(0:wybe.bool, ?#success##0:wybe.bool) + foreign llvm move(undef:tcmc_use_output_twice.tree(T), ?#result##0:tcmc_use_output_twice.tree(T)) + + 1: + foreign lpvm access(~#rec##0:tcmc_use_output_twice.tree(T), 8:wybe.int, 24:wybe.int, 0:wybe.int, ?#result##0:tcmc_use_output_twice.tree(T)) @tcmc_use_output_twice:nn:nn + foreign llvm move(1:wybe.bool, ?#success##0:wybe.bool) + +left > public {inline} (0 calls) +1: tcmc_use_output_twice.tree.left<1> +left(#rec##0:tcmc_use_output_twice.tree(T), ?#rec##1:tcmc_use_output_twice.tree(T), #field##0:tcmc_use_output_twice.tree(T), ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_ne(#rec##0:wybe.int, 0:wybe.int, ?tmp#0##0:wybe.bool) + case ~tmp#0##0:wybe.bool of + 0: + foreign llvm move(0:wybe.bool, ?#success##0:wybe.bool) + foreign llvm move(~#rec##0:tcmc_use_output_twice.tree(T), ?#rec##1:tcmc_use_output_twice.tree(T)) + + 1: + foreign lpvm mutate(~#rec##0:tcmc_use_output_twice.tree(T), ?#rec##1:tcmc_use_output_twice.tree(T), 8:wybe.int, 0:wybe.int, 24:wybe.int, 0:wybe.int, ~#field##0:tcmc_use_output_twice.tree(T)) @tcmc_use_output_twice:nn:nn + foreign llvm move(1:wybe.bool, ?#success##0:wybe.bool) + + + +node > public {inline} (0 calls) +0: tcmc_use_output_twice.tree.node<0> +node(val##0:T, left##0:tcmc_use_output_twice.tree(T), right##0:tcmc_use_output_twice.tree(T), ?#result##0:tcmc_use_output_twice.tree(T))<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign lpvm alloc(24:wybe.int, ?#rec##0:tcmc_use_output_twice.tree(T)) @tcmc_use_output_twice:nn:nn + foreign lpvm mutate(~#rec##0:tcmc_use_output_twice.tree(T), ?#rec##1:tcmc_use_output_twice.tree(T), 0:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, ~val##0:T) @tcmc_use_output_twice:nn:nn + foreign lpvm mutate(~#rec##1:tcmc_use_output_twice.tree(T), ?#rec##2:tcmc_use_output_twice.tree(T), 8:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, ~left##0:tcmc_use_output_twice.tree(T)) @tcmc_use_output_twice:nn:nn + foreign lpvm mutate(~#rec##2:tcmc_use_output_twice.tree(T), ?#result##0:tcmc_use_output_twice.tree(T), 16:wybe.int, 1:wybe.int, 24:wybe.int, 0:wybe.int, ~right##0:tcmc_use_output_twice.tree(T)) @tcmc_use_output_twice:nn:nn +node > public {inline} (0 calls) +1: tcmc_use_output_twice.tree.node<1> +node(?val##0:T, ?left##0:tcmc_use_output_twice.tree(T), ?right##0:tcmc_use_output_twice.tree(T), #result##0:tcmc_use_output_twice.tree(T), ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_ne(#result##0:wybe.int, 0:wybe.int, ?tmp#0##0:wybe.bool) + case ~tmp#0##0:wybe.bool of + 0: + foreign llvm move(0:wybe.bool, ?#success##0:wybe.bool) + foreign llvm move(undef:T, ?val##0:T) + foreign llvm move(undef:tcmc_use_output_twice.tree(T), ?left##0:tcmc_use_output_twice.tree(T)) + foreign llvm move(undef:tcmc_use_output_twice.tree(T), ?right##0:tcmc_use_output_twice.tree(T)) + + 1: + foreign lpvm access(#result##0:tcmc_use_output_twice.tree(T), 0:wybe.int, 24:wybe.int, 0:wybe.int, ?val##0:T) @tcmc_use_output_twice:nn:nn + foreign lpvm access(#result##0:tcmc_use_output_twice.tree(T), 8:wybe.int, 24:wybe.int, 0:wybe.int, ?left##0:tcmc_use_output_twice.tree(T)) @tcmc_use_output_twice:nn:nn + foreign lpvm access(~#result##0:tcmc_use_output_twice.tree(T), 16:wybe.int, 24:wybe.int, 0:wybe.int, ?right##0:tcmc_use_output_twice.tree(T)) @tcmc_use_output_twice:nn:nn + foreign llvm move(1:wybe.bool, ?#success##0:wybe.bool) + + + +right > public {inline} (0 calls) +0: tcmc_use_output_twice.tree.right<0> +right(#rec##0:tcmc_use_output_twice.tree(T), ?#result##0:tcmc_use_output_twice.tree(T), ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_ne(#rec##0:wybe.int, 0:wybe.int, ?tmp#0##0:wybe.bool) + case ~tmp#0##0:wybe.bool of + 0: + foreign llvm move(0:wybe.bool, ?#success##0:wybe.bool) + foreign llvm move(undef:tcmc_use_output_twice.tree(T), ?#result##0:tcmc_use_output_twice.tree(T)) + + 1: + foreign lpvm access(~#rec##0:tcmc_use_output_twice.tree(T), 16:wybe.int, 24:wybe.int, 0:wybe.int, ?#result##0:tcmc_use_output_twice.tree(T)) @tcmc_use_output_twice:nn:nn + foreign llvm move(1:wybe.bool, ?#success##0:wybe.bool) + +right > public {inline} (0 calls) +1: tcmc_use_output_twice.tree.right<1> +right(#rec##0:tcmc_use_output_twice.tree(T), ?#rec##1:tcmc_use_output_twice.tree(T), #field##0:tcmc_use_output_twice.tree(T), ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_ne(#rec##0:wybe.int, 0:wybe.int, ?tmp#0##0:wybe.bool) + case ~tmp#0##0:wybe.bool of + 0: + foreign llvm move(0:wybe.bool, ?#success##0:wybe.bool) + foreign llvm move(~#rec##0:tcmc_use_output_twice.tree(T), ?#rec##1:tcmc_use_output_twice.tree(T)) + + 1: + foreign lpvm mutate(~#rec##0:tcmc_use_output_twice.tree(T), ?#rec##1:tcmc_use_output_twice.tree(T), 16:wybe.int, 0:wybe.int, 24:wybe.int, 0:wybe.int, ~#field##0:tcmc_use_output_twice.tree(T)) @tcmc_use_output_twice:nn:nn + foreign llvm move(1:wybe.bool, ?#success##0:wybe.bool) + + + +val > public {inline} (0 calls) +0: tcmc_use_output_twice.tree.val<0> +val(#rec##0:tcmc_use_output_twice.tree(T), ?#result##0:T, ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_ne(#rec##0:wybe.int, 0:wybe.int, ?tmp#0##0:wybe.bool) + case ~tmp#0##0:wybe.bool of + 0: + foreign llvm move(0:wybe.bool, ?#success##0:wybe.bool) + foreign llvm move(undef:T, ?#result##0:T) + + 1: + foreign lpvm access(~#rec##0:tcmc_use_output_twice.tree(T), 0:wybe.int, 24:wybe.int, 0:wybe.int, ?#result##0:T) @tcmc_use_output_twice:nn:nn + foreign llvm move(1:wybe.bool, ?#success##0:wybe.bool) + +val > public {inline} (0 calls) +1: tcmc_use_output_twice.tree.val<1> +val(#rec##0:tcmc_use_output_twice.tree(T), ?#rec##1:tcmc_use_output_twice.tree(T), #field##0:T, ?#success##0:wybe.bool)<{}; {}>: + AliasPairs: [] + InterestingCallProperties: [] + foreign llvm icmp_ne(#rec##0:wybe.int, 0:wybe.int, ?tmp#0##0:wybe.bool) + case ~tmp#0##0:wybe.bool of + 0: + foreign llvm move(0:wybe.bool, ?#success##0:wybe.bool) + foreign llvm move(~#rec##0:tcmc_use_output_twice.tree(T), ?#rec##1:tcmc_use_output_twice.tree(T)) + + 1: + foreign lpvm mutate(~#rec##0:tcmc_use_output_twice.tree(T), ?#rec##1:tcmc_use_output_twice.tree(T), 0:wybe.int, 0:wybe.int, 24:wybe.int, 0:wybe.int, ~#field##0:T) @tcmc_use_output_twice:nn:nn + foreign llvm move(1:wybe.bool, ?#success##0:wybe.bool) + + + LLVM code : + +; ModuleID = 'tcmc_use_output_twice.tree' + + + + + +declare external ccc i8* @wybe_malloc(i32) + + +declare external ccc void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1) + + +define external fastcc i64 @"tcmc_use_output_twice.tree.empty<0>"() { +entry: + ret i64 0 +} + + +define external fastcc {i64, i1} @"tcmc_use_output_twice.tree.left<0>"(i64 %"#rec##0") { +entry: + %0 = icmp ne i64 %"#rec##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = add i64 %"#rec##0", 8 + %2 = inttoptr i64 %1 to i64* + %3 = load i64, i64* %2 + %4 = insertvalue {i64, i1} undef, i64 %3, 0 + %5 = insertvalue {i64, i1} %4, i1 1, 1 + ret {i64, i1} %5 +if.else: + %6 = insertvalue {i64, i1} undef, i64 undef, 0 + %7 = insertvalue {i64, i1} %6, i1 0, 1 + ret {i64, i1} %7 +} + + +define external fastcc {i64, i1} @"tcmc_use_output_twice.tree.left<1>"(i64 %"#rec##0", i64 %"#field##0") { +entry: + %0 = icmp ne i64 %"#rec##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = trunc i64 24 to i32 + %2 = tail call ccc i8* @wybe_malloc(i32 %1) + %3 = ptrtoint i8* %2 to i64 + %4 = inttoptr i64 %3 to i8* + %5 = inttoptr i64 %"#rec##0" to i8* + %6 = trunc i64 24 to i32 + tail call ccc void @llvm.memcpy.p0i8.p0i8.i32(i8* %4, i8* %5, i32 %6, i1 0) + %7 = add i64 %3, 8 + %8 = inttoptr i64 %7 to i64* + store i64 %"#field##0", i64* %8 + %9 = insertvalue {i64, i1} undef, i64 %3, 0 + %10 = insertvalue {i64, i1} %9, i1 1, 1 + ret {i64, i1} %10 +if.else: + %11 = insertvalue {i64, i1} undef, i64 %"#rec##0", 0 + %12 = insertvalue {i64, i1} %11, i1 0, 1 + ret {i64, i1} %12 +} + + +define external fastcc i64 @"tcmc_use_output_twice.tree.node<0>"(i64 %"val##0", i64 %"left##0", i64 %"right##0") { +entry: + %0 = trunc i64 24 to i32 + %1 = tail call ccc i8* @wybe_malloc(i32 %0) + %2 = ptrtoint i8* %1 to i64 + %3 = inttoptr i64 %2 to i64* + store i64 %"val##0", i64* %3 + %4 = add i64 %2, 8 + %5 = inttoptr i64 %4 to i64* + store i64 %"left##0", i64* %5 + %6 = add i64 %2, 16 + %7 = inttoptr i64 %6 to i64* + store i64 %"right##0", i64* %7 + ret i64 %2 +} + + +define external fastcc {i64, i64, i64, i1} @"tcmc_use_output_twice.tree.node<1>"(i64 %"#result##0") { +entry: + %0 = icmp ne i64 %"#result##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = inttoptr i64 %"#result##0" to i64* + %2 = load i64, i64* %1 + %3 = add i64 %"#result##0", 8 + %4 = inttoptr i64 %3 to i64* + %5 = load i64, i64* %4 + %6 = add i64 %"#result##0", 16 + %7 = inttoptr i64 %6 to i64* + %8 = load i64, i64* %7 + %9 = insertvalue {i64, i64, i64, i1} undef, i64 %2, 0 + %10 = insertvalue {i64, i64, i64, i1} %9, i64 %5, 1 + %11 = insertvalue {i64, i64, i64, i1} %10, i64 %8, 2 + %12 = insertvalue {i64, i64, i64, i1} %11, i1 1, 3 + ret {i64, i64, i64, i1} %12 +if.else: + %13 = insertvalue {i64, i64, i64, i1} undef, i64 undef, 0 + %14 = insertvalue {i64, i64, i64, i1} %13, i64 undef, 1 + %15 = insertvalue {i64, i64, i64, i1} %14, i64 undef, 2 + %16 = insertvalue {i64, i64, i64, i1} %15, i1 0, 3 + ret {i64, i64, i64, i1} %16 +} + + +define external fastcc {i64, i1} @"tcmc_use_output_twice.tree.right<0>"(i64 %"#rec##0") { +entry: + %0 = icmp ne i64 %"#rec##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = add i64 %"#rec##0", 16 + %2 = inttoptr i64 %1 to i64* + %3 = load i64, i64* %2 + %4 = insertvalue {i64, i1} undef, i64 %3, 0 + %5 = insertvalue {i64, i1} %4, i1 1, 1 + ret {i64, i1} %5 +if.else: + %6 = insertvalue {i64, i1} undef, i64 undef, 0 + %7 = insertvalue {i64, i1} %6, i1 0, 1 + ret {i64, i1} %7 +} + + +define external fastcc {i64, i1} @"tcmc_use_output_twice.tree.right<1>"(i64 %"#rec##0", i64 %"#field##0") { +entry: + %0 = icmp ne i64 %"#rec##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = trunc i64 24 to i32 + %2 = tail call ccc i8* @wybe_malloc(i32 %1) + %3 = ptrtoint i8* %2 to i64 + %4 = inttoptr i64 %3 to i8* + %5 = inttoptr i64 %"#rec##0" to i8* + %6 = trunc i64 24 to i32 + tail call ccc void @llvm.memcpy.p0i8.p0i8.i32(i8* %4, i8* %5, i32 %6, i1 0) + %7 = add i64 %3, 16 + %8 = inttoptr i64 %7 to i64* + store i64 %"#field##0", i64* %8 + %9 = insertvalue {i64, i1} undef, i64 %3, 0 + %10 = insertvalue {i64, i1} %9, i1 1, 1 + ret {i64, i1} %10 +if.else: + %11 = insertvalue {i64, i1} undef, i64 %"#rec##0", 0 + %12 = insertvalue {i64, i1} %11, i1 0, 1 + ret {i64, i1} %12 +} + + +define external fastcc {i64, i1} @"tcmc_use_output_twice.tree.val<0>"(i64 %"#rec##0") { +entry: + %0 = icmp ne i64 %"#rec##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = inttoptr i64 %"#rec##0" to i64* + %2 = load i64, i64* %1 + %3 = insertvalue {i64, i1} undef, i64 %2, 0 + %4 = insertvalue {i64, i1} %3, i1 1, 1 + ret {i64, i1} %4 +if.else: + %5 = insertvalue {i64, i1} undef, i64 undef, 0 + %6 = insertvalue {i64, i1} %5, i1 0, 1 + ret {i64, i1} %6 +} + + +define external fastcc {i64, i1} @"tcmc_use_output_twice.tree.val<1>"(i64 %"#rec##0", i64 %"#field##0") { +entry: + %0 = icmp ne i64 %"#rec##0", 0 + br i1 %0, label %if.then, label %if.else +if.then: + %1 = trunc i64 24 to i32 + %2 = tail call ccc i8* @wybe_malloc(i32 %1) + %3 = ptrtoint i8* %2 to i64 + %4 = inttoptr i64 %3 to i8* + %5 = inttoptr i64 %"#rec##0" to i8* + %6 = trunc i64 24 to i32 + tail call ccc void @llvm.memcpy.p0i8.p0i8.i32(i8* %4, i8* %5, i32 %6, i1 0) + %7 = inttoptr i64 %3 to i64* + store i64 %"#field##0", i64* %7 + %8 = insertvalue {i64, i1} undef, i64 %3, 0 + %9 = insertvalue {i64, i1} %8, i1 1, 1 + ret {i64, i1} %9 +if.else: + %10 = insertvalue {i64, i1} undef, i64 %"#rec##0", 0 + %11 = insertvalue {i64, i1} %10, i1 0, 1 + ret {i64, i1} %11 +} diff --git a/test-cases/final-dump/tcmc_use_output_twice.wybe b/test-cases/final-dump/tcmc_use_output_twice.wybe new file mode 100644 index 00000000..ea8ca80e --- /dev/null +++ b/test-cases/final-dump/tcmc_use_output_twice.wybe @@ -0,0 +1,32 @@ +pub type tree(T) { pub empty | node(val: T, left: tree(T), right: tree(T)) } + +def append_tree(a: tree(int), b: tree(int), ?result: tree(int)) { + if { node(?val, ?left, ?right) = a :: + append_tree(b, right, ?right2) + ?result = node(val, right2, right2) + | else :: + ?result = b + } +} + +def print_tree(a: tree(int)) use !io { + if { node(?val, ?left, ?right) = a :: + !print("node(") + !print(val) + !print(",") + !print_tree(left) + !print(",") + !print_tree(right) + !print(")") + | else :: + !print("empty") + } +} + +?x = node(1, empty, empty) +?x2 = node(2, empty, empty) +append_tree(x, x2, ?x3) +!print_tree(x2) +!nl +!print_tree(x3) +!nl \ No newline at end of file diff --git a/test-cases/final-dump/thistype.exp b/test-cases/final-dump/thistype.exp index 40f1f843..d001c24b 100644 --- a/test-cases/final-dump/thistype.exp +++ b/test-cases/final-dump/thistype.exp @@ -343,7 +343,7 @@ if.else2: } -define external fastcc void @"thistype.concat<0>"(i64 %"x##0", i64 %"y##0", i64* %"#result##0") { +define external fastcc void @"thistype.concat<0>"(i64 %"x##0", i64 %"y##0", i64* %"#result#ref##0") { entry: %0 = icmp ne i64 %"x##0", 0 br i1 %0, label %if.then, label %if.else @@ -360,16 +360,16 @@ if.then: store i64 %2, i64* %9 %10 = add i64 %8, 8 %11 = inttoptr i64 %10 to i64* - store i64 %8, i64* %"#result##0" + store i64 %8, i64* %"#result#ref##0" musttail call fastcc void @"thistype.concat<0>"(i64 %5, i64 %"y##0", i64* %11) ret void if.else: - store i64 %"y##0", i64* %"#result##0" + store i64 %"y##0", i64* %"#result#ref##0" ret void } -define external fastcc void @"thistype.concat<0>[410bae77d3]"(i64 %"x##0", i64 %"y##0", i64* %"#result##0") { +define external fastcc void @"thistype.concat<0>[410bae77d3]"(i64 %"x##0", i64 %"y##0", i64* %"#result#ref##0") { entry: %0 = icmp ne i64 %"x##0", 0 br i1 %0, label %if.then, label %if.else @@ -379,11 +379,11 @@ if.then: %3 = load i64, i64* %2 %4 = add i64 %"x##0", 8 %5 = inttoptr i64 %4 to i64* - store i64 %"x##0", i64* %"#result##0" + store i64 %"x##0", i64* %"#result#ref##0" musttail call fastcc void @"thistype.concat<0>[410bae77d3]"(i64 %3, i64 %"y##0", i64* %5) ret void if.else: - store i64 %"y##0", i64* %"#result##0" + store i64 %"y##0", i64* %"#result#ref##0" ret void } diff --git a/test-cases/final-dump/type_list.exp b/test-cases/final-dump/type_list.exp index fedf7a4c..db8e1075 100644 --- a/test-cases/final-dump/type_list.exp +++ b/test-cases/final-dump/type_list.exp @@ -166,7 +166,7 @@ entry: } -define external fastcc void @"type_list.,,<0>"(i64 %"x##0", i64 %"y##0", i64* %"#result##0") { +define external fastcc void @"type_list.,,<0>"(i64 %"x##0", i64 %"y##0", i64* %"#result#ref##0") { entry: %0 = icmp ne i64 %"x##0", 0 br i1 %0, label %if.then, label %if.else @@ -183,16 +183,16 @@ if.then: store i64 %2, i64* %9 %10 = add i64 %8, 8 %11 = inttoptr i64 %10 to i64* - store i64 %8, i64* %"#result##0" + store i64 %8, i64* %"#result#ref##0" musttail call fastcc void @"type_list.,,<0>"(i64 %5, i64 %"y##0", i64* %11) ret void if.else: - store i64 %"y##0", i64* %"#result##0" + store i64 %"y##0", i64* %"#result#ref##0" ret void } -define external fastcc void @"type_list.,,<0>[410bae77d3]"(i64 %"x##0", i64 %"y##0", i64* %"#result##0") { +define external fastcc void @"type_list.,,<0>[410bae77d3]"(i64 %"x##0", i64 %"y##0", i64* %"#result#ref##0") { entry: %0 = icmp ne i64 %"x##0", 0 br i1 %0, label %if.then, label %if.else @@ -202,11 +202,11 @@ if.then: %3 = load i64, i64* %2 %4 = add i64 %"x##0", 8 %5 = inttoptr i64 %4 to i64* - store i64 %"x##0", i64* %"#result##0" + store i64 %"x##0", i64* %"#result#ref##0" musttail call fastcc void @"type_list.,,<0>[410bae77d3]"(i64 %3, i64 %"y##0", i64* %5) ret void if.else: - store i64 %"y##0", i64* %"#result##0" + store i64 %"y##0", i64* %"#result#ref##0" ret void } diff --git a/test-cases/final-dump/types_misleading_error.wybe b/test-cases/final-dump/types_misleading_error.wybe new file mode 100644 index 00000000..b753409f --- /dev/null +++ b/test-cases/final-dump/types_misleading_error.wybe @@ -0,0 +1,7 @@ +def {impure} do_something_with(l: list(T)) { + ?l2 = l +} + +?l = [1,2,3] +!println(l, print) +!do_something_with(l) \ No newline at end of file