Commit 8181b51f authored by Tobias Hombücher's avatar Tobias Hombücher
Browse files

Adds dedicated continue/break label for loops and switch statements

parent da5c5e6c
Pipeline #132876 passed with stages
in 70 minutes and 35 seconds
......@@ -192,8 +192,8 @@ run = fix $ \run' -> proc stmts_ -> do
InvokeStmt invoke -> do
evalInvoke run' -< invoke
run' -< rest
Continue _ -> run' -< rest
Break _ -> run' -< rest
Goto _ -> run' -< rest
Label _ -> run' -< rest
[] -> failString -< printf "PC out of range: #instr=%d" (Vec.length (stmts frame))
{-# INLINE run #-}
......
......@@ -2,7 +2,7 @@
{-# OPTIONS_GHC -Wno-typed-holes #-}
module Preprocessing.GraphToStructured where
import Syntax.General ( Expr, Immediate, label )
import Syntax.General ( Expr, Immediate )
import Syntax.Unstructured ( Statement'(If, TableSwitch, LookupSwitch) )
import qualified Syntax.Structured as Struct
import qualified Syntax.Syntax as Syntax
......@@ -16,7 +16,6 @@ import qualified Data.Graph.Inductive.Query.Dominators as FGLD
import Data.List ( (\\), delete, intersect)
import Data.HashMap.Lazy (HashMap)
import qualified Data.HashMap.Lazy as Map
import Data.Maybe(isNothing,isJust)
data LeaveLoop = LeaveTrue
| LeaveFalse
......@@ -75,8 +74,8 @@ processIf_ :: SCFG.CFG -> HashMap FGL.Node FGL.Node -> HashMap FGL.Node FGL.Node
processIf_ _ _ _ _ [] _ _ = error "should not be called with an empty list of active nodes"
processIf_ graph loopMap switchMap oldNodes (topNode:rest) removedNodes e =
let (nodeTrue, nodeFalse) = getBranches graph topNode
true_check = checkContinueBreak loopMap nodeTrue rest
false_check = checkContinueBreak loopMap nodeFalse rest
true_check = checkContinueBreakLoop loopMap nodeTrue rest
false_check = checkContinueBreakLoop loopMap nodeFalse rest
in case (true_check,false_check) of
(Nothing,Nothing) ->
let join = lidom graph topNode removedNodes
......@@ -104,7 +103,9 @@ processIf_ graph loopMap switchMap oldNodes (topNode:rest) removedNodes e =
-- | 3. calculate all nodes between inn and out
-- | it is important to remove the if node as from the calculated nodes to avoid transforming the same loop again
-- | 4. add the if node to the list of removed nodes to avoid transforming the same loop again
-- | 5. transform the if node to a structure loop statement
-- | 5. add the target continuation label as the last statement of the loop-body
-- | 6. add the target break label as the first statement of the continuation statements
-- | 7. transform the if node to a structure loop statement
-- | and recursively call transform to calculate the inn and out statements respectively
processLoop_ :: SCFG.CFG -> HashMap FGL.Node FGL.Node -> HashMap FGL.Node FGL.Node -> [FGL.Node] -> [FGL.Node] -> [FGL.Node] -> Expr -> [Struct.Statement]
processLoop_ _ _ _ _ [] _ _ = error "should not be called with an empty list of active nodes"
......@@ -114,32 +115,37 @@ processLoop_ graph loopMap switchMap oldNodes (if_node:rest) removedNodes e =
nodes_out = nodesBetween graph (if_node:rest) (if_node:removedNodes) out Nothing
nodes_in = delete if_node (nodesBetween graph rest removedNodes inn (Just out))
removedNodes_ = if_node:removedNodes
-- maybe create unique label here for each loop statement
body = transform graph loopMap_ switchMap oldNodes nodes_in removedNodes_ ++ [Struct.Label $ Struct.ContinueTarget if_node]
continuation = Struct.Label (Struct.BreakTarget if_node) : transform graph loopMap_ switchMap oldNodes nodes_out removedNodes_
in case leaveLoop of
LeaveTrue -> Struct.LoopLeaveTrue e (transform graph loopMap_ switchMap oldNodes nodes_in removedNodes_)
: transform graph loopMap_ switchMap oldNodes nodes_out removedNodes_
LeaveFalse -> Struct.LoopLeaveFalse e (transform graph loopMap_ switchMap oldNodes nodes_in removedNodes_)
: transform graph loopMap_ switchMap oldNodes nodes_out removedNodes_
LeaveTrue -> Struct.LoopLeaveTrue e body : continuation
LeaveFalse -> Struct.LoopLeaveFalse e body : continuation
-- |Processes a tableswitch / lookupswitch
-- |Requires a graph, tableswitch / lookupswitch node, the respective immediate
-- |processes tableswitch and lookupswitch
-- |TODO Break Continue support: 1. Within Loops, 2. Within the switch itself
-- | 1. calculate the case and default successors
-- | 2. calcluate the join node from the case and default successors
-- | 3. calculate all nodes between cases and default and the join node respectively
-- | 4. calculate all nodes starting from join
-- | 5. transform the switch node into a structured switch statement
-- | and recursively call transform to calculate the case, default and join statements
-- | 2. calculate the join point
-- | 3. if there is a join point
-- | 3.1. then add the topNode to a list that tracks the join points of all switch statements
-- | 3.2. else do nothing
-- | 4. check whether there are any breaks or continue statements to loop statements
-- | 5. calculate the statement for all cases
-- | 6. calculate the activeNodes starting from the join node
-- | 7. return the structured switch statement with the already calculated case statments,
-- | add the target label for any switch-break statements
-- | and add the here calculated continuation statements
processSwitch_ :: SCFG.CFG -> HashMap FGL.Node FGL.Node -> HashMap FGL.Node FGL.Node -> [FGL.Node] -> [FGL.Node] -> [FGL.Node] -> Immediate -> [Struct.Statement]
processSwitch_ _ _ _ _ [] _ _ = error "should not be called with an empty list of active nodes"
processSwitch_ graph loopMap switchMap oldNodes (topNode:rest) removedNodes i =
let (caseIds,cases,def) = getCasesAndDefault graph topNode
join = lidom graph topNode removedNodes
switchMap_ = case join of Just a -> Map.insertWith (\_ old -> old) a topNode switchMap
Nothing -> switchMap
join = lidom graph topNode removedNodes
loopInstrCases = map (\x -> checkContinueBreak loopMap x rest) cases
stmts_def = case checkContinueBreak loopMap def rest of
loopInstrCases = map (\x -> checkContinueBreakLoop loopMap x rest) cases
stmts_def = case checkContinueBreakLoop loopMap def rest of
Just a -> Struct.Default [a]
_ -> let activeNodes_def = nodesBetween graph (topNode:rest) removedNodes def join
in Struct.Default (transform graph loopMap switchMap_ oldNodes activeNodes_def removedNodes)
......@@ -150,23 +156,11 @@ processSwitch_ graph loopMap switchMap oldNodes (topNode:rest) removedNodes i =
in Struct.Case case_id (transform graph loopMap switchMap_ oldNodes activeNodes_case removedNodes)
)
tmp1
-- tmp2 = filter (\(_,x) -> isNothing x) tmp1
-- tmp3 = filter (\(_,x) -> isJust x) tmp1
-- activeNodes_cases = [nodesBetween graph (topNode:rest) removedNodes case_ join | case_ <- cases]
activeNodes_join = case join of Just a -> nodesBetween graph (topNode:rest) removedNodes a Nothing
Nothing -> []
-- test = map (\x -> checkContinueBreak loopMap x rest) cases
-- in error $ "test: " ++ show test
-- ++ "activeNodes_cases: " ++ show activeNodes_cases
-- ++ "cases: " ++ show cases
-- in Struct.Switch i
-- [Struct.Case int stmts | (int,stmts) <- zip caseIds (map (\x -> transform graph loopMap switchMap_ oldNodes x removedNodes) activeNodes_cases)]
-- (Struct.Default (transform graph loopMap switchMap_ oldNodes activeNodes_def removedNodes)):transform graph loopMap switchMap_ oldNodes activeNodes_join removedNodes
in Struct.Switch i stmts_cases stmts_def
: transform graph loopMap switchMap_ oldNodes activeNodes_join removedNodes
: (Struct.Label (Struct.BreakTarget topNode)
: transform graph loopMap switchMap_ oldNodes activeNodes_join removedNodes)
-- |process base nodes, basically everything that has only one outgoing edge
......@@ -187,7 +181,7 @@ processBase_ graph loopMap switchMap oldNodes (topNode:activeNodes) removedNodes
[] -> [Syntax.convert lab_]
[successor] ->
let stmt = Syntax.convert lab_
in case checkContinueBreak loopMap successor activeNodes of
in case checkContinueBreakLoop loopMap successor activeNodes of
Just a -> stmt:[a]
_ -> case checkBreakSwitch switchMap successor activeNodes of
Just a -> stmt:[a]
......@@ -254,9 +248,9 @@ lca graph nodes =
-- |Finds the lowest immediate dominator of a given node in a given graph
-- |the lidom is guaranteed to be visited by all possible paths starting from the given node
-- |for this immediate dominators are used:
-- |d dom n: every path from n must go through d
-- |d dom n: every path from then entry node to n must go through d
-- |d strictly dom n: d dom n but is unequal to n
-- |d immediate dom n: d strictly dom n, but doesn not strictly dominate any other that strictly dominates n
-- |d immediate dom n: d strictly dom n, but d does not strictly dominate any other that strictly dominates n
-- | 1. calculate all dominators of the given node in the original graph
-- | 2. calculate all dominators of the given node that are entry points to loops
-- | 3. reverse topologically sort all nodes in the graph, this makes the "deepest node" appear first
......@@ -334,7 +328,7 @@ checkOutOfBounds :: FGL.Node -> [FGL.Node] -> Bool
checkOutOfBounds topNode activeNodes = topNode `notElem` activeNodes
-- |Determines whether a given top node should be a Continue or Break node
-- |Determines whether a given top node should be a Continue or Break node in a Loop
-- | 1. if checkOutOfBounds is true
-- | 1.1. if top node is part of the values of loopMap
-- | 1.1.1. return Continue with the node-id of the respective topNode
......@@ -342,20 +336,27 @@ checkOutOfBounds topNode activeNodes = topNode `notElem` activeNodes
-- | 1.2.1. if there is a value in loopMap that has topNode as a key
-- | 1.2.1.1. return looked up value
-- | else return Nothing
checkContinueBreak :: HashMap FGL.Node FGL.Node -> FGL.Node -> [FGL.Node] -> Maybe Struct.Statement
checkContinueBreak loopMap topNode activeNodes =
checkContinueBreakLoop :: HashMap FGL.Node FGL.Node -> FGL.Node -> [FGL.Node] -> Maybe Struct.Statement
checkContinueBreakLoop loopMap topNode activeNodes =
if checkOutOfBounds topNode activeNodes
then if topNode `elem` loopMap
then Just $ Struct.Continue topNode
then Just $ Struct.Goto $ Struct.Continue topNode
else case Map.lookup topNode loopMap of
Just a -> Just $ Struct.Break a
Just a -> Just $ Struct.Goto $ Struct.Break a
_ -> Nothing
else Nothing
-- |Determines whetehr a given top node should be a Break node in a Switch statement
-- |1. if checkOutOfBounds is true
-- |1.1. if top node is a key in the switchMap
-- |1.1.1. return a Break statament with the value associated to the key as argument
-- |1.1.2. return Nothing
-- |1.2. return Nothing
checkBreakSwitch :: HashMap FGL.Node FGL.Node -> FGL.Node -> [FGL.Node] -> Maybe Struct.Statement
checkBreakSwitch switchMap topNode activeNodes =
if checkOutOfBounds topNode activeNodes
then case Map.lookup topNode switchMap of
Just a -> Just $ Struct.Break a
Just a -> Just $ Struct.Goto $ Struct.Break a
_ -> Nothing
else Nothing
\ No newline at end of file
......@@ -26,10 +26,20 @@ data Statement
| Return (Maybe Immediate)
| Throw Immediate
| InvokeStmt Invoke
| Break Int
| Goto GotoLabel
| Label TargetLabel
deriving (Eq)
data GotoLabel
= Break Int
| Continue Int
deriving (Eq)
data TargetLabel
= BreakTarget Int
| ContinueTarget Int
deriving (Eq)
data Case
= Case Int [Statement]
| Default [Statement]
......@@ -59,8 +69,20 @@ instance Pretty Statement where
Return imm -> "Return" <+> pretty imm
Throw imm -> "Throw" <+> pretty imm
InvokeStmt invoke -> "InvokeStmt" <+> pretty invoke
Break int -> "Break" <+> pretty int
Continue int -> "Continue" <+> pretty int
Goto gotoLabel -> "Goto" <+> pretty gotoLabel
Label targetLabel -> "Label" <+> pretty targetLabel
instance Show GotoLabel where show = show . pretty
instance Pretty GotoLabel where
pretty gotoLabel = case gotoLabel of
Break i -> "Break" <+> pretty i
Continue i -> "Continue" <+> pretty i
instance Show TargetLabel where show = show . pretty
instance Pretty TargetLabel where
pretty targetLabel = case targetLabel of
BreakTarget i -> "Target Break" <+> pretty i
ContinueTarget i -> "Target Continue" <+> pretty i
instance Show Case where show = show . pretty
instance Pretty Case where
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment