Compare commits

..

No commits in common. "690985cb874537e3d149d874279056b95f7019da" and "08049e99551d5770a0c6575a760fbb8d2267eaae" have entirely different histories.

4 changed files with 22 additions and 121 deletions

View File

@ -17,7 +17,7 @@ build-type: Simple
extra-source-files: README.md extra-source-files: README.md
library eoc-lib library eoc-lib
exposed-modules: Eoc, Bril, Bril.CFG exposed-modules: Eoc, Bril
hs-source-dirs: lib hs-source-dirs: lib
build-depends: build-depends:
base >=4.13 && <4.18, base >=4.13 && <4.18,
@ -25,9 +25,8 @@ library eoc-lib
aeson >= 2.2, aeson >= 2.2,
sorted-list ^>= 0.2, sorted-list ^>= 0.2,
bytestring ^>= 0.11, bytestring ^>= 0.11,
scientific ^>= 0.3, scientific ^>= 0.3
containers ^>= 0.6.7 default-language: Haskell2010
default-language: Haskell2010
default-extensions: DeriveGeneric, OverloadedStrings default-extensions: DeriveGeneric, OverloadedStrings
executable eoc executable eoc
@ -47,7 +46,6 @@ test-suite tests
build-depends: build-depends:
base >=4.13 && <4.18, base >=4.13 && <4.18,
HUnit >=1.6, HUnit >=1.6,
QuickCheck ^>=2.15,
eoc-lib, eoc-lib,
text >= 2.0, text >= 2.0,
aeson >= 2.2 aeson >= 2.2

View File

@ -120,24 +120,24 @@ instrFromString s
instance Show InstrOperation where instance Show InstrOperation where
show op = case op of show op = case op of
Add -> "add" Nop -> "add"
Sub -> "sub" Add -> "sub"
Mul -> "mul" Sub -> "mul"
Eq -> "eq" Mul -> "eq"
Lt -> "lt" Eq -> "lt"
Gt -> "gt" Lt -> "gt"
Le -> "le" Gt -> "le"
Ge -> "ge" Le -> "ge"
Not -> "not" Ge -> "not"
And -> "and" Not -> "and"
Or -> "or" And -> "or"
Jmp -> "jmp" Or -> "jmp"
Br -> "br" Jmp -> "br"
Ret -> "ret" Br -> "ret"
Call -> "call" Ret -> "call"
Print -> "print" Call -> "print"
Id -> "id" Print -> "id"
Nop -> "nop" Id -> "nop"
optionalArrayField :: FromJSON a => Data.Aeson.Object -> Data.Aeson.Key -> Parser [a] optionalArrayField :: FromJSON a => Data.Aeson.Object -> Data.Aeson.Key -> Parser [a]

View File

@ -1,85 +0,0 @@
module Bril.CFG (BasicBlock, CFG, createCFG) where
import Bril
import qualified Data.Map.Strict as Map
data BasicBlock = BasicBlock {
instrs :: [Instruction],
incoming :: [String]
}
deriving (Show)
data CFG = CFG {
cfgBlocks :: Map.Map String BasicBlock,
cfgStart :: String
}
deriving (Show)
createCFG :: [Instruction] -> CFG
createCFG instrs =
let
(initCFG, firstLabel) = initializeCFG $ addFallthroughJmp $ splitBBs $ addInitialLabel instrs
cfgBlocks' = foldr processBB (cfgBlocks initCFG) (Map.keys (cfgBlocks initCFG))
in
CFG cfgBlocks' firstLabel
where
processBB :: String -> Map.Map String BasicBlock -> Map.Map String BasicBlock
processBB label m = addBBJumps label (outgoingCFGLabels m label) m
addBBJumps :: String -> [String] -> Map.Map String BasicBlock -> Map.Map String BasicBlock
addBBJumps bblockLabel incomingLabels m = Map.adjust (addLabels incomingLabels) bblockLabel m
addLabels :: [String] -> BasicBlock -> BasicBlock
addLabels labels (BasicBlock instrs incoming) = (BasicBlock instrs (incoming ++ labels))
initializeCFG :: [([Instruction], String)] -> (CFG, String)
initializeCFG instrs =
let mappedBlocks = foldr mapBlock Map.empty instrs -- Map.fromList $ map swap instrs
firstLabel = snd . head $ instrs
in (CFG mappedBlocks firstLabel, firstLabel)
where
mapBlock (instrs, label) m = Map.insert label (BasicBlock instrs []) m
addFallthroughJmp :: [([Instruction], String)] -> [([Instruction], String)]
addFallthroughJmp blocks =
let blocks' = map addJumpToNextBB $ zip blocks $ tail $ map snd blocks
in blocks' ++ [last blocks]
where
addJumpToNextBB (block@(instrs, label), nextLabel)
-- TODO: handle empty instrs
| isJump (last instrs) = block
| otherwise = (instrs ++ [EffectInstr Jmp [] [] [nextLabel]], label)
splitBBs :: [Instruction] -> [([Instruction], String)]
splitBBs instrs = zip (tail basicBlocks) labels
where
(basicBlocks, labels) = foldr splitBBs' ([[]], []) instrs
splitBBs' instr (bblocks, labels)
| isLabel instr = ([] : bblocks, (labelName instr) : labels)
| isJump instr = ([instr] : (tail bblocks) , labels)
| otherwise = ((instr : (head bblocks)) : (tail bblocks), labels)
addInitialLabel :: [Instruction] -> [Instruction]
addInitialLabel instrs@(firstInstr : instrs')
| isLabel firstInstr = instrs
| otherwise = (Label "@start") : instrs
addInitialLabel [] = []
labelName (Label name) = name
isLabel instr = case instr of
(Label _) -> True
_ -> False
isJump instr = case instr of
(EffectInstr op _ _ _) -> op == Jmp || op == Br
_ -> False
outgoingCFGLabels :: Map.Map String BasicBlock -> String -> [String]
outgoingCFGLabels m label =
case Map.lookup label m of
Just bb -> outgoingLabels bb
_ -> []
outgoingLabels :: BasicBlock -> [String]
outgoingLabels (BasicBlock instrs _) =
let (EffectInstr lastOp _ _ labels) = last instrs
in labels

View File

@ -1,8 +1,7 @@
module Main where module Main where
import qualified Bril as B import qualified Bril as B
import qualified Bril.CFG as BCFG import Data.Aeson (eitherDecode, decode, toJSON, parseJSON, Result(..))
import Data.Aeson (eitherDecode, decode, encode, toJSON, parseJSON, Result(..))
import Data.Aeson.Types (parse) import Data.Aeson.Types (parse)
import Data.Text import Data.Text
import Data.Maybe import Data.Maybe
@ -11,7 +10,6 @@ import Data.Function ((&))
import Control.Exception (try) import Control.Exception (try)
import Test.HUnit import Test.HUnit
import qualified Test.QuickCheck as QC
import qualified System.Exit as Exit import qualified System.Exit as Exit
testTypes :: Test testTypes :: Test
@ -83,10 +81,6 @@ testInstrs = TestCase $ do
(eitherDecode "{\"op\": \"id\", \"dest\": \"a\", \"type\": \"bool\", \"args\": [\"b\"]}") (eitherDecode "{\"op\": \"id\", \"dest\": \"a\", \"type\": \"bool\", \"args\": [\"b\"]}")
(Right $ B.ValueInstr B.Id B.Bool "a" ["b"] [] []) (Right $ B.ValueInstr B.Id B.Bool "a" ["b"] [] [])
assertEqual "parse label"
(eitherDecode "{\"label\": \"test\"}")
(Right $ B.Label "test")
testProgramFromFiles :: Test testProgramFromFiles :: Test
testProgramFromFiles = TestCase $ do testProgramFromFiles = TestCase $ do
res <- try $ (B.parseBrilFromPath "bril-sources/add.json") :: IO (Either IOError (Either String B.Program)) res <- try $ (B.parseBrilFromPath "bril-sources/add.json") :: IO (Either IOError (Either String B.Program))
@ -94,10 +88,6 @@ testProgramFromFiles = TestCase $ do
(Right parseResult) -> assertBool "parse add.json" $ isRight parseResult (Right parseResult) -> assertBool "parse add.json" $ isRight parseResult
_ -> assertFailure "cannot open file" _ -> assertFailure "cannot open file"
prop_InvariantBrilSerialization :: B.Program -> Bool
prop_InvariantBrilSerialization program =
(decode (encode program)) == (Just program)
tests :: Test tests :: Test
tests = TestList [ tests = TestList [
@ -110,6 +100,4 @@ tests = TestList [
main :: IO () main :: IO ()
main = do main = do
result <- runTestTT tests result <- runTestTT tests
-- QC.quickCheck prop_InvariantBrilSerialization
if failures result > 0 then Exit.exitFailure else Exit.exitSuccess if failures result > 0 then Exit.exitFailure else Exit.exitSuccess