├── CMakeLists.txt
├── LICENSE.txt
├── README.txt
├── TODO.txt
├── cmake
└── modules
│ └── FindReadline.cmake
├── diff_clang_source_files.sh
├── docs
├── Makefile
├── _build
│ ├── doctrees
│ │ ├── environment.pickle
│ │ └── index.doctree
│ └── html
│ │ ├── .buildinfo
│ │ ├── _sources
│ │ └── index.txt
│ │ ├── _static
│ │ ├── ajax-loader.gif
│ │ ├── basic.css
│ │ ├── comment-bright.png
│ │ ├── comment-close.png
│ │ ├── comment.png
│ │ ├── default.css
│ │ ├── doctools.js
│ │ ├── down-pressed.png
│ │ ├── down.png
│ │ ├── file.png
│ │ ├── jquery.js
│ │ ├── minus.png
│ │ ├── plus.png
│ │ ├── pygments.css
│ │ ├── searchtools.js
│ │ ├── sidebar.js
│ │ ├── underscore.js
│ │ ├── up-pressed.png
│ │ ├── up.png
│ │ └── websupport.js
│ │ ├── genindex.html
│ │ ├── index.html
│ │ ├── objects.inv
│ │ ├── search.html
│ │ └── searchindex.js
├── conf.py
├── index.rst
└── make.bat
├── pull_clang_source_files.sh
├── push_clang_source_files.sh
├── src
├── CMakeLists.txt
├── backend
│ ├── CMakeLists.txt
│ ├── jagger
│ │ ├── codegen.cpp
│ │ ├── instructionstream.cpp
│ │ ├── interface.h
│ │ ├── print.cpp
│ │ └── types.h
│ ├── llvm
│ │ ├── CMakeLists.txt
│ │ ├── IRGen.cpp
│ │ └── IRGen.h
│ └── x64builder
│ │ ├── CMakeLists.txt
│ │ ├── instr.h
│ │ ├── instrbuilder.h
│ │ ├── template.cpp
│ │ └── x64builder.cpp
├── base
│ ├── ArrayTree.h
│ ├── CMakeLists.txt
│ ├── DiagnosticEmitter.h
│ ├── LLVMDependencies.h
│ ├── MemRegion.cpp
│ ├── MemRegion.h
│ ├── MutArrayRef.h
│ ├── NestedStack.h
│ └── SimpleArray.h
├── clang
│ ├── ClangCFGWalker.h
│ ├── ClangTranslator.cpp
│ ├── ClangTranslator.h
│ ├── README.txt
│ ├── diff_clang_source_files.sh
│ ├── pull_clang_source_files.sh
│ └── push_clang_source_files.sh
├── grammar
│ ├── CMakeLists.txt
│ ├── ohmu.grammar
│ ├── parser.grammar
│ └── sexpr.grammar
├── lsa
│ ├── BuildCallGraph.cpp
│ ├── BuildCallGraph.h
│ ├── CMakeLists.txt
│ ├── GraphComputation.h
│ ├── GraphDeserializer.h
│ ├── GraphSerializer.h
│ ├── StandaloneGraphComputation.h
│ ├── StandaloneRunner.h
│ └── examples
│ │ ├── CMakeLists.txt
│ │ ├── EscapeAnalysis.cpp
│ │ ├── EscapeAnalysis.h
│ │ ├── ExampleOhmuComputation.h
│ │ ├── SCCComputation.cpp
│ │ └── SCCComputation.h
├── ohmu
│ ├── examples
│ │ └── argument_dependencies.ohmu
│ ├── test_cfg.ohmu
│ ├── test_dependent_functions.ohmu
│ ├── test_literal.ohmu
│ ├── test_loop.ohmu
│ ├── test_module.ohmu
│ ├── test_scalartypes.ohmu
│ └── test_ssa.ohmu
├── parser
│ ├── ASTNode.cpp
│ ├── ASTNode.h
│ ├── BNFParser.cpp
│ ├── BNFParser.h
│ ├── CMakeLists.txt
│ ├── DefaultLexer.cpp
│ ├── DefaultLexer.h
│ ├── Lexer.cpp
│ ├── Lexer.h
│ ├── Parser.cpp
│ ├── Parser.h
│ ├── ParserBuilder.h
│ ├── TILParser.cpp
│ ├── TILParser.h
│ └── Token.h
├── test
│ ├── CMakeLists.txt
│ ├── Driver.h
│ ├── backend
│ │ ├── CMakeLists.txt
│ │ └── test_llvm.cpp
│ ├── base
│ │ ├── CMakeLists.txt
│ │ └── test_base.cpp
│ ├── lsa
│ │ ├── CMakeLists.txt
│ │ ├── escape_analysis.cpp
│ │ ├── generate_callgraph.cpp
│ │ ├── globals_analysis.cpp
│ │ ├── run_test_lsa.sh
│ │ ├── scc_analysis.cpp
│ │ ├── test_input_callgraph.cpp
│ │ ├── test_input_escape.cpp
│ │ ├── test_input_global_vars.cpp
│ │ └── test_input_scc.cpp
│ ├── parser
│ │ ├── CMakeLists.txt
│ │ ├── test_BNFParser.cpp
│ │ └── test_parser.cpp
│ └── til
│ │ ├── CMakeLists.txt
│ │ ├── test_compare.cpp
│ │ ├── test_copier.cpp
│ │ ├── test_serialization.cpp
│ │ └── test_visitor.cpp
├── til
│ ├── Annotation.h
│ ├── AnnotationImpl.cpp
│ ├── AnnotationImpl.h
│ ├── AttributeGrammar.h
│ ├── Bytecode.cpp
│ ├── Bytecode.h
│ ├── CFGBuilder.cpp
│ ├── CFGBuilder.h
│ ├── CMakeLists.txt
│ ├── CopyReducer.h
│ ├── Evaluator.h
│ ├── Global.cpp
│ ├── Global.h
│ ├── InplaceReducer.h
│ ├── README.txt
│ ├── SSAPass.cpp
│ ├── SSAPass.h
│ ├── TIL.cpp
│ ├── TIL.h
│ ├── TILAnnKinds.def
│ ├── TILBaseType.h
│ ├── TILCompare.h
│ ├── TILOps.def
│ ├── TILPrettyPrint.h
│ ├── TILTraverse.h
│ ├── TILVisitor.h
│ ├── TypedEvaluator.cpp
│ ├── TypedEvaluator.h
│ └── VisitCFG.h
└── unittests
│ ├── CMakeLists.txt
│ └── lsa
│ ├── BuildCallGraphTest.cpp
│ ├── CMakeLists.txt
│ ├── SCCComputationTest.cpp
│ └── StandaloneGraphComputationTest.cpp
└── temp.ohmu
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8)
2 |
3 | # set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/")
4 |
5 | set( CMAKE_EXPORT_COMPILE_COMMANDS 1 )
6 |
7 | add_subdirectory (src)
8 |
--------------------------------------------------------------------------------
/README.txt:
--------------------------------------------------------------------------------
1 |
2 | Ohmu is a new programming language being developed at Google. Right now, it
3 | is just a hobby project that a few engineers are working on in their spare
4 | time. Its purpose is to serve as a sandbox for experimenting with various
5 | compiler technologies, such as type systems, partial evaluation, run-time
6 | code generation, and GPU programming.
7 |
8 | *Disclaimer*: There are no plans to use ohmu internally or to release it as
9 | a real product. Anything and everything is subject to change without
10 | notice. May be known to the State of California to cause cancer in lab
11 | animals, including engineers in computer labs. Do not eat.
12 |
13 |
14 | Build Instructions:
15 |
16 | (1) Install the ohmu source code into a directory, e.g. ohmu.
17 | (2) mkdir ohmu_build (make this directory alongside ohmu)
18 | (3) cd ohmu_build
19 | (4) ccmake ../ohmu
20 | (5) Go to advanced mode
21 | (6) [Optional] Change compiler to clang.
22 | (7) Change LLVM_DIR to "$LLVM_INSTALL_DIR"/share/llvm/cmake/
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/TODO.txt:
--------------------------------------------------------------------------------
1 |
2 | This is a list of bugs and missing functionality that needs to be fixed in
3 | the near term.
4 |
5 | Front-end
6 | =========
7 |
8 | (p1) Parsing of float and integer literals of different widths.
9 | (p1) Report position of syntax errors.
10 |
11 | (p2) Better recovery after parse errors.
12 |
13 |
14 | Middle-end
15 | ==========
16 |
17 | (p1) Add CFG simplification & cleanup pass (unused phi, dup vars, empty BBs)
18 | (p1) Add records, slots, and inheritance.
19 | (p1) Add arithmetic up-conversions and type-checking.
20 | (p1) Calculate numUses and distance metric for variables.
21 |
22 | (p2) Add initial type-checking pass.
23 | (p2) Implement lazy rewriting.
24 | (p2) Implement partial evaluator.
25 |
26 |
27 | Back-end
28 | =========
29 |
30 | (p1) Find and solve constraints.
31 | (p1) Register allocation.
32 | (p1) Emit x86 instructions for CFG.
33 | (p1) JIT-compiler. (Create code page, emit instructions to code page, and run.)
34 |
35 |
36 | Misc
37 | ====
38 |
39 | (p1) Make test infrastructure to automatically run tests.
40 |
--------------------------------------------------------------------------------
/cmake/modules/FindReadline.cmake:
--------------------------------------------------------------------------------
1 | # Code copied from sethhall@github
2 | #
3 | # - Try to find readline include dirs and libraries
4 | #
5 | # Usage of this module as follows:
6 | #
7 | # find_package(Readline)
8 | #
9 | # Variables used by this module, they can change the default behaviour and need
10 | # to be set before calling find_package:
11 | #
12 | # Readline_ROOT_DIR Set this variable to the root installation of
13 | # readline if the module has problems finding the
14 | # proper installation path.
15 | #
16 | # Variables defined by this module:
17 | #
18 | # READLINE_FOUND System has readline, include and lib dirs found
19 | # Readline_INCLUDE_DIR The readline include directories.
20 | # Readline_LIBRARY The readline library.
21 |
22 | find_path(Readline_ROOT_DIR
23 | NAMES include/readline/readline.h
24 | )
25 |
26 | find_path(Readline_INCLUDE_DIR
27 | NAMES readline/readline.h
28 | HINTS ${Readline_ROOT_DIR}/include
29 | )
30 |
31 | find_library(Readline_LIBRARY
32 | NAMES readline
33 | HINTS ${Readline_ROOT_DIR}/lib
34 | )
35 |
36 | if(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY)
37 | set(READLINE_FOUND TRUE)
38 | else(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY)
39 | FIND_LIBRARY(Readline_LIBRARY NAMES readline)
40 | include(FindPackageHandleStandardArgs)
41 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(Readline DEFAULT_MSG Readline_INCLUDE_DIR Readline_LIBRARY )
42 | MARK_AS_ADVANCED(Readline_INCLUDE_DIR Readline_LIBRARY)
43 | endif(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY)
44 |
45 | mark_as_advanced(
46 | Readline_ROOT_DIR
47 | Readline_INCLUDE_DIR
48 | Readline_LIBRARY
49 | )
50 |
--------------------------------------------------------------------------------
/diff_clang_source_files.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | CLANG_INC="$1"/tools/clang/include/clang/Analysis/Til
4 | CLANG_LIB="$1"/tools/clang/lib/Analysis/Til
5 |
6 | diff -u "$CLANG_INC"/base/SimpleArray.h src/base/SimpleArray.h
7 | diff -u "$CLANG_INC"/base/MutArrayRef.h src/base/MutArrayRef.h
8 | diff -u "$CLANG_INC"/base/ArrayTree.h src/base/ArrayTree.h
9 |
10 | diff -u "$CLANG_INC"/TILOps.def src/til/TILOps.def
11 | diff -u "$CLANG_INC"/TILAnnKinds.def src/til/TILAnnKinds.def
12 | diff -u "$CLANG_INC"/TILBaseType.h src/til/TILBaseType.h
13 | diff -u "$CLANG_INC"/TIL.h src/til/TIL.h
14 | diff -u "$CLANG_INC"/TILTraverse.h src/til/TILTraverse.h
15 | diff -u "$CLANG_INC"/TILCompare.h src/til/TILCompare.h
16 | diff -u "$CLANG_INC"/TILPrettyPrint.h src/til/TILPrettyPrint.h
17 | diff -u "$CLANG_INC"/Annotation.h src/til/Annotation.h
18 | diff -u "$CLANG_INC"/AnnotationImpl.h src/til/AnnotationImpl.h
19 | diff -u "$CLANG_INC"/CFGBuilder.h src/til/CFGBuilder.h
20 | diff -u "$CLANG_INC"/AttributeGrammar.h src/til/AttributeGrammar.h
21 | diff -u "$CLANG_INC"/CopyReducer.h src/til/CopyReducer.h
22 | diff -u "$CLANG_INC"/InplaceReducer.h src/til/InplaceReducer.h
23 | diff -u "$CLANG_INC"/SSAPass.h src/til/SSAPass.h
24 | diff -u "$CLANG_INC"/Bytecode.h src/til/Bytecode.h
25 |
26 | diff -u "$CLANG_LIB"/TIL.cpp src/til/TIL.cpp
27 | diff -u "$CLANG_LIB"/CFGBuilder.cpp src/til/CFGBuilder.cpp
28 | diff -u "$CLANG_LIB"/SSAPass.cpp src/til/SSAPass.cpp
29 | diff -u "$CLANG_LIB"/AnnotationImpl.cpp src/til/AnnotationImpl.cpp
30 | diff -u "$CLANG_LIB"/Bytecode.cpp src/til/Bytecode.cpp
31 |
--------------------------------------------------------------------------------
/docs/_build/doctrees/environment.pickle:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ohmu/33991d1bb655ab26ce1f172fdea0fd7eef32e763/docs/_build/doctrees/environment.pickle
--------------------------------------------------------------------------------
/docs/_build/doctrees/index.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ohmu/33991d1bb655ab26ce1f172fdea0fd7eef32e763/docs/_build/doctrees/index.doctree
--------------------------------------------------------------------------------
/docs/_build/html/.buildinfo:
--------------------------------------------------------------------------------
1 | # Sphinx build info version 1
2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
3 | config: eafa5706c0f674d809f34c0c3bbed28b
4 | tags: fbb0d17656682115ca4d033fb2f83ba1
5 |
--------------------------------------------------------------------------------
/docs/_build/html/_sources/index.txt:
--------------------------------------------------------------------------------
1 | .. ohmu documentation master file, created by
2 | sphinx-quickstart on Sun May 11 10:04:06 2014.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Contents
7 | ==================
8 |
9 | .. toctree::
10 | :maxdepth: 2
11 |
12 |
13 | Introduction
14 | ============
15 |
16 | Ohmu is a new programming language being developed at Google. Right now, it
17 | is just a hobby project that a few engineers are working on in their spare
18 | time. Its purpose is to serve as a sandbox for experimenting with various
19 | compiler technologies, such as type systems, partial evaluation, run-time code
20 | generation, and GPU programming.
21 |
22 | *Disclaimer*: There are no plans to use ohmu internally or to release it as a
23 | real product. Anything and everything is subject to change without notice.
24 | May be known to the State of California to cause cancer in lab animals,
25 | including engineers in computer labs. Do not eat.
26 |
27 | Why a new language?
28 | -------------------
29 |
30 | We believe that a good programming language is one where the tool chain
31 | provides as much assistance as possible. Optimizing compilers improve
32 | performance, type systems and warnings help find bugs, while IDEs and
33 | refactoring tools help organize and maintain code. These tools are effective
34 | only if the language itself has a well-defined semantics, so that the compiler
35 | or IDE can analyze and understand the code.
36 |
37 | Unfortunately, most practical programming languages have a semantics that is
38 | informal, ad-hoc, overly complex, or unsound in various ways, which tends to
39 | confound any attempt at analysis. A great deal of academic research has been
40 | done in the area of formal programming language semantics, but academic
41 | languages go too far in the other direction; they are either too formal (e.g.
42 | Agda) or impractical for most real-world tasks (e.g. Haskell).
43 |
44 | Our goal is to collect the best ideas from academic research, combine those
45 | ideas together, and apply them to the design of a modern, elegant, and above
46 | all, a *practical* language.
47 |
48 | Overview of Language Features
49 | -----------------------------
50 |
51 | * High performance:
52 |
53 | * Faster than C.
54 | * Suitable for systems programming, games, or scientific computation.
55 | * Transparent foreign-function interface to C and C++ code.
56 | * Transparent support for GPGPU programming.
57 | * Advanced optimizations driven by static analysis (e.g. alias analysis).
58 |
59 | * Safe:
60 |
61 | * Type and memory safe. No unsafe casts or buffer overflows...
62 | * Thread-safe by design. No race conditions...
63 | * Designed from the ground-up for static analysis.
64 |
65 | * Modular and high-level:
66 |
67 | * Object-oriented programming: classes, inheritance, generics, and mixins.
68 | * Functional programming: type-classes, variant data types, and ADTs.
69 | * Mixin-modules: virtual classes and extensible data types.
70 |
71 | * Extensible:
72 |
73 | * *Extensible syntax*: libraries can extend the language with new syntax.
74 | * *Partial evaluation*: compile language extensions down to the core language.
75 | * Compile-time reflection and meta-programming.
76 | * Support for embedding domain-specific languages (DSLs):
77 |
78 | * E.g. parser generators, matrix libraries, image filters, shaders, etc.
79 |
80 |
81 | Key Technologies
82 | ^^^^^^^^^^^^^^^^
83 |
84 | Although this may look like a long wish-list, all of these features depend
85 | primarily on just two key technologies:
86 |
87 | #. A sophisticated static type system.
88 | #. Partial evaluation.
89 |
90 | **Type system**. Type systems are routinely used to handle structural types,
91 | such as ``int`` and ``String``. However, they can do much more than that.
92 | Type systems a general purpose tool for declaring and enforcing any program
93 | invariant, including aliasing constraints, ownership, or freedom from race
94 | conditions. The ohmu type system is responsible for the *safety* features
95 | above, and it is a key part of *modularity*, since mixin modules have very
96 | complex types. Moreover, the type system enforces program invariants that are
97 | then used by the optimizer to achieve *high performance*.
98 |
99 | **Partial evaluation**. Partial evaluation optimizes code by shifting
100 | computations from run-time to compile-time. Most compilers can perform
101 | constant propogation. However, the ohmu compiler can perform arbitrary
102 | computations at compile-time. Moreover, the partial evaluator is linked to
103 | the static type system, which enables it to perform type-based
104 | transformations, like method de-virtualization. The *extensibility* features
105 | use partial evaluation to eliminate the run-time overhead that is generally
106 | associated with reflection and DSLs.
107 |
108 |
109 | Tradeoffs in Language Design
110 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
111 |
112 | There has traditionally been a tradeoff in language design between performance
113 | and safety. A safe language must perform additional run-time checks, such as
114 | array bounds checks, to prevent unsafe operations from occuring. Ohmu
115 | leverages the type system to achieve both performance and safety at the same
116 | time. E.g. if the type system can prove that the array bounds check always
117 | succeeds, then run-time check can be omitted.
118 |
119 | Similarly, there has traditionally been a tradeoff between performance and
120 | high-level abstractions. Abstractions introduce an additional level of
121 | indirection, which usually has a run-time cost. For example, object-oriented
122 | inheritance and virtual methods are a useful abstraction, but most compilers
123 | cannot inline virtual methods, so they have a high cost. Ohmu leverages
124 | partial evaluation to eliminate the overhead of most abstractions. For
125 | example, the partial evaluator can specialize a polymorphic function to a
126 | concrete type, thus allowing the virtual calls to be eliminated.
127 |
128 |
129 | Indices and tables
130 | ==================
131 |
132 | * :ref:`genindex`
133 | * :ref:`modindex`
134 | * :ref:`search`
135 |
136 |
--------------------------------------------------------------------------------
/docs/_build/html/_static/ajax-loader.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ohmu/33991d1bb655ab26ce1f172fdea0fd7eef32e763/docs/_build/html/_static/ajax-loader.gif
--------------------------------------------------------------------------------
/docs/_build/html/_static/comment-bright.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ohmu/33991d1bb655ab26ce1f172fdea0fd7eef32e763/docs/_build/html/_static/comment-bright.png
--------------------------------------------------------------------------------
/docs/_build/html/_static/comment-close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ohmu/33991d1bb655ab26ce1f172fdea0fd7eef32e763/docs/_build/html/_static/comment-close.png
--------------------------------------------------------------------------------
/docs/_build/html/_static/comment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ohmu/33991d1bb655ab26ce1f172fdea0fd7eef32e763/docs/_build/html/_static/comment.png
--------------------------------------------------------------------------------
/docs/_build/html/_static/default.css:
--------------------------------------------------------------------------------
1 | /*
2 | * default.css_t
3 | * ~~~~~~~~~~~~~
4 | *
5 | * Sphinx stylesheet -- default theme.
6 | *
7 | * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
8 | * :license: BSD, see LICENSE for details.
9 | *
10 | */
11 |
12 | @import url("basic.css");
13 |
14 | /* -- page layout ----------------------------------------------------------- */
15 |
16 | body {
17 | font-family: sans-serif;
18 | font-size: 100%;
19 | background-color: #11303d;
20 | color: #000;
21 | margin: 0;
22 | padding: 0;
23 | }
24 |
25 | div.document {
26 | background-color: #1c4e63;
27 | }
28 |
29 | div.documentwrapper {
30 | float: left;
31 | width: 100%;
32 | }
33 |
34 | div.bodywrapper {
35 | margin: 0 0 0 230px;
36 | }
37 |
38 | div.body {
39 | background-color: #ffffff;
40 | color: #000000;
41 | padding: 0 20px 30px 20px;
42 | }
43 |
44 | div.footer {
45 | color: #ffffff;
46 | width: 100%;
47 | padding: 9px 0 9px 0;
48 | text-align: center;
49 | font-size: 75%;
50 | }
51 |
52 | div.footer a {
53 | color: #ffffff;
54 | text-decoration: underline;
55 | }
56 |
57 | div.related {
58 | background-color: #133f52;
59 | line-height: 30px;
60 | color: #ffffff;
61 | }
62 |
63 | div.related a {
64 | color: #ffffff;
65 | }
66 |
67 | div.sphinxsidebar {
68 | }
69 |
70 | div.sphinxsidebar h3 {
71 | font-family: 'Trebuchet MS', sans-serif;
72 | color: #ffffff;
73 | font-size: 1.4em;
74 | font-weight: normal;
75 | margin: 0;
76 | padding: 0;
77 | }
78 |
79 | div.sphinxsidebar h3 a {
80 | color: #ffffff;
81 | }
82 |
83 | div.sphinxsidebar h4 {
84 | font-family: 'Trebuchet MS', sans-serif;
85 | color: #ffffff;
86 | font-size: 1.3em;
87 | font-weight: normal;
88 | margin: 5px 0 0 0;
89 | padding: 0;
90 | }
91 |
92 | div.sphinxsidebar p {
93 | color: #ffffff;
94 | }
95 |
96 | div.sphinxsidebar p.topless {
97 | margin: 5px 10px 10px 10px;
98 | }
99 |
100 | div.sphinxsidebar ul {
101 | margin: 10px;
102 | padding: 0;
103 | color: #ffffff;
104 | }
105 |
106 | div.sphinxsidebar a {
107 | color: #98dbcc;
108 | }
109 |
110 | div.sphinxsidebar input {
111 | border: 1px solid #98dbcc;
112 | font-family: sans-serif;
113 | font-size: 1em;
114 | }
115 |
116 |
117 |
118 | /* -- hyperlink styles ------------------------------------------------------ */
119 |
120 | a {
121 | color: #355f7c;
122 | text-decoration: none;
123 | }
124 |
125 | a:visited {
126 | color: #355f7c;
127 | text-decoration: none;
128 | }
129 |
130 | a:hover {
131 | text-decoration: underline;
132 | }
133 |
134 |
135 |
136 | /* -- body styles ----------------------------------------------------------- */
137 |
138 | div.body h1,
139 | div.body h2,
140 | div.body h3,
141 | div.body h4,
142 | div.body h5,
143 | div.body h6 {
144 | font-family: 'Trebuchet MS', sans-serif;
145 | background-color: #f2f2f2;
146 | font-weight: normal;
147 | color: #20435c;
148 | border-bottom: 1px solid #ccc;
149 | margin: 20px -20px 10px -20px;
150 | padding: 3px 0 3px 10px;
151 | }
152 |
153 | div.body h1 { margin-top: 0; font-size: 200%; }
154 | div.body h2 { font-size: 160%; }
155 | div.body h3 { font-size: 140%; }
156 | div.body h4 { font-size: 120%; }
157 | div.body h5 { font-size: 110%; }
158 | div.body h6 { font-size: 100%; }
159 |
160 | a.headerlink {
161 | color: #c60f0f;
162 | font-size: 0.8em;
163 | padding: 0 4px 0 4px;
164 | text-decoration: none;
165 | }
166 |
167 | a.headerlink:hover {
168 | background-color: #c60f0f;
169 | color: white;
170 | }
171 |
172 | div.body p, div.body dd, div.body li {
173 | text-align: justify;
174 | line-height: 130%;
175 | }
176 |
177 | div.admonition p.admonition-title + p {
178 | display: inline;
179 | }
180 |
181 | div.admonition p {
182 | margin-bottom: 5px;
183 | }
184 |
185 | div.admonition pre {
186 | margin-bottom: 5px;
187 | }
188 |
189 | div.admonition ul, div.admonition ol {
190 | margin-bottom: 5px;
191 | }
192 |
193 | div.note {
194 | background-color: #eee;
195 | border: 1px solid #ccc;
196 | }
197 |
198 | div.seealso {
199 | background-color: #ffc;
200 | border: 1px solid #ff6;
201 | }
202 |
203 | div.topic {
204 | background-color: #eee;
205 | }
206 |
207 | div.warning {
208 | background-color: #ffe4e4;
209 | border: 1px solid #f66;
210 | }
211 |
212 | p.admonition-title {
213 | display: inline;
214 | }
215 |
216 | p.admonition-title:after {
217 | content: ":";
218 | }
219 |
220 | pre {
221 | padding: 5px;
222 | background-color: #eeffcc;
223 | color: #333333;
224 | line-height: 120%;
225 | border: 1px solid #ac9;
226 | border-left: none;
227 | border-right: none;
228 | }
229 |
230 | tt {
231 | background-color: #ecf0f3;
232 | padding: 0 1px 0 1px;
233 | font-size: 0.95em;
234 | }
235 |
236 | th {
237 | background-color: #ede;
238 | }
239 |
240 | .warning tt {
241 | background: #efc2c2;
242 | }
243 |
244 | .note tt {
245 | background: #d6d6d6;
246 | }
247 |
248 | .viewcode-back {
249 | font-family: sans-serif;
250 | }
251 |
252 | div.viewcode-block:target {
253 | background-color: #f4debf;
254 | border-top: 1px solid #ac9;
255 | border-bottom: 1px solid #ac9;
256 | }
--------------------------------------------------------------------------------
/docs/_build/html/_static/down-pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ohmu/33991d1bb655ab26ce1f172fdea0fd7eef32e763/docs/_build/html/_static/down-pressed.png
--------------------------------------------------------------------------------
/docs/_build/html/_static/down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ohmu/33991d1bb655ab26ce1f172fdea0fd7eef32e763/docs/_build/html/_static/down.png
--------------------------------------------------------------------------------
/docs/_build/html/_static/file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ohmu/33991d1bb655ab26ce1f172fdea0fd7eef32e763/docs/_build/html/_static/file.png
--------------------------------------------------------------------------------
/docs/_build/html/_static/minus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ohmu/33991d1bb655ab26ce1f172fdea0fd7eef32e763/docs/_build/html/_static/minus.png
--------------------------------------------------------------------------------
/docs/_build/html/_static/plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ohmu/33991d1bb655ab26ce1f172fdea0fd7eef32e763/docs/_build/html/_static/plus.png
--------------------------------------------------------------------------------
/docs/_build/html/_static/pygments.css:
--------------------------------------------------------------------------------
1 | .highlight .hll { background-color: #ffffcc }
2 | .highlight { background: #eeffcc; }
3 | .highlight .c { color: #408090; font-style: italic } /* Comment */
4 | .highlight .err { border: 1px solid #FF0000 } /* Error */
5 | .highlight .k { color: #007020; font-weight: bold } /* Keyword */
6 | .highlight .o { color: #666666 } /* Operator */
7 | .highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */
8 | .highlight .cp { color: #007020 } /* Comment.Preproc */
9 | .highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */
10 | .highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
11 | .highlight .gd { color: #A00000 } /* Generic.Deleted */
12 | .highlight .ge { font-style: italic } /* Generic.Emph */
13 | .highlight .gr { color: #FF0000 } /* Generic.Error */
14 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
15 | .highlight .gi { color: #00A000 } /* Generic.Inserted */
16 | .highlight .go { color: #303030 } /* Generic.Output */
17 | .highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
18 | .highlight .gs { font-weight: bold } /* Generic.Strong */
19 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
20 | .highlight .gt { color: #0040D0 } /* Generic.Traceback */
21 | .highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
22 | .highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
23 | .highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
24 | .highlight .kp { color: #007020 } /* Keyword.Pseudo */
25 | .highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
26 | .highlight .kt { color: #902000 } /* Keyword.Type */
27 | .highlight .m { color: #208050 } /* Literal.Number */
28 | .highlight .s { color: #4070a0 } /* Literal.String */
29 | .highlight .na { color: #4070a0 } /* Name.Attribute */
30 | .highlight .nb { color: #007020 } /* Name.Builtin */
31 | .highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
32 | .highlight .no { color: #60add5 } /* Name.Constant */
33 | .highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */
34 | .highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */
35 | .highlight .ne { color: #007020 } /* Name.Exception */
36 | .highlight .nf { color: #06287e } /* Name.Function */
37 | .highlight .nl { color: #002070; font-weight: bold } /* Name.Label */
38 | .highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
39 | .highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */
40 | .highlight .nv { color: #bb60d5 } /* Name.Variable */
41 | .highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
42 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */
43 | .highlight .mf { color: #208050 } /* Literal.Number.Float */
44 | .highlight .mh { color: #208050 } /* Literal.Number.Hex */
45 | .highlight .mi { color: #208050 } /* Literal.Number.Integer */
46 | .highlight .mo { color: #208050 } /* Literal.Number.Oct */
47 | .highlight .sb { color: #4070a0 } /* Literal.String.Backtick */
48 | .highlight .sc { color: #4070a0 } /* Literal.String.Char */
49 | .highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
50 | .highlight .s2 { color: #4070a0 } /* Literal.String.Double */
51 | .highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
52 | .highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */
53 | .highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
54 | .highlight .sx { color: #c65d09 } /* Literal.String.Other */
55 | .highlight .sr { color: #235388 } /* Literal.String.Regex */
56 | .highlight .s1 { color: #4070a0 } /* Literal.String.Single */
57 | .highlight .ss { color: #517918 } /* Literal.String.Symbol */
58 | .highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
59 | .highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
60 | .highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
61 | .highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
62 | .highlight .il { color: #208050 } /* Literal.Number.Integer.Long */
--------------------------------------------------------------------------------
/docs/_build/html/_static/sidebar.js:
--------------------------------------------------------------------------------
1 | /*
2 | * sidebar.js
3 | * ~~~~~~~~~~
4 | *
5 | * This script makes the Sphinx sidebar collapsible.
6 | *
7 | * .sphinxsidebar contains .sphinxsidebarwrapper. This script adds
8 | * in .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton
9 | * used to collapse and expand the sidebar.
10 | *
11 | * When the sidebar is collapsed the .sphinxsidebarwrapper is hidden
12 | * and the width of the sidebar and the margin-left of the document
13 | * are decreased. When the sidebar is expanded the opposite happens.
14 | * This script saves a per-browser/per-session cookie used to
15 | * remember the position of the sidebar among the pages.
16 | * Once the browser is closed the cookie is deleted and the position
17 | * reset to the default (expanded).
18 | *
19 | * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
20 | * :license: BSD, see LICENSE for details.
21 | *
22 | */
23 |
24 | $(function() {
25 | // global elements used by the functions.
26 | // the 'sidebarbutton' element is defined as global after its
27 | // creation, in the add_sidebar_button function
28 | var bodywrapper = $('.bodywrapper');
29 | var sidebar = $('.sphinxsidebar');
30 | var sidebarwrapper = $('.sphinxsidebarwrapper');
31 |
32 | // for some reason, the document has no sidebar; do not run into errors
33 | if (!sidebar.length) return;
34 |
35 | // original margin-left of the bodywrapper and width of the sidebar
36 | // with the sidebar expanded
37 | var bw_margin_expanded = bodywrapper.css('margin-left');
38 | var ssb_width_expanded = sidebar.width();
39 |
40 | // margin-left of the bodywrapper and width of the sidebar
41 | // with the sidebar collapsed
42 | var bw_margin_collapsed = '.8em';
43 | var ssb_width_collapsed = '.8em';
44 |
45 | // colors used by the current theme
46 | var dark_color = $('.related').css('background-color');
47 | var light_color = $('.document').css('background-color');
48 |
49 | function sidebar_is_collapsed() {
50 | return sidebarwrapper.is(':not(:visible)');
51 | }
52 |
53 | function toggle_sidebar() {
54 | if (sidebar_is_collapsed())
55 | expand_sidebar();
56 | else
57 | collapse_sidebar();
58 | }
59 |
60 | function collapse_sidebar() {
61 | sidebarwrapper.hide();
62 | sidebar.css('width', ssb_width_collapsed);
63 | bodywrapper.css('margin-left', bw_margin_collapsed);
64 | sidebarbutton.css({
65 | 'margin-left': '0',
66 | 'height': bodywrapper.height()
67 | });
68 | sidebarbutton.find('span').text('»');
69 | sidebarbutton.attr('title', _('Expand sidebar'));
70 | document.cookie = 'sidebar=collapsed';
71 | }
72 |
73 | function expand_sidebar() {
74 | bodywrapper.css('margin-left', bw_margin_expanded);
75 | sidebar.css('width', ssb_width_expanded);
76 | sidebarwrapper.show();
77 | sidebarbutton.css({
78 | 'margin-left': ssb_width_expanded-12,
79 | 'height': bodywrapper.height()
80 | });
81 | sidebarbutton.find('span').text('«');
82 | sidebarbutton.attr('title', _('Collapse sidebar'));
83 | document.cookie = 'sidebar=expanded';
84 | }
85 |
86 | function add_sidebar_button() {
87 | sidebarwrapper.css({
88 | 'float': 'left',
89 | 'margin-right': '0',
90 | 'width': ssb_width_expanded - 28
91 | });
92 | // create the button
93 | sidebar.append(
94 | '
'
95 | );
96 | var sidebarbutton = $('#sidebarbutton');
97 | light_color = sidebarbutton.css('background-color');
98 | // find the height of the viewport to center the '<<' in the page
99 | var viewport_height;
100 | if (window.innerHeight)
101 | viewport_height = window.innerHeight;
102 | else
103 | viewport_height = $(window).height();
104 | sidebarbutton.find('span').css({
105 | 'display': 'block',
106 | 'margin-top': (viewport_height - sidebar.position().top - 20) / 2
107 | });
108 |
109 | sidebarbutton.click(toggle_sidebar);
110 | sidebarbutton.attr('title', _('Collapse sidebar'));
111 | sidebarbutton.css({
112 | 'color': '#FFFFFF',
113 | 'border-left': '1px solid ' + dark_color,
114 | 'font-size': '1.2em',
115 | 'cursor': 'pointer',
116 | 'height': bodywrapper.height(),
117 | 'padding-top': '1px',
118 | 'margin-left': ssb_width_expanded - 12
119 | });
120 |
121 | sidebarbutton.hover(
122 | function () {
123 | $(this).css('background-color', dark_color);
124 | },
125 | function () {
126 | $(this).css('background-color', light_color);
127 | }
128 | );
129 | }
130 |
131 | function set_position_from_cookie() {
132 | if (!document.cookie)
133 | return;
134 | var items = document.cookie.split(';');
135 | for(var k=0; k
7 |
8 |
9 |
10 |
11 |
12 |
13 | Index — ohmu 0.1 documentation
14 |
15 |
16 |
17 |
18 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
Index
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
80 |
81 |
82 |
91 |
95 |
96 |
--------------------------------------------------------------------------------
/docs/_build/html/objects.inv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/ohmu/33991d1bb655ab26ce1f172fdea0fd7eef32e763/docs/_build/html/objects.inv
--------------------------------------------------------------------------------
/docs/_build/html/search.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Search — ohmu 0.1 documentation
12 |
13 |
14 |
15 |
16 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
34 |
35 |
36 |
37 |
38 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
Search
54 |
55 |
56 |
57 | Please activate JavaScript to enable the search
58 | functionality.
59 |
60 |
61 |
62 | From here you can search these documents. Enter your search
63 | words into the box below and click "search". Note that the search
64 | function will automatically search for all of the words. Pages
65 | containing fewer words won't appear in the result list.
66 |
67 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
84 |
85 |
86 |
95 |
99 |
100 |
--------------------------------------------------------------------------------
/docs/_build/html/searchindex.js:
--------------------------------------------------------------------------------
1 | Search.setIndex({objects:{},terms:{programm:[],all:0,code:0,partial:0,help:0,just:0,softwar:[],antlr:[],modular:0,syntax:0,refactor:0,faster:0,follow:[],simultan:[],find:0,languag:0,ground:0,adt:0,depend:0,chain:0,mix:[],hobbi:0,dsl:0,eat:0,program:0,analyz:0,appli:0,formal:0,arrai:0,introduc:0,inform:0,real:0,them:0,anim:0,string:0,variou:0,transpar:0,far:0,familiar:[],safe:0,gpu:0,game:0,cannot:0,"new":0,veri:0,world:0,now:0,"class":0,discuss:[],introduct:0,enabl:0,specif:0,anyth:0,level:0,list:0,overli:0,collect:0,achiev:0,race:0,bison:[],either:0,alia:0,found:[],agda:0,where:0,page:0,concret:0,system:0,compil:0,prevent:0,domain:0,right:0,deal:0,thu:0,direct:0,intern:0,meta:0,design:0,respons:0,our:0,indirect:0,engin:0,orient:0,special:0,subject:0,index:0,what:[],safeti:0,matrix:0,defin:0,academ:0,crucial:[],below:[],tend:0,content:0,optim:0,state:0,version:[],suitabl:0,between:0,without:0,progress:[],neither:[],experi:0,ever:[],method:0,impract:0,core:0,elimin:0,assist:0,run:0,extend:0,advanc:0,gener:0,error:[],onli:0,like:0,disclaim:0,extens:0,base:0,california:0,believ:0,although:0,same:0,releas:0,organ:0,valu:[],addit:0,unsaf:0,both:0,great:0,thread:0,constraint:0,freedom:0,howev:0,area:0,technolog:0,shader:0,unfortun:0,filter:0,stride:[],enforc:0,sandbox:0,spare:0,chang:0,produc:[],oper:0,routin:0,semant:0,tradeoff:0,mixin:0,primarili:0,overview:0,modul:0,encod:[],bound:0,automat:[],two:0,down:0,unsound:0,written:[],done:0,haskel:0,comput:0,complex:0,mere:[],leverag:0,kei:0,cancer:0,from:0,evalu:0,wai:0,memori:0,data:0,support:0,transform:0,"long":0,sinc:0,few:0,much:0,call:0,includ:0,similarli:0,overhead:0,type:0,tell:[],too:0,analysi:0,modern:0,form:[],imag:0,arbitrari:0,thei:0,search:0,notic:0,idea:0,warn:0,part:0,understand:0,togeth:0,particular:[],known:0,overflow:0,inlin:0,than:0,those:0,must:0,serv:0,commun:[],kind:[],made:[],look:0,possibl:0,provid:0,wish:0,work:0,structur:0,project:0,cast:0,"while":0,cost:0,can:0,abov:0,ohmu:0,sophist:0,"static":0,embed:0,purpos:0,succe:0,"function":0,featur:0,constant:0,have:0,creat:[],"int":0,"abstract":0,parser:0,toolkit:[],indic:0,confound:0,gpgpu:0,befor:[],good:0,exist:[],research:0,interfac:0,been:0,foreign:0,simplest:[],declar:0,alwai:0,multipl:[],googl:0,studi:[],etc:0,perform:0,eleg:0,make:[],detail:[],virtual:0,occur:0,how:[],high:0,exampl:0,best:0,which:0,big:[],techniqu:[],verifi:[],more:0,librari:0,simpl:[],tool:0,difficult:[],product:0,express:[],practial:[],allow:0,normal:[],buffer:0,polymorph:0,why:0,object:0,variant:0,effect:0,lab:0,hand:[],reflect:0,most:0,tabl:0,driven:0,plan:0,ownership:0,improv:0,mai:0,develop:0,shift:0,philosophi:[],associ:0,tradition:0,check:0,hoc:0,other:0,prove:0,handl:0,task:0,attempt:0,practic:0,bug:0,scientif:0,ani:0,condit:0,goal:0,propog:0,well:0,inherit:0,doe:[],caus:0,alias:0,itself:0,maintain:0,combin:0,thi:0,time:0,omit:0,link:0,everyth:0,invari:0,moreov:0,usual:0},objtypes:{},titles:["Contents"],objnames:{},filenames:["index"]})
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | .. ohmu documentation master file, created by
2 | sphinx-quickstart on Sun May 11 10:04:06 2014.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Contents
7 | ==================
8 |
9 | .. toctree::
10 | :maxdepth: 2
11 |
12 |
13 | Introduction
14 | ============
15 |
16 | Ohmu is a new programming language being developed at Google. Right now, it
17 | is just a hobby project that a few engineers are working on in their spare
18 | time. Its purpose is to serve as a sandbox for experimenting with various
19 | compiler technologies, such as type systems, partial evaluation, run-time code
20 | generation, and GPU programming.
21 |
22 | *Disclaimer*: There are no plans to use ohmu internally or to release it as a
23 | real product. Anything and everything is subject to change without notice.
24 | May be known to the State of California to cause cancer in lab animals,
25 | including engineers in computer labs. Do not eat.
26 |
27 | Why a new language?
28 | -------------------
29 |
30 | We believe that a good programming language is one where the tool chain
31 | provides as much assistance as possible. Optimizing compilers improve
32 | performance, type systems and warnings help find bugs, while IDEs and
33 | refactoring tools help organize and maintain code. These tools are effective
34 | only if the language itself has a well-defined semantics, so that the compiler
35 | or IDE can analyze and understand the code.
36 |
37 | Unfortunately, most practical programming languages have a semantics that is
38 | informal, ad-hoc, overly complex, or unsound in various ways, which tends to
39 | confound any attempt at analysis. A great deal of academic research has been
40 | done in the area of formal programming language semantics, but academic
41 | languages go too far in the other direction; they are either too formal (e.g.
42 | Agda) or impractical for most real-world tasks (e.g. Haskell).
43 |
44 | Our goal is to collect the best ideas from academic research, combine those
45 | ideas together, and apply them to the design of a modern, elegant, and above
46 | all, a *practical* language.
47 |
48 | Overview of Language Features
49 | -----------------------------
50 |
51 | * High performance:
52 |
53 | * Faster than C.
54 | * Suitable for systems programming, games, or scientific computation.
55 | * Transparent foreign-function interface to C and C++ code.
56 | * Transparent support for GPGPU programming.
57 | * Advanced optimizations driven by static analysis (e.g. alias analysis).
58 |
59 | * Safe:
60 |
61 | * Type and memory safe. No unsafe casts or buffer overflows...
62 | * Thread-safe by design. No race conditions...
63 | * Designed from the ground-up for static analysis.
64 |
65 | * Modular and high-level:
66 |
67 | * Object-oriented programming: classes, inheritance, generics, and mixins.
68 | * Functional programming: type-classes, variant data types, and ADTs.
69 | * Mixin-modules: virtual classes and extensible data types.
70 |
71 | * Extensible:
72 |
73 | * *Extensible syntax*: libraries can extend the language with new syntax.
74 | * *Partial evaluation*: compile language extensions down to the core language.
75 | * Compile-time reflection and meta-programming.
76 | * Support for embedding domain-specific languages (DSLs):
77 |
78 | * E.g. parser generators, matrix libraries, image filters, shaders, etc.
79 |
80 |
81 | Key Technologies
82 | ^^^^^^^^^^^^^^^^
83 |
84 | Although this may look like a long wish-list, all of these features depend
85 | primarily on just two key technologies:
86 |
87 | #. A sophisticated static type system.
88 | #. Partial evaluation.
89 |
90 | **Type system**. Type systems are routinely used to handle structural types,
91 | such as ``int`` and ``String``. However, they can do much more than that.
92 | Type systems a general purpose tool for declaring and enforcing any program
93 | invariant, including aliasing constraints, ownership, or freedom from race
94 | conditions. The ohmu type system is responsible for the *safety* features
95 | above, and it is a key part of *modularity*, since mixin modules have very
96 | complex types. Moreover, the type system enforces program invariants that are
97 | then used by the optimizer to achieve *high performance*.
98 |
99 | **Partial evaluation**. Partial evaluation optimizes code by shifting
100 | computations from run-time to compile-time. Most compilers can perform
101 | constant propogation. However, the ohmu compiler can perform arbitrary
102 | computations at compile-time. Moreover, the partial evaluator is linked to
103 | the static type system, which enables it to perform type-based
104 | transformations, like method de-virtualization. The *extensibility* features
105 | use partial evaluation to eliminate the run-time overhead that is generally
106 | associated with reflection and DSLs.
107 |
108 |
109 | Tradeoffs in Language Design
110 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
111 |
112 | There has traditionally been a tradeoff in language design between performance
113 | and safety. A safe language must perform additional run-time checks, such as
114 | array bounds checks, to prevent unsafe operations from occuring. Ohmu
115 | leverages the type system to achieve both performance and safety at the same
116 | time. E.g. if the type system can prove that the array bounds check always
117 | succeeds, then run-time check can be omitted.
118 |
119 | Similarly, there has traditionally been a tradeoff between performance and
120 | high-level abstractions. Abstractions introduce an additional level of
121 | indirection, which usually has a run-time cost. For example, object-oriented
122 | inheritance and virtual methods are a useful abstraction, but most compilers
123 | cannot inline virtual methods, so they have a high cost. Ohmu leverages
124 | partial evaluation to eliminate the overhead of most abstractions. For
125 | example, the partial evaluator can specialize a polymorphic function to a
126 | concrete type, thus allowing the virtual calls to be eliminated.
127 |
128 |
129 | Indices and tables
130 | ==================
131 |
132 | * :ref:`genindex`
133 | * :ref:`modindex`
134 | * :ref:`search`
135 |
136 |
--------------------------------------------------------------------------------
/pull_clang_source_files.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | CLANG_INC="$1"/tools/clang/include/clang/Analysis/Til
4 | CLANG_LIB="$1"/tools/clang/lib/Analysis/Til
5 |
6 | cp -v "$CLANG_INC"/base/SimpleArray.h src/base/
7 | cp -v "$CLANG_INC"/base/MutArrayRef.h src/base/
8 | cp -v "$CLANG_INC"/base/ArrayTree.h src/base/
9 |
10 | cp -v "$CLANG_INC"/TILOps.def src/til/
11 | cp -v "$CLANG_INC"/TILAnnKinds.def src/til/
12 | cp -v "$CLANG_INC"/TILBaseType.h src/til/
13 | cp -v "$CLANG_INC"/TIL.h src/til/
14 | cp -v "$CLANG_INC"/TILTraverse.h src/til/
15 | cp -v "$CLANG_INC"/TILCompare.h src/til/
16 | cp -v "$CLANG_INC"/TILPrettyPrint.h src/til/
17 | cp -v "$CLANG_INC"/Annotation.h src/til/
18 | cp -v "$CLANG_INC"/AnnotationImpl.h src/til/
19 | cp -v "$CLANG_INC"/CFGBuilder.h src/til/
20 | cp -v "$CLANG_INC"/AttributeGrammar.h src/til/
21 | cp -v "$CLANG_INC"/CopyReducer.h src/til/
22 | cp -v "$CLANG_INC"/InplaceReducer.h src/til/
23 | cp -v "$CLANG_INC"/SSAPass.h src/til/
24 | cp -v "$CLANG_INC"/Bytecode.h src/til/
25 |
26 | cp -v "$CLANG_LIB"/TIL.cpp src/til/
27 | cp -v "$CLANG_LIB"/CFGBuilder.cpp src/til/
28 | cp -v "$CLANG_LIB"/SSAPass.cpp src/til/
29 | cp -v "$CLANG_LIB"/AnnotationImpl.cpp src/til/
30 | cp -v "$CLANG_LIB"/Bytecode.cpp src/til/
31 |
--------------------------------------------------------------------------------
/push_clang_source_files.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | CLANG_INC="$1"/tools/clang/include/clang/Analysis/Til
4 | CLANG_LIB="$1"/tools/clang/lib/Analysis/Til
5 |
6 | cp -v src/base/SimpleArray.h "$CLANG_INC"/base/
7 | cp -v src/base/MutArrayRef.h "$CLANG_INC"/base/
8 | cp -v src/base/ArrayTree.h "$CLANG_INC"/base/
9 |
10 | cp -v src/til/TILOps.def "$CLANG_INC"
11 | cp -v src/til/TILAnnKinds.def "$CLANG_INC"
12 | cp -v src/til/TILBaseType.h "$CLANG_INC"
13 | cp -v src/til/TIL.h "$CLANG_INC"
14 | cp -v src/til/TILTraverse.h "$CLANG_INC"
15 | cp -v src/til/TILCompare.h "$CLANG_INC"
16 | cp -v src/til/TILPrettyPrint.h "$CLANG_INC"
17 | cp -v src/til/Annotation.h "$CLANG_INC"
18 | cp -v src/til/AnnotationImpl.h "$CLANG_INC"
19 | cp -v src/til/CFGBuilder.h "$CLANG_INC"
20 | cp -v src/til/AttributeGrammar.h "$CLANG_INC"
21 | cp -v src/til/CopyReducer.h "$CLANG_INC"
22 | cp -v src/til/InplaceReducer.h "$CLANG_INC"
23 | cp -v src/til/SSAPass.h "$CLANG_INC"
24 | cp -v src/til/Bytecode.h "$CLANG_INC"
25 |
26 | cp -v src/til/TIL.cpp "$CLANG_LIB"
27 | cp -v src/til/CFGBuilder.cpp "$CLANG_LIB"
28 | cp -v src/til/SSAPass.cpp "$CLANG_LIB"
29 | cp -v src/til/AnnotationImpl.cpp "$CLANG_LIB"
30 | cp -v src/til/Bytecode.cpp "$CLANG_LIB"
31 |
--------------------------------------------------------------------------------
/src/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8)
2 |
3 | # set up LLVM dependencies
4 | # pass -DLLVM_DIR=${LLVM_INSTALL_DIR}/share/llvm/cmake/ to cmake
5 | # or set LLVM_DIR within ccmake, or cmake-gui
6 |
7 | find_package(LLVM REQUIRED CONFIG)
8 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
9 | message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
10 |
11 | foreach (LLVM_INCLUDE_DIR ${LLVM_INCLUDE_DIRS})
12 | set(CLANG_INCLUDE_DIRS
13 | ${CLANG_INCLUDE_DIRS}
14 | ${LLVM_INCLUDE_DIR}/../tools/clang/include
15 | )
16 | endforeach(LLVM_INCLUDE_DIR)
17 | message(STATUS "LLVM include dirs ${LLVM_INCLUDE_DIRS}")
18 | message(STATUS "Clang include dirs ${CLANG_INCLUDE_DIRS}")
19 | include_directories(${LLVM_INCLUDE_DIRS})
20 | include_directories(${CLANG_INCLUDE_DIRS})
21 | add_definitions(${LLVM_DEFINITIONS})
22 |
23 | link_directories("${LLVM_DIR}/../../../lib")
24 | link_directories("${LLVM_DIR}/../../../tools/clang/lib")
25 |
26 | # Find the libraries that correspond to the LLVM components that we wish to use
27 | # llvm_map_components_to_libnames(llvm_libs support core irreader mc option)
28 |
29 |
30 | if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
31 | add_definitions(-std=c++11)
32 | add_definitions(-fno-exceptions)
33 | add_definitions(-fno-rtti)
34 | # add_definitions(-Weverything -Wno-c++98-compat -Wno-padded -Wno-shorten-64-to-32 -Wno-weak-vtables -Wno-unused-parameter -Wno-sign-conversion -Wno-switch-enum -Wno-missing-prototypes -Wno-c++98-compat-pedantic -Wno-missing-noreturn -Wno-zero-length-array -Wno-float-equal)
35 | add_definitions(-Wall)
36 | endif()
37 |
38 | if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
39 | add_definitions(-std=c++11)
40 | add_definitions(-fno-exceptions)
41 | add_definitions(-fno-rtti)
42 | add_definitions(-Wall)
43 | endif()
44 |
45 | # cl likes to complain about POSIX interfaces like fopen, but we don't care.
46 | if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
47 | add_definitions(/wd4200) # nonstandard extension used : zero-sized array in struct/union
48 | add_definitions(/wd4201)
49 | add_definitions(/wd4291)
50 | # add_definitions(/W4 /WX)
51 | add_definitions(/GR-)
52 | add_definitions(/D_CRT_SECURE_NO_WARNINGS)
53 | add_definitions(/DWIN32_LEAN_AND_MEAN)
54 | add_definitions(/D_HAS_EXCEPTIONS=0)
55 | endif()
56 |
57 | include_directories("${PROJECT_SOURCE_DIR}/src")
58 |
59 | add_subdirectory(base)
60 | add_subdirectory(grammar)
61 | add_subdirectory(parser)
62 | add_subdirectory(til)
63 |
64 | # add_subdirectory(backend)
65 | add_subdirectory(lsa)
66 | add_subdirectory(test)
67 |
68 | list(GET LLVM_INCLUDE_DIRS 0 LLVM_SRC_INC_DIR)
69 | set(LLVM_SRC_DIR "${LLVM_SRC_INC_DIR}/../")
70 |
71 | # Unit tests depend on the google test infrastructure.
72 |
73 | if(EXISTS ${LLVM_SRC_DIR}/utils/unittest/googletest/include/gtest/gtest.h)
74 | include_directories(${LLVM_SRC_DIR}/utils/unittest/googletest/include)
75 | include_directories(${LLVM_SRC_DIR}/utils/unittest/googletest/)
76 | add_definitions(-DGTEST_HAS_RTTI=0)
77 | add_library(gtest
78 | ${LLVM_SRC_DIR}/utils/unittest/googletest/src/gtest-all.cc
79 | )
80 | set(GTEST_BIN ${CMAKE_CURRENT_BINARY_DIR})
81 | add_subdirectory(unittests)
82 | endif()
83 |
84 |
--------------------------------------------------------------------------------
/src/backend/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8)
2 |
3 | add_subdirectory(llvm)
4 |
--------------------------------------------------------------------------------
/src/backend/jagger/codegen.cpp:
--------------------------------------------------------------------------------
1 | //===- event.cpp -----------------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 |
18 | // Peephole Notes:
19 | // load->immediate
20 | // mul->add/lea/shift
21 | // div->shift
22 | // cmp 0 folding
23 | // address mode folding
24 | // folding loads/stores into instrs
25 | // 0-offset jump/branch elimination
26 | // Commute arguments for destructive operations
27 |
28 | #if 0
29 | #include "types.h"
30 | #include "interface.h"
31 |
32 | namespace Jagger {
33 | static const GP32Reg regs[] = {
34 | EAX, ECX, EDX, EBX,
35 | R8D, R9D, R10D, R11D,
36 | R12D, R13D, R14D, R15D,
37 | };
38 |
39 | static const char* const regNames[] = {
40 | "EAX", "ECX", "EDX", "EBX",
41 | "R8D", "R9D", "R10D", "R11D",
42 | "R12D", "R13D", "R14D", "R15D",
43 | };
44 |
45 | extern "C" unsigned char _BitScanReverse(unsigned long * Index, unsigned long Mask);
46 |
47 | static int setToIndex(unsigned x) {
48 | unsigned long a;
49 | _BitScanReverse(&a, (unsigned long)x);
50 | return (int)a;
51 | }
52 |
53 | void Jump::emit(X64Builder& builder) {
54 | #if 0
55 | if (kind == JUMP) {
56 | printf("JMP ???\n");
57 | builder.JMP(0);
58 | }
59 | else {
60 | printf("JMPcc ???\n");
61 | builder.JA(0);
62 | }
63 | #endif
64 | }
65 |
66 | void IntLiteral::emit(X64Builder& builder) {
67 | #if 0
68 | for (unsigned set = copySet; set; set &= ~(set & -set))
69 | printf("MOV %s, %d\n", regNames[setToIndex(set)], value);
70 | #endif
71 | }
72 |
73 | void Instruction::emit(X64Builder& builder) {
74 | #if 0
75 | switch (kind) {
76 | case Object::ADD: {
77 | unsigned reg0 = ((Event *)this)[-2].liveRange.reg;
78 | unsigned reg1 = ((Event *)this)[-1].liveRange.reg;
79 | printf("ADD %s, %s\n", regNames[setToIndex(reg0)],
80 | regNames[setToIndex(reg1)]);
81 | for (unsigned set = copySet & ~reg0; set; set &= ~(set & -set))
82 | printf("MOV %s, %s\n", regNames[setToIndex(set & -set)],
83 | regNames[setToIndex(reg0)]);
84 | } break;
85 | case Object::MUL:
86 | printf("MUL\n");
87 | break;
88 | case Object::CMP_EQ:
89 | case Object::CMP_LT:
90 | case Object::CMP_LE:
91 | printf("CMP\n");
92 | break;
93 | //i->instruction.emit(builder);
94 | break;
95 | }
96 | #endif
97 | }
98 |
99 | void emitASM(X64Builder& builder, Event* events, size_t numEvents) {
100 | #if 0
101 | for (auto i = events, e = events + numEvents; i != e; ++i)
102 | switch (i->kind) {
103 | case Object::JUMP:
104 | case Object::BRANCH:
105 | i->jump.emit(builder);
106 | break;
107 | case Object::INT_LITERAL:
108 | i->intLiteral.emit(builder);
109 | break;
110 | case Object::ADD:
111 | case Object::MUL:
112 | case Object::CMP_EQ:
113 | case Object::CMP_LT:
114 | case Object::CMP_LE:
115 | i->instruction.emit(builder);
116 | break;
117 | }
118 | #endif
119 | }
120 | }
121 | #endif
122 |
--------------------------------------------------------------------------------
/src/backend/jagger/interface.h:
--------------------------------------------------------------------------------
1 | //===- event.cpp -----------------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 |
18 | #pragma once
19 | #include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
20 |
21 | // FIXME: Should take an allocator rather than a buffer.
22 | void encode(clang::threadSafety::til::SCFG* cfg, char* output);
23 |
--------------------------------------------------------------------------------
/src/backend/jagger/print.cpp:
--------------------------------------------------------------------------------
1 | //===- event.cpp -----------------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 |
18 | #include "types.h"
19 | #include
20 |
21 | namespace Jagger {
22 | void Instruction::print(const Instruction* base) {
23 | const Opcode* opcode = this->opcode;
24 | printf("%3d %-10s", this - base, opcode->name);
25 | if (opcode->isJump) printf(" jump to %d", arg1 - base);
26 | if (opcode->hasResult)
27 | printf(" |%3d| {%04x (%04x) : %04x} [%2d]", key - base, ~invalidRegs,
28 | preferredRegs, reg, pressure);
29 | if (opcode->hasArg0) {
30 | printf(" (%d", arg0 - base);
31 | if (!arg0Live)
32 | printf("*");
33 | if (opcode->hasArg1) {
34 | printf(", %d", arg1 - base);
35 | if (!arg1Live)
36 | printf("*");
37 | }
38 | printf(")");
39 | }
40 | if (opcode->isIntLiteral)
41 | printf(" %-3d ", arg0);
42 | printf("\n");
43 | }
44 |
45 | void print(Instruction* instrs, size_t numInstrs) {
46 | for (auto i = instrs, e = instrs + numInstrs; i != e; ++i)
47 | i->print(instrs);
48 | }
49 | }
--------------------------------------------------------------------------------
/src/backend/llvm/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8)
2 |
3 | add_library(backend_llvm STATIC
4 | IRGen.cpp
5 | )
6 |
--------------------------------------------------------------------------------
/src/backend/llvm/IRGen.h:
--------------------------------------------------------------------------------
1 | //===- IRGen.h -------------------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 | //
18 | // Defines the LLVM IR Generation layer.
19 | //
20 | //===----------------------------------------------------------------------===//
21 |
22 | #ifndef OHMU_BACKEND_LLVM_IRGEN_H
23 | #define OHMU_BACKEND_LLVM_IRGEN_H
24 |
25 | #include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
26 |
27 |
28 | #include "llvm/IR/Verifier.h"
29 | #include "llvm/IR/DerivedTypes.h"
30 | #include "llvm/IR/IRBuilder.h"
31 | #include "llvm/IR/LLVMContext.h"
32 | #include "llvm/IR/Module.h"
33 | #include "llvm/Support/Casting.h"
34 |
35 |
36 | namespace ohmu {
37 | namespace backend_llvm {
38 |
39 | using namespace clang::threadSafety::til;
40 |
41 | void generate_LLVM_IR(SExpr* E);
42 |
43 | } // end namespace backend_llvm
44 | } // end namespace ohmu
45 |
46 | #endif // OHMU_BACKEND_LLVM_IRGEN_H
47 |
--------------------------------------------------------------------------------
/src/backend/x64builder/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8)
2 |
3 | add_executable(x64builder x64builder.cpp)
4 |
5 | if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
6 | add_definitions(/Dsnprintf=sprintf_s)
7 | endif()
8 |
--------------------------------------------------------------------------------
/src/backend/x64builder/instrbuilder.h:
--------------------------------------------------------------------------------
1 | // Warren Hunt : 2014/02/08
2 |
3 | #include "instr.h"
4 | #include "args.h"
5 |
6 | //enum ConditionCode {
7 | // O, NO, B, NAE = B, C = B, NB, AE = NB, NC = NB, Z, E = Z, NZ, NE = NZ, BE, NA = BE, NBE, A = NBE,
8 | // S, NS, P, PE = P, NP, PO = NP, L, NGE = L, NL, GE = NL, LE, NG = LE, NLE, G = NLE
9 | //};
10 |
11 |
--------------------------------------------------------------------------------
/src/base/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8)
2 |
3 | add_library(base STATIC
4 | MemRegion.cpp
5 | )
6 |
--------------------------------------------------------------------------------
/src/base/DiagnosticEmitter.h:
--------------------------------------------------------------------------------
1 | //===- DiagnosticEmitter.h -------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 | //
18 | // Provide a simple class for emitting error and warning messages.
19 | //
20 | //===----------------------------------------------------------------------===//
21 |
22 | #ifndef OHMU_TIL_DIAGNOSTIC_H
23 | #define OHMU_TIL_DIAGNOSTIC_H
24 |
25 | #include "LLVMDependencies.h"
26 |
27 | #include
28 |
29 | namespace ohmu {
30 |
31 |
32 | /// Wraps a std::ostream to provide custom output for various things.
33 | class DiagnosticStream {
34 | public:
35 | DiagnosticStream(std::ostream& s) : ss(s), emitted(false) { }
36 | ~DiagnosticStream() {
37 | if (emitted)
38 | ss << "\n";
39 | }
40 |
41 | DiagnosticStream& operator<<(bool b) {
42 | emitted = true;
43 | if (b) ss << "true";
44 | else ss << "false";
45 | return *this;
46 | }
47 |
48 | DiagnosticStream& operator<<(int i) {
49 | emitted = true;
50 | ss << i;
51 | return *this;
52 | }
53 |
54 | DiagnosticStream& operator<<(unsigned i) {
55 | emitted = true;
56 | ss << i;
57 | return *this;
58 | }
59 |
60 | DiagnosticStream& operator<<(const char* msg) {
61 | emitted = true;
62 | ss << msg;
63 | return *this;
64 | }
65 |
66 | DiagnosticStream& operator<<(StringRef msg) {
67 | emitted = true;
68 | ss << msg.c_str();
69 | return *this;
70 | }
71 |
72 | std::ostream& outputStream() {
73 | emitted = true;
74 | return ss;
75 | }
76 |
77 | public:
78 | std::ostream& ss;
79 |
80 | private:
81 | bool emitted;
82 | };
83 |
84 |
85 |
86 | /// This file defines a simple interface for publishing warnings and errors.
87 | /// The current methods are placeholders; they will be improved in the future.
88 | class DiagnosticEmitter {
89 | public:
90 | DiagnosticEmitter() : dstream_(std::cerr) { }
91 |
92 | DiagnosticStream& error(const char* msg) {
93 | dstream_ << "\nerror: " << msg;
94 | return dstream_;
95 | }
96 |
97 | DiagnosticStream& warning(const char* msg) {
98 | dstream_ << "\nwarning: " << msg;
99 | return dstream_;
100 | }
101 |
102 | private:
103 | DiagnosticStream dstream_;
104 | };
105 |
106 |
107 | } // end namespace ohmu
108 |
109 | #endif // OHMU_TIL_DIAGNOSTIC_H
110 |
--------------------------------------------------------------------------------
/src/base/MemRegion.cpp:
--------------------------------------------------------------------------------
1 | //===- MemRegion.cpp -------------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 |
18 | #include "MemRegion.h"
19 |
20 | namespace ohmu {
21 |
22 | MemRegion::MemRegion()
23 | : currentBlock_(0), currentBlockEnd_(0), currentPosition_(0),
24 | largeBlocks_(0) {
25 | grabNewBlock();
26 | }
27 |
28 |
29 | inline void freeList(char* p) {
30 | while (p) {
31 | // std::cerr << ".";
32 | // Each block has a pointer to the previous block at the start
33 | char* np = *reinterpret_cast(p);
34 | free(p);
35 | p = np; // pun intended.
36 | }
37 | // std::cerr << "\n";
38 | }
39 |
40 |
41 | MemRegion::~MemRegion() {
42 | // std::cerr << "\nfree[" << std::hex << reinterpret_cast(this) << "]";
43 | freeList(currentBlock_);
44 | // std::cerr << "\nfree[]";
45 | freeList(largeBlocks_);
46 | }
47 |
48 |
49 | void MemRegion::grabNewBlock() {
50 | // std::cerr << "\nallocBlock[" << std::hex << reinterpret_cast(this) << "]";
51 |
52 | // FIXME: ideally, we'd like to allocate exact memory pages.
53 | // If defaultBlockSize=4096, and malloc adds headers of its own, then we
54 | // may be over page size.
55 | char* newBlock = reinterpret_cast(malloc(defaultBlockSize));
56 | linkBack(currentBlock_, newBlock);
57 |
58 | currentPosition_ = newBlock + headerSize;
59 | currentBlockEnd_ = newBlock + defaultBlockSize;
60 | }
61 |
62 |
63 | } // end namespace ohmu
64 |
--------------------------------------------------------------------------------
/src/base/MemRegion.h:
--------------------------------------------------------------------------------
1 | //===- MemRegion.h ---------------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 | //
18 | // MemRegion is a class which does bump pointer allocation. Everything
19 | // allocated in the region will be destroyed when the region is destroyed.
20 | //
21 | // MemRegionRef stores a reference to a region.
22 | //
23 | //===----------------------------------------------------------------------===//
24 |
25 |
26 | #ifndef OHMU_MEMREGION_H
27 | #define OHMU_MEMREGION_H
28 |
29 | #include
30 | #include
31 | #include
32 |
33 | namespace ohmu {
34 |
35 |
36 | class MemRegion {
37 | public:
38 | // Create a new MemRegion
39 | MemRegion();
40 |
41 | // Destroy a MemRegion, along with all data that was allocated in it.
42 | ~MemRegion();
43 |
44 | // Pad sizes out to nearest 8 byte boundary.
45 | inline unsigned getAlignedSize(unsigned size) {
46 | if ((size & 0x7) == 0)
47 | return size;
48 | else
49 | return ((size >> 3) + 1) << 3;
50 | }
51 |
52 | template
53 | inline T* allocateT() {
54 | return reinterpret_cast(allocate(sizeof(T)));
55 | }
56 |
57 | template
58 | inline T* allocateT(size_t nelems) {
59 | return reinterpret_cast(allocate(sizeof(T) * nelems));
60 | }
61 |
62 | // Allocate memory for a new object from the pool.
63 | // Small objects are bump allocated; large ones are not.
64 | inline void* allocate(size_t size) {
65 | // std::cerr << "allocate " << size << ".\n";
66 | size = getAlignedSize(size);
67 | if (size <= maxBumpAllocSize)
68 | return allocateSmall(size);
69 | else
70 | return allocateLarge(size);
71 | }
72 |
73 | // No-op.
74 | void deallocate(void* ptr) { }
75 |
76 | inline void* allocateSmall(size_t size) {
77 | if (currentPosition_ + size >= currentBlockEnd_)
78 | grabNewBlock();
79 |
80 | void* result = currentPosition_;
81 | currentPosition_ += size;
82 | return result;
83 | }
84 |
85 | inline void* allocateLarge(size_t size) {
86 | // std::cerr << "\nallocLarge " << size;
87 | char* p = reinterpret_cast(malloc(size + headerSize));
88 | linkBack(largeBlocks_, p);
89 | return p + headerSize;
90 | }
91 |
92 | void grabNewBlock();
93 |
94 | private:
95 | static const unsigned defaultBlockSize = 4096; // 4kb blocks
96 | static const unsigned maxBumpAllocSize = 512; // 8 allocs per block
97 | static const unsigned headerSize = sizeof(void*);
98 |
99 | void linkBack(char*& blockPointer, char* newBlock) {
100 | *reinterpret_cast(newBlock) = blockPointer;
101 | blockPointer = newBlock;
102 | }
103 |
104 | char* currentBlock_; // current bump allocation block
105 | char* currentBlockEnd_;
106 | char* currentPosition_;
107 |
108 | char* largeBlocks_; // linked list of large blocks
109 | };
110 |
111 |
112 | // Simple wrapper class which holds a pointer to a region.
113 | class MemRegionRef {
114 | public:
115 | MemRegionRef() : allocator_(nullptr) {}
116 | MemRegionRef(MemRegion *region) : allocator_(region) { }
117 |
118 | void setRegion(MemRegion *r) { allocator_ = r; }
119 |
120 | void *allocate(size_t sz) {
121 | return allocator_->allocate(sz);
122 | }
123 |
124 | template T *allocateT() {
125 | return allocator_->allocateT();
126 | }
127 |
128 | template T *allocateT(size_t nelems) {
129 | return allocator_->allocateT(nelems);
130 | }
131 |
132 | private:
133 | MemRegion* allocator_;
134 | };
135 |
136 |
137 | } // end namespace ohmu
138 |
139 |
140 | inline void* operator new(size_t size, ohmu::MemRegionRef& region) {
141 | return region.allocate(size);
142 | }
143 |
144 |
145 | #endif // OHMU_MEMREGION_H
146 |
--------------------------------------------------------------------------------
/src/base/MutArrayRef.h:
--------------------------------------------------------------------------------
1 | //===- MutArrayRef.h -------------------------------------------*- C++ --*-===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT in the LLVM repository for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 |
10 | #ifndef OHMU_BASE_MUTARRAYREF_H
11 | #define OHMU_BASE_MUTARRAYREF_H
12 |
13 |
14 | namespace ohmu {
15 |
16 | // A version of ArrayRef which provides mutable access to the underlying data.
17 | template
18 | class MutArrayRef {
19 | public:
20 | typedef T* iterator;
21 | typedef const T* const_iterator;
22 |
23 | MutArrayRef() : data_(nullptr), len_(0) { }
24 | MutArrayRef(T* dat, size_t sz) : data_(dat), len_(sz) { }
25 | MutArrayRef(T* begin, T* end) : data_(begin), len_(end-begin) { }
26 |
27 | size_t size() const { return len_; }
28 | T& operator[](size_t i) { return data_[i]; }
29 | const T& operator[](size_t i) const { return data_[i]; }
30 |
31 | iterator begin() { return data_; }
32 | const_iterator begin() const { return begin(); }
33 | const_iterator cbegin() const { return begin(); }
34 |
35 | iterator end() { return data_ + len_; }
36 | const_iterator end() const { return end(); }
37 | const_iterator cend() const { return end(); }
38 |
39 | private:
40 | T* data_;
41 | size_t len_;
42 | };
43 |
44 | } // end namespace ohmu
45 |
46 | #endif // OHMU_BASE_MUTARRAYREF_H
47 |
--------------------------------------------------------------------------------
/src/base/NestedStack.h:
--------------------------------------------------------------------------------
1 | //===- NestedStack.h -------------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 |
18 |
19 | #ifndef OHMU_BASE_NESTEDSTACK_H_
20 | #define OHMU_BASE_NESTEDSTACK_H_
21 |
22 | #include
23 |
24 | namespace ohmu {
25 |
26 |
27 | /// NestedStack implements a logical "stack of stacks".
28 | /// There is a topmost stack of elements, which is visible, and allows
29 | /// elements to be pushed and popped as usual.
30 | /// The topmost stack can be saved, which will create a new, empty topmost
31 | /// stack. The original stack can then be restored later.
32 | /// The implementation uses a single contiguous array for all logical stacks.
33 | template
34 | class NestedStack {
35 | public:
36 | NestedStack() : Start(0) { }
37 |
38 | /// Push a new element onto the topmost stack.
39 | void push_back(const T& Elem) { Elements.push_back(Elem); }
40 |
41 | /// Pop an element off of the topmost stack.
42 | void pop_back() {
43 | assert(size() > 0 && "Cannot pop off of empty stack!.");
44 | Elements.pop_back();
45 | }
46 |
47 | /// Return top element on topmost stack.
48 | const T& back() const { return Elements.back(); }
49 | T& back() { return Elements.back(); }
50 |
51 | /// Return the i^th element on the topmost stack.
52 | const T& at(unsigned i) const { return Elements.at(Start + i); }
53 | T& at(unsigned i) { return Elements.at(Start + i); }
54 |
55 | /// Return size of topmost stack
56 | unsigned size() const { return Elements.size() - Start; }
57 |
58 | /// Return true if topmost stack is empty.
59 | bool empty() const { return size() == 0; }
60 |
61 | /// Return all elements in topmost stack.
62 | ArrayRef elements() {
63 | T* pbegin = &Elements[Start];
64 | return ArrayRef(pbegin, size());
65 | }
66 |
67 | /// Clear all elements from topmost stack.
68 | void clear() {
69 | for (unsigned i=0,n=size(); i < n; ++i)
70 | Elements.pop_back();
71 | }
72 |
73 | /// Save topmost stack, and return an id that can be used to restore it.
74 | /// Clear topmost stack.
75 | unsigned save() {
76 | unsigned Sv = Start;
77 | Start = Elements.size();
78 | return Sv;
79 | }
80 |
81 | /// Restore a stack that was previously saved.
82 | void restore(unsigned SaveID) {
83 | assert(size() == 0 && "Must clear stack before restoring!");
84 | Start = SaveID;
85 | }
86 |
87 | private:
88 | std::vector Elements; //< Array of elements.
89 | unsigned Start; //< Index of first elem in topmost stack.
90 | };
91 |
92 |
93 |
94 | } // end namespace ohmu
95 |
96 | #endif // SRC_BASE_NESTEDSTACK_H_
97 |
--------------------------------------------------------------------------------
/src/base/SimpleArray.h:
--------------------------------------------------------------------------------
1 | //===- SimpleArray.h -------------------------------------------*- C++ --*-===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT in the LLVM repository for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 |
10 | #ifndef OHMU_BASE_SIMPLEARRAY_H
11 | #define OHMU_BASE_SIMPLEARRAY_H
12 |
13 | #include "MemRegion.h"
14 |
15 |
16 | namespace ohmu {
17 |
18 | // A simple fixed size array class that does not manage its own memory,
19 | // suitable for use with bump pointer allocation.
20 | template class SimpleArray {
21 | public:
22 | SimpleArray() : Data(nullptr), Size(0), Capacity(0) {}
23 | SimpleArray(T *Dat, size_t Cp, size_t Sz = 0)
24 | : Data(Dat), Size(Sz), Capacity(Cp) {}
25 | SimpleArray(MemRegionRef A, size_t Cp)
26 | : Data(Cp == 0 ? nullptr : A.allocateT(Cp)), Size(0), Capacity(Cp) {}
27 | SimpleArray(SimpleArray &&A)
28 | : Data(A.Data), Size(A.Size), Capacity(A.Capacity) {
29 | A.Data = nullptr;
30 | A.Size = 0;
31 | A.Capacity = 0;
32 | }
33 |
34 | SimpleArray &operator=(SimpleArray &&RHS) {
35 | if (this != &RHS) {
36 | Data = RHS.Data;
37 | Size = RHS.Size;
38 | Capacity = RHS.Capacity;
39 |
40 | RHS.Data = nullptr;
41 | RHS.Size = RHS.Capacity = 0;
42 | }
43 | return *this;
44 | }
45 |
46 | /// Reserve space for at least Ncp items, reallocating if necessary.
47 | void reserve(size_t Ncp, MemRegionRef A) {
48 | if (Ncp <= Capacity)
49 | return;
50 | T *Odata = Data;
51 | Data = A.allocateT(Ncp);
52 | Capacity = Ncp;
53 | memcpy(Data, Odata, sizeof(T) * Size);
54 | return;
55 | }
56 |
57 | /// Resize to Nsz, initializing newly-added elements to V
58 | void resize(size_t Nsz, MemRegionRef A, const T& V) {
59 | if (Nsz <= Size)
60 | return;
61 | reserve(Nsz, A);
62 | for (size_t i = Size; i < Nsz; ++i)
63 | Data[i] = V;
64 | Size = Nsz;
65 | }
66 |
67 | /// Reserve space for at least N more items.
68 | void reserveCheck(size_t N, MemRegionRef A) {
69 | if (Capacity == 0)
70 | reserve(u_max(InitialCapacity, N), A);
71 | else if (Size + N > Capacity)
72 | reserve(u_max(Size + N, Capacity * 2), A);
73 | }
74 |
75 | typedef T *iterator;
76 | typedef const T *const_iterator;
77 |
78 | size_t size() const { return Size; }
79 | size_t capacity() const { return Capacity; }
80 |
81 | T &operator[](unsigned i) {
82 | assert(i < Size && "Array index out of bounds.");
83 | return Data[i];
84 | }
85 | const T &operator[](unsigned i) const {
86 | assert(i < Size && "Array index out of bounds.");
87 | return Data[i];
88 | }
89 | T &back() {
90 | assert(Size && "No elements in the array.");
91 | return Data[Size - 1];
92 | }
93 | const T &back() const {
94 | assert(Size && "No elements in the array.");
95 | return Data[Size - 1];
96 | }
97 |
98 | iterator begin() { return Data; }
99 | iterator end() { return Data + Size; }
100 |
101 | const_iterator begin() const { return Data; }
102 | const_iterator end() const { return Data + Size; }
103 |
104 | const_iterator cbegin() const { return Data; }
105 | const_iterator cend() const { return Data + Size; }
106 |
107 | void push_back(const T &Elem) {
108 | assert(Size < Capacity);
109 | Data[Size++] = Elem;
110 | }
111 |
112 | template
113 | void emplace_back(Params... Ps) {
114 | assert(Size < Capacity);
115 | new (&Data[Size++]) T(Ps...);
116 | }
117 |
118 | /// drop last n elements from array
119 | void drop(unsigned n = 0) {
120 | assert(Size > n);
121 | Size -= n;
122 | }
123 |
124 | /// drop all elements from array.
125 | void clear() {
126 | Size = 0;
127 | }
128 |
129 | void setValues(unsigned Sz, const T& C) {
130 | assert(Sz <= Capacity);
131 | Size = Sz;
132 | for (unsigned i = 0; i < Sz; ++i) {
133 | Data[i] = C;
134 | }
135 | }
136 |
137 | template unsigned append(Iter I, Iter E) {
138 | size_t Osz = Size;
139 | size_t J = Osz;
140 | for (; J < Capacity && I != E; ++J, ++I)
141 | Data[J] = *I;
142 | Size = J;
143 | return J - Osz;
144 | }
145 |
146 | // An adaptor to reverse a simple array
147 | class ReverseAdaptor {
148 | public:
149 | ReverseAdaptor(SimpleArray &Arr) : Array(Arr) {}
150 | // A reverse iterator used by the reverse adaptor
151 | class Iterator {
152 | public:
153 | Iterator(T *Dat) : Data(Dat) {}
154 | T &operator*() { return *Data; }
155 | const T &operator*() const { return *Data; }
156 | Iterator &operator++() {
157 | --Data;
158 | return *this;
159 | }
160 | bool operator!=(Iterator Other) { return Data != Other.Data; }
161 |
162 | private:
163 | T *Data;
164 | };
165 | Iterator begin() { return Array.end() - 1; }
166 | Iterator end() { return Array.begin() - 1; }
167 | const Iterator begin() const { return Array.end() - 1; }
168 | const Iterator end() const { return Array.begin() - 1; }
169 |
170 | private:
171 | SimpleArray &Array;
172 | };
173 |
174 | const ReverseAdaptor reverse() const { return ReverseAdaptor(*this); }
175 | ReverseAdaptor reverse() { return ReverseAdaptor(*this); }
176 |
177 | private:
178 | // std::max is annoying here, because it requires a reference,
179 | // thus forcing InitialCapacity to be initialized outside the .h file.
180 | size_t u_max(size_t i, size_t j) { return (i < j) ? j : i; }
181 |
182 | static const size_t InitialCapacity = 4;
183 |
184 | SimpleArray(const SimpleArray &A) = delete;
185 |
186 | T *Data;
187 | size_t Size;
188 | size_t Capacity;
189 | };
190 |
191 | } // end namespace ohmu
192 |
193 | #endif // OHMU_BASE_SIMPLEARRAY_H
194 |
--------------------------------------------------------------------------------
/src/clang/README.txt:
--------------------------------------------------------------------------------
1 |
2 | This directory contains files that translate the clang CFG into ohmu.
3 | These cannot currently be compiled separately from clang, but are checked
4 | in here, until such time as they are accepted upstream.
5 |
6 | --- The following will be updated on every sync with clang.
7 |
8 | Valid for clang revision: r242554
9 |
--------------------------------------------------------------------------------
/src/clang/diff_clang_source_files.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | CLANG_INC="$1"/tools/clang/include/clang/Analysis/Til
4 | CLANG_LIB="$1"/tools/clang/lib/Analysis/Til
5 |
6 | diff -u "$CLANG_INC"/ClangCFGWalker.h ClangCFGWalker.h
7 | diff -u "$CLANG_INC"/ClangTranslator.h ClangTranslator.h
8 |
9 | diff -u "$CLANG_LIB"/ClangTranslator.cpp ClangTranslator.cpp
10 |
11 |
--------------------------------------------------------------------------------
/src/clang/pull_clang_source_files.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | CLANG_INC="$1"/tools/clang/include/clang/Analysis/Til
4 | CLANG_LIB="$1"/tools/clang/lib/Analysis/Til
5 |
6 | cp -v "$CLANG_INC"/ClangCFGWalker.h .
7 | cp -v "$CLANG_INC"/ClangTranslator.h .
8 |
9 | cp -v "$CLANG_LIB"/ClangTranslator.cpp .
10 |
11 |
--------------------------------------------------------------------------------
/src/clang/push_clang_source_files.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | CLANG_INC="$1"/tools/clang/include/clang/Analysis/Til
4 | CLANG_LIB="$1"/tools/clang/lib/Analysis/Til
5 |
6 | cp -v ClangCFGWalker.h "$CLANG_INC"
7 | cp -v ClangTranslator.h "$CLANG_INC"
8 |
9 | cp -v ClangTranslator.cpp "$CLANG_LIB"
10 |
11 |
--------------------------------------------------------------------------------
/src/grammar/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8)
2 |
3 | add_custom_target(parser_grammar)
4 | add_custom_command(
5 | TARGET parser_grammar
6 | DEPENDS parser.grammar
7 | COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/parser.grammar ${CMAKE_CURRENT_BINARY_DIR}/parser.grammar)
8 |
9 | add_custom_target(ohmu_grammar)
10 | add_custom_command(
11 | TARGET ohmu_grammar
12 | DEPENDS ohmu.grammar
13 | COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/ohmu.grammar ${CMAKE_CURRENT_BINARY_DIR}/ohmu.grammar)
14 |
--------------------------------------------------------------------------------
/src/grammar/ohmu.grammar:
--------------------------------------------------------------------------------
1 |
2 | // First rule for files
3 | definitions ::=
4 | e=slot { (append [] e) }
5 | |*[es] e=slot { (append es e) }
6 | ;
7 |
8 | // First rule for read-eval-print loop
9 | command ::=
10 | %TK_Newline { (litNull) }
11 | | e=expr %TK_Newline { e }
12 | ;
13 |
14 | literal ::=
15 | "null" { (litNull) }
16 | | "true" { (litBool "true") }
17 | | "false" { (litBool "false") }
18 | | s= %TK_LitCharacter { (litChar s) }
19 | | s= %TK_LitInteger { (litInteger s) }
20 | | s= %TK_LitFloat { (litFloat s) }
21 | | s= %TK_LitString { (litString s) }
22 | ;
23 |
24 | value ::=
25 | literal
26 | | "\\" "(" function
27 | | "\\@" "(" sfunction
28 | | "struct" ( "{" ss=slotList "}" { (record ss) }
29 | | "extends" e=expr "{" ss=slotList "}" { (record e ss) }
30 | )
31 | | "[" es=exprList "]" { (array es) }
32 | ;
33 |
34 | field ::=
35 | ":" t=expr "=" ( e=expr { (field t e) }
36 | | "_" { (field t (litNull)) }
37 | )
38 | ;
39 |
40 | function ::=
41 | ")" funBody
42 | | x= %TK_Identifier ":" t=expr v=funRest { (function x t v) }
43 | ;
44 |
45 | funRest ::=
46 | ")" funBody
47 | | "," x= %TK_Identifier ":" t=expr v=funRest { (function x t v) }
48 | ;
49 |
50 | sfunction ::=
51 | x= %TK_Identifier ")" v=funBody { (sfunction x v) }
52 | ;
53 |
54 | funBody ::=
55 | "(" function
56 | | "@" "(" sfunction
57 | | "->" expr
58 | | ":" t=expr "->" ( e=expr { (code t e) }
59 | | "_" { (code t (litNull)) }
60 | )
61 | ;
62 |
63 | slot ::=
64 | m= %TK_Identifier
65 | ( "(" f=function ";" { (slot m f) }
66 | | "@" "(" f=sfunction ";" { (slot m f) }
67 | | f=field ";" { (slot m f) }
68 | | "=" e=expr ";" { (slot m e) }
69 | )
70 | ;
71 |
72 | slotList ::=
73 | s=slot { (append [] s) }
74 | |*[ss] s=slot { (append ss s) }
75 | ;
76 |
77 | exprList ::=
78 | e=expr { (append [] e) }
79 | |*[es] "," e=expr { (append es e) }
80 | ;
81 |
82 | simple ::=
83 | value
84 | | s= %TK_Identifier { (identifier s) }
85 | | "(" e=expr ")" { e }
86 | | "{" e=statement "}" { e }
87 | ;
88 |
89 | mkApply[f,a] ::=
90 | ")" { (apply f a) }
91 | | "," app={ (apply f a) } b=expr mkApply[app, b]
92 | ;
93 |
94 | postfix ::=
95 | simple
96 | |*[f] ( "(" ( ")" { (call f) }
97 | | a=expr mkApply[f,a]
98 | )
99 | | "@" "(" ( ")" { (sapply f) }
100 | | a=expr ")" { (sapply f a) }
101 | )
102 | | "." m= %TK_Identifier { (project f m) }
103 | | "[" i=expr "]" { (arrayIndex f i) }
104 | | "^" { (load f) }
105 | )
106 | ;
107 |
108 | unary ::=
109 | postfix
110 | | "-" e=unary { (unary "-" e) }
111 | | "~" e=unary { (unary "~" e) }
112 | | "!" e=unary { (unary "!" e) }
113 | ;
114 |
115 | expr10 ::=
116 | unary
117 | |*[a] ( "*" b=unary { (binary "*" a b) }
118 | | "/" b=unary { (binary "/" a b) }
119 | | "%" b=unary { (binary "%" a b) }
120 | )
121 | ;
122 |
123 | expr20 ::=
124 | expr10
125 | |*[a] ( "+" b=expr10 { (binary "+" a b) }
126 | | "-" b=expr10 { (binary "-" a b) }
127 | )
128 | ;
129 |
130 | expr30 ::=
131 | expr20
132 | |*[a] ( "<<" b=expr20 { (binary "<<" a b) }
133 | | ">>" b=expr20 { (binary ">>" a b) }
134 | )
135 | ;
136 |
137 | expr40 ::=
138 | expr30
139 | |*[a] "&" b=expr30 { (binary "&" a b) }
140 | ;
141 |
142 | expr41 ::=
143 | expr40
144 | |*[a] "^^" b=expr40 { (binary "^" a b) }
145 | ;
146 |
147 | expr42 ::=
148 | expr41
149 | |*[a] "|" b=expr41 { (binary "|" a b) }
150 | ;
151 |
152 | expr50 ::=
153 | a=expr42 ( "==" b=expr42 { (binary "==" a b) }
154 | | "!=" b=expr42 { (binary "!=" a b) }
155 | | "<" b=expr42 { (binary "<" a b) }
156 | | "<=" b=expr42 { (binary "<=" a b) }
157 | | ">" b=expr42 { (binary ">" a b) }
158 | | ">=" b=expr42 { (binary ">=" a b) }
159 | | { a }
160 | )
161 | ;
162 |
163 | expr60 ::=
164 | expr50
165 | |*[a] "&&" b=expr50 { (binary "&&" a b) }
166 | ;
167 |
168 | expr61 ::=
169 | expr60
170 | |*[a] "||" b=expr60 { (binary "||" a b) }
171 | ;
172 |
173 | expr70 ::=
174 | expr61
175 | | "new" e1=expr61 { (alloc e1) }
176 | ;
177 |
178 | expr90 ::=
179 | a=expr70 (":=" b=expr70 { (store a b) }
180 | | { a }
181 | )
182 | ;
183 |
184 | expr ::=
185 | expr90
186 | | "if" "(" c=expr90 ")" "then" e1=expr90 "else" e2=expr90 { (if c e1 e2) }
187 | ;
188 |
189 | statement ::=
190 | e1=expr ";" (e2=statement { (let "" e1 e2) }
191 | | { e1 }
192 | )
193 | | "let" s= %TK_Identifier e1=letbody ";" e2=statement { (let s e1 e2) }
194 | | "var" s= %TK_Identifier ":" t1=expr "=" e1=expr ";" e2=statement
195 | { (let s (alloc (field t1 e1)) e2) }
196 | ;
197 |
198 |
199 | letbody ::=
200 | "=" expr
201 | | "(" function
202 | | "@" "(" sfunction
203 | ;
204 |
--------------------------------------------------------------------------------
/src/grammar/parser.grammar:
--------------------------------------------------------------------------------
1 |
2 | // An AST node, using Lisp-like syntax
3 | astNode ::=
4 | s = %TK_LitString { (tokenStr s) }
5 | | id = %TK_Identifier { (variable id) }
6 | | "[" "]" { (emptyList) }
7 | | "(" ( "append" e1=astNode e2=astNode ")" { (astAppend e1 e2) }
8 | | f = %TK_Identifier args=astNodeList ")" { (construct f args) }
9 | )
10 | ;
11 |
12 | astNodeList ::=
13 | { [] }
14 | |*[es] e=astNode { (append es e) }
15 | ;
16 |
17 | // Simple expressions, not including references
18 | simple ::=
19 | s = %TK_LitString { (keyword s) }
20 | | "%" s = %TK_Identifier { (token s) }
21 | | "(" e=recurseLeft ")" { e }
22 | | "{" e=astNode "}" { (action e) }
23 | ;
24 |
25 | arguments ::=
26 | id = %TK_Identifier { (append [] id) }
27 | |*[as] "," id = %TK_Identifier { (append as id) }
28 | ;
29 |
30 | // Parse arguments, if any, and construct a reference from id
31 | reference[id] ::=
32 | "[" as=arguments "]" { (reference id as) }
33 | | { (reference id []) }
34 | ;
35 |
36 | // Simple expression or reference
37 | simpleCall ::=
38 | simple
39 | | id = %TK_Identifier reference[id]
40 | ;
41 |
42 | // Continue the sequence if possible, otherwise stop and return e.
43 | maybeSequence[e] ::=
44 | sq=sequence { (sequence e sq) }
45 | | { e };
46 |
47 | sequence ::=
48 | e=simple maybeSequence[e]
49 | | id = %TK_Identifier ( "=" e=simpleCall sq=sequence { (sequence id e sq) }
50 | | e=reference[id] maybeSequence[e]
51 | );
52 |
53 | option ::=
54 | e1=sequence ( "|" e2=option { (option e1 e2) }
55 | | { e1 }
56 | );
57 |
58 | recurseLeft ::=
59 | e1=option ( "|*" "[" id = %TK_Identifier "]" e2=sequence
60 | { (recurseLeft id e1 e2 ) }
61 | | { e1 }
62 | );
63 |
64 | maybeArguments ::=
65 | "[" as=arguments "]" { as }
66 | | { [] };
67 |
68 | definition ::=
69 | id = %TK_Identifier as=maybeArguments "::=" e=recurseLeft ";"
70 | { (definition id as e) };
71 |
72 | definitionList ::=
73 | { [] }
74 | |*[ds] d=definition { (definitionList ds d) }
75 | ;
76 |
--------------------------------------------------------------------------------
/src/grammar/sexpr.grammar:
--------------------------------------------------------------------------------
1 |
2 | // An AST node, using Lisp-like syntax
3 | astNode ::=
4 | s = %TK_LitString { (tokenStr s) }
5 | | id = %TK_Identifier { (variable id) }
6 | | "[" "]" { (emptyList) }
7 | | "(" ( "append" e1=astNode e2=astNode ")" { (astAppend e1 e2) }
8 | | f = %TK_Identifier args=astNodeList ")" { (construct f args) }
9 | )
10 | ;
11 |
12 | astNodeList ::=
13 | { [] }
14 | |*[es] e=astNode { (append es e) }
15 | ;
16 |
--------------------------------------------------------------------------------
/src/lsa/BuildCallGraph.h:
--------------------------------------------------------------------------------
1 | //===- BuildCallGraph.h ----------------------------------------*- C++ --*-===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT in the LLVM repository for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 | // Construction of a call graph of C++ functions, paired with their Ohmu IR
10 | // translated bodies.
11 | //===----------------------------------------------------------------------===//
12 |
13 | #ifndef OHMU_LSA_BUILDCALLGRAPH_H
14 | #define OHMU_LSA_BUILDCALLGRAPH_H
15 |
16 | #include "clang/ASTMatchers/ASTMatchFinder.h"
17 |
18 | #include
19 | #include
20 | #include
21 | #include
22 |
23 | namespace ohmu {
24 | namespace lsa {
25 |
26 | /// Interface for actually constructing the call graph from the discovered calls
27 | /// and produced Ohmu IR. In this graph functions are identified by their C++
28 | /// mangled name.
29 | class CallGraphBuilder {
30 | public:
31 | virtual ~CallGraphBuilder() {}
32 |
33 | /// Request to store the information that there is a path in function From on
34 | /// which function To is called.
35 | virtual void AddCall(const std::string &From, const std::string &To) = 0;
36 |
37 | /// Request to store the generated ohmu IR representation of the function
38 | /// identified by Func.
39 | virtual void SetOhmuIR(const std::string &Func, const std::string &IR) = 0;
40 | };
41 |
42 | /// The standard implementation of GraphConstructor stores the call graph as a
43 | /// mapping from function identifier to CGNode.
44 | class DefaultCallGraphBuilder : public CallGraphBuilder {
45 | public:
46 | void AddCall(const std::string &From, const std::string &To) override;
47 | void SetOhmuIR(const std::string &Func, const std::string &IR) override;
48 |
49 | void Print(std::ostream &Out);
50 |
51 | class CallGraphNode {
52 | public:
53 | void AddCall(const std::string &To) { OutgoingCalls.insert(To); }
54 | void SetIR(const std::string &IR) { OhmuIR = IR; }
55 | void Print(std::ostream &Out);
56 |
57 | const std::unordered_set *GetCalls() const {
58 | return &OutgoingCalls;
59 | }
60 | const std::string &GetIR() const { return OhmuIR; }
61 |
62 | private:
63 | std::unordered_set OutgoingCalls;
64 | std::string OhmuIR;
65 | };
66 |
67 | const std::unordered_map> &
68 | GetGraph() {
69 | return Graph;
70 | }
71 |
72 | private:
73 | /// Returns the CGNode currently constructed for the function identified by
74 | /// Func. Creates a new node if none is associated with this function yet.
75 | CallGraphNode *GetNodeByName(const std::string &Func);
76 |
77 | std::unordered_map>
78 | Graph; // Mapping function names to their nodes.
79 | };
80 |
81 | /// Tool to be used for creating call graphs with Ohmu IR for each function.
82 | class CallGraphBuilderTool {
83 | public:
84 | /// Create the required AST matchers and register them with 'Finder'.
85 | /// Matches all function declarations.
86 | void RegisterMatchers(CallGraphBuilder &Builder,
87 | clang::ast_matchers::MatchFinder *Finder);
88 |
89 | private:
90 | /// This tool creates and owns its MatchCallbacks.
91 | std::vector>
92 | match_callbacks_;
93 | };
94 |
95 | } // namespace lsa
96 | } // namespace ohmu
97 |
98 | #endif // OHMU_LSA_BUILDCALLGRAPH_H
99 |
--------------------------------------------------------------------------------
/src/lsa/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_library(lsa
2 | BuildCallGraph.cpp
3 | )
4 |
5 | # There is quite some repetition here, but it does not as simple to remove
6 | # dependencies as it may appear.
7 | target_link_libraries(lsa
8 | clangASTMatchers
9 | clangTooling
10 | clangDriver
11 | clangAST
12 | clangLex
13 | clangParse
14 | clangBasic
15 | clangFrontend
16 | clangEdit
17 | clangAST
18 | clangSerialization
19 | clangSema
20 | clangAST
21 | clangAnalysis
22 | clangASTMatchers
23 | clangFrontendTool
24 | clangDynamicASTMatchers
25 | clangTooling
26 | clangAST
27 | clangASTMatchers
28 | clangBasic
29 | clangFrontend
30 | clangLex
31 | clangRewrite
32 | clangTooling
33 | clangToolingCore
34 |
35 | ohmuTil
36 |
37 | LLVMMC
38 | LLVMMCParser
39 | LLVMIRReader
40 | LLVMOption
41 | LLVMCore
42 | LLVMSupport
43 | )
44 |
45 | add_subdirectory (examples)
--------------------------------------------------------------------------------
/src/lsa/GraphComputation.h:
--------------------------------------------------------------------------------
1 | //===- GraphComputation.h --------------------------------------*- C++ --*-===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT in the LLVM repository for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 | // The purpose of this level of indirection is to easily replace the standalone
10 | // framework with a different framework providing the same GraphComputation and
11 | // GraphVertex interface.
12 | //===----------------------------------------------------------------------===//
13 |
14 | #ifndef OHMU_LSA_GRAPHCOMPUTATION_H
15 | #define OHMU_LSA_GRAPHCOMPUTATION_H
16 |
17 | #include "StandaloneGraphComputation.h"
18 |
19 | /// To provide serialization in Google's Pregel framework.
20 | template class StringCoderCustom;
21 |
22 | namespace ohmu {
23 | namespace lsa {
24 |
25 | // Adapted from til/Bytecode.cpp:
26 | static void writeUInt64ToString(uint64_t V, string *result) {
27 | if (V == 0) {
28 | result->push_back('\0');
29 | return;
30 | }
31 | while (V > 0) {
32 | uint64_t V2 = V >> 7;
33 | uint8_t Hibit = (V2 == 0) ? 0 : 0x80;
34 | // Write lower 7 bits. The 8th bit is high if there's more to write.
35 | result->push_back(static_cast((V & 0x7Fu) | Hibit));
36 | V = V2;
37 | }
38 | }
39 |
40 | static uint64_t readUInt64FromString(const string &str, int &index) {
41 | uint64_t V = 0;
42 | for (unsigned B = 0; B < 64; B += 7) {
43 | uint64_t Byt = str[index++];
44 | V = V | ((Byt & 0x7Fu) << B);
45 | if ((Byt & 0x80) == 0)
46 | break;
47 | }
48 | return V;
49 | }
50 |
51 | } // namespace lsa
52 | } // namespace ohmu
53 |
54 | #endif // OHMU_LSA_GRAPHCOMPUTATION_H
55 |
--------------------------------------------------------------------------------
/src/lsa/GraphDeserializer.h:
--------------------------------------------------------------------------------
1 | #ifndef OHMU_LSA_GRAPHDESERIALIZER_H
2 | #define OHMU_LSA_GRAPHDESERIALIZER_H
3 |
4 | #include "lsa/StandaloneGraphComputation.h"
5 | #include "til/Bytecode.h"
6 |
7 | namespace ohmu {
8 | namespace lsa {
9 |
10 | template
11 | class GraphDeserializer {
12 | public:
13 | static void read(const std::string& FileName,
14 | StandaloneGraphBuilder *Builder) {
15 | ohmu::MemRegion Arena;
16 | ohmu::til::BytecodeFileReader ReadStream(FileName,
17 | ohmu::MemRegionRef(&Arena));
18 |
19 | int32_t NFunc = ReadStream.readInt32();
20 | for (unsigned i = 0; i < NFunc; i++) {
21 | std::string Function = ReadStream.readString();
22 | std::string OhmuIR = ReadStream.readString();
23 | typename GraphTraits::VertexValueType Value;
24 | Builder->addVertex(Function, OhmuIR, Value);
25 |
26 | int32_t NNodes = ReadStream.readInt32();
27 | for (unsigned n = 0; n < NNodes; n++) {
28 | std::string Call = ReadStream.readString();
29 | Builder->addCall(Function, Call);
30 | }
31 | }
32 | }
33 | };
34 |
35 | } // namespace lsa
36 | } // namespace ohmu
37 |
38 | #endif // OHMU_LSA_GRAPHDESERIALIZER_H
39 |
--------------------------------------------------------------------------------
/src/lsa/GraphSerializer.h:
--------------------------------------------------------------------------------
1 | #ifndef OHMU_LSA_GRAPHSERIALIZER_H
2 | #define OHMU_LSA_GRAPHSERIALIZER_H
3 |
4 | #include "clang/Analysis/Til/Bytecode.h"
5 | #include "lsa/BuildCallGraph.h"
6 |
7 | namespace ohmu {
8 | namespace lsa {
9 |
10 | class GraphSerializer {
11 | public:
12 | static void write(const std::string& FileName,
13 | DefaultCallGraphBuilder *Builder) {
14 | ohmu::til::BytecodeFileWriter WriteStream(FileName);
15 |
16 | WriteStream.writeInt32(Builder->GetGraph().size());
17 | for (const auto &Pair : Builder->GetGraph()) {
18 | WriteStream.writeString(Pair.first);
19 | WriteStream.writeString(Pair.second->GetIR());
20 | WriteStream.writeInt32(Pair.second->GetCalls()->size());
21 | for (const std::string &Call : *Pair.second->GetCalls()) {
22 | WriteStream.writeString(Call);
23 | }
24 | }
25 |
26 | WriteStream.flush();
27 | }
28 | };
29 |
30 | } // namespace lsa
31 | } // namespace ohmu
32 |
33 | #endif // OHMU_LSA_GRAPHSERIALIZER_H
34 |
--------------------------------------------------------------------------------
/src/lsa/StandaloneRunner.h:
--------------------------------------------------------------------------------
1 | //===- StandaloneRunner.h --------------------------------------*- C++ --*-===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT in the LLVM repository for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 | // Convenience class providing methods to run graph computations with the LSA
10 | // framework.
11 | //===----------------------------------------------------------------------===/
12 |
13 | #ifndef OHMU_LSA_STANDALONERUNNER_H
14 | #define OHMU_LSA_STANDALONERUNNER_H
15 |
16 | #include "clang/Tooling/CommonOptionsParser.h"
17 | #include "llvm/Support/CommandLine.h"
18 | #include "lsa/GraphDeserializer.h"
19 | #include "lsa/StandaloneGraphComputation.h"
20 |
21 | #include
22 |
23 | namespace ohmu {
24 | namespace lsa {
25 |
26 | static llvm::cl::opt NThreads("t",
27 | llvm::cl::desc("Specify number of threads"),
28 | llvm::cl::value_desc("number"),
29 | llvm::cl::Optional);
30 |
31 | static llvm::cl::opt
32 | InputFile("i", llvm::cl::desc("Specify input file"),
33 | llvm::cl::value_desc("file"), llvm::cl::Required);
34 |
35 | template class StandaloneRunner {
36 | public:
37 | StandaloneRunner(int argc, const char *argv[]) {
38 | llvm::cl::ParseCommandLineOptions(argc, argv);
39 | }
40 |
41 | void readCallGraph() {
42 | GraphDeserializer::read(InputFile.getValue(),
43 | &ComputationGraphBuilder);
44 | }
45 |
46 | void runComputation() {
47 | if (NThreads.getNumOccurrences() > 0)
48 | ComputationGraphBuilder.setNThreads(NThreads.getValue());
49 |
50 | ComputationGraphBuilder.run(&Factory);
51 | }
52 |
53 | void printComputationResult(bool Alphabetic = false) {
54 | std::unique_ptr> Computation(
55 | Factory.createComputation());
56 | if (Alphabetic)
57 | ComputationGraphBuilder.sortVertices();
58 | for (const auto &Vertex : ComputationGraphBuilder.getVertices())
59 | std::cout << Vertex.id() << ": " << Computation->output(&Vertex) << "\n";
60 | }
61 |
62 | private:
63 | ohmu::lsa::StandaloneGraphBuilder ComputationGraphBuilder;
64 | ohmu::lsa::GraphComputationFactory Factory;
65 | };
66 |
67 | } // namespace lsa
68 | } // namespace ohmu
69 |
70 | #endif // OHMU_LSA_STANDALONERUNNER_H
71 |
--------------------------------------------------------------------------------
/src/lsa/examples/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_library(lsa_example_scc
2 | SCCComputation.cpp
3 | )
4 |
5 | add_library(lsa_example_escape
6 | EscapeAnalysis.cpp
7 | )
8 |
9 | # Would prefer to link these against til instead of ohmuTil. However, there
10 | # seems to be a problem with the Ohmu version of MemRegion? Or at least it
11 | # behaves differently.
12 | target_link_libraries(lsa_example_scc
13 | ohmuTil LLVMOption
14 | )
15 | target_link_libraries(lsa_example_escape
16 | ohmuTil LLVMOption
17 | )
--------------------------------------------------------------------------------
/src/lsa/examples/ExampleOhmuComputation.h:
--------------------------------------------------------------------------------
1 | //===- SCCComputation.h ----------------------------------------*- C++ --*-===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT in the LLVM repository for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 | // Simple computation that checks whether a function, or any of the functions it
10 | // calls, modifies a global variable. It serves as an example of how to run an
11 | // Ohmu analysis, and is by no means perfect :)
12 | //
13 | // The computation only finds direct changes to global variables, not changes
14 | // via e.g. aliased values or passed-by-reference. It also has false positive,
15 | // e.g. when assigning to a local reference.
16 | //===----------------------------------------------------------------------===//
17 |
18 | #ifndef OHMU_LSA_EXAMPLES_EXAMPLEOHMUOMPUTATION_H
19 | #define OHMU_LSA_EXAMPLES_EXAMPLEOHMUOMPUTATION_H
20 |
21 | // NOTE: Whatever is included should not include ohmu's version of MemRegion.h,
22 | // since in a standalone computation this code is combined with the call graph
23 | // builder, which uses the version of MemRegion.h residing in Clang, which is
24 | // different. The solution is to let the standalone version also generate
25 | // intermediate results on disks, allowing us to create separate binaries for
26 | // call graph generation and analysis.
27 |
28 | #include "clang/Analysis/Til/TILTraverse.h"
29 | #include "lsa/GraphComputation.h"
30 |
31 | namespace ohmu {
32 | namespace lsa {
33 |
34 | class OhmuComputation;
35 |
36 | template <> struct GraphTraits {
37 | // True if we think this function changes a global variable.
38 | typedef bool VertexValueType;
39 | typedef bool MessageValueType;
40 | };
41 |
42 | /// Simple traversal that looks for any store operation of the kind "a.b := c"
43 | /// where "a" is not part of a record. If such a store operation exists, we
44 | /// conclude that "b" is a global variable and mark this function as modifying
45 | /// global variables.
46 | class FindGlobalModification
47 | : public ohmu::til::Traversal,
48 | public ohmu::til::DefaultScopeHandler,
49 | public ohmu::til::DefaultReducer {
50 | public:
51 | typedef ohmu::til::Traversal SuperTv;
52 |
53 | FindGlobalModification() : MadeModification(false) {}
54 |
55 | void reduceStore(ohmu::til::Store *E) {
56 | if (auto *Dest = ohmu::dyn_cast(E->destination())) {
57 | if (!Dest->record()) {
58 | MadeModification = true;
59 | }
60 | }
61 | }
62 |
63 | /// Shortcut traversal if we already know that this function makes global
64 | /// modifications.
65 | template void traverse(T *E, ohmu::til::TraversalKind K) {
66 | if (!MadeModification)
67 | SuperTv::traverse(E, K);
68 | }
69 |
70 | /// Returns true if the traversed function modifies a global variable.
71 | bool madeModification() { return MadeModification; }
72 |
73 | protected:
74 | bool MadeModification;
75 | };
76 |
77 | /// Distributed graph computation that determines whether calling a function
78 | /// changes a global variable. In the first step it computes the changes made
79 | /// in this function body; then forwards this information to its callers.
80 | class OhmuComputation : public GraphComputation {
81 | public:
82 | void computePhase(GraphVertex *Vertex, const string &Phase,
83 | MessageList Messages) override {
84 |
85 | // First step, compute if this function modifies a global variable. If so,
86 | // update the state and inform callers.
87 | if (stepCount() == 0) {
88 | *Vertex->mutableValue() = modifiesGlobal(Vertex);
89 |
90 | if (Vertex->value())
91 | for (const string &Out : Vertex->outgoingCalls())
92 | Vertex->sendMessage(Out, true);
93 |
94 | // Second step; only care about incoming messages if so far we think this
95 | // function does not change global variables. If one of the functions we
96 | // call informs us that it changes a global variable, update the state
97 | // and inform callers of this function.
98 | } else if (!Vertex->value()) {
99 | for (const Message &In : Messages) {
100 | if (In.value()) {
101 | *Vertex->mutableValue() = true;
102 | }
103 | }
104 | if (Vertex->value())
105 | for (const string &Out : Vertex->outgoingCalls())
106 | Vertex->sendMessage(Out, true);
107 | }
108 |
109 | Vertex->voteToHalt();
110 | }
111 |
112 | string output(const GraphVertex *Vertex) const override {
113 | return Vertex->value() ? "yes" : "no";
114 | }
115 |
116 | private:
117 | /// Run traversal to determine if this function changes a global variable.
118 | bool modifiesGlobal(GraphVertex *Vertex) {
119 | if (!Vertex->ohmuIR()) {
120 | std::cerr << "Could not read OhmuIR of " << Vertex->id() << ".\n";
121 | return false;
122 | }
123 |
124 | FindGlobalModification Finder;
125 | Finder.traverseAll(Vertex->ohmuIR());
126 | return Finder.madeModification();
127 | }
128 | };
129 |
130 | } // namespace ohmu
131 | } // namespace lsa
132 |
133 | #endif // OHMU_LSA_EXAMPLES_EXAMPLEOHMUOMPUTATION_H
134 |
--------------------------------------------------------------------------------
/src/lsa/examples/SCCComputation.cpp:
--------------------------------------------------------------------------------
1 | //===- SCCComputation.cpp --------------------------------------*- C++ --*-===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT in the LLVM repository for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 |
10 | #include
11 |
12 | #include "SCCComputation.h"
13 |
14 | namespace {
15 | /// Phase identifiers
16 | const char kPhaseForward[] = "phase_forward";
17 | const char kPhaseBackward[] = "phase_backward";
18 | const char kPhaseDecompose[] = "phase_decompose";
19 |
20 | /// Special value representing 'infinity' as vertex identity. Thus assuming that
21 | /// this is not a value that can appear as a real identity.
22 | const char kInfinity[] = "INF";
23 | } // end namespace
24 |
25 | namespace ohmu {
26 | namespace lsa {
27 |
28 | SCCNode::SCCNode() {
29 | ForwardMin = kInfinity;
30 | BackwardMin = kInfinity;
31 | }
32 |
33 | string SCCComputation::transition(const string &Phase) {
34 | if (!shouldReiterate())
35 | return "HALT";
36 | if (Phase == "START") {
37 | return kPhaseForward;
38 | } else if (Phase == kPhaseForward) {
39 | return kPhaseBackward;
40 | } else if (Phase == kPhaseBackward) {
41 | return kPhaseDecompose;
42 | } else if (Phase == kPhaseDecompose) {
43 | return kPhaseForward;
44 | }
45 | return "HALT";
46 | }
47 |
48 | void SCCComputation::computePhase(GraphVertex *Vertex, const string &Phase,
49 | MessageList Messages) {
50 | // As long as some vertex is not in a known SCC, we should keep cycling
51 | // through the phases.
52 | if (!inSCC(Vertex)) {
53 | Vertex->voteToReiterate();
54 | if (Phase == kPhaseForward) {
55 | forwardMin(Vertex, Messages);
56 | } else if (Phase == kPhaseBackward) {
57 | backwardMin(Vertex, Messages);
58 | } else if (Phase == kPhaseDecompose) {
59 | decomposeGraph(Vertex, Messages);
60 | }
61 | }
62 |
63 | // Always halt; only wake up on incoming messages.
64 | Vertex->voteToHalt();
65 | }
66 |
67 | /// First set the current ForwardMin to this vertex' id and forward it on all
68 | /// outgoing calls. While the incoming messages contain an id lower than
69 | /// ForwardMin, update it and forward the new lowest value.
70 | void SCCComputation::forwardMin(GraphVertex *Vertex, MessageList Messages) {
71 | if (stepCount() == 0) {
72 | (*Vertex->mutableValue()).ForwardMin = Vertex->id();
73 | for (const string &Out : Vertex->outgoingCalls()) {
74 | Vertex->sendMessage(Out, Vertex->value().ForwardMin);
75 | }
76 | } else {
77 | bool updated = false;
78 | for (const Message &Incoming : Messages) {
79 | if (Incoming.value().compare(Vertex->value().ForwardMin) < 0 ||
80 | Vertex->value().ForwardMin == kInfinity) {
81 | (*Vertex->mutableValue()).ForwardMin = Incoming.value();
82 | updated = true;
83 | }
84 | }
85 | // If we updated ForwardMin, inform our forward-neighbours.
86 | if (updated) {
87 | for (const string &Out : Vertex->outgoingCalls()) {
88 | Vertex->sendMessage(Out, Vertex->value().ForwardMin);
89 | }
90 | }
91 | }
92 | }
93 |
94 | /// First set the current BackwardMin to this vertex' id if it received its
95 | /// own id as ForwardMin, otherwise to infinite. While the incoming messages
96 | /// contain an id lower than BackwardMin, update it and backward the new value.
97 | void SCCComputation::backwardMin(GraphVertex *Vertex, MessageList Messages) {
98 | if (stepCount() == 0) {
99 | if (Vertex->id() != Vertex->value().ForwardMin) {
100 | (*Vertex->mutableValue()).BackwardMin = kInfinity;
101 | } else {
102 | (*Vertex->mutableValue()).BackwardMin = Vertex->id();
103 | for (const string &In : Vertex->incomingCalls()) {
104 | Vertex->sendMessage(In, Vertex->value().BackwardMin);
105 | }
106 | }
107 | } else {
108 | bool updated = false;
109 | for (const Message &Incoming : Messages) {
110 | if (Incoming.value().compare(Vertex->value().BackwardMin) < 0 ||
111 | Vertex->value().BackwardMin == kInfinity) {
112 | (*Vertex->mutableValue()).BackwardMin = Incoming.value();
113 | updated = true;
114 | }
115 | }
116 | // If we updated BackwardMin, inform our backward-neighbours.
117 | if (updated) {
118 | for (const string &In : Vertex->incomingCalls()) {
119 | Vertex->sendMessage(In, Vertex->value().BackwardMin);
120 | }
121 | }
122 | }
123 | }
124 |
125 | /// In step 0, send on all outgoing calls this vertex' partition id.
126 | /// In SCCComputation 1, remove calls to vertices that sent a different
127 | /// partition id.
128 | void SCCComputation::decomposeGraph(GraphVertex *Vertex, MessageList Messages) {
129 | string partition = partitionID(Vertex);
130 | if (stepCount() == 0) {
131 | for (const string &Out : Vertex->outgoingCalls()) {
132 | Vertex->sendMessage(Out, partition);
133 | }
134 | } else {
135 | for (const Message &Incoming : Messages) {
136 | if (Incoming.value() != partition) {
137 | removeCall(Incoming.source(), Vertex->id());
138 | }
139 | }
140 | }
141 | }
142 |
143 | bool SCCComputation::inSCC(GraphVertex *Vertex) {
144 | return Vertex->value().ForwardMin != kInfinity &&
145 | Vertex->value().ForwardMin == Vertex->value().BackwardMin;
146 | }
147 |
148 | string SCCComputation::partitionID(const GraphVertex *Vertex) const {
149 | std::stringstream Stream;
150 | Stream << Vertex->value().ForwardMin;
151 | Stream << ":";
152 | Stream << Vertex->value().BackwardMin;
153 | return Stream.str();
154 | }
155 |
156 | } // namespace ohmu
157 | } // namespace lsa
158 |
--------------------------------------------------------------------------------
/src/lsa/examples/SCCComputation.h:
--------------------------------------------------------------------------------
1 | //===- SCCComputation.h ----------------------------------------*- C++ --*-===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT in the LLVM repository for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 | // Example distributed graph computation, computing the strongly connected
10 | // components (SCC) in a graph. This is an implementation of the unoptimized SCC
11 | // algorithm described by Yan et al. in "Pregel Algorithms for Graph
12 | // Connectivity Problems with Performance Guarantees" from VLDB 2014:
13 | //
14 | // http://www.vldb.org/pvldb/vol7/p1821-yan.pdf
15 | //
16 | // The algorithm consists of three phases which are repeated until all SCCs are
17 | // found:
18 | // 1) forward-min: vertices keep communicating the minimal vertex-id they have
19 | // encountered over their forward edges until no lower id is received.
20 | // 2) backward-min: vertices keep communicating the minimal vertex-id they have
21 | // encountered over their backward edges until no lower id is received.
22 | // 3) decompose: edges between vertices whose pairs (forwardMin, backwardMin),
23 | // ie their partitions, are not equal are removed
24 | // Vertices are in an SCC when forwardMin = backwardMin.
25 | // The SCCs are identified by the pair (forwardMin, backwardMin).
26 | //===----------------------------------------------------------------------===//
27 |
28 | #ifndef OHMU_LSA_EXAMPLES_SCCCOMPUTATION_H
29 | #define OHMU_LSA_EXAMPLES_SCCCOMPUTATION_H
30 |
31 | #include "lsa/GraphComputation.h"
32 |
33 | namespace ohmu {
34 | namespace lsa {
35 |
36 | /// The type of the value at a vertex during SCC computation.
37 | class SCCNode {
38 | public:
39 | SCCNode();
40 |
41 | /// The minimal ID encountered sending over the outgoing calls.
42 | string ForwardMin;
43 |
44 | /// The minimal ID encountered sending over the incoming calls.
45 | string BackwardMin;
46 | };
47 |
48 | class SCCComputation;
49 |
50 | template <> struct GraphTraits {
51 | typedef SCCNode VertexValueType;
52 | typedef string MessageValueType;
53 | };
54 |
55 | class SCCComputation : public GraphComputation {
56 | public:
57 | void computePhase(GraphVertex *Vertex, const string &Phase,
58 | MessageList Messages) override;
59 |
60 | string transition(const string &Phase) override;
61 |
62 | string output(const GraphVertex *Vertex) const override {
63 | return partitionID(Vertex);
64 | }
65 |
66 | private:
67 | /// Returns true if the SCC of this vertex is known.
68 | bool inSCC(GraphVertex *Vertex);
69 |
70 | /// The computation phases.
71 | void forwardMin(GraphVertex *Vertex, MessageList Messages);
72 | void backwardMin(GraphVertex *Vertex, MessageList Messages);
73 | void decomposeGraph(GraphVertex *Vertex, MessageList Messages);
74 |
75 | /// Send a message with this vertex' current minimal value. The argument
76 | /// indicates whether we are in the forward or backward phase.
77 | void sendUpdateMessage(GraphVertex *Vertex, bool Forward);
78 |
79 | /// Returns this vertex' partition id. This is the concatenation of the
80 | /// ForwardMin and BackwardMin value.
81 | string partitionID(const GraphVertex *Vertex) const;
82 | };
83 |
84 | } // namespace ohmu
85 | } // namespace lsa
86 |
87 | /// Serialization for Google's Pregel framework.
88 | template <> class StringCoderCustom {
89 | public:
90 | static void Encode(const ohmu::lsa::SCCNode &value, string *result) {
91 | result->clear();
92 | ohmu::lsa::writeUInt64ToString(value.ForwardMin.size(), result);
93 | result->append(value.ForwardMin);
94 | ohmu::lsa::writeUInt64ToString(value.BackwardMin.size(), result);
95 | result->append(value.BackwardMin);
96 | }
97 |
98 | static bool Decode(const string &str, ohmu::lsa::SCCNode *result) {
99 | int index = 0;
100 | uint64_t length = ohmu::lsa::readUInt64FromString(str, index);
101 | if (str.length() < index + length)
102 | return false;
103 | result->ForwardMin = str.substr(index, length);
104 | index += length;
105 | length = ohmu::lsa::readUInt64FromString(str, index);
106 | if (str.length() < index + length)
107 | return false;
108 | result->BackwardMin = str.substr(index, length);
109 | return true;
110 | }
111 | };
112 |
113 | #endif // OHMU_LSA_EXAMPLES_SCCCOMPUTATION_H
114 |
--------------------------------------------------------------------------------
/src/ohmu/examples/argument_dependencies.ohmu:
--------------------------------------------------------------------------------
1 |
2 |
3 | Array(nDim: Int) = struct {
4 | dim (i: Int): Int -> _;
5 | data(dims: List(Int)): Int -> _;
6 |
7 | elem = elemImpl(0, []);
8 |
9 | elemImpl(d: Int, dims: List(Int)) =
10 | if (d >= nDim) then
11 | (: Int -> data(dims)())
12 | else
13 | \(i: Int) = elemImpl(d+1, append(dims, dim(i)));
14 | };
15 |
16 |
17 | varArgs(n: Int, args: List(Int), f: Function) =
18 | if (n == 0)
19 | (: T -> f(args))
20 | else
21 | \(i: Int) = varArgs(n-1, append(args, i))
22 |
23 |
24 | printIntegers(n: Int) = varArgs(n, [], print)
25 |
--------------------------------------------------------------------------------
/src/ohmu/test_dependent_functions.ohmu:
--------------------------------------------------------------------------------
1 |
2 | foo(i: Int): Int -> 0;
3 |
4 | bar(i: Int) ->
5 | if (i == 0) then
6 | \(): Int -> 0
7 | else
8 | \(x: Int) -> bar(i-1);
9 |
10 |
11 | testGood(): Int -> {
12 | let a = foo(0)();
13 | let b = bar(0)();
14 | let c = bar(1, 0)();
15 | let d = bar(2, 0, 0)();
16 | d;
17 | };
18 |
19 | /*
20 | testBad0(): Int -> {
21 | let a = bar(0, 0)();
22 | a;
23 | };
24 |
25 | testBad1(): Int -> {
26 | let a = bar(1)();
27 | a;
28 | };
29 | */
30 |
--------------------------------------------------------------------------------
/src/ohmu/test_literal.ohmu:
--------------------------------------------------------------------------------
1 |
2 | 123;
3 | 0xFFFF;
4 |
5 | 123.456;
6 | 123.456e+2;
7 | 123.456e-3;
8 | 123.456E+5;
9 | 123E+6;
10 | 123e-6;
11 |
12 | "Hello!";
13 |
14 | 'c';
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/ohmu/test_loop.ohmu:
--------------------------------------------------------------------------------
1 |
2 | sum(n: Int): Int -> {
3 | let loop@(loop)(i: Int, total: Int): Int -> {
4 | if (i == 0) then total
5 | else loop@()(i-1, total+i)();
6 | };
7 | loop@()(n, 0)();
8 | };
9 |
--------------------------------------------------------------------------------
/src/ohmu/test_module.ohmu:
--------------------------------------------------------------------------------
1 |
2 | pi = 3; // The biblical pi
3 |
4 | circle = \@self struct {
5 | radius = 10;
6 |
7 | area(): Int -> 2 * pi * radius;
8 | };
9 |
10 | circleArea(): Int -> circle.area();
11 |
12 | getArea(c: circle): Int -> c.area();
13 |
14 | foo(a: Int, b: Int): Int -> a + b;
15 |
16 | bar(a: Int, b: Int): Int -> foo(a, b) * foo(b, a);
--------------------------------------------------------------------------------
/src/ohmu/test_scalartypes.ohmu:
--------------------------------------------------------------------------------
1 |
2 | foo(a: Int, b: Int, c: Float, d: Double): Int -> {
3 | let x = a*a + b*b;
4 | let y = c*c + d*d;
5 | let z = x + y;
6 | let w = -x + y + z;
7 | let ans = if (x > z) then ~a else b;
8 | ans+1;
9 | };
10 |
11 |
12 | bar(): Int -> {
13 | var a = 0;
14 | var b = 1;
15 | let c = if (a^ < b^) then a^ else b^;
16 | c;
17 | };
18 |
19 |
--------------------------------------------------------------------------------
/src/ohmu/test_ssa.ohmu:
--------------------------------------------------------------------------------
1 |
2 | sum(n: Int): Int -> {
3 | var i: Int = 0;
4 | var total: Int = 0;
5 | let loop@(loop): Int -> {
6 | if (i^ >= n) then total^
7 | else {
8 | total := total^ + i^;
9 | i := i^ + 1;
10 | loop@()();
11 | };
12 | };
13 | loop@()();
14 | };
15 |
16 |
--------------------------------------------------------------------------------
/src/parser/ASTNode.cpp:
--------------------------------------------------------------------------------
1 | //===- ASTNode.cpp ---------------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 |
18 | #include "parser/ASTNode.h"
19 |
20 |
21 | namespace ohmu {
22 | namespace parsing {
23 | namespace ast {
24 |
25 |
26 | void PrettyPrinter::print(const ASTNode* node, std::ostream &ss) {
27 | switch (node->opcode()) {
28 | case ASTNode::AST_None:
29 | printNone(ss);
30 | return;
31 | case ASTNode::AST_Variable:
32 | printVariable(cast(node), ss);
33 | return;
34 | case ASTNode::AST_TokenStr:
35 | printTokenStr(cast(node), ss);
36 | return;
37 | case ASTNode::AST_Construct:
38 | printConstruct(cast(node), ss);
39 | return;
40 | case ASTNode::AST_EmptyList:
41 | printEmptyList(cast(node), ss);
42 | return;
43 | case ASTNode::AST_Append:
44 | printAppend(cast(node), ss);
45 | return;
46 | }
47 | }
48 |
49 | void PrettyPrinter::printNone(std::ostream& ss) {
50 | ss << "null";
51 | }
52 |
53 | void PrettyPrinter::printVariable(const Variable* e, std::ostream& ss) {
54 | ss << e->name();
55 | }
56 |
57 | void PrettyPrinter::printTokenStr(const TokenStr* e, std::ostream& ss) {
58 | ss << "\"";
59 | ss << e->string();
60 | ss << "\"";
61 | }
62 |
63 | void PrettyPrinter::printConstruct(const Construct* e, std::ostream& ss) {
64 | ss << "(" << e->opcodeName();
65 | for (unsigned i = 0; i < e->arity(); ++i) {
66 | ss << " ";
67 | print(e->subExpr(i), ss);
68 | }
69 | ss << ")";
70 | }
71 |
72 | void PrettyPrinter::printEmptyList(const EmptyList* e, std::ostream& ss) {
73 | ss << "[]";
74 | }
75 |
76 | void PrettyPrinter::printAppend(const Append* e, std::ostream& ss) {
77 | ss << "(append ";
78 | print(e->list(), ss);
79 | ss << " ";
80 | print(e->item(), ss);
81 | ss << ")";
82 | }
83 |
84 |
85 |
86 | } // namespace ast
87 | } // namespace parsing
88 | } // namespace ohmu
89 |
--------------------------------------------------------------------------------
/src/parser/BNFParser.h:
--------------------------------------------------------------------------------
1 | //===- BNFParser.h ---------------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 | //
18 | // BNFParser is a concrete parser. It parses grammar files in BNF form, and
19 | // will construct other parsers from them.
20 | //
21 | //===----------------------------------------------------------------------===//
22 |
23 | #include
24 |
25 | #include "parser/ASTNode.h"
26 | #include "parser/DefaultLexer.h"
27 | #include "parser/Parser.h"
28 | #include "parser/ParserBuilder.h"
29 |
30 |
31 | #ifndef OHMU_BNF_PARSER_H
32 | #define OHMU_BNF_PARSER_H
33 |
34 | namespace ohmu {
35 | namespace parsing {
36 |
37 |
38 | class BNFParser : public Parser {
39 | public:
40 | enum BNF_Opcode {
41 | // ParseRules
42 | BNF_None = 0,
43 | BNF_Token,
44 | BNF_Keyword,
45 | BNF_Sequence,
46 | BNF_Option,
47 | BNF_RecurseLeft,
48 | BNF_Reference,
49 | BNF_Action,
50 | BNF_NamedDefinition,
51 | BNF_DefinitionList,
52 |
53 | // ASTNodes
54 | BNF_Variable,
55 | BNF_TokenStr,
56 | BNF_Construct,
57 | BNF_EmptyList,
58 | BNF_Append
59 | };
60 |
61 | enum BNF_Result {
62 | BPR_ParseRule = ParseResult::PRS_UserDefined,
63 | BPR_ASTNode
64 | };
65 |
66 | // Main entry point.
67 | // Read grammar definition from file, and use it to initialize parser.
68 | // If trace is true, will print out debugging information.
69 | static bool initParserFromFile(Parser &parser, FILE* file, bool trace=false);
70 |
71 | public:
72 | BNFParser(Lexer *lexer) : Parser(lexer) {
73 | initMap();
74 | }
75 | ~BNFParser() { }
76 |
77 | // Initialize opcode dictionary. (Dictionary used by lookupOpcode.)
78 | void initMap();
79 |
80 | // Get the name of op. Used to construct opcode dictionary.
81 | const char* getOpcodeName(BNF_Opcode op);
82 |
83 | // Lookup the opcode for string s.
84 | unsigned lookupOpcode(const std::string &s) override;
85 |
86 | // Make a ParseRule or ASTNode.
87 | ParseResult makeExpr(unsigned op, unsigned arity, ParseResult *prs) override;
88 |
89 | // Create the default BNF grammar.
90 | void defineGrammar();
91 |
92 | // The BNF parser parses a grammar definition in BNF form,
93 | // and it will add all of the definitions to the target parser.
94 | void setTarget(Parser* p) { targetParser_ = p; }
95 |
96 | public:
97 | std::unordered_map opcodeNameMap_;
98 | Parser* targetParser_ = nullptr;
99 | };
100 |
101 |
102 | } // end namespace parser
103 | } // end namespace ohmu
104 |
105 | #endif // OHMU_BNF_PARSER_H
106 |
107 |
108 |
--------------------------------------------------------------------------------
/src/parser/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8)
2 |
3 | # find_package(Readline REQUIRED)
4 |
5 | add_library(parser STATIC
6 | Lexer.cpp
7 | DefaultLexer.cpp
8 | Parser.cpp
9 | ASTNode.cpp
10 | BNFParser.cpp
11 | TILParser.cpp
12 | )
13 |
14 | target_link_libraries(parser base)
15 |
16 | if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
17 | target_link_libraries(parser readline)
18 | endif()
19 |
--------------------------------------------------------------------------------
/src/parser/DefaultLexer.h:
--------------------------------------------------------------------------------
1 | //===- DefaultLexer.h ------------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 | //
18 | // This file defines the default lexer for ohmu. Tokens consist of:
19 | //
20 | // identifers: x, y, foobar
21 | // operators: +, <<, %^&= (any sequence of symbols, excluding punctuation)
22 | // booleans: true, false
23 | // integers: 0, 324, 0x32FF
24 | // floats: 1.52, 1.2e+6
25 | // characters: 'a', 'z'
26 | // strings: "Hello World!\n"
27 | // punctuation: ( ) [ ] { } , ; : .
28 | //
29 | // Keywords overlap with identifiers and symbols, and must be registered.
30 | //
31 | //===----------------------------------------------------------------------===//
32 |
33 |
34 | #ifndef OHMU_DEFAULTLEXER_H
35 | #define OHMU_DEFAULTLEXER_H
36 |
37 | #include "base/MemRegion.h"
38 | #include "base/LLVMDependencies.h"
39 |
40 | #include "parser/Token.h"
41 | #include "parser/Lexer.h"
42 |
43 |
44 | namespace ohmu {
45 | namespace parsing {
46 |
47 |
48 | enum DefaultTokenIDs {
49 | TK_Identifier = TK_BasicTokenEnd,
50 | TK_Operator,
51 |
52 | TK_LitCharacter,
53 | TK_LitInteger,
54 | TK_LitFloat,
55 | TK_LitString,
56 |
57 | TK_LParen,
58 | TK_RParen,
59 | TK_LCurlyBrace,
60 | TK_RCurlyBrace,
61 | TK_LSquareBrace,
62 | TK_RSquareBrace,
63 | TK_Comma,
64 | TK_Semicolon,
65 | TK_Colon,
66 | TK_Period,
67 |
68 | TK_BeginKeywordIDs
69 | };
70 |
71 |
72 | class DefaultLexer : public Lexer {
73 | public:
74 | DefaultLexer() : interactive_(false) {
75 | setKeywordStartID(TK_BeginKeywordIDs);
76 | stringArena_.setRegion(&stringRegion_);
77 | }
78 | DefaultLexer(const DefaultLexer& l) = delete;
79 |
80 | void readNewline(char c);
81 |
82 | void readIdentifier(char startChar);
83 | void readInteger (char startChar);
84 | void readHexInteger();
85 | void readOperator (char startChar);
86 |
87 | void readLineComment();
88 | bool readEscapeCharacter(char c);
89 | bool readString();
90 | bool readCharacter();
91 | bool readFloatExp(char startChar);
92 |
93 | StringRef copyStr(StringRef s) {
94 | char* mem = static_cast(stringArena_.allocate(s.size()+1));
95 | return copyStringRef(mem, s);
96 | }
97 |
98 | virtual const char* getTokenIDString(unsigned tid);
99 | virtual unsigned registerKeyword(const std::string& s);
100 |
101 | virtual Token readToken();
102 |
103 | inline bool isInteractive() const { return interactive_; }
104 | inline void setInteractive(bool b) { interactive_ = b; }
105 |
106 | private:
107 | MemRegion stringRegion_; // Region to allocate all token strings
108 | MemRegionRef stringArena_;
109 |
110 | bool interactive_;
111 | };
112 |
113 | } // end namespace parsing
114 |
115 | } // end namespace ohmu
116 |
117 | #endif
118 |
--------------------------------------------------------------------------------
/src/parser/Lexer.cpp:
--------------------------------------------------------------------------------
1 | //===- Lexer.cpp -----------------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 |
18 | #include
19 | #include
20 |
21 | #ifndef _MSC_VER
22 | #include
23 | #include
24 | #endif
25 |
26 | #include "parser/Lexer.h"
27 |
28 | namespace ohmu {
29 |
30 | namespace parsing {
31 |
32 | unsigned FileStream::fillBuffer(char* buf, unsigned size) {
33 | size_t n = fread(buf, 1, size, file_);
34 | return static_cast(n);
35 | }
36 |
37 | unsigned StringStream::fillBuffer(char* buf, unsigned size) {
38 | if (str_[0] == 0)
39 | return 0;
40 | unsigned i = 0;
41 | while (i < size && str_[0] != 0) {
42 | buf[i] = str_[0];
43 | ++i;
44 | ++str_;
45 | }
46 | return i;
47 | }
48 |
49 |
50 | #ifndef _MSC_VER
51 | bool InteractiveStream::readlineLibraryInitialized_ = false;
52 |
53 | InteractiveStream::InteractiveStream(const char* p1, const char* p2)
54 | : prompt1_(p1), prompt2_(p2), firstLine_(true) {
55 | if (!readlineLibraryInitialized_) {
56 | // Do nothing for now...
57 | readlineLibraryInitialized_ = true;
58 | }
59 | }
60 |
61 |
62 | unsigned InteractiveStream::fillBuffer(char* buf, unsigned size) {
63 | const char* p = firstLine_ ? prompt1_ : prompt2_;
64 |
65 | char* line = readline(p);
66 | if (line == 0)
67 | return 0;
68 |
69 | unsigned i = 0;
70 | while (i < size && line[i] != 0) {
71 | buf[i] = line[i];
72 | ++i;
73 | }
74 | if (i+1 < size) {
75 | buf[i] = '\n'; // add on a newline.
76 | buf[i+1] = ' '; // add whitespace to satisfy lexer lookahead.
77 | i += 2;
78 | }
79 | free(line);
80 | firstLine_ = false;
81 | return i;
82 | }
83 | #endif
84 |
85 |
86 | // Look up the token id for the token named s.
87 | unsigned Lexer::lookupTokenID(const std::string& s) {
88 | // initialize token dictionary on first call
89 | if (tokenList_.size() == 0) {
90 | for (unsigned i=0,n=getKeywordStartID(); isecond;
100 | }
101 |
102 |
103 | unsigned Lexer::registerKeyword(const std::string& s) {
104 | KeywordDict::iterator it = keyDict_.find(s);
105 | if (it == keyDict_.end()) {
106 | unsigned sz = keyList_.size();
107 | keyList_.push_back(s); // map from unsigned to string
108 | keyDict_[s] = sz; // map from string to unsigned
109 | return sz + startKeywordTokenID_;
110 | }
111 | return it->second + startKeywordTokenID_;
112 | }
113 |
114 |
115 | void Lexer::signalLexicalError() {
116 | char c = lookChar();
117 | std::cerr << "Lexical error: unknown character ";
118 | if (c) std::cerr << "'" << c << "'";
119 | else std::cerr << 0;
120 | lexical_error = true;
121 | }
122 |
123 |
124 | // Tell the lexer that a close brace has been seen. The id should
125 | // be that of the corresponding open brace.
126 | bool Lexer::signalCloseBrace(unsigned short tokid) {
127 | if (braces_.size() > 0 && braces_.back() == tokid) {
128 | braces_.pop_back();
129 | return true;
130 | }
131 | // attempt to recover by popping extra braces off the stack
132 | while (braces_.size() > 0 && braces_.back() != tokid)
133 | braces_.pop_back();
134 | if (braces_.size() > 0)
135 | braces_.pop_back(); // pop off the given brace
136 | return false;
137 | }
138 |
139 |
140 | void Lexer::readTokens(unsigned numTokens) {
141 | unsigned i = 0;
142 | for (; i < numTokens; ++i) {
143 | if (stream_eof_ || lexical_error)
144 | break;
145 | lookAhead_.push_back(readToken());
146 | }
147 |
148 | // push extra EOF tokens onto the end if necessary to enable
149 | // unlimited lookahead.
150 | for (; i < numTokens; ++i) {
151 | lookAhead_.push_back(eofToken_);
152 | }
153 | }
154 |
155 |
156 | void Lexer::fillBuffer(unsigned numChars) {
157 | unsigned bsize = bufferSize();
158 |
159 | if (bufferPos_ > 0) {
160 | // Move unread characters to begining of buffer.
161 | // There should only be a few.
162 | if (bufferPos_ > bsize) {
163 | memcpy(buffer_, buffer_ + bufferPos_, bsize);
164 | }
165 | else {
166 | // regions overlap -- move the data byte by byte.
167 | char* p = buffer_ + bufferPos_;
168 | for (unsigned i = 0; i < bsize; ++i, ++p)
169 | buffer_[i] = *p;
170 | }
171 |
172 | bufferPos_ = 0;
173 | bufferLen_ = bsize;
174 | }
175 |
176 | // Sanity check.
177 | if (numChars + bufferLen_ > bufferCapacity_-1)
178 | numChars = bufferCapacity_ - bufferLen_ - 1;
179 |
180 | unsigned read = 0;
181 | while (read < numChars && !stream_eof_) {
182 | unsigned nread =
183 | charStream_->fillBuffer(buffer_ + bufferLen_,
184 | bufferCapacity_ - bufferLen_);
185 | if (nread == 0) {
186 | stream_eof_ = true;
187 | break;
188 | }
189 |
190 | read += nread;
191 | bufferLen_ += nread;
192 | }
193 |
194 | // 0-pad any requested lookahead past end of file
195 | while (read < numChars) {
196 | buffer_[bufferLen_] = 0;
197 | ++bufferLen_;
198 | ++read;
199 | }
200 | }
201 |
202 | } // end namespace parsing
203 |
204 | } // end namespace ohmu
205 |
--------------------------------------------------------------------------------
/src/parser/TILParser.h:
--------------------------------------------------------------------------------
1 | //===- TILParser.h ---------------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 | //
18 | // TILParser is a concrete parser, which constructs TIL expressions.
19 | // The TIL grammar is read from an external grammar file.
20 | //
21 | //===----------------------------------------------------------------------===//
22 |
23 | #ifndef OHMU_TIL_PARSER_H
24 | #define OHMU_TIL_PARSER_H
25 |
26 | #include "parser/Parser.h"
27 | #include "parser/BNFParser.h"
28 | #include "til/TIL.h"
29 |
30 |
31 | namespace ohmu {
32 | namespace parsing {
33 |
34 | using namespace ohmu::til;
35 |
36 |
37 | class TILParser : public Parser {
38 | public:
39 |
40 | // The set of opcodes that are allowed to appear in astNode constructors.
41 | // This mostly mirrors TIL_Opcode, but there are some differences, e
42 | // especially with regard to literals and variables.
43 | enum TIL_ConstructOp {
44 | TCOP_LitNull,
45 | TCOP_LitBool,
46 | TCOP_LitChar,
47 | TCOP_LitInteger,
48 | TCOP_LitFloat,
49 | TCOP_LitString,
50 |
51 | TCOP_Identifier,
52 | TCOP_Function,
53 | TCOP_SFunction,
54 | TCOP_Code,
55 | TCOP_Field,
56 | TCOP_Record,
57 | TCOP_Slot,
58 | TCOP_Array,
59 |
60 | TCOP_Apply,
61 | TCOP_SApply,
62 | TCOP_Project,
63 | TCOP_Call,
64 |
65 | TCOP_Alloc,
66 | TCOP_Load,
67 | TCOP_Store,
68 | TCOP_ArrayIndex,
69 | TCOP_ArrayAdd,
70 |
71 | TCOP_UnaryOp,
72 | TCOP_BinaryOp,
73 | TCOP_Cast,
74 |
75 | TCOP_Let,
76 | TCOP_If
77 | };
78 |
79 | static const unsigned short TCOP_MAX = TCOP_If;
80 |
81 | // All parse rules return SExprs.
82 | static const unsigned short TILP_SExpr = ParseResult::PRS_UserDefined;
83 |
84 |
85 | TILParser(Lexer *lexer) : Parser(lexer) {
86 | initMap();
87 | }
88 | ~TILParser() { }
89 |
90 | MemRegionRef arena() { return arena_; }
91 |
92 | void setArenas(MemRegionRef strArena, MemRegionRef parseArena) {
93 | arena_ = parseArena;
94 | stringArena_ = strArena;
95 | }
96 |
97 | const char* getOpcodeName(TIL_ConstructOp op);
98 |
99 | void initMap();
100 |
101 | StringRef copyStr (StringRef s);
102 | bool toBool (StringRef s);
103 | char toChar (StringRef s);
104 | int toInteger(StringRef s);
105 | double toDouble (StringRef s);
106 | StringRef toString (StringRef s);
107 |
108 | unsigned lookupOpcode(const std::string &s) override;
109 |
110 | TIL_UnaryOpcode lookupUnaryOpcode(StringRef s);
111 | TIL_BinaryOpcode lookupBinaryOpcode(StringRef s);
112 | TIL_CastOpcode lookupCastOpcode(StringRef s);
113 |
114 | ParseResult makeExpr(unsigned op, unsigned arity, ParseResult *prs) override;
115 |
116 | private:
117 | MemRegionRef arena_;
118 | MemRegionRef stringArena_;
119 |
120 | std::unordered_map opcodeMap_;
121 | std::unordered_map unaryOpcodeMap_;
122 | std::unordered_map binaryOpcodeMap_;
123 | std::unordered_map castOpcodeMap_;
124 | };
125 |
126 |
127 | } // end namespace parsing
128 | } // end namespace ohmu
129 |
130 | #endif // OHMU_TIL_PARSER_H
131 |
--------------------------------------------------------------------------------
/src/parser/Token.h:
--------------------------------------------------------------------------------
1 | //===- Token.h -------------------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 | //
18 | // Defines classes for dealing with source files and tokens.
19 | //
20 | // class SourceLocation: a location within a source file.
21 | // class Token: consists of a token id, the parsed string, and a SourceLocation.
22 | // class TokenSet: a set of token ids. Used in parsing.
23 | //
24 | //===----------------------------------------------------------------------===//
25 |
26 |
27 | #ifndef OHMU_TOKEN_H
28 | #define OHMU_TOKEN_H
29 |
30 | #include "base/LLVMDependencies.h"
31 |
32 | namespace ohmu {
33 |
34 | namespace parsing {
35 |
36 | enum BasicTokenID {
37 | TK_None = 0,
38 | TK_EOF,
39 | TK_Error,
40 | TK_Newline,
41 | TK_Whitespace,
42 | TK_Comment,
43 | TK_BasicTokenEnd
44 | };
45 |
46 |
47 | struct SourceLocation {
48 | unsigned lineNum;
49 | unsigned short linePos;
50 | unsigned short fileIndex;
51 |
52 | SourceLocation()
53 | : lineNum(0), linePos(0), fileIndex(0)
54 | { }
55 | SourceLocation(unsigned ln, unsigned short lp, unsigned short fi=0)
56 | : lineNum(ln), linePos(lp), fileIndex(fi)
57 | { }
58 | };
59 |
60 |
61 | class Token {
62 | public:
63 | Token()
64 | : tokenID_(TK_EOF), tokenStr_("")
65 | { }
66 | Token(const Token& tok)
67 | : tokenID_(tok.tokenID_), tokenStr_(tok.tokenStr_),
68 | sourceLoc_(tok.sourceLoc_)
69 | { }
70 | Token(unsigned short tid)
71 | : tokenID_(tid), tokenStr_(""), sourceLoc_(SourceLocation())
72 | { }
73 | Token(unsigned short tid, const char* s, const SourceLocation& loc)
74 | : tokenID_(tid), tokenStr_(StringRef(s)), sourceLoc_(SourceLocation())
75 | { }
76 | Token(unsigned short tid, StringRef s, const SourceLocation& loc)
77 | : tokenID_(tid), tokenStr_(s), sourceLoc_(loc)
78 | { }
79 |
80 | unsigned id() const { return tokenID_; }
81 | unsigned length() const { return tokenStr_.size(); }
82 | StringRef string() const { return tokenStr_; }
83 | SourceLocation location() const { return sourceLoc_; }
84 |
85 | std::string cppString() const {
86 | return std::string(tokenStr_.c_str(), tokenStr_.size());
87 | }
88 |
89 | const char* c_str() const { return tokenStr_.c_str(); }
90 |
91 | private:
92 | unsigned short tokenID_;
93 | StringRef tokenStr_;
94 | SourceLocation sourceLoc_;
95 | };
96 |
97 |
98 | class TokenSet {
99 | public:
100 | bool get(int i) const {
101 | unsigned idx = i/sizeof(unsigned);
102 | unsigned rem = i - idx*sizeof(unsigned);
103 | return (bits_[idx] >> rem) & 0x01;
104 | }
105 |
106 | void set(int i) {
107 | unsigned idx = i/sizeof(unsigned);
108 | unsigned rem = i - idx*sizeof(unsigned);
109 | bits_[idx] |= 0x01 << rem;
110 | }
111 |
112 | static void makeZero(TokenSet& tset) {
113 | for (unsigned i = 0; i < maxSize; ++i) tset.bits_[i] = 0;
114 | }
115 |
116 | static void makeUnion(TokenSet& set1, TokenSet& set2,
117 | TokenSet& result)
118 | {
119 | for (unsigned i = 0; i < maxSize; ++i)
120 | result.bits_[i] = set1.bits_[i] | set2.bits_[i];
121 | }
122 |
123 | private:
124 | static const unsigned maxSize = 16;
125 |
126 | unsigned bits_[maxSize]; // 16*32 token types should be enough...
127 | };
128 |
129 |
130 | } // end namespace lexing
131 | } // end namespace ohmu
132 |
133 | #endif
134 |
135 |
--------------------------------------------------------------------------------
/src/test/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8)
2 |
3 | add_subdirectory(backend)
4 | add_subdirectory(base)
5 | add_subdirectory(lsa)
6 | add_subdirectory(parser)
7 | add_subdirectory(til)
8 |
--------------------------------------------------------------------------------
/src/test/Driver.h:
--------------------------------------------------------------------------------
1 | //===- Driver.h ------------------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 | //
18 | // Driver provides a simple harness for parsing and compiling an ohmu program
19 | // which is shared between test cases.
20 | //
21 | //===----------------------------------------------------------------------===//
22 |
23 |
24 | #ifndef OHMU_TEST_DRIVER_H
25 | #define OHMU_TEST_DRIVER_H
26 |
27 |
28 | #include "parser/DefaultLexer.h"
29 | #include "parser/BNFParser.h"
30 | #include "parser/TILParser.h"
31 | #include "til/Global.h"
32 | #include "til/TIL.h"
33 | #include "til/TILCompare.h"
34 | #include "til/TILPrettyPrint.h"
35 | #include "til/TILTraverse.h"
36 |
37 |
38 | #include
39 |
40 | namespace ohmu {
41 |
42 | using namespace ohmu::parsing;
43 | using namespace ohmu::til;
44 |
45 |
46 | class Driver {
47 | public:
48 | bool initParser(FILE* grammarFile);
49 | bool initParser(const char* grammarFileName);
50 |
51 | bool parseDefinitions(Global *global, CharStream &stream);
52 | bool parseDefinitions(Global *global, FILE *file);
53 | bool parseDefinitions(Global *global, const char* fname);
54 |
55 | Driver() : tilParser(&lexer), startRule(nullptr) { }
56 |
57 | private:
58 | DefaultLexer lexer;
59 | TILParser tilParser;
60 | ParseNamedDefinition* startRule;
61 | };
62 |
63 |
64 | bool Driver::initParser(FILE* grammarFile) {
65 | // Build the ohmu parser from the grammar file.
66 | bool success = BNFParser::initParserFromFile(tilParser, grammarFile, false);
67 | if (!success)
68 | return false;
69 |
70 | // Find the starting point.
71 | startRule = tilParser.findDefinition("definitions");
72 | if (!startRule) {
73 | std::cout << "Grammar does not contain rule named 'definitions'.\n";
74 | return false;
75 | }
76 | return true;
77 | }
78 |
79 |
80 | bool Driver::initParser(const char* grammarFileName) {
81 | // Open the grammar file.
82 | FILE* grammarFile = fopen(grammarFileName, "r");
83 | if (!grammarFile) {
84 | std::cout << "File " << grammarFileName << " not found.\n";
85 | return false;
86 | }
87 | bool success = initParser(grammarFile);
88 | fclose(grammarFile);
89 | return success;
90 | }
91 |
92 |
93 |
94 |
95 | bool Driver::parseDefinitions(Global *global, CharStream &stream) {
96 | tilParser.setArenas(global->StringArena, global->ParseArena);
97 | lexer.setStream(&stream);
98 | // tilParser.setTrace(true);
99 | ParseResult result = tilParser.parse(startRule);
100 | if (tilParser.parseError())
101 | return false;
102 |
103 | // Add parsed definitions to global namespace.
104 | auto* v = result.getList(TILParser::TILP_SExpr);
105 | if (!v) {
106 | std::cout << "No definitions found.\n";
107 | return false;
108 | }
109 | global->addDefinitions(*v);
110 | delete v;
111 | return true;
112 | }
113 |
114 | bool Driver::parseDefinitions(Global *global, FILE *file) {
115 | // Parse file.
116 | FileStream fs(file);
117 | return parseDefinitions(global, fs);
118 | }
119 |
120 |
121 | bool Driver::parseDefinitions(Global *global, const char* fname) {
122 | FILE* file = fopen(fname, "r");
123 | if (!file) {
124 | std::cout << "File " << fname << " not found.\n";
125 | return false;
126 | }
127 | bool success = parseDefinitions(global, file);
128 | fclose(file);
129 | return success;
130 | }
131 |
132 | } // end namespace ohmu
133 |
134 |
135 | #endif // OHMU_TEST_DRIVER_H
136 |
--------------------------------------------------------------------------------
/src/test/backend/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | #add_executable(test_llvm test_llvm.cpp)
2 | #target_link_libraries(test_llvm base parser til backend_llvm ${llvm_libs})
3 | #add_dependencies(test_llvm ohmu_grammar)
--------------------------------------------------------------------------------
/src/test/backend/test_llvm.cpp:
--------------------------------------------------------------------------------
1 | //===- test_TILParser.cpp --------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 |
18 | #include "backend/llvm/IRGen.h"
19 | #include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
20 | #include "clang/Analysis/Analyses/ThreadSafetyTraverse.h"
21 | #include "parser/DefaultLexer.h"
22 | #include "parser/BNFParser.h"
23 | #include "parser/TILParser.h"
24 | #include "til/CFGReducer.h"
25 |
26 | #include
27 |
28 | using namespace ohmu;
29 | using namespace ohmu::parsing;
30 | using namespace clang::threadSafety;
31 |
32 | class TILPrinter : public til::PrettyPrinter {
33 | public:
34 | TILPrinter() : PrettyPrinter(false, false) { }
35 | };
36 |
37 | void printSExpr(til::SExpr* e) {
38 | TILPrinter::print(e, std::cout);
39 | }
40 |
41 |
42 | int main(int argc, const char** argv) {
43 | DefaultLexer lexer;
44 | TILParser tilParser(&lexer);
45 |
46 |
47 | const char* grammarFileName = "src/grammar/ohmu.grammar";
48 | FILE* file = fopen(grammarFileName, "r");
49 | if (!file) {
50 | std::cout << "File " << grammarFileName << " not found.\n";
51 | return -1;
52 | }
53 |
54 | bool success = BNFParser::initParserFromFile(tilParser, file, false);
55 | std::cout << "\n";
56 | // if (success)
57 | // tilParser.printSyntax(std::cout);
58 |
59 | fclose(file);
60 |
61 | if (argc == 0)
62 | return 0;
63 |
64 | // Read the ohmu file.
65 | auto *startRule = tilParser.findDefinition("definitions");
66 | if (!startRule) {
67 | std::cout << "Grammar does not contain rule named 'definitions'.\n";
68 | return -1;
69 | }
70 |
71 | file = fopen(argv[1], "r");
72 | if (!file) {
73 | std::cout << "File " << argv[1] << " not found.\n";
74 | return -1;
75 | }
76 |
77 | std::cout << "\nParsing " << argv[1] << "...\n";
78 | FileStream fs(file);
79 | lexer.setStream(&fs);
80 | // tilParser.setTrace(true);
81 | ParseResult result = tilParser.parse(startRule);
82 | if (tilParser.parseError())
83 | return -1;
84 |
85 | // Pretty print the parsed ohmu code.
86 | auto* v = result.getList(TILParser::TILP_SExpr);
87 | if (!v) {
88 | std::cout << "No definitions found.\n";
89 | return 0;
90 | }
91 |
92 | for (SExpr* e : *v) {
93 | std::cout << "\nDefinition:\n";
94 | printSExpr(e);
95 | std::cout << "\nCFG:\n";
96 | SExpr* e2 = CFGReducer::lower(e, tilParser.arena());
97 | printSExpr(e2);
98 |
99 | //backend_llvm::generate_LLVM_IR(cfg);
100 | }
101 |
102 | delete v;
103 |
104 | std::cout << "\n";
105 | return 0;
106 | }
107 |
108 |
--------------------------------------------------------------------------------
/src/test/base/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_executable(test_base test_base.cpp)
2 | target_link_libraries(test_base base)
--------------------------------------------------------------------------------
/src/test/base/test_base.cpp:
--------------------------------------------------------------------------------
1 | //===- test_base.cpp -------------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 | //
18 | // Test code for classes in base.
19 | //
20 | //===----------------------------------------------------------------------===//
21 |
22 | #include "base/LLVMDependencies.h"
23 | #include "base/MemRegion.h"
24 | #include "base/ArrayTree.h"
25 |
26 | #include
27 |
28 | using namespace ohmu;
29 |
30 |
31 | void error(const char* msg) {
32 | std::cerr << msg;
33 | assert(false && "Test failed.");
34 | }
35 |
36 |
37 | class UnMoveableItem {
38 | public:
39 | UnMoveableItem() : uniqueHandle(0) { }
40 | UnMoveableItem(unsigned h) : uniqueHandle(h) { }
41 | ~UnMoveableItem() { uniqueHandle = 0; }
42 |
43 | unsigned getHandle() { return uniqueHandle; }
44 |
45 | private:
46 | UnMoveableItem(const UnMoveableItem& i) = delete;
47 | UnMoveableItem(UnMoveableItem&& i) = delete;
48 |
49 | void operator=(const UnMoveableItem& i) = delete;
50 | void operator=(UnMoveableItem&& i) = delete;
51 |
52 | private:
53 | unsigned uniqueHandle;
54 | };
55 |
56 |
57 | void testTreeArray() {
58 | MemRegion region;
59 | MemRegionRef arena(®ion);
60 | ArrayTree atree;
61 | std::vector items;
62 |
63 | unsigned i = 0;
64 | unsigned n = 1024;
65 |
66 | for (i = 0; i < n; ++i) {
67 | atree.emplace_back(arena, i);
68 | items.push_back(&atree.back());
69 | }
70 |
71 | for (i = 0; i < n; ++i) {
72 | // std::cerr << i << ",";
73 | if (atree[i].getHandle() != i)
74 | error("Error: ArrayTree construction failed.\n");
75 | }
76 |
77 | i = 0;
78 | for (auto& H : atree) {
79 | // std::cerr << i << ",";
80 | if (H.getHandle() != i)
81 | error("Error: ArrayTree iterator failed.\n");
82 | ++i;
83 | }
84 | if (i != n)
85 | error("Error: ArrayTree iteration failed.\n");
86 |
87 | i = n;
88 | for (auto & H : atree.reverse()) {
89 | if (H.getHandle() != i-1)
90 | error("Error: ArrayTree reverse iterator failed.\n");
91 | --i;
92 | }
93 | if (i != 0)
94 | error("Error: ArrayTree reverse iteration failed.\n");
95 |
96 | unsigned n2 = n + 2713;
97 | atree.resize(arena, n2, 42);
98 | for (i = n; i < n2; ++i) {
99 | if (atree[i].getHandle() != 42)
100 | error("Error: ArrayTree construction failed.\n");
101 | }
102 |
103 | unsigned n3 = n*4;
104 | atree.resize(arena, n3, 43);
105 | for (i = n2; i < n3; ++i) {
106 | if (atree[i].getHandle() != 43)
107 | error("Error: ArrayTree construction failed.\n");
108 | }
109 |
110 | atree.clear();
111 | for (auto *H : items) {
112 | if (H->getHandle() != 0)
113 | error("Error: ArrayTree clear failed.\n");
114 | }
115 | }
116 |
117 |
118 |
119 | int main(int argc, char** argv) {
120 | testTreeArray();
121 | return 0;
122 | }
123 |
124 |
--------------------------------------------------------------------------------
/src/test/lsa/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | ## Call graph generation
2 |
3 | add_executable(generate_callgraph
4 | generate_callgraph.cpp
5 | test_input_callgraph.cpp
6 | )
7 | target_link_libraries(generate_callgraph
8 | lsa
9 | )
10 |
11 | ## Analyses
12 |
13 | add_executable(scc_analysis
14 | scc_analysis.cpp
15 | test_input_scc.cpp
16 | )
17 | target_link_libraries(scc_analysis
18 | lsa_example_scc
19 | )
20 |
21 | add_executable(globals_analysis
22 | globals_analysis.cpp
23 | test_input_global_vars.cpp
24 | )
25 | target_link_libraries(globals_analysis
26 | ohmuTil LLVMOption
27 | )
28 |
29 | add_executable(escape_analysis
30 | escape_analysis.cpp
31 | test_input_escape.cpp
32 | )
33 | target_link_libraries(escape_analysis
34 | lsa_example_escape
35 | )
36 |
37 |
38 | ## Helper command
39 |
40 | add_custom_target(run_test_lsa)
41 | add_custom_command(
42 | TARGET run_test_lsa
43 | DEPENDS run_test_lsa.sh
44 | COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/run_test_lsa.sh ${CMAKE_CURRENT_BINARY_DIR}/run_test_lsa.sh)
45 |
--------------------------------------------------------------------------------
/src/test/lsa/escape_analysis.cpp:
--------------------------------------------------------------------------------
1 | //===- escape_analysis.cpp -------------------------------------*- C++ --*-===//
2 | //
3 | //===----------------------------------------------------------------------===//
4 |
5 | #include "lsa/examples/EscapeAnalysis.h"
6 | #include "lsa/StandaloneRunner.h"
7 |
8 | int main(int argc, const char *argv[]) {
9 |
10 | ohmu::lsa::StandaloneRunner Runner(argc, argv);
11 |
12 | Runner.readCallGraph();
13 | Runner.runComputation();
14 | Runner.printComputationResult(true);
15 |
16 | return 0;
17 | }
18 |
--------------------------------------------------------------------------------
/src/test/lsa/generate_callgraph.cpp:
--------------------------------------------------------------------------------
1 | //===- generate_callgraph.cpp ----------------------------------*- C++ --*-===//
2 | // Simple program that generates and prints the call graph and OhmuIR of a
3 | // single translation unit.
4 | //===----------------------------------------------------------------------===//
5 |
6 | #include
7 |
8 | #include "clang/Tooling/CommonOptionsParser.h"
9 | #include "clang/Tooling/Tooling.h"
10 | #include "llvm/Support/CommandLine.h"
11 | #include "lsa/BuildCallGraph.h"
12 | #include "lsa/GraphSerializer.h"
13 |
14 | static llvm::cl::opt
15 | OutputFile("o", llvm::cl::desc("Specify output file"),
16 | llvm::cl::value_desc("file"), llvm::cl::Optional);
17 |
18 | int main(int argc, const char *argv[]) {
19 |
20 | clang::tooling::CommonOptionsParser OptParser(argc, argv,
21 | llvm::cl::GeneralCategory);
22 | ohmu::lsa::DefaultCallGraphBuilder CallGraphBuilder;
23 | clang::ast_matchers::MatchFinder Finder;
24 | ohmu::lsa::CallGraphBuilderTool BuilderTool;
25 | BuilderTool.RegisterMatchers(CallGraphBuilder, &Finder);
26 |
27 | clang::tooling::ClangTool Tool(OptParser.getCompilations(),
28 | OptParser.getSourcePathList());
29 |
30 | int Res = Tool.run(clang::tooling::newFrontendActionFactory(&Finder).get());
31 | if (Res != 0)
32 | return Res;
33 |
34 | if (OutputFile.getNumOccurrences() > 0) {
35 | ohmu::lsa::GraphSerializer::write(OutputFile.getValue(), &CallGraphBuilder);
36 | } else {
37 | CallGraphBuilder.Print(std::cout);
38 | }
39 |
40 | return 0;
41 | }
42 |
--------------------------------------------------------------------------------
/src/test/lsa/globals_analysis.cpp:
--------------------------------------------------------------------------------
1 | //===- test_lsa_global_vars.cpp --------------------------------*- C++ --*-===//
2 | // Runs the LSA call graph generation on a clang compiled file and computes
3 | // which functions modify global variables.
4 | //===----------------------------------------------------------------------===//
5 |
6 | #include "lsa/examples/ExampleOhmuComputation.h"
7 | #include "lsa/StandaloneRunner.h"
8 |
9 | int main(int argc, const char *argv[]) {
10 |
11 | ohmu::lsa::StandaloneRunner Runner(argc, argv);
12 |
13 | Runner.readCallGraph();
14 | Runner.runComputation();
15 | Runner.printComputationResult();
16 |
17 | return 0;
18 | }
19 |
--------------------------------------------------------------------------------
/src/test/lsa/run_test_lsa.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Assisting script to call a clang-tool binary with the right arguments to the
4 | # Clang include headers. Requires that the environment variable LLVM_BUILD is
5 | # set to the LLVM build directory that includes Clang.
6 | #
7 | # Call this script as:
8 | # ./run_test_lsa.sh
9 | #
10 | BPATH=${LLVM_BUILD:?"Specify the absolute path to the LLVM build directory as the environment variable LLVM_BUILD."}
11 | VERSION=`ls $BPATH/lib/clang | sort -n | tail -1`
12 | COMMAND=$1
13 | shift 1
14 | "$COMMAND" \
15 | -extra-arg=-I \
16 | -extra-arg=$BPATH/lib/clang/$VERSION/include \
17 | $@
18 |
19 |
--------------------------------------------------------------------------------
/src/test/lsa/scc_analysis.cpp:
--------------------------------------------------------------------------------
1 | //===- test_lsa_scc.cpp ----------------------------------------*- C++ --*-===//
2 | // Runs the LSA call graph generation on a clang compiled file. To call this
3 | // binary, use run_test_lsa.sh which sets the right include path for clang
4 | // libraries. The clang tool requires the json compilation database to be
5 | // present in the directory of the specified source file or a parent directory
6 | // of the source file. Alternatively, you can specify the path to the folder
7 | // containing the database with -p (eg: "-p=.").
8 | //
9 | // To create the database, specify "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON" when
10 | // running CMake, or "-t compdb" when running ninja.
11 | //
12 | // In addition, since clang requires some substitute includes for common system
13 | // headers, use the exported shell script for a more convenient call:
14 | // $ export LLVM_BUILD=/path/to/llvm/with/clang/build/
15 | // $ ./src/test/run_test_lsa.sh -p=.
16 | //===----------------------------------------------------------------------===//
17 |
18 | #include "lsa/examples/SCCComputation.h"
19 | #include "lsa/StandaloneRunner.h"
20 |
21 | int main(int argc, const char *argv[]) {
22 |
23 | ohmu::lsa::StandaloneRunner Runner(argc, argv);
24 |
25 | Runner.readCallGraph();
26 | Runner.runComputation();
27 | Runner.printComputationResult();
28 |
29 | return 0;
30 | }
31 |
--------------------------------------------------------------------------------
/src/test/lsa/test_input_callgraph.cpp:
--------------------------------------------------------------------------------
1 | /// basics
2 |
3 | void globalFunction() { }
4 |
5 | void globalFunctionWithArg(int i) { }
6 |
7 | void callingGlobalFunction() {
8 | globalFunction();
9 | }
10 |
11 | void callingGlobalFunctionWithArg() {
12 | globalFunctionWithArg(3);
13 | }
14 |
15 | void multipleCalls() {
16 | globalFunction();
17 | globalFunction();
18 | globalFunctionWithArg(15);
19 | globalFunctionWithArg(100);
20 | }
21 |
22 | /// basics classes
23 | class B {
24 | public:
25 | void memberFunctionWithOneArg(int x) { }
26 | };
27 |
28 | void callingMemberFunctionWithOneArg() {
29 | B b;
30 | b.memberFunctionWithOneArg(15);
31 | }
32 |
33 | class A {
34 | public:
35 | void bar() { globalFunction(); }
36 | };
37 |
38 | void callingViaPointer(A* a) {
39 | a->bar();
40 | }
41 |
42 | /// templated functions
43 |
44 | template
45 | void templatedFunction(T t) {
46 | globalFunction();
47 | }
48 |
49 | void callingTemplatedFunction() {
50 | templatedFunction(false);
51 | templatedFunction(3);
52 | }
53 |
54 | template
55 | void templatedFunctionCalling(T t) {
56 | t.memberFunctionWithOneArg(13);
57 | }
58 |
59 | void callingTemplatedFunctionCalling() {
60 | B b;
61 | templatedFunctionCalling(b);
62 | }
63 |
64 | /// Specializations
65 | template
66 | void specializeMe(T t) {
67 | globalFunction();
68 | }
69 |
70 | template <>
71 | void specializeMe(int x) {
72 | globalFunctionWithArg(x);
73 | }
74 |
75 | void callSpecialInt() {
76 | specializeMe(13);
77 | }
78 |
79 |
80 | /// templated classes
81 |
82 | template
83 | class TemplatedClass {
84 | public:
85 | T* getResultT() { globalFunction(); return 0; }
86 | };
87 |
88 | void callingTemplatedClass() {
89 | TemplatedClass Tbool;
90 | Tbool.getResultT();
91 | TemplatedClass Tint;
92 | Tint.getResultT();
93 | }
94 |
95 | template
96 | class CRTP {
97 | public:
98 | Self *self() { return static_cast(this); }
99 |
100 | void CRTPFunction() {
101 | Self* s = self();
102 | s->semiVirtualFunction();
103 | }
104 | };
105 |
106 | class InstanceCRTP : public CRTP {
107 | public:
108 | void semiVirtualFunction() {
109 | globalFunction();
110 | }
111 | };
112 |
113 | void callingInstanceCRTP(InstanceCRTP C) {
114 | C.CRTPFunction();
115 | }
116 |
117 | class C {
118 | public:
119 | void end() {
120 | globalFunction();
121 | }
122 | ~C() {
123 | end();
124 | }
125 | };
126 |
127 | void constructDestruct() {
128 | C c;
129 | }
130 |
131 | template
132 | class X {
133 | public:
134 | void x();
135 | private:
136 | int * _m;
137 | };
138 |
139 | template
140 | void X<_T>::x() {
141 | delete this->_m;
142 | }
143 |
144 | /// overwriting virtual
145 |
146 | /// dynamic dispatch on arguments
147 |
148 | /// different return types?
149 |
150 |
--------------------------------------------------------------------------------
/src/test/lsa/test_input_escape.cpp:
--------------------------------------------------------------------------------
1 | int *Global;
2 | int GlobalCopy;
3 |
4 | void EscapeBoth(int *inp1, int *inp2) {
5 | Global = inp1 + 1 -1;
6 | int *tmp = inp2;
7 | Global = tmp;
8 | }
9 |
10 | void EscapeFirstOnly(int *fst, int *snd) {
11 | EscapeBoth(fst, fst);
12 | }
13 |
14 | void EscapeSecondOnly(int *fst, int *snd) {
15 | EscapeFirstOnly(snd, fst);
16 | }
17 |
18 | class EscapeSelf {
19 | private:
20 | EscapeSelf *Leak;
21 | public:
22 | void escape() {
23 | Leak = this;
24 | }
25 | void callEscape() {
26 | escape();
27 | }
28 | };
29 |
30 |
31 | void SimpleNoEscapePointer(int *i) { }
32 | void SimpleNoEscapeReference(int &i) { }
33 | void SimpleNoEscapeCopy(int i) { Global = &i; }
34 |
35 | void SimpleEscapePointer(int *i) { Global = i; }
36 | void SimpleEscapeReference(int &i) { Global = &i; }
37 |
38 | void NoEscapeDereference(int *p) {
39 | GlobalCopy = *p;
40 | }
41 |
42 | void EscapeReferenceDereference(int *p) {
43 | Global = &(*p);
44 | }
45 |
46 | void bar(int a) { }
47 |
48 | int* foo(int *a, int *b) {
49 | int c = *a + *b;
50 | bar(*a + *b);
51 | bar(c); // getting rid of compile warning
52 | return a;
53 | }
54 |
55 | int* phiTestBothReturn(int *a, int *b, bool c) {
56 | if (c) {
57 | return a;
58 | } else {
59 | return b;
60 | }
61 | }
62 |
63 | void phiTestBothBranch(int *a, int *b, bool c) {
64 | int *x;
65 | if (c) {
66 | x = a;
67 | } else {
68 | x = b;
69 | }
70 | Global = x;
71 | }
72 |
73 | int* phiTestSingleReturn(int *a, int *b, bool c) {
74 | if (c) {
75 | return b;
76 | } else {
77 | return b;
78 | }
79 | }
80 |
81 | void phiTestSingleBranch(int *a, int *b, bool c) {
82 | int *x;
83 | if (c) {
84 | x = a;
85 | } else {
86 | x = a;
87 | }
88 | Global = x;
89 | }
90 |
91 | // Code below would serve testing with lifetime of objects.
92 |
93 | /*
94 | class Collection {
95 | public:
96 | int TotalAge;
97 | };
98 |
99 | class User {
100 | private:
101 | int Age;
102 | char *Name;
103 | Collection *Copy;
104 |
105 | public:
106 | void AddAge(Collection *C) {
107 | C->TotalAge += Age;
108 | }
109 |
110 | void SaveCollectionPointer(Collection *C) {
111 | Copy = C;
112 | }
113 |
114 | void SaveCollectionReference(Collection &C) {
115 | Copy = &C;
116 | }
117 | };
118 |
119 | void NoEscapeLocalCollection(User* U) {
120 | Collection C;
121 | U->AddAge(&C);
122 | }
123 |
124 | void EscapeLocalCollectionReference(User* U) {
125 | Collection C;
126 | U->SaveCollectionReference(C);
127 | }
128 |
129 | void EscapeLocalCollectionPointer(User* U) {
130 | Collection C;
131 | U->SaveCollectionPointer(&C);
132 | }
133 |
134 | void NoEscapeLocalUserLocalCollection() {
135 | User U;
136 | Collection C;
137 | U.SaveCollectionPointer(&C);
138 | }
139 | */
140 |
--------------------------------------------------------------------------------
/src/test/lsa/test_input_global_vars.cpp:
--------------------------------------------------------------------------------
1 | //===- test_input_global_vars.cpp ------------------------------*- C++ --*-===//
2 | // A simple file for testing detecting changes to global variables.
3 | //===----------------------------------------------------------------------===//
4 |
5 | int globalVariable;
6 |
7 | void changeGlobalVariable() {
8 | globalVariable = 10;
9 | }
10 |
11 | void dontChangeAnything() {
12 |
13 | }
14 |
15 | void changeLocalVariable() {
16 | int localVariable;
17 | localVariable = 10;
18 | }
19 |
20 | int changeGlobalVariableMoreCode(bool b) {
21 | if (b) {
22 | return 11;
23 | } else {
24 | int x = 0;
25 | while (x < 21) {
26 | ++x;
27 | }
28 | globalVariable = 10;
29 | return globalVariable;
30 | }
31 | }
32 |
33 | int dontChangeGlobalVariableMoreCode(bool b) {
34 | if (b) {
35 | return 11;
36 | } else {
37 | int x = 0;
38 | while (x < 21) {
39 | ++x;
40 | }
41 | return globalVariable;
42 | }
43 | }
44 |
45 | class MyClass {
46 | public:
47 | int classVariable;
48 | void changeMemberVariable() {
49 | this->classVariable = 10;
50 | }
51 | };
52 |
53 | void changeMemberVariableOutside() {
54 | MyClass C;
55 | C.classVariable = 10;
56 | }
57 |
58 | void changeMemberVariableOutside(MyClass &C) {
59 | C.classVariable = 10;
60 | }
61 |
62 | void changeAPointer(int *p) {
63 | *p = 10;
64 | }
65 |
66 | void changeGlobalVariableViaPointerCall() {
67 | changeAPointer(&globalVariable);
68 | }
69 |
70 | void changeGlobalVariableViaPointer() {
71 | int *p = &globalVariable;
72 | *p = 10;
73 | }
74 |
75 | void changeLocalVariableViaPointer() {
76 | int localVariable = 3;
77 | int *p = &localVariable;
78 | *p = 10;
79 | }
80 |
81 | void changeGlobalVariableViaReference() {
82 | int &p = globalVariable;
83 | p = 10;
84 | }
85 |
86 | void changeLocalVariableViaReference() {
87 | int localVariable = 3;
88 | int &p = localVariable;
89 | p = 10;
90 | }
91 |
--------------------------------------------------------------------------------
/src/test/lsa/test_input_scc.cpp:
--------------------------------------------------------------------------------
1 | //===- test_input_scc.cpp --------------------------------------*- C++ --*-===//
2 | // A simple file for testing call graph generation and SCC computation.
3 | //
4 | // Generated graph:
5 | //
6 | // a ----> b ----> c ----> d ----> e
7 | // ^ ^ | ^ |
8 | // | | | | |
9 | // | | | v |
10 | // \------- f <------/ g <------/
11 | //
12 | // SCC #1: {a, b, c, f}
13 | // SCC #2: {d, e, g}
14 | //===----------------------------------------------------------------------===//
15 |
16 | void a();
17 | void b();
18 | void c();
19 | void d();
20 | void e();
21 | void f();
22 | void g();
23 |
24 | void a() { b(); }
25 | void b() { c(); }
26 | void c() { f(); d(); }
27 | void d() { e(); g(); }
28 | void e() { g(); }
29 | void f() { a(); b(); }
30 | void g() { d(); }
31 |
--------------------------------------------------------------------------------
/src/test/parser/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_executable(test_BNFParser test_BNFParser.cpp)
2 | target_link_libraries(test_BNFParser base parser til)
3 | add_dependencies(test_BNFParser parser_grammar)
4 |
5 | add_executable(test_parser test_parser.cpp)
6 | target_link_libraries(test_parser parser til)
7 | add_dependencies(test_parser ohmu_grammar)
--------------------------------------------------------------------------------
/src/test/parser/test_BNFParser.cpp:
--------------------------------------------------------------------------------
1 | //===- test_BNFParser.cpp --------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 |
18 | #include
19 | #include
20 |
21 | #include "parser/DefaultLexer.h"
22 | #include "parser/BNFParser.h"
23 | #include "parser/TILParser.h"
24 |
25 | using namespace ohmu::parsing;
26 |
27 | int bootstrapBNF() {
28 | const char* fname = "src/grammar/parser.grammar";
29 |
30 | ohmu::parsing::DefaultLexer lexer;
31 | ohmu::parsing::BNFParser bootstrapBNFParser(&lexer);
32 |
33 | FILE* file = fopen(fname, "r");
34 | if (!file) {
35 | std::cout << "File '" << fname << "' not found.\n";
36 | return -1;
37 | }
38 |
39 | BNFParser::initParserFromFile(bootstrapBNFParser, file, false);
40 | bootstrapBNFParser.printSyntax(std::cout);
41 |
42 | fclose(file);
43 | return 0;
44 | }
45 |
46 | int makeTILParser(const char* fname) {
47 | ohmu::parsing::DefaultLexer lexer;
48 | ohmu::parsing::TILParser myParser(&lexer);
49 |
50 | FILE* file = fopen(fname, "r");
51 | if (!file) {
52 | std::cout << "File '" << fname << "' not found.\n";
53 | return -1;
54 | }
55 |
56 | BNFParser::initParserFromFile(myParser, file, false);
57 | myParser.printSyntax(std::cout);
58 |
59 | fclose(file);
60 | return 0;
61 | }
62 |
63 |
64 | int main(int argc, const char** argv) {
65 | if (argc <= 1)
66 | return bootstrapBNF();
67 | else
68 | return makeTILParser(argv[1]);
69 | }
70 |
71 |
--------------------------------------------------------------------------------
/src/test/parser/test_parser.cpp:
--------------------------------------------------------------------------------
1 | //===- test_parser.cpp -----------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 |
18 | #include "test/Driver.h"
19 | #include "til/Bytecode.h"
20 | #include "til/VisitCFG.h"
21 |
22 |
23 | using namespace ohmu;
24 | using namespace ohmu::parsing;
25 | using namespace ohmu::til;
26 |
27 |
28 | void printSExpr(SExpr* e) {
29 | TILDebugPrinter::print(e, std::cout);
30 | }
31 |
32 |
33 | int main(int argc, const char** argv) {
34 | if (argc == 1) {
35 | std::cerr << "No file to parse.\n";
36 | return 0;
37 | }
38 |
39 | Global global;
40 | Driver driver;
41 |
42 | // Load up the ohmu grammar.
43 | bool success = driver.initParser("src/grammar/ohmu.grammar");
44 | if (!success)
45 | return -1;
46 |
47 | // Parse the ohmu source file.
48 | if (strcmp("--",argv[1]) == 0) {
49 | InteractiveStream IS("Ohmu > ", ".... > ");
50 | success = driver.parseDefinitions(&global, IS);
51 | }
52 | else {
53 | success = driver.parseDefinitions(&global, argv[1]);
54 | }
55 | if (!success)
56 | return -1;
57 |
58 | // Convert high-level AST to low-level IR.
59 | global.lower();
60 | std::cout << "\n------ Ohmu IR ------\n";
61 | global.print(std::cout);
62 |
63 | // Find all of the CFGs.
64 | VisitCFG visitCFG;
65 | visitCFG.traverseAll(global.global());
66 |
67 | std::cout << "\n\nNumber of CFGs: " << visitCFG.cfgs().size() << "\n\n";
68 | return 0;
69 | }
70 |
71 |
--------------------------------------------------------------------------------
/src/test/til/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_executable(test_serialization test_serialization.cpp)
2 | target_link_libraries(test_serialization til)
3 |
4 | add_executable(test_copier test_copier.cpp)
5 | target_link_libraries(test_copier til)
6 |
7 | add_executable(test_compare test_compare.cpp)
8 | target_link_libraries(test_compare parser til)
9 | add_dependencies(test_compare ohmu_grammar)
--------------------------------------------------------------------------------
/src/test/til/test_copier.cpp:
--------------------------------------------------------------------------------
1 | //===- test_copier.cpp -----------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 |
18 | #include "til/CFGBuilder.h"
19 | #include "til/CopyReducer.h"
20 | #include "til/TILPrettyPrint.h"
21 | #include "til/TypedEvaluator.h"
22 |
23 | #include
24 |
25 | using namespace ohmu;
26 | using namespace til;
27 |
28 | SExpr* makeSimple(CFGBuilder& bld) {
29 | auto* four = bld.newLiteralT(4);
30 | four->addAnnotation(bld.newAnnotationT(132));
31 |
32 | auto* vd = bld.newVarDecl(VarDecl::VK_Let, "four", four);
33 | vd->setVarIndex(1);
34 | auto* anncond = bld.newBinaryOp(BOP_Leq, bld.newLiteralT(5),
35 | bld.newLiteralT(3));
36 | anncond->addAnnotation(
37 | bld.newAnnotationT(bld.newLiteralT(true)));
38 | vd->addAnnotation(bld.newAnnotationT(anncond));
39 |
40 | auto* cond2 = bld.newLiteralT(13);
41 | auto* precond2 = bld.newAnnotationT(cond2);
42 | auto *cond = bld.newBinaryOp(BOP_Leq, bld.newLiteralT(6),
43 | bld.newLiteralT(7));
44 | cond->addAnnotation(precond2);
45 | cond->addAnnotation(bld.newAnnotationT("COMPARE"));
46 |
47 | auto* let = bld.newLet(vd, cond);
48 | let->addAnnotation(bld.newAnnotationT("LET"));
49 |
50 | auto* A = bld.newBinaryOp(BOP_Leq, bld.newLiteralT(200),
51 | bld.newLiteralT(201));
52 | auto* B = bld.newBinaryOp(BOP_Leq, bld.newLiteralT(300),
53 | bld.newLiteralT(301));
54 |
55 | auto* Acond = bld.newLiteralT(13);
56 | A->addAnnotation(bld.newAnnotationT(Acond));
57 | B->addAnnotation(bld.newAnnotationT("lequals"));
58 |
59 | auto* C = bld.newBinaryOp(BOP_Leq, bld.newLiteralT(400),
60 | bld.newLiteralT(401));
61 | auto* tri = bld.newAnnotationT(A, B, C);
62 | let->addAnnotation(tri);
63 |
64 | return let;
65 | }
66 |
67 | void testCopying(CFGBuilder& bld, SExpr *e) {
68 | std::cout << "Original:\n";
69 | TILDebugPrinter::print(e, std::cout);
70 | std::cout << "\n\n";
71 |
72 | std::cout << "Copy to same arena:\n";
73 | SExprCopier copier(bld.arena());
74 | SExpr* e1 = copier.copy(e, bld.arena());
75 | TILDebugPrinter::print(e1, std::cout);
76 | std::cout << "\n\n";
77 |
78 | std::cout << "Copy to different arena:\n";
79 | MemRegion region;
80 | MemRegionRef arena(®ion);
81 | SExpr* e2 = copier.copy(e, arena);
82 | TILDebugPrinter::print(e2, std::cout);
83 | std::cout << "\n\n";
84 |
85 | std::cout << "Inplace reduce (TypedEvaluator):\n";
86 | TypedEvaluator eval(bld.arena());
87 | SExpr* e3 = eval.traverseAll(e);
88 | TILDebugPrinter::print(e3, std::cout);
89 | std::cout << "\n\n";
90 | }
91 |
92 |
93 | void testCopying() {
94 | MemRegion region;
95 | MemRegionRef arena(®ion);
96 | CFGBuilder builder(arena);
97 |
98 | testCopying(builder, makeSimple(builder));
99 | }
100 |
101 | int main(int argc, const char** argv) {
102 | testCopying();
103 | }
104 |
--------------------------------------------------------------------------------
/src/test/til/test_visitor.cpp:
--------------------------------------------------------------------------------
1 | //===- test_visitor.cpp ----------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 | //
18 | // Compile-only test.
19 | // Instantiates some visitor and traverser templates for testing purposes.
20 | //
21 | //===----------------------------------------------------------------------===//
22 |
23 | #include "til/TILVisitor.h"
24 |
25 | namespace ohmu {
26 | namespace til {
27 |
28 |
29 | class SimpleVisitor : public Visitor { };
30 |
31 |
32 | void test(SExpr* E) {
33 | SimpleVisitor::visit(E);
34 | }
35 |
36 |
37 | } // end namespace til
38 | } // end namespace ohmu
39 |
--------------------------------------------------------------------------------
/src/til/Annotation.h:
--------------------------------------------------------------------------------
1 | //===- Annotation.h --------------------------------------------*- C++ --*-===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT in the LLVM repository for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 |
10 | #ifndef OHMU_TIL_ANNOTATION_H
11 | #define OHMU_TIL_ANNOTATION_H
12 |
13 | #include "base/LLVMDependencies.h"
14 | #include "base/MemRegion.h"
15 |
16 | namespace ohmu {
17 | namespace til {
18 |
19 | /// Enum for the various kinds of attributes
20 | enum TIL_AnnKind {
21 | #define TIL_ANNKIND_DEF(X) ANNKIND_##X,
22 | #include "TILAnnKinds.def"
23 | };
24 |
25 | /// Annotation stores one annotation and a next-pointer; thus doubling as a
26 | /// linked list. New annotations need to be created in an arena.
27 | class Annotation {
28 | public:
29 | TIL_AnnKind kind() const { return static_cast(Kind); }
30 |
31 | /// Allocate Annotation in the given region. Annotations must be allocated in
32 | /// regions.
33 | void *operator new(size_t S, MemRegionRef &R) {
34 | return ::operator new(S, R);
35 | }
36 |
37 | /// Annotation objects cannot be deleted.
38 | // This declaration is public to workaround a gcc bug that breaks building
39 | // with REQUIRES_EH=1.
40 | void operator delete(void *) = delete;
41 |
42 | Annotation *next() const { return Next; }
43 |
44 | /// Insert annotation in this sorted list of annotations.
45 | void insert(Annotation *A) {
46 | if (A == nullptr)
47 | return;
48 | assert(A->kind() >= kind() && "Keep annotations sorted, change list head.");
49 | Annotation *Ap = this;
50 | while (Ap->next() && A->kind() >= Ap->kind()) {
51 | Ap = Ap->next();
52 | }
53 | A->Next = Ap->next();
54 | Ap->Next = A;
55 | }
56 |
57 | /// Get annotation of the specified derived type. Returns nullptr if no such
58 | /// annotation exists in the list.
59 | template
60 | T *getAnnotation() {
61 | Annotation *Ap = this;
62 | do {
63 | if (isa(Ap))
64 | return cast(Ap);
65 | Ap = Ap->Next;
66 | } while (Ap);
67 | return nullptr;
68 | }
69 |
70 | /// Get all annotations of the specified derived type.
71 | template
72 | std::vector getAllAnnotations() {
73 | std::vector Res;
74 | T *A = getAnnotation();
75 | // Using the fact that the list is sorted.
76 | while (A) {
77 | Res.push_back(A);
78 | if (A->next() && A->kind() == A->next()->kind())
79 | A = A->next();
80 | else
81 | A = nullptr;
82 | }
83 | return Res;
84 | }
85 |
86 | protected:
87 | Annotation(TIL_AnnKind K) : Kind(K), Next(nullptr) { }
88 |
89 | private:
90 | Annotation() = delete;
91 |
92 | /// Annotation objects must be created in an arena.
93 | void *operator new(size_t) = delete;
94 |
95 | const uint16_t Kind;
96 |
97 | Annotation* Next;
98 | };
99 |
100 | } // end namespace til
101 | } // end namespace ohmu
102 |
103 | #endif // OHMU_TIL_ANNOTATION_H
104 |
--------------------------------------------------------------------------------
/src/til/AnnotationImpl.cpp:
--------------------------------------------------------------------------------
1 | //===- AnnotationImpl.cpp --------------------------------------*- C++ --*-===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT in the LLVM repository for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 |
10 | #include "AnnotationImpl.h"
11 | #include "Bytecode.h"
12 | #include "CFGBuilder.h"
13 |
14 | namespace ohmu {
15 | namespace til {
16 |
17 |
18 | InstrNameAnnot *InstrNameAnnot::copy(CFGBuilder &Builder,
19 | const std::vector &SubExprs) {
20 | return Builder.newAnnotationT(Name);
21 | }
22 |
23 | void InstrNameAnnot::serialize(BytecodeWriter *B) {
24 | B->getWriter()->writeString(Name);
25 | }
26 |
27 | InstrNameAnnot *InstrNameAnnot::deserialize(BytecodeReader *B) {
28 | StringRef Nm = B->getReader()->readString();
29 | return B->getBuilder().newAnnotationT(Nm);
30 | }
31 |
32 |
33 | SourceLocAnnot *SourceLocAnnot::copy(CFGBuilder &Builder,
34 | const std::vector &SubExprs) {
35 | return Builder.newAnnotationT(Position);
36 | }
37 |
38 | void SourceLocAnnot::serialize(BytecodeWriter *B) {
39 | B->getWriter()->writeInt64(Position);
40 | }
41 |
42 | SourceLocAnnot *SourceLocAnnot::deserialize(BytecodeReader *B) {
43 | SourcePosition P = B->getReader()->readInt64();
44 | return B->getBuilder().newAnnotationT(P);
45 | }
46 |
47 |
48 | PreconditionAnnot*
49 | PreconditionAnnot::copy(CFGBuilder &Builder,
50 | const std::vector &SubExprs) {
51 | return Builder.newAnnotationT(SubExprs.at(0));
52 | }
53 |
54 | void PreconditionAnnot::serialize(BytecodeWriter *B) { }
55 |
56 | PreconditionAnnot *PreconditionAnnot::deserialize(BytecodeReader *B) {
57 | PreconditionAnnot *A =
58 | B->getBuilder().newAnnotationT(B->arg(0));
59 | B->drop(1);
60 | return A;
61 | }
62 |
63 |
64 | TestTripletAnnot *TestTripletAnnot::copy(CFGBuilder &Builder,
65 | const std::vector &SubExprs) {
66 | return Builder.newAnnotationT(
67 | SubExprs.at(0), SubExprs.at(1), SubExprs.at(2));
68 | }
69 |
70 | void TestTripletAnnot::serialize(BytecodeWriter *B) { }
71 |
72 | TestTripletAnnot *TestTripletAnnot::deserialize(BytecodeReader *B) {
73 | TestTripletAnnot *A = B->getBuilder().newAnnotationT(
74 | B->arg(2), B->arg(1), B->arg(0));
75 | B->drop(3);
76 | return A;
77 | }
78 |
79 |
80 | } // end namespace til
81 | } // end namespace ohmu
82 |
--------------------------------------------------------------------------------
/src/til/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8)
2 |
3 | add_library(til STATIC
4 | Bytecode.cpp
5 | CFGBuilder.cpp
6 | Global.cpp
7 | SSAPass.cpp
8 | AnnotationImpl.cpp
9 | TIL.cpp
10 | TypedEvaluator.cpp
11 | )
12 |
13 | target_link_libraries(til base)
14 |
--------------------------------------------------------------------------------
/src/til/Evaluator.h:
--------------------------------------------------------------------------------
1 | //===- TypedEvaluator.h ----------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 |
18 | #ifndef OHMU_TIL_EVALUATOR_H
19 | #define OHMU_TIL_EVALUATOR_H
20 |
21 | #include "TIL.h"
22 |
23 | namespace ohmu {
24 | namespace til {
25 |
26 | // TODO: minimum integer size should not be hardcoded at ST_32.
27 | // See TILBaseType.h
28 |
29 |
30 | #define DEFINE_BINARY_OP_CLASS(CName, OP, RTy) \
31 | template \
32 | struct CName { \
33 | typedef Literal* ReturnType; \
34 | static Literal* defaultAction(MemRegionRef A, Literal*, Literal*) { \
35 | return nullptr; \
36 | } \
37 | static LiteralT* action(MemRegionRef A, Literal* E0, Literal* E1) { \
38 | return new (A) LiteralT(E0->as()->value() OP \
39 | E1->as()->value()); \
40 | } \
41 | };
42 |
43 |
44 | namespace opclass {
45 |
46 | DEFINE_BINARY_OP_CLASS(Add, +, Ty1)
47 | DEFINE_BINARY_OP_CLASS(Sub, -, Ty1)
48 | DEFINE_BINARY_OP_CLASS(Mul, *, Ty1)
49 | DEFINE_BINARY_OP_CLASS(Div, /, Ty1)
50 | DEFINE_BINARY_OP_CLASS(Rem, %, Ty1)
51 | DEFINE_BINARY_OP_CLASS(Shl, <<, Ty1)
52 | DEFINE_BINARY_OP_CLASS(Shr, >>, Ty1)
53 | DEFINE_BINARY_OP_CLASS(BitAnd, &, Ty1)
54 | DEFINE_BINARY_OP_CLASS(BitXor, ^, Ty1)
55 | DEFINE_BINARY_OP_CLASS(BitOr, |, Ty1)
56 |
57 | DEFINE_BINARY_OP_CLASS(Eq, ==, bool)
58 | DEFINE_BINARY_OP_CLASS(Neq, !=, bool)
59 | DEFINE_BINARY_OP_CLASS(Lt, <, bool)
60 | DEFINE_BINARY_OP_CLASS(Leq, <=, bool)
61 |
62 | DEFINE_BINARY_OP_CLASS(LogicAnd, &&, Ty1)
63 | DEFINE_BINARY_OP_CLASS(LogicOr, ||, Ty1)
64 |
65 | } // end namespace opclass
66 |
67 | #undef DEFINE_BINARY_OP_CLASS
68 |
69 |
70 | #define ARGS(OP) opclass::OP, Literal*, MemRegionRef, Literal*, Literal*
71 |
72 | Literal* evaluateBinaryOp(TIL_BinaryOpcode Op, BaseType Bt, MemRegionRef A,
73 | Literal* E0, Literal* E1) {
74 | switch (Op) {
75 | case BOP_Add:
76 | return BtBr::branchOnNumeric(Bt, A, E0, E1);
77 | case BOP_Sub:
78 | return BtBr::branchOnNumeric(Bt, A, E0, E1);
79 | case BOP_Mul:
80 | return BtBr::branchOnNumeric(Bt, A, E0, E1);
81 | case BOP_Div:
82 | return BtBr::branchOnNumeric(Bt, A, E0, E1);
83 | case BOP_Rem:
84 | return BtBr::branchOnIntegral(Bt, A, E0, E1);
85 | case BOP_Shl:
86 | return BtBr::branchOnIntegral(Bt, A, E0, E1);
87 | case BOP_Shr:
88 | return BtBr::branchOnIntegral(Bt, A, E0, E1);
89 | case BOP_BitAnd:
90 | return BtBr::branchOnIntegral(Bt, A, E0, E1);
91 | case BOP_BitXor:
92 | return BtBr::branchOnIntegral(Bt, A, E0, E1);
93 | case BOP_BitOr:
94 | return BtBr::branchOnIntegral(Bt, A, E0, E1);
95 | case BOP_Eq:
96 | return BtBr::branch(Bt, A, E0, E1);
97 | case BOP_Neq:
98 | return BtBr::branch(Bt, A, E0, E1);
99 | case BOP_Lt:
100 | return BtBr::branchOnNumeric(Bt, A, E0, E1);
101 | case BOP_Leq:
102 | return BtBr::branchOnNumeric(Bt, A, E0, E1);
103 | case BOP_Gt:
104 | return BtBr::branchOnNumeric(Bt, A, E1, E0);
105 | case BOP_Geq:
106 | return BtBr::branchOnNumeric(Bt, A, E1, E0);
107 | case BOP_LogicAnd:
108 | return opclass::LogicAnd::action(A, E0, E1);
109 | case BOP_LogicOr:
110 | return opclass::LogicOr::action(A, E0, E1);
111 | }
112 | return nullptr;
113 | }
114 |
115 | #undef ARGS
116 |
117 |
118 | } // endif namespace til
119 | } // endif namespace ohmu
120 |
121 | #endif // OHMU_TIL_EVALUATOR_H
122 |
--------------------------------------------------------------------------------
/src/til/Global.cpp:
--------------------------------------------------------------------------------
1 | //===- Global.cpp ----------------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 |
18 | #include "Global.h"
19 | #include "TypedEvaluator.h"
20 |
21 | namespace ohmu {
22 | namespace til {
23 |
24 |
25 | template
26 | inline Slot* scalarTypeSlot(Global &G, StringRef Name) {
27 | auto* Ty = new (G.LangArena) ScalarType(BaseType::getBaseType());
28 | auto* Slt = new (G.ParseArena) Slot(Name, Ty);
29 | Slt->setModifier(Slot::SLT_Final);
30 | return Slt;
31 | }
32 |
33 | void Global::createPrelude() {
34 | PreludeDefs.push_back( scalarTypeSlot (*this, "Void") );
35 | PreludeDefs.push_back( scalarTypeSlot (*this, "Bool") );
36 | PreludeDefs.push_back( scalarTypeSlot (*this, "Int8") );
37 | PreludeDefs.push_back( scalarTypeSlot (*this, "UInt8") );
38 | PreludeDefs.push_back( scalarTypeSlot (*this, "Int16") );
39 | PreludeDefs.push_back( scalarTypeSlot (*this, "UInt16") );
40 | PreludeDefs.push_back( scalarTypeSlot (*this, "Int32") );
41 | PreludeDefs.push_back( scalarTypeSlot (*this, "UInt32") );
42 | PreludeDefs.push_back( scalarTypeSlot (*this, "Int64") );
43 | PreludeDefs.push_back( scalarTypeSlot (*this, "UInt64") );
44 | PreludeDefs.push_back( scalarTypeSlot (*this, "Float") );
45 | PreludeDefs.push_back( scalarTypeSlot (*this, "Double") );
46 | PreludeDefs.push_back( scalarTypeSlot(*this, "String") );
47 | PreludeDefs.push_back( scalarTypeSlot (*this, "PointerType") );
48 |
49 | PreludeDefs.push_back( scalarTypeSlot(*this, "Int") );
50 | PreludeDefs.push_back( scalarTypeSlot(*this, "UInt") );
51 | }
52 |
53 |
54 | void Global::addDefinitions(std::vector& Defs) {
55 | assert(GlobalRec == nullptr && "FIXME: support multiple calls.");
56 |
57 | if (PreludeDefs.empty())
58 | createPrelude();
59 |
60 | unsigned Sz = PreludeDefs.size() + Defs.size();
61 | GlobalRec = new (ParseArena) Record(ParseArena, Sz);
62 |
63 | for (auto *Slt : PreludeDefs) {
64 | GlobalRec->slots().emplace_back(ParseArena, Slt);
65 | }
66 | for (auto *E : Defs) {
67 | auto *Slt = dyn_cast_or_null(E);
68 | if (Slt)
69 | GlobalRec->slots().emplace_back(ParseArena, Slt);
70 | }
71 |
72 | auto *Vd = new (ParseArena) VarDecl(VarDecl::VK_SFun, "global", nullptr);
73 | GlobalSFun = new (ParseArena) Function(Vd, GlobalRec);
74 | }
75 |
76 |
77 | void Global::lower() {
78 | TypedEvaluator eval(DefArena);
79 | SExpr* E = eval.traverseAll(GlobalSFun);
80 |
81 | // Replace the global definitions with lowered versions.
82 | GlobalSFun = dyn_cast(E);
83 | if (GlobalSFun)
84 | GlobalRec = dyn_cast(GlobalSFun->body());
85 | else
86 | GlobalRec = nullptr;
87 | }
88 |
89 |
90 | void Global::print(std::ostream &SS) {
91 | TILDebugPrinter::print(GlobalSFun, SS);
92 | }
93 |
94 |
95 | } // end namespace til
96 | } // end namespace ohmu
97 |
--------------------------------------------------------------------------------
/src/til/Global.h:
--------------------------------------------------------------------------------
1 | //===- Global.h ------------------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 |
18 | #ifndef OHMU_TIL_GLOBAL_H
19 | #define OHMU_TIL_GLOBAL_H
20 |
21 | #include "TIL.h"
22 |
23 | #include
24 |
25 | namespace ohmu {
26 | namespace til {
27 |
28 |
29 | class Global {
30 | public:
31 | Global()
32 | : GlobalRec(nullptr), GlobalSFun(nullptr),
33 | LangArena(&LangRegion), StringArena(&StringRegion),
34 | ParseArena(&ParseRegion), DefArena(&DefRegion)
35 | { }
36 |
37 | inline SExpr* global() { return GlobalSFun; }
38 |
39 | void createPrelude();
40 |
41 | // Add Defs to the set of global, newly parsed definitions.
42 | void addDefinitions(std::vector &Defs);
43 |
44 | // Lower the parsed definitions.
45 | void lower();
46 |
47 | // Dump outputs to the given stream
48 | void print(std::ostream &SS);
49 |
50 | private:
51 | MemRegion LangRegion; // Standard language definitions.
52 | MemRegion StringRegion; // Region to hold string constants.
53 | MemRegion ParseRegion; // Region for the initial AST produced by the parser.
54 | MemRegion DefRegion; // Region for rewritten definitions.
55 |
56 | Record *GlobalRec;
57 | Function *GlobalSFun;
58 | std::vector PreludeDefs;
59 |
60 | public:
61 | MemRegionRef LangArena;
62 | MemRegionRef StringArena;
63 | MemRegionRef ParseArena;
64 | MemRegionRef DefArena;
65 | };
66 |
67 |
68 | } // end namespace til
69 | } // end namespace ohmu
70 |
71 | #endif // OHMU_TIL_GLOBAL_H
72 |
--------------------------------------------------------------------------------
/src/til/README.txt:
--------------------------------------------------------------------------------
1 |
2 | The Ohmu Typed Intermediate Language (TIL) has been carefully designed to be
3 | language-agnostic. The hope is that many different source languages can be
4 | translated down to the TIL, so that the ohmu static analysis can be made
5 | language agnostic.
6 |
7 | The clang C++ compiler uses the TIL to do thread safety analysis. Many of the
8 | files in this directory are thus mirrored in the clang open source repository,
9 | and can be found under clang/lib/Analysis/Analyses/ThreadSafety/. Files which
10 | shared with clang are released under the LLVM open source license, rather than
11 | the Apache open source license, and are written in the clang/LLVM style.
12 |
13 |
--------------------------------------------------------------------------------
/src/til/SSAPass.h:
--------------------------------------------------------------------------------
1 | //===- SSAPass.h -----------------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 | //
18 | // Implements the conversion to SSA.
19 | //
20 | //===----------------------------------------------------------------------===//
21 |
22 | #ifndef OHMU_TIL_SSAPASS_H
23 | #define OHMU_TIL_SSAPASS_H
24 |
25 | #include "InplaceReducer.h"
26 |
27 | namespace ohmu {
28 | namespace til {
29 |
30 |
31 | // Map from local variables (allocID) to their definitions (SExpr*).
32 | typedef std::vector LocalVarMap;
33 |
34 | // Maintain a variable map for each basic block.
35 | struct SSABlockInfo {
36 | LocalVarMap AllocVarMap;
37 | };
38 |
39 |
40 | class SSAPass : public InplaceReducer,
41 | public AGTraversal {
42 | public:
43 | void enterCFG(SCFG *Cfg);
44 | void exitCFG(SCFG *Cfg);
45 | void enterBlock(BasicBlock *B);
46 | void exitBlock(BasicBlock *B);
47 |
48 | void reduceWeak(Instruction *I);
49 | void reduceAlloc(Alloc *Orig);
50 | void reduceStore(Store *Orig);
51 | void reduceLoad (Load *Orig);
52 |
53 | protected:
54 | // An Alloc instruction that may be removed.
55 | class FutureAlloc : public Future {
56 | public:
57 | FutureAlloc(Alloc* A) : AllocInstr(A) { }
58 | virtual ~FutureAlloc() { }
59 |
60 | /// We don't use evaluate(); FutureAllocs are forced manually.
61 | virtual SExpr* evaluate() override {
62 | assert(false && "Cannot force this future.");
63 | return nullptr;
64 | }
65 |
66 | Alloc *AllocInstr;
67 | };
68 |
69 | // A Store instruction that may be removed.
70 | class FutureStore : public Future {
71 | public:
72 | FutureStore(Store* S, Alloc* A) : StoreInstr(S), AllocInstr(A) { }
73 | virtual ~FutureStore() { }
74 |
75 | /// We don't use evaluate(); FutureStores are forced manually.
76 | virtual SExpr* evaluate() override {
77 | assert(false && "Cannot force this future.");
78 | return nullptr;
79 | }
80 |
81 | Store *StoreInstr;
82 | Alloc *AllocInstr;
83 | };
84 |
85 | // A load instruction that needs to be rewritten.
86 | class FutureLoad : public Future {
87 | public:
88 | FutureLoad(Load* L, Alloc* A) : LoadInstr(L), AllocInstr(A) { }
89 | virtual ~FutureLoad() { }
90 |
91 | /// We don't use evaluate(); FutureLoads are forced manually.
92 | virtual SExpr* evaluate() override {
93 | assert(false && "Cannot force this future.");
94 | return nullptr;
95 | }
96 |
97 | Load *LoadInstr;
98 | Alloc *AllocInstr;
99 | };
100 |
101 | // Look up variable in the cache.
102 | SExpr* lookupInCache(LocalVarMap *LvarMap, unsigned LvarID);
103 |
104 | // Make a new phi node, with the first i values set to E
105 | Phi* makeNewPhiNode(unsigned i, SExpr *E, unsigned numPreds);
106 |
107 | // Lookup value of local variable at the beginning of basic block B
108 | SExpr* lookupInPredecessors(BasicBlock *B, unsigned LvarID, StringRef Nm);
109 |
110 | // Lookup value of local variable at the end of basic block B
111 | SExpr* lookup(BasicBlock *B, unsigned LvarID, StringRef Nm);
112 |
113 | // Second pass of SSA -- lookup variables and replace all loads.
114 | void replacePending();
115 |
116 | public:
117 | SSAPass(MemRegionRef A)
118 | : InplaceReducer(A), CurrentVarMap(nullptr) {
119 | FutArena.setRegion(&FutRegion);
120 | }
121 |
122 | private:
123 | typedef InplaceReducer Super;
124 | typedef Traversal SuperTv;
125 |
126 | SSAPass() = delete;
127 |
128 | MemRegion FutRegion; ///< Put Futures in region for immediate deletion.
129 | MemRegionRef FutArena;
130 |
131 | LocalVarMap* CurrentVarMap;
132 |
133 | std::vector BInfoMap; ///< Side table for basic blocks.
134 | std::vector PendingAllocs; ///< Possibly removable allocs.
135 | std::vector PendingStores; ///< Possibly removable stores.
136 | std::vector PendingLoads; ///< Loads that need to be forced.
137 |
138 | std::vector NumUses;
139 | };
140 |
141 |
142 | } // end namespace til
143 | } // end namespace ohmu
144 |
145 | #endif // OHMU_TIL_SSAPASS_H
146 |
--------------------------------------------------------------------------------
/src/til/TILAnnKinds.def:
--------------------------------------------------------------------------------
1 | //===- TILAnnKinds.def -----------------------------------------*- C++ --*-===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 | //
10 | // This file defines the list of annotation kinds for the Typed Intermediate
11 | // language. See Annotation.h for their usage.
12 | //
13 | //===----------------------------------------------------------------------===//
14 |
15 | #ifdef TIL_ANNKIND_FIRST
16 | TIL_ANNKIND_FIRST(InstrName)
17 | #undef TIL_ANNKIND_FIRST
18 | #endif
19 |
20 | #ifdef TIL_ANNKIND_DEF
21 |
22 | // Declarations and definitions
23 | TIL_ANNKIND_DEF(InstrNameAnnot)
24 | TIL_ANNKIND_DEF(SourceLocAnnot)
25 | TIL_ANNKIND_DEF(TestTripletAnnot)
26 | TIL_ANNKIND_DEF(PreconditionAnnot)
27 |
28 | #undef TIL_ANNKIND_DEF
29 | #endif // TIL_ANNKIND_DEF
30 |
31 | #ifdef TIL_ANNKIND_LAST
32 | TIL_ANNKIND_LAST(Precondition)
33 | #undef TIL_ANNKIND_LAST
34 | #endif
35 |
--------------------------------------------------------------------------------
/src/til/TILOps.def:
--------------------------------------------------------------------------------
1 | //===- ThreadSafetyTIL.h ---------------------------------------*- C++ --*-===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 | //
10 | // This file defines the list of core opcodes for the Thread Safety
11 | // Typed Intermediate language. Please see ThreadSafetyTIL.h for more
12 | // information.
13 | //
14 | //===----------------------------------------------------------------------===//
15 |
16 | #ifdef TIL_OPCODE_FIRST
17 | TIL_OPCODE_FIRST(VarDecl)
18 | #undef TIL_OPCODE_FIRST
19 | #endif
20 |
21 | #ifdef TIL_OPCODE_DEF
22 |
23 | // Declarations and definitions
24 | TIL_OPCODE_DEF(VarDecl)
25 | TIL_OPCODE_DEF(Function)
26 | TIL_OPCODE_DEF(Code)
27 | TIL_OPCODE_DEF(Field)
28 | TIL_OPCODE_DEF(Slot)
29 | TIL_OPCODE_DEF(Record)
30 | TIL_OPCODE_DEF(Array)
31 | TIL_OPCODE_DEF(ScalarType)
32 |
33 | // CFG constructs
34 | TIL_OPCODE_DEF(SCFG)
35 | TIL_OPCODE_DEF(BasicBlock)
36 |
37 | // Instructions
38 | TIL_OPCODE_DEF(Literal)
39 | TIL_OPCODE_DEF(Variable)
40 |
41 | // Paths
42 | TIL_OPCODE_DEF(Apply)
43 | TIL_OPCODE_DEF(Project)
44 |
45 | TIL_OPCODE_DEF(Call)
46 | TIL_OPCODE_DEF(Alloc)
47 | TIL_OPCODE_DEF(Load)
48 | TIL_OPCODE_DEF(Store)
49 | TIL_OPCODE_DEF(ArrayIndex)
50 | TIL_OPCODE_DEF(ArrayAdd)
51 | TIL_OPCODE_DEF(UnaryOp)
52 | TIL_OPCODE_DEF(BinaryOp)
53 | TIL_OPCODE_DEF(Cast)
54 | TIL_OPCODE_DEF(Phi)
55 |
56 | // Terminator instructions
57 | TIL_OPCODE_DEF(Goto)
58 | TIL_OPCODE_DEF(Branch)
59 | TIL_OPCODE_DEF(Switch)
60 | TIL_OPCODE_DEF(Return)
61 |
62 | // Future and Undefined are instructions for rewriting purposes.
63 | TIL_OPCODE_DEF(Future)
64 | TIL_OPCODE_DEF(Undefined)
65 |
66 | // Pseudo-terms
67 | TIL_OPCODE_DEF(Wildcard)
68 |
69 | TIL_OPCODE_DEF(Identifier)
70 | TIL_OPCODE_DEF(Let)
71 | TIL_OPCODE_DEF(IfThenElse)
72 |
73 | #undef TIL_OPCODE_DEF
74 | #endif // TIL_OPCODE_DEF
75 |
76 | #ifdef TIL_OPCODE_LAST
77 | TIL_OPCODE_LAST(IfThenElse)
78 | #undef TIL_OPCODE_LAST
79 | #endif
80 |
--------------------------------------------------------------------------------
/src/til/TILVisitor.h:
--------------------------------------------------------------------------------
1 | //===- TILVisitor.h --------------------------------------------*- C++ --*-===//
2 | //
3 | // The LLVM Compiler Infrastructure
4 | //
5 | // This file is distributed under the University of Illinois Open Source
6 | // License. See LICENSE.TXT for details.
7 | //
8 | //===----------------------------------------------------------------------===//
9 | //
10 | // Implements the reducer interface so that every reduce method simply
11 | // calls a corresponding visit method.
12 | //
13 | //===----------------------------------------------------------------------===//
14 |
15 | #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETY_TILVISITOR_H
16 | #define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETY_TILVISITOR_H
17 |
18 | #include "TIL.h"
19 | #include "TILTraverse.h"
20 |
21 | namespace ohmu {
22 | namespace til {
23 |
24 |
25 | /// Implements a post-order visitor.
26 | template
27 | class Visitor : public Traversal,
28 | public DefaultScopeHandler,
29 | public DefaultReducer {
30 | public:
31 | typedef Traversal SuperTv;
32 |
33 | Self* self() { return static_cast(this); }
34 |
35 | Visitor() : Success(true) { }
36 |
37 | static bool visit(SExpr *E) {
38 | Self Visitor;
39 | Visitor.traverseAll(E);
40 | return Visitor.Success;
41 | }
42 |
43 | /// Visit routines may invoke fail() to abort the visitor.
44 | void fail() { Success = false; }
45 |
46 | /// Override traverse to abort traversal on failure.
47 | template
48 | void traverse(T* E, TraversalKind K) {
49 | if (Success)
50 | SuperTv::traverse(E, K);
51 | }
52 |
53 | protected:
54 | bool Success;
55 | };
56 |
57 |
58 | } // end namespace til
59 | } // end namespace ohmu
60 |
61 | #endif // LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETY_TILVISITOR_H
62 |
--------------------------------------------------------------------------------
/src/til/VisitCFG.h:
--------------------------------------------------------------------------------
1 | //===- VisitCFG.h --------------------------------------------*- C++ --*-===//
2 | // Copyright 2014 Google
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 | //===----------------------------------------------------------------------===//
17 | //
18 | // This is a simple Visitor class that collects all of the CFGs in a module
19 | // into a list.
20 | //
21 | //===----------------------------------------------------------------------===//
22 |
23 | #include "TILVisitor.h"
24 |
25 | #ifndef OHMU_TIL_VISITCFG_H_
26 | #define OHMU_TIL_VISITCFG_H_
27 |
28 | namespace ohmu {
29 | namespace til {
30 |
31 |
32 | // Simple visitor which finds all CFGs and adds them to list.
33 | class VisitCFG : public Visitor {
34 | public:
35 | // Don't traverse inside CFGs; just add them to the list.
36 | bool traverseSCFG(SCFG* cfg) {
37 | cfgList_.push_back(cfg);
38 | return true;
39 | }
40 |
41 | std::vector& cfgs() { return cfgList_; }
42 |
43 | private:
44 | std::vector cfgList_;
45 | };
46 |
47 |
48 | } // end namespace til
49 | } // end namespace ohmu
50 |
51 | #endif // OHMU_TIL_VISITCFG_H_
52 |
--------------------------------------------------------------------------------
/src/unittests/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | find_package(Threads)
2 |
3 | macro(run_test TEST_NAME)
4 | add_dependencies(${TEST_NAME} gtest)
5 | target_link_libraries(${TEST_NAME}
6 | ${GTEST_BIN}/libgtest.a
7 | )
8 | target_link_libraries(${TEST_NAME} ${CMAKE_THREAD_LIBS_INIT})
9 | add_test(run_${TEST_NAME} ${TEST_NAME})
10 | endmacro(run_test)
11 |
12 | add_subdirectory(lsa)
13 |
14 |
--------------------------------------------------------------------------------
/src/unittests/lsa/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_executable(lsa_callgraph_unittests BuildCallGraphTest.cpp)
2 | target_link_libraries(lsa_callgraph_unittests lsa)
3 | run_test(lsa_callgraph_unittests)
4 |
5 | add_executable(lsa_standalone_graph_unittests
6 | StandaloneGraphComputationTest.cpp)
7 | target_link_libraries(lsa_standalone_graph_unittests lsa)
8 | run_test(lsa_standalone_graph_unittests)
9 |
10 | add_executable(lsa_scc_unittests SCCComputationTest.cpp)
11 | target_link_libraries(lsa_scc_unittests lsa_example_scc)
12 | run_test(lsa_scc_unittests)
13 |
--------------------------------------------------------------------------------
/src/unittests/lsa/SCCComputationTest.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "gtest/gtest.h"
4 | #include "lsa/examples/SCCComputation.h"
5 |
6 | namespace {
7 | /// Return the partition identifier as it is used in the SCC computation.
8 | string partition(string id) { return id + ":" + id; }
9 |
10 | /// Actually runs the test. Creates the graph with specified vertices and calls.
11 | /// Runs the SCC computation and checks whether each vertex ends up in the
12 | /// expected SCC (partition).
13 | void TestSCC(const std::vector &vertices,
14 | const std::vector> &calls,
15 | const std::unordered_map &expected) {
16 | ohmu::lsa::StandaloneGraphBuilder Builder;
17 |
18 | for (const string &vertex : vertices) {
19 | ohmu::lsa::SCCNode node;
20 | Builder.addVertex(vertex, "", node);
21 | }
22 |
23 | for (const auto &call : calls) {
24 | Builder.addCall(call.first, call.second);
25 | }
26 | ohmu::lsa::GraphComputationFactory Factory;
27 | Builder.run(&Factory);
28 |
29 | std::unique_ptr>
30 | Computation(Factory.createComputation());
31 | for (const auto &Vertex : Builder.getVertices()) {
32 | string expected_partition = expected.find(Vertex.id())->second;
33 | string actual_partition = Computation->output(&Vertex);
34 | EXPECT_EQ(expected_partition, actual_partition)
35 | << "When checking SCC of vertex " << Vertex.id() << ".\n";
36 | }
37 | }
38 |
39 | } // end namespace
40 |
41 | TEST(SCCComputation, SingletonSCC) {
42 | string aId = "a", bId = "b", cId = "c";
43 |
44 | // Generated graph:
45 | //
46 | // a b c
47 | //
48 | // SCC #1: {a}
49 | // SCC #2: {b}
50 | // SCC #3: {c}
51 |
52 | std::vector vertices = {aId, bId, cId};
53 | std::vector> calls = {};
54 | std::unordered_map expected = {
55 | {aId, partition(aId)}, {bId, partition(bId)}, {cId, partition(cId)}};
56 |
57 | TestSCC(vertices, calls, expected);
58 | }
59 |
60 | TEST(SCCComputation, OneSCC) {
61 | string aId = "a", bId = "b", cId = "c";
62 |
63 | // Generated graph:
64 | //
65 | // a ----> b ----> c
66 | // ^ |
67 | // \-------------------/
68 | //
69 | // SCC #1: {a, b, c}
70 |
71 | std::vector vertices = {aId, bId, cId};
72 | std::vector> calls = {
73 | {aId, bId}, {bId, cId}, {cId, aId}};
74 | std::unordered_map expected = {
75 | {aId, partition(aId)}, {bId, partition(aId)}, {cId, partition(aId)}};
76 |
77 | TestSCC(vertices, calls, expected);
78 | }
79 |
80 | TEST(SCCComputation, TwoSCC) {
81 | string aId = "a", bId = "b", cId = "c", dId = "d", eId = "e", fId = "f",
82 | gId = "g";
83 |
84 | // Generated graph:
85 | //
86 | // a ----> b ----> c ----> d ----> e
87 | // ^ ^ | ^ |
88 | // | | | | |
89 | // | | | v |
90 | // \------- f <------/ g <------/
91 | //
92 | // SCC #1: {a, b, c, f}
93 | // SCC #2: {d, e, g}
94 |
95 | std::vector vertices = {aId, bId, cId, dId, eId, fId, gId};
96 | std::vector> calls = {
97 | {aId, bId}, {bId, cId}, {cId, fId}, {cId, dId}, {dId, eId},
98 | {dId, gId}, {eId, gId}, {fId, bId}, {fId, aId}, {gId, dId}};
99 | std::unordered_map expected = {
100 | {aId, partition(aId)}, {bId, partition(aId)}, {cId, partition(aId)},
101 | {fId, partition(aId)}, {dId, partition(dId)}, {eId, partition(dId)},
102 | {gId, partition(dId)}};
103 |
104 | TestSCC(vertices, calls, expected);
105 | }
106 |
107 | int main(int argc, char **argv) {
108 | ::testing::InitGoogleTest(&argc, argv);
109 | return RUN_ALL_TESTS();
110 | }
111 |
--------------------------------------------------------------------------------
/temp.ohmu:
--------------------------------------------------------------------------------
1 |
2 | let x = (let y = 2; y*y);
3 | x+x;
4 |
--------------------------------------------------------------------------------