Skip to content

Commit 4a0d9c7

Browse files
authored
feat(#360): factor common constants from forks and replace with tables (#531)
* feat(#495): add foreign lpvm sizeof instr * refactor(#495): clean up LPVM translation of sizeof * refactor(#495): clean up flatten of sizeof * test(#495): sizeof Fixes failing lazy test * docs(#495): add sizeof docs * feat(#360): add MergedFork * fix: static, global constats are aliased * feat: merge branches where difference is only variable names * fix: switch defaults * feat: refine normalised tag type * refactor: dump of merged branch * fix: use MergedFork default in LLVM generation * feat: consider merging default with branches * feat: merge more kinds of forks refactors to use MaybeT for merging * test: test case for merged branches * feat: use default for disjoint branches * refactor: remove trivial factored vars
1 parent 71d006c commit 4a0d9c7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+6245
-5061
lines changed

WYBE.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2443,6 +2443,13 @@ converting its type from *type1* to *type2*, without changing the
24432443
representation. This just allows getting around LLVM strong typing; it does not
24442444
actually require any instructions.
24452445
2446+
- `foreign lpvm sizeof(`*arg:type*, `?`*size:int_type*`)` Get the size of the *type* of
2447+
the first argument in bytes. To get the size in bits, specify the `bits` modifier.
2448+
The size of a type is the size of it's largest constructor (at most a machine word), or the size of its' representation.
2449+
The first argument can be anything except for an outwards-flowing variable.
2450+
The type of the second argument, *int_type*, can have any integer represented type.
2451+
This instruction is resolved statically, with _no_ runtime cost.
2452+
24462453
24472454
#### Handling impurity
24482455

src/AST.hs

Lines changed: 84 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ module AST (
6565
speczVersionToId, SpeczProcBodies,
6666
MultiSpeczDepInfo, CallSiteProperty(..), InterestingCallProperty(..),
6767
ProcAnalysis(..), emptyProcAnalysis,
68-
ProcBody(..), PrimFork(..), Ident, VarName,
69-
ProcName, ResourceDef(..), FlowDirection(..), showFlowName,
68+
ProcBody(..), PrimFork(..), MergedForkTable, prependToBody, appendToBody, unMergeFork, guardedMergedFork,
69+
Ident, VarName, ProcName, ResourceDef(..), FlowDirection(..), showFlowName,
7070
argFlowDirection, argType, setArgType, setArgFlow, setArgFlowType, maybeArgFlowType,
7171
argDescription, argIntVal, trustArgInt, setParamType, paramIsResourceful,
7272
setPrimParamType, setTypeFlowType,
@@ -2456,14 +2456,65 @@ data ProcBody = ProcBody {
24562456
data PrimFork =
24572457
NoFork |
24582458
PrimFork {
2459+
forkVar::PrimVarName, -- ^The variable that selects branch to take
2460+
forkVarType::TypeSpec, -- ^The Wybe type of the forkVar
2461+
forkVarLast::Bool, -- ^Is this the last occurrence of forkVar
2462+
forkBodies::[(Integer,ProcBody)],
2463+
-- ^one branch for each value of forkVar
2464+
forkDefault::Maybe ProcBody -- ^branch to take if forkVar is out of range
2465+
} |
2466+
MergedFork {
24592467
forkVar::PrimVarName, -- ^The variable that selects branch to take
24602468
forkVarType::TypeSpec, -- ^The Wybe type of the forkVar
24612469
forkVarLast::Bool, -- ^Is this the last occurrence of forkVar
2462-
forkBodies::[ProcBody], -- ^one branch for each value of forkVar
2463-
forkDefault::Maybe ProcBody -- ^branch to take if forkVar is out of range
2470+
forkTable::MergedForkTable,
2471+
-- ^Each variable factored out from each branch,
2472+
-- with the list of values indexed by the branch
2473+
forkBody::ProcBody, -- ^The rest of the "branch",
2474+
forkDefault::Maybe ProcBody
2475+
-- ^The branch if the var is out of range
24642476
}
24652477
deriving (Eq, Show, Generic)
24662478

2479+
type MergedForkTable = [(PrimVarName, TypeSpec, [PrimArg])]
2480+
2481+
-- |Add the specified statements at the end of the given body
2482+
appendToBody :: ProcBody -> [Placed Prim] -> ProcBody
2483+
appendToBody (ProcBody prims NoFork) after
2484+
= ProcBody (prims++after) NoFork
2485+
appendToBody (ProcBody prims (PrimFork v ty lst bodies deflt)) after
2486+
= let bodies' = List.map (mapSnd (`appendToBody` after)) bodies
2487+
in ProcBody prims $ PrimFork v ty lst bodies'
2488+
$ (`appendToBody` after) <$> deflt
2489+
appendToBody body@ProcBody{bodyFork=merged@MergedFork{forkBody=fork}} after
2490+
= body{bodyFork=merged{forkBody=fork `appendToBody` after}}
2491+
2492+
-- |Add the specified statements at the front of the given body
2493+
prependToBody :: [Placed Prim] -> ProcBody -> ProcBody
2494+
prependToBody before (ProcBody prims fork)
2495+
= ProcBody (before++prims) fork
2496+
2497+
-- |Un-merge a fork, replacing the tabled variables with a series of moved in the PrimFork branches
2498+
unMergeFork :: PrimFork -> PrimFork
2499+
unMergeFork (MergedFork var ty final table body dlft) =
2500+
let untabled = List.transpose
2501+
$ List.map (\(var', ty', vals) -> List.map (\p -> Unplaced $ PrimForeign "llvm" "move" [] [p, ArgVar var' ty' FlowOut Ordinary False]) vals)
2502+
table
2503+
in if List.null untabled
2504+
then NoFork
2505+
else PrimFork var ty final (zip [0..] (List.map (`prependToBody` body) untabled)) dlft
2506+
unMergeFork fork = shouldnt $ "unMergeFork on non-merged " ++ show fork
2507+
2508+
-- |Replace a default-y MergedFork with a guarded non-defaulted MergedFork in a ProcBody,
2509+
-- with the given var used int the fork
2510+
guardedMergedFork :: PrimVarName -> PrimVarName -> TypeSpec -> Integer -> ProcBody -> Maybe ProcBody -> ProcBody
2511+
guardedMergedFork _ _ _ _ body Nothing = body
2512+
guardedMergedFork tmp var ty limit body (Just dflt) =
2513+
ProcBody
2514+
[Unplaced $ PrimForeign "llvm" "icmp_ule" []
2515+
[ArgVar var ty FlowIn Ordinary False, ArgInt limit ty, ArgVar tmp bit FlowOut Ordinary False]]
2516+
$ PrimFork tmp bit True (zip [0..] [dflt,body]) Nothing
2517+
where bit = Representation $ Bits 1
24672518

24682519
data LLBlock = LLBlock {
24692520
llInstrs::[LLInstr],
@@ -2621,13 +2672,14 @@ foldBodyPrims primFn emptyConj abDisj (ProcBody pprims fork) =
26212672
[] -> a
26222673
(pp:pps) -> primFn (final && List.null pps) (content pp) a)
26232674
emptyConj $ tails pprims
2675+
foldAll = List.foldl (\a b -> abDisj a $ foldBodyPrims primFn common abDisj b)
26242676
in case fork of
26252677
NoFork -> common
2626-
PrimFork _ _ _ [] _ -> shouldnt "empty clause list in a PrimFork"
2678+
PrimFork _ _ _ [] _ -> shouldnt "foldBodyPrims empty clause list in a PrimFork"
26272679
PrimFork _ _ _ (body:bodies) deflt ->
2628-
List.foldl (\a b -> abDisj a $ foldBodyPrims primFn common abDisj b)
2629-
(foldBodyPrims primFn common abDisj body)
2630-
$ bodies ++ maybeToList deflt
2680+
foldAll (foldBodyPrims primFn common abDisj $ snd body) $ List.map snd bodies ++ maybeToList deflt
2681+
MergedFork{forkBody=body, forkDefault=deflt} ->
2682+
foldAll (foldBodyPrims primFn common abDisj body) $ maybeToList deflt
26312683

26322684

26332685
-- |Similar to foldBodyPrims, except that it assumes that abstract
@@ -2647,14 +2699,16 @@ foldBodyDistrib primFn emptyConj abDisj abConj (ProcBody pprims fork) =
26472699
[] -> a
26482700
(pp:pps) -> primFn (final && List.null pps) (content pp) a)
26492701
emptyConj $ tails pprims
2702+
foldAll = (abConj common .) . List.foldl (\a b -> abDisj a $ foldBodyDistrib primFn common abDisj abConj b)
26502703
in case fork of
26512704
NoFork -> common
2652-
PrimFork _ _ _ [] _ -> shouldnt "empty clause list in a PrimFork"
2705+
PrimFork _ _ _ [] _ -> shouldnt "foldBodyDistrib empty clause list in a PrimFork"
26532706
PrimFork _ _ _ (body:bodies) deflt ->
2654-
abConj common $
2655-
List.foldl (\a b -> abDisj a $ foldBodyDistrib primFn common abDisj abConj b)
2656-
(foldBodyPrims primFn common abDisj body)
2657-
$ bodies ++ maybeToList deflt
2707+
foldAll (foldBodyDistrib primFn common abDisj abConj $ snd body) $ List.map snd bodies ++ maybeToList deflt
2708+
MergedFork{forkBody=body, forkDefault=deflt} ->
2709+
foldAll (foldBodyDistrib primFn common abDisj abConj body) $ maybeToList deflt
2710+
2711+
26582712

26592713

26602714
-- |Traverse a ProcBody applying a monadic primFn to every Prim and applying a
@@ -2667,8 +2721,11 @@ mapLPVMBodyM primFn argFn (ProcBody pprims fork) = do
26672721
case fork of
26682722
NoFork -> return ()
26692723
(PrimFork _ _ _ bodies deflt) -> do
2670-
mapM_ (mapLPVMBodyM primFn argFn) bodies
2671-
maybe (return ()) (mapLPVMBodyM primFn argFn) deflt
2724+
mapM_ (mapLPVMBodyM primFn argFn . snd) bodies
2725+
forM_ deflt (mapLPVMBodyM primFn argFn)
2726+
MergedFork{forkBody=body,forkDefault=deflt} -> do
2727+
mapLPVMBodyM primFn argFn body
2728+
forM_ deflt (mapLPVMBodyM primFn argFn)
26722729

26732730

26742731
-- |Handle a single Prim for mapLPVMBodyM doing the needful.
@@ -3631,6 +3688,7 @@ expOutputs (DisjExp pexp1 pexp2) = pexpListOutputs [pexp1,pexp2]
36313688
expOutputs (Where _ pexp) = expOutputs $ content pexp
36323689
expOutputs (CondExp _ pexp1 pexp2) = pexpListOutputs [pexp1,pexp2]
36333690
expOutputs (Fncall _ _ _ args) = pexpListOutputs args
3691+
expOutputs (ForeignFn "lpvm" "sizeof" _ (_:args)) = pexpListOutputs args
36343692
expOutputs (ForeignFn _ _ _ args) = pexpListOutputs args
36353693
expOutputs (CaseExp _ cases deflt) =
36363694
pexpListOutputs $ maybe id (:) deflt (snd <$> cases)
@@ -4097,8 +4155,17 @@ showFork ind (PrimFork var ty last bodies deflt) =
40974155
":" ++ show ty ++ " of" ++
40984156
List.concatMap (\(val,body) ->
40994157
startLine ind ++ show val ++ ":" ++
4100-
showBlock (ind+4) body ++ "\n")
4101-
(zip [0..] bodies)
4158+
showBlock (ind+4) body ++ "\n") bodies
4159+
++ maybe "" (\b -> startLine ind ++ "else:"
4160+
++ showBlock (ind+4) b ++ "\n") deflt
4161+
showFork ind (MergedFork var ty last vars body deflt) =
4162+
startLine ind ++ "factored " ++ (if last then "~" else "") ++ show var ++
4163+
":" ++ show ty ++ " of" ++
4164+
List.concatMap (\(var, ty, vals) ->
4165+
startLine (ind + 2) ++ "?" ++ show var ++ ":" ++ show ty ++
4166+
" <- [ " ++ intercalate ", " (List.map show vals) ++ " ]")
4167+
vars
4168+
++ showBlock (ind+4) body
41024169
++ maybe "" (\b -> startLine ind ++ "else:"
41034170
++ showBlock (ind+4) b ++ "\n") deflt
41044171

src/AliasAnalysis.hs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import Config (specialName2)
4141
data AliasMapLocalItem
4242
= LiveVar PrimVarName
4343
| AliasByGlobal GlobalInfo
44+
| AliasByConstant PrimArg
4445
| AliasByParam PrimVarName
4546
| MaybeAliasByParam PrimVarName
4647
deriving (Eq, Ord, Show)
@@ -193,8 +194,11 @@ aliasedByFork caller body analysisInfo = do
193194
logAlias ">>> Forking:"
194195
analysisInfos <-
195196
mapM (\body' -> aliasedByBody caller body' analysisInfo)
196-
$ fBodies ++ maybeToList deflt
197+
$ List.map snd fBodies ++ maybeToList deflt
197198
return $ mergeAnalysisInfo analysisInfos
199+
MergedFork{} -> do
200+
logAlias ">>> Merged fork:"
201+
aliasedByFork caller body{bodyFork=unMergeFork fork} analysisInfo
198202
NoFork -> do
199203
logAlias ">>> No fork."
200204
-- drop "deadCells", we don't need it after fork
@@ -338,17 +342,20 @@ _maybeAliasPrimArgs args = do
338342
let escapedVars = catMaybes args'
339343
return escapedVars
340344
where
341-
filterArg arg =
342-
case arg of
343-
ArgVar{argVarName=var, argVarType=ty} -> maybeAddressAlias arg ty $ LiveVar var
344-
ArgGlobal global ty -> maybeAddressAlias arg ty $ AliasByGlobal global
345-
_ -> return Nothing
345+
filterArg arg@ArgVar{argVarName=var, argVarType=ty} = maybeAddressAlias arg ty $ LiveVar var
346+
filterArg arg@(ArgGlobal global ty) = maybeAddressAlias arg ty $ AliasByGlobal global
347+
filterArg arg@ArgClosure{} | argIsConst arg = return $ Just $ AliasByConstant arg
348+
filterArg arg@ArgString{} = return $ Just $ AliasByConstant arg
349+
filterArg _ = return Nothing
346350
maybeAddressAlias arg ty item = do
347351
rep <- lookupTypeRepresentation ty
348-
-- Only Pointer types will create alias
349-
if rep == Just Pointer
352+
if maybe False aliasedRep rep
350353
then return $ Just item
351354
else return Nothing
355+
aliasedRep CPointer = True
356+
aliasedRep Pointer = True
357+
aliasedRep Func{} = True
358+
aliasedRep _ = False
352359

353360

354361
-- Check Arg aliases in one of proc calls inside a ProcBody

0 commit comments

Comments
 (0)