├── LICENSE ├── ORGANIZATION ├── README.md ├── cspgen.cabal ├── examples ├── basic │ ├── Descriptions │ ├── cpp_test_001.cpp │ ├── cpp_test_001.lltest.csp │ ├── cpp_test_002.cpp │ ├── cpp_test_002.lltest.csp │ ├── cpp_test_003.cpp │ ├── cpp_test_003.lltest.csp │ ├── cpp_test_004.cpp │ ├── cpp_test_004.lltest.csp │ ├── cpp_test_005.cpp │ ├── cpp_test_005.lltest.csp │ ├── cpp_test_006.cpp │ ├── cpp_test_006.lltest.csp │ ├── cpp_test_007.cpp │ ├── cpp_test_007.lltest.csp │ ├── cpp_test_008.cpp │ ├── cpp_test_008.lltest.csp │ ├── externals │ ├── externalsLLVM │ ├── runtime.csp │ ├── runtimeChans.csp │ ├── runtimeCont.csp │ ├── runtimeLLVM.csp │ ├── runtimePThread.csp │ ├── test_001.c │ ├── test_001.ctest.csp │ ├── test_001.lltest.csp │ ├── test_002.c │ ├── test_002.ctest.csp │ ├── test_002.lltest.csp │ ├── test_003.c │ ├── test_003.ctest.csp │ ├── test_003.lltest.csp │ ├── test_004.c │ ├── test_004.ctest.csp │ ├── test_004.lltest.csp │ ├── test_005.c │ ├── test_005.ctest.csp │ ├── test_005.lltest.csp │ ├── test_006.c │ ├── test_006.ctest.csp │ ├── test_006.lltest.csp │ ├── test_007.c │ ├── test_007.ctest.csp │ ├── test_007.lltest.csp │ ├── test_008.c │ ├── test_008.ctest.csp │ ├── test_008.lltest.csp │ ├── test_009.c │ ├── test_009.ctest.csp │ ├── test_009.lltest.csp │ ├── test_010.c │ ├── test_010.ctest.csp │ ├── test_010.lltest.csp │ ├── test_011.c │ ├── test_011.ctest.csp │ ├── test_011.lltest.csp │ ├── test_012.c │ ├── test_012.ctest.csp │ ├── test_012.lltest.csp │ ├── test_013.c │ ├── test_013.ctest.csp │ ├── test_013.lltest.csp │ ├── test_014.c │ ├── test_014.ctest.csp │ ├── test_014.lltest.csp │ ├── test_015.c │ ├── test_015.ctest.csp │ ├── test_015.lltest.csp │ ├── test_016.c │ ├── test_016.ctest.csp │ ├── test_016.lltest.csp │ ├── test_017.c │ ├── test_017.ctest.csp │ ├── test_017.lltest.csp │ ├── test_018.c │ ├── test_018.ctest.csp │ ├── test_018.lltest.csp │ ├── test_019.c │ ├── test_019.ctest.csp │ ├── test_019.lltest.csp │ ├── test_020.c │ ├── test_020.ctest.csp │ ├── test_020.lltest.csp │ ├── test_021.c │ ├── test_021.ctest.csp │ ├── test_021.lltest.csp │ ├── test_022.c │ ├── test_022.ctest.csp │ ├── test_022.lltest.csp │ ├── test_023.c │ ├── test_023.ctest.csp │ ├── test_023.lltest.csp │ ├── test_024.c │ ├── test_024.ctest.csp │ ├── test_024.lltest.csp │ ├── test_025.c │ ├── test_025.ctest.csp │ ├── test_025.lltest.csp │ ├── test_026.c │ ├── test_026.ctest.csp │ ├── test_026.lltest.csp │ ├── test_027.c │ ├── test_027.ctest.csp │ ├── test_027.lltest.csp │ ├── test_028.c │ ├── test_028.ctest.csp │ ├── test_028.lltest.csp │ ├── test_029.c │ ├── test_029.ctest.csp │ ├── test_029.lltest.csp │ ├── test_030.c │ ├── test_030.ctest.csp │ ├── test_030.lltest.csp │ ├── test_031.c │ ├── test_031.ctest.csp │ ├── test_031.lltest.csp │ ├── test_032.c │ ├── test_032.ctest.csp │ ├── test_032.lltest.csp │ ├── test_033.c │ ├── test_033.ctest.csp │ ├── test_033.lltest.csp │ ├── test_034.c │ ├── test_034.ctest.csp │ ├── test_034.lltest.csp │ ├── test_035.c │ ├── test_035.ctest.csp │ ├── test_035.lltest.csp │ ├── test_036.c │ ├── test_036.ctest.csp │ ├── test_036.lltest.csp │ ├── test_037.c │ ├── test_037.ctest.csp │ ├── test_037.lltest.csp │ ├── test_038.c │ ├── test_038.ctest.csp │ ├── test_038.lltest.csp │ ├── test_039.c │ ├── test_039.ctest.csp │ ├── test_039.lltest.csp │ ├── test_040.c │ ├── test_040.ctest.csp │ ├── test_040.lltest.csp │ ├── test_041.c │ ├── test_041.ctest.csp │ ├── test_041.lltest.csp │ ├── test_042.c │ ├── test_042.ctest.csp │ ├── test_042.lltest.csp │ ├── test_043.c │ ├── test_043.ctest.csp │ ├── test_043.lltest.csp │ ├── test_044.c │ ├── test_044.ctest.csp │ ├── test_044.lltest.csp │ ├── test_045.c │ ├── test_045.ctest.csp │ ├── test_045.lltest.csp │ ├── test_046.c │ ├── test_046.ctest.csp │ ├── test_046.lltest.csp │ ├── test_047.c │ ├── test_047.ctest.csp │ ├── test_047.lltest.csp │ ├── test_048.c │ ├── test_048.ctest.csp │ ├── test_048.lltest.csp │ ├── test_049.c │ ├── test_049.ctest.csp │ ├── test_049.lltest.csp │ ├── test_050.c │ ├── test_050.ctest.csp │ ├── test_050.lltest.csp │ ├── test_051.c │ ├── test_051.ctest.csp │ ├── test_051.lltest.csp │ ├── test_052.c │ ├── test_052.ctest.csp │ ├── test_052.lltest.csp │ ├── test_053.c │ ├── test_053.ctest.csp │ ├── test_053.lltest.csp │ ├── test_054.c │ ├── test_054.ctest.csp │ ├── test_054.lltest.csp │ ├── test_055.c │ ├── test_055.lltest.csp │ ├── test_056.c │ ├── test_056.lltest.csp │ ├── test_057.c │ ├── test_057.lltest.csp │ ├── test_058.c │ └── test_058.lltest.csp └── demos │ ├── DGraph.png │ ├── Divergence.c │ ├── Divergence.png │ ├── DivergenceCheck.csp │ ├── RCGraph.png │ ├── RaceCond.c │ ├── RaceCondRefines.csp │ ├── externals │ ├── runtime.csp │ └── runtimePThread.csp ├── src ├── CodeGen │ ├── C │ │ ├── ASTtoCFG.hs │ │ ├── CFG.hs │ │ ├── CFGEmptyBlocks.hs │ │ ├── CFGLiveness.hs │ │ ├── CFGPointsTo.hs │ │ ├── CFGPretty.hs │ │ ├── CGMonad.hs │ │ ├── CodeGen.hs │ │ ├── DriverC.hs │ │ ├── Externals.hs │ │ ├── HedgeTrimmer.hs │ │ ├── Parser.hs │ │ ├── Pretty.hs │ │ ├── SimplifyLValues.hs │ │ ├── SimplifyLoop.hs │ │ ├── SimplifyReferences.hs │ │ ├── Syntax.hs │ │ └── SyntaxSimplifier.hs │ ├── Driver.hs │ ├── LLVM │ │ ├── Analysis.hs │ │ ├── CGMonad.hs │ │ ├── DESIGN │ │ ├── DriverLLVM.hs │ │ ├── Externals.hs │ │ ├── ModelBasics.hs │ │ ├── ModelIdentifiers.hs │ │ ├── ModelStack.hs │ │ ├── OPTIMIZATIONS │ │ ├── TODO │ │ └── TransModule.hs │ └── Util │ │ └── LLVMInstrCount.hs ├── Main.hs └── Tests │ ├── CParseTest │ ├── CParseTest.hs │ └── Main.hs │ ├── CSPGenTest │ ├── CSPGenTest.hs │ └── Main.hs │ └── LLVMTest │ ├── LLVMTest.hs │ └── Main.hs └── verif ├── CSP_OpSem.v ├── CSP_Syntax.v ├── Makefile ├── README.md ├── Translation.v └── While_Definitions.v /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, The Charles Stark Draper Laboratory, Inc. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE CHARLES STARK DRAPER LABORATORY, INC BE 19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 21 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 24 | THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /ORGANIZATION: -------------------------------------------------------------------------------- 1 | This file briefly describes the organization of the cspgen development. 2 | 3 | The outer directory contains the cabal file and some documentation. The 4 | top-level directories are: 5 | 6 | src: Contains the haskell source. Main.hs for the command-line tool is here. 7 | 8 | - src/CodeGen/LLVM contains the llvm version. See DriverLLVM.hs for the 9 | external interface, or TransModel.hs for the top-level translation on the 10 | LLVM AST. 11 | 12 | - src/CodeGen/C contains the C version. See DriverC.hs for the external 13 | interface, or CodeGen.hs for the top-level translation on the C AST. 14 | This pass is not organized very well and needs to be refactored. 15 | 16 | - src/Tests has some testing infrastructure 17 | 18 | examples: has our test cases and a few higher-level "demo" examples. 19 | 20 | verif: has the coq proofs 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | cspgen is a command line tool for creating models of software in the 2 | Communicating Sequential Processes (CSP) process calculus. The tool accepts 3 | both C programs and LLVM IR as input, and writes a corresponding .csp file to 4 | disk. The output is compatible with FDR3, the Oxford CSP model checker. FDR 5 | may be used to check the model for for general properties, like deadlock 6 | freedom, divergence freedom and determinism, or may be compared with 7 | specifications written in CSP using refinement. cspgen aims to model the 8 | high-level communication behavior of the input code and to abstract data as much 9 | as possible to reduce model-checking time. It supports a subset of the pthreads 10 | library for multithreading and mutex primitives. 11 | 12 | This repository also includes a formally verified Coq implementation of cspgen's 13 | core algorithm. 14 | 15 | This is prototype, research software. 16 | 17 | 18 | ## Usage 19 | 20 | ``` 21 | Usage: cspgen [OPTIONS] FILE 22 | -o FILE --output=FILE Output destination 23 | -l --llvm Take in LLVM IR rather than C 24 | -d --dump Dump the AST representation of the C-Flat code 25 | -c --emit-c Output the parsed C code 26 | -e FILE --externals=FILE External function specifications 27 | -r FILE --runtime=FILE Runtime file 28 | -p STRING --cpp-opts=STRING Options to be passed to cpp 29 | -t --test Run test files 30 | -w --warn Hide warnings 31 | -i --intermediate Show intermediate results 32 | ``` 33 | 34 | Note: By default, the input is assumed to be a C program. Use the -l flag if 35 | supplying LLVM IR instead. 36 | 37 | ## Installation 38 | 39 | Cspgen is written in Haskell and can be built with cabal, the Haskell package 40 | manager. If you already have cabal installed, simply run `cabal install` from 41 | the top-level `specgen` directory. The build depends on LLVM 3.4, which may be 42 | available from your operating systems package manager. The `cspgen` binary will 43 | be installed to `~/.cabal/bin`. You can add this directory to your path or move 44 | the binary elsewhere. 45 | 46 | ## Examples and Organization 47 | 48 | The `examples` directory contains a variety of C and C++ files we use as test 49 | cases and examples. The tests can be run with `cabal test` or with `cspgen -t`, 50 | which provides more information. Note that some of the LLVM tests are currently 51 | known to fail. 52 | 53 | The `verif` directory contains a coq verification of the core algorithm. 54 | 55 | For information about the organization of the source code, see the ORGANIZATION 56 | file in this directory. 57 | 58 | ## Documention 59 | 60 | Someday there may be some. 61 | 62 | ## Credit 63 | 64 | Cspgen has been developed primarly by Chris Casinghino and Chinedu Okongwu. 65 | 66 | 67 | ## Contact 68 | ------- 69 | 70 | Cspgen is developed by Draper Labs. Contact Chris Casinghino 71 | (ccasinghino@draper.com) for additional information. 72 | -------------------------------------------------------------------------------- /cspgen.cabal: -------------------------------------------------------------------------------- 1 | name: cspgen 2 | version: 0.3.0.1 3 | synopsis: A tool for translating imperative programs to CSP 4 | -- description: 5 | license: BSD3 6 | license-file: LICENSE 7 | -- author: 8 | -- maintainer: 9 | -- copyright: 10 | category: Language 11 | build-type: Simple 12 | cabal-version: >=1.8 13 | 14 | executable cspgen 15 | main-is: Main.hs 16 | hs-source-dirs: src 17 | ghc-options: -Wall -O2 18 | extensions: NamedFieldPuns, TupleSections, DoAndIfThenElse, GADTs, 19 | TypeFamilies, FlexibleContexts, ViewPatterns 20 | other-modules: 21 | build-depends: base >=4.6, 22 | cspretty >= 0.3.3, 23 | hashable >=1.1, 24 | mtl >=2.2, 25 | parsec >=3.1, 26 | transformers >=0.3, 27 | pretty >=1.1, 28 | containers >=0.5, 29 | bytestring >=0.10, 30 | language-c >=0.5, 31 | process >=1.1, 32 | unix >=2.6, 33 | filepath >= 1.3, 34 | hoopl >= 3.10.1, 35 | tasty >= 0.10, 36 | tasty-hunit >= 0.9, 37 | directory >= 1.2, 38 | llvm-general >= 3.4 && < 3.5, 39 | llvm-general-pure >= 3.4 && < 3.5 40 | 41 | test-suite CParseTest 42 | type: exitcode-stdio-1.0 43 | main-is: CParseTest/Main.hs 44 | hs-source-dirs: src, src/Tests 45 | ghc-options: -Wall -O2 46 | extensions: NamedFieldPuns, TupleSections, DoAndIfThenElse, GADTs, 47 | TypeFamilies, FlexibleContexts, ViewPatterns 48 | other-modules: 49 | build-depends: base >=4.6, 50 | cspretty >= 0.3.2, 51 | hashable >=1.1, 52 | mtl >=2.2, 53 | parsec >=3.1, 54 | transformers >=0.3, 55 | pretty >=1.1, 56 | containers >=0.5, 57 | bytestring >=0.10, 58 | language-c >=0.5, 59 | process >=1.1, 60 | unix >=2.6, 61 | filepath >= 1.3, 62 | hoopl >= 3.10.1, 63 | Cabal, 64 | tasty >= 0.10, 65 | tasty-hunit >= 0.9 66 | 67 | test-suite CSPGenTest 68 | type: exitcode-stdio-1.0 69 | main-is: Tests/CSPGenTest/Main.hs 70 | hs-source-dirs: src, src/Tests 71 | ghc-options: -Wall -O2 72 | extensions: NamedFieldPuns, TupleSections, DoAndIfThenElse, GADTs, 73 | TypeFamilies, FlexibleContexts, ViewPatterns 74 | 75 | other-modules: 76 | build-depends: base >=4.6, 77 | cspretty >= 0.3.2, 78 | hashable >=1.1, 79 | mtl >=2.2, 80 | parsec >=3.1, 81 | transformers >=0.3, 82 | pretty >=1.1, 83 | containers >=0.5, 84 | bytestring >=0.10, 85 | language-c >=0.5, 86 | process >=1.1, 87 | unix >=2.6, 88 | filepath >= 1.3, 89 | hoopl >= 3.10.1, 90 | Cabal, 91 | tasty >= 0.10, 92 | tasty-hunit >= 0.9, 93 | directory >= 1.2 94 | -------------------------------------------------------------------------------- /examples/basic/Descriptions: -------------------------------------------------------------------------------- 1 | High-level descriptions of some of the tests: 2 | 3 | test_001.c 4 | Global variable update 5 | 6 | test_002.c 7 | Global variable update, recursion 8 | 9 | test_003.c 10 | Simple for loops and global variables 11 | 12 | test_004.c 13 | test_005.c 14 | Simple for loops, global addresses 15 | 16 | test_006.c 17 | Structs, simple for loops, global addresses 18 | 19 | test_007.c 20 | test_008.c 21 | Structs, indirect struct assignment, global address manipulation 22 | 23 | test_009.c 24 | Nested structs, global struct variable field updates 25 | 26 | test_010.c 27 | Repeated updates to a local variable, global address manipulation 28 | 29 | test_011.c 30 | If statements with unknown scrutinees. 31 | 32 | test_012.c 33 | Nested if statements. 34 | 35 | test_013.c 36 | Loops modifying locals. 37 | 38 | test_014.c 39 | Local address manipulation, echo 40 | 41 | test_015.c 42 | Local address manipulation, loops, echo 43 | 44 | test_016.c 45 | test_017.c 46 | test_018.c 47 | test_019.c 48 | test_020.c 49 | test_021.c 50 | test_022.c 51 | Nested loops, loop init/update/bound, breaks, if in loops, local addresses, echo 52 | 53 | test_023.c 54 | Floats, for 55 | 56 | test_024.c 57 | Floats, for 58 | 59 | test_025.c 60 | Repeated local var updates, ++/--, global address manipulation 61 | 62 | test_026.c 63 | ++ and -- on ints, echo 64 | 65 | test_027.c 66 | bitwise operators (|, &, ^, ~), echo 67 | 68 | test_028.c 69 | _Bool, typedef, if on _Bool, ++/-- on _Bool 70 | 71 | test_029.c 72 | ternary operator 73 | 74 | test_030.c 75 | << and >> operators, echo 76 | 77 | test_031.c 78 | Casts between int and _Bool, implicit casts in assignment and _?_:_, echo 79 | 80 | test_032.c 81 | Array assignment and reading, echo 82 | 83 | test_033.c 84 | _Bool, casting _Bool to int, echo 85 | -------------------------------------------------------------------------------- /examples/basic/cpp_test_001.cpp: -------------------------------------------------------------------------------- 1 | extern "C" { 2 | void echo(int x); 3 | } 4 | 5 | class Animal { 6 | private: 7 | int age; 8 | public: 9 | int get_age() {return age;}; 10 | virtual void noise() {echo(0);}; 11 | Animal(int a) {age=a;}; 12 | }; 13 | 14 | class Dog : public Animal { 15 | public: 16 | void noise() {echo(1);}; 17 | Dog(int a) : Animal(a) {}; 18 | }; 19 | 20 | class Cat : public Animal { 21 | public: 22 | void noise() {echo(2);}; 23 | Cat(int a) : Animal(a) {}; 24 | }; 25 | 26 | int main () { 27 | Dog fido = Dog(3); 28 | Cat mittens = Cat(4); 29 | fido.noise(); 30 | echo(fido.get_age()); 31 | mittens.noise(); 32 | echo(mittens.get_age()); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /examples/basic/cpp_test_001.lltest.csp: -------------------------------------------------------------------------------- 1 | include "cpp_test_001.csp" 2 | 3 | testMain = 4 | echo_c.CIntKnown.1 5 | -> echo_c.CIntKnown.3 6 | -> echo_c.CIntKnown.2 7 | -> echo_c.CIntKnown.4 8 | -> STOP 9 | 10 | assert testMain [FD= runAsMain(main) 11 | assert runAsMain(main) [FD= testMain 12 | 13 | -------------------------------------------------------------------------------- /examples/basic/cpp_test_002.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "stdio.h" 3 | 4 | extern "C" { 5 | void echo(int x); 6 | } 7 | 8 | class Animal { 9 | private: 10 | int age; 11 | public: 12 | int get_age() {return age;}; 13 | virtual void noise() =0; 14 | Animal(int a) {age=a;}; 15 | }; 16 | 17 | class Dog : public Animal { 18 | public: 19 | Dog(int a) : Animal(a) {}; 20 | virtual void noise() {echo(1);}; 21 | }; 22 | 23 | class Cat : public Animal { 24 | public: 25 | Cat(int a) : Animal(a) {}; 26 | virtual void noise() {echo(2);}; 27 | }; 28 | 29 | void make_noise(Animal* a) { 30 | a->noise(); 31 | return; 32 | } 33 | 34 | int main () { 35 | Dog fido = Dog(3); 36 | Cat mittens = Cat(4); 37 | make_noise(&fido); 38 | make_noise(&mittens); 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /examples/basic/cpp_test_002.lltest.csp: -------------------------------------------------------------------------------- 1 | include "cpp_test_002.csp" 2 | 3 | testMain = 4 | echo_c.CIntKnown.1 5 | -> echo_c.CIntKnown.2 6 | -> STOP 7 | 8 | assert testMain [FD= hideMemory(runAsMain(main)) 9 | assert hideMemory(runAsMain(main)) [FD= testMain 10 | 11 | -------------------------------------------------------------------------------- /examples/basic/cpp_test_003.cpp: -------------------------------------------------------------------------------- 1 | // This tests reading from C++ user defined class objects 2 | 3 | class Test{ 4 | public: 5 | int a; 6 | Test () { a = 2; }; 7 | }; 8 | 9 | volatile int x; 10 | 11 | int main(){ 12 | x = 0; 13 | Test example; 14 | x = example.a; 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /examples/basic/cpp_test_003.lltest.csp: -------------------------------------------------------------------------------- 1 | include "cpp_test_003.csp" 2 | 3 | testMain :: Proc 4 | testMain = cIntWrite_c.TID.0.CIntLoc_x.CIntKnown.0 -> 5 | cIntWrite_c.TID.0.CIntLoc_x.CIntKnown.2 -> STOP 6 | 7 | assert testMain [FD= runAsMain(main) 8 | assert runAsMain(main) [FD= testMain 9 | -------------------------------------------------------------------------------- /examples/basic/cpp_test_004.cpp: -------------------------------------------------------------------------------- 1 | // This tests the use of C++ classes and objects 2 | 3 | class Test{ 4 | int a, b; 5 | public: 6 | void setter(int,int); 7 | int getSum(); 8 | }; 9 | 10 | void Test::setter(int x, int y){ 11 | a = x; 12 | b = y; 13 | } 14 | 15 | int Test::getSum(){ 16 | return (a + b); 17 | } 18 | 19 | volatile int x; 20 | 21 | int main(){ 22 | Test example; 23 | x = 0; 24 | example.setter(1,1); 25 | x = example.getSum(); 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /examples/basic/cpp_test_004.lltest.csp: -------------------------------------------------------------------------------- 1 | include "cpp_test_004.csp" 2 | 3 | testMain :: Proc 4 | testMain = cIntWrite_c.TID.0.CIntLoc_x.CIntKnown.0 -> 5 | cIntWrite_c.TID.0.CIntLoc_x.CIntKnown.2 -> STOP 6 | 7 | assert testMain [FD= runAsMain(main) 8 | assert runAsMain(main) [FD= testMain 9 | -------------------------------------------------------------------------------- /examples/basic/cpp_test_005.cpp: -------------------------------------------------------------------------------- 1 | // This test the use of constructors in C++ classes 2 | 3 | class Test{ 4 | int a, b; 5 | public: 6 | Test(int,int); 7 | int getSum(); 8 | }; 9 | 10 | Test::Test(int j, int k){ 11 | a = j; 12 | b = k; 13 | } 14 | 15 | int Test::getSum(){ 16 | return (a + b); 17 | } 18 | 19 | volatile int x; 20 | 21 | int main(){ 22 | x = 0; 23 | Test example (1,1); 24 | x = example.getSum(); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /examples/basic/cpp_test_005.lltest.csp: -------------------------------------------------------------------------------- 1 | include "cpp_test_005.csp" 2 | 3 | testMain :: Proc 4 | testMain = cIntWrite_c.TID.0.CIntLoc_x.CIntKnown.0 -> 5 | cIntWrite_c.TID.0.CIntLoc_x.CIntKnown.2 -> STOP 6 | 7 | assert testMain [FD= runAsMain(main) 8 | assert runAsMain(main) [FD= testMain 9 | -------------------------------------------------------------------------------- /examples/basic/cpp_test_006.cpp: -------------------------------------------------------------------------------- 1 | // This test the use of overloaded constructors in C++ classes 2 | 3 | class Test{ 4 | int a, b; 5 | public: 6 | Test(); 7 | Test(int,int); 8 | int getSum(); 9 | }; 10 | 11 | Test::Test(){ 12 | a = 0; 13 | b = 3; 14 | } 15 | 16 | Test::Test(int j, int k){ 17 | a = j; 18 | b = k; 19 | } 20 | 21 | int Test::getSum(){ 22 | return (a + b); 23 | } 24 | 25 | volatile int x, y; 26 | 27 | int main(){ 28 | Test example1; 29 | Test example2 (1,1); 30 | x = 0; 31 | y = 0; 32 | x = example1.getSum(); 33 | y = example2.getSum(); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /examples/basic/cpp_test_006.lltest.csp: -------------------------------------------------------------------------------- 1 | include "cpp_test_006.csp" 2 | 3 | testMain :: Proc 4 | testMain = cIntWrite_c.TID.0.CIntLoc_x.CIntKnown.0 -> 5 | cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.0 -> 6 | cIntWrite_c.TID.0.CIntLoc_x.CIntKnown.3 -> 7 | cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.2 -> STOP 8 | 9 | assert testMain [FD= runAsMain(main) 10 | assert runAsMain(main) [FD= testMain 11 | -------------------------------------------------------------------------------- /examples/basic/cpp_test_007.cpp: -------------------------------------------------------------------------------- 1 | extern "C" { 2 | void echo(int x); 3 | } 4 | 5 | class Animal { 6 | private: 7 | int age; 8 | public: 9 | int get_age() {return age;}; 10 | virtual void noise() {echo(0);}; 11 | Animal(int a) {age=a;}; 12 | }; 13 | 14 | class Dog : public Animal { 15 | public: 16 | void noise() {echo(1);}; 17 | Dog(int a) : Animal(a) {}; 18 | }; 19 | 20 | class Cat : public Animal { 21 | public: 22 | void noise() {echo(2);}; 23 | Cat(int a) : Animal(a) {}; 24 | }; 25 | 26 | Dog fido = Dog(3); 27 | Cat mittens = Cat(4); 28 | 29 | int main () { 30 | fido.noise(); 31 | echo(fido.get_age()); 32 | mittens.noise(); 33 | echo(mittens.get_age()); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /examples/basic/cpp_test_007.lltest.csp: -------------------------------------------------------------------------------- 1 | include "cpp_test_007.csp" 2 | 3 | testMain = 4 | echo_c.CIntKnown.1 5 | -> echo_c.CIntKnown.3 6 | -> echo_c.CIntKnown.2 7 | -> echo_c.CIntKnown.4 8 | -> STOP 9 | 10 | assert testMain [FD= hideMemory(runAsMain(main)) 11 | assert hideMemory(runAsMain(main)) [FD= testMain 12 | 13 | -------------------------------------------------------------------------------- /examples/basic/cpp_test_008.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "stdio.h" 3 | 4 | extern "C" { 5 | void echo(int x); 6 | } 7 | 8 | class Animal { 9 | private: 10 | int age; 11 | public: 12 | int get_age() {return age;}; 13 | virtual void noise() =0; 14 | Animal(int a) {age=a;}; 15 | }; 16 | 17 | class Dog : public Animal { 18 | public: 19 | Dog(int a) : Animal(a) {}; 20 | virtual void noise() {echo(1);}; 21 | }; 22 | 23 | class Cat : public Animal { 24 | public: 25 | Cat(int a) : Animal(a) {}; 26 | virtual void noise() {echo(2);}; 27 | }; 28 | 29 | void make_noise(Animal* a) { 30 | a->noise(); 31 | return; 32 | } 33 | 34 | Dog fido = Dog(3); 35 | Cat mittens = Cat(4); 36 | 37 | int main () { 38 | make_noise(&fido); 39 | make_noise(&mittens); 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /examples/basic/cpp_test_008.lltest.csp: -------------------------------------------------------------------------------- 1 | include "cpp_test_008.csp" 2 | 3 | testMain = 4 | echo_c.CIntKnown.1 5 | -> echo_c.CIntKnown.2 6 | -> STOP 7 | 8 | assert testMain [FD= hideMemory(runAsMain(main)) 9 | assert hideMemory(runAsMain(main)) [FD= testMain 10 | 11 | -------------------------------------------------------------------------------- /examples/basic/externals: -------------------------------------------------------------------------------- 1 | -- Default external functions 2 | -- 3 | -- Specify functions like: 4 | -- 5 | -- returnType name(argMode1,...,argModen); 6 | -- 7 | -- Where argMode ::= in | out | inout 8 | -- 9 | -- For input arguments (the usual case), output arguments (like a pointer where 10 | -- the function stores something), or arguments used both ways. 11 | 12 | 13 | @section FUNCTIONS { 14 | 15 | void send(in,in,in); 16 | 17 | void recv(in,in,out); 18 | 19 | void echo(in); 20 | 21 | void spawn(in); 22 | 23 | pid pthread_self(); 24 | 25 | int pthread_equal(in,in); 26 | 27 | int pthread_create(out, in, in, in); 28 | 29 | int pthread_mutex_init(in, in); 30 | 31 | int pthread_mutex_lock(in); 32 | 33 | int pthread_mutex_unlock(in); 34 | 35 | } 36 | 37 | @section SETTINGS { 38 | 39 | minimumCVal = 0; 40 | 41 | maximumCVal = 4; 42 | 43 | } 44 | -------------------------------------------------------------------------------- /examples/basic/externalsLLVM: -------------------------------------------------------------------------------- 1 | @section FUNCTIONS { 2 | 3 | void echo(int); 4 | 5 | } 6 | 7 | @section SETTINGS { 8 | 9 | minimumCVal = 0; 10 | 11 | maximumCVal = 5; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /examples/basic/runtimeChans.csp: -------------------------------------------------------------------------------- 1 | include "runtime.csp" 2 | 3 | channel smsg_chan : ChannelNames.SMsg_istrTyp 4 | 5 | send :: (SMsg_istrLoc,CVal,ChannelNames, 6 | LocalState, 7 | PIDTyp, 8 | (LocalState,PIDTyp,SMsg_istrTyp) -> Proc) -> Proc 9 | send (sloc,_,cname,st,pid,k) = 10 | smsg_istrReader(st,pid,sloc, 11 | \st',pid',smsg @ smsg_chan!cname!smsg -> k(st',pid',smsg)) 12 | 13 | recv :: (SMsg_istrLoc,CVal,ChannelNames, 14 | LocalState, 15 | PIDTyp, 16 | (LocalState, PIDTyp,SMsg_istrTyp) -> Proc) -> Proc 17 | recv (sloc,_,cname,st,pid,k) = 18 | smsg_chan!cname?smsg 19 | -> smsg_istrWriter(st,pid,sloc,smsg,k) 20 | -------------------------------------------------------------------------------- /examples/basic/runtimeCont.csp: -------------------------------------------------------------------------------- 1 | include "globVarDecs.csp" 2 | 3 | -- datatype CValTyp = CKnown.{0..4} | CUnknown 4 | 5 | -- channel ivread, ivwrite : CValLoc.CValTyp -- read / write interface to heap 6 | 7 | minCVal, maxCVal :: Int 8 | minCVal = 0 9 | maxCVal = 4 10 | 11 | boundCVal :: (Int) -> CValTyp 12 | boundCVal (x) = 13 | if x < minCVal then CUnknown 14 | else if x > maxCVal then CUnknown 15 | else CKnown.x 16 | 17 | ----- 18 | ----- Arithmetic 19 | ----- 20 | 21 | unknownOrBound :: ((Int) -> (Int) -> Int) -> (CValTyp,CValTyp) -> CValTyp 22 | unknownOrBound (_) (CUnknown,_) = CUnknown 23 | unknownOrBound (_) (_,CUnknown) = CUnknown 24 | unknownOrBound (f) (CKnown.x,CKnown.y) = boundCVal (f (x) (y)) 25 | 26 | plus :: (CValTyp,CValTyp) -> CValTyp 27 | plus = unknownOrBound (\x @ \y @ x + y) 28 | 29 | minus :: (CValTyp,CValTyp) -> CValTyp 30 | minus = unknownOrBound (\x @ \y @ x - y) 31 | 32 | divide :: (CValTyp,CValTyp) -> CValTyp 33 | divide = unknownOrBound (\x @ \y @ x / y) 34 | 35 | multiply :: (CValTyp,CValTyp) -> CValTyp 36 | multiply = unknownOrBound (\x @ \y @ x * y) 37 | 38 | mod :: (CValTyp,CValTyp) -> CValTyp 39 | mod = unknownOrBound (\x @ \y @ x % y) 40 | 41 | negate :: (CValTyp) -> CValTyp 42 | negate (CUnknown) = CUnknown 43 | negate (CKnown.x) = boundCVal (-x) 44 | 45 | ----- 46 | ----- Comparisons 47 | ----- 48 | 49 | unknownOrBool :: ((Int) -> (Int) -> Bool) -> (CValTyp,CValTyp) -> CValTyp 50 | unknownOrBool (_) (CUnknown,_) = CUnknown 51 | unknownOrBool (_) (_,CUnknown) = CUnknown 52 | unknownOrBool (f) (CKnown.x,CKnown.y) = if (f (x) (y)) then CKnown.1 else CKnown.0 53 | 54 | neq :: (CValTyp,CValTyp) -> CValTyp 55 | neq = unknownOrBool (\x @ \y @ x != y) 56 | 57 | eq :: (CValTyp,CValTyp) -> CValTyp 58 | eq = unknownOrBool (\x @ \y @ x == y) 59 | 60 | lt :: (CValTyp,CValTyp) -> CValTyp 61 | lt = unknownOrBool (\x @ \y @ x < y) 62 | 63 | le :: (CValTyp,CValTyp) -> CValTyp 64 | le = unknownOrBool (\x @ \y @ x <= y) 65 | 66 | gt :: (CValTyp,CValTyp) -> CValTyp 67 | gt = unknownOrBool (\x @ \y @ x > y) 68 | 69 | ge :: (CValTyp,CValTyp) -> CValTyp 70 | ge = unknownOrBool (\x @ \y @ x >= y) 71 | 72 | 73 | ----- 74 | ----- Logical operations 75 | ----- 76 | 77 | land :: (CValTyp,CValTyp) -> CValTyp 78 | land = unknownOrBool (\x @ \y @ (x != 0) and (y != 0)) 79 | 80 | lor :: (CValTyp,CValTyp) -> CValTyp 81 | lor = unknownOrBool (\x @ \y @ (x != 0) or (y != 0)) 82 | 83 | lnot :: (CValTyp) -> CValTyp 84 | lnot (CUnknown) = CUnknown 85 | lnot (CKnown.x) = if x == 0 then CKnown.1 else CKnown.0 86 | 87 | ----- 88 | 89 | ifthenelseProc :: (CValTyp,Proc,Proc) -> Proc 90 | ifthenelseProc (CKnown.x,y,n) = if x == 0 then n else y 91 | ifthenelseProc (CUnknown,y,n) = y |~| n 92 | 93 | ---- Basic datatypes 94 | 95 | datatype Unit = UnitVal 96 | 97 | 98 | ---- A simple way to produce CSP events 99 | 100 | channel echo_c : CValTyp 101 | 102 | echo :: (CValTyp,(| LocalAddress => DataUnion |), 103 | ((| LocalAddress => DataUnion |)) -> Proc) -> Proc 104 | echo (v,st,k) = echo_c!v -> k(st) 105 | -------------------------------------------------------------------------------- /examples/basic/runtimePThread.csp: -------------------------------------------------------------------------------- 1 | include "runtime.csp" 2 | 3 | -- These are implementations of the pthreads mutex functions against our model. 4 | -- 5 | -- We are being a little unfaithful to the pthreads model: when something goes 6 | -- wrong (e.g., code attempts to lock an uninitialized mutex), we are causing a 7 | -- CSP error rather than returning an error code. 8 | -- 9 | -- This has the advantage that these kinds of errors are highly visible, but the 10 | -- disadvantages that (1) we aren't completely sound and (2) we'll incorrectly 11 | -- report errors for code that checks for and gracefully handles error conditions. 12 | -- 13 | -- A better compromise might be to create some csp events indicating the errors 14 | -- and return error codes but also communicate those events. This would retain 15 | -- the high visibility of the error conditions but also be sound. 16 | 17 | 18 | 19 | -- XXX Right now we ignore the parameters argument. Ideally we'd check that 20 | -- it's null, and fail otherwise. That's tricky because the type for this 21 | -- struct is actually generated at runtime. We really need a better story about 22 | -- external dependencies. 23 | -- 24 | --pthread_mutex_init :: 25 | -- (MutexLoc, 26 | -- LocalState, 27 | -- PIDTyp, 28 | -- (LocalState, PIDTyp, CInt) -> Proc) 29 | -- -> Proc 30 | pthread_mutex_init (mutLoc,_,locals,pid,k) = 31 | mutex_init_c?mid 32 | -> mutexCSPWriter(locals,pid,mutLoc,MutCSP.mid, 33 | \locals', pid', _ @ k(locals',pid',CIntKnown.0)) 34 | 35 | pthread_mutex_destroy :: 36 | (MutexCSPLoc, 37 | LocalState, 38 | PIDTyp, 39 | (LocalState, PIDTyp, CInt) -> Proc) 40 | -> Proc 41 | pthread_mutex_destroy (mutLoc,locals,pid,k) = 42 | let 43 | destroy_mut (_,_,Mut_UNINITIALIZED) = 44 | destroy_uninit_mutex_ERROR -> STOP 45 | destroy_mut (locals',pid',Mut.mid) = 46 | mutex_destroy_c!mid -> k(locals',pid',CIntKnown.0) 47 | within 48 | mutexCSPReader(locals,pid,mutLoc,destroy_mut) 49 | 50 | pthread_mutex_lock :: 51 | (MutexCSPLoc, 52 | LocalState, 53 | PIDTyp, 54 | (LocalState, PIDTyp, CInt) -> Proc) 55 | -> Proc 56 | pthread_mutex_lock (mutLoc,locals,pid,k) = 57 | let 58 | lock_mut (_,_,Mut_UNINITIALIZED) = 59 | lock_uninit_mutex_ERROR -> STOP 60 | lock_mut (locals',pid',Mut.mid) = 61 | mutex_lock_c!mid!pid' -> k(locals',pid',CIntKnown.0) 62 | within 63 | mutexCSPReader(locals,pid,mutLoc,lock_mut) 64 | 65 | pthread_mutex_unlock :: 66 | (MutexCSPLoc, 67 | LocalState, 68 | PIDTyp, 69 | (LocalState, PIDTyp, CInt) -> Proc) 70 | -> Proc 71 | pthread_mutex_unlock (mutLoc,locals,pid,k) = 72 | let 73 | unlock_mut (_,_,Mut_UNINITIALIZED) = 74 | unlock_uninit_mutex_ERROR -> STOP 75 | unlock_mut (locals',pid',Mut.mid) = 76 | mutex_unlock_c!mid!pid' -> k(locals',pid',CIntKnown.0) 77 | within 78 | mutexCSPReader(locals,pid,mutLoc,unlock_mut) 79 | 80 | pthread_self :: (LocalState,PIDTyp, 81 | (LocalState,PIDTyp,PIDTyp) -> Proc) 82 | -> Proc 83 | pthread_self (s,p,k) = k (s,p,p) 84 | 85 | pthread_equal :: (PIDTyp,PIDTyp,LocalState,PIDTyp, 86 | (LocalState,PIDTyp,CInt) -> Proc) 87 | -> Proc 88 | pthread_equal (PIDUnknown,_,s,p,k) = k (s,p,CIntUnknown) 89 | pthread_equal (_,PIDUnknown,s,p,k) = k (s,p,CIntUnknown) 90 | pthread_equal (PID.x,PID.y,s,p,k) = 91 | k (s,p,if x == y then CIntKnown.1 else CIntKnown.0) 92 | 93 | -- XXX Right now we ignore the parameters argument. Ideally we'd check that 94 | -- it's null, and fail otherwise. That's tricky because the type for this 95 | -- struct is actually generated at runtime. We really need a better story about 96 | -- external dependencies. 97 | -- 98 | -- XXX Right now we imagine that each thread has a completely separate stack 99 | -- address space. Threads can not read from or write to the stack variables of 100 | -- other threads, even if you pass the addresses around, because of the way we 101 | -- represent local state. If we encounter code that stack-allocates variables 102 | -- and then passes their addresses around, it will result in an error in FDR and 103 | -- we'll need to revisit this assumption. 104 | -- 105 | -- pthread_create :: (PIDTypLoc, 106 | -- pthrad_attr_tLoc, 107 | -- ((VoidStar,LocalState,PIDTyp, 108 | -- ((LocalState,PIDType,VoidStar) -> Proc)) -> Proc), 109 | -- VoidStar, 110 | -- LocalState, 111 | -- PIDTyp, 112 | -- (LocalState,PIDTyp,CInt) -> Proc) -> Proc 113 | pthread_create (thread_id_loc, config, to_spawn, arg, 114 | st, pid, k) = 115 | new_pid_c?new_pid -> 116 | pIDTypWriter(st,pid,thread_id_loc,new_pid, 117 | \st',pid',_ @ 118 | ( (to_spawn(arg,emptyLocalState,new_pid,\_,_,_@ SKIP)) 119 | ||| (k (st',pid',CIntKnown.0)))) 120 | -------------------------------------------------------------------------------- /examples/basic/test_001.c: -------------------------------------------------------------------------------- 1 | volatile int y = 2; 2 | 3 | int main() { 4 | y = 1; 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /examples/basic/test_001.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_001.csp" 2 | 3 | testMain :: Proc 4 | testMain = cIntWrite_c.PID.0.CIntLoc_y.CIntKnown.1 -> STOP 5 | 6 | 7 | assert testMain [FD= runMain 8 | -------------------------------------------------------------------------------- /examples/basic/test_001.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_001.csp" 2 | 3 | testMain :: Proc 4 | testMain = cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.1 -> STOP 5 | 6 | 7 | assert testMain [FD= runAsMain(main) 8 | -------------------------------------------------------------------------------- /examples/basic/test_002.c: -------------------------------------------------------------------------------- 1 | volatile int y = 0; 2 | 3 | void incr() { 4 | y = (y + 1) % 2; 5 | incr(); 6 | } 7 | 8 | 9 | int main() { 10 | incr(); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /examples/basic/test_002.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_002.csp" 2 | 3 | testMain :: Proc 4 | testMain = cIntRead_c.PID.0.CIntLoc_y.CIntKnown.0 -> 5 | cIntWrite_c.PID.0.CIntLoc_y.CIntKnown.1 -> 6 | cIntRead_c.PID.0.CIntLoc_y.CIntKnown.1 -> 7 | cIntWrite_c.PID.0.CIntLoc_y.CIntKnown.0 -> testMain 8 | 9 | assert testMain [FD= runMain 10 | -------------------------------------------------------------------------------- /examples/basic/test_002.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_002.csp" 2 | 3 | testMain :: Proc 4 | testMain = cIntRead_c.TID.0.CIntLoc_y.CIntKnown.0 -> 5 | cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.1 -> 6 | cIntRead_c.TID.0.CIntLoc_y.CIntKnown.1 -> 7 | cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.0 -> testMain 8 | 9 | assert testMain [FD= runAsMain(main) 10 | -------------------------------------------------------------------------------- /examples/basic/test_003.c: -------------------------------------------------------------------------------- 1 | volatile int y = 0; 2 | 3 | void incr() { 4 | while(1) { 5 | y = (y + 1) % 2; 6 | }; 7 | return; 8 | } 9 | 10 | 11 | int main() { 12 | incr(); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /examples/basic/test_003.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_003.csp" 2 | 3 | testMain :: Proc 4 | testMain = cIntRead_c.PID.0.CIntLoc_y.CIntKnown.0 -> 5 | cIntWrite_c.PID.0.CIntLoc_y.CIntKnown.1 -> 6 | cIntRead_c.PID.0.CIntLoc_y.CIntKnown.1 -> 7 | cIntWrite_c.PID.0.CIntLoc_y.CIntKnown.0 -> testMain 8 | 9 | assert testMain [FD= runMain 10 | -------------------------------------------------------------------------------- /examples/basic/test_003.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_003.csp" 2 | 3 | testMain :: Proc 4 | testMain = cIntRead_c.TID.0.CIntLoc_y.CIntKnown.0 -> 5 | cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.1 -> 6 | cIntRead_c.TID.0.CIntLoc_y.CIntKnown.1 -> 7 | cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.0 -> testMain 8 | 9 | assert testMain [FD= runAsMain(main) 10 | -------------------------------------------------------------------------------- /examples/basic/test_004.c: -------------------------------------------------------------------------------- 1 | volatile int y = 0; 2 | 3 | void incr(int* x) { 4 | *x = (*x + 1) % 2; 5 | return; 6 | } 7 | 8 | 9 | int main() { 10 | for (;;) { 11 | incr(&y); 12 | }; 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /examples/basic/test_004.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_004.csp" 2 | 3 | testMain :: Proc 4 | testMain = cIntRead_c.PID.0.CIntLoc_y.CIntKnown.0 -> 5 | cIntWrite_c.PID.0.CIntLoc_y.CIntKnown.1 -> 6 | cIntRead_c.PID.0.CIntLoc_y.CIntKnown.1 -> 7 | cIntWrite_c.PID.0.CIntLoc_y.CIntKnown.0 -> testMain 8 | 9 | assert testMain [FD= runMain 10 | -------------------------------------------------------------------------------- /examples/basic/test_004.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_004.csp" 2 | 3 | testMain :: Proc 4 | testMain = cIntRead_c.TID.0.CIntLoc_y.CIntKnown.0 -> 5 | cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.1 -> 6 | cIntRead_c.TID.0.CIntLoc_y.CIntKnown.1 -> 7 | cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.0 -> testMain 8 | 9 | assert testMain [FD= runAsMain(main) 10 | -------------------------------------------------------------------------------- /examples/basic/test_005.c: -------------------------------------------------------------------------------- 1 | volatile int x = 0; 2 | volatile int y = 0; 3 | 4 | void incr(int* x) { 5 | *x = (*x + 1) % 2; 6 | return; 7 | } 8 | 9 | 10 | int main() { 11 | for (;;) { 12 | incr(&x); 13 | incr(&y); 14 | }; 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /examples/basic/test_005.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_005.csp" 2 | 3 | testMain :: Proc 4 | testMain = cIntRead_c.PID.0.CIntLoc_x.CIntKnown.0 -> 5 | cIntWrite_c.PID.0.CIntLoc_x.CIntKnown.1 -> 6 | cIntRead_c.PID.0.CIntLoc_y.CIntKnown.0 -> 7 | cIntWrite_c.PID.0.CIntLoc_y.CIntKnown.1 -> 8 | cIntRead_c.PID.0.CIntLoc_x.CIntKnown.1 -> 9 | cIntWrite_c.PID.0.CIntLoc_x.CIntKnown.0 -> 10 | cIntRead_c.PID.0.CIntLoc_y.CIntKnown.1 -> 11 | cIntWrite_c.PID.0.CIntLoc_y.CIntKnown.0 -> testMain 12 | 13 | assert testMain [FD= runMain 14 | -------------------------------------------------------------------------------- /examples/basic/test_005.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_005.csp" 2 | 3 | testMain :: Proc 4 | testMain = cIntRead_c.TID.0.CIntLoc_x.CIntKnown.0 -> 5 | cIntWrite_c.TID.0.CIntLoc_x.CIntKnown.1 -> 6 | cIntRead_c.TID.0.CIntLoc_y.CIntKnown.0 -> 7 | cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.1 -> 8 | cIntRead_c.TID.0.CIntLoc_x.CIntKnown.1 -> 9 | cIntWrite_c.TID.0.CIntLoc_x.CIntKnown.0 -> 10 | cIntRead_c.TID.0.CIntLoc_y.CIntKnown.1 -> 11 | cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.0 -> testMain 12 | 13 | assert testMain [FD= runAsMain(main) 14 | -------------------------------------------------------------------------------- /examples/basic/test_006.c: -------------------------------------------------------------------------------- 1 | 2 | typedef struct { 3 | int *foo; 4 | char bar; 5 | char *baz; 6 | } chan_c; 7 | 8 | volatile int y = 0; 9 | volatile chan_c z; 10 | 11 | 12 | void incr(int* x) { 13 | *x = (*x + 1) % 2; 14 | return; 15 | } 16 | 17 | 18 | int main() { 19 | for (;;) { 20 | incr(&y); 21 | }; 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /examples/basic/test_006.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_006.csp" 2 | 3 | testMain :: Proc 4 | testMain = cIntRead_c.PID.0.CIntLoc_y.CIntKnown.0 -> 5 | cIntWrite_c.PID.0.CIntLoc_y.CIntKnown.1 -> 6 | cIntRead_c.PID.0.CIntLoc_y.CIntKnown.1 -> 7 | cIntWrite_c.PID.0.CIntLoc_y.CIntKnown.0 -> testMain 8 | 9 | assert testMain [FD= runMain 10 | -------------------------------------------------------------------------------- /examples/basic/test_006.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_006.csp" 2 | 3 | testMain :: Proc 4 | testMain = cIntRead_c.TID.0.CIntLoc_y.CIntKnown.0 -> 5 | cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.1 -> 6 | cIntRead_c.TID.0.CIntLoc_y.CIntKnown.1 -> 7 | cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.0 -> testMain 8 | 9 | assert testMain [FD= runAsMain(main) 10 | -------------------------------------------------------------------------------- /examples/basic/test_007.c: -------------------------------------------------------------------------------- 1 | 2 | typedef struct pair { 3 | int x; 4 | int y; 5 | } MyPair; 6 | 7 | volatile MyPair mypair; 8 | volatile int k = 0; 9 | 10 | void assignk(struct pair* p) { 11 | p -> x = k; 12 | p -> y = k; 13 | return; 14 | } 15 | 16 | int main() { 17 | for (;;) { 18 | assignk(&mypair); 19 | k = (k + 1) % 2; 20 | }; 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /examples/basic/test_007.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_007.csp" 2 | 3 | 4 | testMain :: (Int) -> Proc 5 | testMain (k) = 6 | cIntRead_c.PID.0.CIntLoc_k.CIntKnown.k -> 7 | pair_x_write_c.PID.0.pairLoc_mypair.CIntKnown.k -> 8 | cIntRead_c.PID.0.CIntLoc_k.CIntKnown.k -> 9 | pair_y_write_c.PID.0.pairLoc_mypair.CIntKnown.k -> 10 | cIntRead_c.PID.0.CIntLoc_k.CIntKnown.k -> 11 | cIntWrite_c.PID.0.CIntLoc_k.CIntKnown.((k+1)%2) -> 12 | testMain((k+1)%2) 13 | 14 | assert testMain(0) [FD= runMain 15 | -------------------------------------------------------------------------------- /examples/basic/test_007.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_007.csp" 2 | 3 | testMain :: (Int) -> Proc 4 | testMain (k) = 5 | cIntRead_c.TID.0.CIntLoc_k.CIntKnown.k -> 6 | cIntWrite_c.TID.0.CIntLoc_mypair.CIntKnown.k -> 7 | cIntRead_c.TID.0.CIntLoc_k.CIntKnown.k -> 8 | cIntWrite_c.TID.0.CIntLoc_mypair_1.CIntKnown.k -> 9 | cIntRead_c.TID.0.CIntLoc_k.CIntKnown.k -> 10 | cIntWrite_c.TID.0.CIntLoc_k.CIntKnown.((k+1)%2) -> 11 | testMain((k+1)%2) 12 | 13 | assert testMain(0) [FD= runAsMain(main) 14 | -------------------------------------------------------------------------------- /examples/basic/test_008.c: -------------------------------------------------------------------------------- 1 | 2 | typedef struct { 3 | int x; 4 | int y; 5 | } pair; 6 | 7 | volatile int k; 8 | 9 | volatile pair mypair; 10 | 11 | void incr(pair* p) { 12 | p -> x = ((p -> x) + 1) % 2; 13 | p -> y = ((p -> y) + 1) % 2; 14 | return; 15 | } 16 | 17 | int main() { 18 | for (;;) { 19 | incr(&mypair); 20 | }; 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /examples/basic/test_008.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_008.csp" 2 | 3 | testMain :: (Int) -> Proc 4 | testMain (k) = 5 | pair_istr_x_read_c.PID.0.pair_istrLoc_mypair.CIntKnown.k -> 6 | pair_istr_x_write_c.PID.0.pair_istrLoc_mypair.CIntKnown.((k+1)%2) -> 7 | pair_istr_y_read_c.PID.0.pair_istrLoc_mypair.CIntKnown.k -> 8 | pair_istr_y_write_c.PID.0.pair_istrLoc_mypair.CIntKnown.((k+1)%2) -> 9 | testMain((k+1)%2) 10 | 11 | assert testMain(0) [FD= runMain 12 | -------------------------------------------------------------------------------- /examples/basic/test_008.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_008.csp" 2 | 3 | testMain :: (Int) -> Proc 4 | testMain (k) = 5 | cIntRead_c.TID.0.CIntLoc_mypair.CIntKnown.k -> 6 | cIntWrite_c.TID.0.CIntLoc_mypair.CIntKnown.((k+1)%2) -> 7 | cIntRead_c.TID.0.CIntLoc_mypair_1.CIntKnown.k -> 8 | cIntWrite_c.TID.0.CIntLoc_mypair_1.CIntKnown.((k+1)%2) -> 9 | testMain ((k+1)%2) 10 | 11 | 12 | 13 | assert testMain(0) [FD= runAsMain(main) 14 | -------------------------------------------------------------------------------- /examples/basic/test_009.c: -------------------------------------------------------------------------------- 1 | 2 | typedef struct pair { 3 | int y; 4 | int z; 5 | } Pair; 6 | 7 | typedef struct triple { 8 | int x; 9 | Pair p; 10 | } Triple; 11 | 12 | volatile Triple mytriple; 13 | int main() { 14 | for (;;) { 15 | mytriple.x = (mytriple.x + 1)%2; 16 | mytriple.p.z = (mytriple.p.z + 1)%2; 17 | }; 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /examples/basic/test_009.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_009.csp" 2 | 3 | testMain :: (Int) -> Proc 4 | testMain (k) = 5 | triple_x_read_c.PID.0.tripleLoc_mytriple.CIntKnown.k -> 6 | triple_x_write_c.PID.0.tripleLoc_mytriple.CIntKnown.((k+1)%2) -> 7 | triple_p_z_read_c.PID.0.tripleLoc_mytriple.CIntKnown.k -> 8 | triple_p_z_write_c.PID.0.tripleLoc_mytriple.CIntKnown.((k+1)%2) -> 9 | testMain((k+1)%2) 10 | 11 | 12 | 13 | assert testMain(0) [FD= runMain 14 | -------------------------------------------------------------------------------- /examples/basic/test_009.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_009.csp" 2 | 3 | testMain :: (Int) -> Proc 4 | testMain (k) = 5 | cIntRead_c.TID.0.CIntLoc_mytriple.CIntKnown.k -> 6 | cIntWrite_c.TID.0.CIntLoc_mytriple.CIntKnown.((k+1)%2) -> 7 | cIntRead_c.TID.0.CIntLoc_mytriple_2.CIntKnown.k -> 8 | cIntWrite_c.TID.0.CIntLoc_mytriple_2.CIntKnown.((k+1)%2) -> 9 | testMain((k+1)%2) 10 | 11 | 12 | assert testMain(0) [FD= runAsMain(main) 13 | -------------------------------------------------------------------------------- /examples/basic/test_010.c: -------------------------------------------------------------------------------- 1 | // This tests repeated updates to a local variable. 2 | 3 | volatile int y = 0; 4 | 5 | int update(int* loc) { 6 | int k = 1; 7 | k = k + 1; 8 | k = k + 1; 9 | *loc = k; 10 | return (k + 1); 11 | } 12 | 13 | int main() { 14 | y = update(&y); 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /examples/basic/test_010.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_010.csp" 2 | 3 | testMain :: Proc 4 | testMain = cIntWrite_c.PID.0.CIntLoc_y.CIntKnown.3 -> 5 | cIntWrite_c.PID.0.CIntLoc_y.CIntKnown.4 -> STOP 6 | 7 | 8 | assert testMain [FD= runMain 9 | -------------------------------------------------------------------------------- /examples/basic/test_010.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_010.csp" 2 | 3 | testMain :: Proc 4 | testMain = cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.3 -> 5 | cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.4 -> STOP 6 | 7 | 8 | assert testMain [FD= runAsMain(main) 9 | -------------------------------------------------------------------------------- /examples/basic/test_011.c: -------------------------------------------------------------------------------- 1 | // This tests if statements. in this particular case, the picture 2 | // should branch because "-1" isn't represented in our model so either 3 | // branch of the if appears possible. 4 | 5 | static int foo(int i) { 6 | int return_var; 7 | if (i > 0) 8 | {return_var = 1;} 9 | else 10 | {return_var = 2;} 11 | return return_var; 12 | } 13 | 14 | volatile int k = 0; 15 | 16 | int main() { 17 | int z; 18 | k = foo(z); 19 | k = foo(k); 20 | k = foo(3); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /examples/basic/test_011.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_011.csp" 2 | 3 | testMain :: Proc 4 | testMain = BRANCH 5 | 6 | 7 | BRANCH :: Proc 8 | BRANCH = BRANCH1 |~| BRANCH2 9 | 10 | BRANCH1 :: Proc 11 | BRANCH1 = cIntWrite_c.PID.0.CIntLoc_k.CIntKnown.1 -> 12 | cIntRead_c.PID.0.CIntLoc_k.CIntKnown.1 -> 13 | cIntWrite_c.PID.0.CIntLoc_k.CIntKnown.1 -> TAIL 14 | 15 | BRANCH2 :: Proc 16 | BRANCH2 = cIntWrite_c.PID.0.CIntLoc_k.CIntKnown.2 -> 17 | cIntRead_c.PID.0.CIntLoc_k.CIntKnown.2 -> 18 | cIntWrite_c.PID.0.CIntLoc_k.CIntKnown.1 -> TAIL 19 | 20 | TAIL :: Proc 21 | TAIL = cIntWrite_c.PID.0.CIntLoc_k.CIntKnown.1 -> STOP 22 | 23 | assert testMain [FD= runMain 24 | -------------------------------------------------------------------------------- /examples/basic/test_011.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_011.csp" 2 | 3 | testMain :: Proc 4 | testMain = BRANCH 5 | 6 | 7 | BRANCH :: Proc 8 | BRANCH = BRANCH1 |~| BRANCH2 9 | 10 | BRANCH1 :: Proc 11 | BRANCH1 = cIntWrite_c.TID.0.CIntLoc_k.CIntKnown.1 -> 12 | cIntRead_c.TID.0.CIntLoc_k.CIntKnown.1 -> 13 | cIntWrite_c.TID.0.CIntLoc_k.CIntKnown.1 -> TAIL 14 | 15 | BRANCH2 :: Proc 16 | BRANCH2 = cIntWrite_c.TID.0.CIntLoc_k.CIntKnown.2 -> 17 | cIntRead_c.TID.0.CIntLoc_k.CIntKnown.2 -> 18 | cIntWrite_c.TID.0.CIntLoc_k.CIntKnown.1 -> TAIL 19 | 20 | TAIL :: Proc 21 | TAIL = cIntWrite_c.TID.0.CIntLoc_k.CIntKnown.1 -> STOP 22 | 23 | assert testMain [FD= runAsMain(main) 24 | -------------------------------------------------------------------------------- /examples/basic/test_012.c: -------------------------------------------------------------------------------- 1 | // This one tests nested if statements, which was the source of a bug previously. 2 | 3 | static int foo(int i) { 4 | int return_var; 5 | if (i > 0) {return_var = 1;} 6 | else { 7 | if (i < 0) {return_var = (-1);} 8 | else { 9 | return_var = 0; 10 | } 11 | } 12 | return return_var; 13 | } 14 | 15 | volatile int y = 0; 16 | 17 | int main() { 18 | y = foo(3); 19 | y = foo(y); 20 | y = foo(-1); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /examples/basic/test_012.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_012.csp" 2 | 3 | testMain :: Proc 4 | testMain = cIntWrite_c.PID.0.CIntLoc_y.CIntKnown.1 -> 5 | cIntRead_c.PID.0.CIntLoc_y.CIntKnown.1 -> 6 | cIntWrite_c.PID.0.CIntLoc_y.CIntKnown.1 -> BRANCH1 7 | 8 | 9 | 10 | BRANCH1 :: Proc 11 | BRANCH1 = (cIntWrite_c.PID.0.CIntLoc_y.CIntKnown.1 -> STOP) |~| BRANCH2 12 | 13 | BRANCH2 :: Proc 14 | BRANCH2 = (cIntWrite_c.PID.0.CIntLoc_y.CIntUnknown -> STOP) |~| 15 | (cIntWrite_c.PID.0.CIntLoc_y.CIntKnown.0 -> STOP) 16 | 17 | 18 | assert testMain [FD= runMain 19 | -------------------------------------------------------------------------------- /examples/basic/test_012.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_012.csp" 2 | 3 | testMain :: Proc 4 | testMain = cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.1 -> 5 | cIntRead_c.TID.0.CIntLoc_y.CIntKnown.1 -> 6 | cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.1 -> BRANCH1 7 | 8 | 9 | 10 | BRANCH1 :: Proc 11 | BRANCH1 = (cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.1 -> STOP) |~| BRANCH2 12 | 13 | BRANCH2 :: Proc 14 | BRANCH2 = (cIntWrite_c.TID.0.CIntLoc_y.CIntUnknown -> STOP) |~| 15 | (cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.0 -> STOP) 16 | 17 | 18 | assert testMain [FD= runAsMain(main) 19 | -------------------------------------------------------------------------------- /examples/basic/test_013.c: -------------------------------------------------------------------------------- 1 | // A for loop that modifies a local variable? Insanity! 2 | 3 | volatile int y = 0; 4 | 5 | void foo(int start) { 6 | int mod4 = start % 4; 7 | for (;;) { 8 | y = mod4 % 2; 9 | mod4 = (mod4 + 1) % 4; 10 | } 11 | return; 12 | } 13 | 14 | int main() { 15 | foo(0); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /examples/basic/test_013.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_013.csp" 2 | 3 | testMain :: Proc 4 | testMain = cIntWrite_c.PID.0.CIntLoc_y.CIntKnown.0 -> testMainAux 5 | 6 | testMainAux :: Proc 7 | testMainAux = cIntWrite_c.PID.0.CIntLoc_y.CIntKnown.1 -> 8 | cIntWrite_c.PID.0.CIntLoc_y.CIntKnown.0 -> testMainAux 9 | 10 | assert testMain [FD= runMain 11 | -------------------------------------------------------------------------------- /examples/basic/test_013.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_013.csp" 2 | 3 | testMain :: Proc 4 | testMain = cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.0 -> testMainAux 5 | 6 | testMainAux :: Proc 7 | testMainAux = cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.1 -> 8 | cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.0 -> testMainAux 9 | 10 | assert testMain [FD= runAsMain(main) 11 | -------------------------------------------------------------------------------- /examples/basic/test_014.c: -------------------------------------------------------------------------------- 1 | // passing around the addresses of local variables 2 | extern void echo(int); 3 | 4 | void foo(int* x) { 5 | echo(*x); 6 | *x = 2; 7 | echo(*x); 8 | *x = *x + 1; 9 | echo(*x - 2); 10 | } 11 | 12 | int main() { 13 | int x; 14 | foo(&x); 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /examples/basic/test_014.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_014.csp" 2 | 3 | testMain :: Proc 4 | testMain = echo_c.CIntUnknown 5 | -> echo_c.CIntKnown.2 6 | -> echo_c.CIntKnown.1 -> STOP 7 | 8 | assert testMain [FD= runMain 9 | -------------------------------------------------------------------------------- /examples/basic/test_014.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_014.csp" 2 | 3 | testMain :: Proc 4 | testMain = echo_c.CIntUnknown 5 | -> echo_c.CIntKnown.2 6 | -> echo_c.CIntKnown.1 -> STOP 7 | 8 | assert testMain [FD= runAsMain(main) 9 | -------------------------------------------------------------------------------- /examples/basic/test_015.c: -------------------------------------------------------------------------------- 1 | // passing around the addresses of local variables 2 | extern void echo(int); 3 | 4 | void foo(int* x, int *y) { 5 | int z = 1; 6 | int* z_addr = &z; 7 | if(*y) {*z_addr = 0;}; 8 | for(;;) { 9 | echo(*x); 10 | *x = (*x + *z_addr) % 2; 11 | } 12 | } 13 | 14 | int main() { 15 | int x,y; 16 | x = 0; 17 | foo(&x,&y); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /examples/basic/test_015.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_015.csp" 2 | 3 | loop1 :: Proc 4 | loop1 = echo_c.CIntKnown.0 -> loop1 5 | 6 | loop2 :: Proc 7 | loop2 = echo_c.CIntKnown.0 -> echo_c.CIntKnown.1 -> loop2 8 | 9 | testMain :: Proc 10 | testMain = loop1 |~| loop2 11 | 12 | assert testMain [FD= runMain 13 | -------------------------------------------------------------------------------- /examples/basic/test_015.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_015.csp" 2 | 3 | loop1 :: Proc 4 | loop1 = echo_c.CIntKnown.0 -> loop1 5 | 6 | loop2 :: Proc 7 | loop2 = echo_c.CIntKnown.0 -> echo_c.CIntKnown.1 -> loop2 8 | 9 | testMain :: Proc 10 | testMain = loop1 |~| loop2 11 | 12 | assert testMain [FD= runAsMain(main) 13 | -------------------------------------------------------------------------------- /examples/basic/test_016.c: -------------------------------------------------------------------------------- 1 | // for loops with break statements 2 | extern void echo(int); 3 | 4 | void foo(int* z) { 5 | int x = *z; 6 | int y = 0; 7 | for(;;) { 8 | echo(x); 9 | if(y >= 1) {break;} 10 | y = y + 1; 11 | } 12 | x = x + 1; 13 | y = 0; 14 | for(;;) { 15 | echo(x); 16 | if(y >= 1) {break;} 17 | y = y + 1; 18 | } 19 | } 20 | 21 | int main() { 22 | int z = 0; 23 | foo(&z); 24 | z = z + 1; 25 | foo(&z); 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /examples/basic/test_016.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_016.csp" 2 | 3 | testMain :: Proc 4 | testMain = echo_c.CIntKnown.0 5 | -> echo_c.CIntKnown.0 6 | -> echo_c.CIntKnown.1 7 | -> echo_c.CIntKnown.1 8 | -> echo_c.CIntKnown.1 9 | -> echo_c.CIntKnown.1 10 | -> echo_c.CIntKnown.2 11 | -> echo_c.CIntKnown.2 12 | -> STOP 13 | 14 | assert testMain [FD= runMain 15 | -------------------------------------------------------------------------------- /examples/basic/test_016.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_016.csp" 2 | 3 | testMain :: Proc 4 | testMain = echo_c.CIntKnown.0 5 | -> echo_c.CIntKnown.0 6 | -> echo_c.CIntKnown.1 7 | -> echo_c.CIntKnown.1 8 | -> echo_c.CIntKnown.1 9 | -> echo_c.CIntKnown.1 10 | -> echo_c.CIntKnown.2 11 | -> echo_c.CIntKnown.2 12 | -> STOP 13 | 14 | assert testMain [FD= runAsMain(main) 15 | -------------------------------------------------------------------------------- /examples/basic/test_017.c: -------------------------------------------------------------------------------- 1 | // nested loops with breaks 2 | extern void echo(int); 3 | 4 | void foo(int* z) { 5 | int x = *z; 6 | for(;;) { 7 | int z; 8 | z = 0; 9 | for(;;) { 10 | echo(x); 11 | if(z >= 1) {break;} 12 | z = z + 1; 13 | } 14 | if (x >= 1) {break;} 15 | x = x + 1; 16 | } 17 | } 18 | 19 | int main() { 20 | int z = 0; 21 | foo(&z); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /examples/basic/test_017.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_017.csp" 2 | 3 | testMain :: Proc 4 | testMain = echo_c.CIntKnown.0 5 | -> echo_c.CIntKnown.0 6 | -> echo_c.CIntKnown.1 7 | -> echo_c.CIntKnown.1 8 | -> STOP 9 | 10 | assert testMain [FD= runMain 11 | -------------------------------------------------------------------------------- /examples/basic/test_017.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_017.csp" 2 | 3 | testMain :: Proc 4 | testMain = echo_c.CIntKnown.0 5 | -> echo_c.CIntKnown.0 6 | -> echo_c.CIntKnown.1 7 | -> echo_c.CIntKnown.1 8 | -> STOP 9 | 10 | assert testMain [FD= runAsMain(main) 11 | -------------------------------------------------------------------------------- /examples/basic/test_018.c: -------------------------------------------------------------------------------- 1 | // nested loops with breaks 2 | extern void echo(int); 3 | 4 | void foo(int* z) { 5 | int x = *z; 6 | for(;;) { 7 | int z; 8 | z = 0; 9 | for(;;) { 10 | echo(x); 11 | if(z >= 1) {break;} 12 | z = z + 1; 13 | } 14 | x = (x + 1) % 2; 15 | } 16 | } 17 | 18 | int main() { 19 | int z = 0; 20 | foo(&z); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /examples/basic/test_018.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_018.csp" 2 | 3 | testMain :: Proc 4 | testMain = echo_c.CIntKnown.0 5 | -> echo_c.CIntKnown.0 6 | -> echo_c.CIntKnown.1 7 | -> echo_c.CIntKnown.1 8 | -> testMain 9 | 10 | assert testMain [FD= runMain 11 | -------------------------------------------------------------------------------- /examples/basic/test_018.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_018.csp" 2 | 3 | testMain :: Proc 4 | testMain = echo_c.CIntKnown.0 5 | -> echo_c.CIntKnown.0 6 | -> echo_c.CIntKnown.1 7 | -> echo_c.CIntKnown.1 8 | -> testMain 9 | 10 | assert testMain [FD= runAsMain(main) 11 | -------------------------------------------------------------------------------- /examples/basic/test_019.c: -------------------------------------------------------------------------------- 1 | extern void echo(int); 2 | 3 | int main() { 4 | for(int x = 0; x < 3; x = x + 1) { 5 | echo(x); 6 | } 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /examples/basic/test_019.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_019.csp" 2 | 3 | testMain :: Proc 4 | testMain = echo_c.CIntKnown.0 5 | -> echo_c.CIntKnown.1 6 | -> echo_c.CIntKnown.2 7 | -> STOP 8 | 9 | assert testMain [FD= runMain 10 | -------------------------------------------------------------------------------- /examples/basic/test_019.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_019.csp" 2 | 3 | testMain :: Proc 4 | testMain = echo_c.CIntKnown.0 5 | -> echo_c.CIntKnown.1 6 | -> echo_c.CIntKnown.2 7 | -> STOP 8 | 9 | assert testMain [FD= runAsMain(main) 10 | -------------------------------------------------------------------------------- /examples/basic/test_020.c: -------------------------------------------------------------------------------- 1 | // nested loops 2 | extern void echo(int); 3 | 4 | int main() { 5 | do { 6 | for(int x = 0; x < 3; x = x + 1) { 7 | echo(x); 8 | } 9 | } while (1); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /examples/basic/test_020.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_020.csp" 2 | 3 | testMain :: Proc 4 | testMain = echo_c.CIntKnown.0 5 | -> echo_c.CIntKnown.1 6 | -> echo_c.CIntKnown.2 7 | -> testMain 8 | 9 | assert testMain [FD= runMain 10 | -------------------------------------------------------------------------------- /examples/basic/test_020.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_020.csp" 2 | 3 | testMain :: Proc 4 | testMain = echo_c.CIntKnown.0 5 | -> echo_c.CIntKnown.1 6 | -> echo_c.CIntKnown.2 7 | -> testMain 8 | 9 | assert testMain [FD= runAsMain(main) 10 | -------------------------------------------------------------------------------- /examples/basic/test_021.c: -------------------------------------------------------------------------------- 1 | // nested loops 2 | extern void echo(int); 3 | 4 | int main() { 5 | do { 6 | for(int x = 0; x < 3; x = x + 1) { 7 | echo(x); 8 | } 9 | } while (0); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /examples/basic/test_021.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_021.csp" 2 | 3 | testMain :: Proc 4 | testMain = echo_c.CIntKnown.0 5 | -> echo_c.CIntKnown.1 6 | -> echo_c.CIntKnown.2 7 | -> STOP 8 | 9 | assert testMain [FD= runMain 10 | -------------------------------------------------------------------------------- /examples/basic/test_021.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_021.csp" 2 | 3 | testMain :: Proc 4 | testMain = echo_c.CIntKnown.0 5 | -> echo_c.CIntKnown.1 6 | -> echo_c.CIntKnown.2 7 | -> STOP 8 | 9 | assert testMain [FD= runAsMain(main) 10 | -------------------------------------------------------------------------------- /examples/basic/test_022.c: -------------------------------------------------------------------------------- 1 | // nested loops with breaks 2 | extern void echo(int); 3 | 4 | int main() { 5 | for (int x = 0; 1; x = (x + 1)%2) { 6 | int y = 0; 7 | while (y < 2) { 8 | y = y + 1; 9 | int z = 0; 10 | do { 11 | z = z + 1; 12 | if (z >= 3) {break;}; 13 | echo (x+z); 14 | } while (1); 15 | } 16 | } 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /examples/basic/test_022.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_022.csp" 2 | 3 | testMain :: Proc 4 | testMain = echo_c.CIntKnown.1 5 | -> echo_c.CIntKnown.2 6 | -> echo_c.CIntKnown.1 7 | -> echo_c.CIntKnown.2 8 | -> echo_c.CIntKnown.2 9 | -> echo_c.CIntKnown.3 10 | -> echo_c.CIntKnown.2 11 | -> echo_c.CIntKnown.3 12 | -> testMain 13 | 14 | assert testMain [FD= runMain 15 | -------------------------------------------------------------------------------- /examples/basic/test_022.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_022.csp" 2 | 3 | testMain :: Proc 4 | testMain = echo_c.CIntKnown.1 5 | -> echo_c.CIntKnown.2 6 | -> echo_c.CIntKnown.1 7 | -> echo_c.CIntKnown.2 8 | -> echo_c.CIntKnown.2 9 | -> echo_c.CIntKnown.3 10 | -> echo_c.CIntKnown.2 11 | -> echo_c.CIntKnown.3 12 | -> testMain 13 | 14 | assert testMain [FD= runAsMain(main) 15 | -------------------------------------------------------------------------------- /examples/basic/test_023.c: -------------------------------------------------------------------------------- 1 | // floats! 2 | extern void echo(int); 3 | 4 | int main () { 5 | float x = 0.3; 6 | for (; x < 0.9; ) { 7 | x = x + 0.1; 8 | echo(0); 9 | } 10 | echo(1); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /examples/basic/test_023.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_023.csp" 2 | 3 | testMain :: Proc 4 | testMain = (echo_c.CIntKnown.0 -> testMain) 5 | |~| (echo_c.CIntKnown.1 -> STOP) 6 | 7 | assert testMain [FD= runMain 8 | -------------------------------------------------------------------------------- /examples/basic/test_023.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_023.csp" 2 | 3 | testMain :: Proc 4 | testMain = (echo_c.CIntKnown.0 -> testMain) 5 | |~| (echo_c.CIntKnown.1 -> STOP) 6 | 7 | assert testMain [FD= runAsMain(main) 8 | -------------------------------------------------------------------------------- /examples/basic/test_024.c: -------------------------------------------------------------------------------- 1 | // floats! 2 | extern void echo(int); 3 | 4 | volatile float x; 5 | 6 | int main () { 7 | for (x = 0.0; x < 0.9; ) { 8 | x = x + 0.1; 9 | echo(0); 10 | } 11 | echo(1); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /examples/basic/test_024.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_024.csp" 2 | 3 | loop :: Proc 4 | loop = 5 | cFloatRead_c.PID.0.CFloatLoc_x?_ 6 | -> ( ( cFloatRead_c.PID.0.CFloatLoc_x?_ 7 | -> cFloatWrite_c.PID.0.CFloatLoc_x.CFloatUnknown 8 | -> echo_c.CIntKnown.0 9 | -> loop) 10 | |~| (echo_c.CIntKnown.1 -> STOP)) 11 | 12 | testMain :: Proc 13 | testMain = cFloatWrite_c.PID.0.CFloatLoc_x.CFloatUnknown 14 | -> loop 15 | 16 | assert testMain [FD= runMain 17 | -------------------------------------------------------------------------------- /examples/basic/test_024.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_024.csp" 2 | 3 | loop :: Proc 4 | loop = 5 | cFloatRead_c.TID.0.CFloatLoc_x?_ 6 | -> ( ( cFloatRead_c.TID.0.CFloatLoc_x?_ 7 | -> cFloatWrite_c.TID.0.CFloatLoc_x.CFloatUnknown 8 | -> echo_c.CIntKnown.0 9 | -> loop) 10 | |~| (echo_c.CIntKnown.1 -> STOP)) 11 | 12 | testMain :: Proc 13 | testMain = cFloatWrite_c.TID.0.CFloatLoc_x.CFloatUnknown 14 | -> loop 15 | 16 | assert testMain [FD= runAsMain(main) 17 | -------------------------------------------------------------------------------- /examples/basic/test_025.c: -------------------------------------------------------------------------------- 1 | // This tests repeated updates to a local variable. 2 | 3 | volatile int y = 0; 4 | 5 | int update(int* loc) { 6 | int k = 1; 7 | k++; 8 | ++k; 9 | *loc = k; 10 | return (k + 1); 11 | } 12 | 13 | int main() { 14 | y = update(&y); 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /examples/basic/test_025.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_025.csp" 2 | 3 | testMain :: Proc 4 | testMain = cIntWrite_c.PID.0.CIntLoc_y.CIntKnown.3 -> 5 | cIntWrite_c.PID.0.CIntLoc_y.CIntKnown.4 -> STOP 6 | 7 | 8 | assert testMain [FD= runMain 9 | -------------------------------------------------------------------------------- /examples/basic/test_025.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_025.csp" 2 | 3 | testMain :: Proc 4 | testMain = cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.3 -> 5 | cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.4 -> STOP 6 | 7 | 8 | assert testMain [FD= runAsMain(main) 9 | -------------------------------------------------------------------------------- /examples/basic/test_026.c: -------------------------------------------------------------------------------- 1 | // This tests ++ and -- 2 | 3 | void echo(int); 4 | 5 | int main() { 6 | int x = 0; 7 | int y = x++; 8 | echo(y); 9 | y = ++x; 10 | echo(y); 11 | y = --x; 12 | echo(y); 13 | y = x--; 14 | echo(y); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /examples/basic/test_026.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_026.csp" 2 | 3 | testMain :: Proc 4 | testMain = echo_c.CIntKnown.0 -> 5 | echo_c.CIntKnown.2 -> 6 | echo_c.CIntKnown.1 -> 7 | echo_c.CIntKnown.1 -> 8 | STOP 9 | 10 | 11 | assert testMain [FD= runMain 12 | -------------------------------------------------------------------------------- /examples/basic/test_026.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_026.csp" 2 | 3 | testMain :: Proc 4 | testMain = echo_c.CIntKnown.0 -> 5 | echo_c.CIntKnown.2 -> 6 | echo_c.CIntKnown.1 -> 7 | echo_c.CIntKnown.1 -> 8 | STOP 9 | 10 | 11 | assert testMain [FD= runAsMain(main) 12 | -------------------------------------------------------------------------------- /examples/basic/test_027.c: -------------------------------------------------------------------------------- 1 | // This tests bitwise operators 2 | 3 | void echo(int); 4 | 5 | int main() { 6 | echo(0 | 0); 7 | echo(0 | 1); 8 | echo(1 | 0); 9 | echo(1 | 1); 10 | echo(2 | 0); 11 | echo(0 | 10); 12 | 13 | echo(0 & 0); 14 | echo(0 & 1); 15 | echo(1 & 0); 16 | echo(1 & 1); 17 | echo(2 & 0); 18 | echo(0 & 30); 19 | 20 | echo(0 ^ 0); 21 | echo(0 ^ 1); 22 | echo(1 ^ 0); 23 | echo(1 ^ 1); 24 | echo(2 ^ 0); 25 | echo(0 ^ 30); 26 | 27 | echo(~0); 28 | echo(~1); 29 | echo(~30); 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /examples/basic/test_027.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_027.csp" 2 | 3 | testMain :: Proc 4 | testMain = echo_c.CIntKnown.0 -> 5 | echo_c.CIntKnown.1 -> 6 | echo_c.CIntKnown.1 -> 7 | echo_c.CIntKnown.1 -> 8 | echo_c.CIntUnknown -> 9 | echo_c.CIntUnknown -> 10 | 11 | echo_c.CIntKnown.0 -> 12 | echo_c.CIntKnown.0 -> 13 | echo_c.CIntKnown.0 -> 14 | echo_c.CIntKnown.1 -> 15 | echo_c.CIntUnknown -> 16 | echo_c.CIntUnknown -> 17 | 18 | echo_c.CIntKnown.0 -> 19 | echo_c.CIntKnown.1 -> 20 | echo_c.CIntKnown.1 -> 21 | echo_c.CIntKnown.0 -> 22 | echo_c.CIntUnknown -> 23 | echo_c.CIntUnknown -> 24 | 25 | echo_c.CIntUnknown -> 26 | echo_c.CIntUnknown -> 27 | echo_c.CIntUnknown -> 28 | 29 | STOP 30 | 31 | 32 | assert testMain [FD= runMain 33 | -------------------------------------------------------------------------------- /examples/basic/test_027.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_027.csp" 2 | 3 | testMain :: Proc 4 | testMain = echo_c.CIntKnown.0 -> 5 | echo_c.CIntKnown.1 -> 6 | echo_c.CIntKnown.1 -> 7 | echo_c.CIntKnown.1 -> 8 | echo_c.CIntUnknown -> 9 | echo_c.CIntUnknown -> 10 | 11 | echo_c.CIntKnown.0 -> 12 | echo_c.CIntKnown.0 -> 13 | echo_c.CIntKnown.0 -> 14 | echo_c.CIntKnown.1 -> 15 | echo_c.CIntUnknown -> 16 | echo_c.CIntUnknown -> 17 | 18 | echo_c.CIntKnown.0 -> 19 | echo_c.CIntKnown.1 -> 20 | echo_c.CIntKnown.1 -> 21 | echo_c.CIntKnown.0 -> 22 | echo_c.CIntUnknown -> 23 | echo_c.CIntUnknown -> 24 | 25 | echo_c.CIntUnknown -> 26 | echo_c.CIntUnknown -> 27 | echo_c.CIntUnknown -> 28 | 29 | STOP 30 | 31 | 32 | assert testMain [FD= runAsMain(main) 33 | -------------------------------------------------------------------------------- /examples/basic/test_028.c: -------------------------------------------------------------------------------- 1 | // This tests booleans, a bit. 2 | 3 | typedef _Bool bool; 4 | void echo(int); 5 | 6 | void test(bool x) { 7 | if(x) { 8 | echo(1); 9 | } else { 10 | echo(0); 11 | } 12 | } 13 | 14 | int main() { 15 | bool x = 0; 16 | 17 | test(x); 18 | 19 | test(++x); 20 | 21 | test(++x); 22 | 23 | --x; 24 | 25 | test(x); 26 | 27 | return 0; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /examples/basic/test_028.ctest.csp: -------------------------------------------------------------------------------- 1 | 2 | 3 | include "test_028.csp" 4 | 5 | testMain1 :: Proc 6 | testMain1 = echo_c.CIntKnown.0 -> 7 | echo_c.CIntKnown.1 -> 8 | ( (echo_c.CIntKnown.0 -> testMain2) 9 | |~| (echo_c.CIntKnown.1 -> testMain2)) 10 | 11 | testMain2 :: Proc 12 | testMain2 = (echo_c.CIntKnown.0 -> STOP) 13 | |~| (echo_c.CIntKnown.1 -> STOP) 14 | 15 | assert testMain1 [FD= runMain 16 | -------------------------------------------------------------------------------- /examples/basic/test_028.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_028.csp" 2 | 3 | testMain1 :: Proc 4 | testMain1 = echo_c.CIntKnown.0 -> 5 | echo_c.CIntKnown.1 -> 6 | ( (echo_c.CIntKnown.0 -> testMain2) 7 | |~| (echo_c.CIntKnown.1 -> testMain2)) 8 | 9 | testMain2 :: Proc 10 | testMain2 = (echo_c.CIntKnown.0 -> STOP) 11 | |~| (echo_c.CIntKnown.1 -> STOP) 12 | 13 | assert testMain1 [FD= runAsMain(main) 14 | -------------------------------------------------------------------------------- /examples/basic/test_029.c: -------------------------------------------------------------------------------- 1 | // This tests the ternary operator. in this particular case, the picture 2 | // should branch because "-1" isn't represented in our model so either 3 | // branch of the if appears possible. 4 | 5 | void echo(int); 6 | 7 | static int foo(int i) { 8 | int return_var = i>0 ? 1 : 2; 9 | return return_var; 10 | } 11 | 12 | volatile int k = 0; 13 | 14 | int main() { 15 | k = foo(-1); 16 | k = foo(k); 17 | k = foo(3); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /examples/basic/test_029.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_029.csp" 2 | 3 | testMain :: Proc 4 | testMain = BRANCH 5 | 6 | 7 | BRANCH :: Proc 8 | BRANCH = BRANCH1 |~| BRANCH2 9 | 10 | BRANCH1 :: Proc 11 | BRANCH1 = cIntWrite_c.PID.0.CIntLoc_k.CIntKnown.1 -> 12 | cIntRead_c.PID.0.CIntLoc_k.CIntKnown.1 -> 13 | cIntWrite_c.PID.0.CIntLoc_k.CIntKnown.1 -> TAIL 14 | 15 | BRANCH2 :: Proc 16 | BRANCH2 = cIntWrite_c.PID.0.CIntLoc_k.CIntKnown.2 -> 17 | cIntRead_c.PID.0.CIntLoc_k.CIntKnown.2 -> 18 | cIntWrite_c.PID.0.CIntLoc_k.CIntKnown.1 -> TAIL 19 | 20 | TAIL :: Proc 21 | TAIL = cIntWrite_c.PID.0.CIntLoc_k.CIntKnown.1 -> STOP 22 | 23 | assert testMain [FD= runMain 24 | -------------------------------------------------------------------------------- /examples/basic/test_029.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_029.csp" 2 | 3 | testMain :: Proc 4 | testMain = BRANCH 5 | 6 | 7 | BRANCH :: Proc 8 | BRANCH = BRANCH1 |~| BRANCH2 9 | 10 | BRANCH1 :: Proc 11 | BRANCH1 = cIntWrite_c.TID.0.CIntLoc_k.CIntKnown.1 -> 12 | cIntRead_c.TID.0.CIntLoc_k.CIntKnown.1 -> 13 | cIntWrite_c.TID.0.CIntLoc_k.CIntKnown.1 -> TAIL 14 | 15 | BRANCH2 :: Proc 16 | BRANCH2 = cIntWrite_c.TID.0.CIntLoc_k.CIntKnown.2 -> 17 | cIntRead_c.TID.0.CIntLoc_k.CIntKnown.2 -> 18 | cIntWrite_c.TID.0.CIntLoc_k.CIntKnown.1 -> TAIL 19 | 20 | TAIL :: Proc 21 | TAIL = cIntWrite_c.TID.0.CIntLoc_k.CIntKnown.1 -> STOP 22 | 23 | assert testMain [FD= runAsMain(main) 24 | -------------------------------------------------------------------------------- /examples/basic/test_030.c: -------------------------------------------------------------------------------- 1 | // This tests the shift operations 2 | 3 | void echo(int x); 4 | 5 | int main() { 6 | echo(0 << 2); 7 | echo(0 << 30); 8 | echo(1 << 1); 9 | echo(2 << 0); 10 | echo(8 << 1); 11 | 12 | echo(0 >> 0); 13 | echo(0 >> 3); 14 | echo(2 >> 1); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /examples/basic/test_030.ctest.csp: -------------------------------------------------------------------------------- 1 | 2 | 3 | include "test_030.csp" 4 | 5 | testMain = 6 | echo_c.CIntKnown.0 7 | -> echo_c.CIntKnown.0 8 | -> echo_c.CIntKnown.2 9 | -> echo_c.CIntKnown.2 10 | -> echo_c.CIntUnknown 11 | -> echo_c.CIntUnknown 12 | -> echo_c.CIntUnknown 13 | -> echo_c.CIntUnknown 14 | -> STOP 15 | 16 | 17 | 18 | assert testMain [FD= runMain 19 | -------------------------------------------------------------------------------- /examples/basic/test_030.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_030.csp" 2 | 3 | testMain = 4 | echo_c.CIntKnown.0 5 | -> echo_c.CIntKnown.0 6 | -> echo_c.CIntKnown.2 7 | -> echo_c.CIntKnown.2 8 | -> echo_c.CIntUnknown 9 | -> echo_c.CIntUnknown 10 | -> echo_c.CIntUnknown 11 | -> echo_c.CIntUnknown 12 | -> STOP 13 | 14 | 15 | 16 | assert testMain [FD= runAsMain(main) 17 | -------------------------------------------------------------------------------- /examples/basic/test_031.c: -------------------------------------------------------------------------------- 1 | // this tests casts 2 | 3 | void echo(int); 4 | 5 | int main () { 6 | _Bool foo = 0; 7 | int bar = foo; 8 | echo(bar); 9 | echo((int)foo); 10 | echo(foo ? 0 : 1); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /examples/basic/test_031.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_031.csp" 2 | 3 | testMain = 4 | echo_c.CIntKnown.0 5 | -> echo_c.CIntKnown.0 6 | -> echo_c.CIntKnown.1 7 | -> STOP 8 | 9 | 10 | 11 | assert testMain [FD= runMain 12 | -------------------------------------------------------------------------------- /examples/basic/test_031.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_031.csp" 2 | 3 | testMain = 4 | echo_c.CIntKnown.0 5 | -> echo_c.CIntKnown.0 6 | -> echo_c.CIntKnown.1 7 | -> STOP 8 | 9 | 10 | 11 | assert testMain [FD= runAsMain(main) 12 | -------------------------------------------------------------------------------- /examples/basic/test_032.c: -------------------------------------------------------------------------------- 1 | void echo(int); 2 | 3 | // test array assignment. 4 | int main () { 5 | int foo[30]; 6 | foo[3] = 0; 7 | int x = foo[3]; 8 | echo(x); 9 | echo(foo[3]); 10 | x = foo[4]; 11 | echo(x); 12 | echo(foo[4]); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /examples/basic/test_032.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_032.csp" 2 | 3 | testMain = echo_c.CIntKnown.0 4 | -> echo_c.CIntKnown.0 5 | -> echo_c.CIntUnknown 6 | -> echo_c.CIntUnknown 7 | -> STOP 8 | 9 | 10 | 11 | assert testMain [FD= hideMemory(runMain) 12 | assert hideMemory(runMain) [FD= testMain 13 | -------------------------------------------------------------------------------- /examples/basic/test_032.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_032.csp" 2 | 3 | testMain = echo_c.CIntKnown.0 4 | -> echo_c.CIntKnown.0 5 | -> echo_c.CIntUnknown 6 | -> echo_c.CIntUnknown 7 | -> STOP 8 | 9 | 10 | 11 | assert testMain [FD= hideMemory(runAsMain(main)) 12 | assert hideMemory(runAsMain(main)) [FD= testMain 13 | -------------------------------------------------------------------------------- /examples/basic/test_033.c: -------------------------------------------------------------------------------- 1 | void echo(int); 2 | 3 | _Bool foo () { 4 | return 1; 5 | } 6 | 7 | int main () { 8 | _Bool bar = foo(); 9 | echo((int)bar); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /examples/basic/test_033.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_033.csp" 2 | 3 | testMain = 4 | echo_c.CIntKnown.1 5 | -> STOP 6 | 7 | assert testMain [FD= runMain 8 | -------------------------------------------------------------------------------- /examples/basic/test_033.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_033.csp" 2 | 3 | testMain = 4 | echo_c.CIntKnown.1 5 | -> STOP 6 | 7 | assert testMain [FD= runAsMain(main) 8 | -------------------------------------------------------------------------------- /examples/basic/test_034.c: -------------------------------------------------------------------------------- 1 | // This tests that our reachability analysis helps prevent our liveness analysis 2 | // from cleaning up variables prematurely. 3 | // 4 | // In particular, the old, non-reachabilty aware liveness analysis would "clean 5 | // up" the variable "x" after the line: 6 | // 7 | // int* z = &x; 8 | // 9 | // which appears to be the last use of x. But the reachability analysis can see 10 | // that x remains reachable from z, and thus it does not get cleaned up any 11 | // more. 12 | 13 | void echo(int x); 14 | 15 | int main () { 16 | int x = 1; 17 | echo(x); 18 | int* z = &x; 19 | echo(*z); 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /examples/basic/test_034.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_034.csp" 2 | 3 | testMain = 4 | echo_c.CIntKnown.1 5 | -> echo_c.CIntKnown.1 6 | -> STOP 7 | 8 | assert testMain [FD= runMain 9 | -------------------------------------------------------------------------------- /examples/basic/test_034.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_034.csp" 2 | 3 | testMain = 4 | echo_c.CIntKnown.1 5 | -> echo_c.CIntKnown.1 6 | -> STOP 7 | 8 | assert testMain [FD= runAsMain(main) 9 | -------------------------------------------------------------------------------- /examples/basic/test_035.c: -------------------------------------------------------------------------------- 1 | // This tests recursive structs 2 | struct int_list { 3 | int val; 4 | struct int_list *next; 5 | }; 6 | 7 | volatile struct int_list x,y; 8 | 9 | extern void echo(int x); 10 | 11 | void echo_list(struct int_list *l) { 12 | if(l) { 13 | echo(l -> val); 14 | echo_list(l -> next); 15 | } else { 16 | return; 17 | } 18 | } 19 | 20 | int main () { 21 | x.val = 1; 22 | x.next = &y; 23 | y.val = 2; 24 | struct int_list z; 25 | y.next = &z; 26 | z.val = 3; 27 | z.next = 0; 28 | echo_list(&x); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /examples/basic/test_035.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_035.csp" 2 | 3 | testMain = 4 | echo_c.CIntKnown.1 5 | -> echo_c.CIntKnown.2 6 | -> echo_c.CIntKnown.3 7 | -> STOP 8 | 9 | assert testMain [FD= hideMemSys(runMain) 10 | assert hideMemSys(runMain) [FD= testMain 11 | -------------------------------------------------------------------------------- /examples/basic/test_035.lltest.csp: -------------------------------------------------------------------------------- 1 | // I am putting stuff that doesn't parse here to intentionally fail the test quickly. 2 | // Either my model is wrong or FDR handles the recursion here poorly - either way it runs forever. 3 | askfd akl;sjdflkajg 4 | 5 | 6 | include "test_035.csp" 7 | 8 | testMain = 9 | echo_c.CIntKnown.1 10 | -> echo_c.CIntKnown.2 11 | -> echo_c.CIntKnown.3 12 | -> STOP 13 | 14 | assert testMain [FD= hideMemory(runAsMain(main)) 15 | assert hideMemory(runAsMain(main)) [FD= testMain 16 | -------------------------------------------------------------------------------- /examples/basic/test_036.c: -------------------------------------------------------------------------------- 1 | // this tests some basic void* stuff 2 | 3 | extern void echo(int); 4 | 5 | int is_null(void* p) { 6 | if(p) { 7 | return 0; 8 | } else { 9 | return 1; 10 | } 11 | } 12 | 13 | volatile int* q; 14 | 15 | int main() { 16 | int* p; 17 | int x = 1; 18 | 19 | int result; 20 | 21 | // 1 22 | result = is_null((void*)q); 23 | echo(result); 24 | 25 | // 0 26 | result = is_null((void*)&x); 27 | echo(result); 28 | 29 | // 0 30 | q = &x; 31 | result = is_null((void*)q); 32 | echo(result); 33 | 34 | // unknown 35 | result = is_null((void*)p); 36 | echo(result); 37 | 38 | // 0 39 | p = &x; 40 | result = is_null((void*)p); 41 | echo(result); 42 | 43 | // 1 44 | p = 0; 45 | result = is_null((void*)p); 46 | echo(result); 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /examples/basic/test_036.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_036.csp" 2 | 3 | testMain1 = 4 | echo_c.CIntKnown.1 5 | -> echo_c.CIntKnown.0 6 | -> echo_c.CIntKnown.0 7 | -> ( (echo_c.CIntKnown.0 -> testMain2) 8 | [] (echo_c.CIntKnown.1 -> testMain2)) 9 | 10 | testMain2 = 11 | echo_c.CIntKnown.0 12 | -> echo_c.CIntKnown.1 13 | -> STOP 14 | 15 | assert hideMemSys(runMain) [FD= testMain1 16 | -------------------------------------------------------------------------------- /examples/basic/test_036.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_036.csp" 2 | 3 | testMain1 = 4 | echo_c.CIntKnown.1 5 | -> echo_c.CIntKnown.0 6 | -> echo_c.CIntKnown.0 7 | -> ( (echo_c.CIntKnown.0 -> testMain2) 8 | [] (echo_c.CIntKnown.1 -> testMain2)) 9 | 10 | testMain2 = 11 | echo_c.CIntKnown.0 12 | -> echo_c.CIntKnown.1 13 | -> STOP 14 | 15 | assert hideMemory(runAsMain(main)) [FD= testMain1 16 | -------------------------------------------------------------------------------- /examples/basic/test_037.c: -------------------------------------------------------------------------------- 1 | // this tests the ability of a thread to get its pid and to compare pids. 2 | 3 | #include 4 | 5 | extern void echo(int); 6 | extern void spawn(void (*f)()); 7 | 8 | volatile pthread_t first_thread; 9 | 10 | volatile int ft_set = 0; 11 | 12 | void check () { 13 | while(!ft_set) { 14 | } 15 | 16 | pthread_t me = pthread_self(); 17 | if (pthread_equal(me,first_thread)) { 18 | echo(0); 19 | } else { 20 | echo(1); 21 | } 22 | } 23 | 24 | void set_and_check () { 25 | first_thread = pthread_self(); 26 | ft_set = 1; 27 | check(); 28 | } 29 | 30 | int main() { 31 | spawn(set_and_check); 32 | spawn(check); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /examples/basic/test_037.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_037.csp" 2 | 3 | channel foo 4 | 5 | testMain = (echo_c.CIntKnown.1 -> echo_c.CIntKnown.0 -> STOP) 6 | |~| (echo_c.CIntKnown.0 -> echo_c.CIntKnown.1 -> STOP) 7 | 8 | testMainDiv = 9 | let 10 | testMainDiv' = testMain |~| (foo -> testMainDiv') 11 | within 12 | testMainDiv' \ {foo} 13 | 14 | assert hideMemSys(runMain) [FD= testMain 15 | assert not testMain [FD= hideMemSys(runMain) 16 | 17 | assert hideMemSys(runMain) [FD= testMainDiv 18 | assert testMainDiv [FD= hideMemSys(runMain) 19 | -------------------------------------------------------------------------------- /examples/basic/test_037.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_037.csp" 2 | 3 | channel foo 4 | 5 | testMain = (echo_c.CIntKnown.1 -> echo_c.CIntKnown.0 -> STOP) 6 | |~| (echo_c.CIntKnown.0 -> echo_c.CIntKnown.1 -> STOP) 7 | 8 | testMainDiv = 9 | let 10 | testMainDiv' = testMain |~| (foo -> testMainDiv') 11 | within 12 | testMainDiv' \ {foo} 13 | 14 | assert hideMemSys(runAsMain(main)) [FD= testMain 15 | assert not testMain [FD= hideMemSys(runAsMain(main)) 16 | 17 | assert hideMemSys(runAsMain(main)) [FD= testMainDiv 18 | assert testMainDiv [FD= hideMemSys(runAsMain(main)) 19 | -------------------------------------------------------------------------------- /examples/basic/test_038.c: -------------------------------------------------------------------------------- 1 | // this tests pthread_create 2 | 3 | #include 4 | 5 | extern void echo(int); 6 | 7 | volatile int ft_set = 0; 8 | volatile pthread_t first_thread; 9 | volatile pthread_t second_thread; 10 | 11 | void* check (void* ft) { 12 | while(!ft_set) { 13 | } 14 | 15 | pthread_t me = pthread_self(); 16 | if (pthread_equal(me,*(pthread_t*)ft)) { 17 | echo(0); 18 | } else { 19 | echo(1); 20 | } 21 | } 22 | 23 | int main() { 24 | pthread_create(&first_thread,NULL,check,(void*) &first_thread); 25 | ft_set = 1; 26 | pthread_create(&second_thread,NULL,check,(void*) &first_thread); 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /examples/basic/test_038.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_038.csp" 2 | 3 | channel foo 4 | 5 | testMain = (echo_c.CIntKnown.1 -> echo_c.CIntKnown.0 -> STOP) 6 | |~| (echo_c.CIntKnown.0 -> echo_c.CIntKnown.1 -> STOP) 7 | 8 | testMainDiv = 9 | let 10 | testMainDiv' = testMain |~| (foo -> testMainDiv') 11 | within 12 | testMainDiv' \ {foo} 13 | 14 | assert hideMemSys(runMain) [FD= testMain 15 | assert not testMain [FD= hideMemSys(runMain) 16 | 17 | assert hideMemSys(runMain) [FD= testMainDiv 18 | assert testMainDiv [FD= hideMemSys(runMain) 19 | -------------------------------------------------------------------------------- /examples/basic/test_038.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_038.csp" 2 | 3 | channel foo 4 | 5 | testMain = (echo_c.CIntKnown.1 -> echo_c.CIntKnown.0 -> STOP) 6 | |~| (echo_c.CIntKnown.0 -> echo_c.CIntKnown.1 -> STOP) 7 | 8 | testMainDiv = 9 | let 10 | testMainDiv' = testMain |~| (foo -> testMainDiv') 11 | within 12 | testMainDiv' \ {foo} 13 | 14 | assert hideMemSys(runAsMain(main)) [FD= testMain 15 | assert not testMain [FD= hideMemSys(runAsMain(main)) 16 | 17 | assert hideMemSys(runAsMain(main)) [FD= testMainDiv 18 | assert testMainDiv [FD= hideMemSys(runAsMain(main)) 19 | -------------------------------------------------------------------------------- /examples/basic/test_039.c: -------------------------------------------------------------------------------- 1 | // test simple array initialization and use 2 | 3 | extern void echo(int); 4 | 5 | volatile int count, buf[3]; 6 | 7 | void actionOne(){ 8 | buf[0] = 1; 9 | count++; 10 | } 11 | 12 | void actionTwo(){ 13 | buf[1] = 2; 14 | count++; 15 | } 16 | 17 | void actionThree(){ 18 | buf[2] = 3; 19 | count++; 20 | } 21 | 22 | int main(){ 23 | actionOne(); 24 | actionTwo(); 25 | actionThree(); 26 | echo(buf[0]); 27 | echo(buf[1]); 28 | echo(buf[2]); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /examples/basic/test_039.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_039.csp" 2 | 3 | testMain = echo_c.CIntKnown.1 -> echo_c.CIntKnown.2 -> 4 | echo_c.CIntKnown.3 -> STOP 5 | 6 | assert testMain [FD= hideMemSys(runMain) 7 | -------------------------------------------------------------------------------- /examples/basic/test_039.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_039.csp" 2 | 3 | testMain = echo_c.CIntKnown.1 -> echo_c.CIntKnown.2 -> 4 | echo_c.CIntKnown.3 -> STOP 5 | 6 | assert testMain [FD= hideMemSys(runAsMain(main)) 7 | -------------------------------------------------------------------------------- /examples/basic/test_040.c: -------------------------------------------------------------------------------- 1 | // additional tests, checks the proper passing of integer values 2 | extern void echo(int); 3 | 4 | volatile int a=1; 5 | 6 | void rotate(){ 7 | a=(a%3) + 1; 8 | } 9 | 10 | int main(){ 11 | while(1){ 12 | echo(a); 13 | rotate(); 14 | } 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /examples/basic/test_040.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_040.csp" 2 | 3 | 4 | testMain :: Proc 5 | testMain = cIntRead_c.PID.0.CIntLoc_a.CIntKnown.1 -> echo_c.CIntKnown.1 -> 6 | cIntRead_c.PID.0.CIntLoc_a.CIntKnown.1 -> 7 | cIntWrite_c.PID.0.CIntLoc_a.CIntKnown.2 -> 8 | cIntRead_c.PID.0.CIntLoc_a.CIntKnown.2 -> echo_c.CIntKnown.2 -> cIntRead_c.PID.0.CIntLoc_a.CIntKnown.2 -> 9 | cIntWrite_c.PID.0.CIntLoc_a.CIntKnown.3 -> 10 | cIntRead_c.PID.0.CIntLoc_a.CIntKnown.3 -> echo_c.CIntKnown.3 -> cIntRead_c.PID.0.CIntLoc_a.CIntKnown.3 -> 11 | cIntWrite_c.PID.0.CIntLoc_a.CIntKnown.1 -> testMain 12 | 13 | assert testMain [FD= runMain 14 | -------------------------------------------------------------------------------- /examples/basic/test_040.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_040.csp" 2 | 3 | 4 | testMain :: Proc 5 | testMain = cIntRead_c.TID.0.CIntLoc_a.CIntKnown.1 -> echo_c.CIntKnown.1 -> 6 | cIntRead_c.TID.0.CIntLoc_a.CIntKnown.1 -> 7 | cIntWrite_c.TID.0.CIntLoc_a.CIntKnown.2 -> 8 | cIntRead_c.TID.0.CIntLoc_a.CIntKnown.2 -> echo_c.CIntKnown.2 -> cIntRead_c.TID.0.CIntLoc_a.CIntKnown.2 -> 9 | cIntWrite_c.TID.0.CIntLoc_a.CIntKnown.3 -> 10 | cIntRead_c.TID.0.CIntLoc_a.CIntKnown.3 -> echo_c.CIntKnown.3 -> cIntRead_c.TID.0.CIntLoc_a.CIntKnown.3 -> 11 | cIntWrite_c.TID.0.CIntLoc_a.CIntKnown.1 -> testMain 12 | 13 | assert testMain [FD= runAsMain(main) 14 | -------------------------------------------------------------------------------- /examples/basic/test_041.c: -------------------------------------------------------------------------------- 1 | // additional tests, checks for proper passing and conversion of void pointers 2 | extern void echo(int); 3 | 4 | volatile int a = 1; 5 | 6 | void action(void* arg){ 7 | echo(*(int*)arg); 8 | } 9 | 10 | int main(){ 11 | while(1){ 12 | action((void*)&a); 13 | a = (a+1)%2; 14 | } 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /examples/basic/test_041.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_041.csp" 2 | 3 | testMain = cIntRead_c.PID.0.CIntLoc_a.CIntKnown.1 -> echo_c.CIntKnown.1 -> 4 | cIntRead_c.PID.0.CIntLoc_a.CIntKnown.1 -> 5 | cIntWrite_c.PID.0.CIntLoc_a.CIntKnown.0 -> 6 | cIntRead_c.PID.0.CIntLoc_a.CIntKnown.0 -> echo_c.CIntKnown.0 -> 7 | cIntRead_c.PID.0.CIntLoc_a.CIntKnown.0 -> 8 | cIntWrite_c.PID.0.CIntLoc_a.CIntKnown.1 -> testMain 9 | 10 | assert testMain [FD= runMain 11 | -------------------------------------------------------------------------------- /examples/basic/test_041.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_041.csp" 2 | 3 | testMain = cIntRead_c.TID.0.CIntLoc_a.CIntKnown.1 -> echo_c.CIntKnown.1 -> 4 | cIntRead_c.TID.0.CIntLoc_a.CIntKnown.1 -> 5 | cIntWrite_c.TID.0.CIntLoc_a.CIntKnown.0 -> 6 | cIntRead_c.TID.0.CIntLoc_a.CIntKnown.0 -> echo_c.CIntKnown.0 -> 7 | cIntRead_c.TID.0.CIntLoc_a.CIntKnown.0 -> 8 | cIntWrite_c.TID.0.CIntLoc_a.CIntKnown.1 -> testMain 9 | 10 | assert testMain [FD= runAsMain(main) 11 | -------------------------------------------------------------------------------- /examples/basic/test_042.c: -------------------------------------------------------------------------------- 1 | // additional test, checks pointer use and if statements 2 | extern void echo(int); 3 | 4 | void action(int* a,int* b){ 5 | // 6 | if(*a){ 7 | echo(*a); 8 | *a = (*a + 1)%2; 9 | } 10 | else if(*b){ 11 | echo(*b); 12 | *b= (*b + 1)%2; 13 | } 14 | } 15 | 16 | int main(){ 17 | int x,y=1; 18 | action(&x,&y); 19 | return 0; 20 | } -------------------------------------------------------------------------------- /examples/basic/test_042.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_042.csp" 2 | 3 | branch1 :: Proc 4 | branch1 = echo_c.CIntUnknown -> STOP 5 | 6 | branch2 :: Proc 7 | branch2 = echo_c.CIntKnown.1 -> STOP 8 | 9 | testMain :: Proc 10 | testMain = branch1 |~| branch2 11 | 12 | assert testMain [FD= runMain 13 | -------------------------------------------------------------------------------- /examples/basic/test_042.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_042.csp" 2 | 3 | branch1 :: Proc 4 | branch1 = echo_c.CIntUnknown -> STOP 5 | 6 | branch2 :: Proc 7 | branch2 = echo_c.CIntKnown.1 -> STOP 8 | 9 | testMain :: Proc 10 | testMain = branch1 |~| branch2 11 | 12 | assert testMain [FD= runAsMain(main) 13 | -------------------------------------------------------------------------------- /examples/basic/test_043.c: -------------------------------------------------------------------------------- 1 | // additional test, checks void pointer use with if statements 2 | extern void echo(int); 3 | 4 | volatile int x,y=1; 5 | 6 | void action(void* a,void* b){ 7 | // 8 | if(*(int*)a){ 9 | echo(*(int*)a); 10 | *(int*)a = (*(int*)a + 1)%2; 11 | } 12 | else if(*(int*)b){ 13 | echo(*(int*)b); 14 | *(int*)b= (*(int*)b + 1)%2; 15 | } 16 | } 17 | 18 | int main(){ 19 | action((void*)&x,(void*)&y); 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /examples/basic/test_043.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_043.csp" 2 | 3 | testMain = cIntRead_c.PID.0.CIntLoc_x.CIntKnown.0 -> 4 | cIntRead_c.PID.0.CIntLoc_y.CIntKnown.1 -> 5 | cIntRead_c.PID.0.CIntLoc_y.CIntKnown.1 -> echo_c.CIntKnown.1 -> 6 | cIntRead_c.PID.0.CIntLoc_y.CIntKnown.1 -> 7 | cIntWrite_c.PID.0.CIntLoc_y.CIntKnown.0 -> STOP 8 | 9 | assert testMain [FD= runMain 10 | -------------------------------------------------------------------------------- /examples/basic/test_043.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_043.csp" 2 | 3 | testMain = cIntRead_c.TID.0.CIntLoc_x.CIntKnown.0 -> 4 | cIntRead_c.TID.0.CIntLoc_y.CIntKnown.1 -> 5 | cIntRead_c.TID.0.CIntLoc_y.CIntKnown.1 -> echo_c.CIntKnown.1 -> 6 | cIntRead_c.TID.0.CIntLoc_y.CIntKnown.1 -> 7 | cIntWrite_c.TID.0.CIntLoc_y.CIntKnown.0 -> STOP 8 | 9 | assert testMain [FD= runAsMain(main) 10 | -------------------------------------------------------------------------------- /examples/basic/test_044.c: -------------------------------------------------------------------------------- 1 | // additional test, checks void pointer use with structs and conditionals 2 | extern void echo(int); 3 | 4 | struct foo{ 5 | int a; 6 | _Bool b; 7 | }; 8 | 9 | volatile struct foo bar; 10 | 11 | void action(void* arg){ 12 | if( ((struct foo*)arg)->b ){ 13 | echo( (int)((struct foo*)arg)->b ); 14 | ((struct foo*)arg)->b = !((struct foo*)arg)->b; 15 | } 16 | else { 17 | echo( ((struct foo*)arg)->a ); 18 | ((struct foo*)arg)->a = ( ((struct foo*)arg)->a + 1 ) % 2; 19 | } 20 | } 21 | 22 | int main(){ 23 | bar.a=1; 24 | bar.b=0; 25 | action((void*)&bar); 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /examples/basic/test_044.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_044.csp" 2 | 3 | testMain = foo_a_write_c.PID.0.fooLoc_bar.CIntKnown.1 -> 4 | foo_b_write_c.PID.0.fooLoc_bar.CBoolFalse -> 5 | foo_b_read_c.PID.0.fooLoc_bar.CBoolFalse -> 6 | foo_a_read_c.PID.0.fooLoc_bar.CIntKnown.1 -> echo_c.CIntKnown.1 -> 7 | foo_a_read_c.PID.0.fooLoc_bar.CIntKnown.1 -> 8 | foo_a_write_c.PID.0.fooLoc_bar.CIntKnown.0 -> STOP 9 | 10 | assert testMain [FD= runMain 11 | -------------------------------------------------------------------------------- /examples/basic/test_044.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_044.csp" 2 | 3 | testMain = foo_a_write_c.TID.0.fooLoc_bar.CIntKnown.1 -> 4 | foo_b_write_c.TID.0.fooLoc_bar.CBoolFalse -> 5 | foo_b_read_c.TID.0.fooLoc_bar.CBoolFalse -> 6 | foo_a_read_c.TID.0.fooLoc_bar.CIntKnown.1 -> echo_c.CIntKnown.1 -> 7 | foo_a_read_c.TID.0.fooLoc_bar.CIntKnown.1 -> 8 | foo_a_write_c.TID.0.fooLoc_bar.CIntKnown.0 -> STOP 9 | 10 | assert testMain [FD= runAsMain(main) 11 | -------------------------------------------------------------------------------- /examples/basic/test_045.c: -------------------------------------------------------------------------------- 1 | // test some stuff with global, statically-allocated arrays. 2 | extern void echo(int); 3 | 4 | volatile int x[3]; 5 | 6 | int main() { 7 | echo(x[0]); 8 | echo(x[1]); 9 | echo(x[2]); 10 | 11 | x[1] = 3; 12 | echo(x[0]); 13 | echo(x[1]); 14 | echo(x[2]); 15 | 16 | x[0] = 2; 17 | x[2] = 1; 18 | echo(x[0]); 19 | echo(x[1]); 20 | echo(x[2]); 21 | 22 | x[1] = x[0] + x[2] - 1; 23 | echo(x[0]); 24 | echo(x[1]); 25 | echo(x[2]); 26 | 27 | x[2] = x[1] + x[2]; 28 | echo(x[0]); 29 | echo(x[1]); 30 | echo(x[2]); 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /examples/basic/test_045.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_045.csp" 2 | 3 | testMain = echo_c.CIntKnown.0 4 | -> echo_c.CIntKnown.0 5 | -> echo_c.CIntKnown.0 6 | 7 | -> echo_c.CIntKnown.0 8 | -> echo_c.CIntKnown.3 9 | -> echo_c.CIntKnown.0 10 | 11 | -> echo_c.CIntKnown.2 12 | -> echo_c.CIntKnown.3 13 | -> echo_c.CIntKnown.1 14 | 15 | -> echo_c.CIntKnown.2 16 | -> echo_c.CIntKnown.2 17 | -> echo_c.CIntKnown.1 18 | 19 | -> echo_c.CIntKnown.2 20 | -> echo_c.CIntKnown.2 21 | -> echo_c.CIntKnown.3 22 | 23 | -> STOP 24 | 25 | assert testMain [FD= hideMemory(runMain) 26 | assert hideMemory(runMain) [FD= testMain 27 | 28 | -------------------------------------------------------------------------------- /examples/basic/test_045.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_045.csp" 2 | 3 | testMain = echo_c.CIntKnown.0 4 | -> echo_c.CIntKnown.0 5 | -> echo_c.CIntKnown.0 6 | 7 | -> echo_c.CIntKnown.0 8 | -> echo_c.CIntKnown.3 9 | -> echo_c.CIntKnown.0 10 | 11 | -> echo_c.CIntKnown.2 12 | -> echo_c.CIntKnown.3 13 | -> echo_c.CIntKnown.1 14 | 15 | -> echo_c.CIntKnown.2 16 | -> echo_c.CIntKnown.2 17 | -> echo_c.CIntKnown.1 18 | 19 | -> echo_c.CIntKnown.2 20 | -> echo_c.CIntKnown.2 21 | -> echo_c.CIntKnown.3 22 | 23 | -> STOP 24 | 25 | assert testMain [FD= hideMemory(runAsMain(main)) 26 | assert hideMemory(runAsMain(main)) [FD= testMain 27 | 28 | -------------------------------------------------------------------------------- /examples/basic/test_046.c: -------------------------------------------------------------------------------- 1 | // passing around global arrays as args 2 | extern void echo(int); 3 | 4 | volatile int x[2]; 5 | 6 | void write_arr(int *x, int n) { 7 | x[0] = n; 8 | x[1] = n+2; 9 | return; 10 | } 11 | 12 | void read_arr(int x[2]) { 13 | int y = x[0]; 14 | echo(y); 15 | y = x[1]; 16 | echo(y); 17 | return; 18 | } 19 | 20 | int main() { 21 | write_arr(x,0); 22 | read_arr(x); 23 | write_arr(x,1); 24 | read_arr(x); 25 | } 26 | -------------------------------------------------------------------------------- /examples/basic/test_046.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_046.csp" 2 | 3 | testMain = echo_c.CIntKnown.0 4 | -> echo_c.CIntKnown.2 5 | -> echo_c.CIntKnown.1 6 | -> echo_c.CIntKnown.3 7 | -> STOP 8 | 9 | assert testMain [FD= hideMemory(runMain) 10 | assert hideMemory(runMain) [FD= testMain 11 | 12 | -------------------------------------------------------------------------------- /examples/basic/test_046.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_046.csp" 2 | 3 | testMain = echo_c.CIntKnown.0 4 | -> echo_c.CIntKnown.2 5 | -> echo_c.CIntKnown.1 6 | -> echo_c.CIntKnown.3 7 | -> STOP 8 | 9 | assert testMain [FD= hideMemory(runAsMain(main)) 10 | assert hideMemory(runAsMain(main)) [FD= testMain 11 | 12 | -------------------------------------------------------------------------------- /examples/basic/test_047.c: -------------------------------------------------------------------------------- 1 | // test out-of-bounds error 2 | extern void echo(int); 3 | 4 | volatile int x[3]; 5 | 6 | int main() { 7 | x[0] = 1; 8 | x[1] = 2; 9 | x[2] = 3; 10 | 11 | echo(x[0]); 12 | echo(x[1]); 13 | echo(x[2]); 14 | 15 | x[3] = 4; 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /examples/basic/test_047.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_047.csp" 2 | 3 | testMain = echo_c.CIntKnown.1 4 | -> echo_c.CIntKnown.2 5 | -> echo_c.CIntKnown.3 6 | -> arrayIndex_ERROR 7 | -> STOP 8 | 9 | assert testMain [FD= hideMemory(runMain) 10 | assert hideMemory(runMain) [FD= testMain 11 | 12 | -------------------------------------------------------------------------------- /examples/basic/test_047.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_047.csp" 2 | 3 | testMain = echo_c.CIntKnown.1 4 | -> echo_c.CIntKnown.2 5 | -> echo_c.CIntKnown.3 6 | -> arrayIndex_ERROR 7 | -> STOP 8 | 9 | assert testMain [FD= hideMemory(runAsMain(main)) 10 | assert hideMemory(runAsMain(main)) [FD= testMain 11 | 12 | -------------------------------------------------------------------------------- /examples/basic/test_048.c: -------------------------------------------------------------------------------- 1 | // this tests mutex functionality 2 | 3 | #include 4 | 5 | extern void echo(int); 6 | 7 | volatile pthread_t firstThread; 8 | volatile pthread_t secondThread; 9 | volatile pthread_mutex_t lock; 10 | volatile int count, start; 11 | 12 | void* firstAction(void* arg){ 13 | while(1){ 14 | if(!start){ 15 | pthread_mutex_lock(&lock); 16 | start = 1; 17 | count = (++count) % 4; 18 | echo(count); 19 | pthread_mutex_unlock(&lock); 20 | } 21 | } 22 | return NULL; 23 | } 24 | 25 | void* secondAction(void* arg){ 26 | while(1){ 27 | if(start){ 28 | pthread_mutex_lock(&lock); 29 | start = 0; 30 | count = (count+3) % 4; 31 | echo(count); 32 | pthread_mutex_unlock(&lock); 33 | } 34 | } 35 | return NULL; 36 | } 37 | 38 | int main(){ 39 | if(pthread_mutex_init(&lock,NULL) != 0){ 40 | return 1; 41 | } 42 | pthread_create(&firstThread, NULL, firstAction, NULL); 43 | pthread_create(&secondThread, NULL, secondAction, NULL); 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /examples/basic/test_048.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_048.csp" 2 | 3 | channel foo 4 | 5 | testMain = echo_c.CIntKnown.1 -> echo_c.CIntKnown.0 -> testMain 6 | 7 | testMainDiv = 8 | let 9 | testMainDiv' = testMain |~| (foo -> testMainDiv') 10 | within 11 | testMainDiv' \ {foo} 12 | 13 | assert hideMemSys(runMain) [FD= testMain 14 | assert not testMain [FD= hideMemSys(runMain) 15 | 16 | assert hideMemSys(runMain) [FD= testMainDiv 17 | assert testMainDiv [FD= hideMemSys(runMain) 18 | -------------------------------------------------------------------------------- /examples/basic/test_048.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_048.csp" 2 | 3 | channel foo 4 | 5 | testMain = echo_c.CIntKnown.1 -> echo_c.CIntKnown.0 -> testMain 6 | 7 | testMainDiv = 8 | let 9 | testMainDiv' = testMain |~| (foo -> testMainDiv') 10 | within 11 | testMainDiv' \ {foo} 12 | 13 | assert hideMemSys(runAsMain(main)) [FD= testMain 14 | assert not testMain [FD= hideMemSys(runAsMain(main)) 15 | 16 | assert hideMemSys(runAsMain(main)) [FD= testMainDiv 17 | assert testMainDiv [FD= hideMemSys(runAsMain(main)) 18 | -------------------------------------------------------------------------------- /examples/basic/test_049.c: -------------------------------------------------------------------------------- 1 | // additional test for mutex functionality 2 | 3 | #include 4 | 5 | extern void echo(int); 6 | 7 | volatile pthread_t first_thread; 8 | volatile pthread_t second_thread; 9 | volatile pthread_mutex_t lock; 10 | volatile int count, start; 11 | 12 | void* action(void* arg){ 13 | pthread_t self = pthread_self(); 14 | if(pthread_equal(self,first_thread)) 15 | while(!start); 16 | int i, j; 17 | 18 | pthread_mutex_lock(&lock); 19 | start = 1; 20 | count = 0; 21 | echo(count); 22 | 23 | count = (++count) % 4; 24 | echo(count); 25 | pthread_mutex_unlock(&lock); 26 | return NULL; 27 | } 28 | 29 | int main(){ 30 | if(pthread_mutex_init(&lock,NULL) != 0){ 31 | return 1; 32 | } 33 | pthread_create(&first_thread, NULL, action, NULL); 34 | pthread_create(&second_thread, NULL, action, NULL); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /examples/basic/test_049.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_049.csp" 2 | 3 | channel foo 4 | 5 | testMain = echo_c.CIntKnown.0 -> echo_c.CIntKnown.1 -> 6 | echo_c.CIntKnown.0 -> echo_c.CIntKnown.1 -> STOP 7 | 8 | testMainDiv = 9 | let 10 | testMainDiv' = testMain |~| (foo -> testMainDiv') 11 | within 12 | testMainDiv' \ {foo} 13 | 14 | assert hideMemSys(runMain) [FD= testMain 15 | assert not testMain [FD= hideMemSys(runMain) 16 | 17 | assert hideMemSys(runMain) [FD= testMainDiv 18 | assert testMainDiv [FD= hideMemSys(runMain) 19 | -------------------------------------------------------------------------------- /examples/basic/test_049.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_049.csp" 2 | 3 | channel foo 4 | 5 | testMain = echo_c.CIntKnown.0 -> echo_c.CIntKnown.1 -> 6 | echo_c.CIntKnown.0 -> echo_c.CIntKnown.1 -> STOP 7 | 8 | testMainDiv = 9 | let 10 | testMainDiv' = testMain |~| (foo -> testMainDiv') 11 | within 12 | testMainDiv' \ {foo} 13 | 14 | assert hideMemSys(runAsMain(main)) [FD= testMain 15 | assert not testMain [FD= hideMemSys(runAsMain(main)) 16 | 17 | assert hideMemSys(runAsMain(main)) [FD= testMainDiv 18 | assert testMainDiv [FD= hideMemSys(runAsMain(main)) 19 | -------------------------------------------------------------------------------- /examples/basic/test_050.c: -------------------------------------------------------------------------------- 1 | // test some stuff with local, statically-allocated arrays. 2 | extern void echo(int); 3 | 4 | int main() { 5 | int x[3]; 6 | 7 | echo(x[0]); 8 | echo(x[1]); 9 | echo(x[2]); 10 | 11 | x[1] = 3; 12 | echo(x[0]); 13 | echo(x[1]); 14 | echo(x[2]); 15 | 16 | x[0] = 2; 17 | x[2] = 1; 18 | echo(x[0]); 19 | echo(x[1]); 20 | echo(x[2]); 21 | 22 | x[1] = x[0] + x[2] - 1; 23 | echo(x[0]); 24 | echo(x[1]); 25 | echo(x[2]); 26 | 27 | x[2] = x[1] + x[2]; 28 | echo(x[0]); 29 | echo(x[1]); 30 | echo(x[2]); 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /examples/basic/test_050.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_050.csp" 2 | 3 | testMain = echo_c.CIntUnknown 4 | -> echo_c.CIntUnknown 5 | -> echo_c.CIntUnknown 6 | 7 | -> echo_c.CIntUnknown 8 | -> echo_c.CIntKnown.3 9 | -> echo_c.CIntUnknown 10 | 11 | -> echo_c.CIntKnown.2 12 | -> echo_c.CIntKnown.3 13 | -> echo_c.CIntKnown.1 14 | 15 | -> echo_c.CIntKnown.2 16 | -> echo_c.CIntKnown.2 17 | -> echo_c.CIntKnown.1 18 | 19 | -> echo_c.CIntKnown.2 20 | -> echo_c.CIntKnown.2 21 | -> echo_c.CIntKnown.3 22 | 23 | -> STOP 24 | 25 | assert testMain [FD= hideMemory(runMain) 26 | assert hideMemory(runMain) [FD= testMain 27 | 28 | -------------------------------------------------------------------------------- /examples/basic/test_050.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_050.csp" 2 | 3 | testMain = echo_c.CIntUnknown 4 | -> echo_c.CIntUnknown 5 | -> echo_c.CIntUnknown 6 | 7 | -> echo_c.CIntUnknown 8 | -> echo_c.CIntKnown.3 9 | -> echo_c.CIntUnknown 10 | 11 | -> echo_c.CIntKnown.2 12 | -> echo_c.CIntKnown.3 13 | -> echo_c.CIntKnown.1 14 | 15 | -> echo_c.CIntKnown.2 16 | -> echo_c.CIntKnown.2 17 | -> echo_c.CIntKnown.1 18 | 19 | -> echo_c.CIntKnown.2 20 | -> echo_c.CIntKnown.2 21 | -> echo_c.CIntKnown.3 22 | 23 | -> STOP 24 | 25 | assert testMain [FD= hideMemory(runAsMain(main)) 26 | assert hideMemory(runAsMain(main)) [FD= testMain 27 | 28 | -------------------------------------------------------------------------------- /examples/basic/test_051.c: -------------------------------------------------------------------------------- 1 | // This tests structs with initializers 2 | extern void echo(int x); 3 | 4 | struct foo{ 5 | int x; 6 | int y; 7 | }; 8 | 9 | volatile struct foo pair = { .x = 1, .y=2 }; 10 | 11 | int main(){ 12 | echo(pair.x); 13 | echo(pair.y); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /examples/basic/test_051.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_051.csp" 2 | 3 | testMain = echo_c.CIntKnown.1 4 | -> echo_c.CIntKnown.2 5 | -> STOP 6 | 7 | assert testMain [FD= hideMemSys(runMain) 8 | assert hideMemSys(runMain) [FD= testMain 9 | -------------------------------------------------------------------------------- /examples/basic/test_051.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_051.csp" 2 | 3 | testMain = echo_c.CIntKnown.1 4 | -> echo_c.CIntKnown.2 5 | -> STOP 6 | 7 | assert testMain [FD= hideMemSys(runAsMain(main)) 8 | assert hideMemSys(runAsMain(main)) [FD= testMain 9 | -------------------------------------------------------------------------------- /examples/basic/test_052.c: -------------------------------------------------------------------------------- 1 | // This tests partial initialization of structs 2 | extern void echo(int x); 3 | 4 | struct foo{ 5 | int x; 6 | int y; 7 | }; 8 | 9 | volatile struct foo pairOne = { .x = 1 }; 10 | volatile struct foo pairTwo = { .y = 2 }; 11 | 12 | int main(){ 13 | echo(pairOne.x); 14 | echo(pairOne.y); 15 | echo(pairTwo.x); 16 | echo(pairTwo.y); 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /examples/basic/test_052.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_052.csp" 2 | 3 | testMain = echo_c.CIntKnown.1 4 | -> echo_c.CIntKnown.0 5 | -> echo_c.CIntKnown.0 6 | -> echo_c.CIntKnown.2 7 | -> STOP 8 | 9 | assert testMain [FD= hideMemSys(runMain) 10 | assert hideMemSys(runMain) [FD= testMain 11 | -------------------------------------------------------------------------------- /examples/basic/test_052.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_052.csp" 2 | 3 | testMain = echo_c.CIntKnown.1 4 | -> echo_c.CIntKnown.0 5 | -> echo_c.CIntKnown.0 6 | -> echo_c.CIntKnown.2 7 | -> STOP 8 | 9 | assert testMain [FD= hideMemSys(runAsMain(main)) 10 | assert hideMemSys(runAsMain(main)) [FD= testMain 11 | -------------------------------------------------------------------------------- /examples/basic/test_053.c: -------------------------------------------------------------------------------- 1 | // passing around local arrays as args 2 | extern void echo(int); 3 | 4 | void write_arr(int *x, int n) { 5 | x[0] = n; 6 | x[1] = n+2; 7 | return; 8 | } 9 | 10 | void read_arr(int x[2]) { 11 | int y = x[0]; 12 | echo(y); 13 | y = x[1]; 14 | echo(y); 15 | return; 16 | } 17 | 18 | int main() { 19 | int x[2]; 20 | write_arr(x,0); 21 | read_arr(x); 22 | write_arr(x,1); 23 | read_arr(x); 24 | } 25 | -------------------------------------------------------------------------------- /examples/basic/test_053.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_053.csp" 2 | 3 | testMain = echo_c.CIntKnown.0 4 | -> echo_c.CIntKnown.2 5 | -> echo_c.CIntKnown.1 6 | -> echo_c.CIntKnown.3 7 | -> STOP 8 | 9 | assert testMain [FD= hideMemory(runMain) 10 | assert hideMemory(runMain) [FD= testMain 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/basic/test_053.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_053.csp" 2 | 3 | testMain = echo_c.CIntKnown.0 4 | -> echo_c.CIntKnown.2 5 | -> echo_c.CIntKnown.1 6 | -> echo_c.CIntKnown.3 7 | -> STOP 8 | 9 | assert testMain [FD= hideMemory(runAsMain(main)) 10 | assert hideMemory(runAsMain(main)) [FD= testMain 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/basic/test_054.c: -------------------------------------------------------------------------------- 1 | // test out-of-bounds error on local array 2 | extern void echo(int); 3 | 4 | int main() { 5 | int x[3]; 6 | 7 | x[0] = 1; 8 | x[1] = 2; 9 | x[2] = 3; 10 | 11 | echo(x[0]); 12 | echo(x[1]); 13 | echo(x[2]); 14 | 15 | x[3] = 4; 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /examples/basic/test_054.ctest.csp: -------------------------------------------------------------------------------- 1 | include "test_054.csp" 2 | 3 | testMain = echo_c.CIntKnown.1 4 | -> echo_c.CIntKnown.2 5 | -> echo_c.CIntKnown.3 6 | -> arrayIndex_ERROR 7 | -> STOP 8 | 9 | assert testMain [FD= hideMemory(runMain) 10 | assert hideMemory(runMain) [FD= testMain 11 | 12 | -------------------------------------------------------------------------------- /examples/basic/test_054.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_054.csp" 2 | 3 | testMain = echo_c.CIntKnown.1 4 | -> echo_c.CIntKnown.2 5 | -> echo_c.CIntKnown.3 6 | -> arrayIndex_ERROR 7 | -> STOP 8 | 9 | assert testMain [FD= hideMemory(runAsMain(main)) 10 | assert hideMemory(runAsMain(main)) [FD= testMain 11 | 12 | -------------------------------------------------------------------------------- /examples/basic/test_055.c: -------------------------------------------------------------------------------- 1 | // test non-constant index into global array 2 | void echo(int); 3 | 4 | volatile int x[4] = {4,2,0,6}; 5 | 6 | int main() { 7 | for (int i = 0; i < 3; i++) { 8 | echo(x[i]); 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /examples/basic/test_055.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_055.csp" 2 | 3 | testMain = 4 | cIntRead_c.TID.0.CIntLoc_x.CIntKnown.4 5 | -> echo_c.CIntKnown.4 6 | -> cIntRead_c.TID.0.CIntLoc_x_1.CIntKnown.2 7 | -> echo_c.CIntKnown.2 8 | -> cIntRead_c.TID.0.CIntLoc_x_2.CIntKnown.0 9 | -> echo_c.CIntKnown.0 10 | -> STOP 11 | 12 | assert testMain [FD= runAsMain(main) 13 | assert runAsMain(main) [FD= testMain 14 | 15 | -------------------------------------------------------------------------------- /examples/basic/test_056.c: -------------------------------------------------------------------------------- 1 | // test non-constant index into local array 2 | void echo(int); 3 | 4 | int main() { 5 | int x[4]; 6 | x[0] = 4; 7 | x[1] = 2; 8 | x[2] = 0; 9 | x[3] = 6; 10 | for (int i = 0; i < 3; i++) { 11 | echo(x[i]); 12 | } 13 | } 14 | 15 | -------------------------------------------------------------------------------- /examples/basic/test_056.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_056.csp" 2 | 3 | testMain = 4 | echo_c.CIntKnown.4 5 | -> echo_c.CIntKnown.2 6 | -> echo_c.CIntKnown.0 7 | -> STOP 8 | 9 | assert testMain [FD= runAsMain(main) 10 | assert runAsMain(main) [FD= testMain 11 | 12 | -------------------------------------------------------------------------------- /examples/basic/test_057.c: -------------------------------------------------------------------------------- 1 | // this test generates GEP instructions with non-zero first indices, in the llvm 2 | // version. 3 | 4 | void echo(int); 5 | 6 | void readArr(int *x) { 7 | echo(x[0]); 8 | echo(x[1]); 9 | echo(x[2]); 10 | } 11 | 12 | volatile int a[3] = {2,1,2}; 13 | 14 | int main() { 15 | int b[3]; 16 | b[0] = 1; 17 | b[1] = 3; 18 | b[2] = 1; 19 | readArr(a); 20 | readArr(b); 21 | return 0; 22 | } 23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/basic/test_057.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_057.csp" 2 | 3 | testMain = 4 | cIntRead_c.TID.0.CIntLoc_a.CIntKnown.2 5 | -> echo_c.CIntKnown.2 6 | -> cIntRead_c.TID.0.CIntLoc_a_1.CIntKnown.1 7 | -> echo_c.CIntKnown.1 8 | -> cIntRead_c.TID.0.CIntLoc_a_2.CIntKnown.2 9 | -> echo_c.CIntKnown.2 10 | -> echo_c.CIntKnown.1 11 | -> echo_c.CIntKnown.3 12 | -> echo_c.CIntKnown.1 13 | -> STOP 14 | 15 | assert testMain [FD= runAsMain(main) 16 | assert runAsMain(main) [FD= testMain 17 | 18 | -------------------------------------------------------------------------------- /examples/basic/test_058.c: -------------------------------------------------------------------------------- 1 | // This checks that we push stack values in the right order. 2 | 3 | typedef struct { 4 | int x; 5 | void (**f)(); 6 | } S; 7 | 8 | void echo(int); 9 | 10 | void inspect(S* s) { 11 | echo(s->x); 12 | } 13 | 14 | int main() { 15 | S s; 16 | inspect(&s); 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /examples/basic/test_058.lltest.csp: -------------------------------------------------------------------------------- 1 | include "test_058.csp" 2 | 3 | testMain = echo_c.CIntUnknown -> STOP 4 | 5 | assert testMain [FD= runAsMain(main) 6 | assert runAsMain(main) [FD= testMain 7 | 8 | -------------------------------------------------------------------------------- /examples/demos/DGraph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperlaboratory/cspgen/46c41f6d8bd926be1188cd6bd014801557380ebe/examples/demos/DGraph.png -------------------------------------------------------------------------------- /examples/demos/Divergence.c: -------------------------------------------------------------------------------- 1 | 2 | void echo(int y); 3 | void spawn(void (*f)()); 4 | 5 | int x = 0; 6 | 7 | void countToTwo () { 8 | while(1) { 9 | if (x==2) break; 10 | x++; 11 | } 12 | echo(x); 13 | } 14 | 15 | void attacker () { 16 | x = 3; 17 | return; 18 | } 19 | 20 | int main() { 21 | spawn(countToTwo); 22 | spawn(attacker); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /examples/demos/Divergence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperlaboratory/cspgen/46c41f6d8bd926be1188cd6bd014801557380ebe/examples/demos/Divergence.png -------------------------------------------------------------------------------- /examples/demos/DivergenceCheck.csp: -------------------------------------------------------------------------------- 1 | 2 | include "Divergence.csp" 3 | 4 | assert hideMemory(runMain) :[divergence free] 5 | -------------------------------------------------------------------------------- /examples/demos/RCGraph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperlaboratory/cspgen/46c41f6d8bd926be1188cd6bd014801557380ebe/examples/demos/RCGraph.png -------------------------------------------------------------------------------- /examples/demos/RaceCond.c: -------------------------------------------------------------------------------- 1 | void echo(int y); 2 | void spawn(void (*f)()); 3 | 4 | int x = 0; 5 | 6 | void addOne() { 7 | int y = ++x; 8 | echo(y); 9 | } 10 | 11 | int main() { 12 | spawn(addOne); 13 | spawn(addOne); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /examples/demos/RaceCondRefines.csp: -------------------------------------------------------------------------------- 1 | include "RaceCond.csp" 2 | 3 | raceCondSpec :: Proc 4 | raceCondSpec = (echo_c.CIntKnown.1 -> echo_c.CIntKnown.2 -> STOP) 5 | 6 | assert raceCondSpec [T= hideMemSys(runMain) 7 | 8 | -------------------------------------------------------------------------------- /examples/demos/externals: -------------------------------------------------------------------------------- 1 | -- Default external functions 2 | -- 3 | -- Specify functions like: 4 | -- 5 | -- returnType name(argMode1,...,argModen); 6 | -- 7 | -- Where argMode ::= in | out | inout 8 | -- 9 | -- For input arguments (the usual case), output arguments (like a pointer where 10 | -- the function stores something), or arguments used both ways. 11 | 12 | 13 | @section FUNCTIONS { 14 | 15 | void send(in,in,in); 16 | 17 | void recv(in,in,out); 18 | 19 | void echo(in); 20 | 21 | void spawn(in); 22 | 23 | pid pthread_self(); 24 | 25 | int pthread_equal(in,in); 26 | 27 | int pthread_create(out, in, in, in); 28 | 29 | int pthread_mutex_init(in, in); 30 | 31 | int pthread_mutex_lock(in); 32 | 33 | int pthread_mutex_unlock(in); 34 | 35 | } 36 | 37 | @section SETTINGS { 38 | 39 | minimumCVal = 0; 40 | 41 | maximumCVal = 4; 42 | 43 | } 44 | -------------------------------------------------------------------------------- /examples/demos/runtimePThread.csp: -------------------------------------------------------------------------------- 1 | include "runtime.csp" 2 | 3 | -- These are implementations of the pthreads mutex functions against our model. 4 | -- 5 | -- We are being a little unfaithful to the pthreads model: when something goes 6 | -- wrong (e.g., code attempts to lock an uninitialized mutex), we are causing a 7 | -- CSP error rather than returning an error code. 8 | -- 9 | -- This has the advantage that these kinds of errors are highly visible, but the 10 | -- disadvantages that (1) we aren't completely sound and (2) we'll incorrectly 11 | -- report errors for code that checks for and gracefully handles error conditions. 12 | -- 13 | -- A better compromise might be to create some csp events indicating the errors 14 | -- and return error codes but also communicate those events. This would retain 15 | -- the high visibility of the error conditions but also be sound. 16 | 17 | 18 | 19 | -- XXX Right now we ignore the parameters argument. Ideally we'd check that 20 | -- it's null, and fail otherwise. That's tricky because the type for this 21 | -- struct is actually generated at runtime. We really need a better story about 22 | -- external dependencies. 23 | -- 24 | --pthread_mutex_init :: 25 | -- (MutexLoc, 26 | -- LocalState, 27 | -- PIDTyp, 28 | -- (LocalState, PIDTyp, CInt) -> Proc) 29 | -- -> Proc 30 | pthread_mutex_init (mutLoc,_,locals,pid,k) = 31 | mutex_init_c?mid 32 | -> mutexCSPWriter(locals,pid,mutLoc,MutCSP.mid, 33 | \locals', pid', _ @ k(locals',pid',CIntKnown.0)) 34 | 35 | pthread_mutex_destroy :: 36 | (MutexCSPLoc, 37 | LocalState, 38 | PIDTyp, 39 | (LocalState, PIDTyp, CInt) -> Proc) 40 | -> Proc 41 | pthread_mutex_destroy (mutLoc,locals,pid,k) = 42 | let 43 | destroy_mut (_,_,Mut_UNINITIALIZED) = 44 | destroy_uninit_mutex_ERROR -> STOP 45 | destroy_mut (locals',pid',Mut.mid) = 46 | mutex_destroy_c!mid -> k(locals',pid',CIntKnown.0) 47 | within 48 | mutexCSPReader(locals,pid,mutLoc,destroy_mut) 49 | 50 | pthread_mutex_lock :: 51 | (MutexCSPLoc, 52 | LocalState, 53 | PIDTyp, 54 | (LocalState, PIDTyp, CInt) -> Proc) 55 | -> Proc 56 | pthread_mutex_lock (mutLoc,locals,pid,k) = 57 | let 58 | lock_mut (_,_,Mut_UNINITIALIZED) = 59 | lock_uninit_mutex_ERROR -> STOP 60 | lock_mut (locals',pid',Mut.mid) = 61 | mutex_lock_c!mid!pid' -> k(locals',pid',CIntKnown.0) 62 | within 63 | mutexCSPReader(locals,pid,mutLoc,lock_mut) 64 | 65 | pthread_mutex_unlock :: 66 | (MutexCSPLoc, 67 | LocalState, 68 | PIDTyp, 69 | (LocalState, PIDTyp, CInt) -> Proc) 70 | -> Proc 71 | pthread_mutex_unlock (mutLoc,locals,pid,k) = 72 | let 73 | unlock_mut (_,_,Mut_UNINITIALIZED) = 74 | unlock_uninit_mutex_ERROR -> STOP 75 | unlock_mut (locals',pid',Mut.mid) = 76 | mutex_unlock_c!mid!pid' -> k(locals',pid',CIntKnown.0) 77 | within 78 | mutexCSPReader(locals,pid,mutLoc,unlock_mut) 79 | 80 | pthread_self :: (LocalState,PIDTyp, 81 | (LocalState,PIDTyp,PIDTyp) -> Proc) 82 | -> Proc 83 | pthread_self (s,p,k) = k (s,p,p) 84 | 85 | pthread_equal :: (PIDTyp,PIDTyp,LocalState,PIDTyp, 86 | (LocalState,PIDTyp,CInt) -> Proc) 87 | -> Proc 88 | pthread_equal (PIDUnknown,_,s,p,k) = k (s,p,CIntUnknown) 89 | pthread_equal (_,PIDUnknown,s,p,k) = k (s,p,CIntUnknown) 90 | pthread_equal (PID.x,PID.y,s,p,k) = 91 | k (s,p,if x == y then CIntKnown.1 else CIntKnown.0) 92 | 93 | -- XXX Right now we ignore the parameters argument. Ideally we'd check that 94 | -- it's null, and fail otherwise. That's tricky because the type for this 95 | -- struct is actually generated at runtime. We really need a better story about 96 | -- external dependencies. 97 | -- 98 | -- XXX Right now we imagine that each thread has a completely separate stack 99 | -- address space. Threads can not read from or write to the stack variables of 100 | -- other threads, even if you pass the addresses around, because of the way we 101 | -- represent local state. If we encounter code that stack-allocates variables 102 | -- and then passes their addresses around, it will result in an error in FDR and 103 | -- we'll need to revisit this assumption. 104 | -- 105 | -- pthread_create :: (PIDTypLoc, 106 | -- pthrad_attr_tLoc, 107 | -- ((VoidStar,LocalState,PIDTyp, 108 | -- ((LocalState,PIDType,VoidStar) -> Proc)) -> Proc), 109 | -- VoidStar, 110 | -- LocalState, 111 | -- PIDTyp, 112 | -- (LocalState,PIDTyp,CInt) -> Proc) -> Proc 113 | pthread_create (thread_id_loc, config, to_spawn, arg, 114 | st, pid, k) = 115 | new_pid_c?new_pid -> 116 | pIDTypWriter(st,pid,thread_id_loc,new_pid, 117 | \st',pid',_ @ 118 | ( (to_spawn(arg,emptyLocalState,new_pid,\_,_,_@ SKIP)) 119 | ||| (k (st',pid',CIntKnown.0)))) 120 | -------------------------------------------------------------------------------- /src/CodeGen/C/CFG.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE GADTs #-} 2 | 3 | module CodeGen.C.CFG where 4 | 5 | 6 | {- | 7 | 8 | Module : CodeGen.C.CFG 9 | Description : Control-flow graph for a C-like IR 10 | Copyright : Draper Laboratories 11 | 12 | Author : Chris Casinghino 13 | -} 14 | 15 | import Compiler.Hoopl 16 | 17 | import CodeGen.C.Syntax 18 | import CodeGen.C.Pretty (emitId,emitExp,emitDecln) 19 | import CodeGen.C.CGMonad 20 | 21 | import qualified Language.CSPM.Syntax as T 22 | 23 | import Data.List (intersperse,intercalate) 24 | import qualified Data.Map as M 25 | 26 | -- We're cheating a bit here in the case of IExp and function calls. 27 | -- 28 | -- In C, function calls are a type of expressions, which we've said 29 | -- are "open on exit" here. But function calls are a non-local 30 | -- control transfer, and thus are really "closed on exit". 31 | -- 32 | -- I think that since I'm only interested intraprocedural analysis for 33 | -- now I can basically get away with this. We're basically modelling 34 | -- a function call as a black box that does some stuff and then comes 35 | -- back to the call site. That's not strictly true, but only in the 36 | -- case where a function never returns, which shouldn't mess up any of 37 | -- our analyses. 38 | data Insn e x where 39 | ILabel :: SPos -> Label -> Insn C O 40 | 41 | IExp :: Exp -> Insn O O 42 | IDecl :: Decln -> Insn O O 43 | ICleanup :: Id -> Insn O O 44 | 45 | -- The exit nodes all take an extra [Id] parameter, which indicates a bunch of 46 | -- IDs that need to be cleaned up just before this control-flow transfer (but, 47 | -- crucially, after evaluating any expressions embedded in the exit 48 | -- instruction, which is why we don't just add ICleanup nodes). ICond takes 49 | -- two lists of IDs because the ids that need to be cleaned up may be 50 | -- different by branch. 51 | -- 52 | -- XXX It's quite possible we could get rid of ICleanup all-together and just 53 | -- do cleanup before control-flow transfers without any hit to performance. 54 | -- This would simplify the CFG structure a bit, but I think it would make it 55 | -- harder to implement the liveness analysis with Hoopl. 56 | IGoto :: SPos -> [Id] -> Label -> Insn O C 57 | ICond :: SPos -> [Id] -> [Id] -> Exp -> Label -> Label -> Insn O C 58 | IReturn :: SPos -> [Id] -> Maybe Exp -> Insn O C 59 | 60 | -- Though we don't model most function calls as actual control-flow transfer, 61 | -- it's convenient to have recursive tail calls as a special case because of 62 | -- the way loop detection works in FDR. 63 | ITailCall :: SPos -> [Id] -> [Exp] -> Insn O C 64 | 65 | instance NonLocal Insn where 66 | entryLabel (ILabel _ l) = l 67 | 68 | successors (IGoto _ _ l) = [l] 69 | successors (ICond _ _ _ _ l1 l2) = [l1,l2] 70 | successors (IReturn _ _ _) = [] 71 | successors (ITailCall _ _ _) = [] 72 | 73 | instance Show (Insn e x) where 74 | show (ILabel _ l) = "Label: " ++ show l ++ ";" 75 | 76 | show (IExp e) = emitExp e ++ ";" 77 | show (IDecl d) = emitDecln d 78 | show (ICleanup i) = "" 79 | 80 | show (IGoto _ ids l) = "goto " ++ showIdsNice ids ++ " " ++ show l ++ ";" 81 | show (ICond _ ids1 ids2 e l1 l2) = 82 | "cond " ++ showIdsNice ids1 ++ " " ++ showIdsNice ids2 ++ " (" ++ show e ++ ") " 83 | ++ show l1 ++ " " ++ show l2 ++ ";" 84 | show (IReturn _ ids me) = "return " ++ showIdsNice ids 85 | ++ maybe "" (\e -> " " ++ show e) me ++ ";" 86 | show (ITailCall _ ids args) = "recursiveTailCall " ++ showIdsNice ids ++ " (" 87 | ++ concat (intersperse "," (map show args)) ++ ")" 88 | 89 | -- We allow instructions in the graph to be annotated. Typically, we will chose 90 | -- annotations that result from dataflow analysis to improve the code generation. 91 | data AInsn a e x = AInsn (Insn e x) a 92 | 93 | instance NonLocal (AInsn a) where 94 | entryLabel (AInsn i _) = entryLabel i 95 | 96 | successors (AInsn i _) = successors i 97 | 98 | instance Show a => Show (AInsn a e x) where 99 | show (AInsn i a) = 100 | show i ++ " <" ++ show a ++ ">" 101 | 102 | getInsn :: AInsn a e x -> Insn e x 103 | getInsn (AInsn i _) = i 104 | 105 | getAnnot :: AInsn a e x -> a 106 | getAnnot (AInsn _ a) = a 107 | 108 | 109 | 110 | data Proc a = 111 | Proc {procDecln :: FInfo, 112 | procArgs :: [(Id,BaseType)], 113 | procPos :: SPos, 114 | 115 | procEntry :: Label, 116 | procBody :: Graph (AInsn a) C C, 117 | 118 | procLocations :: M.Map Label T.Id 119 | } 120 | 121 | failProc :: Proc a -> String -> CG b 122 | failProc p msg = 123 | fail $ "Error in translation: " ++ msg ++ ", in function " 124 | ++ (T.namePart $ ftid $ procDecln p) ++ " at " ++ show (procPos p) 125 | 126 | instance Show a => Show (Proc a) where 127 | show (Proc {procDecln=FInfo {ftid,fret},procArgs,procBody}) = 128 | show fret ++ " " ++ show ftid ++ "(" 129 | ++ (concat $ intersperse ", " $ 130 | map (\(argnm,ty) -> show ty ++ " " ++ show argnm) procArgs) 131 | ++ ")\n" ++ showGraph show procBody ++ "\n\n" 132 | 133 | -- XXX This is probably reallllly inefficient, but I couldn't find a better way to 134 | -- do it with what's available in the Hoopl library. 135 | mapProc :: (Block (AInsn a) C C -> Block (AInsn b) C C) 136 | -> Proc a -> Proc b 137 | mapProc f p@(Proc {procBody,procEntry}) = p {procBody = body'} 138 | where 139 | blocks = case procBody of 140 | GMany NothingO body NothingO -> 141 | postorder_dfs_from body procEntry 142 | 143 | body' = bodyGraph $ mapFromList $ map (\b -> (entryLabel b,f b)) blocks 144 | 145 | showIdsNice :: [Id] -> String 146 | showIdsNice ids = "[" ++ (intercalate "," $ map emitId ids) ++ "]" 147 | -------------------------------------------------------------------------------- /src/CodeGen/C/CFGEmptyBlocks.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE RankNTypes #-} 2 | {- | 3 | 4 | Module : CodeGen.C.ReduceLabels 5 | Description : Remove redudant labels from the CFG 6 | Copyright : Draper Laboratories 7 | 8 | Author : Chinedu Okongwu 9 | 10 | This module eliminates certain unnecessary blocks from the control flow graph. 11 | In particular, because of the way the graph is generated, it includes many 12 | blocks of the form: 13 | 14 | Label1: 15 | goto Label2 16 | 17 | This block can be eliminated if we change any jump to Label1 with a jump to 18 | Label2, which is what this module does. 19 | -} 20 | 21 | module CodeGen.C.CFGEmptyBlocks (eliminateEmptyBlocks) where 22 | 23 | -- We use Hoopl's graph representation 24 | import Compiler.Hoopl 25 | 26 | -- source and target 27 | import qualified CodeGen.C.CFG as T 28 | 29 | import CodeGen.C.CFGPointsTo 30 | 31 | import qualified Data.Map as M 32 | import Data.Maybe (fromMaybe) 33 | 34 | 35 | -- This function removes any potentially redundant label blocks and label 36 | -- from the list of Proc PTFacts objects. 37 | -- 38 | -- The general way this works is by checking each instruction in each block to 39 | -- see if it contains a conditional jump to instruction or a GoTo 40 | -- instruction. If so, the forward referenced label is checked to see if it 41 | -- refers to a block with an empty body and GoTo instruction as its exit. If 42 | -- this is also the case, the original forward referencing label is replaced 43 | -- with the destination label of this GoTo instruction. In order to maintain the 44 | -- integrity of the Proc PTFact, the entry label is also checked and potentially 45 | -- modified to ensure that it does not also refer to a redundant block. 46 | eliminateEmptyBlocks :: T.Proc PTFacts -> T.Proc PTFacts 47 | eliminateEmptyBlocks p@(T.Proc {T.procBody=body,T.procEntry=entry}) = 48 | p {T.procBody=newBody, T.procEntry=newEntry} 49 | where 50 | newEntry :: Label 51 | newBody :: Graph (T.AInsn PTFacts) C C 52 | (newEntry, newBody) = cleanProc entry body 53 | 54 | -- Pulls apart the Proc into a list of labelled blocks, cleans that up, and 55 | -- packages the result back up into a Proc. 56 | cleanProc :: Label -> Graph (T.AInsn PTFacts) C C 57 | -> (Label,Graph (T.AInsn PTFacts) C C) 58 | cleanProc l (GMany NothingO body NothingO) = 59 | (getLabel l realLabels, GMany NothingO cleanedBody NothingO) 60 | where 61 | realLabels :: M.Map Label Label 62 | realLabels = buildLabelMap body 63 | 64 | relabelledBody :: Body (T.AInsn PTFacts) 65 | relabelledBody = cleanBody realLabels body 66 | 67 | cleanedBody :: Body (T.AInsn PTFacts) 68 | cleanedBody = shrinkBody realLabels relabelledBody 69 | 70 | 71 | -- Replaces jump target labels in each block in the body according to the 72 | -- supplied map. 73 | cleanBody :: M.Map Label Label 74 | -> Body (T.AInsn PTFacts) 75 | -> Body (T.AInsn PTFacts) 76 | cleanBody labels body = mapMap (cleanBlock labels) body 77 | 78 | -- Replaces jump target labels in each instruction in the block according to the 79 | -- supplied map. We only need to change the exit node, since it's the only one 80 | -- that can jump. 81 | cleanBlock :: M.Map Label Label 82 | -> Block (T.AInsn PTFacts) C C 83 | -> Block (T.AInsn PTFacts) C C 84 | cleanBlock labels block = blockJoin bEntry bBody (cleanAInsn labels bExit) 85 | where 86 | bEntry :: T.AInsn PTFacts C O 87 | bBody :: Block (T.AInsn PTFacts) O O 88 | bExit :: T.AInsn PTFacts O C 89 | (bEntry,bBody,bExit) = blockSplit block 90 | 91 | -- Replaces any jump target in the instruction according to the supplied map. 92 | cleanAInsn :: M.Map Label Label 93 | -> T.AInsn PTFacts O C 94 | -> T.AInsn PTFacts O C 95 | cleanAInsn labels (T.AInsn i ptf) = T.AInsn (cleanInsn i) ptf 96 | where 97 | cleanInsn :: T.Insn O C -> T.Insn O C 98 | cleanInsn (T.IGoto s ids l) = T.IGoto s ids (getLabel l labels) 99 | cleanInsn (T.ICond s ids1 ids2 e l1 l2) = 100 | T.ICond s ids1 ids2 e (getLabel l1 labels) (getLabel l2 labels) 101 | cleanInsn p@(T.IReturn _ _ _) = p 102 | cleanInsn p@(T.ITailCall _ _ _) = p 103 | 104 | -- Creates a map from each label to the label we'd like to replace it with, 105 | -- possibly itself. For example, for the blocks: 106 | -- 107 | -- L1: 108 | -- Goto L2; 109 | -- L2: 110 | -- Goto L3; 111 | -- L3: 112 | -- 113 | -- return; 114 | -- 115 | -- We create the map <(L1,L3),(L2,L3),(L3,L3)>, since we're going to remove the 116 | -- L1 and L2 blocks from the program and anybody who used to jump to those 117 | -- labels should now jump to L3. 118 | buildLabelMap :: LabelMap (Block (T.AInsn PTFacts) C C) -> M.Map Label Label 119 | buildLabelMap block = M.fromList $ map (\l -> (l, chaseLabel l block)) 120 | (mapKeys block) 121 | 122 | -- Takes a label l and find the "real" corresponding label (i.e., the label of 123 | -- the first block that (a) will be jumped to after jumping to l and (b) 124 | -- actually does something). 125 | chaseLabel :: Label -> LabelMap (Block (T.AInsn PTFacts) C C) -> Label 126 | chaseLabel l lbs = chase l 127 | where 128 | -- This does the main work of chaseLabel. The only sublety is that we must 129 | -- check if "isEmptyGoto" returns the original label l, so that we don't 130 | -- enter an infinite loop in the case of divergent C code. In this corner 131 | -- case, we leave the whole loop alone - it would be cleaner (but more 132 | -- complicated) to reduce it to a single label. 133 | chase :: Label -> Label 134 | chase l' = 135 | case mapLookup l' lbs >>= isEmptyGoto of 136 | Nothing -> l' 137 | Just l'' | l'' == l -> l 138 | Just l'' | otherwise -> chase l'' 139 | 140 | -- Checks to see if the input block has an empty body and a goto instruction as 141 | -- an exit. If so, the jump to label is returned. 142 | isEmptyGoto :: Block (T.AInsn PTFacts) C C -> Maybe Label 143 | isEmptyGoto block = if isEmptyBlock blockBody then gotoLabel else Nothing 144 | where 145 | blockBody :: Block (T.AInsn PTFacts) O O 146 | blockExit :: T.AInsn PTFacts O C 147 | (_, blockBody, blockExit) = blockSplit block 148 | 149 | gotoLabel :: Maybe Label 150 | gotoLabel = 151 | case blockExit of 152 | T.AInsn (T.IGoto _ _ l) _ -> Just l 153 | _ -> Nothing 154 | 155 | -- Checks the given map for a label that has the input label as its key. 156 | -- It then returns either the input label or the found label value. 157 | getLabel :: Label -> M.Map Label Label -> Label 158 | getLabel l m = fromMaybe l (M.lookup l m) 159 | 160 | 161 | -- Eliminates empty blocks from the body. Note that not _every_ empty block can 162 | -- be removed because we leave in empty blocks that are part of an infinite loop 163 | -- to avoid changing the semantics. So, instead, we remove any blocks whose 164 | -- label is no longer used (according to the label map). 165 | shrinkBody :: M.Map Label Label 166 | -> Body (T.AInsn PTFacts) 167 | -> Body (T.AInsn PTFacts) 168 | shrinkBody labels body = mapFilter shrinkCheck body 169 | where 170 | shrinkCheck :: Block (T.AInsn PTFacts) C C -> Bool 171 | shrinkCheck b = let label = entryLabel b in 172 | label == getLabel label labels 173 | 174 | -------------------------------------------------------------------------------- /src/CodeGen/C/CFGPretty.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE RankNTypes #-} 2 | {- | 3 | Module : CFGPretty 4 | Description : Pretty Printing for the CFGs generated using ASTtoCFG 5 | Copyright : Draper Laboratories 6 | 7 | Author : Chinedu Okongwu 8 | 9 | This generates a string which should be suitable as input for the cspgen code generator 10 | -} 11 | module CodeGen.C.CFGPretty (ppCFG) where 12 | 13 | import Compiler.Hoopl 14 | 15 | import CodeGen.C.CFG 16 | import CodeGen.C.Pretty 17 | import CodeGen.C.CGMonad 18 | import CodeGen.C.CFGPointsTo 19 | 20 | import qualified Language.CSPM.Syntax as T 21 | 22 | import Data.List (intersperse) 23 | 24 | 25 | ppCFG :: [Proc PTFacts] -> String 26 | ppCFG x = concat $ map printProc x 27 | 28 | printProc :: Proc PTFacts -> String 29 | printProc (Proc {procDecln=FInfo {ftid,fret},procArgs,procBody}) = 30 | ppBaseType fret ++ " " ++ pprintId ftid ++ "(" 31 | ++ (concat $ intersperse ", " $ 32 | map (\(argnm,ty) -> ppBaseType ty ++ " " ++ emitId argnm) procArgs) 33 | ++ ")\n" ++ ppProcBody procBody ++ "\n\n" 34 | 35 | 36 | pprintId :: T.Id -> String 37 | pprintId (T.Id (x,_)) = show x 38 | pprintId (T.Fixed x) = show x 39 | 40 | -- GNil and GUnit constructors make graphs that are open at entry and exit. 41 | -- No need to worry about pattern matching those because the type of procbody 42 | -- is closed at both entry and exit 43 | ppProcBody :: Graph (AInsn PTFacts) C C -> String 44 | ppProcBody pbody = g pbody 45 | where g :: Graph (AInsn PTFacts) e x -> String 46 | g GNil = "" 47 | g (GUnit block) = b block 48 | g (GMany g_entry g_blocks g_exit) = 49 | open b g_entry ++ body g_blocks ++ open b g_exit 50 | 51 | body :: Body (AInsn PTFacts) -> String 52 | body blocks = concatMap b (mapElems blocks) 53 | 54 | b :: forall e x . Block (AInsn PTFacts) e x -> String 55 | b (BlockCO l b1) = ppAInsn l ++ "\n" ++ b b1 56 | b (BlockCC l b1 n) = ppAInsn l ++ "\n" ++ b b1 ++ ppAInsn n ++ "\n" 57 | b (BlockOC b1 n) = b b1 ++ ppAInsn n ++ "\n" 58 | b (BNil) = "" 59 | b (BMiddle n) = ppAInsn n ++ "\n" 60 | b (BCat b1 b2) = b b1 ++ b b2 61 | b (BSnoc b1 n) = b b1 ++ ppAInsn n ++ "\n" 62 | b (BCons n b1) = ppAInsn n ++ "\n" ++ b b1 63 | 64 | ppAInsn :: AInsn PTFacts e x -> String 65 | ppAInsn (AInsn i ptf) = ppInsn i ++ " <" ++ ppPTFacts ptf ++ ">" 66 | 67 | ppInsn :: Insn e x -> String 68 | ppInsn (ILabel _ l) = "Label: " ++ show l ++ ";" 69 | ppInsn (IExp e) = emitExp e ++ ";" 70 | ppInsn (IDecl d) = emitDecln d 71 | ppInsn (ICleanup i) = "" 72 | 73 | ppInsn (IGoto _ ids l) = "goto " ++ showIdsNice ids ++ " " ++ show l ++ ";" 74 | ppInsn (ICond _ ids1 ids2 e l1 l2) = 75 | "cond " ++ showIdsNice ids1 ++ " " ++ showIdsNice ids2 ++ " (" ++ emitExp e ++ ") " 76 | ++ show l1 ++ " " ++ show l2 ++ ";" 77 | ppInsn (IReturn _ ids me) = "return " ++ showIdsNice ids 78 | ++ maybe "" (\e -> " " ++ emitExp e) me ++ ";" 79 | ppInsn (ITailCall _ ids args) = "recursiveTailCall " ++ showIdsNice ids ++ " (" 80 | ++ concat (intersperse "," (map show args)) ++ ")" 81 | 82 | open :: (a -> String) -> MaybeO z a -> String 83 | open _ NothingO = "" 84 | open p (JustO n) = p n 85 | -------------------------------------------------------------------------------- /src/CodeGen/C/DriverC.hs: -------------------------------------------------------------------------------- 1 | module CodeGen.C.DriverC where 2 | 3 | import CodeGen.C.Parser (cppParseSanity) 4 | import qualified Language.CSPM.Pretty as Pretty 5 | import CodeGen.C.CodeGen 6 | import qualified CodeGen.C.Pretty as CPretty 7 | import qualified CodeGen.C.CFGPretty as GPretty 8 | import CodeGen.C.CFGLiveness (Mode(..)) 9 | import CodeGen.C.ASTtoCFG (cfgTransUnit) 10 | import CodeGen.C.CGMonad 11 | import CodeGen.Driver 12 | 13 | import CodeGen.C.SimplifyLoop (sLoopTransUnit) 14 | import CodeGen.C.SimplifyLValues (sLValTransUnit) 15 | import CodeGen.C.SimplifyReferences (sRefTransUnit) 16 | 17 | import CodeGen.C.HedgeTrimmer 18 | 19 | import CodeGen.C.Externals (getExternals,ExternalsInfo(..)) 20 | 21 | import Data.List (intercalate) 22 | import qualified Data.Map as M 23 | 24 | -- only needed for send/recv hack 25 | import qualified Language.CSPM.Syntax as T 26 | import qualified CodeGen.C.Syntax as S 27 | import qualified Language.C as C 28 | 29 | import Control.Monad.Except 30 | 31 | genCodeE :: DriverInput -> DriverM Output 32 | genCodeE di@(DriverInput {diFilename,diIntermediate,diExternals, 33 | diInputList,diWarn}) = do 34 | liftIO $ do 35 | putStrLn $ "Translating " ++ diFilename ++ " to CSPm." 36 | putStrLn $ "Step 1: Parsing..." 37 | ExternalsInfo{funcInfo=externalDefs,minInt,maxInt} <- getExternals diExternals 38 | let externalCNames = map (\(nm,_,_) -> C.builtinIdent nm) externalDefs 39 | (sids,code) <- cppParseSanity di externalCNames 40 | liftIO $ do 41 | putStrLn $ " Parsing successful (" ++ show (ltu code) 42 | ++ " top-level declarations)" 43 | when diIntermediate $ 44 | writeFile (diFilename ++ ".step1" ) (CPretty.emitTransUnit code) 45 | putStrLn "Step 2: Trimming the hedges..." 46 | let trimmedCode = trim (diFilename:diInputList) code 47 | liftIO $ do 48 | putStrLn $ " Trimming succesful (" ++ show (ltu trimmedCode) 49 | ++ " top-level declarations remain)" 50 | putStrLn "Step 3: Generating CSP..." 51 | when diIntermediate $ 52 | writeFile (diFilename ++ ".step2") (CPretty.emitTransUnit trimmedCode) 53 | let 54 | -- Initial CG context, computed from parsed external definitions config 55 | -- file and the corresponding identifiers. 56 | externalFInfos :: [(S.Id,FInfo)] 57 | externalFInfos = zip sids $ map externalFInfo externalDefs 58 | where 59 | externalFInfo :: (String,[Mode],BaseType) -> FInfo 60 | externalFInfo (nm,modes,fret) = 61 | FInfo {ftid = T.Fixed nm, 62 | fret, 63 | fargs = map (\_ -> UnknownType internal) modes, 64 | fvararg = False, 65 | fdef = True} 66 | 67 | state = initState (minInt,maxInt) externalFInfos 68 | 69 | -- A list of the preprocessing stuff we run directly on the C AST. 70 | -- The must be applied from left to right. 71 | simplifications = [sRefTransUnit,sLoopTransUnit,sLValTransUnit] 72 | 73 | -- A list with the itermediate steps to print via command option -i 74 | simplifiedCode :: S.TransUnit 75 | steps :: [S.TransUnit] 76 | (simplifiedCode,steps) = 77 | foldl (\(curCode,acc) opt -> (opt curCode, curCode : acc)) 78 | (trimmedCode,[]) simplifications 79 | 80 | when diIntermediate $ liftIO $ do 81 | let codeString = map (CPretty.emitTransUnit) steps 82 | writeTUFiles diFilename codeString 83 | 84 | let 85 | -- the argument modes of the external functions from the config file 86 | modes :: M.Map S.Id [Mode] 87 | modes = M.fromList $ 88 | map (\(fsid,(_,mode,_)) -> (fsid,mode)) 89 | (zip sids externalDefs) 90 | 91 | 92 | cfgAndCsp :: CG (String, CspModules) 93 | cfgAndCsp = do cfg <- cfgTransUnit modes simplifiedCode 94 | (GPretty.ppCFG cfg,) <$> transGen cfg 95 | 96 | ((cfgString,CspModules {cmGlobalState,cmStubs,cmCode}),cgWarnings) <- 97 | case runCG state cfgAndCsp of 98 | (Left err,_) -> 99 | -- XXX in this case we discard the warnings. It would be nice to show 100 | -- them. 101 | throwError ("Compilation Error:\n" ++ err) 102 | (Right val,w) -> return (val,w) 103 | liftIO $ do 104 | when diIntermediate $ 105 | writeFile (diFilename ++ ".step" ++ cfgStepNum steps) cfgString 106 | putStrLn " Code generation successful." 107 | when diWarn $ putStrLn $ intercalate "\n" $ map show cgWarnings 108 | 109 | modules <- 110 | case cmStubs of 111 | Nothing -> return [cmGlobalState,cmCode] 112 | Just stubMod -> do 113 | liftIO $ putStrLn $ 114 | "Warning: " ++ show (length $ T.topLevels stubMod) 115 | ++ " functions were " 116 | ++ "declared but not defined. Stubs for these functions " 117 | ++ "will be included in the generated CSP." 118 | return [cmGlobalState,stubMod,cmCode] 119 | 120 | let (txt,warns) = Pretty.emitMods modules 121 | when (not $ null warns) $ liftIO $ do 122 | putStrLn "The pretty printer warns that:" 123 | mapM_ putStrLn warns 124 | case txt of 125 | (gtxt:codetxt:[]) -> 126 | return $ 127 | Output {memModel = gtxt, 128 | stubs = Nothing, 129 | code = codetxt} 130 | (gtxt:stubtxt:codetxt:[]) -> 131 | return 132 | Output {memModel = gtxt, 133 | stubs = Just stubtxt, 134 | code = codetxt} 135 | _ -> error "Internal Error: emitMods returned incorrect number of modules." 136 | where 137 | writeTUFiles :: String -> [String] -> IO () 138 | writeTUFiles fname tu = 139 | mapM_ (\(x,y) -> writeFile (fname ++ ".step" ++ show y) x) 140 | (zip tu ([3..] :: [Int])) 141 | 142 | cfgStepNum :: [a] -> String 143 | cfgStepNum x = show $ 3 + (length x) 144 | 145 | ltu :: S.TransUnit -> Int 146 | ltu = length . S.exts 147 | 148 | genCSP :: Driver 149 | genCSP = Driver genCodeE 150 | 151 | -- TODO: change (Maybe String, String) to a built-in type 152 | genAST :: Driver 153 | genAST = Driver $ \di -> do 154 | (_,code) <- cppParseSanity di [] 155 | return $ 156 | Output {memModel = "", 157 | stubs = Nothing, 158 | code = show code} 159 | 160 | genCPretty :: Driver 161 | genCPretty = Driver $ \di -> do 162 | (_,code) <- cppParseSanity di [] 163 | return $ 164 | Output {memModel = "", 165 | stubs = Nothing, 166 | code = CPretty.emitTransUnit code} 167 | -------------------------------------------------------------------------------- /src/CodeGen/C/Externals.hs: -------------------------------------------------------------------------------- 1 | {- | 2 | Module : CodeGen.C.Externals 3 | Description : Parser for external function specs 4 | Copyright : Draper Laboratories 5 | 6 | This parses configuration files for cspgen. The files have two sections and may 7 | contain comments in Haskell style. The high-level format is: 8 | 9 | @section FUNCTIONS { 10 | 11 | 12 | 13 | } 14 | 15 | @section SETTINGS { 16 | 17 | 18 | 19 | } 20 | 21 | ----- 22 | 23 | The FUNCTIONS section contains a list of functions which are used in the C code 24 | but whose implementations are expected to be provided by the cspgen runtime. 25 | The format for these files is a list of declarations of the form: 26 | 27 | @ 28 | returnType name(argMode_1,...,argMode_n); 29 | @ 30 | 31 | Here, @returnType@ is the return type of the function (currently the grammar for 32 | these is quite limited). @name@ is the function's name, which must match both 33 | the name used in the C code and the name in the csp runtime. The function must 34 | have @n@ arguments, and @argMode@ is defined by: 35 | 36 | @ 37 | argMode ::= in | out | inout 38 | @ 39 | 40 | This specifies the mode of the argument. "@in@" indicates a normal argument 41 | used as an input to the function. "@out@" indicates an "output" argument, for 42 | example when a pointer is passed to a function as a location to write some data 43 | to. "@inout@" is an argument that is read from and then written to. This 44 | information is necessary for the control flow analysis done by cspgen. 45 | 46 | ----- 47 | 48 | The SETTINGS section contains a list of options and the values assigned to them. 49 | The format is a list of declarations of the form: 50 | 51 | settingName = value; 52 | 53 | Currently the only "settingName"s supported are "minimumCVal" and "maximumCVal". 54 | The value must be an integer. 55 | 56 | ----- 57 | 58 | XXX One flaw in the current system is that types are not supported very well. 59 | We only handle a few basic return types to avoid needing a full C parser here, 60 | and we don't handle argument types at all. 61 | 62 | 63 | -} 64 | 65 | module CodeGen.C.Externals (getExternals,ExternalsInfo(..)) where 66 | 67 | import Text.Parsec 68 | import Text.Parsec.Token 69 | import Text.Parsec.Language (haskellStyle) 70 | 71 | import Control.Monad.Except 72 | 73 | import System.Directory (doesFileExist) 74 | 75 | import CodeGen.C.CFGLiveness (Mode(..)) 76 | import CodeGen.C.CGMonad (BaseType(..)) 77 | import qualified CodeGen.C.Syntax as S (SPos(..)) 78 | 79 | -- holds nput from parser 80 | data Setting = MinInt Int | MaxInt Int | NoValue 81 | 82 | -- holds output 83 | data ExternalsInfo = 84 | ExternalsInfo { 85 | funcInfo :: [(String,[Mode],BaseType)], 86 | minInt :: Int, 87 | maxInt :: Int 88 | } 89 | 90 | defaultExternalsInfo :: ExternalsInfo 91 | defaultExternalsInfo = 92 | ExternalsInfo { 93 | funcInfo = [], 94 | minInt = 0, 95 | maxInt = 4 96 | } 97 | 98 | -- Setting up tokenizer 99 | externalsStyle :: LanguageDef st 100 | externalsStyle = haskellStyle {reservedNames = ["in","out","inout", 101 | "void","int","bool","pid", 102 | "minimumCVal","maximumCVal"], 103 | reservedOpNames = ["=", "section"]} 104 | 105 | exCommaSep :: Parsec String u a -> Parsec String u [a] 106 | exIdentifier :: Parsec String u String 107 | exParens :: Parsec String u a -> Parsec String u a 108 | exReserved :: String -> Parsec String u () 109 | exReservedOp :: String -> Parsec String u () 110 | exWhiteSpace :: Parsec String u () 111 | exSemi :: Parsec String u String 112 | exInteger :: Parsec String u Integer 113 | exBraces :: Parsec String u a -> Parsec String u a 114 | exSymbol :: String -> Parsec String u String 115 | TokenParser {commaSep = exCommaSep, 116 | reserved = exReserved, 117 | reservedOp = exReservedOp, 118 | identifier = exIdentifier, 119 | parens = exParens, 120 | whiteSpace = exWhiteSpace, 121 | semi = exSemi, 122 | integer = exInteger, 123 | braces = exBraces, 124 | symbol = exSymbol} 125 | = makeTokenParser externalsStyle 126 | 127 | getPos :: Monad m => ParsecT s u m S.SPos 128 | getPos = do 129 | sourcePos <- getPosition 130 | return $ S.SPos {S.sourceName = sourceName sourcePos, 131 | S.sourceLine = sourceLine sourcePos, 132 | S.sourceColumn = sourceColumn sourcePos} 133 | 134 | ------------------------------------- 135 | --- FUNCTIONS section parsing 136 | ------------------------------------- 137 | 138 | -- Parsec parser definitions 139 | typeParser :: Parsec String () BaseType 140 | typeParser = do 141 | pos <- getPos 142 | choice $ typeParsers pos 143 | where 144 | types :: [(String,S.SPos -> BaseType)] 145 | types = [("int",IntType), 146 | ("bool",BoolType), 147 | ("void",UnknownType), 148 | ("pid",PIDType) 149 | ] 150 | 151 | typeParsers :: S.SPos -> [Parsec String () BaseType] 152 | typeParsers pos = map (\(s,t) -> exReserved s >> return (t pos)) 153 | types 154 | 155 | modeParser :: Parsec String () Mode 156 | modeParser = 157 | (exReserved "in" >> return MInput) 158 | <|> (exReserved "out" >> return MOutput) 159 | <|> (exReserved "inout" >> return MUnknown) 160 | 161 | externalFuncParser :: Parsec String () (String,[Mode],BaseType) 162 | externalFuncParser = do 163 | eType <- typeParser 164 | eName <- exIdentifier 165 | eModes <- exParens $ exCommaSep modeParser 166 | return (eName,eModes,eType) 167 | 168 | 169 | ------------------------------------- 170 | --- SETTINGS section parsing 171 | ------------------------------------- 172 | 173 | settingNameParser :: String -> Parsec String () String 174 | settingNameParser name = do 175 | exReserved name 176 | return name 177 | 178 | externalSettingParser :: Parsec String () Setting 179 | externalSettingParser = do 180 | eName <- settingNameParser "minimumCVal" <|> settingNameParser "maximumCVal" 181 | exReservedOp "=" 182 | eValue <- exInteger 183 | let setting = case eName of 184 | "minimumCVal" -> MinInt (min (fromInteger eValue) 0) 185 | "maximumCVal" -> MaxInt (max (fromInteger eValue) 1) 186 | _ -> NoValue 187 | return setting 188 | 189 | 190 | -- Updates the provided ExternalsInfo with any explicit settings that appeared 191 | -- in the configuation file. 192 | settingsExtractor :: ExternalsInfo -> [Setting] -> ExternalsInfo 193 | settingsExtractor = foldr handleSetting 194 | where 195 | handleSetting :: Setting -> ExternalsInfo -> ExternalsInfo 196 | handleSetting NoValue ei = ei 197 | handleSetting (MinInt val) ei = ei {minInt=val} 198 | handleSetting (MaxInt val) ei = ei {maxInt=val} 199 | 200 | 201 | ----------------------------------- 202 | ---- Top level parser and interface 203 | ----------------------------------- 204 | 205 | missingExternalWarning :: String -> String 206 | missingExternalWarning fname = 207 | "Warning: \"" ++ fname ++ "\" not found. Proceeding with " 208 | ++ "no external functions." 209 | 210 | sectionParser :: String -> Parsec String () a -> Parsec String () [a] 211 | sectionParser name p = do 212 | _ <- exSymbol "@section" 213 | _ <- exSymbol name 214 | info <- exBraces $ sepEndBy p exSemi 215 | return info 216 | 217 | externalsParser :: Parsec String () ExternalsInfo 218 | externalsParser = do 219 | exWhiteSpace 220 | externals <- sectionParser "FUNCTIONS" externalFuncParser 221 | values <- sectionParser "SETTINGS" externalSettingParser 222 | optional exWhiteSpace 223 | eof 224 | let ei = settingsExtractor (defaultExternalsInfo {funcInfo=externals}) 225 | values 226 | return ei 227 | 228 | 229 | getExternals :: (MonadError String m, MonadIO m) => FilePath -> m ExternalsInfo 230 | getExternals fileName = do 231 | externalsExists <- liftIO $ doesFileExist fileName 232 | if externalsExists then do 233 | cfgFileContents <- liftIO $ readFile fileName 234 | let result = parse externalsParser fileName cfgFileContents 235 | case result of 236 | Left parseError -> throwError $ show parseError 237 | Right externals -> return externals 238 | else do 239 | liftIO $ putStrLn $ missingExternalWarning fileName 240 | return defaultExternalsInfo 241 | -------------------------------------------------------------------------------- /src/CodeGen/C/Parser.hs: -------------------------------------------------------------------------------- 1 | {-# OPTIONS_GHC -fno-warn-missing-signatures #-} 2 | {- necessary due to a bug in this version of GHC -} 3 | 4 | {- | 5 | Module : CodeGen.C.Parser 6 | Description : Parser for C-flat 7 | Copyright : Draper Laboratories 8 | 9 | Author : Chris Casinghino 10 | 11 | This parses and sanity-checks C files. We use the Language.C haskell library 12 | for the parsing, then we translate the resulting AST into a simpler internal 13 | AST, throwing an error if we encounter syntactic forms we don't handle. 14 | 15 | -} 16 | 17 | module CodeGen.C.Parser (cppParseSanity) where 18 | 19 | import Language.C.Parser 20 | import Language.C.Data.Position 21 | 22 | import qualified Data.ByteString as B 23 | import Data.List (intercalate) 24 | 25 | import qualified Language.C as S 26 | import qualified CodeGen.C.Syntax as T 27 | import CodeGen.C.SyntaxSimplifier (simplifyTranslUnit,SimplResult(..)) 28 | import CodeGen.Driver (DriverInput(..)) 29 | 30 | import System.Process 31 | import System.Exit (ExitCode(..)) 32 | import System.FilePath 33 | 34 | import Control.Monad.Except 35 | 36 | 37 | cLangParser :: MonadError String m => B.ByteString -> Position -> m S.CTranslUnit 38 | cLangParser contents pos = 39 | case parseC contents pos of 40 | Left perr -> throwError $ show perr 41 | Right ctu -> return ctu 42 | 43 | data InputError = CPPError | CParseError String | SanityError String 44 | 45 | instance Show InputError where 46 | show CPPError = "Error during preprocessing" 47 | show (CParseError s) = "Error during parsing: " ++ s 48 | show (SanityError s) = "Error while sanity-checking the parsed code: " ++ s 49 | 50 | -- Does all three phases 51 | cppParseSanity :: (MonadError String m, MonadIO m) => 52 | DriverInput -> [S.Ident] -> m ([T.Id],T.TransUnit) 53 | cppParseSanity (DriverInput {diFilename,diCPPOpts,diWarn}) lib = do 54 | let tempfile = "/tmp/" ++ takeFileName diFilename ++ ".cpp" 55 | args = [diCPPOpts,"-w","-o " ++ tempfile, diFilename] 56 | cppECode <- liftIO $ system ("cpp " ++ intercalate " " args) 57 | case cppECode of 58 | ExitSuccess -> do 59 | preprocessedC <- liftIO $ B.readFile tempfile 60 | cAST <- cLangParser preprocessedC (initPos diFilename) 61 | case simplifyTranslUnit cAST lib of 62 | Left err -> throwError $ show $ SanityError err 63 | Right (SR {srWarnings,srResult,srLibIds}) -> do 64 | when diWarn $ liftIO $ mapM_ putStrLn srWarnings 65 | return (srLibIds,srResult) 66 | _ -> throwError $ "Error during preprocessing" 67 | -------------------------------------------------------------------------------- /src/CodeGen/C/SimplifyLValues.hs: -------------------------------------------------------------------------------- 1 | module CodeGen.C.SimplifyLValues (sLValTransUnit) where 2 | 3 | {- | 4 | Module : CodeGen.C.LValues 5 | Description : C Simplifier - clean up lvalues 6 | Copyright : Draper Laboratories 7 | 8 | Author : Chris Casinghino 9 | 10 | This module implements a simple translation on our C AST. 11 | 1) Expression of the form e -> l are translated to (*e).l 12 | 2) Expressions of the form *&e are translated to e 13 | 14 | -} 15 | 16 | import CodeGen.C.Syntax 17 | 18 | sLValExp :: Exp -> Exp 19 | sLValExp (CommaExp es sp) = CommaExp (map sLValExp es) sp 20 | sLValExp e@(IdExp _ _) = e 21 | sLValExp e@(ConstExp _ _) = e 22 | sLValExp (AssignExp aop e1 e2 sp) = AssignExp aop (sLValExp e1) 23 | (sLValExp e2) sp 24 | sLValExp (Subscript e1 e2 sp) = Subscript (sLValExp e1) (sLValExp e2) sp 25 | sLValExp (FunCall e es sp) = FunCall (sLValExp e) (map sLValExp es) sp 26 | sLValExp (CompSel e sop nm sp) = 27 | case sop of 28 | IndirSel -> CompSel (sLValExp $ Unary Indirection e sp) DirSel nm sp 29 | DirSel -> CompSel (sLValExp e) sop nm sp 30 | 31 | sLValExp (Unary uop e sp) = 32 | case uop of 33 | Indirection -> 34 | case e of 35 | Unary Address e' _ -> sLValExp e' 36 | _ -> normalCase 37 | _ -> normalCase 38 | where 39 | normalCase = Unary uop (sLValExp e) sp 40 | sLValExp (Bin bop e1 e2 sp) = Bin bop (sLValExp e1) (sLValExp e2) sp 41 | sLValExp (SizeOfExp e1 sp) = SizeOfExp (sLValExp e1) sp 42 | sLValExp e@(SizeOfTy _ _) = e 43 | sLValExp (Cast t e sp) = Cast t (sLValExp e) sp 44 | sLValExp (Cond e1 me2 e3 sp) = Cond (sLValExp e1) (fmap sLValExp me2) 45 | (sLValExp e3) sp 46 | 47 | sLValInit :: Initializer -> Initializer 48 | sLValInit (SimpleInitializer e) = SimpleInitializer (sLValExp e) 49 | sLValInit (ListInitializer is) = 50 | ListInitializer $ map (\(ds,i) -> (map sLValDesig ds, sLValInit i)) is 51 | where 52 | sLValDesig :: InitDesignator -> InitDesignator 53 | sLValDesig (ArrDesig e sp) = ArrDesig (sLValExp e) sp 54 | sLValDesig d@(MemberDesig _ _) = d 55 | 56 | sLValStmt :: Statement -> Statement 57 | sLValStmt (Compound eds sp) = Compound (map sLValDeclStmt eds) sp 58 | where 59 | sLValDeclStmt :: Either Decln Statement -> Either Decln Statement 60 | sLValDeclStmt (Left d) = Left $ sLValDecln d 61 | sLValDeclStmt (Right s) = Right $ sLValStmt s 62 | sLValStmt (IfStm e s1 s2 sp) = IfStm (sLValExp e) (sLValStmt s1) 63 | (fmap sLValStmt s2) sp 64 | sLValStmt (Switch e s sp) = Switch (sLValExp e) (sLValStmt s) sp 65 | sLValStmt (ExpStm e sp) = ExpStm (fmap sLValExp e) sp 66 | sLValStmt (Case e s sp) = Case (sLValExp e) (sLValStmt s) sp 67 | sLValStmt (Default s sp) = Default (sLValStmt s) sp 68 | sLValStmt st@(Continue _) = st 69 | sLValStmt st@(Goto _ _) = st 70 | sLValStmt st@(Asm _) = st 71 | sLValStmt (While e s sp) = While (sLValExp e) (sLValStmt s) sp 72 | sLValStmt (DoWhile s e sp) = DoWhile (sLValStmt s) (sLValExp e) sp 73 | sLValStmt (For de1 me2 me3 s sp) = For de1' me2' me3' s' sp 74 | where 75 | de1' = case de1 of 76 | Left ds -> Left $ map sLValDecln ds 77 | Right me -> Right $ fmap sLValExp me 78 | 79 | me2' = fmap sLValExp me2 80 | me3' = fmap sLValExp me3 81 | s' = sLValStmt s 82 | sLValStmt (Labelled nm s sp) = Labelled nm (sLValStmt s) sp 83 | sLValStmt (Return e sp) = Return (fmap sLValExp e) sp 84 | sLValStmt st@(Break _) = st 85 | 86 | sLValDecln :: Decln -> Decln 87 | sLValDecln (VarDecln vd sp) = VarDecln (vd {vdInit = fmap sLValInit $ vdInit vd}) 88 | sp 89 | sLValDecln d@(FunDecln _ _) = d 90 | sLValDecln d@(TyDef _ _ _) = d 91 | sLValDecln d@(StructDecln _ _) = d 92 | sLValDecln d@(UnionDecln _ _) = d 93 | sLValDecln d@(EnumDecln _ _) = d 94 | 95 | sLValFunDef :: FunDef -> FunDef 96 | sLValFunDef fd = fd {funBody = sLValStmt (funBody fd)} 97 | 98 | sLValExternalDecln :: ExternalDecln -> ExternalDecln 99 | sLValExternalDecln (ExtFunDef fdef) = ExtFunDef (sLValFunDef fdef) 100 | sLValExternalDecln (ExtDecln dcl) = ExtDecln (sLValDecln dcl) 101 | 102 | sLValTransUnit :: TransUnit -> TransUnit 103 | sLValTransUnit (TransUnit {exts}) = 104 | TransUnit {exts=map sLValExternalDecln exts} 105 | -------------------------------------------------------------------------------- /src/CodeGen/C/SimplifyLoop.hs: -------------------------------------------------------------------------------- 1 | module CodeGen.C.SimplifyLoop (sLoopTransUnit) where 2 | 3 | {- | 4 | Module : CodeGen.C.SimplifyLoop 5 | Description : C Simplifier - translate away most loops 6 | Copyright : Draper Laboratories 7 | 8 | Author : Chris Casinghino 9 | 10 | 11 | This module implements a simple translation on our C AST. All loops are 12 | translated into loops of the form "for (;;) {...}". 13 | 14 | -} 15 | 16 | import CodeGen.C.Syntax 17 | 18 | -- These functions translate all loops into loops of the form "for (;;) {...}". 19 | -- 20 | -- The translation goes as follows: 21 | -- 22 | -- "While" loops are easiest: 23 | -- 24 | -- while(e) {s}; 25 | -- ~> for (;;) {if (e) {s} else {break}} 26 | -- 27 | -- "Do while" loops are a little trickier. Note that the statement "s" here 28 | -- goes into its own block, to make sure any declarations in it aren't in 29 | -- scope in e. 30 | -- 31 | -- do {s} while (e); 32 | -- ~> for (;;) { {s}; if (e) { } else {break}} 33 | -- 34 | -- "For" loops are: 35 | -- 36 | -- for (s1;e;s2) { s } 37 | -- ~> s1; for(;;) {if (e) {break;} else {{s};s2}} 38 | -- 39 | -- Again we make sure "s" is its own block, since definition in it aren't in 40 | -- scope in s2. 41 | 42 | likeTrue :: Exp -> Bool 43 | likeTrue (ConstExp (IntConst i) _) = i /= 0 44 | likeTrue _ = False 45 | 46 | -- Makes a "for (;;) { }} 47 | simpleFor :: SPos -> Statement -> Statement 48 | simpleFor sp s = For (Right Nothing) Nothing Nothing s sp 49 | 50 | sLoopStmt :: Statement -> Statement 51 | sLoopStmt (Compound eds sp) = Compound (map sLoopDeclStmt eds) sp 52 | where 53 | sLoopDeclStmt :: Either Decln Statement -> Either Decln Statement 54 | sLoopDeclStmt (Left d) = Left d 55 | sLoopDeclStmt (Right s) = Right $ sLoopStmt s 56 | sLoopStmt (IfStm e s1 s2 sp) = IfStm e (sLoopStmt s1) (fmap sLoopStmt s2) sp 57 | sLoopStmt (Switch e s sp) = Switch e (sLoopStmt s) sp 58 | sLoopStmt st@(ExpStm _ _) = st 59 | sLoopStmt (Case e s sp) = Case e (sLoopStmt s) sp 60 | sLoopStmt (Default s sp) = Default (sLoopStmt s) sp 61 | sLoopStmt st@(Continue _) = st 62 | sLoopStmt st@(Goto _ _) = st 63 | sLoopStmt st@(Asm _) = st 64 | -- While loops, with a special case for while(1) 65 | sLoopStmt (While e s sp) | likeTrue e = simpleFor sp $ sLoopStmt s 66 | sLoopStmt (While e s sp) = simpleFor sp (IfStm e s' (Just $ Break sp) sp) 67 | where 68 | s' = sLoopStmt s 69 | 70 | -- Do-while loops, with a special case for while(1) 71 | sLoopStmt (DoWhile s e sp) | likeTrue e = simpleFor sp $ sLoopStmt s 72 | sLoopStmt (DoWhile s e sp) = 73 | simpleFor sp $ 74 | Compound [Right $ Compound [Right s'] sp, 75 | Right $ IfStm e (ExpStm Nothing sp) (Just $ Break sp) sp] sp 76 | where 77 | s' = sLoopStmt s 78 | 79 | -- For loops, with some special cases to more cleanly handle the possibility that any of 80 | -- s1, e and s2 are missing. 81 | sLoopStmt (For de1 me2 me3 s sp) = 82 | case de1 of 83 | Right Nothing -> loop 84 | Right (Just e1) -> Compound [Right (ExpStm (Just e1) sp), Right loop] sp 85 | Left d -> Compound ((map Left d) ++ [Right loop]) sp 86 | where 87 | s' = sLoopStmt s 88 | 89 | 90 | loop = simpleFor sp (case me2 of 91 | Nothing -> body 92 | Just e2 -> IfStm e2 body (Just $ Break sp) sp) 93 | 94 | body = case me3 of 95 | Nothing -> s' 96 | Just e3 -> 97 | Compound [Right $ Compound [Right s'] sp, 98 | Right $ ExpStm (Just e3) sp] sp 99 | 100 | sLoopStmt (Labelled nm s sp) = Labelled nm (sLoopStmt s) sp 101 | sLoopStmt st@(Return _ _) = st 102 | sLoopStmt st@(Break _) = st 103 | 104 | 105 | sLoopFunDef :: FunDef -> FunDef 106 | sLoopFunDef fd = fd {funBody = sLoopStmt (funBody fd)} 107 | 108 | sLoopExternalDecln :: ExternalDecln -> ExternalDecln 109 | sLoopExternalDecln (ExtFunDef fdef) = ExtFunDef (sLoopFunDef fdef) 110 | sLoopExternalDecln ed@(ExtDecln _) = ed 111 | 112 | sLoopTransUnit :: TransUnit -> TransUnit 113 | sLoopTransUnit (TransUnit {exts}) = 114 | TransUnit {exts=map sLoopExternalDecln exts} 115 | -------------------------------------------------------------------------------- /src/CodeGen/Driver.hs: -------------------------------------------------------------------------------- 1 | module CodeGen.Driver where 2 | 3 | import Control.Monad.Except 4 | 5 | data Output = Output {memModel :: String, 6 | stubs :: Maybe String, 7 | code :: String} 8 | type DriverM a = ExceptT String IO a 9 | 10 | data DriverInput = DriverInput {diFilename :: String, 11 | diCPPOpts :: String, 12 | diRuntime :: String, 13 | diExternals :: String, 14 | diWarn :: Bool, 15 | diIntermediate :: Bool, 16 | diInputList :: [String]} 17 | 18 | data Driver = Driver {genCode :: DriverInput -> DriverM Output} 19 | 20 | runDriver :: Driver -> DriverInput -> IO Output 21 | runDriver d di = do 22 | mOutput <- runExceptT $ genCode d di 23 | case mOutput of 24 | Left err -> error err 25 | Right output -> return output 26 | 27 | data OutputLocs = OutputLocs {memModelLoc :: FilePath, 28 | stubLoc :: FilePath, 29 | codeLoc :: FilePath} 30 | 31 | defaultDriver :: Driver 32 | defaultDriver = Driver $ \DriverInput {diFilename} -> do 33 | ftxt <- liftIO $ readFile diFilename 34 | return $ Output {memModel = "", 35 | stubs = Nothing, 36 | code = ftxt} 37 | 38 | outputLocs :: FilePath -> OutputLocs 39 | outputLocs codeLoc = OutputLocs { 40 | memModelLoc = "globVarDecs.csp", 41 | stubLoc = "stubs.csp", 42 | codeLoc 43 | } 44 | 45 | 46 | -- Transformer that adds the given filepath to the head of FDR output 47 | addHeaders :: [FilePath] -> String -> String 48 | addHeaders fps s = concatMap hdr fps ++ s 49 | where 50 | hdr fp = "include " ++ show fp ++ "\n" 51 | 52 | toStdOut :: Output -> IO () 53 | toStdOut (Output {memModel,stubs,code}) = putStrLn strOutput 54 | where 55 | strOutput = 56 | ( "--- begin memory model ---\n" 57 | ++ memModel 58 | ++ "\n--- end memory model ---\n") 59 | ++ (case stubs of 60 | Nothing -> "" 61 | Just stubtxt -> 62 | "--- begin stubs ---\n" 63 | ++ stubtxt 64 | ++ "\n--- end stubs ---\n") 65 | ++ code 66 | 67 | -- Input, variable declarations and output file 68 | toFile :: DriverInput -> OutputLocs -> Output -> IO () 69 | toFile (DriverInput {diRuntime}) 70 | (OutputLocs {memModelLoc,stubLoc,codeLoc}) 71 | (Output {memModel,stubs,code}) = 72 | do case stubs of 73 | Just stubCode -> do 74 | writeFile codeLoc (addHeaders [diRuntime,stubName] code) 75 | writeFile stubLoc stubCode 76 | Nothing -> 77 | writeFile codeLoc (addHeaders [diRuntime] code) 78 | writeFile memModelLoc memModel 79 | where 80 | stubName = "stubs.csp" 81 | -------------------------------------------------------------------------------- /src/CodeGen/LLVM/DriverLLVM.hs: -------------------------------------------------------------------------------- 1 | {- | 2 | Module : CodeGen.LLVM.DriverLLVM 3 | Description : Driver for LLVM translation to CSP 4 | 5 | Author : Chris Casinghino 6 | 7 | This module contains the high level "Driver" used by main to invoke the LLVM 8 | translation to CSP. 9 | -} 10 | module CodeGen.LLVM.DriverLLVM where 11 | 12 | import qualified LLVM.General as L 13 | import qualified LLVM.General.Context as L 14 | import qualified LLVM.General.AST as LA (Name(..)) 15 | import qualified LLVM.General.Diagnostic as Diag 16 | 17 | -- import qualified LLVM.General.PassManager as PM 18 | 19 | import Control.Monad.Except 20 | 21 | import CodeGen.Driver 22 | import CodeGen.LLVM.CGMonad 23 | import CodeGen.LLVM.TransModule 24 | import CodeGen.LLVM.Externals (getExternals,ExternalsInfo(..)) 25 | 26 | import Data.List (intercalate) 27 | import qualified Language.CSPM.Syntax as T 28 | import qualified Language.CSPM.Pretty as Pretty 29 | 30 | processModule :: ExternalsInfo -> L.Module -> IO (Either String CspModules, [Warning]) 31 | processModule (ExternalsInfo {funcInfo,minInt,maxInt}) lm = do 32 | -- How to run LLVM passes 33 | -- _ <- runExceptT $ L.writeLLVMAssemblyToFile (L.File "modBefore") lm 34 | -- b <- PM.withPassManager (PM.defaultCuratedPassSetSpec {PM.optLevel = Just 3}) 35 | -- (\pm -> PM.runPassManager pm lm) 36 | -- _ <- runExceptT $ L.writeLLVMAssemblyToFile (L.File "modAfter") lm 37 | lam <- L.moduleAST lm 38 | let extFunc :: (String,BaseType,[BaseType]) -> (LA.Name,GlobFuncInfo) 39 | extFunc (nm,ret,args) = (LA.Name nm, 40 | GFInfo {ftid=T.Fixed nm, 41 | fret=ret, 42 | fargs=args, 43 | ftag=T.Fixed ("FP_" ++ nm), 44 | fdef=True}) 45 | 46 | state = initState (minInt,maxInt) $ map extFunc funcInfo 47 | return $ runCG state (transModule lam) 48 | 49 | driver :: DriverInput -> DriverM Output 50 | driver (DriverInput {diFilename,diWarn,diExternals}) = do 51 | ext <- getExternals diExternals 52 | result <- 53 | liftIO $ L.withContext $ \c -> 54 | runExceptT $ L.withModuleFromLLVMAssembly c file (processModule ext) 55 | (output,warnings) <- 56 | case result of 57 | Left (Left s) -> throwError s 58 | Left (Right d) -> throwError $ Diag.diagnosticDisplay d 59 | Right o -> return o 60 | when diWarn $ liftIO $ putStrLn $ intercalate "\n" $ map show warnings 61 | CspModules {cmGlobalState,cmStubs,cmCode} <- 62 | case output of 63 | Left err -> throwError ("Compilation Error:\n" ++ err) 64 | Right o -> do 65 | liftIO $ putStrLn "Code generation successful" 66 | return o 67 | -- XXX factor out everything from here on down - it's identical in C version 68 | modules <- 69 | case cmStubs of 70 | Nothing -> return [cmGlobalState,cmCode] 71 | Just stubMod -> do 72 | liftIO $ putStrLn $ 73 | "Warning: " ++ show (length $ T.topLevels stubMod) 74 | ++ " functions were " 75 | ++ "declared but not defined. Stubs for these functions " 76 | ++ "will be included in the generated CSP." 77 | return [cmGlobalState,stubMod,cmCode] 78 | let (txt,warns) = Pretty.emitMods modules 79 | when (not $ null warns) $ liftIO $ do 80 | putStrLn "The pretty printer warns that:" 81 | mapM_ putStrLn warns 82 | case txt of 83 | (gtxt:codetxt:[]) -> 84 | return $ 85 | Output {memModel = gtxt, 86 | stubs = Nothing, 87 | code = codetxt} 88 | (gtxt:stubtxt:codetxt:[]) -> 89 | return 90 | Output {memModel = gtxt, 91 | stubs = Just stubtxt, 92 | code = codetxt} 93 | _ -> error "Internal Error: emitMods returned incorrect number of modules." 94 | where 95 | file = L.File diFilename 96 | 97 | genCSP :: Driver 98 | genCSP = Driver driver 99 | -------------------------------------------------------------------------------- /src/CodeGen/LLVM/Externals.hs: -------------------------------------------------------------------------------- 1 | {- | 2 | Module : CodeGen.LLVM.Externals 3 | Description : Parser for external function specs 4 | Copyright : Draper Laboratories 5 | 6 | This parses configuration files for cspgen. The files have two sections and may 7 | contain comments in Haskell style. The high-level format is: 8 | 9 | @section FUNCTIONS { 10 | 11 | 12 | 13 | } 14 | 15 | @section SETTINGS { 16 | 17 | 18 | 19 | } 20 | 21 | ----- 22 | 23 | The FUNCTIONS section contains a list of functions which are used in the C code 24 | but whose implementations are expected to be provided by the cspgen runtime. 25 | The format for these files is a list of declarations of the form: 26 | 27 | @ 28 | returnType name(argType1,...,argType2); 29 | @ 30 | 31 | Here, @returnType@ is the return type of the function (currently the grammar for 32 | these is quite limited). @name@ is the function's name, which must match the 33 | LLVM name. For now, this means the mangled name must occur here. 34 | 35 | Currently supported types are: 36 | 37 | ty := int | bool | ty* | | void 38 | 39 | ----- 40 | 41 | The SETTINGS section contains a list of options and the values assigned to them. 42 | The format is a list of declarations of the form: 43 | 44 | settingName = value; 45 | 46 | Currently the only "settingName"s supported are "minimumCVal" and "maximumCVal". 47 | The value must be an integer. 48 | 49 | ----- 50 | 51 | XXX One flaw in the current system is that types are not supported very well. 52 | We only handle a few basic return types to avoid needing a full C parser here, 53 | and we don't handle argument types at all. 54 | 55 | XXX this is mostly a copy of the C version. Factor out this functionality if 56 | it doesn't diverge substantially. 57 | 58 | XXX 59 | 60 | 61 | -} 62 | 63 | module CodeGen.LLVM.Externals (getExternals,ExternalsInfo(..)) where 64 | 65 | import Text.Parsec 66 | import Text.Parsec.Token 67 | import Text.Parsec.Expr 68 | import Text.Parsec.Language (haskellStyle) 69 | 70 | import Control.Monad.Except 71 | 72 | import System.Directory (doesFileExist) 73 | 74 | import CodeGen.LLVM.CGMonad (BaseType(..)) 75 | 76 | -- holds input from parser 77 | data Setting = MinInt Int | MaxInt Int | NoValue 78 | 79 | -- holds output 80 | data ExternalsInfo = 81 | ExternalsInfo { 82 | funcInfo :: [(String,BaseType,[BaseType])], 83 | minInt :: Int, 84 | maxInt :: Int 85 | } 86 | 87 | defaultExternalsInfo :: ExternalsInfo 88 | defaultExternalsInfo = 89 | ExternalsInfo { 90 | funcInfo = [], 91 | minInt = 0, 92 | maxInt = 4 93 | } 94 | 95 | -- Setting up tokenizer 96 | externalsStyle :: LanguageDef st 97 | externalsStyle = haskellStyle {reservedNames = ["void","int","bool","pid", 98 | "minimumCVal","maximumCVal"], 99 | reservedOpNames = ["=", "section"]} 100 | 101 | exCommaSep :: Parsec String u a -> Parsec String u [a] 102 | exIdentifier :: Parsec String u String 103 | exParens :: Parsec String u a -> Parsec String u a 104 | exReserved :: String -> Parsec String u () 105 | exReservedOp :: String -> Parsec String u () 106 | exWhiteSpace :: Parsec String u () 107 | exSemi :: Parsec String u String 108 | exInteger :: Parsec String u Integer 109 | exBraces :: Parsec String u a -> Parsec String u a 110 | exSymbol :: String -> Parsec String u String 111 | TokenParser {commaSep = exCommaSep, 112 | reserved = exReserved, 113 | reservedOp = exReservedOp, 114 | identifier = exIdentifier, 115 | parens = exParens, 116 | whiteSpace = exWhiteSpace, 117 | semi = exSemi, 118 | integer = exInteger, 119 | braces = exBraces, 120 | symbol = exSymbol} 121 | = makeTokenParser externalsStyle 122 | 123 | ------------------------------------- 124 | --- FUNCTIONS section parsing 125 | ------------------------------------- 126 | 127 | -- Parsec parser definitions 128 | typeParser :: Parsec String () BaseType 129 | typeParser = buildExpressionParser table simpleType 130 | where 131 | -- table :: OperatorTable String () a BaseType 132 | table = 133 | [[Postfix $ do _ <- char '*' 134 | return PointerType]] 135 | 136 | simpleType :: Parsec String () BaseType 137 | simpleType = choice knownTypes 138 | 139 | knownTypes :: [Parsec String () BaseType] 140 | knownTypes = map (\(n,b) -> exReserved n >> return b) 141 | [("int",IntType), 142 | ("bool",BoolType), 143 | ("void",VoidType), 144 | ("pid",PIDType) 145 | ] 146 | 147 | -- typeName :: Parsec String () BaseType 148 | -- typeName = NamedType <$> T.Fixed exIdentifier 149 | 150 | externalFuncParser :: Parsec String () (String,BaseType,[BaseType]) 151 | externalFuncParser = do 152 | eRetType <- typeParser 153 | eName <- exIdentifier 154 | eArgTypes <- exParens $ exCommaSep typeParser 155 | return (eName,eRetType,eArgTypes) 156 | 157 | 158 | ------------------------------------- 159 | --- SETTINGS section parsing 160 | ------------------------------------- 161 | 162 | settingNameParser :: String -> Parsec String () String 163 | settingNameParser name = do 164 | exReserved name 165 | return name 166 | 167 | externalSettingParser :: Parsec String () Setting 168 | externalSettingParser = do 169 | eName <- settingNameParser "minimumCVal" <|> settingNameParser "maximumCVal" 170 | exReservedOp "=" 171 | eValue <- exInteger 172 | let setting = case eName of 173 | "minimumCVal" -> MinInt (min (fromInteger eValue) 0) 174 | "maximumCVal" -> MaxInt (max (fromInteger eValue) 1) 175 | _ -> NoValue 176 | return setting 177 | 178 | 179 | -- Updates the provided ExternalsInfo with any explicit settings that appeared 180 | -- in the configuation file. 181 | settingsExtractor :: ExternalsInfo -> [Setting] -> ExternalsInfo 182 | settingsExtractor = foldr handleSetting 183 | where 184 | handleSetting :: Setting -> ExternalsInfo -> ExternalsInfo 185 | handleSetting NoValue ei = ei 186 | handleSetting (MinInt val) ei = ei {minInt=val} 187 | handleSetting (MaxInt val) ei = ei {maxInt=val} 188 | 189 | 190 | ----------------------------------- 191 | ---- Top level parser and interface 192 | ----------------------------------- 193 | 194 | missingExternalWarning :: String -> String 195 | missingExternalWarning fname = 196 | "Warning: \"" ++ fname ++ "\" not found. Proceeding with " 197 | ++ "no external functions." 198 | 199 | sectionParser :: String -> Parsec String () a -> Parsec String () [a] 200 | sectionParser name p = do 201 | _ <- exSymbol "@section" 202 | _ <- exSymbol name 203 | info <- exBraces $ sepEndBy p exSemi 204 | return info 205 | 206 | externalsParser :: Parsec String () ExternalsInfo 207 | externalsParser = do 208 | exWhiteSpace 209 | externals <- sectionParser "FUNCTIONS" externalFuncParser 210 | values <- sectionParser "SETTINGS" externalSettingParser 211 | optional exWhiteSpace 212 | eof 213 | let ei = settingsExtractor (defaultExternalsInfo {funcInfo=externals}) 214 | values 215 | return ei 216 | 217 | 218 | getExternals :: (MonadError String m, MonadIO m) => FilePath -> m ExternalsInfo 219 | getExternals fileName = do 220 | externalsExists <- liftIO $ doesFileExist fileName 221 | if externalsExists then do 222 | cfgFileContents <- liftIO $ readFile fileName 223 | let result = parse externalsParser fileName cfgFileContents 224 | case result of 225 | Left parseError -> throwError $ show parseError 226 | Right externals -> return externals 227 | else do 228 | liftIO $ putStrLn $ missingExternalWarning fileName 229 | return defaultExternalsInfo 230 | -------------------------------------------------------------------------------- /src/CodeGen/LLVM/ModelBasics.hs: -------------------------------------------------------------------------------- 1 | {- | 2 | 3 | Module : CodeGen.LLVM.ModelBasics 4 | Description : Basic CSP data representations and common definitions 5 | 6 | Author : Chris Casinghino 7 | 8 | This contains the data representations for basic parts of the model (for 9 | example, Unit, Int and Float). It also contains some basic csp defintions used in 10 | other parts of the model (like zero and one). 11 | -} 12 | 13 | module CodeGen.LLVM.ModelBasics where 14 | 15 | import Language.CSPM.Syntax as T 16 | 17 | import CodeGen.LLVM.ModelIdentifiers 18 | import CodeGen.LLVM.CGMonad 19 | 20 | 21 | 22 | ------------------------------------------------- 23 | --- Integers 24 | 25 | -- representation definition 26 | minIntDef, maxIntDef :: Int -> T.Definition 27 | minIntDef x = T.DVar (T.PId minIntId) $ T.EConst $ T.CInt $ toInteger x 28 | maxIntDef x = T.DVar (T.PId maxIntId) $ T.EConst $ T.CInt $ toInteger x 29 | 30 | intDataRep :: T.Definition 31 | intDataRep = 32 | T.DDataType (fciRepType intFCInfo) 33 | [(knownIntCon,[T.ESetFromTo (T.EId minIntId) 34 | (T.EId maxIntId)]), 35 | (unknownIntCon,[])] 36 | 37 | -- Helpers 38 | unknownInt :: T.Exp 39 | unknownInt = T.EDot (T.EId unknownIntCon) [] 40 | 41 | knownInt :: Integer -> T.Exp 42 | knownInt i = T.EDot (T.EId knownIntCon) [T.EConst $ T.CInt i] 43 | 44 | intZero, intOne :: T.Exp 45 | intZero = knownInt 0 46 | intOne = knownInt 1 47 | 48 | 49 | -------------------------------------------------------- 50 | --- Booleans 51 | 52 | --- XXX do we need this in LLVM verison? 53 | 54 | cBoolDataRep :: T.Definition 55 | cBoolDataRep = 56 | T.DDataType (fciRepType boolFCInfo) 57 | [(boolTrueCon,[]), 58 | (boolFalseCon,[]), 59 | (unknownBoolCon,[])] 60 | 61 | unknownBool :: T.Exp 62 | unknownBool = T.EDot (T.EId unknownBoolCon) [] 63 | 64 | boolFalse :: T.Exp 65 | boolFalse = T.EDot (T.EId boolFalseCon) [] 66 | 67 | boolTrue :: T.Exp 68 | boolTrue = T.EDot (T.EId boolTrueCon) [] 69 | 70 | -------------------------------------------------------- 71 | --- Floats 72 | 73 | cFloatDataRep :: T.Definition 74 | cFloatDataRep = 75 | T.DDataType (fciRepType floatFCInfo) 76 | [(unknownFloatCon,[])] 77 | 78 | unknownFloat :: T.Exp 79 | unknownFloat = T.EDot (T.EId unknownFloatCon) [] 80 | 81 | -------------------------------------------------------- 82 | --- Unit 83 | 84 | unitDataRep :: T.Definition 85 | unitDataRep = 86 | T.DDataType unitRepId [(unitValCon,[])] 87 | 88 | cspUnit :: T.Exp 89 | cspUnit = T.EDot (T.EId unitValCon) [] 90 | 91 | 92 | -------------------------------------------------------- 93 | --- Thread IDs 94 | 95 | -- The data representation for process IDs. The MAX should be configurable, but 96 | -- is not currently. 97 | maxTidDef :: T.Definition 98 | maxTidDef = T.DVar (T.PId maxTidId) $ T.EConst $ T.CInt 6 99 | 100 | tidDataRep :: T.Definition 101 | tidDataRep = 102 | T.DDataType tidTypId 103 | [(tidKnownCon, [T.ESetFromTo (T.EConst (T.CInt 0)) 104 | (T.EId maxTidId)]), 105 | (tidUnknownCon, [])] 106 | 107 | tidZero :: T.Exp 108 | tidZero = T.EDot (T.EId tidKnownCon) [T.EConst (T.CInt 0)] 109 | 110 | -------------------------------------------------------- 111 | --- Mutex IDs 112 | 113 | maxMidDef :: T.Definition 114 | maxMidDef = T.DVar (T.PId maxMidId) $ T.EConst $ T.CInt 5 115 | 116 | midDataRep :: T.Definition 117 | midDataRep = 118 | T.DDataType midTypId 119 | [(midConId, [T.ESetFromTo (T.EConst (T.CInt 0)) 120 | (T.EId maxMidId)])] 121 | 122 | -------------------------------------------------------- 123 | --- Mutexes 124 | 125 | 126 | -- A mutex is represented essentially as a (Maybe MutexID). "Nothing" indicates 127 | -- this mutex has not been initialized. 128 | 129 | mutDataRep :: T.Definition 130 | mutDataRep = 131 | T.DDataType (fciRepType mutexFCInfo) 132 | [(mutexInitCon,[T.EDot (T.EId midTypId) []]), 133 | (mutexUnInitCon,[])] 134 | 135 | uninitializedMutex :: T.Exp 136 | uninitializedMutex = T.EDot (T.EId mutexUnInitCon) [] 137 | 138 | 139 | -------------------------------------------------------- 140 | --- Assorted common CSP idioms 141 | 142 | -- used repeatedly 143 | noId :: T.Id 144 | noId = T.Fixed "_" 145 | -------------------------------------------------------------------------------- /src/CodeGen/LLVM/ModelIdentifiers.hs: -------------------------------------------------------------------------------- 1 | {- | 2 | 3 | Module : CodeGen.LLVM.ModelIdentifiers 4 | Description : This module holds the fixed identifiers used by the model 5 | 6 | Author : Chris Casinghino 7 | 8 | -} 9 | 10 | module CodeGen.LLVM.ModelIdentifiers where 11 | 12 | import qualified Language.CSPM.Syntax as T 13 | 14 | ---------------------------------------------- 15 | ---- Basic datatype representation identifiers 16 | 17 | -- Ints 18 | knownIntCon,unknownIntCon :: T.Id 19 | knownIntCon = T.Fixed "CIntKnown" 20 | unknownIntCon = T.Fixed "CIntUnknown" 21 | 22 | minIntId, maxIntId :: T.Id 23 | minIntId = T.Fixed "minimumCVal" 24 | maxIntId = T.Fixed "maximumCVal" 25 | 26 | 27 | -- Floats 28 | unknownFloatCon :: T.Id 29 | unknownFloatCon = T.Fixed "CFloatUnknown" 30 | 31 | -- Bools 32 | boolTrueCon, boolFalseCon, unknownBoolCon :: T.Id 33 | boolTrueCon = T.Fixed "CBoolTrue" 34 | boolFalseCon = T.Fixed "CBoolFalse" 35 | unknownBoolCon = T.Fixed "CBoolUnknown" 36 | 37 | -- Mutex IDs 38 | midTypId :: T.Id 39 | midTypId = T.Fixed "MutexID" 40 | 41 | midConId :: T.Id 42 | midConId = T.Fixed "M_ID" 43 | 44 | maxMidId :: T.Id 45 | maxMidId = T.Fixed "maximumMID" 46 | 47 | -- Mutex IDs and Mutexes themselves 48 | mutexInitCon, mutexUnInitCon :: T.Id 49 | mutexInitCon = T.Fixed "Mut" 50 | mutexUnInitCon = T.Fixed "Mut_UNINITIALIZED" 51 | 52 | 53 | -- Unit 54 | unitRepId :: T.Id 55 | unitRepId = T.Fixed "Unit" 56 | 57 | unitValCon :: T.Id 58 | unitValCon = T.Fixed "UnitVal" 59 | 60 | --Function pointers 61 | fptrRepId :: T.Id 62 | fptrRepId = T.Fixed "FPtr" 63 | 64 | fptrNullCon :: T.Id 65 | fptrNullCon = T.Fixed "FPtr_NULL" 66 | 67 | fptrUnknownCon :: T.Id 68 | fptrUnknownCon = T.Fixed "FPtr_UNKNOWN" 69 | 70 | fptrErrorName :: T.Id 71 | fptrErrorName = T.Fixed "fptr_deref_ERROR" 72 | 73 | ---------------------------------------------- 74 | --- Identifiers related to thread IDs 75 | 76 | tidTypId :: T.Id 77 | tidTypId = T.Fixed "TIDTyp" 78 | 79 | tidKnownCon, tidUnknownCon :: T.Id 80 | tidKnownCon = T.Fixed "TID" 81 | tidUnknownCon = T.Fixed "TIDUnknown" 82 | 83 | maxTidId :: T.Id 84 | maxTidId = T.Fixed "maximumTID" 85 | 86 | ---------------------------------------------- 87 | ---- Datatype conversion identifiers 88 | 89 | cIntToBool, cBoolToInt :: T.Id 90 | cIntToBool = T.Fixed "intToBool" 91 | cBoolToInt = T.Fixed "boolToInt" 92 | 93 | cIntToFloat, cFloatToInt :: T.Id 94 | cIntToFloat = T.Fixed "intToFloat" 95 | cFloatToInt = T.Fixed "floatToInt" 96 | 97 | ---------------------------------------------- 98 | ---- Stack representation and manipulators 99 | 100 | stackType :: T.Id 101 | stackType = T.Fixed "Stack" 102 | 103 | stackAddrType,stackAddrCon :: T.Id 104 | stackAddrType = T.Fixed "StackAddr" 105 | stackAddrCon = T.Fixed "SA" 106 | 107 | maxStackAddr :: T.Id 108 | maxStackAddr = T.Fixed "maxStackAddr" 109 | 110 | -- read or write from/to a stack variable, or push a new variable 111 | readFromStackId,writeToStackId,pushOnStackId :: T.Id 112 | readFromStackId = T.Fixed "readFromStack" 113 | writeToStackId = T.Fixed "writeToStack" 114 | pushOnStackId = T.Fixed "pushOnStack" 115 | 116 | -- stack data 117 | stackValType :: T.Id 118 | stackValType = T.Fixed "StackVal" 119 | 120 | stackFrameCon :: T.Id 121 | stackFrameCon = T.Fixed "StackFrameBoundary" 122 | 123 | -- stack frame manipulation 124 | pushStackFrameId, popStackFrameId :: T.Id 125 | pushStackFrameId = T.Fixed "pushStackFrame" 126 | popStackFrameId = T.Fixed "popStackFrame" 127 | 128 | -- stackErrors 129 | stackOverflowErrorId, stackUnderflowErrorId :: T.Id 130 | stackOverflowErrorId = T.Fixed "stackOverflowError" 131 | stackUnderflowErrorId = T.Fixed "stackUnderflowError" 132 | 133 | stackMisprojErrorId :: T.Id 134 | stackMisprojErrorId = T.Fixed "stackMisprojectionError" 135 | 136 | ---------------------------------------------- 137 | ---- Top-level memory model identifiers 138 | 139 | memoryName, runInMemoryName, hideMemoryName :: T.Id 140 | memoryName = T.Fixed "MEMORY" 141 | runInMemoryName = T.Fixed "runInMemory" 142 | hideMemoryName = T.Fixed "hideMemory" 143 | 144 | --getElementPtr errors 145 | gepErrorName :: T.Id 146 | gepErrorName = T.Fixed "gepERROR" 147 | 148 | ---------------------------------------- 149 | -- Runtime names 150 | 151 | selectId :: T.Id 152 | selectId = T.Fixed "selectLLVM" 153 | 154 | 155 | --------------------------- 156 | --- Top-level program stuff 157 | 158 | runAsMainName :: T.Id 159 | runAsMainName = T.Fixed "runAsMain" 160 | 161 | runName :: T.Id 162 | runName = T.Fixed "run" 163 | -------------------------------------------------------------------------------- /src/CodeGen/LLVM/OPTIMIZATIONS: -------------------------------------------------------------------------------- 1 | It's going to take a lot of experimentation to determine what combination of 2 | clang and llvm-backend optimizations should be run on input to our toolchain, 3 | and how to do it. Optimal performance will almost certainly require writing 4 | custom passes, but we're definitely going to avoid that for as long as possible, 5 | as we spin up the tool. 6 | 7 | I've found the following tiny example C program to be useful for 8 | experimentation: 9 | 10 | > #include 11 | > 12 | > struct foo { 13 | > int x; 14 | > int y; 15 | > } z; 16 | > 17 | > int main() { 18 | > struct foo a = {1,2}; 19 | > z = a; 20 | > printf("%d\n",z.y); 21 | > return 0; 22 | > } 23 | 24 | clang optimization passes 25 | ------------------------- 26 | 27 | - clang appears to always start main by allocating a local variable for the 28 | return value (via alloca). In this case, that value is always 0. This 29 | allocation appears when optimization is turned off entirely, but it removed at 30 | -O1 and up. 31 | 32 | - At -O0 and -O1, but not higher, there is a private global mirroring "a": 33 | 34 | > @main.a = private unnamed_addr constant %struct.foo { i32 1, i32 2 }, align 4 35 | 36 | At -O0, "a" is also allocated locally in main. At -O2 and higher, a is 37 | optimized away completely, since its value is fixed. 38 | 39 | - The initialization of "a" is interesting. At -O0, we get this: 40 | 41 | > %a = alloca %struct.foo, align 4 42 | > %2 = bitcast %struct.foo* %a to i8* 43 | > call void @llvm.memcpy.p0i8.p0i8.i64(i8* %2, i8* bitcast (%struct.foo* @main.a to i8*), i64 8, i32 4, i1 false) 44 | 45 | These instructions do the following: 46 | 47 | 1) allocate a as a local (now %a is a pointer to a's location on the stack). 48 | 49 | 2) create another local, %2, which is a copy of %a but has a different type 50 | (it has been cast from a struct foo* to an i8*). This is needed because 51 | the llvm.memcpy.STUFF function requires its arguments to be pointers of 52 | this type (which is almost sensible, since the length is specified in 53 | bytes). 54 | 55 | 3) the arguments to memcpy are: destination, source, length, alignment, volatility. 56 | 57 | Here, we see that we are copying from location @main.a to location %2 58 | (i.e., to a's location on the stack). We are copying 8 bytes of data (two 59 | i32s). The data is 4-aligned, and the copy is "non-volatile (whatever that 60 | means). 61 | 62 | At -O1 and higher, there is no local variable %a, and thus it is not 63 | initialized. In those versions, in the place where the value of a is needed, 64 | the i64 "8589934593" is used. To understand this, recall that a's value is 65 | {1,2}, and observe that 8589934593 is 0x0000000200000001. Why does the first 66 | field come second? Some detail of memory layout I should think harder about. 67 | 68 | - The assignment "z = a;" is also interesting. With no optimization, we get: 69 | 70 | > %3 = bitcast %struct.foo* %a to i8* 71 | > call void @llvm.memcpy.p0i8.p0i8.i64(i8* bitcast (%struct.foo* @z to i8*), i8* %3, i64 8, i32 4, i1 false) 72 | 73 | Here we're again casting the address of a to an i8*. This time it's our 74 | source, though. The destination is the global z, also cast (in-line) to a 75 | i8*. We copy 8 bytes of memory, as expected. 76 | 77 | At -O1 and higher, there is no local variable a and the value mentioned above 78 | is used in its place. Additionally, "store" is used rather than "memcpy" - 79 | this is a slight change in semantics, as store is atomic but memcpy is not. 80 | 81 | > store i64 8589934593, i64* bitcast (%struct.foo* @z to i64*), align 4 82 | 83 | -------------------------------------------------------------------------------- /src/CodeGen/LLVM/TODO: -------------------------------------------------------------------------------- 1 | - The operandType/constantType functions need to be in the monad because they 2 | require type info, and should probably be moved back to Analysis. We should 3 | just make that module's toplevel monadic. 4 | 5 | - We need to carefully consider our runtime model of each arithmetic function. 6 | I'm sure it's wrong sometimes (for example, for small int sizes). Just make 7 | int width a parameter of the arithmetic functions? 8 | 9 | - Right now we're not keeping track of any function information so we can't 10 | check that function applications are sensible. Is this is a problem? 11 | 12 | - We need to fail (warn?) more gracefully in the presence of metadata 13 | 14 | - Fail more gracefully in analysis (put in monad?). See repackageBlock, for 15 | example. 16 | 17 | - Stack is inefficient. Address space for individual types should only include 18 | stack addresses if necessary, and the stack data union should only include the 19 | types that are actually stored on the stack. 20 | 21 | - Constants are treated like any other globals, leading to lots and lots of 22 | inefficient memory cells (for example, when there are strings in the program). 23 | Build a better model for global constants (when a global declaration includes 24 | the constant keyword, or maybe constant and unnamed_addr). One idea: modify 25 | the "read" functions so that they just return the right answer in these cases, 26 | and the "write" functions so that they error. 27 | -------------------------------------------------------------------------------- /src/Main.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import Data.Maybe (fromMaybe) 4 | 5 | import System.Console.GetOpt 6 | import System.Environment 7 | import System.FilePath.Posix (takeBaseName) 8 | import System.Exit (ExitCode(..), exitWith) 9 | 10 | import Control.Monad (when) 11 | 12 | import qualified CodeGen.C.DriverC as FM 13 | import qualified CodeGen.LLVM.DriverLLVM as LL 14 | import qualified CodeGen.Driver as D 15 | import qualified Tests.CSPGenTest.CSPGenTest as Test 16 | import qualified Tests.CParseTest.CParseTest as PTest 17 | import qualified Tests.LLVMTest.LLVMTest as LTest 18 | 19 | data Options = Options {optOutput :: Maybe FilePath, 20 | optDumpAST :: Bool, 21 | optDumpC :: Bool, 22 | optExternals :: Maybe FilePath, 23 | optRuntime :: Maybe FilePath, 24 | optTest :: Bool, 25 | optTestLLVM :: Bool, 26 | optCPP :: String, 27 | optWarn :: Bool, 28 | optIntermediate :: Bool, 29 | optLLVM :: Bool 30 | } 31 | 32 | 33 | defaultOpts :: Options 34 | defaultOpts = Options {optOutput = Nothing, 35 | optDumpAST = False, 36 | optDumpC = False, 37 | optRuntime = Nothing, 38 | optExternals = Nothing, 39 | optTest = False, 40 | optTestLLVM = False, 41 | optCPP = "", 42 | optWarn = True, 43 | optIntermediate = False, 44 | optLLVM = False 45 | } 46 | 47 | 48 | -- A list of options consisting of: 49 | -- * a short name 50 | -- * a long name 51 | -- * an options transformer 52 | -- * a short description of the option 53 | optionList :: [(Char, String, ArgDescr (Options -> Options), String)] 54 | optionList = [('o', "output", ReqArg (\s o -> o {optOutput=Just s}) "FILE", 55 | "Output destination"), 56 | ('l', "llvm", 57 | NoArg (\o -> o {optLLVM=True, 58 | optRuntime=case optRuntime o of 59 | Nothing -> Just "runtimeLLVM.csp" 60 | Just s -> Just s}), 61 | "Take in LLVM IR rather than C"), 62 | ('d', "dump", NoArg (\o -> o {optDumpAST=True}), 63 | "Dump the AST representation of the C-Flat code"), 64 | ('c', "emit-c", NoArg (\o -> o {optDumpC=True}), 65 | "Output the parsed C code"), 66 | ('e', "externals", ReqArg (\s o -> o {optExternals=Just s}) "FILE", 67 | "External function specifications"), 68 | ('r', "runtime", ReqArg (\s o -> o {optRuntime=Just s}) "FILE", 69 | "Runtime file"), 70 | ('p', "cpp-opts", ReqArg (\s o -> o {optCPP = s}) "STRING", 71 | "Options to be passed to cpp"), 72 | ('t', "test", NoArg (\o -> o {optTest=True}), 73 | "Run test files"), 74 | ('u', "lltest", NoArg (\o -> o {optTestLLVM=True}), 75 | "Run LLVM tests only"), 76 | ('w', "warn", NoArg (\o -> o {optWarn=False}), 77 | "Hide warnings"), 78 | ('i', "intermediate", NoArg (\o -> o {optIntermediate=True}), 79 | "Show intermediate results") 80 | ] 81 | 82 | options :: [OptDescr (Options -> Options)] 83 | options = map (\(a, b, c, d) -> Option [a] [b] c d) optionList 84 | 85 | optionPrint :: String 86 | optionPrint = concat $ map (\(x,_,_,_) -> [' ','-',x]) optionList 87 | 88 | main :: IO () 89 | main = do 90 | argv <- getArgs 91 | case getOpt Permute options argv of 92 | (opts,ifiles,[]) -> do 93 | let Options {optOutput, optDumpAST, optDumpC, optLLVM, 94 | optExternals, optRuntime, optTest, optTestLLVM, optCPP, 95 | optWarn, optIntermediate} = 96 | foldl (\o f -> f o) defaultOpts opts 97 | when (1 < (length $ filter id [optDumpAST,optTest,optTestLLVM])) $ 98 | error $ usage ["Please specify only one of -d, -t, or -u."] 99 | when optTest $ do PTest.runtests 100 | Test.runtests 101 | LTest.runtests 102 | exitWith ExitSuccess 103 | when optTestLLVM $ LTest.runtests >> exitWith ExitSuccess 104 | when (length ifiles == 0) $ 105 | error $ usage ["Please specify an input file."] 106 | when (length ifiles > 1) $ do 107 | writeFile tmpFile "" 108 | mapM_ addFile ifiles 109 | 110 | let ifile, ofile, rfile, efile :: FilePath 111 | ifile 112 | | length ifiles < 2 = head ifiles 113 | | otherwise = tmpFile -- if more than 1 use temp file 114 | ofile = 115 | case (optOutput,ifiles) of 116 | (Just f,_) -> f 117 | (_, [f]) -> (takeBaseName f) ++ ".csp" 118 | _ -> "cspgenModel.csp" 119 | rfile = fromMaybe "runtime.csp" optRuntime 120 | efile = fromMaybe (if optLLVM then "externalsLLVM" else "externals") optExternals 121 | let driver :: D.Driver 122 | driver = if optLLVM then LL.genCSP else 123 | if optDumpAST then FM.genAST else 124 | if optDumpC then FM.genCPretty else 125 | FM.genCSP 126 | 127 | di = D.DriverInput {D.diFilename=ifile, 128 | D.diCPPOpts=optCPP, 129 | D.diRuntime=rfile, 130 | D.diExternals=efile, 131 | D.diWarn=optWarn, 132 | D.diIntermediate=optIntermediate, 133 | D.diInputList=ifiles} 134 | output <- D.runDriver driver di 135 | D.toFile di (D.outputLocs ofile) output 136 | (_,_,errs) -> error $ usage errs 137 | where 138 | header = "Usage: cspgen [OPTIONS] FILE" 139 | usage errs = concat errs ++ "\n" ++ usageInfo header options 140 | tmpFile = "tmp___001" 141 | 142 | addFile :: String -> IO () 143 | addFile fin = do 144 | contents <- readFile fin 145 | appendFile tmpFile $ "\n#line 1 \"" ++ fin ++ "\"\n" ++ contents 146 | -------------------------------------------------------------------------------- /src/Tests/CParseTest/CParseTest.hs: -------------------------------------------------------------------------------- 1 | module Tests.CParseTest.CParseTest where 2 | 3 | import CodeGen.Driver (DriverInput(..)) 4 | import CodeGen.C.Parser 5 | import qualified CodeGen.C.Pretty as CPretty 6 | import Language.C 7 | import qualified Test.Tasty as T 8 | import qualified Test.Tasty.HUnit as H 9 | import Control.Monad.Except (runExceptT) 10 | 11 | testPath :: FilePath 12 | testPath = "examples/basic/" 13 | 14 | testFiles :: [String] 15 | testFiles = (map (\i -> "test_00" ++ show i) ([1..9] :: [Int])) 16 | ++ (map (\i -> "test_0" ++ show i) ([10..54] :: [Int])) 17 | 18 | process :: FilePath -> IO Bool 19 | process file = do 20 | let diFilename = testPath ++ file ++ ".c" 21 | di = DriverInput {diFilename,diCPPOpts="",diRuntime="runtime.csp", 22 | diExternals="externals",diWarn=False, 23 | diIntermediate=False,diInputList=[]} 24 | putStrLn $ "Processing " ++ file ++ "..." 25 | input <- runExceptT $ cppParseSanity di builtins 26 | case input of 27 | Left err -> do putStrLn $ "FAILED\n" ++ show err 28 | return False 29 | Right (_,code) -> do 30 | let tempFile = "/tmp/" ++ file ++ ".c.bootstrap" 31 | writeFile tempFile $ CPretty.emitTransUnit code 32 | input' <- runExceptT $ cppParseSanity (di {diFilename=tempFile}) builtins 33 | case input' of 34 | Left err -> do putStrLn $ "FAILED\n" ++ show err 35 | return False 36 | Right (_,code') -> 37 | let result = code == code' in 38 | do if result then putStrLn "PASSED" 39 | else do putStrLn "FAILED: ASTs don't match" 40 | print code 41 | print code' 42 | 43 | return result 44 | 45 | where 46 | builtins = [builtinIdent "send", 47 | builtinIdent "echo", 48 | builtinIdent "recv"] 49 | 50 | makeTest :: (String, Bool) -> T.TestTree 51 | makeTest (fname, result) = H.testCase fname $ H.assertBool "Result" result 52 | 53 | processedTests :: [IO Bool] 54 | processedTests = map process testFiles 55 | 56 | allTests :: IO T.TestTree 57 | allTests = do 58 | results <- sequence processedTests 59 | let zippedResult = zip testFiles results 60 | let tests = T.testGroup "CParse Tests" $ fmap makeTest zippedResult 61 | return tests 62 | 63 | runtests, runtestsuite :: IO () 64 | runtestsuite = do 65 | tests <- allTests 66 | T.defaultMain tests 67 | 68 | 69 | runtests = do -- runs command line tests 70 | exits <- sequence $ processedTests 71 | let total = length exits 72 | wins = length (filter id exits) 73 | putStrLn $ "Passed " ++ show wins ++ " of " ++ show total ++ " tests." 74 | -------------------------------------------------------------------------------- /src/Tests/CParseTest/Main.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import Tests.CParseTest.CParseTest 4 | 5 | main :: IO () 6 | main = runtestsuite 7 | 8 | -------------------------------------------------------------------------------- /src/Tests/CSPGenTest/CSPGenTest.hs: -------------------------------------------------------------------------------- 1 | module Tests.CSPGenTest.CSPGenTest where 2 | 3 | import Data.List (isInfixOf) 4 | import Control.Monad.Except (runExceptT) 5 | 6 | import System.Exit (ExitCode(..)) 7 | import System.Process (readProcessWithExitCode) 8 | 9 | import qualified CodeGen.C.DriverC as C 10 | import qualified CodeGen.Driver as D 11 | 12 | import qualified Test.Tasty as T 13 | import qualified Test.Tasty.HUnit as H 14 | 15 | testPath :: FilePath 16 | testPath = "examples/basic/" 17 | 18 | globVarDecsLoc :: FilePath 19 | globVarDecsLoc = testPath ++ "globVarDecs.csp" 20 | 21 | stubLoc :: FilePath 22 | stubLoc = testPath ++ "stubs.csp" 23 | 24 | runtimeLoc :: FilePath 25 | runtimeLoc = "runtime.csp" 26 | 27 | runtimePTLoc :: FilePath 28 | runtimePTLoc = "runtimePThread.csp" 29 | 30 | 31 | runtimeAlt :: FilePath 32 | runtimeAlt = "runtimeChans.csp" 33 | 34 | externalsLoc :: FilePath 35 | externalsLoc = testPath ++ "externals" 36 | 37 | refinesOpts :: [String] 38 | refinesOpts = ["-q", "--format=plain"] 39 | 40 | data TestCase = TestCase 41 | {tcSource :: FilePath, 42 | tcDest :: FilePath, 43 | tcSpec :: FilePath, 44 | tcRuntime :: FilePath} 45 | 46 | testCases :: [TestCase] 47 | testCases = map (tc runtimeLoc) [1..36] 48 | ++ map (tc runtimePTLoc) [37..38] 49 | ++ map (tc runtimeLoc) [39..47] 50 | ++ map (tc runtimePTLoc) [48..49] 51 | ++ map (tc runtimeLoc) [50..54] 52 | where 53 | tc :: FilePath -> Int -> TestCase 54 | tc rt n = TestCase {tcSource=testName ++ ".c", 55 | tcDest =testName ++ ".csp", 56 | tcSpec =testName ++ ".ctest.csp", 57 | tcRuntime=rt} 58 | where 59 | ns = show n 60 | testName = "test_" ++ (replicate (3 - length ns) '0') ++ ns 61 | 62 | 63 | process :: TestCase -> IO Bool 64 | process (TestCase {tcSource,tcDest,tcSpec,tcRuntime}) = do 65 | let di = D.DriverInput {D.diFilename=testPath ++ tcSource, 66 | D.diRuntime=tcRuntime, 67 | D.diCPPOpts = "", 68 | D.diExternals=externalsLoc, 69 | D.diWarn=False, D.diIntermediate=False, 70 | D.diInputList=[]} 71 | 72 | ofile = testPath ++ tcDest 73 | driver = C.genCSP 74 | putStrLn $ "Processing " ++ tcSource ++ "..." 75 | result <- runExceptT $ D.genCode driver di 76 | case result of 77 | Left err -> do putStrLn $ "FAILED\n" ++ err 78 | return False 79 | Right o -> do 80 | D.toFile di ((D.outputLocs ofile) {D.memModelLoc = globVarDecsLoc, 81 | D.stubLoc = stubLoc}) o 82 | (e, out, err) <- readProcessWithExitCode "refines" 83 | [testPath ++ tcSpec, "-q", "--format=plain"] "" 84 | case e of 85 | ExitFailure _ -> do putStrLn $ "FAILED\n" ++ err 86 | return False 87 | ExitSuccess -> if "Failed" `isInfixOf` out 88 | then 89 | do putStrLn $ "FAILED\n" ++ 90 | "In file " ++ ofile ++ "\nFailed assertion:\n" ++ out 91 | return False 92 | else 93 | do putStrLn "SUCCESS" 94 | return True 95 | 96 | makeTest :: (TestCase, Bool) -> T.TestTree 97 | makeTest (TestCase {tcSource}, result) = H.testCase tcSource $ H.assertBool "Result" result 98 | 99 | processedTests :: [IO Bool] 100 | processedTests = map process testCases 101 | 102 | allTests :: IO T.TestTree 103 | allTests = do 104 | results <- sequence processedTests 105 | let zippedResult = zip testCases results 106 | let tests = T.testGroup "CSPGen Tests" $ fmap makeTest zippedResult 107 | return tests 108 | 109 | runtests, runtestsuite :: IO () 110 | runtestsuite = do 111 | tests <- allTests 112 | T.defaultMain tests 113 | 114 | runtests = do 115 | exits <- sequence $ map process testCases 116 | let total = length exits 117 | wins = length (filter id exits) 118 | putStrLn $ "Passed " ++ show wins ++ " of " ++ show total ++ " tests.\n" 119 | -------------------------------------------------------------------------------- /src/Tests/CSPGenTest/Main.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import Tests.CSPGenTest.CSPGenTest 4 | 5 | main :: IO () 6 | main = runtestsuite -------------------------------------------------------------------------------- /src/Tests/LLVMTest/LLVMTest.hs: -------------------------------------------------------------------------------- 1 | module Tests.LLVMTest.LLVMTest where 2 | 3 | import Data.List (isInfixOf) 4 | -- import Control.Monad (when) 5 | import Control.Monad.Except (runExceptT) 6 | 7 | import System.Exit (ExitCode(..)) 8 | import System.Process (readProcessWithExitCode) 9 | 10 | import qualified CodeGen.LLVM.DriverLLVM as L 11 | import qualified CodeGen.Driver as D 12 | 13 | -- import HSH.Command 14 | 15 | import qualified Test.Tasty as T 16 | import qualified Test.Tasty.HUnit as H 17 | 18 | testPath :: FilePath 19 | testPath = "examples/basic/" 20 | 21 | cTestNames :: [String] 22 | cTestNames = (map (\i -> "test_00" ++ show i) ([1..9] :: [Int])) 23 | ++ (map (\i -> "test_0" ++ show i) ([10..59] :: [Int])) 24 | 25 | cppTestNames :: [String] 26 | cppTestNames = map (\i -> "cpp_test_00" ++ show i) ([1..8] :: [Int]) 27 | 28 | globVarDecsLoc :: FilePath 29 | globVarDecsLoc = testPath ++ "globVarDecs.csp" 30 | 31 | stubLoc :: FilePath 32 | stubLoc = testPath ++ "stubs.csp" 33 | 34 | 35 | runtimeLLVM :: FilePath 36 | runtimeLLVM = "runtimeLLVM.csp" 37 | 38 | data TestInfo = TestInfo {testSuffix :: String, 39 | testCompiler :: String, 40 | testFlags :: [String]} 41 | 42 | runTest :: TestInfo -> String -> IO Bool 43 | runTest (TestInfo {testSuffix,testCompiler,testFlags}) testname = do 44 | let cFilename = testPath ++ testname ++ testSuffix 45 | diFilename = testPath ++ testname ++ ".ll" 46 | -- compileCmd = ShellCommand $ "clang -emit-llvm -S " ++ diFilename 47 | di = D.DriverInput {D.diFilename,D.diCPPOpts="",D.diRuntime=runtimeLLVM, 48 | D.diExternals="examples/basic/externalsLLVM", 49 | D.diWarn=False,D.diIntermediate=False,D.diInputList=[]} 50 | 51 | outputFile = testPath ++ testname ++ ".csp" 52 | driver = L.genCSP 53 | putStrLn $ "Processing " ++ testname ++ " for LLVMTest..." 54 | putStrLn "Compiling LLVM from source..." 55 | -- runIo compileCmd 56 | (_, _, _) <- readProcessWithExitCode 57 | testCompiler 58 | (testFlags ++ ["-m32","-emit-llvm","-S","-o",diFilename,cFilename]) 59 | "" 60 | putStrLn "Generating CSP ..." 61 | result <- runExceptT $ D.genCode driver di 62 | case result of 63 | Left err -> do putStrLn $ "FAILED\n" ++ err 64 | return False 65 | Right o -> do 66 | D.toFile di ((D.outputLocs outputFile){D.memModelLoc = globVarDecsLoc, 67 | D.stubLoc = stubLoc}) o 68 | putStrLn "Checking refinement ..." 69 | (e2, out2, err2) <- readProcessWithExitCode "refines" 70 | [testPath ++ testname ++ ".lltest.csp", "-q", "--format=plain"] "" 71 | case e2 of 72 | ExitFailure _ -> do putStrLn $ "FAILED\n" ++ err2 73 | return False 74 | ExitSuccess -> if "Failed" `isInfixOf` out2 75 | then 76 | do putStrLn $ "FAILED\n" ++ 77 | "In file " ++ outputFile ++ "\nFailed assertion:\n" ++ out2 78 | return False 79 | else 80 | do putStrLn "SUCCESS" 81 | return True 82 | 83 | makeTest :: (String, Bool) -> T.TestTree 84 | makeTest (file, result) = H.testCase file $ H.assertBool "Result" result 85 | 86 | cTestResults :: [IO Bool] 87 | cTestResults = map (runTest tinfo) cTestNames 88 | where 89 | tinfo = TestInfo {testSuffix=".c", 90 | testCompiler="clang", 91 | testFlags=[]} 92 | 93 | cppTestResults :: [IO Bool] 94 | cppTestResults = map (runTest tinfo) cppTestNames 95 | where 96 | tinfo = TestInfo {testSuffix=".cpp", 97 | testCompiler="clang++", 98 | testFlags=["-fno-rtti"]} 99 | 100 | allTests :: IO T.TestTree 101 | allTests = do 102 | cresults <- sequence cTestResults 103 | cppresults <- sequence cppTestResults 104 | let zippedResult = zip (cTestNames ++ cppTestNames) 105 | (cresults ++ cppresults) 106 | let tests = T.testGroup "DriverLLVM Tests" $ fmap makeTest zippedResult 107 | return tests 108 | 109 | runtests, runtestsuite :: IO () 110 | runtestsuite = do 111 | tests <- allTests 112 | T.defaultMain tests 113 | 114 | runtests = do 115 | exits <- sequence (cTestResults ++ cppTestResults) 116 | let total = length exits 117 | wins = length (filter id exits) 118 | putStrLn $ "Passed " ++ show wins ++ " of " ++ show total ++ " tests.\n" 119 | 120 | -------------------------------------------------------------------------------- /src/Tests/LLVMTest/Main.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import Tests.LLVMTest.LLVMTest 4 | 5 | main :: IO () 6 | main = runtestsuite 7 | -------------------------------------------------------------------------------- /verif/Makefile: -------------------------------------------------------------------------------- 1 | 2 | COQFILES = CSP_Syntax.v CSP_OpSem.v While_Definitions.v Translation.v 3 | 4 | 5 | all : coq 6 | 7 | coq: Makefile $(COQFILES) 8 | coqc $(COQFILES) 9 | 10 | clean : 11 | rm -f *.vo *~ *.glob 12 | 13 | -------------------------------------------------------------------------------- /verif/README.md: -------------------------------------------------------------------------------- 1 | This directory contains a Coq verification of cspgen's core translation for a 2 | toy imperative language. Roughly, we prove that, for any execution of a program 3 | in the operational semantics of the imperative language, there is a 4 | corresponding trace of its translated CSP process. The imperative language is 5 | similar to the one that appears in the "Imp" chapter of Software Foundations, 6 | which it itself based on Winskel's classic book. 7 | 8 | There are four files: 9 | 10 | - `CSP_Syntax.v`, which contains the CSP AST. 11 | 12 | - `CSP_OpSem.v`, which contains the CSP operational semantics. 13 | 14 | - `While_Definitions.v`, which contains the imperative syntax and operational 15 | semantics. 16 | 17 | - `Translation.v`, which contains the translation and proof of correctness. 18 | 19 | You can run "make all" to build everything. This is all known to compile with 20 | Coq 8.5pl2. The scripts are not very clean, so future versions of Coq may break 21 | them (changes in name generation often break this kind of proof). 22 | --------------------------------------------------------------------------------