├── .appveyor.yml ├── .clang-format ├── .github ├── dependabot.yml └── workflows │ └── c-cpp.yml ├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── LICENSE.txt ├── README.md ├── SECURITY.md ├── bugs.rst ├── check_format.sh ├── docker ├── Dockerfile └── docker-entrypoint.sh ├── papers ├── yarpgen-ooplsa-2020.pdf └── yarpgen-pldi-2023.pdf ├── scripts ├── blame_opt.py ├── build_binutils.sh ├── build_gcc.sh ├── build_llvm.sh ├── build_yarpgen.sh ├── check_isa.cpp ├── collect_other_stats.py ├── common.py ├── gen_test_makefile.py ├── ispc-disp ├── ispc-proxy ├── rechecker.py ├── run_gen.py ├── test_sets.txt └── tmp_cleaner.sh └── src ├── CMakeLists.txt ├── context.cpp ├── context.h ├── data.cpp ├── data.h ├── data_test.cpp ├── emit_policy.cpp ├── emit_policy.h ├── enums.h ├── expr.cpp ├── expr.h ├── expr_test.cpp ├── gen_policy.cpp ├── gen_policy.h ├── gen_test.cpp ├── hash.cpp ├── hash.h ├── ir_node.h ├── ir_value.cpp ├── ir_value.h ├── main.cpp ├── options.cpp ├── options.h ├── program.cpp ├── program.h ├── statistics.cpp ├── statistics.h ├── stmt.cpp ├── stmt.h ├── type.cpp ├── type.h ├── type_test.cpp ├── utils.cpp └── utils.h /.appveyor.yml: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # Copyright (c) 2018-2020, Intel Corporation 4 | # Copyright (c) 2019-2020, University of Utah 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | ############################################################################### 19 | 20 | # Minimum VS version is 2015, as it's first to support C++14. 21 | 22 | environment: 23 | matrix: 24 | - APPVEYOR_BUILD_WORKER_IMAGE: macos 25 | - APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu 26 | cmake_arch: x86 27 | - APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu 28 | cmake_arch: x64 29 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 30 | GENERATOR: "Visual Studio 15 2017" 31 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 32 | GENERATOR: "Visual Studio 15 2017 Win64" 33 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 34 | GENERATOR: "Visual Studio 16 2019" 35 | ARCH_ARG: "-A Win32" 36 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 37 | GENERATOR: "Visual Studio 16 2019" 38 | ARCH_ARG: "-A x64" 39 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 40 | GENERATOR: "Visual Studio 16 2019" 41 | ARCH_ARG: "-A ARM" 42 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 43 | GENERATOR: "Visual Studio 16 2019" 44 | ARCH_ARG: "-A ARM64" 45 | 46 | 47 | for: 48 | - 49 | matrix: 50 | only: 51 | - APPVEYOR_BUILD_WORKER_IMAGE: macos 52 | 53 | init: |- 54 | cmake --version 55 | build_script: |- 56 | echo macOS build script 57 | pwd 58 | mkdir build && cd build 59 | cmake -DCMAKE_BUILD_TYPE=Release .. 60 | make -j4 61 | 62 | - 63 | matrix: 64 | only: 65 | - APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu 66 | 67 | init: |- 68 | if [ "$cmake_arch" = "x86" ]; 69 | then 70 | export extra_cmake_flags=-DCMAKE_CXX_FLAGS=-m32; 71 | sudo apt-get update; 72 | sudo apt-get install -y g++-9-multilib; 73 | fi; 74 | cmake --version 75 | 76 | build_script: |- 77 | echo Ubuntu build script 78 | pwd 79 | mkdir build && cd build 80 | cmake -DCMAKE_BUILD_TYPE=Release $extra_cmake_flags .. 81 | make -j4 82 | 83 | - 84 | matrix: 85 | only: 86 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 87 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 88 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 89 | 90 | # dump environment variable for debug 91 | init: |- 92 | echo APPVEYOR_BUILD_WORKER_IMAGE: %APPVEYOR_BUILD_WORKER_IMAGE% 93 | echo cmake args: %ARCH_ARG% -G "%GENERATOR%" 94 | cmake --version 95 | 96 | before_build: |- 97 | mkdir build && cd build 98 | cmake .. %ARCH_ARG% -G "%GENERATOR%" 99 | 100 | build: 101 | project: c:\projects\yarpgen\build\YARPGen.sln 102 | verbosity: minimal 103 | parallel: true 104 | 105 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlines: Right 9 | AlignOperands: true 10 | AlignTrailingComments: true 11 | AllowAllParametersOfDeclarationOnNextLine: true 12 | AllowShortBlocksOnASingleLine: false 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: All 15 | AllowShortIfStatementsOnASingleLine: false 16 | AllowShortLoopsOnASingleLine: false 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: false 20 | AlwaysBreakTemplateDeclarations: MultiLine 21 | BinPackArguments: true 22 | BinPackParameters: true 23 | BraceWrapping: 24 | AfterClass: false 25 | AfterControlStatement: false 26 | AfterEnum: false 27 | AfterFunction: false 28 | AfterNamespace: false 29 | AfterObjCDeclaration: false 30 | AfterStruct: false 31 | AfterUnion: false 32 | AfterExternBlock: false 33 | BeforeCatch: false 34 | BeforeElse: true 35 | IndentBraces: false 36 | SplitEmptyFunction: true 37 | SplitEmptyRecord: true 38 | SplitEmptyNamespace: true 39 | BreakBeforeBinaryOperators: None 40 | BreakBeforeBraces: Custom 41 | BreakBeforeInheritanceComma: false 42 | BreakInheritanceList: BeforeColon 43 | BreakBeforeTernaryOperators: true 44 | BreakConstructorInitializersBeforeComma: false 45 | BreakConstructorInitializers: BeforeColon 46 | BreakAfterJavaFieldAnnotations: false 47 | BreakStringLiterals: true 48 | ColumnLimit: 80 49 | CommentPragmas: '^ IWYU pragma:' 50 | CompactNamespaces: false 51 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 52 | ConstructorInitializerIndentWidth: 4 53 | ContinuationIndentWidth: 4 54 | Cpp11BracedListStyle: true 55 | DerivePointerAlignment: false 56 | DisableFormat: false 57 | ExperimentalAutoDetectBinPacking: false 58 | FixNamespaceComments: true 59 | ForEachMacros: 60 | - foreach 61 | - Q_FOREACH 62 | - BOOST_FOREACH 63 | IncludeBlocks: Preserve 64 | IncludeCategories: 65 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 66 | Priority: 2 67 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 68 | Priority: 3 69 | - Regex: '.*' 70 | Priority: 1 71 | IncludeIsMainRegex: '(Test)?$' 72 | IndentCaseLabels: true 73 | IndentPPDirectives: None 74 | IndentWidth: 4 75 | IndentWrappedFunctionNames: false 76 | JavaScriptQuotes: Leave 77 | JavaScriptWrapImports: true 78 | KeepEmptyLinesAtTheStartOfBlocks: true 79 | MacroBlockBegin: '' 80 | MacroBlockEnd: '' 81 | MaxEmptyLinesToKeep: 1 82 | NamespaceIndentation: None 83 | ObjCBinPackProtocolList: Auto 84 | ObjCBlockIndentWidth: 2 85 | ObjCSpaceAfterProperty: false 86 | ObjCSpaceBeforeProtocolList: true 87 | PenaltyBreakAssignment: 2 88 | PenaltyBreakBeforeFirstCallParameter: 19 89 | PenaltyBreakComment: 300 90 | PenaltyBreakFirstLessLess: 120 91 | PenaltyBreakString: 1000 92 | PenaltyBreakTemplateDeclaration: 10 93 | PenaltyExcessCharacter: 1000000 94 | PenaltyReturnTypeOnItsOwnLine: 60 95 | PointerAlignment: Right 96 | ReflowComments: true 97 | SortIncludes: true 98 | SortUsingDeclarations: true 99 | SpaceAfterCStyleCast: false 100 | SpaceAfterTemplateKeyword: true 101 | SpaceBeforeAssignmentOperators: true 102 | SpaceBeforeCpp11BracedList: false 103 | SpaceBeforeCtorInitializerColon: true 104 | SpaceBeforeInheritanceColon: true 105 | SpaceBeforeParens: ControlStatements 106 | SpaceBeforeRangeBasedForLoopColon: true 107 | SpaceInEmptyParentheses: false 108 | SpacesBeforeTrailingComments: 1 109 | SpacesInAngles: false 110 | SpacesInContainerLiterals: true 111 | SpacesInCStyleCastParentheses: false 112 | SpacesInParentheses: false 113 | SpacesInSquareBrackets: false 114 | Standard: Cpp11 115 | StatementMacros: 116 | - Q_UNUSED 117 | - QT_REQUIRE_VERSION 118 | TabWidth: 4 119 | UseTab: Never 120 | ... 121 | 122 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2025, Intel Corporation 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | version: 2 5 | updates: 6 | # Maintain dependencies for GitHub Actions 7 | - package-ecosystem: "github-actions" 8 | directory: "/" 9 | schedule: 10 | interval: "weekly" 11 | commit-message: 12 | prefix: "ci:" 13 | open-pull-requests-limit: 1 14 | groups: 15 | ga-dependencies: 16 | applies-to: version-updates 17 | patterns: 18 | - "*" 19 | ignore: 20 | - dependency-name: "*" 21 | update-types: ["version-update:semver-patch"] # Ignore patch updates 22 | -------------------------------------------------------------------------------- /.github/workflows/c-cpp.yml: -------------------------------------------------------------------------------- 1 | name: Build YARPGen and generate sample tests 2 | 3 | on: [push, pull_request, workflow_dispatch] 4 | 5 | permissions: read-all 6 | 7 | jobs: 8 | build-and-run-lin: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v4 13 | - name: Check environment 14 | run: | 15 | cat /proc/cpuinfo 16 | - name: configure and build 17 | run: | 18 | mkdir build && cd build 19 | cmake -DCMAKE_BUILD_TYPE=Release .. 20 | make -j4 21 | - name: run tests 22 | run: | 23 | build/type_test 24 | build/data_test 25 | build/expr_test 26 | build/gen_test 27 | - name: generate cpp tests 28 | run: | 29 | mkdir tests-cpp && cd tests-cpp 30 | for i in {0..9} 31 | do 32 | mkdir $i && cd $i 33 | ../../build/yarpgen --std=c++ 34 | cd .. 35 | done 36 | - name: generate sycl tests 37 | run: | 38 | mkdir tests-sycl && cd tests-sycl 39 | for i in {0..9} 40 | do 41 | mkdir $i && cd $i 42 | ../../build/yarpgen --std=sycl 43 | cd .. 44 | done 45 | - name: generate ispc tests 46 | run: | 47 | mkdir tests-ispc && cd tests-ispc 48 | for i in {0..10} 49 | do 50 | mkdir $i && cd $i 51 | ../../build/yarpgen --std=ispc 52 | cd .. 53 | done 54 | - name: Upload cpp tests 55 | uses: actions/upload-artifact@v4 56 | with: 57 | name: tests-cpp-lin 58 | path: tests-cpp 59 | - name: Upload sycl tests 60 | uses: actions/upload-artifact@v4 61 | with: 62 | name: tests-sycl-lin 63 | path: tests-sycl 64 | - name: Upload ispc tests 65 | uses: actions/upload-artifact@v4 66 | with: 67 | name: tests-ispc-lin 68 | path: tests-ispc 69 | 70 | build-and-run-mac: 71 | runs-on: macos-latest 72 | 73 | steps: 74 | - uses: actions/checkout@v4 75 | - name: Check environment 76 | run: | 77 | sysctl -n machdep.cpu.brand_string 78 | - name: configure and build 79 | run: | 80 | mkdir build && cd build 81 | cmake -DCMAKE_BUILD_TYPE=Release .. 82 | make -j4 83 | - name: run tests 84 | run: | 85 | build/type_test 86 | build/data_test 87 | build/expr_test 88 | build/gen_test 89 | - name: generate cpp tests 90 | run: | 91 | mkdir tests-cpp && cd tests-cpp 92 | for i in {0..9} 93 | do 94 | mkdir $i && cd $i 95 | ../../build/yarpgen --std=c++ 96 | cd .. 97 | done 98 | - name: generate sycl tests 99 | run: | 100 | mkdir tests-sycl && cd tests-sycl 101 | for i in {0..9} 102 | do 103 | mkdir $i && cd $i 104 | ../../build/yarpgen --std=sycl 105 | cd .. 106 | done 107 | - name: generate ispc tests 108 | run: | 109 | mkdir tests-ispc && cd tests-ispc 110 | for i in {0..10} 111 | do 112 | mkdir $i && cd $i 113 | ../../build/yarpgen --std=ispc 114 | cd .. 115 | done 116 | - name: Upload cpp tests 117 | uses: actions/upload-artifact@v4 118 | with: 119 | name: tests-cpp-mac 120 | path: tests-cpp 121 | - name: Upload sycl tests 122 | uses: actions/upload-artifact@v4 123 | with: 124 | name: tests-sycl-mac 125 | path: tests-sycl 126 | - name: Upload ispc tests 127 | uses: actions/upload-artifact@v4 128 | with: 129 | name: tests-ispc-mac 130 | path: tests-ispc 131 | 132 | build-and-run-win: 133 | runs-on: windows-latest 134 | 135 | steps: 136 | - uses: actions/checkout@v4 137 | - name: Check environment 138 | shell: cmd 139 | run: | 140 | wmic cpu get caption, deviceid, name, numberofcores, maxclockspeed, status 141 | - name: configure and build 142 | shell: cmd 143 | run: | 144 | mkdir build 145 | cmake -B build -DCMAKE_BUILD_TYPE=Release . 146 | cmake --build build -j4 --config Release 147 | - name: run tests 148 | shell: cmd 149 | run: | 150 | cd build\Release 151 | type_test.exe 152 | data_test.exe 153 | expr_test.exe 154 | gen_test.exe 155 | - name: generate cpp tests 156 | shell: cmd 157 | run: | 158 | mkdir tests-cpp && cd tests-cpp 159 | ..\build\Release\yarpgen.exe --std=c++ 160 | - name: generate sycl tests 161 | shell: cmd 162 | run: | 163 | mkdir tests-sycl && cd tests-sycl 164 | ..\build\Release\yarpgen.exe --std=sycl 165 | - name: generate ispc tests 166 | shell: cmd 167 | run: | 168 | mkdir tests-ispc && cd tests-ispc 169 | ..\build\Release\yarpgen.exe --std=ispc 170 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *~ 3 | libyarpgen.a 4 | yarpgen 5 | objs 6 | res 7 | *.swp 8 | found/old-* 9 | check_isa 10 | Test_Makefile 11 | testing_log_* 12 | gen_test_makefile_log_* 13 | statistics_*.log 14 | csmith_statistics_*.log 15 | scripts/testing/process*/* 16 | scripts/testing/result/** 17 | 18 | !*/ 19 | .idea 20 | *.log 21 | .vs/ 22 | build/ 23 | out/ 24 | .DS_Store -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # Copyright (c) 2018-2020, Intel Corporation 4 | # Copyright (c) 2019-2020, University of Utah 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | ############################################################################### 19 | 20 | language: cpp 21 | 22 | jobs: 23 | include: 24 | - stage: check format 25 | os: linux 26 | dist: focal 27 | addons: 28 | apt: 29 | packages: 30 | - clang-format 31 | script: 32 | - ./check_format.sh clang-format-10 33 | 34 | - stage: build 35 | # Ubuntu 16.04, gcc 9 36 | os: linux 37 | dist: xenial 38 | addons: 39 | apt: 40 | sources: 41 | - ubuntu-toolchain-r-test 42 | packages: 43 | - g++-9 44 | env: 45 | - MATRIX_EVAL="CC=gcc-9 && CXX=g++-9" 46 | 47 | # Ubuntu 16.04, clang 8 48 | - os: linux 49 | dist: xenial 50 | addons: 51 | apt: 52 | sources: 53 | - llvm-toolchain-xenial-8 54 | packages: 55 | - clang-8 56 | env: 57 | - MATRIX_EVAL="CC=clang-8 && CXX=clang++-8" 58 | 59 | # Ubuntu 20.04, clang 8 60 | - os: linux 61 | dist: focal 62 | addons: 63 | apt: 64 | sources: 65 | - llvm-toolchain-focal-10 66 | packages: 67 | - clang-10 68 | env: 69 | - MATRIX_EVAL="CC=clang-10 && CXX=clang++-10" 70 | 71 | # OSX 72 | - os: osx 73 | osx_image: xcode9.4 74 | env: 75 | - MATRIX_EVAL="CC=clang && CXX=clang++" 76 | 77 | before_install: 78 | - eval "${MATRIX_EVAL}" 79 | 80 | script: 81 | - mkdir build; cd build 82 | - cmake -DCMAKE_BUILD_TYPE=Release .. 83 | - make -j2 84 | 85 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # Copyright (c) 2018-2020, Intel Corporation 4 | # Copyright (c) 2019-2020, University of Utah 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | ############################################################################### 19 | 20 | cmake_minimum_required(VERSION 3.6) 21 | project(YARPGen 22 | VERSION 2.0 23 | LANGUAGES CXX) 24 | 25 | STRING(TIMESTAMP BUILD_DATE "%Y:%m:%d") 26 | 27 | if(NOT CMAKE_BUILD_TYPE) 28 | set(CMAKE_BUILD_TYPE "Release") 29 | message(STATUS "Build type not specified: Use Release by default.") 30 | endif(NOT CMAKE_BUILD_TYPE) 31 | 32 | find_package(Git) 33 | set(GIT_HASH "no_version_info") 34 | if(GIT_FOUND) 35 | execute_process( 36 | COMMAND ${GIT_EXECUTABLE} log -1 --format=%h HEAD 37 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 38 | OUTPUT_VARIABLE GIT_HASH 39 | OUTPUT_STRIP_TRAILING_WHITESPACE 40 | ) 41 | endif() 42 | 43 | set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) 44 | 45 | add_subdirectory(src) 46 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2020, Intel Corporation 2 | Copyright (c) 2019-2020, University of Utah 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 | Copyrights and Licenses for Third Party Software Distributed with 18 | Yet Another Random Program Generator 19 | =========================================================================== 20 | 21 | Yet Another Random Program Generator incorporates code of hash function from 22 | the Boost library, which is covered by the following license: 23 | 24 | Boost Software License - Version 1.0 - August 17th, 2003 25 | 26 | Permission is hereby granted, free of charge, to any person or organization 27 | obtaining a copy of the software and accompanying documentation covered by 28 | this license (the "Software") to use, reproduce, display, distribute, 29 | execute, and transmit the Software, and to prepare derivative works of the 30 | Software, and to permit third-parties to whom the Software is furnished to 31 | do so, all subject to the following: 32 | 33 | The copyright notices in the Software and this entire statement, including 34 | the above license grant, this restriction and the following disclaimer, 35 | must be included in all copies of the Software, in whole or in part, and 36 | all derivative works of the Software, unless such copies or derivative 37 | works are solely in the form of machine-executable object code generated by 38 | a source language processor. 39 | 40 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 41 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 42 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 43 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 44 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 45 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 46 | DEALINGS IN THE SOFTWARE. 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Yet Another Random Program Generator 2 | ==================================== 3 | 4 | [![TravisCI build status (Linux and Mac)](https://travis-ci.org/intel/yarpgen.svg?branch=main)](https://travis-ci.org/intel/yarpgen) 5 | [![Appveyor build status (Windows and Ubuntu)](https://ci.appveyor.com/api/projects/status/meuyl409mtd4cljb/branch/main?svg=true)](https://ci.appveyor.com/project/webmasterintel/yarpgen/branch/main) 6 | [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](https://github.com/intel/yarpgen/blob/main/LICENSE.txt) 7 | 8 | ``yarpgen`` is a random program generator, which produces correct runnable C/C++ and DPC++(this work is in an early stage) programs. The generator is specifically designed to trigger compiler optimization bugs and is intended for compiler testing. 9 | 10 | A generated random program is guaranteed to be statically and dynamically correct program. This implies no undefined behavior, but allows for implementation defined behavior. 11 | 12 | Currently, there exist two versions of YARPGen: one is designed to test loops (it is under development and lives in the main branch), and the other one is designed to test scalar optimizations (it lives in [v1 branch](https://github.com/intel/yarpgen/tree/v1)). 13 | The information about YARPGen and loop version can be found in [this talk](https://youtu.be/Yyj2Fex9yEo) and [this paper](papers/yarpgen-pldi-2023.pdf), published at PLDI23. 14 | More information about scalar version can be found in [this talk](https://www.youtube.com/watch?v=mb9aRoXnicE) and [this paper](papers/yarpgen-ooplsa-2020.pdf), published at the OOPSLA 2020 and received an ACM SIGPLAN distinguished paper award. 15 | 16 | Each generated program consists of several files and after being compiled and run produces a decimal number, which is hash of all program global variable values. This number is supposed to be the same for all compilers and optimization levels. If the output differs for different compilers and/or optimization levels, you should have encountered a compiler bug. 17 | 18 | Several techniques are used to increase the probability of triggering compiler bugs: 19 | 20 | * all variable types, alignments and values / value ranges are known at the time of generation, which allows the accurate detection of undefined behavior and provides maximum variability of produced code. 21 | * the generation is random, but it is guided by a number of policies, which increase the likelihood of applying optimizations to the generated code. 22 | * in some cases a high level model of computations with known properties is generated first and then augmented with other random computations. This ensures that the code is "meaningful" and is more similar to code written by a human being. 23 | 24 | Compiler bugs found by YARP Generator 25 | ------------------------------------- 26 | 27 | ``yarpgen`` managed to find more than 260 bugs in [``gcc``](https://gcc.gnu.org/), [``clang``](https://clang.llvm.org/), [``ispc``](https://ispc.github.io/), [``dpc++``](https://software.intel.com/content/www/us/en/develop/tools/oneapi/components/dpc-compiler.html), [``sde``](https://software.intel.com/content/www/us/en/develop/articles/intel-software-development-emulator.html), [`alive2`](https://github.com/AliveToolkit/alive2) and a comparable number of bugs in 28 | proprietary compilers. For the list of the bugs in ``gcc``, ``clang``, ``ispc``, and ``alive2`` see [bugs.rst](bugs.rst). 29 | 30 | If you have used ``yarpgen`` to find bugs in open source compilers, please update bugs.rst. We are also excited to hear about your experience using it with proprietary compilers and other tools you might want to validate. 31 | 32 | Building and running 33 | -------------------- 34 | 35 | Building ``yarpgen`` is trivial. All you have to do is to use cmake: 36 | 37 | ```sh 38 | mkdir build 39 | cd build 40 | cmake .. 41 | make 42 | ``` 43 | 44 | To run ``yarpgen`` we recommend using [``run_gen.py``](scripts/run_gen.py) script, which will run the generator for you 45 | on a number of available compilers with a set of pre-defined options. Feel free to hack 46 | [``test_sets.txt``](scripts/test_sets.txt) to add or remove compiler options. 47 | 48 | The script will run several compilers with several compiler options and run executables to compare the output results. If the results mismatch, the test program will be saved in "testing/results" folder for your analysis. 49 | 50 | Also you may want to test compilers for future hardware, which is not available to you at the moment. The standard way to do that is to download the [Intel® Software Development Emulator](http://www.intel.com/software/sde). ``run_gen.py`` assumes that it is available in your ``$PATH``. 51 | 52 | ISPC testing 53 | ------------ 54 | 55 | If you want to test [ISPC](https://ispc.github.io/), make sure that it is present in your path, as well as 56 | [``ispc-proxy``](scripts/ispc-proxy) and [``ispc-disp``](scripts/ispc-disp). After that you can use 57 | [``run_gen.py``](scripts/run_gen.py) with ``--std=ispc`` as usual. 58 | 59 | Contacts 60 | -------- 61 | 62 | To contact authors, ask questions, or leave your feedback please use Github [issues](https://github.com/intel/yarpgen/issues) or reach out directly through contacts available in Github profiles. 63 | 64 | People 65 | ------ 66 | 67 | * Vsevolod Livinskii 68 | * Dmitry Babokin 69 | * John Regehr 70 | 71 | Special thanks to Martin Liška and Detlef Riekenberg who used YARPGen to find bugs in various compilers. 72 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | Intel is committed to rapidly addressing security vulnerabilities affecting 3 | our customers and providing clear guidance on the solution, impact, severity 4 | and mitigation. 5 | 6 | ## Reporting a Vulnerability 7 | Please report any security vulnerabilities in this project utilizing 8 | the guidelines [here](https://www.intel.com/content/www/us/en/security-center/vulnerability-handling-guidelines.html). 9 | -------------------------------------------------------------------------------- /check_format.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ############################################################################### 3 | # 4 | # Copyright (c) 2018-2020, Intel Corporation 5 | # Copyright (c) 2019-2020, University of Utah 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | ############################################################################### 20 | EXIT_CODE=0 21 | echo "\ 22 | ############################################################################ 23 | Checking formatting of modified files. It is expected that the files were 24 | formatted with clang-format 10.0.0. It is also expected that clang-format 25 | version 10.0.0 is used for the check. Otherwise the result can ne unexpected. 26 | ############################################################################" 27 | 28 | CLANG_FORMAT="clang-format" 29 | [[ ! -z $1 ]] && CLANG_FORMAT=$1 30 | REQUIRED_VERSION="10.0.0" 31 | VERSION_STRING="clang-format version $REQUIRED_VERSION.*" 32 | CURRENT_VERSION="$($CLANG_FORMAT --version)" 33 | if ! [[ $CURRENT_VERSION =~ $VERSION_STRING ]] ; then 34 | echo WARNING: clang-format version $REQUIRED_VERSION is required but $CURRENT_VERSION is used. 35 | echo The results can be unexpected. 36 | fi 37 | 38 | # Check all source files. 39 | FILES=`ls src/*.{h,cpp}` 40 | for FILE in $FILES; do 41 | $CLANG_FORMAT $FILE | cmp $FILE >/dev/null 42 | if [ $? -ne 0 ]; then 43 | echo "[!] INCORRECT FORMATTING! $FILE" >&2 44 | EXIT_CODE=1 45 | fi 46 | done 47 | if [ $EXIT_CODE -eq 0 ]; then 48 | echo "No formatting issues found" 49 | fi 50 | exit $EXIT_CODE 51 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | 3 | ENV TESTING_HOME=/testing 4 | 5 | ENV GCC_HOME=$TESTING_HOME/gcc 6 | ARG GCC_REPO=https://gcc.gnu.org/git/gcc.git 7 | ARG GCC_VERSION=master 8 | 9 | ENV LLVM_HOME=$TESTING_HOME/llvm 10 | ARG LLVM_REPO=https://github.com/llvm/llvm-project.git 11 | ARG LLVM_VERSION=main 12 | 13 | ARG SDE_REPO=https://downloadmirror.intel.com/751535 14 | ARG SDE_VERSION=sde-external-9.14.0-2022-10-25-lin 15 | 16 | ENV YARPGEN_HOME=$TESTING_HOME/yarpgen 17 | ARG YARPGEN_REPO=https://github.com/intel/yarpgen 18 | ARG YARPGEN_VERSION=main 19 | 20 | ENV BINUTILS_HOME=$TESTING_HOME/binutils 21 | ARG BINUTILS_REPO=https://sourceware.org/git/binutils-gdb.git 22 | 23 | ARG USER_AGENT="Mozilla/5.0" 24 | 25 | RUN apt-get -y update &&\ 26 | DEBIAN_FRONTEND=noninteractive apt-get install -y \ 27 | bison \ 28 | bzip2 \ 29 | cmake \ 30 | creduce \ 31 | curl \ 32 | flex \ 33 | gcc \ 34 | gcc-multilib \ 35 | g++ \ 36 | git \ 37 | libgmp-dev \ 38 | libmpfr-dev \ 39 | libz-dev \ 40 | ninja-build \ 41 | python3 \ 42 | texinfo \ 43 | wget \ 44 | xz-utils \ 45 | && rm -rf /var/lib/apt/lists/* 46 | 47 | WORKDIR $TESTING_HOME 48 | 49 | RUN git clone $YARPGEN_REPO $YARPGEN_HOME &&\ 50 | cd $YARPGEN_HOME &&\ 51 | git checkout $YARPGEN_VERSION 52 | 53 | RUN $YARPGEN_HOME/scripts/build_gcc.sh $GCC_REPO $GCC_VERSION 54 | 55 | # We want to test Sapphire Rapids target. The problem is that 56 | # the system default version of binutils doesn't support it yet. 57 | # Therefore, we have to build them by ourselves. 58 | # We should switch back to the system default version when it is updated. 59 | RUN $YARPGEN_HOME/scripts/build_binutils.sh $BINUTILS_REPO 60 | 61 | RUN $YARPGEN_HOME/scripts/build_llvm.sh $LLVM_REPO $LLVM_VERSION 62 | 63 | RUN wget -U $USER_AGENT --retry-connrefused --waitretry=5 --read-timeout=20 --timeout=15 -t 5 $SDE_REPO/$SDE_VERSION.tar.xz 64 | RUN tar -xf $SDE_VERSION.tar.xz 65 | ENV PATH=$TESTING_HOME/$SDE_VERSION:$PATH 66 | 67 | RUN $YARPGEN_HOME/scripts/build_yarpgen.sh 68 | 69 | ENV PATH=$GCC_HOME/bin_$GCC_VERSION/bin:$PATH 70 | ENV LD_LIBRARY_PATH=$GCC_HOME/bin_$GCC_VERSION/lib64/:$LD_LIBRARY_PATH 71 | 72 | ENV PATH=$BINUTILS_HOME/bin/bin:$PATH 73 | ENV LD_LIBRARY_PATH=$BINUTILS_HOME/bin/lib/:$LD_LIBRARY_PATH 74 | 75 | ENV PATH=$LLVM_HOME/bin_$LLVM_VERSION/bin/:$PATH 76 | ENV LD_LIBRARY_PATH=$LLVM_HOME/bin_$LLVM_VERSION/lib/:$LD_LIBRARY_PATH 77 | 78 | ARG RESULT_DIR 79 | ENV RESULT_DIR=${RESULT_DIR:-$TESTING_HOME/result} 80 | 81 | COPY docker-entrypoint.sh / 82 | # It is recommended to use a no-cache build, otherwise compiler won't be updated: 83 | # docker build --no-cache -t yarpgen-testing . 84 | # 85 | # Use this command to start a testing for 24-hours. 86 | # Feel free to change the parameters that are passed to run_gen.py 87 | # docker run --rm --name yarpgen-daily --mount source=yarpgen-result,target=/testing/result -e HOST_HOSTNAME=$(uname -n) yarpgen-testing -t 1440 88 | ENTRYPOINT ["/docker-entrypoint.sh"] 89 | CMD ["-t 1"] 90 | 91 | -------------------------------------------------------------------------------- /docker/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | is_result_mounted=`mount | grep "$RESULT_DIR"` 4 | if [ -z "is_result_mounted" ] 5 | then 6 | echo "Output directory for the result is not mounted, so we can't save the result" 7 | echo "If you want to fix that, add '--mount source=yarpgen-result,target=/testing/result' to docker run" 8 | cd $YARPGEN_HOME/scripts 9 | else 10 | # Create output dir 11 | # date-time format is the following: 20230123_1622 for 2023 Jan 23, 16:22. 12 | DATETIME=$(date '+%F_%H%M') 13 | OUT_DIR=$RESULT_DIR/$DATETIME-$HOST_HOSTNAME 14 | mkdir $OUT_DIR 15 | 16 | # Save revisions 17 | cp $GCC_HOME/gcc_rev.txt $OUT_DIR/gcc_rev.txt 18 | cp $LLVM_HOME/llvm_rev.txt $OUT_DIR/llvm_rev.txt 19 | cp $YARPGEN_HOME/yarpgen_rev.txt $OUT_DIR/yarpgen_rev.txt 20 | sde --version > $OUT_DIR/sde_version.txt 21 | 22 | # Test 23 | cd $YARPGEN_HOME/scripts 24 | nice -n 10 ./run_gen.py --output $OUT_DIR --log-file $OUT_DIR/log.txt $@ 25 | fi 26 | 27 | -------------------------------------------------------------------------------- /papers/yarpgen-ooplsa-2020.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/yarpgen/7dfc181a41f31a56e465287c8c6c76058564b478/papers/yarpgen-ooplsa-2020.pdf -------------------------------------------------------------------------------- /papers/yarpgen-pldi-2023.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/yarpgen/7dfc181a41f31a56e465287c8c6c76058564b478/papers/yarpgen-pldi-2023.pdf -------------------------------------------------------------------------------- /scripts/build_binutils.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # Args: BINUTILS_REPO 3 | 4 | if [[ -z "${BINUTILS_HOME}" ]]; then 5 | echo "Error! Environmental variable for BINUTILS_HOME is not set!" 6 | exit 127 7 | fi 8 | 9 | BINUTILS_REPO=$1 10 | 11 | if [[ -z "${BINUTILS_REPO}" ]]; then 12 | echo "Error! Parameters for BINUTILS repository are incorrect" 13 | exit 127 14 | fi 15 | 16 | mkdir -p $BINUTILS_HOME 17 | cd $BINUTILS_HOME 18 | # Get the source code 19 | git clone $BINUTILS_REPO binutils_src 20 | mkdir build bin 21 | cd $BINUTILS_HOME/binutils_src 22 | echo $BINUTILS_REPO > $BINUTILS_HOME/binutils_rev.txt 23 | git log --format="%H" -n 1 >> $BINUTILS_HOME/binutils_rev.txt 24 | 25 | # Pre-compilation steps 26 | cd $BINUTILS_HOME/build 27 | $BINUTILS_HOME/binutils_src/configure --prefix=$BINUTILS_HOME/bin 28 | 29 | # Compilation 30 | make -j `nrpoc` 31 | make -j `nproc` install 32 | 33 | # Cleanup 34 | rm -rf $BINUTILS_HOME/build $BINUTILS_HOME/binutils_src 35 | 36 | -------------------------------------------------------------------------------- /scripts/build_gcc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # Args: GCC_REPO GCC_VERSION 3 | 4 | if [[ -z "${GCC_HOME}" ]]; then 5 | echo "Error! Environmental variable for GCC_HOME is not set!" 6 | exit 127 7 | fi 8 | 9 | GCC_REPO=$1 10 | GCC_VERSION=$2 11 | 12 | if [[ -z "${GCC_REPO}" ]] || [[ -z "${GCC_VERSION}" ]]; then 13 | echo "Error! Parameters for GCC repository are incorrect" 14 | exit 127 15 | fi 16 | 17 | mkdir -p $GCC_HOME 18 | cd $GCC_HOME 19 | # Get the source code 20 | git clone $GCC_REPO gcc_src_$GCC_VERSION 21 | mkdir build_$GCC_VERSION bin_$GCC_VERSION 22 | cd $GCC_HOME/gcc_src_$GCC_VERSION 23 | git checkout $GCC_VERSION 24 | echo $GCC_REPO:$GCC_VERSION > $GCC_HOME/gcc_rev.txt 25 | git log --format="%H" -n 1 >> $GCC_HOME/gcc_rev.txt 26 | 27 | # Pre-compilation steps 28 | contrib/download_prerequisites 29 | # We can use the same script to build the compiler, but it uses bootstrap and it is hard to disable it 30 | contrib/gcc_build -d $GCC_HOME/gcc_src_$GCC_VERSION \ 31 | -o $GCC_HOME/build_$GCC_VERSION \ 32 | -c "--enable-multilib --prefix=$GCC_HOME/bin_$GCC_VERSION --disable-bootstrap" \ 33 | configure 34 | 35 | # Compilation 36 | cd $GCC_HOME/build_$GCC_VERSION 37 | make -j `nrpoc` 38 | make -j `nproc` install 39 | 40 | # Cleanup 41 | rm -rf $GCC_HOME/build_$GCC_VERSION $GCC_HOME/gcc_src_$GCC_VERSION 42 | 43 | -------------------------------------------------------------------------------- /scripts/build_llvm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # Args: LLVM_REPO LLVM_VERSION 3 | 4 | if [[ -z "${LLVM_HOME}" ]]; then 5 | echo "Error! Environmental variable for LLVM_HOME is not set!" 6 | exit 127 7 | fi 8 | 9 | LLVM_REPO=$1 10 | LLVM_VERSION=$2 11 | 12 | if [[ -z "${LLVM_REPO}" ]] || [[ -z "${LLVM_VERSION}" ]]; then 13 | echo "Error! Parameters for LLVM repository are incorrect" 14 | exit 127 15 | fi 16 | 17 | # Get the source code 18 | mkdir -p $LLVM_HOME 19 | cd $LLVM_HOME 20 | git clone $LLVM_REPO llvm_src_$LLVM_VERSION 21 | mkdir build_$LLVM_VERSION bin_$LLVM_VERSION 22 | cd $LLVM_HOME/llvm_src_$LLVM_VERSION 23 | git checkout $LLVM_VERSION 24 | echo $LLVM_REPO:$LLVM_VERSION > $LLVM_HOME/llvm_rev.txt 25 | git log --format="%H" -n 1 >> $LLVM_HOME/llvm_rev.txt 26 | 27 | # Pre-compilation steps 28 | cd $LLVM_HOME/build_$LLVM_VERSION 29 | cmake -G "Ninja" \ 30 | -DCMAKE_INSTALL_PREFIX=$LLVM_HOME/bin_$LLVM_VERSION \ 31 | -DCMAKE_BUILD_TYPE=Release \ 32 | -DLLVM_ENABLE_ASSERTIONS=ON \ 33 | -DLLVM_INSTALL_UTILS=ON \ 34 | -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ 35 | -DLLVM_TARGETS_TO_BUILD=X86 \ 36 | -DLLVM_ENABLE_PROJECTS="clang;compiler-rt;clang-tools-extra;polly" \ 37 | $LLVM_HOME/llvm_src_$LLVM_VERSION/llvm &&\ 38 | 39 | # Compile 40 | ninja install 41 | 42 | # Cleanup 43 | rm -rf $LLVM_HOME/build_$LLVM_VERSION $LLVM_HOME/llvm_src_$LLVM_VERSION 44 | 45 | -------------------------------------------------------------------------------- /scripts/build_yarpgen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | if [[ -z "${YARPGEN_HOME}" ]]; then 4 | echo "Error! Environmental variable for YARPGEN_HOME is not set!" 5 | exit 127 6 | fi 7 | 8 | cd $YARPGEN_HOME 9 | mkdir build 10 | git remote -v > $YARPGEN_HOME/yarpgen_rev.txt 11 | git log --format="%H" -n 1 >> $YARPGEN_HOME/yarpgen_rev.txt 12 | 13 | # Pre-compilation steps 14 | cd $YARPGEN_HOME/build 15 | cmake -G "Ninja" $YARPGEN_HOME 16 | 17 | # Compile 18 | ninja 19 | 20 | -------------------------------------------------------------------------------- /scripts/check_isa.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013-2023, Intel Corporation 3 | 4 | SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /////////////////////////////////////////////////////////////////////////////// 8 | // // 9 | // This file is a standalone program, which detects the best supported ISA. // 10 | // // 11 | /////////////////////////////////////////////////////////////////////////////// 12 | 13 | #include 14 | 15 | #if defined(_WIN32) || defined(_WIN64) 16 | #define HOST_IS_WINDOWS 17 | #include 18 | #elif defined(__APPLE__) 19 | #define HOST_IS_APPLE 20 | #endif 21 | 22 | #if !defined(HOST_IS_WINDOWS) 23 | static void __cpuid(int info[4], int infoType) { 24 | __asm__ __volatile__("cpuid" : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) : "0"(infoType)); 25 | } 26 | 27 | static void __cpuidex(int info[4], int level, int count) { 28 | __asm__ __volatile__("cpuid" : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) : "0"(level), "2"(count)); 29 | } 30 | #endif // !HOST_IS_WINDOWS 31 | 32 | static bool __os_has_avx_support() { 33 | #if defined(HOST_IS_WINDOWS) 34 | // Check if the OS will save the YMM registers 35 | unsigned long long xcrFeatureMask = _xgetbv(_XCR_XFEATURE_ENABLED_MASK); 36 | return (xcrFeatureMask & 6) == 6; 37 | #else // !defined(HOST_IS_WINDOWS) 38 | // Check xgetbv; this uses a .byte sequence instead of the instruction 39 | // directly because older assemblers do not include support for xgetbv and 40 | // there is no easy way to conditionally compile based on the assembler used. 41 | int rEAX, rEDX; 42 | __asm__ __volatile__(".byte 0x0f, 0x01, 0xd0" : "=a"(rEAX), "=d"(rEDX) : "c"(0)); 43 | return (rEAX & 6) == 6; 44 | #endif // !defined(HOST_IS_WINDOWS) 45 | } 46 | 47 | static bool __os_has_avx512_support() { 48 | #if defined(HOST_IS_WINDOWS) 49 | // Check if the OS saves the XMM, YMM and ZMM registers, i.e. it supports AVX2 and AVX512. 50 | // See section 2.1 of software.intel.com/sites/default/files/managed/0d/53/319433-022.pdf 51 | unsigned long long xcrFeatureMask = _xgetbv(_XCR_XFEATURE_ENABLED_MASK); 52 | return (xcrFeatureMask & 0xE6) == 0xE6; 53 | #elif defined(HOST_IS_APPLE) 54 | // macOS has different way of dealing with AVX512 than Windows and Linux: 55 | // - by default AVX512 is off in the newly created thread, which means CPUID flags will 56 | // indicate AVX512 availability, but OS support check (XCR0) will not succeed. 57 | // - AVX512 can be enabled either by calling thread_set_state() or by executing any 58 | // AVX512 instruction, which would cause #UD exception handled by the OS. 59 | // The purpose of this check is to identify if AVX512 is potentially available, so we 60 | // need to bypass OS check and look at CPUID flags only. 61 | // See ispc issue #1854 for more details. 62 | return true; 63 | #else // !defined(HOST_IS_WINDOWS) 64 | // Check xgetbv; this uses a .byte sequence instead of the instruction 65 | // directly because older assemblers do not include support for xgetbv and 66 | // there is no easy way to conditionally compile based on the assembler used. 67 | int rEAX, rEDX; 68 | __asm__ __volatile__(".byte 0x0f, 0x01, 0xd0" : "=a"(rEAX), "=d"(rEDX) : "c"(0)); 69 | return (rEAX & 0xE6) == 0xE6; 70 | #endif // !defined(HOST_IS_WINDOWS) 71 | } 72 | 73 | static const char *lGetSystemISA() { 74 | int info[4]; 75 | __cpuid(info, 1); 76 | 77 | int info2[4]; 78 | // Call cpuid with eax=7, ecx=0 79 | __cpuidex(info2, 7, 0); 80 | 81 | // clang-format off 82 | bool sse2 = (info[3] & (1 << 26)) != 0; 83 | bool sse41 = (info[2] & (1 << 19)) != 0; 84 | bool sse42 = (info[2] & (1 << 20)) != 0; 85 | bool avx_f16c = (info[2] & (1 << 29)) != 0; 86 | bool avx_rdrand = (info[2] & (1 << 30)) != 0; 87 | bool osxsave = (info[2] & (1 << 27)) != 0; 88 | bool avx = (info[2] & (1 << 28)) != 0; 89 | bool avx2 = (info2[1] & (1 << 5)) != 0; 90 | bool avx512_f = (info2[1] & (1 << 16)) != 0; 91 | // clang-format on 92 | 93 | if (osxsave && avx2 && avx512_f && __os_has_avx512_support()) { 94 | // We need to verify that AVX2 is also available, 95 | // as well as AVX512, because our targets are supposed 96 | // to use both. 97 | 98 | int info3[4] = {0, 0, 0, 0}; 99 | int max_subleaf = info2[0]; 100 | // Call cpuid with eax=7, ecx=1 101 | if (max_subleaf >= 1) 102 | __cpuidex(info3, 7, 1); 103 | 104 | // clang-format off 105 | bool avx512_dq = (info2[1] & (1 << 17)) != 0; 106 | bool avx512_pf = (info2[1] & (1 << 26)) != 0; 107 | bool avx512_er = (info2[1] & (1 << 27)) != 0; 108 | bool avx512_cd = (info2[1] & (1 << 28)) != 0; 109 | bool avx512_bw = (info2[1] & (1 << 30)) != 0; 110 | bool avx512_vl = (info2[1] & (1 << 31)) != 0; 111 | bool avx512_vbmi2 = (info2[2] & (1 << 6)) != 0; 112 | bool avx512_gfni = (info2[2] & (1 << 8)) != 0; 113 | bool avx512_vaes = (info2[2] & (1 << 9)) != 0; 114 | bool avx512_vpclmulqdq = (info2[2] & (1 << 10)) != 0; 115 | bool avx512_vnni = (info2[2] & (1 << 11)) != 0; 116 | bool avx512_bitalg = (info2[2] & (1 << 12)) != 0; 117 | bool avx512_vpopcntdq = (info2[2] & (1 << 14)) != 0; 118 | bool avx_vnni = (info3[0] & (1 << 4)) != 0; 119 | bool avx512_bf16 = (info3[0] & (1 << 5)) != 0; 120 | bool avx512_vp2intersect = (info2[3] & (1 << 8)) != 0; 121 | bool avx512_amx_bf16 = (info2[3] & (1 << 22)) != 0; 122 | bool avx512_amx_tile = (info2[3] & (1 << 24)) != 0; 123 | bool avx512_amx_int8 = (info2[3] & (1 << 25)) != 0; 124 | bool avx512_fp16 = (info2[3] & (1 << 23)) != 0; 125 | // clang-format on 126 | 127 | // Knights Landing: KNL = F + PF + ER + CD 128 | // Skylake server: SKX = F + DQ + CD + BW + VL 129 | // Cascade Lake server: CLX = SKX + VNNI 130 | // Cooper Lake server: CPX = CLX + BF16 131 | // Ice Lake client & server: ICL = CLX + VBMI2 + GFNI + VAES + VPCLMULQDQ + BITALG + VPOPCNTDQ 132 | // Tiger Lake: TGL = ICL + VP2INTERSECT 133 | // Sapphire Rapids: SPR = ICL + BF16 + AMX_BF16 + AMX_TILE + AMX_INT8 + AVX_VNNI + FP16 134 | bool knl = avx512_pf && avx512_er && avx512_cd; 135 | bool skx = avx512_dq && avx512_cd && avx512_bw && avx512_vl; 136 | bool clx = skx && avx512_vnni; 137 | bool cpx = clx && avx512_bf16; 138 | bool icl = 139 | clx && avx512_vbmi2 && avx512_gfni && avx512_vaes && avx512_vpclmulqdq && avx512_bitalg && avx512_vpopcntdq; 140 | bool tgl = icl && avx512_vp2intersect; 141 | bool spr = 142 | icl && avx512_bf16 && avx512_amx_bf16 && avx512_amx_tile && avx512_amx_int8 && avx_vnni && avx512_fp16; 143 | #pragma unused(cpx, tgl) 144 | if (spr) { 145 | return "spr"; // Sapphire Rapids 146 | } else if (skx) { 147 | return "skx"; // SkyLake Server 148 | } else if (knl) { 149 | return "knl"; // Knights Landing 150 | } 151 | // If it's unknown AVX512 target, fall through and use AVX2 152 | // or whatever is available in the machine. 153 | } 154 | 155 | if (osxsave && avx && __os_has_avx_support()) { 156 | // AVX1 for sure.... 157 | // Ivy Bridge? 158 | if (avx_f16c && avx_rdrand) { 159 | // So far, so good. AVX2? 160 | if (avx2) { 161 | return "hsw"; // AVX2 (codename Haswell) 162 | } else { 163 | return "ivb"; // AVX1.1 (codename Ivy Bridge) 164 | } 165 | } 166 | // Regular AVX 167 | return "snb"; // AVX (codename Sandy Bridge) 168 | } else if (sse42) { 169 | return "nhm"; // SSE 4.2 170 | } else if (sse41) { 171 | return "pnr"; // SSE 4.1 172 | } else if (sse2) { 173 | return "p4"; // SSE 2 174 | } else { 175 | return "Error"; 176 | } 177 | } 178 | 179 | int main() { 180 | const char *isa = lGetSystemISA(); 181 | printf("%s", isa); 182 | 183 | return 0; 184 | } 185 | -------------------------------------------------------------------------------- /scripts/collect_other_stats.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | ############################################################################### 3 | # 4 | # Copyright (c) 2017-2020, Intel Corporation 5 | # Copyright (c) 2019-2020, University of Utah 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | ############################################################################### 20 | """ 21 | Script for autonomous collect of different statistics from csmith. 22 | """ 23 | ############################################################################### 24 | 25 | import argparse 26 | import datetime 27 | import logging 28 | import multiprocessing 29 | import os 30 | import shutil 31 | import sys 32 | import time 33 | 34 | import common 35 | import gen_test_makefile 36 | import run_gen 37 | 38 | # We should init variable, so let's do it this way 39 | script_start_time = datetime.datetime.now() 40 | 41 | csmith_timeout = 30 42 | 43 | ############################################################################### 44 | 45 | 46 | def form_statistics(stat, prev_len, task_threads=None): 47 | verbose_stat_str = "" 48 | for i in gen_test_makefile.CompilerTarget.all_targets: 49 | if stat.is_stat_collected(i.name): 50 | verbose_stat_str += "\n=================================\n" 51 | verbose_stat_str += "Statistics for " + i.name + "\n" 52 | verbose_stat_str += "Optimization statistics: \n" 53 | verbose_stat_str += stat.get_stats(i.name, run_gen.StatsVault.opt_stats_id) + "\n\n" 54 | verbose_stat_str += "Statement statistics: \n" 55 | verbose_stat_str += stat.get_stats(i.name, run_gen.StatsVault.stmt_stats_id) + "\n" 56 | verbose_stat_str += "\n=================================\n" 57 | 58 | active = 0 59 | if task_threads: 60 | for task in task_threads: 61 | if task.is_alive(): 62 | active = active + 1 63 | 64 | stat_str = '\r' 65 | stat_str += "time " + run_gen.strfdelta(datetime.datetime.now() - script_start_time, 66 | "{days} d {hours}:{minutes}:{seconds}") + " | " 67 | stat_str += " active " + str(active) + " | " 68 | stat_str += "processed " + str(stat.get_yarpgen_runs(run_gen.ok)) 69 | 70 | spaces_needed = prev_len - len(stat_str) 71 | for i in range(spaces_needed): 72 | stat_str += " " 73 | prev_len = len(stat_str) 74 | 75 | return stat_str, verbose_stat_str, prev_len 76 | 77 | 78 | def print_statistics(stat, task_threads, num_jobs): 79 | any_alive = True 80 | prev_len = 0 81 | while any_alive: 82 | stat_str, verbose_stat_str, prev_len = form_statistics(stat, prev_len, task_threads) 83 | common.stat_logger.log(logging.INFO, verbose_stat_str) 84 | sys.stdout.write(stat_str) 85 | sys.stdout.flush() 86 | 87 | time.sleep(run_gen.stat_update_delay) 88 | 89 | any_alive = False 90 | for num in range(num_jobs): 91 | any_alive |= task_threads[num].is_alive() 92 | 93 | 94 | def prepare_and_start(work_dir, config_file, timeout, num_jobs, csmith_bin_path, csmith_runtime, csmith_args, optsets): 95 | common.check_dir_and_create(work_dir) 96 | 97 | # Check for binary of generator 98 | csmith_home = os.environ.get("CSMITH_HOME") 99 | if csmith_home is None: 100 | common.print_and_exit("Please set CSMITH_HOME environment variable") 101 | csmith_bin = os.path.abspath(csmith_home + os.sep + csmith_bin_path + os.sep + "csmith") 102 | common.check_and_copy(csmith_bin, work_dir) 103 | os.chdir(work_dir) 104 | ret_code, output, err_output, time_expired, elapsed_time = \ 105 | common.run_cmd(["." + os.sep + "csmith", "-v"], csmith_timeout, 0) 106 | csmith_version_str = str(output, "utf-8") 107 | # TODO: need to add some check, but I hope that it is safe 108 | common.log_msg(logging.DEBUG, "Csmith version: " + csmith_version_str) 109 | 110 | common.set_standard("c99") 111 | gen_test_makefile.set_standard() 112 | gen_test_makefile.parse_config(config_file) 113 | 114 | compiler_run_args = {} 115 | optsets_list = optsets.split() 116 | target_was_found = False 117 | failed_targets = [] 118 | for i in optsets_list: 119 | for target in gen_test_makefile.CompilerTarget.all_targets: 120 | if target.name != i: 121 | continue 122 | target_was_found = True 123 | common.log_msg(logging.DEBUG, "Trying to form compiler args for " + str(i)) 124 | run_str = target.specs.comp_c_name + " " 125 | run_str += target.args + " " 126 | if target.arch.comp_name != "": 127 | run_str += " " + target.specs.arch_prefix + target.arch.comp_name + " " 128 | run_str += gen_test_makefile.StatisticsOptions.get_options(target.specs) + " " 129 | run_str += csmith_runtime + " " 130 | common.log_msg(logging.DEBUG, "Formed compiler args: " + run_str) 131 | compiler_run_args[i] = run_str 132 | 133 | if not target_was_found: 134 | failed_targets.append(i) 135 | target_was_found = False 136 | 137 | if len(failed_targets) > 0: 138 | common.log_msg(logging.WARNING, "Can't find relevant target: " + str(failed_targets)) 139 | 140 | for i in range(num_jobs): 141 | common.check_dir_and_create(run_gen.process_dir + str(i)) 142 | 143 | manager_obj = run_gen.manager() 144 | stat = manager_obj.Statistics() 145 | 146 | start_time = time.time() 147 | end_time = start_time + timeout * 60 148 | if timeout == -1: 149 | end_time = -1 150 | 151 | task_threads = [0] * num_jobs 152 | for num in range(num_jobs): 153 | task_threads[num] = multiprocessing.Process(target=run_csmith, 154 | args=(num, csmith_args, compiler_run_args, end_time, stat)) 155 | task_threads[num].start() 156 | 157 | print_statistics(stat, task_threads, num_jobs) 158 | 159 | sys.stdout.write("\n") 160 | for i in range(num_jobs): 161 | common.log_msg(logging.DEBUG, "Removing " + run_gen.process_dir + str(i) + " dir") 162 | shutil.rmtree(run_gen.process_dir + str(i)) 163 | 164 | stat_str, verbose_stat_str, prev_len = form_statistics(stat, 0) 165 | sys.stdout.write(verbose_stat_str) 166 | sys.stdout.flush() 167 | 168 | 169 | def run_csmith(num, csmith_args, compiler_run_args, end_time, stat): 170 | common.log_msg(logging.DEBUG, "Job #" + str(num)) 171 | os.chdir(run_gen.process_dir + str(num)) 172 | work_dir = os.getcwd() 173 | inf = (end_time == -1) 174 | 175 | while inf or end_time > time.time(): 176 | if os.getcwd() != work_dir: 177 | raise 178 | common.clean_dir(".") 179 | 180 | ret_code, output, err_output, time_expired, elapsed_time = \ 181 | common.run_cmd([".." + os.sep + "csmith"] + csmith_args.split(), csmith_timeout, num) 182 | if ret_code != 0: 183 | continue 184 | test_file = open("func.c", "w") 185 | test_file.write(str(output, "utf-8")) 186 | test_file.close() 187 | for optset_name, compiler_run_arg in compiler_run_args.items(): 188 | ret_code, output, err_output, time_expired, elapsed_time = \ 189 | common.run_cmd(compiler_run_arg.split() + ["func.c"], run_gen.compiler_timeout, num) 190 | if ret_code != 0: 191 | continue 192 | 193 | opt_stats = None 194 | stmt_stats = None 195 | if "clang" in optset_name: 196 | opt_stats = run_gen.StatsParser.parse_clang_opt_stats_file("func.stats") 197 | stmt_stats = run_gen.StatsParser.parse_clang_stmt_stats_file(str(err_output, "utf-8")) 198 | stat.add_stats(opt_stats, optset_name, run_gen.StatsVault.opt_stats_id) 199 | stat.add_stats(stmt_stats, optset_name, run_gen.StatsVault.stmt_stats_id) 200 | stat.update_yarpgen_runs(run_gen.ok) 201 | 202 | 203 | 204 | ############################################################################### 205 | 206 | if __name__ == '__main__': 207 | if os.environ.get("YARPGEN_HOME") is None: 208 | sys.stderr.write("\nWarning: please set YARPGEN_HOME environment variable to point to yarpgen's directory," 209 | " using " + common.yarpgen_home + " for now\n") 210 | 211 | description = 'Script for autonomous collection of different statistics.' 212 | parser = argparse.ArgumentParser(description=description, formatter_class=argparse.ArgumentDefaultsHelpFormatter) 213 | parser.add_argument("--csmith-bin", dest="csmith_bin", default="", type=str, 214 | help="Relative path from $CSMITH_HOME to csmith binary") 215 | parser.add_argument("--csmith-runtime", dest="csmith_runtime", default="", type=str, 216 | help="Dependencies, required by csmith") 217 | parser.add_argument("--csmith-args", dest="csmith_args", default="", type=str, 218 | help="Arguments, directly passed to csmith") 219 | parser.add_argument("--optsets", dest="optsets", default="clang_opt", type=str, 220 | help="Targets for testing (see test_sets.txt).") 221 | parser.add_argument("--work-dir", dest="work_dir", default="collect_stats_dir", type=str, 222 | help="Directory, which is used for statistics' collection process.") 223 | parser.add_argument("-t", "--timeout", dest="timeout", type=int, default=1, 224 | help="Timeout for test system in minutes. -1 means infinity") 225 | parser.add_argument("-j", dest="num_jobs", default=multiprocessing.cpu_count(), type=int, 226 | help='Maximum number of instances to run in parallel. By default, it is set to' 227 | ' number of processor in your system') 228 | parser.add_argument("--config-file", dest="config_file", 229 | default=os.path.join(common.yarpgen_scripts, gen_test_makefile.default_test_sets_file_name), 230 | type=str, help="Configuration file for testing") 231 | parser.add_argument("--stat-log-file", dest="stat_log_file", default="csmith_statistics.log", type=str, 232 | help="Logfile for statistics") 233 | parser.add_argument("-v", "--verbose", dest="verbose", default=False, action="store_true", 234 | help="Increase output verbosity") 235 | args = parser.parse_args() 236 | 237 | log_level = logging.DEBUG if args.verbose else logging.INFO 238 | common.setup_logger(None, log_level) 239 | 240 | stat_log_file = common.wrap_log_file(args.stat_log_file, parser.get_default("stat_log_file")) 241 | common.setup_stat_logger(stat_log_file) 242 | 243 | script_start_time = datetime.datetime.now() 244 | common.log_msg(logging.DEBUG, "Command line: " + " ".join(str(p) for p in sys.argv)) 245 | common.log_msg(logging.DEBUG, "Start time: " + script_start_time.strftime('%Y/%m/%d %H:%M:%S')) 246 | common.check_python_version() 247 | 248 | prepare_and_start(work_dir=args.work_dir, timeout=args.timeout, num_jobs=args.num_jobs, config_file=args.config_file, 249 | csmith_bin_path=args.csmith_bin, csmith_runtime=args.csmith_runtime, csmith_args=args.csmith_args, 250 | optsets=args.optsets) 251 | -------------------------------------------------------------------------------- /scripts/common.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | ############################################################################### 3 | # 4 | # Copyright (c) 2015-2020, Intel Corporation 5 | # Copyright (c) 2019-2020, University of Utah 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | ############################################################################### 20 | """ 21 | File for common data and functions, which are used in scripts 22 | """ 23 | ############################################################################### 24 | import collections 25 | import datetime 26 | import enum 27 | import errno 28 | import logging 29 | import os 30 | import shutil 31 | import signal 32 | import subprocess 33 | import sys 34 | 35 | scripts_dir_name = "scripts" 36 | # $YARPGEN_HOME environment variable should be set to YARPGen directory 37 | yarpgen_home = os.environ["YARPGEN_HOME"] if "YARPGEN_HOME" in os.environ else os.getcwd() 38 | yarpgen_scripts = os.path.join(os.environ["YARPGEN_HOME"], scripts_dir_name) if "YARPGEN_HOME" in os.environ else os.path.dirname(__file__) 39 | yarpgen_version_str = "" 40 | 41 | main_logger_name = "main_logger" 42 | main_logger = None 43 | __duplicate_err_to_stderr__ = False 44 | 45 | stat_logger_name = "stat_logger" 46 | stat_logger = None 47 | 48 | 49 | @enum.unique 50 | class StdID(enum.IntEnum): 51 | # Better to use enum.auto, but it is available only since python3.6 52 | C = enum.auto() 53 | CXX = enum.auto() 54 | SYCL = enum.auto() 55 | ISPC = enum.auto() 56 | MAX_STD_ID = enum.auto() 57 | 58 | def is_c (self): 59 | return self.value == StdID.C 60 | 61 | def is_cxx (self): 62 | return self.value == StdID.CXX or \ 63 | self.value == StdID.SYCL or \ 64 | self.value == StdID.ISPC 65 | 66 | ''' Enum doesn't allow to use '++' in names, so we need this function. ''' 67 | @staticmethod 68 | def get_pretty_std_name (std_id): 69 | if std_id == StdID.CXX: 70 | return std_id.name.replace("CXX", "c++") 71 | return std_id.name.lower() 72 | 73 | ''' Enum doesn't allow to use '++' in names, so we need this function. ''' 74 | def get_full_pretty_std_name (self): 75 | if self.is_cxx(): 76 | return "c++11" 77 | return "c99" 78 | 79 | ''' Easy way to convert string to StdID ''' 80 | StrToStdID = collections.OrderedDict() 81 | for i in StdID: 82 | if not i.name.startswith("MAX"): 83 | StrToStdID[StdID.get_pretty_std_name(i)] = i 84 | 85 | selected_standard = None 86 | 87 | def get_file_ext(): 88 | if selected_standard.is_c(): 89 | return ".c" 90 | if selected_standard.is_cxx(): 91 | return ".cpp" 92 | return None 93 | 94 | def append_file_ext(file): 95 | if (file.startswith("func") and selected_standard == StdID.ISPC): 96 | return file + ".ispc" 97 | if selected_standard.is_c(): 98 | return file + ".c" 99 | if selected_standard.is_cxx(): 100 | return file + ".cpp" 101 | return None 102 | 103 | def set_standard(std_str): 104 | global selected_standard 105 | selected_standard = StrToStdID[std_str] 106 | 107 | def get_standard (): 108 | global selected_standard 109 | return StdID.get_pretty_std_name(selected_standard) 110 | 111 | def check_if_std_defined (): 112 | if selected_standard is None or \ 113 | selected_standard == StdID.MAX_STD_ID: 114 | print_and_exit("Language standard wasn't selected!") 115 | 116 | def print_and_exit(msg): 117 | log_msg(logging.ERROR, msg) 118 | exit(-1) 119 | 120 | 121 | def setup_logger(log_file, log_level): 122 | global main_logger 123 | main_logger = logging.getLogger(main_logger_name) 124 | formatter = logging.Formatter("%(asctime)s [%(levelname)-5.5s] %(message)s") 125 | main_logger.setLevel(log_level) 126 | 127 | if log_file is not None: 128 | file_handler = logging.FileHandler(log_file) 129 | file_handler.setFormatter(formatter) 130 | main_logger.addHandler(file_handler) 131 | global __duplicate_err_to_stderr__ 132 | __duplicate_err_to_stderr__ = True 133 | else: 134 | stream_handler = logging.StreamHandler() 135 | stream_handler.setFormatter(formatter) 136 | main_logger.addHandler(stream_handler) 137 | 138 | 139 | def wrap_log_file(log_file, default_log_file): 140 | if log_file == default_log_file: 141 | log_file = log_file.replace(".log", "") 142 | return log_file + "_" + datetime.datetime.now().strftime('%Y_%m_%d_%H_%M_%S') + ".log" 143 | else: 144 | return log_file 145 | 146 | 147 | def log_msg(log_level, message, forced_duplication = False): 148 | global main_logger 149 | main_logger.log(log_level, message) 150 | if __duplicate_err_to_stderr__ and (log_level == logging.ERROR or forced_duplication): 151 | sys.stderr.write("\n" + str(message) + "\n") 152 | sys.stderr.flush() 153 | 154 | 155 | class StatisticsFileHandler(logging.FileHandler): 156 | def emit(self, record): 157 | if self.stream is None: 158 | self.stream = self._open() 159 | logging.StreamHandler.emit(self, record) 160 | self.close() 161 | 162 | 163 | def setup_stat_logger(log_file): 164 | global stat_logger 165 | stat_logger = logging.getLogger(stat_logger_name) 166 | if log_file is not None: 167 | stat_handler = StatisticsFileHandler(filename=log_file, mode="w", delay=True) 168 | stat_logger.addHandler(stat_handler) 169 | stat_logger.setLevel(logging.INFO) 170 | 171 | 172 | def check_python_version(): 173 | if sys.version_info < (3, 3): 174 | print_and_exit("This script requires at least python 3.3.") 175 | 176 | 177 | def check_and_open_file(file_name, mode): 178 | norm_file_name = os.path.abspath(file_name) 179 | if not os.path.isfile(norm_file_name): 180 | print_and_exit("File " + norm_file_name + " doesn't exist and can't be opened") 181 | return open(norm_file_name, mode) 182 | 183 | 184 | def check_and_copy(src, dst): 185 | if not isinstance(src, str) or not isinstance(dst, str): 186 | print_and_exit("Src and dst should be strings") 187 | norm_src = os.path.abspath(src) 188 | norm_dst = os.path.abspath(dst) 189 | if os.path.exists(norm_src): 190 | log_msg(logging.DEBUG, "Copying " + norm_src + " to " + norm_dst) 191 | if os.path.isfile(norm_src): 192 | shutil.copy(norm_src, norm_dst) 193 | elif os.path.isdir(norm_src): 194 | # for directories, destination should be not the dir where it will be 195 | # copied to, but the new directory name. I.e. copying "abc" to ".." we 196 | # need to provide destination as "../abc". 197 | shutil.copytree(norm_src, norm_dst + os.sep + os.path.basename(src)) 198 | else: 199 | print_and_exit("Can't copy " + norm_src) 200 | else: 201 | print_and_exit("File " + norm_src + " wasn't found") 202 | 203 | 204 | def copy_test_to_out(test_dir, out_dir, lock): 205 | log_msg(logging.DEBUG, "Copying " + test_dir + " to " + out_dir) 206 | lock.acquire() 207 | try: 208 | shutil.copytree(test_dir, out_dir) 209 | except OSError as e: 210 | if e.errno == errno.EEXIST: 211 | pass 212 | else: 213 | raise 214 | finally: 215 | lock.release() 216 | 217 | 218 | def check_if_dir_exists(directory): 219 | norm_dir = os.path.abspath(directory) 220 | if not os.path.exists(norm_dir) or not os.path.isdir(norm_dir): 221 | return False 222 | return True 223 | 224 | 225 | def check_dir_and_create(directory): 226 | norm_dir = os.path.abspath(directory) 227 | if not os.path.exists(norm_dir): 228 | log_msg(logging.DEBUG, "Creating '" + str(norm_dir) + "' directory") 229 | os.makedirs(norm_dir) 230 | elif not os.path.isdir(norm_dir): 231 | print_and_exit("Can't use '" + norm_dir + "' directory") 232 | 233 | 234 | def run_cmd(cmd, time_out=None, num=-1, memory_limit=None): 235 | is_time_expired = False 236 | shell = False 237 | if memory_limit is not None: 238 | shell = True 239 | new_cmd = "ulimit -v " + str(memory_limit) + " ; " 240 | new_cmd += " ".join(i for i in cmd) 241 | cmd = new_cmd 242 | start_time = os.times() 243 | with subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, start_new_session=True, shell=shell) as process: 244 | try: 245 | log_msg_str = "Running " + str(cmd) 246 | if num != -1: 247 | log_msg_str += " in process " + str(num) 248 | if time_out is None: 249 | log_msg_str += " without timeout" 250 | else: 251 | log_msg_str += " with " + str(time_out) + " timeout" 252 | log_msg(logging.DEBUG, log_msg_str) 253 | output, err_output = process.communicate(timeout=time_out) 254 | ret_code = process.poll() 255 | except subprocess.TimeoutExpired: 256 | log_msg(logging.DEBUG, "Timeout triggered for proc num " + str(process.pid) + " sending kill signal to group") 257 | # Sigterm is good enough here and compared to sigkill gives a chance to the processes 258 | # to clean up after themselves. 259 | os.killpg(os.getpgid(process.pid), signal.SIGTERM) 260 | # once in a while stdout/stderr may not exist when the process is killed, so using try. 261 | try: 262 | output, err_output = process.communicate() 263 | except ValueError: 264 | output = b'' 265 | err_output = b'' 266 | log_msg(logging.DEBUG, "Process " + str(process.pid) + " has finally died") 267 | is_time_expired = True 268 | ret_code = None 269 | except: 270 | log_msg(logging.ERROR, str(cmd) + " failed: unknown exception (proc num "+ str(process.pid) + ")") 271 | # Something really bad is going on, so better to send sigkill 272 | os.killpg(os.getpgid(process.pid), signal.SIGKILL) 273 | process.wait() 274 | log_msg(logging.DEBUG, "Process " + str(process.pid) + " has finally died") 275 | raise 276 | end_time = os.times() 277 | elapsed_time = end_time.children_user - start_time.children_user + \ 278 | end_time.children_system - start_time.children_system 279 | return ret_code, output, err_output, is_time_expired, elapsed_time 280 | 281 | 282 | def if_exec_exist(program): 283 | def is_exe(file_path): 284 | return os.path.isfile(file_path) and os.access(file_path, os.X_OK) 285 | 286 | log_msg(logging.DEBUG, "Checking if " + str(program) + " exists") 287 | fpath, fname = os.path.split(program) 288 | if fpath: 289 | if is_exe(program): 290 | log_msg(logging.DEBUG, "Exec " + program + " was found at " + program) 291 | return True 292 | else: 293 | for path in os.environ["PATH"].split(os.pathsep): 294 | path = path.strip('"') 295 | exe_file = os.path.join(path, program) 296 | if is_exe(exe_file): 297 | log_msg(logging.DEBUG, "Exec " + program + " was found at " + exe_file) 298 | return True 299 | log_msg(logging.DEBUG, "Exec wasn't found") 300 | return False 301 | 302 | def clean_dir(path): 303 | for root, dirs, files in os.walk(path, topdown=False): 304 | for name in files: 305 | os.remove(os.path.join(root, name)) 306 | for name in dirs: 307 | os.rmdir(os.path.join(root, name)) 308 | -------------------------------------------------------------------------------- /scripts/ispc-disp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | ############################################################################### 3 | # 4 | # Copyright (c) 2020, Intel Corporation 5 | # Copyright (c) 2020, University of Utah 6 | # SPDX-License-Identifier: Apache-2.0 7 | # 8 | ############################################################################### 9 | # This script modifies passed arguments to provide a common interface for ispc 10 | # and clang. 11 | # It is a terrible work-around and we need to change it in the future. 12 | ############################################################################### 13 | 14 | import re 15 | import sys 16 | 17 | 18 | ispc_replacements = [('-c', ''), ('-std=c++11', '')] 19 | clang_replacements = [('-woff', '-w'), ('--pic', '-fPIC'), ('--mcmodel=large', '-mcmodel=large')] 20 | targ_replacements = [('sse\d', 'westmere'), 21 | ('avx1', 'sandybridge'), 22 | ('avx2', 'haswell'), 23 | ('avx512knl', 'knl'), 24 | ('avx512skx', '')] 25 | 26 | def replace_arg(arg, replacements): 27 | for repl in replacements: 28 | sig, new_arg = repl 29 | if arg == sig: 30 | return new_arg 31 | return arg 32 | 33 | def replace_targ(arg): 34 | march_arg, arch = arg.split('=') 35 | new_arg = "-march=" 36 | arch = arch.split('-')[0] 37 | for i in targ_replacements: 38 | arch = re.sub(i[0], i[1], arch) 39 | new_arg += arch 40 | return new_arg 41 | 42 | def process(args): 43 | is_clang = False 44 | if 'func.ispc' not in args: 45 | is_clang = True 46 | new_args = [] 47 | if not is_clang: 48 | new_args.append("ispc") 49 | for arg in args[1:]: 50 | new_args.append(replace_arg(arg, ispc_replacements)) 51 | else: 52 | new_args.append("clang++") 53 | for arg in args[1:]: 54 | if arg.startswith("--target"): 55 | new_args.append(replace_targ(arg)) 56 | else: 57 | 58 | new_args.append(replace_arg(arg, clang_replacements)) 59 | new_args = " ".join(new_args) 60 | print(new_args) 61 | 62 | 63 | if __name__ == '__main__': 64 | process(sys.argv) 65 | -------------------------------------------------------------------------------- /scripts/ispc-proxy: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ############################################################################### 3 | # 4 | # Copyright (c) 2020, Intel Corporation 5 | # Copyright (c) 2020, University of Utah 6 | # SPDX-License-Identifier: Apache-2.0 7 | # 8 | ############################################################################### 9 | # This script is supposed to provide a common interface for ispc and clang. 10 | # We have to do it because of the limitations of our current testing system, 11 | # so we need to redesign it in the future. 12 | ############################################################################### 13 | 14 | cmd=$(ispc-disp $@) 15 | ($cmd) 16 | exit $? 17 | -------------------------------------------------------------------------------- /scripts/rechecker.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | ############################################################################### 3 | # 4 | # Copyright (c) 2015-2020, Intel Corporation 5 | # Copyright (c) 2019-2020, University of Utah 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | ############################################################################### 20 | """ 21 | Script for rechecking of previously found errors 22 | """ 23 | ############################################################################### 24 | 25 | import argparse 26 | import logging 27 | import multiprocessing 28 | import os 29 | import sys 30 | import queue 31 | 32 | import common 33 | import gen_test_makefile 34 | import run_gen 35 | import blame_opt 36 | 37 | 38 | ############################################################################### 39 | 40 | def process_dir(directory, task_queue): 41 | common.log_msg(logging.DEBUG, "Searching for test directories in " + str(directory)) 42 | for root, dirs, files in os.walk(directory): 43 | for name in dirs: 44 | if name.startswith("S_"): 45 | common.log_msg(logging.DEBUG, "Adding " + str(os.path.join(root, name))) 46 | task_queue.put(os.path.join(root, name)) 47 | else: 48 | process_dir(os.path.join(root, name), task_queue) 49 | return task_queue 50 | 51 | 52 | def prepare_env_and_recheck(input_dir, out_dir, target, num_jobs, config_file): 53 | if not common.check_if_dir_exists(input_dir): 54 | common.print_and_exit("Can't use input directory") 55 | common.check_dir_and_create(out_dir) 56 | 57 | run_gen.gen_test_makefile_and_copy(out_dir, config_file) 58 | run_gen.dump_testing_sets(target) 59 | run_gen.print_compilers_version(target) 60 | 61 | lock = multiprocessing.Lock() 62 | 63 | task_queue = multiprocessing.JoinableQueue() 64 | process_dir(input_dir, task_queue) 65 | failed_queue = multiprocessing.SimpleQueue() 66 | passed_queue = multiprocessing.SimpleQueue() 67 | 68 | task_threads = [0] * num_jobs 69 | for num in range(num_jobs): 70 | task_threads[num] = \ 71 | multiprocessing.Process(target=recheck, 72 | args=(num, lock, task_queue, failed_queue, passed_queue, target, out_dir)) 73 | task_threads[num].start() 74 | 75 | task_queue.join() 76 | task_queue.close() 77 | 78 | for num in range(num_jobs): 79 | task_threads[num].join() 80 | 81 | 82 | def recheck(num, lock, task_queue, failed_queue, passed_queue, target, out_dir): 83 | common.log_msg(logging.DEBUG, "Started recheck. Process #" + str(num)) 84 | cwd_save = os.getcwd() 85 | abs_out_dir = os.path.join(cwd_save, out_dir) 86 | job_finished = False 87 | while not job_finished: 88 | try: 89 | test_dir = task_queue.get_nowait() 90 | task_queue.task_done() 91 | common.log_msg(logging.DEBUG, "#" + str(num) + " test directory: " + str(test_dir)) 92 | abs_test_dir = os.path.join(cwd_save, test_dir) 93 | common.check_and_copy(os.path.join(os.path.join(cwd_save, out_dir), gen_test_makefile.Test_Makefile_name), 94 | os.path.join(abs_test_dir, gen_test_makefile.Test_Makefile_name)) 95 | os.chdir(os.path.join(cwd_save, abs_test_dir)) 96 | 97 | valid_res = None 98 | out_res = set() 99 | prev_out_res_len = 1 # We can't check first result 100 | for i in gen_test_makefile.CompilerTarget.all_targets: 101 | if i.specs.name not in target.split(): 102 | continue 103 | 104 | common.log_msg(logging.DEBUG, "Re-checking target " + i.name) 105 | ret_code, output, err_output, time_expired, elapsed_time = \ 106 | common.run_cmd(["make", "-f", gen_test_makefile.Test_Makefile_name, i.name], 107 | run_gen.compiler_timeout, num) 108 | if time_expired or ret_code != 0: 109 | failed_queue.put(test_dir) 110 | common.log_msg(logging.DEBUG, "#" + str(num) + " Compilation failed") 111 | common.copy_test_to_out(abs_test_dir, os.path.join(abs_out_dir, test_dir), lock) 112 | break 113 | 114 | ret_code, output, err_output, time_expired, elapsed_time = \ 115 | common.run_cmd(["make", "-f", gen_test_makefile.Test_Makefile_name, "run_" + i.name], 116 | run_gen.run_timeout, num) 117 | if time_expired or ret_code != 0: 118 | failed_queue.put(test_dir) 119 | common.log_msg(logging.DEBUG, "#" + str(num) + " Execution failed") 120 | common.copy_test_to_out(abs_test_dir, os.path.join(abs_out_dir, test_dir), lock) 121 | break 122 | 123 | out_res.add(str(output, "utf-8").split()[-1]) 124 | if len(out_res) > prev_out_res_len: 125 | prev_out_res_len = len(out_res) 126 | failed_queue.put(test_dir) 127 | common.log_msg(logging.DEBUG, "#" + str(num) + " Out differs") 128 | if not blame_opt.prepare_env_and_blame(abs_test_dir, valid_res, i, abs_out_dir, lock, num): 129 | common.copy_test_to_out(abs_test_dir, os.path.join(abs_out_dir, test_dir), lock) 130 | break 131 | valid_res = str(output, "utf-8").split()[-1] 132 | 133 | passed_queue.put(test_dir) 134 | os.chdir(cwd_save) 135 | 136 | except queue.Empty: 137 | job_finished = True 138 | 139 | 140 | ############################################################################### 141 | 142 | if __name__ == '__main__': 143 | if os.environ.get("YARPGEN_HOME") is None: 144 | sys.stderr.write("\nWarning: please set YARPGEN_HOME environment variable to point to yarpgen's directory," 145 | "using " + common.yarpgen_home + " for now\n") 146 | 147 | description = 'Script for rechecking of compiler errors' 148 | parser = argparse.ArgumentParser(description=description, formatter_class=argparse.ArgumentDefaultsHelpFormatter) 149 | 150 | requiredNamed = parser.add_argument_group('required named arguments') 151 | requiredNamed.add_argument("-i", "--input-dir", dest="input_dir", type=str, required=True, 152 | help="Input directory for re-checking") 153 | 154 | parser.add_argument('--std', dest="std_str", default="c++11", type=str, 155 | help='Language standard. Possible variants are ' + str(list(gen_test_makefile.StrToStdId))[1:-1]) 156 | parser.add_argument("-o", "--output-dir", dest="out_dir", default="re-checked", type=str, 157 | help="Output directory with relevant fails") 158 | parser.add_argument("--config-file", dest="config_file", 159 | default=os.path.join(common.yarpgen_scripts, gen_test_makefile.default_test_sets_file_name), 160 | type=str, help="Configuration file for testing") 161 | parser.add_argument("--target", dest="target", default="clang ubsan_clang gcc", type=str, 162 | help="Targets for testing (see test_sets.txt). By default, possible variants are " 163 | "clang, ubsan and gcc (ubsan is a clang with sanitizer options).") 164 | parser.add_argument("-j", dest="num_jobs", default=multiprocessing.cpu_count(), type=int, 165 | help='Maximum number of instances to run in parallel. By default, ' 166 | 'it is set to number of processor in your system') 167 | parser.add_argument("-v", "--verbose", dest="verbose", default=False, action="store_true", 168 | help="Increase output verbosity") 169 | parser.add_argument("--log-file", dest="log_file", type=str, 170 | help="Logfile") 171 | args = parser.parse_args() 172 | 173 | log_level = logging.DEBUG if args.verbose else logging.INFO 174 | common.setup_logger(args.log_file, log_level) 175 | 176 | common.check_python_version() 177 | common.set_standard(args.std_str) 178 | gen_test_makefile.set_standard() 179 | prepare_env_and_recheck(args.input_dir, args.out_dir, args.target, args.num_jobs, args.config_file) 180 | -------------------------------------------------------------------------------- /scripts/test_sets.txt: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # Copyright (c) 2016-2023, Intel Corporation 4 | # Copyright (c) 2019-2020, University of Utah 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | ############################################################################### 19 | # README: 20 | # Testing configuration file 21 | # You can start single-line comment with #. Don't use indentation at the beginning of line! 22 | # Config can contain only one "Compiler specs" and "Testing sets" blocks! 23 | # You should always specify "Compiler specs" before "Testing sets"! 24 | ############################################################################### 25 | 26 | Compiler specs: 27 | # Spec name - codename for compiler and its options 28 | # Executable name - name of compiler binary file. It should be in your PATH 29 | # Common arguments - arguments which will be passed to every compiler run 30 | # Arch prefix - prefix for specifying different architectures (it will be concatenated with Compiler arch value) 31 | 32 | # Spec name | C++ executable name | C executable name | Common arguments | Arch prefix 33 | gcc | g++ | gcc | -fPIC -mcmodel=large -w -fpermissive | -march= 34 | clang | clang++ | clang | -fPIC -mcmodel=large -w -fopenmp-simd | -march= 35 | polly | clang++ | clang | -fPIC -mcmodel=large -w -fopenmp-simd -mllvm -polly -mllvm -polly-vectorizer=stripmine | -march= 36 | # Ubsan is clang or gcc with sanitizer options. It is used for generator check. 37 | # If you want to use sanitizer with -m32, please make sure that you pass "-rtlib=compiler-rt -lgcc_s" options if you are using clang. 38 | # Otherwise it may fail with "undefined reference to `__mulodi4'" error message. 39 | # See https://bugs.llvm.org//show_bug.cgi?id=16404 for more information 40 | # Note that -fpermissive option for gcc is required to allow reduction of ubsan_gcc fails. 41 | # Otherwise result of reduction is empty program. 42 | ubsan_clang | clang++ | clang | -fPIC -mcmodel=large -fsanitize=undefined -fno-sanitize-recover=undefined -Werror=uninitialized -Werror=implicitly-unsigned-literal | -march= 43 | ubsan_gcc | g++ | gcc | -fPIC -mcmodel=large -fsanitize=undefined -fno-sanitize-recover=undefined -Werror=uninitialized -fpermissive | -march= 44 | icc | icpc | icc | -fPIC -mcmodel=large -w | -x 45 | icx | icpx | icx | -fPIC -mcmodel=large -w -fopenmp-simd -mllvm -vec-threshold=0 | -march= 46 | dpcpp | clang++ | clang | -fsycl -w | -march= 47 | ispc | ispc-proxy | ispc-proxy | -woff --pic --mcmodel=large | --target= 48 | 49 | Testing sets: 50 | # Set name - codename for testing set 51 | # Spec name - codename of spec, it should be described in Compiler specs 52 | # Arguments - compiler options for this testing set 53 | # Compiler arch - architecture which will be passed to compiler 54 | # Sde arch - architecture which will be passed to SDE 55 | 56 | # Set name | Spec name | Arguments | Compiler arch | Sde arch 57 | ubsan_clang_o0 | ubsan_clang | -O0 | | 58 | #ubsan_clang_o2 | ubsan_clang | -O2 | | 59 | ubsan_gcc_o0 | ubsan_gcc | -O0 | | 60 | #ubsan_gcc_o2 | ubsan_gcc | -O2 | | 61 | 62 | gcc_no_opt | gcc | -O0 | | 63 | gcc_opt | gcc | -O3 | | 64 | #gcc_wsm_opt | gcc | -O3 | westmere | wsm 65 | #gcc_ivb_opt | gcc | -O3 | ivybridge | ivb 66 | #gcc_hsw_opt | gcc | -O3 | haswell | hsw 67 | #gcc_bdw_opt | gcc | -O3 | broadwell | bdw 68 | #gcc_knl_no_opt | gcc | -O0 | knl | knl 69 | #gcc_knl_opt | gcc | -O3 | knl | knl 70 | #gcc_skx_no_opt | gcc | -O0 | skylake-avx512 | skx 71 | gcc_skx_opt | gcc | -O3 | skylake-avx512 | skx 72 | #gcc_icx_no_opt | gcc | -O0 | icelake-server | icx 73 | #gcc_icx_opt | gcc | -O3 | icelake-server | icx 74 | #gcc_tgl_no_opt | gcc | -O0 | tigerlake | tgl 75 | #gcc_tgl_opt | gcc | -O3 | tigerlake | tgl 76 | #gcc_spr_no_opt | gcc | -O0 | sapphirerapids | spr 77 | gcc_spr_opt | gcc | -O3 | sapphirerapids | spr 78 | 79 | clang_no_opt | clang | -O0 | | 80 | clang_opt | clang | -O3 | | 81 | #clang_knl_no_opt | clang | -O0 | knl | knl 82 | #clang_knl_opt | clang | -O3 | knl | knl 83 | #clang_skx_no_opt | clang | -O0 | skx | skx 84 | clang_skx_opt | clang | -O3 | skx | skx 85 | #clang_icx_no_opt | clang | -O0 | icelake-server | icx 86 | #clang_icx_opt | clang | -O3 | icelake-server | icx 87 | #clang_tgl_no_opt | clang | -O0 | tigerlake | tgl 88 | #clang_tgl_opt | clang | -O3 | tigerlake | tgl 89 | #clang_spr_no_opt | clang | -O0 | sapphirerapids | spr 90 | clang_spr_opt | clang | -O3 | sapphirerapids | spr 91 | 92 | #polly_no_opt | polly | -O0 | | 93 | polly_opt | polly | -O3 | | 94 | #polly_knl_no_opt | polly | -O0 | knl | knl 95 | #polly_knl_opt | polly | -O3 | knl | knl 96 | #polly_skx_no_opt | polly | -O0 | skx | skx 97 | polly_skx_opt | polly | -O3 | skx | skx 98 | #polly_icx_no_opt | polly | -O0 | icelake-server | icx 99 | #polly_icx_opt | polly | -O3 | icelake-server | icx 100 | #polly_tgl_no_opt | polly | -O0 | tigerlake | tgl 101 | #polly_tgl_opt | polly | -O3 | tigerlake | tgl 102 | #polly_spr_no_opt | polly | -O0 | sapphirerapids | spr 103 | polly_spr_opt | polly | -O3 | sapphirerapids | spr 104 | 105 | icc_no_opt | icc | -O0 | | 106 | icc_opt | icc | -O3 | | 107 | #icc_knl_no_opt | icc | -O0 | MIC-AVX512 | knl 108 | #icc_knl_opt | icc | -O3 | MIC-AVX512 | knl 109 | #icc_skx_no_opt | icc | -O0 | CORE-AVX512 | skx 110 | #icc_skx_opt | icc | -O3 | CORE-AVX512 | skx 111 | 112 | icx_no_opt | icx | -O0 | | 113 | icx_opt | icx | -O3 | | 114 | #icx_skx_no_opt | icx | -O0 | skx | skx 115 | icx_skx_opt | icx | -O3 | skx | skx 116 | #icx_icx_no_opt | icx | -O0 | icelake-server | icx 117 | icx_icx_opt | icx | -O3 | icelake-server | icx 118 | #icx_tgl_no_opt | icx | -O0 | tigerlake | tgl 119 | #icx_tgl_opt | icx | -O3 | tigerlake | tgl 120 | 121 | #dpcpp_no_opt | dpcpp | -O0 | | 122 | #dpcpp_opt | dpcpp | -O3 | | 123 | 124 | dpcpp_cpu_no_opt | dpcpp | -O0 -DCPU | | 125 | dpcpp_cpu_opt | dpcpp | -O3 -DCPU | | 126 | 127 | dpcpp_gpu_no_opt | dpcpp | -O0 -DGPU | | 128 | dpcpp_gpu_opt | dpcpp | -O3 -DGPU | | 129 | 130 | ispc_sse_no_opt | ispc | -O0 | sse2-i32x4 | 131 | ispc_avx2_i32x8_opt | ispc | -O2 | avx2-i32x8 | 132 | ispc_avx2_i32x16_opt | ispc | -O2 | avx2-i32x16 | 133 | ispc_avx2_i64x4_opt | ispc | -O2 | avx2-i64x4 | 134 | ispc_avx512skx-i32x16_opt | ispc | -O2 | avx512skx-i32x16 | skx 135 | ispc_avx512skx-i8x64_opt | ispc | -O2 | avx512skx-i8x64 | skx 136 | ispc_avx512skx-i16x32_opt | ispc | -O2 | avx512skx-i16x32 | skx 137 | 138 | Options for statistics' capture: 139 | #Spec name | Arguments 140 | ubsan_clang | -save-stats -Xclang -print-stats 141 | clang | -save-stats -Xclang -print-stats 142 | -------------------------------------------------------------------------------- /scripts/tmp_cleaner.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ############################################################################### 3 | # 4 | # Copyright (c) 2015-2020, Intel Corporation 5 | # Copyright (c) 2019-2020, University of Utah 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | ############################################################################### 20 | 21 | current_user=`whoami` 22 | find /tmp -user $current_user -name "check*.cpp" -type f -mmin +60 -delete 23 | find /tmp -user $current_user -name "driver*.cpp" -type f -mmin +60 -delete 24 | find /tmp -user $current_user -name "driver*.o" -type f -mmin +60 -delete 25 | find /tmp -user $current_user -name "func*.cpp" -type f -mmin +60 -delete 26 | find /tmp -user $current_user -name "func*.sh" -type f -mmin +60 -delete 27 | find /tmp -user $current_user -name "f-*.sh" -type f -mmin +60 -delete 28 | find /tmp -user $current_user -name "hash*.cpp" -type f -mmin +60 -delete 29 | find /tmp -user $current_user -name "init*.cpp" -type f -mmin +60 -delete 30 | find /tmp -user $current_user -name "init*.sh" -type f -mmin +60 -delete 31 | find /tmp -user $current_user -name "iccdash*" -type f -mmin +60 -delete 32 | find /tmp -user $current_user -name "iccdummy*" -type f -mmin +60 -delete 33 | find /tmp -user $current_user -name "iccgccdash*" -type f -mmin +60 -delete 34 | find /tmp -user $current_user -name "icclibgcc*" -type f -mmin +60 -delete 35 | find /tmp -user $current_user -name "icpc*" -type f -mmin +60 -delete 36 | find /tmp -user $current_user -name "data.*" -type f -mmin +60 -delete 37 | find /tmp -user $current_user -name "creduce*" -type f -mmin +60 -delete 38 | find /tmp -user $current_user -name "tmp*" -type f -mmin +60 -delete 39 | find /tmp -user $current_user -name "cc*" -type f -mmin +60 -delete 40 | find /tmp -user $current_user -name "symbolizer*" -type f -mmin +60 -delete 41 | find /tmp -user $current_user -name "??????????" -type f -mmin +60 -delete 42 | echo "tmp_cleaner was run" >> cleaner.log 43 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # Copyright (c) 2019-2020, Intel Corporation 4 | # Copyright (c) 2019-2020, University of Utah 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | ############################################################################### 19 | 20 | set(LIB_SRCS 21 | "context.cpp" 22 | "context.h" 23 | "data.cpp" 24 | "data.h" 25 | "emit_policy.cpp" 26 | "emit_policy.h" 27 | "enums.h" 28 | "expr.cpp" 29 | "expr.h" 30 | "gen_policy.cpp" 31 | "gen_policy.h" 32 | "hash.cpp" 33 | "hash.h" 34 | "ir_node.h" 35 | "ir_value.cpp" 36 | "ir_value.h" 37 | "options.cpp" 38 | "options.h" 39 | "program.cpp" 40 | "program.h" 41 | "statistics.cpp" 42 | "statistics.h" 43 | "stmt.cpp" 44 | "stmt.h" 45 | "type.cpp" 46 | "type.h" 47 | "utils.cpp" 48 | "utils.h") 49 | 50 | # Common std and build flags for all executables 51 | set(STD cxx_std_17) 52 | set(FLAGS # $<$:/WX> 53 | $<$,$,$>:-Wall -Wpedantic -Werror> 54 | -DBUILD_VERSION="${GIT_HASH}" -DBUILD_DATE="${BUILD_DATE}" 55 | -DYARPGEN_VERSION_MAJOR="${PROJECT_VERSION_MAJOR}" -DYARPGEN_VERSION_MINOR="${PROJECT_VERSION_MINOR}") 56 | 57 | # Static library to avoid building sources multiple times 58 | add_library(yarpgen_lib STATIC ${LIB_SRCS}) 59 | target_compile_features(yarpgen_lib PRIVATE ${STD}) 60 | target_compile_options(yarpgen_lib PRIVATE ${FLAGS}) 61 | 62 | # Main executable 63 | add_executable(yarpgen main.cpp) 64 | target_compile_features(yarpgen PRIVATE ${STD}) 65 | target_compile_options(yarpgen PRIVATE ${FLAGS}) 66 | target_link_libraries(yarpgen yarpgen_lib) 67 | # Copy main executable next to scripts for convenience 68 | add_custom_command(TARGET yarpgen 69 | POST_BUILD 70 | COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_SOURCE_DIR}/scripts) 71 | 72 | # Test executables 73 | add_executable(type_test type_test.cpp) 74 | target_compile_features(type_test PRIVATE ${STD}) 75 | target_compile_options(type_test PRIVATE ${FLAGS}) 76 | target_link_libraries(type_test yarpgen_lib) 77 | 78 | add_executable(data_test data_test.cpp) 79 | target_compile_features(data_test PRIVATE ${STD}) 80 | target_compile_options(data_test PRIVATE ${FLAGS}) 81 | target_link_libraries(data_test yarpgen_lib) 82 | 83 | add_executable(expr_test expr_test.cpp) 84 | target_compile_features(expr_test PRIVATE ${STD}) 85 | target_compile_options(expr_test PRIVATE ${FLAGS}) 86 | target_link_libraries(expr_test yarpgen_lib) 87 | 88 | add_executable(gen_test gen_test.cpp) 89 | target_compile_features(gen_test PRIVATE ${STD}) 90 | target_compile_options(gen_test PRIVATE ${FLAGS}) 91 | target_link_libraries(gen_test yarpgen_lib) 92 | -------------------------------------------------------------------------------- /src/context.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019-2020, Intel Corporation 3 | Copyright (c) 2019-2020, University of Utah 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | */ 17 | 18 | ////////////////////////////////////////////////////////////////////////////// 19 | #include "context.h" 20 | 21 | #include 22 | 23 | using namespace yarpgen; 24 | 25 | std::shared_ptr EmitCtx::default_emit_ctx = 26 | std::make_shared(); 27 | 28 | PopulateCtx::PopulateCtx(std::shared_ptr _par_ctx) 29 | : PopulateCtx() { 30 | local_sym_tbl = std::make_shared(); 31 | if (_par_ctx.use_count() != 0) { 32 | par_ctx = _par_ctx; 33 | gen_policy = par_ctx->gen_policy; 34 | local_sym_tbl = 35 | std::make_shared(*(par_ctx->getLocalSymTable())); 36 | ext_inp_sym_tbl = par_ctx->ext_inp_sym_tbl; 37 | ext_out_sym_tbl = par_ctx->ext_out_sym_tbl; 38 | arith_depth = par_ctx->getArithDepth(); 39 | loop_depth = par_ctx->getLoopDepth(); 40 | taken = par_ctx->isTaken(); 41 | inside_foreach = par_ctx->isInsideForeach(); 42 | inside_mutation = par_ctx->isInsideMutation(); 43 | inside_omp_simd = par_ctx->inside_omp_simd; 44 | dims = par_ctx->dims; 45 | in_stencil = par_ctx->in_stencil; 46 | mul_vals_iter = par_ctx->mul_vals_iter; 47 | allow_mul_vals = par_ctx->allow_mul_vals; 48 | } 49 | } 50 | 51 | PopulateCtx::PopulateCtx() { 52 | par_ctx = nullptr; 53 | local_sym_tbl = std::make_shared(); 54 | ext_inp_sym_tbl = std::make_shared(); 55 | ext_out_sym_tbl = std::make_shared(); 56 | arith_depth = 0; 57 | taken = true; 58 | inside_mutation = false; 59 | inside_omp_simd = false; 60 | in_stencil = false; 61 | mul_vals_iter = nullptr; 62 | allow_mul_vals = false; 63 | } 64 | 65 | size_t PopulateCtx::generateNumberOfDims(ArrayDimsUseKind dims_use_kind) const { 66 | size_t ret = 0; 67 | if (dims_use_kind == ArrayDimsUseKind::SAME || 68 | (dims_use_kind == ArrayDimsUseKind::FEWER && dims.size() == 1)) 69 | ret = dims.size(); 70 | else if (dims_use_kind == ArrayDimsUseKind::FEWER && dims.size() > 1) 71 | ret = 72 | rand_val_gen->getRandValue(static_cast(1), dims.size() - 1); 73 | else if (dims_use_kind == ArrayDimsUseKind::MORE) { 74 | ret = rand_val_gen->getRandValue( 75 | dims.size() + 1, 76 | static_cast( 77 | std::ceil(dims.size() * gen_policy->arrays_dims_ext_factor))); 78 | } 79 | else 80 | ERROR("Unsupported case!"); 81 | return std::min(ret, gen_policy->array_dims_num_limit); 82 | } 83 | 84 | void SymbolTable::addArray(std::shared_ptr array) { 85 | arrays.push_back(array); 86 | assert(array->getType()->isArrayType() && 87 | "Array should have an array type"); 88 | auto array_type = std::static_pointer_cast(array->getType()); 89 | array_dim_map[array_type->getDimensions().size()].push_back(array); 90 | } 91 | 92 | std::vector> 93 | SymbolTable::getArraysWithDimNum(size_t dim) { 94 | auto find_res = array_dim_map.find(dim); 95 | if (find_res != array_dim_map.end()) 96 | return find_res->second; 97 | return {}; 98 | } 99 | -------------------------------------------------------------------------------- /src/context.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019-2020, Intel Corporation 3 | Copyright (c) 2019-2020, University of Utah 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | */ 17 | 18 | ////////////////////////////////////////////////////////////////////////////// 19 | 20 | #pragma once 21 | 22 | #include "data.h" 23 | #include "emit_policy.h" 24 | #include "expr.h" 25 | #include "gen_policy.h" 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | namespace yarpgen { 32 | 33 | // Class that is used to determine the evaluation context. 34 | // It allows us to evaluate the same arithmetic tree with different input 35 | // values. 36 | class EvalCtx { 37 | public: 38 | EvalCtx() 39 | : total_iter_num(-1), mul_vals_iter(nullptr), use_main_vals(true) {} 40 | // TODO: we use string as a unique identifier and it is not a right way to 41 | // do it 42 | std::map input; 43 | // The total number of iterations that we have to do 44 | // -1 is used as a poison value that indicates that the information is 45 | // unknown 46 | int64_t total_iter_num; 47 | 48 | // Iterator that is used to iterate over multiple values 49 | std::shared_ptr mul_vals_iter; 50 | // If true, we use main values for evaluation 51 | bool use_main_vals; 52 | }; 53 | 54 | class GenCtx { 55 | public: 56 | GenCtx() : loop_depth(0), if_else_depth(0), inside_foreach(false) { 57 | gen_policy = std::make_shared(); 58 | } 59 | void setGenPolicy(std::shared_ptr gen_pol) { 60 | gen_policy = std::move(gen_pol); 61 | } 62 | std::shared_ptr getGenPolicy() { return gen_policy; }; 63 | 64 | size_t getLoopDepth() { return loop_depth; } 65 | void incLoopDepth(size_t change) { loop_depth += change; } 66 | void decLoopDepth(size_t change) { loop_depth -= change; } 67 | size_t getIfElseDepth() { return if_else_depth; } 68 | void incIfElseDepth() { if_else_depth++; } 69 | void decIfElseDepth() { if_else_depth--; } 70 | 71 | void setInsideForeach(bool _inside) { inside_foreach = _inside; } 72 | bool isInsideForeach() { return inside_foreach; } 73 | 74 | protected: 75 | std::shared_ptr gen_policy; 76 | // Current loop depth 77 | size_t loop_depth; 78 | size_t if_else_depth; 79 | 80 | // ISPC 81 | bool inside_foreach; 82 | }; 83 | 84 | // Auxiliary class for stencil generation 85 | // It defines all parameters for each stencil element 86 | class ArrayStencilParams { 87 | public: 88 | explicit ArrayStencilParams(std::shared_ptr _arr) 89 | : arr(std::move(_arr)), dims_defined(false), offsets_defined(false), 90 | dims_order(SubscriptOrderKind::RANDOM) {} 91 | 92 | // We use an array of structures instead of a structure of arrays to keep 93 | // parameters of each dimension together 94 | // If parameter is not defined, it is set to false/nullptr/zero accordingly 95 | struct ArrayStencilDimParams { 96 | bool dim_active; 97 | // This is an absolute index of the iterator in context 98 | // We need to save this info to create special subscript expressions 99 | size_t abs_idx; 100 | std::shared_ptr iter; 101 | int64_t offset; 102 | 103 | ArrayStencilDimParams() 104 | : dim_active(false), abs_idx(0), iter(nullptr), offset(0) {} 105 | }; 106 | 107 | std::shared_ptr getArray() { return arr; } 108 | 109 | void setParams(std::vector _params, 110 | bool _dims_defined, bool _offsets_defined, 111 | SubscriptOrderKind _dims_order) { 112 | params = std::move(_params); 113 | dims_defined = _dims_defined; 114 | offsets_defined = _offsets_defined; 115 | dims_order = _dims_order; 116 | } 117 | 118 | std::vector &getParams() { return params; } 119 | 120 | bool areDimsDefined() const { return dims_defined; } 121 | bool areOffsetsDefined() const { return offsets_defined; } 122 | SubscriptOrderKind getDimsOrderKind() const { return dims_order; } 123 | 124 | private: 125 | std::shared_ptr arr; 126 | bool dims_defined; 127 | bool offsets_defined; 128 | SubscriptOrderKind dims_order; 129 | std::vector params; 130 | }; 131 | 132 | class SymbolTable { 133 | public: 134 | void addVar(std::shared_ptr var) { vars.push_back(var); } 135 | void addArray(std::shared_ptr array); 136 | void addIters(std::shared_ptr iter) { iters.push_back(iter); } 137 | void deleteLastIters() { iters.pop_back(); } 138 | 139 | std::vector> getVars() { return vars; } 140 | std::vector> getArrays() { return arrays; } 141 | std::vector> getArraysWithDimNum(size_t dim); 142 | std::vector> &getIters() { return iters; } 143 | 144 | void addVarExpr(std::shared_ptr var) { 145 | avail_vars.push_back(var); 146 | } 147 | 148 | std::vector> getAvailVars() { 149 | return avail_vars; 150 | } 151 | 152 | void setStencilsParams(std::vector _stencils) { 153 | stencils = _stencils; 154 | } 155 | std::vector &getStencilsParams() { return stencils; } 156 | 157 | private: 158 | std::vector> vars; 159 | std::vector> arrays; 160 | std::map>> array_dim_map; 161 | std::vector> iters; 162 | std::vector> avail_vars; 163 | std::vector stencils; 164 | }; 165 | 166 | // TODO: should we inherit it from Generation Context or should it be a separate 167 | // thing? 168 | class PopulateCtx : public GenCtx { 169 | public: 170 | PopulateCtx(); 171 | explicit PopulateCtx(std::shared_ptr ctx); 172 | 173 | std::shared_ptr getParentCtx() { return par_ctx; } 174 | 175 | std::shared_ptr getExtInpSymTable() { return ext_inp_sym_tbl; } 176 | std::shared_ptr getExtOutSymTable() { return ext_out_sym_tbl; } 177 | std::shared_ptr getLocalSymTable() { return local_sym_tbl; } 178 | void setExtInpSymTable(std::shared_ptr _sym_table) { 179 | ext_inp_sym_tbl = std::move(_sym_table); 180 | } 181 | void setExtOutSymTable(std::shared_ptr _sym_table) { 182 | ext_out_sym_tbl = std::move(_sym_table); 183 | } 184 | 185 | size_t getArithDepth() { return arith_depth; } 186 | void incArithDepth() { arith_depth++; } 187 | void decArithDepth() { arith_depth--; } 188 | 189 | bool isTaken() { return taken; } 190 | void setTaken(bool _taken) { taken = _taken; } 191 | 192 | bool isInsideMutation() { return inside_mutation; } 193 | void setIsInsideMutation(bool _val) { inside_mutation = _val; } 194 | 195 | void setInsideOMPSimd(bool val) { inside_omp_simd = val; } 196 | bool isInsideOMPSimd() { return inside_omp_simd; } 197 | 198 | size_t generateNumberOfDims(ArrayDimsUseKind dims_use_kind) const; 199 | void addDimension(size_t dim) { dims.push_back(dim); } 200 | std::vector getDimensions() { return dims; } 201 | void deleteLastDim() { dims.pop_back(); } 202 | 203 | void setInStencil(bool _val) { in_stencil = _val; } 204 | bool getInStencil() { return in_stencil; } 205 | 206 | void setMulValsIter(std::shared_ptr _iter) { 207 | mul_vals_iter = _iter; 208 | } 209 | std::shared_ptr getMulValsIter() { return mul_vals_iter; } 210 | 211 | void setAllowMulVals(bool _val) { allow_mul_vals = _val; } 212 | bool getAllowMulVals() { return allow_mul_vals; } 213 | 214 | private: 215 | std::shared_ptr par_ctx; 216 | std::shared_ptr ext_inp_sym_tbl; 217 | std::shared_ptr ext_out_sym_tbl; 218 | std::shared_ptr local_sym_tbl; 219 | size_t arith_depth; 220 | // If the test will actually execute the code 221 | bool taken; 222 | 223 | // This flag indicates if we are inside a region that we try to mutate 224 | bool inside_mutation; 225 | 226 | // As of now, the pragma omp simd is attached to a loop and can't be nested. 227 | // TODO: we need to think about pragma omp ordered simd 228 | bool inside_omp_simd; 229 | 230 | // Each loop header has a limit that any iterator should respect 231 | // For the simplicity, we assume that the limit is the same for all 232 | // iterators in the same loop nest. Different loop nests can have different 233 | // limits 234 | // TODO: We need to eliminate this constraint in the future 235 | // For now, we use vector with the same number in all elements to keep track 236 | // of the loop depth. This way, it will be easier to change the code in the 237 | // future 238 | std::vector dims; 239 | 240 | // This flag indicates if we are inside arithmetic tree generation for 241 | // stencil pattern 242 | bool in_stencil; 243 | 244 | // This iterator is used to operate with multiple values 245 | std::shared_ptr mul_vals_iter; 246 | // If we want to allow multiple values in this context 247 | bool allow_mul_vals; 248 | }; 249 | 250 | // TODO: maybe we need to inherit from some class 251 | class EmitCtx { 252 | public: 253 | // This is a hack. EmitPolicy is required to get a name of a variable. 254 | // Because we use a name of a variable as a unique ID, we end up creating 255 | // a lot of objects that are useless. 256 | // TODO: replace UID type of vars to something better 257 | static std::shared_ptr default_emit_ctx; 258 | 259 | EmitCtx() : ispc_types(false), sycl_access(false) { 260 | emit_policy = std::make_shared(); 261 | } 262 | std::shared_ptr getEmitPolicy() { return emit_policy; } 263 | 264 | void setIspcTypes(bool _val) { ispc_types = _val; } 265 | bool useIspcTypes() { return ispc_types; } 266 | 267 | void setSYCLAccess(bool _val) { sycl_access = _val; } 268 | bool useSYCLAccess() { return sycl_access; } 269 | 270 | void setSYCLPrefix(std::string _val) { sycl_prefix = std::move(_val); } 271 | std::string getSYCLPrefix() { return sycl_prefix; } 272 | 273 | private: 274 | std::shared_ptr emit_policy; 275 | bool ispc_types; 276 | bool sycl_access; 277 | std::string sycl_prefix; 278 | }; 279 | } // namespace yarpgen 280 | -------------------------------------------------------------------------------- /src/data.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015-2020, Intel Corporation 3 | Copyright (c) 2019-2020, University of Utah 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | */ 17 | 18 | ////////////////////////////////////////////////////////////////////////////// 19 | 20 | #pragma once 21 | 22 | #include "enums.h" 23 | #include "ir_value.h" 24 | #include "options.h" 25 | #include "type.h" 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace yarpgen { 32 | 33 | class GenCtx; 34 | class PopulateCtx; 35 | class EmitCtx; 36 | 37 | class Data { 38 | public: 39 | Data(std::string _name, std::shared_ptr _type) 40 | : name(std::move(_name)), type(std::move(_type)), 41 | ub_code(UBKind::Uninit), is_dead(true), alignment(0) {} 42 | virtual ~Data() = default; 43 | 44 | virtual std::string getName(std::shared_ptr ctx) { return name; } 45 | void setName(std::string _name) { name = std::move(_name); } 46 | std::shared_ptr getType() { return type; } 47 | 48 | UBKind getUBCode() { return ub_code; } 49 | void setUBCode(UBKind _ub) { ub_code = _ub; } 50 | bool hasUB() { return ub_code != UBKind::NoUB; } 51 | 52 | virtual bool isScalarVar() { return false; } 53 | virtual bool isArray() { return false; } 54 | virtual bool isIterator() { return false; } 55 | virtual bool isTypedData() { return false; } 56 | 57 | virtual DataKind getKind() { return DataKind::MAX_DATA_KIND; } 58 | 59 | virtual void dbgDump() = 0; 60 | 61 | virtual std::shared_ptr makeVarying() = 0; 62 | 63 | void setIsDead(bool val) { is_dead = val; } 64 | bool getIsDead() { return is_dead; } 65 | 66 | void setAlignment(size_t _alignment) { alignment = _alignment; } 67 | size_t getAlignment() { return alignment; } 68 | 69 | protected: 70 | template static std::shared_ptr makeVaryingImpl(T val) { 71 | auto ret = std::make_shared(val); 72 | ret->type = ret->getType()->makeVarying(); 73 | return ret; 74 | } 75 | 76 | std::string name; 77 | std::shared_ptr type; 78 | // It is not enough to have UB code just inside the IRValue. 79 | // E.g. if we go out of the array bounds of a multidimensional array, 80 | // we can't return IRValue and we need to indicate an error. 81 | UBKind ub_code; 82 | 83 | // Sometimes we create more variables than we use. 84 | // They create a lot of dead code in the test, so we need to prune them. 85 | bool is_dead; 86 | size_t alignment; 87 | }; 88 | 89 | // Shorthand to make it simpler 90 | using DataType = std::shared_ptr; 91 | 92 | // This class serves as a placeholder for one of the real data classes. 93 | // We propagate the type information before we propagate values. 94 | // One option is to separate type from the value and store both. This idea has 95 | // several downsides: 96 | // 1. The value already stores the type 97 | // 2. Type and data will be disjoint from each other, which can lead to 98 | // divergence and conflicts between them. 99 | // Current solution is to create a placeholder class that stores just the type. 100 | // It should be replaced with real data class after we start to propagate values 101 | class TypedData : public Data { 102 | public: 103 | explicit TypedData(std::shared_ptr _type) 104 | : Data("", std::move(_type)) {} 105 | bool isTypedData() final { return true; } 106 | DataType replaceWith(DataType _new_data); 107 | void dbgDump() final; 108 | std::shared_ptr makeVarying() override { 109 | return makeVaryingImpl(*this); 110 | }; 111 | }; 112 | 113 | class ScalarVar : public Data { 114 | public: 115 | ScalarVar(std::string _name, const std::shared_ptr &_type, 116 | IRValue _init_value) 117 | : Data(std::move(_name), _type), init_val(_init_value), 118 | cur_val(_init_value) { 119 | ub_code = init_val.getUBCode(); 120 | } 121 | bool isScalarVar() final { return true; } 122 | DataKind getKind() final { return DataKind::VAR; } 123 | 124 | std::string getName(std::shared_ptr ctx) override; 125 | 126 | IRValue getInitValue() { return init_val; } 127 | IRValue getCurrentValue() { return cur_val; } 128 | void setCurrentValue(IRValue _val) { 129 | cur_val = _val; 130 | ub_code = cur_val.getUBCode(); 131 | } 132 | 133 | void dbgDump() final; 134 | 135 | static std::shared_ptr create(std::shared_ptr ctx); 136 | 137 | std::shared_ptr makeVarying() override { 138 | return makeVaryingImpl(*this); 139 | }; 140 | 141 | private: 142 | IRValue init_val; 143 | IRValue cur_val; 144 | }; 145 | 146 | class Array : public Data { 147 | public: 148 | Array(std::string _name, const std::shared_ptr &_type, 149 | IRValue _val); 150 | IRValue getInitValues(bool use_main_vals) { 151 | return mul_vals_axis_idx == -1 || use_main_vals 152 | ? init_vals[Options::main_val_idx] 153 | : init_vals[Options::alt_val_idx]; 154 | } 155 | IRValue getCurrentValues(bool use_main_vals) { 156 | return mul_vals_axis_idx == -1 || use_main_vals 157 | ? cur_vals[Options::main_val_idx] 158 | : cur_vals[Options::alt_val_idx]; 159 | } 160 | void setInitValue(IRValue _val, bool use_main_vals, 161 | int64_t mul_val_axis_idx); 162 | void setCurrentValue(IRValue _val, bool use_main_vals); 163 | int64_t getMulValsAxisIdx() { return mul_vals_axis_idx; } 164 | 165 | bool isArray() final { return true; } 166 | DataKind getKind() final { return DataKind::ARR; } 167 | 168 | void dbgDump() final; 169 | static std::shared_ptr create(std::shared_ptr ctx, 170 | bool inp); 171 | 172 | std::shared_ptr makeVarying() override { 173 | return makeVaryingImpl(*this); 174 | }; 175 | 176 | private: 177 | // TODO: 178 | // We want elements of the array to have different values. 179 | // It is the only way to properly test masked instructions and optimizations 180 | // designed to work with them. 181 | // Each vector represents a "cluster" with different values that is "copied" 182 | // over the whole array. The size of the cluster should be smaller than the 183 | // typical target architecture vector size. This way we can cover 184 | // all of the interesting cases while preserving the simplicity of 185 | // the analysis. 186 | 187 | // Span of initialization value can always be determined from array 188 | // dimensions and current value span 189 | std::array init_vals; 190 | std::array cur_vals; 191 | // We use int64_t to use negative values as poison values that 192 | // indicate that the values are uniform 193 | int64_t mul_vals_axis_idx; 194 | }; 195 | 196 | class Expr; 197 | 198 | class Iterator : public Data { 199 | public: 200 | Iterator(std::string _name, std::shared_ptr _type, 201 | std::shared_ptr _start, size_t _max_left_offset, 202 | std::shared_ptr _end, size_t _max_right_offset, 203 | std::shared_ptr _step, bool _degenerate, 204 | size_t _total_iters_num) 205 | : Data(std::move(_name), std::move(_type)), start(std::move(_start)), 206 | max_left_offset(_max_left_offset), end(std::move(_end)), 207 | max_right_offset(_max_right_offset), step(std::move(_step)), 208 | degenerate(_degenerate), total_iters_num(_total_iters_num), 209 | supports_mul_values(false), main_vals_on_last_iter(true) {} 210 | 211 | bool isIterator() final { return true; } 212 | DataKind getKind() final { return DataKind::ITER; } 213 | 214 | std::shared_ptr getStart() { return start; } 215 | size_t getMaxLeftOffset() { return max_left_offset; } 216 | size_t getMaxRightOffset() { return max_right_offset; } 217 | std::shared_ptr getEnd() { return end; } 218 | std::shared_ptr getStep() { return step; } 219 | void setParameters(std::shared_ptr _start, std::shared_ptr _end, 220 | std::shared_ptr _step); 221 | bool isDegenerate() { return degenerate; } 222 | size_t getTotalItersNum() { return total_iters_num; } 223 | 224 | void setSupportsMulValues(bool _supports_mul_values) { 225 | supports_mul_values = _supports_mul_values; 226 | } 227 | bool getSupportsMulValues() { return supports_mul_values; } 228 | void setMainValsOnLastIter(bool _main_vals_on_last_iter) { 229 | main_vals_on_last_iter = _main_vals_on_last_iter; 230 | } 231 | bool getMainValsOnLastIter() { return main_vals_on_last_iter; } 232 | 233 | void dbgDump() final; 234 | 235 | static std::shared_ptr create(std::shared_ptr ctx, 236 | size_t _end_val, 237 | bool is_uniform = true); 238 | void populate(std::shared_ptr ctx); 239 | 240 | std::shared_ptr makeVarying() override { 241 | return makeVaryingImpl(*this); 242 | }; 243 | 244 | private: 245 | // TODO: should the expression contain full update on the iterator or only 246 | // the "meaningful" part? 247 | // For now we assume the latter, but it limits expressiveness 248 | std::shared_ptr start; 249 | size_t max_left_offset; 250 | std::shared_ptr end; 251 | size_t max_right_offset; 252 | std::shared_ptr step; 253 | bool degenerate; 254 | // Total number of iterations 255 | size_t total_iters_num; 256 | // A flag that indicates whether the iterator supports multiple values 257 | bool supports_mul_values; 258 | // A flag that indicates whether the iterator has main values on the last 259 | // iteration 260 | bool main_vals_on_last_iter; 261 | }; 262 | 263 | } // namespace yarpgen 264 | -------------------------------------------------------------------------------- /src/data_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019-2020, Intel Corporation 3 | Copyright (c) 2019-2020, University of Utah 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | */ 17 | 18 | ////////////////////////////////////////////////////////////////////////////// 19 | 20 | #include "context.h" 21 | #include "data.h" 22 | 23 | using namespace yarpgen; 24 | 25 | static const size_t MAX_DIMS = 4; 26 | static const size_t MAX_SIZE = 256; 27 | 28 | // Will be used to obtain a seed for the random number engine 29 | static std::random_device rd; 30 | static std::mt19937 generator; 31 | 32 | #define CHECK(cond, msg) \ 33 | do { \ 34 | if (!(cond)) { \ 35 | std::cerr << "ERROR at " << __FILE__ << ":" << __LINE__ \ 36 | << ", function " << __func__ << "():\n " << (msg) \ 37 | << std::endl; \ 38 | abort(); \ 39 | } \ 40 | } while (false) 41 | 42 | void scalarVarTest() { 43 | // Scalar Variable Test 44 | for (auto i = static_cast(IntTypeID::BOOL); 45 | i < static_cast(IntTypeID::MAX_INT_TYPE_ID); ++i) 46 | for (auto j = static_cast(CVQualifier::NONE); 47 | j <= static_cast(CVQualifier::CONST_VOLAT); ++j) 48 | for (int k = false; k <= true; ++k) { 49 | std::shared_ptr ptr_to_type = IntegralType::init( 50 | static_cast(i), static_cast(k), 51 | static_cast(j)); 52 | auto scalar_var = std::make_shared( 53 | std::to_string(i), ptr_to_type, ptr_to_type->getMin()); 54 | scalar_var->setCurrentValue(ptr_to_type->getMax()); 55 | 56 | CHECK(scalar_var->getName(std::make_shared()) == 57 | std::to_string(i), 58 | "Name"); 59 | CHECK(scalar_var->getType() == ptr_to_type, "Type"); 60 | CHECK(scalar_var->getUBCode() == 61 | ptr_to_type->getMin().getUBCode(), 62 | "UB Code"); 63 | CHECK(!scalar_var->hasUB(), "Has UB"); 64 | 65 | CHECK(scalar_var->isScalarVar(), "ScalarVar identity"); 66 | CHECK(scalar_var->getKind() == DataKind::VAR, "ScalarVar kind"); 67 | 68 | // Comparison operations are defined not for all types, so we 69 | // need cast trick 70 | IRValue init_val = 71 | scalar_var->getInitValue().castToType(IntTypeID::ULLONG); 72 | IRValue min_val = 73 | ptr_to_type->getMin().castToType(IntTypeID::ULLONG); 74 | IRValue cur_val = 75 | scalar_var->getCurrentValue().castToType(IntTypeID::ULLONG); 76 | IRValue max_val = 77 | ptr_to_type->getMax().castToType(IntTypeID::ULLONG); 78 | CHECK((init_val == min_val).getValueRef(), "Init Value"); 79 | CHECK((cur_val == max_val).getValueRef(), "CurrentValue"); 80 | CHECK(scalar_var->getIsDead(), "Is dead"); 81 | } 82 | } 83 | 84 | void arrayTest() { 85 | for (auto i = static_cast(IntTypeID::BOOL); 86 | i < static_cast(IntTypeID::MAX_INT_TYPE_ID); ++i) 87 | for (auto j = static_cast(CVQualifier::NONE); 88 | j <= static_cast(CVQualifier::CONST_VOLAT); ++j) 89 | for (int k = false; k <= true; ++k) { 90 | 91 | std::shared_ptr ptr_to_type = IntegralType::init( 92 | static_cast(i), static_cast(k), 93 | static_cast(j)); 94 | 95 | auto scalar_var = std::make_shared( 96 | std::to_string(i), ptr_to_type, ptr_to_type->getMin()); 97 | 98 | size_t dim_size = std::uniform_int_distribution( 99 | 1, MAX_DIMS)(generator); 100 | std::vector dims; 101 | dims.reserve(dim_size); 102 | for (size_t l = 0; l < dim_size; ++l) 103 | dims.push_back(std::uniform_int_distribution( 104 | 1, MAX_SIZE)(generator)); 105 | auto array_type = 106 | ArrayType::init(ptr_to_type, dims, static_cast(k), 107 | static_cast(k)); 108 | 109 | auto array = std::make_shared( 110 | std::to_string(i), array_type, ptr_to_type->getMin()); 111 | 112 | CHECK(array->getName(std::make_shared()) == 113 | std::to_string(i), 114 | "Name"); 115 | CHECK(array->getType() == array_type, "Type"); 116 | CHECK(array->getUBCode() == ptr_to_type->getMin().getUBCode(), 117 | "UB Code"); 118 | CHECK(!array->hasUB(), "Has UB"); 119 | 120 | CHECK(array->isArray(), "Array identity"); 121 | CHECK(array->getKind() == DataKind::ARR, "Array kind"); 122 | 123 | array->setCurrentValue(ptr_to_type->getMax(), 124 | Options::main_val_idx); 125 | 126 | CHECK( 127 | (array->getInitValues(Options::main_val_idx) 128 | .getAbsValue() == ptr_to_type->getMin().getAbsValue()), 129 | "Init Value"); 130 | CHECK( 131 | (array->getCurrentValues(Options::main_val_idx) 132 | .getAbsValue() == ptr_to_type->getMax().getAbsValue()), 133 | "CurrentValue"); 134 | CHECK(array->getIsDead(), "Is dead"); 135 | } 136 | } 137 | 138 | int main() { 139 | auto seed = rd(); 140 | std::cout << "Test seed: " << seed << std::endl; 141 | generator.seed(seed); 142 | 143 | scalarVarTest(); 144 | arrayTest(); 145 | // TODO: we need an iterator test, but it is better to add it after 146 | // expressions test 147 | } 148 | -------------------------------------------------------------------------------- /src/emit_policy.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020, Intel Corporation 3 | Copyright (c) 2020, University of Utah 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | ////////////////////////////////////////////////////////////////////////////// 17 | 18 | #include "emit_policy.h" 19 | 20 | using namespace yarpgen; 21 | 22 | EmitPolicy::EmitPolicy() { 23 | asserts_check_distr.emplace_back(Probability(true, 50)); 24 | asserts_check_distr.emplace_back(Probability(false, 50)); 25 | 26 | pass_as_param_distr.emplace_back(Probability(true, 50)); 27 | pass_as_param_distr.emplace_back(Probability(true, 50)); 28 | 29 | emit_align_attr_distr.emplace_back(Probability(true, 50)); 30 | emit_align_attr_distr.emplace_back(Probability(true, 50)); 31 | 32 | align_size_distr.emplace_back( 33 | Probability(AlignmentSize::A16, 33)); 34 | align_size_distr.emplace_back( 35 | Probability(AlignmentSize::A32, 33)); 36 | align_size_distr.emplace_back( 37 | Probability(AlignmentSize::A64, 33)); 38 | } 39 | -------------------------------------------------------------------------------- /src/emit_policy.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020, Intel Corporation 3 | Copyright (c) 2020, University of Utah 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | ////////////////////////////////////////////////////////////////////////////// 17 | 18 | #pragma once 19 | 20 | #include "enums.h" 21 | #include "utils.h" 22 | #include 23 | 24 | namespace yarpgen { 25 | 26 | class EmitPolicy { 27 | public: 28 | EmitPolicy(); 29 | 30 | std::vector> asserts_check_distr; 31 | std::vector> pass_as_param_distr; 32 | std::vector> emit_align_attr_distr; 33 | std::vector> align_size_distr; 34 | }; 35 | 36 | } // namespace yarpgen 37 | -------------------------------------------------------------------------------- /src/enums.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019-2020, Intel Corporation 3 | Copyright (c) 2019-2020, University of Utah 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | */ 17 | 18 | ////////////////////////////////////////////////////////////////////////////// 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | namespace yarpgen { 25 | 26 | // All possible Integral Types, used as a backend type 27 | enum class IntTypeID { 28 | BOOL, 29 | // We don't have "char" as a type, because its signedness is 30 | // implementation-defined 31 | SCHAR, 32 | UCHAR, 33 | SHORT, 34 | USHORT, 35 | INT, 36 | UINT, 37 | // We don't have any kind of "long" types, 38 | // because their real size depends on the architecture 39 | LLONG, 40 | ULLONG, 41 | MAX_INT_TYPE_ID 42 | }; 43 | 44 | enum class CVQualifier { 45 | NONE, 46 | CONST, 47 | VOLAT, 48 | CONST_VOLAT, 49 | }; 50 | 51 | // All possible cases of Undefined Behaviour. 52 | // For now we treat implementation-defined behaviour as undefined behaviour 53 | // TODO: do we want to allow implementation-defined behaviour? 54 | enum class UBKind { 55 | NoUB, 56 | Uninit, // Uninitialized 57 | // NullPtr, // nullptr ptr dereference 58 | SignOvf, // Signed overflow 59 | SignOvfMin, // Special case of signed overflow: INT_MIN * (-1) 60 | ZeroDiv, // FPE 61 | ShiftRhsNeg, // Shift by negative value 62 | ShiftRhsLarge, // Shift by large value 63 | NegShift, // Shift of negative value 64 | NoMemeber, // Can't find member of structure 65 | OutOfBounds, // Access out of the bounds 66 | MaxUB 67 | }; 68 | 69 | // This enum defines possible representation of array 70 | enum class ArrayKind { 71 | C_ARR, 72 | // PTR, 73 | STD_ARR, 74 | STD_VEC, 75 | VALARR, 76 | MAX_ARRAY_KIND 77 | }; 78 | 79 | enum class DataKind { VAR, ARR, ITER, MAX_DATA_KIND }; 80 | 81 | enum class IRNodeKind { 82 | CONST, 83 | SCALAR_VAR_USE, 84 | ITER_USE, 85 | ARRAY_USE, 86 | SUBSCRIPT, 87 | TYPE_CAST, 88 | ASSIGN, 89 | REDUCTION, 90 | UNARY, 91 | BINARY, 92 | TERNARY, 93 | CALL, 94 | MAX_EXPR_KIND, 95 | EXPR, 96 | DECL, 97 | BLOCK, 98 | SCOPE, 99 | LOOP_SEQ, 100 | LOOP_NEST, 101 | IF_ELSE, 102 | STUB, 103 | MAX_STMT_KIND, 104 | // Fake node kinds so we can use Probability mechanism 105 | STENCIL, 106 | }; 107 | 108 | enum class UnaryOp { PLUS, NEGATE, LOG_NOT, BIT_NOT, MAX_UN_OP }; 109 | 110 | enum class BinaryOp { 111 | ADD, 112 | SUB, 113 | MUL, 114 | DIV, 115 | MOD, 116 | LT, 117 | GT, 118 | LE, 119 | GE, 120 | EQ, 121 | NE, 122 | LOG_AND, 123 | LOG_OR, 124 | BIT_AND, 125 | BIT_OR, 126 | BIT_XOR, 127 | SHL, 128 | SHR, 129 | MAX_BIN_OP 130 | }; 131 | 132 | enum class LibCallKind { 133 | MIN, 134 | MAX, 135 | SELECT, 136 | ANY, 137 | ALL, 138 | NONE, 139 | RED_MIN, 140 | RED_MAX, 141 | RED_EQ, 142 | EXTRACT, 143 | MAX_LIB_CALL_KIND 144 | }; 145 | 146 | enum class LoopEndKind { CONST, VAR, EXPR, MAX_LOOP_KIND }; 147 | 148 | enum class OptionKind { 149 | HELP, 150 | VERSION, 151 | SEED, 152 | STD, 153 | INP_AS_ARGS, 154 | EMIT_ALIGN_ATTR, 155 | UNIQUE_ALIGN_SIZE, 156 | ALIGN_SIZE, 157 | ALLOW_DEAD_DATA, 158 | EMIT_PRAGMAS, 159 | OUT_DIR, 160 | PARAM_SHUFFLE, 161 | EXPL_LOOP_PARAM, 162 | CHECK_ALGO, 163 | MUTATE, 164 | MUTATION_SEED, 165 | UB_IN_DC, 166 | MAX_OPTION_ID 167 | }; 168 | 169 | enum class OptionLevel { NONE, SOME, ALL, MAX_OPTION_LEVEL }; 170 | 171 | enum class LangStd { C, CXX, ISPC, SYCL, MAX_LANG_STD }; 172 | 173 | enum class AlignmentSize { 174 | A16, 175 | A32, 176 | A64, 177 | MAX_ALIGNMENT_SIZE /*it is reserved to mean any of the above at random*/ 178 | }; 179 | 180 | enum class PragmaKind { 181 | CLANG_VECTORIZE, 182 | CLANG_INTERLEAVE, 183 | CLANG_VEC_PREDICATE, 184 | CLANG_UNROLL, 185 | OMP_SIMD, 186 | MAX_PRAGMA_KIND, 187 | }; 188 | 189 | // TODO: convert it to a bit-vector encoding 190 | enum class SimilarOperators { 191 | ADDITIVE, // +, - (unary and binary) 192 | BITWISE, // ~, &, |, ^ 193 | LOGIC, // !, &&, || 194 | MULTIPLICATIVE, // *, / and unary +, - 195 | BIT_SH, // ~, &, |, ^, >>, << 196 | ADD_MUL, // +, - (unary and binary) and *, / 197 | MAX_SIMILAR_OP // No limitations 198 | }; 199 | 200 | enum class ConstUse { 201 | HALF, // Half of the leaves are constants 202 | ALL, // All of the leaves are constants 203 | MAX_CONST_USE // No limitations 204 | }; 205 | 206 | enum class SpecialConst { 207 | ZERO, 208 | MIN, 209 | MAX, 210 | BIT_BLOCK, 211 | END_BITS, 212 | MAX_SPECIAL_CONST 213 | }; 214 | 215 | enum class CheckAlgo { HASH, ASSERTS, PRECOMPUTE, MAX_CHECK_ALGO }; 216 | 217 | enum class MutationKind { NONE, EXPRS, ALL, MAX_MUTATION_FIND }; 218 | 219 | // TODO: not all of the cases are supported yet 220 | enum class ArrayDimsUseKind { FEWER, SAME, MORE }; 221 | enum class ArrayDimsReuseKind { SAME, OFFSET, SCALE, COMBINE }; 222 | // TODO: add scale, combine, and swap (?) cases 223 | // And maybe combine repeat with offset somehow 224 | // REPEAT means that we repeat the iterator that we've used before. It also 225 | // conflicts with the dimensions in-order setting 226 | // SWAP means that we swap new iterator with one that we've used before. 227 | // The goal here is to alternate the order so we can generate something like 228 | // matrix multiplication 229 | enum class SubscriptKind { CONST, ITER, OFFSET, REPEAT }; 230 | // We need to make sure that we create special cases of array access patterns 231 | // These have a small probability of being generated, so we create special cases 232 | // to handle them. 233 | // RANDOM is used as a pseudo-poison value which indicates the general case 234 | // The generation for reverse is handled as in-order with reverse at the end of 235 | // the generation process 236 | // TODO: add swap to support almost in-order case? 237 | enum class SubscriptOrderKind { IN_ORDER, REVERSE, DIAGONAL, RANDOM }; 238 | } // namespace yarpgen 239 | -------------------------------------------------------------------------------- /src/expr_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019-2020, Intel Corporation 3 | Copyright (c) 2019-2020, University of Utah 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | */ 17 | 18 | ////////////////////////////////////////////////////////////////////////////// 19 | 20 | #include "data.h" 21 | #include "expr.h" 22 | 23 | using namespace yarpgen; 24 | 25 | int main() { 26 | IRValue start_val(IntTypeID::INT); 27 | start_val.setValue({false, 0}); 28 | auto start_expr = std::make_shared(start_val); 29 | 30 | IRValue end_val(IntTypeID::INT); 31 | end_val.setValue({false, 0}); 32 | auto end_expr = std::make_shared(end_val); 33 | } 34 | -------------------------------------------------------------------------------- /src/gen_policy.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015-2020, Intel Corporation 3 | Copyright (c) 2019-2020, University of Utah 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | ////////////////////////////////////////////////////////////////////////////// 17 | 18 | #pragma once 19 | 20 | #include "options.h" 21 | #include "utils.h" 22 | #include 23 | #include 24 | 25 | namespace yarpgen { 26 | 27 | // ISPC had problems with vector divisions in foreach loops if the iteration 28 | // space is not aligned with the vector size. This is a workaround for that 29 | // problem. YARPGen uses this parameter to determine the maximal vector size. 30 | constexpr size_t ISPC_MAX_VECTOR_SIZE = 64; 31 | // Some reduction operations are implemented via a straightforward loop. 32 | // In case of large iteration space, this loop can take a lot of time. 33 | // Therefore, we limit the maximal number of iterations for reduction 34 | constexpr size_t ITERATIONS_THRESHOLD_FOR_REDUCTION = 10000000; 35 | 36 | class GenPolicy { 37 | public: 38 | GenPolicy(); 39 | 40 | // Hard limit for total statements number 41 | size_t stmt_num_lim; 42 | 43 | // Maximal number of loops in a single LoopSequence 44 | size_t loop_seq_num_lim; 45 | // Distribution of loop numbers for a LoopSequence 46 | std::vector> loop_seq_num_distr; 47 | 48 | // Maximal depth of a single LoopNest 49 | size_t loop_nest_depth_lim; 50 | // Distribution of depths for a LoopNest 51 | std::vector> loop_nest_depth_distr; 52 | 53 | // Hard threshold for loop depth 54 | size_t loop_depth_limit; 55 | 56 | // Hard threshold for if-else depth 57 | size_t if_else_depth_limit; 58 | 59 | // Number of statements in a scope 60 | size_t scope_stmt_min_num; 61 | size_t scope_stmt_max_num; 62 | std::vector> scope_stmt_num_distr; 63 | 64 | // TODO: we want to replace constant parameters of iterators with something 65 | // smarter 66 | 67 | // End limits for iterators 68 | size_t iters_end_limit_min; 69 | size_t iter_end_limit_max; 70 | // ISPC has problems with division when foreach loop is not aligned with 71 | // vector size. Therefore, we limit the maximal vector size 72 | size_t ispc_iter_end_limit_max; 73 | 74 | // Step distribution for iterators 75 | std::vector> iters_step_distr; 76 | 77 | // Distribution of statements type for structure generation 78 | std::vector> stmt_kind_struct_distr; 79 | 80 | // Distribution of "else" branch in ifElseStmt 81 | std::vector> else_br_distr; 82 | 83 | // Distribution of statements type for population generation 84 | std::vector> expr_stmt_kind_pop_distr; 85 | 86 | // Distribution of available integral types 87 | std::vector> int_type_distr; 88 | 89 | // Number of external input variables 90 | size_t min_inp_vars_num; 91 | size_t max_inp_vars_num; 92 | 93 | // Number of new arrays that we create in each loop scope 94 | size_t min_new_arr_num; 95 | size_t max_new_arr_num; 96 | std::vector> new_arr_num_distr; 97 | 98 | // Output kind probability 99 | std::vector> out_kind_distr; 100 | 101 | // Maximal depth of arithmetic expression 102 | size_t max_arith_depth; 103 | // Distribution of nodes in arithmetic expression 104 | std::vector> arith_node_distr; 105 | // Unary operator distribution 106 | std::vector> unary_op_distr; 107 | // Binary operator distribution 108 | std::vector> binary_op_distr; 109 | 110 | std::vector> c_lib_call_distr; 111 | std::vector> cxx_lib_call_distr; 112 | std::vector> ispc_lib_call_distr; 113 | 114 | std::vector> reduction_as_bin_op_prob; 115 | std::vector> reduction_bin_op_distr; 116 | std::vector> reduction_as_lib_call_distr; 117 | 118 | static size_t leaves_prob_bump; 119 | 120 | std::vector> loop_end_kind_distr; 121 | 122 | std::vector> pragma_num_distr; 123 | std::vector> pragma_kind_distr; 124 | 125 | std::vector> mutation_probability; 126 | 127 | // ISPC 128 | // Probability to generate loop header as foreach or foreach_tiled 129 | std::vector> foreach_distr; 130 | 131 | std::vector> apply_similar_op_distr; 132 | std::vector> similar_op_distr; 133 | // This function overrides default distributions 134 | void chooseAndApplySimilarOp(); 135 | 136 | std::vector> apply_const_use_distr; 137 | std::vector> const_use_distr; 138 | // This function overrides default distributions 139 | void chooseAndApplyConstUse(); 140 | 141 | std::vector> use_special_const_distr; 142 | std::vector> special_const_distr; 143 | std::vector> use_lsb_bit_end_distr; 144 | std::vector> use_const_offset_distr; 145 | size_t max_offset; 146 | size_t min_offset; 147 | std::vector> const_offset_distr; 148 | std::vector> pos_const_offset_distr; 149 | static size_t const_buf_size; 150 | std::vector> replace_in_buf_distr; 151 | std::vector> reuse_const_prob; 152 | std::vector> use_const_transform_distr; 153 | std::vector> const_transform_distr; 154 | 155 | std::vector> allow_stencil_prob; 156 | size_t max_stencil_span = 4; 157 | std::vector> stencil_span_distr; 158 | std::vector> arrs_in_stencil_distr; 159 | // If we want to use same dimensions for all arrays 160 | std::vector> stencil_same_dims_all_distr; 161 | // If we want to use the same dimension for each array 162 | std::vector> stencil_same_dims_one_arr_distr; 163 | // If we want to use same offsets in the same dimensions for all arrays 164 | std::vector> stencil_same_offset_all_distr; 165 | // The number of dimensions used in stencil. Zero is used to indicate 166 | // a special case when we use all available dimensions 167 | std::vector> stencil_dim_num_distr; 168 | std::map>> stencil_in_dim_prob; 169 | double stencil_in_dim_prob_offset = 0.1; 170 | 171 | double stencil_prob_weight_alternation = 0.3; 172 | // Probability to leave UB in DeadCode when it is allowed 173 | std::vector> ub_in_dc_prob; 174 | 175 | // Probability to generate array with dims that are in natural order of 176 | // context 177 | std::vector> subs_order_kind_distr; 178 | std::vector> subs_kind_prob; 179 | std::vector> subs_diagonal_prob; 180 | 181 | // It determines the number of dimensions that array have in relation 182 | // to the current loop depth 183 | std::vector> array_dims_use_kind; 184 | 185 | // The factor that determines maximal array dimension for each context 186 | double arrays_dims_ext_factor = 1.3; 187 | // TODO: this seems like it doesn't work, so we will have to fix it 188 | size_t array_dims_num_limit; 189 | 190 | std::vector> use_iters_cache_prob; 191 | 192 | std::vector> same_iter_space; 193 | std::vector> same_iter_space_span; 194 | 195 | std::vector> array_with_mul_vals_prob; 196 | std::vector> loop_body_with_mul_vals_prob; 197 | 198 | std::vector> hide_zero_in_versioning_prob; 199 | 200 | std::vector> same_iter_space_span_distr; 201 | 202 | std::vector> vectorizable_loop_distr; 203 | void makeVectorizable(); 204 | 205 | private: 206 | template 207 | void uniformProbFromMax(std::vector> &distr, size_t max_num, 208 | size_t min_num = 0); 209 | template 210 | void removeProbability(std::vector> &orig, U id); 211 | 212 | SimilarOperators active_similar_op; 213 | ConstUse active_const_use; 214 | }; 215 | 216 | } // namespace yarpgen 217 | -------------------------------------------------------------------------------- /src/gen_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020, Intel Corporation 3 | Copyright (c) 2020, University of Utah 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | */ 17 | 18 | ////////////////////////////////////////////////////////////////////////////// 19 | 20 | #include "context.h" 21 | #include "stmt.h" 22 | 23 | #include 24 | 25 | using namespace yarpgen; 26 | 27 | int main() { 28 | rand_val_gen = std::make_shared(0); 29 | 30 | auto gen_ctx = std::make_shared(); 31 | auto scope_stmt = ScopeStmt::generateStructure(gen_ctx); 32 | auto emit_ctx = std::make_shared(); 33 | scope_stmt->emit(emit_ctx, std::cout); 34 | std::cout << std::endl; 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /src/hash.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019-2020, Intel Corporation 3 | Copyright (c) 2019-2020, University of Utah 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | */ 17 | 18 | ////////////////////////////////////////////////////////////////////////////// 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "enums.h" 25 | #include "hash.h" 26 | #include "type.h" 27 | #include "utils.h" 28 | 29 | using namespace yarpgen; 30 | 31 | IntTypeKey::IntTypeKey(IntTypeID _int_type_id, bool _is_static, 32 | CVQualifier _cv_qualifier, bool _is_uniform) 33 | : int_type_id(_int_type_id), is_static(_is_static), 34 | cv_qualifier(_cv_qualifier), is_uniform(_is_uniform) {} 35 | 36 | IntTypeKey::IntTypeKey(std::shared_ptr &item) { 37 | int_type_id = item->getIntTypeId(); 38 | is_static = item->getIsStatic(); 39 | cv_qualifier = item->getCVQualifier(); 40 | is_uniform = item->isUniform(); 41 | } 42 | 43 | bool IntTypeKey::operator==(const IntTypeKey &other) const { 44 | return (int_type_id == other.int_type_id) && 45 | (is_static == other.is_static) && 46 | (cv_qualifier == other.cv_qualifier) && 47 | (is_uniform == other.is_uniform); 48 | } 49 | 50 | std::size_t IntTypeKeyHasher::operator()(const IntTypeKey &key) const { 51 | Hash hash; 52 | hash(key.int_type_id); 53 | hash(key.is_static); 54 | hash(key.cv_qualifier); 55 | hash(key.is_uniform); 56 | return hash.getSeed(); 57 | } 58 | 59 | ArrayTypeKey::ArrayTypeKey(std::shared_ptr _base_type, 60 | std::vector _dims, ArrayKind _kind, 61 | bool _is_static, CVQualifier _cv_qual, 62 | bool _is_uniform) 63 | : base_type(std::move(_base_type)), dims(std::move(_dims)), kind(_kind), 64 | is_static(_is_static), cv_qualifier(_cv_qual), is_uniform(_is_uniform) {} 65 | 66 | bool ArrayTypeKey::operator==(const ArrayTypeKey &other) const { 67 | if (base_type != other.base_type) 68 | return false; 69 | 70 | if (base_type->isIntType()) { 71 | auto base_int_type = std::static_pointer_cast(base_type); 72 | auto other_int_type = 73 | std::static_pointer_cast(other.base_type); 74 | if (!IntegralType::isSame(base_int_type, other_int_type)) { 75 | return false; 76 | } 77 | } 78 | else { 79 | ERROR("Unsupported base type for array!"); 80 | } 81 | 82 | return (dims == other.dims) && (kind == other.kind) && 83 | (is_static == other.is_static) && 84 | (cv_qualifier == other.cv_qualifier) && 85 | (is_uniform == other.is_uniform); 86 | } 87 | 88 | std::size_t ArrayTypeKeyHasher::operator()(const ArrayTypeKey &key) const { 89 | Hash hash; 90 | 91 | if (key.base_type->isIntType()) { 92 | auto base_int_type = 93 | std::static_pointer_cast(key.base_type); 94 | IntTypeKeyHasher base_int_hasher; 95 | size_t base_int_hash = base_int_hasher(IntTypeKey(base_int_type)); 96 | hash(base_int_hash); 97 | } 98 | else { 99 | ERROR("Unsupported base type for array"); 100 | } 101 | 102 | hash(key.dims); 103 | hash(key.kind); 104 | hash(key.is_static); 105 | hash(key.cv_qualifier); 106 | hash(key.is_uniform); 107 | 108 | return hash.getSeed(); 109 | } 110 | -------------------------------------------------------------------------------- /src/hash.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019-2020, Intel Corporation 3 | Copyright (c) 2019-2020, University of Utah 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | */ 17 | 18 | ////////////////////////////////////////////////////////////////////////////// 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "enums.h" 27 | 28 | namespace yarpgen { 29 | 30 | const size_t HASH_SEED = 42; 31 | 32 | // Class that is used to calculate various hashes. 33 | // Right now it is used for folding sets of various types. 34 | class Hash { 35 | public: 36 | Hash() : seed(HASH_SEED) {} 37 | 38 | // TODO: we have a collisions. We need to think about better hash-functions 39 | template 40 | inline typename std::enable_if::value, void>::type 41 | operator()(T value) { 42 | hashCombine(std::hash()(value)); 43 | } 44 | 45 | // TODO we don't need separate template for enums, because C++ 14 allows to 46 | // pass them to std::hash. The issue here is that Ubuntu 16.04 doesn't 47 | // provide a library that supports that. When we switch to Ubuntu 18.04, we 48 | // can get rid of this function. 49 | template 50 | inline typename std::enable_if::value, void>::type 51 | operator()(T value) { 52 | static_assert( 53 | std::is_enum::value, 54 | "In current implementation we need to hash only enum type"); 55 | using enum_under_type = typename std::underlying_type::type; 56 | hashCombine( 57 | std::hash()(static_cast(value))); 58 | } 59 | 60 | template inline void operator()(std::vector value) { 61 | Hash hash; 62 | for (const auto &elem : value) 63 | hash(elem); 64 | hashCombine(hash.getSeed()); 65 | } 66 | 67 | size_t getSeed() { return seed; } 68 | 69 | private: 70 | // Combine existing seed with a new hash value. 71 | void hashCombine(size_t value) { 72 | seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2); 73 | } 74 | 75 | size_t seed; 76 | }; 77 | 78 | // We need a folding set for integral types. There is a fixed number of them. 79 | // Otherwise we will just waste too much memory, because almost every object in 80 | // IR has a type. This class is used as a key in the folding set. 81 | class IntegralType; 82 | 83 | class IntTypeKey { 84 | public: 85 | IntTypeKey(IntTypeID _int_type_id, bool _is_static, 86 | CVQualifier _cv_qualifier, bool _is_uniform); 87 | explicit IntTypeKey(std::shared_ptr &item); 88 | bool operator==(const IntTypeKey &other) const; 89 | 90 | IntTypeID int_type_id; 91 | bool is_static; 92 | CVQualifier cv_qualifier; 93 | bool is_uniform; 94 | }; 95 | 96 | // This class provides a hashing mechanism for folding set. 97 | class IntTypeKeyHasher { 98 | public: 99 | std::size_t operator()(const IntTypeKey &key) const; 100 | }; 101 | 102 | class Type; 103 | 104 | // This class is used as a key in the folding set. 105 | class ArrayTypeKey { 106 | public: 107 | ArrayTypeKey(std::shared_ptr _base_type, std::vector _dims, 108 | ArrayKind _kind, bool _is_static, CVQualifier _cv_qual, 109 | bool _is_uniform); 110 | bool operator==(const ArrayTypeKey &other) const; 111 | 112 | std::shared_ptr base_type; 113 | std::vector dims; 114 | ArrayKind kind; 115 | bool is_static; 116 | CVQualifier cv_qualifier; 117 | bool is_uniform; 118 | }; 119 | 120 | // This class provides a hashing mechanism for folding set. 121 | class ArrayTypeKeyHasher { 122 | public: 123 | std::size_t operator()(const ArrayTypeKey &key) const; 124 | }; 125 | } // namespace yarpgen 126 | -------------------------------------------------------------------------------- /src/ir_node.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015-2020, Intel Corporation 3 | Copyright (c) 2019-2020, University of Utah 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | */ 17 | 18 | ////////////////////////////////////////////////////////////////////////////// 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | namespace yarpgen { 25 | 26 | class EmitCtx; 27 | 28 | class IRNode { 29 | public: 30 | virtual ~IRNode() = default; 31 | // This method emits internal representation of the test to a contextual 32 | // form using recursive calls. The callee is responsible for all of the 33 | // wrapping (e.g., parentheses). The caller is obligated to handle the 34 | // offset properly. 35 | // TODO: in the future we might output the same test using different 36 | // language constructions 37 | virtual void emit(std::shared_ptr ctx, std::ostream &stream, 38 | std::string offset = "") = 0; 39 | // TODO: make it pure virtual later 40 | virtual void populate(std::shared_ptr ctx){}; 41 | }; 42 | 43 | } // namespace yarpgen 44 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015-2020, Intel Corporation 3 | Copyright (c) 2019-2020, University of Utah 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | */ 17 | 18 | ////////////////////////////////////////////////////////////////////////////// 19 | #include "options.h" 20 | #include "program.h" 21 | #include "utils.h" 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | using namespace yarpgen; 28 | 29 | int main(int argc, char *argv[]) { 30 | OptionParser::initOptions(); 31 | OptionParser::parse(argc, argv); 32 | 33 | Options &options = Options::getInstance(); 34 | rand_val_gen = std::make_shared(options.getSeed()); 35 | options.setSeed(rand_val_gen->getSeed()); 36 | 37 | if (options.getMutationKind() == MutationKind::EXPRS || 38 | options.getMutationKind() == MutationKind::ALL) { 39 | rand_val_gen->setMutationSeed(options.getMutationSeed()); 40 | } 41 | 42 | ProgramGenerator new_program; 43 | new_program.emit(); 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /src/options.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2017-2020, Intel Corporation 3 | Copyright (c) 2019-2020, University of Utah 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | */ 17 | 18 | ////////////////////////////////////////////////////////////////////////////// 19 | #pragma once 20 | 21 | #include "enums.h" 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace yarpgen { 32 | 33 | class OptionDescr { 34 | public: 35 | OptionDescr(OptionKind _kind, std::string _short_arg, std::string _long_arg, 36 | bool _has_value, std::string _help_msg, std::string _err_msg, 37 | std::function _action, std::string _def_val, 38 | std::vector _values) 39 | : kind(_kind), short_arg(std::move(_short_arg)), 40 | long_arg(std::move(_long_arg)), has_value(_has_value), 41 | help_msg(std::move(_help_msg)), err_msg(std::move(_err_msg)), 42 | action(std::move(_action)), def_val(std::move(_def_val)), 43 | values(std::move(_values)) {} 44 | OptionKind getKind() { return kind; } 45 | std::string getShortArg() { return short_arg; } 46 | std::string getLongArg() { return long_arg; } 47 | bool hasValue() { return has_value; } 48 | std::string getHelpMsg() { return help_msg; } 49 | std::string getErrMsg() { return err_msg; } 50 | std::function getAction() { return action; } 51 | std::string getDefaultVal() { return def_val; } 52 | std::vector getAvailVals() { return values; } 53 | 54 | private: 55 | OptionKind kind; 56 | std::string short_arg; 57 | std::string long_arg; 58 | bool has_value; 59 | std::string help_msg; 60 | std::string err_msg; 61 | std::function action; 62 | std::string def_val; 63 | std::vector values; 64 | }; 65 | 66 | class Options; 67 | 68 | class OptionParser { 69 | public: 70 | static void parse(size_t argc, char *argv[]); 71 | // Initialize options with default values 72 | static void initOptions(); 73 | 74 | static std::vector options_set; 75 | 76 | private: 77 | static void printVersion(std::string arg); 78 | static void printHelpAndExit(std::string error_msg = ""); 79 | static bool optionStartsWith(char *option, const char *test); 80 | static bool parseShortArg(size_t argc, size_t &argv_iter, char **&argv, 81 | OptionDescr &option); 82 | static bool parseLongArg(size_t &argv_iter, char **&argv, 83 | OptionDescr &option); 84 | static bool parseLongAndShortArgs(size_t argc, size_t &argv_iter, 85 | char **&argv, OptionDescr &option); 86 | 87 | static void parseSeed(std::string seed_str); 88 | static void parseStandard(std::string std); 89 | static void parseCheckAlgo(std::string val); 90 | static void parseInpAsArgs(std::string val); 91 | static void parseEmitAlignAttr(std::string val); 92 | static void parseUniqueAlignSize(std::string val); 93 | static void parseAlignSize(std::string val); 94 | static void parseAllowDeadData(std::string val); 95 | static void parseEmitPragmas(std::string val); 96 | static void parseOutDir(std::string val); 97 | static void parseUseParamShuffle(std::string val); 98 | static void parseExplLoopParams(std::string val); 99 | static void parseMutationKind(std::string mutate_str); 100 | static void parseMutationSeed(std::string mutation_seed_str); 101 | static void parseAllowUBInDC(std::string allow_ub_in_dc_str); 102 | }; 103 | 104 | class Options { 105 | public: 106 | // The number of divergent values that we support in loops 107 | // In theory, it can be made higher, but we assume that 2 is enough 108 | // for now. The agreement that main values are tied to the 0-th index 109 | static size_t constexpr vals_number = 2; 110 | static size_t constexpr main_val_idx = 0; 111 | static size_t constexpr alt_val_idx = 1; 112 | 113 | static Options &getInstance() { 114 | static Options instance; 115 | return instance; 116 | } 117 | Options(const Options &options) = delete; 118 | Options &operator=(const Options &) = delete; 119 | 120 | void setRawOptions(size_t argc, char *argv[]); 121 | 122 | void setSeed(uint64_t _seed) { seed = _seed; } 123 | uint64_t getSeed() { return seed; } 124 | 125 | void setLangStd(LangStd _std) { std = _std; } 126 | LangStd getLangStd() { return std; } 127 | bool isC() { return std == LangStd::C; } 128 | bool isCXX() { return std == LangStd::CXX; } 129 | bool isISPC() { return std == LangStd::ISPC; } 130 | bool isSYCL() { return std == LangStd::SYCL; } 131 | 132 | void setCheckAlgo(CheckAlgo val) { check_algo = val; } 133 | CheckAlgo getCheckAlgo() { return check_algo; } 134 | 135 | void setInpAsArgs(OptionLevel val) { inp_as_args = val; } 136 | OptionLevel inpAsArgs() { return inp_as_args; } 137 | 138 | void setEmitAlignAttr(OptionLevel _val) { emit_align_attr = _val; } 139 | OptionLevel getEmitAlignAttr() { return emit_align_attr; } 140 | 141 | void setUniqueAlignSize(bool _val) { unique_align_size = _val; } 142 | bool getUniqueAlignSize() { return unique_align_size; } 143 | 144 | void setAlignSize(AlignmentSize _val) { align_size = _val; } 145 | AlignmentSize getAlignSize() { return align_size; } 146 | 147 | void setAllowDeadData(bool val) { allow_dead_data = val; } 148 | bool getAllowDeadData() { return allow_dead_data; } 149 | 150 | void setEmitPragmas(OptionLevel _val) { emit_pragmas = _val; } 151 | OptionLevel getEmitPragmas() { return emit_pragmas; } 152 | 153 | void setOutDir(std::string _out_dir) { out_dir = _out_dir; } 154 | std::string getOutDir() { return out_dir; } 155 | 156 | void setUseParamShuffle(bool val) { use_param_shuffle = val; } 157 | bool getUseParamShuffle() { return use_param_shuffle; } 158 | 159 | void setExplLoopParams(bool val) { expl_loop_params = val; } 160 | bool getExplLoopParams() { return expl_loop_params; } 161 | 162 | void setMutationKind(MutationKind val) { mutation_kind = val; } 163 | MutationKind getMutationKind() { return mutation_kind; } 164 | 165 | void setMutationSeed(uint64_t val) { mutation_seed = val; } 166 | uint64_t getMutationSeed() { return mutation_seed; } 167 | 168 | void setAllowUBInDC(OptionLevel _val) { allow_ub_in_dc = _val; } 169 | OptionLevel getAllowUBInDC() { return allow_ub_in_dc; } 170 | 171 | void dump(std::ostream &stream); 172 | 173 | private: 174 | Options() 175 | : seed(0), std(LangStd::CXX), check_algo(CheckAlgo::HASH), 176 | inp_as_args(OptionLevel::SOME), emit_align_attr(OptionLevel::SOME), 177 | unique_align_size(false), 178 | align_size(AlignmentSize::MAX_ALIGNMENT_SIZE), allow_dead_data(false), 179 | emit_pragmas(OptionLevel::SOME), out_dir("."), 180 | use_param_shuffle(false), expl_loop_params(false), 181 | mutation_kind(MutationKind::NONE), mutation_seed(0), 182 | allow_ub_in_dc(OptionLevel::NONE) {} 183 | 184 | std::vector raw_options; 185 | 186 | uint64_t seed; 187 | LangStd std; 188 | CheckAlgo check_algo; 189 | // Pass input data to a test function as parameters 190 | OptionLevel inp_as_args; 191 | 192 | // Options for alignment attributes 193 | OptionLevel emit_align_attr; 194 | bool unique_align_size; 195 | AlignmentSize align_size; 196 | 197 | bool allow_dead_data; 198 | 199 | OptionLevel emit_pragmas; 200 | 201 | std::string out_dir; 202 | 203 | bool use_param_shuffle; 204 | 205 | // Explicit loop parameters. Some applications need that option available 206 | bool expl_loop_params; 207 | 208 | MutationKind mutation_kind; 209 | uint64_t mutation_seed; 210 | 211 | // If we want to allow Undefined Behavior in Dead Code 212 | OptionLevel allow_ub_in_dc; 213 | }; 214 | } // namespace yarpgen 215 | -------------------------------------------------------------------------------- /src/program.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015-2020, Intel Corporation 3 | Copyright (c) 2019-2020, University of Utah 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | ////////////////////////////////////////////////////////////////////////////// 17 | #pragma once 18 | 19 | #include "stmt.h" 20 | 21 | #include 22 | 23 | namespace yarpgen { 24 | 25 | class ProgramGenerator { 26 | public: 27 | ProgramGenerator(); 28 | void emit(); 29 | 30 | private: 31 | void emitCheckFunc(std::ostream &stream); 32 | void emitDecl(std::shared_ptr ctx, std::ostream &stream); 33 | void emitInit(std::shared_ptr ctx, std::ostream &stream); 34 | void emitCheck(std::shared_ptr ctx, std::ostream &stream); 35 | void emitExtDecl(std::shared_ptr ctx, std::ostream &stream); 36 | void emitTest(std::shared_ptr ctx, std::ostream &stream); 37 | void emitMain(std::shared_ptr ctx, std::ostream &stream); 38 | 39 | std::shared_ptr ext_inp_sym_tbl; 40 | std::shared_ptr ext_out_sym_tbl; 41 | std::shared_ptr new_test; 42 | 43 | unsigned long long int hash_seed; 44 | void hash(unsigned long long int const v); 45 | void hashArray(std::shared_ptr const &arr); 46 | void hashArrayStep(std::shared_ptr const &arr, 47 | std::vector &dims, std::vector &idx_vec, 48 | size_t cur_idx, bool has_to_use_init_val, 49 | uint64_t &init_val, uint64_t &cur_val, 50 | std::vector &steps); 51 | }; 52 | 53 | } // namespace yarpgen 54 | -------------------------------------------------------------------------------- /src/statistics.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020, Intel Corporation 3 | Copyright (c) 2020, University of Utah 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | ////////////////////////////////////////////////////////////////////////////// 17 | 18 | #include "statistics.h" 19 | 20 | using namespace yarpgen; 21 | -------------------------------------------------------------------------------- /src/statistics.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020, Intel Corporation 3 | Copyright (c) 2020, University of Utah 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | ////////////////////////////////////////////////////////////////////////////// 17 | #pragma once 18 | 19 | #include "enums.h" 20 | #include 21 | #include 22 | 23 | namespace yarpgen { 24 | class Statistics { 25 | public: 26 | static Statistics &getInstance() { 27 | static Statistics instance; 28 | return instance; 29 | } 30 | Statistics(const Statistics &options) = delete; 31 | Statistics &operator=(const Statistics &) = delete; 32 | 33 | void addStmt(size_t val = 1) { stmt_num += val; } 34 | size_t getStmtNum() { return stmt_num; } 35 | 36 | void addUB(UBKind kind) { ub_num.at(static_cast(kind))++; } 37 | 38 | private: 39 | Statistics() : stmt_num(0), ub_num({}) {} 40 | 41 | size_t stmt_num; 42 | // TODO: count undefined behavior stats 43 | std::array(UBKind::MaxUB)> ub_num; 44 | }; 45 | 46 | } // namespace yarpgen 47 | -------------------------------------------------------------------------------- /src/stmt.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015-2020, Intel Corporation 3 | Copyright (c) 2019-2020, University of Utah 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | */ 17 | 18 | ////////////////////////////////////////////////////////////////////////////// 19 | 20 | #pragma once 21 | 22 | #include "context.h" 23 | #include "enums.h" 24 | #include "expr.h" 25 | #include "ir_node.h" 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | namespace yarpgen { 33 | 34 | class Stmt : public IRNode { 35 | public: 36 | virtual IRNodeKind getKind() { return IRNodeKind::MAX_STMT_KIND; } 37 | // We need to know if we have any nested foreach to make a correct decision 38 | // about the number of iterations. Those two decisions are made in 39 | // different places, so we need to have a way to communicate this 40 | virtual bool detectNestedForeach() { return false; } 41 | }; 42 | 43 | class ExprStmt : public Stmt { 44 | public: 45 | explicit ExprStmt(std::shared_ptr _expr) : expr(std::move(_expr)) {} 46 | IRNodeKind getKind() final { return IRNodeKind::EXPR; } 47 | 48 | std::shared_ptr getExpr() { return expr; } 49 | 50 | void emit(std::shared_ptr ctx, std::ostream &stream, 51 | std::string offset = "") final; 52 | static std::shared_ptr create(std::shared_ptr ctx); 53 | 54 | private: 55 | std::shared_ptr expr; 56 | }; 57 | 58 | class DeclStmt : public Stmt { 59 | public: 60 | explicit DeclStmt(std::shared_ptr _data) : data(std::move(_data)) {} 61 | DeclStmt(std::shared_ptr _data, std::shared_ptr _expr) 62 | : data(std::move(_data)), init_expr(std::move(_expr)) {} 63 | IRNodeKind getKind() final { return IRNodeKind::DECL; } 64 | void emit(std::shared_ptr ctx, std::ostream &stream, 65 | std::string offset = "") final; 66 | 67 | private: 68 | std::shared_ptr data; 69 | std::shared_ptr init_expr; 70 | }; 71 | 72 | class StmtBlock : public Stmt { 73 | public: 74 | StmtBlock() = default; 75 | explicit StmtBlock(std::vector> _stmts) 76 | : stmts(std::move(_stmts)) {} 77 | IRNodeKind getKind() override { return IRNodeKind::BLOCK; } 78 | 79 | void addStmt(std::shared_ptr stmt) { 80 | stmts.push_back(std::move(stmt)); 81 | } 82 | 83 | std::vector> getStmts() { return stmts; } 84 | 85 | void emit(std::shared_ptr ctx, std::ostream &stream, 86 | std::string offset = "") override; 87 | static std::shared_ptr 88 | generateStructure(std::shared_ptr ctx); 89 | void populate(std::shared_ptr ctx) override; 90 | 91 | bool detectNestedForeach() override { 92 | return std::accumulate(stmts.begin(), stmts.end(), false, 93 | [](bool acc, const std::shared_ptr &stmt) { 94 | return acc || stmt->detectNestedForeach(); 95 | }); 96 | } 97 | 98 | protected: 99 | std::vector> stmts; 100 | }; 101 | 102 | class ScopeStmt : public StmtBlock { 103 | public: 104 | IRNodeKind getKind() final { return IRNodeKind::SCOPE; } 105 | void emit(std::shared_ptr ctx, std::ostream &stream, 106 | std::string offset = "") final; 107 | static std::shared_ptr 108 | generateStructure(std::shared_ptr ctx); 109 | }; 110 | 111 | class LoopStmt : public Stmt {}; 112 | 113 | class Pragma { 114 | public: 115 | explicit Pragma(PragmaKind _kind) : kind(_kind) {} 116 | PragmaKind getKind() { return kind; } 117 | void emit(std::shared_ptr ctx, std::ostream &stream, 118 | std::string offset = ""); 119 | static std::shared_ptr create(std::shared_ptr ctx); 120 | static std::vector> 121 | create(size_t num, std::shared_ptr ctx); 122 | 123 | private: 124 | PragmaKind kind; 125 | }; 126 | 127 | class LoopHead { 128 | public: 129 | LoopHead() 130 | : prefix(nullptr), suffix(nullptr), is_foreach(false), 131 | same_iter_space(false), vectorizable(false) {} 132 | 133 | std::shared_ptr getPrefix() { return prefix; } 134 | void addPrefix(std::shared_ptr _prefix) { 135 | prefix = std::move(_prefix); 136 | } 137 | void addIterator(std::shared_ptr _iter) { 138 | iters.push_back(std::move(_iter)); 139 | } 140 | std::vector> getIterators() { return iters; } 141 | std::shared_ptr getSuffix() { return suffix; } 142 | void addSuffix(std::shared_ptr _suffix) { 143 | suffix = std::move(_suffix); 144 | } 145 | void emitPrefix(std::shared_ptr ctx, std::ostream &stream, 146 | std::string offset = ""); 147 | void emitHeader(std::shared_ptr ctx, std::ostream &stream, 148 | std::string offset = ""); 149 | void emitSuffix(std::shared_ptr ctx, std::ostream &stream, 150 | std::string offset = ""); 151 | 152 | void setIsForeach(bool _val) { is_foreach = _val; } 153 | bool isForeach() { return is_foreach; } 154 | 155 | std::shared_ptr 156 | populateIterators(std::shared_ptr ctx, size_t _end_val); 157 | void createPragmas(std::shared_ptr ctx); 158 | bool hasSIMDPragma(); 159 | 160 | static void populateArrays(std::shared_ptr ctx); 161 | 162 | void setSameIterSpace() { same_iter_space = true; } 163 | 164 | void setVectorizable() { vectorizable = true; } 165 | 166 | private: 167 | std::shared_ptr prefix; 168 | // Loop iterations space is defined by the iterators that we can use 169 | std::vector> iters; 170 | std::shared_ptr suffix; 171 | 172 | std::vector> pragmas; 173 | 174 | // ISPC 175 | bool is_foreach; 176 | 177 | // We need to save info about of the loop belongs to the loop sequence with 178 | // the same iteration space (mostly for debug purposes) 179 | bool same_iter_space; 180 | 181 | bool vectorizable; 182 | }; 183 | 184 | // According to the agreement, a single standalone loop should be represented as 185 | // a LoopSeqStmt of size one 186 | class LoopSeqStmt : public LoopStmt { 187 | public: 188 | IRNodeKind getKind() final { return IRNodeKind::LOOP_SEQ; } 189 | void 190 | addLoop(std::pair, std::shared_ptr> 191 | _loop) { 192 | loops.push_back(std::move(_loop)); 193 | } 194 | void emit(std::shared_ptr ctx, std::ostream &stream, 195 | std::string offset = "") final; 196 | static std::shared_ptr 197 | generateStructure(std::shared_ptr ctx); 198 | void populate(std::shared_ptr ctx) override; 199 | 200 | bool detectNestedForeach() override { 201 | return std::accumulate( 202 | loops.begin(), loops.end(), false, 203 | [](bool acc, const std::pair, 204 | std::shared_ptr> &loop) { 205 | return acc || loop.first->isForeach() || 206 | loop.second->detectNestedForeach(); 207 | }); 208 | } 209 | 210 | private: 211 | std::vector< 212 | std::pair, std::shared_ptr>> 213 | loops; 214 | }; 215 | 216 | class LoopNestStmt : public LoopStmt { 217 | public: 218 | IRNodeKind getKind() final { return IRNodeKind::LOOP_NEST; } 219 | void addLoop(std::shared_ptr _loop) { 220 | loops.push_back(std::move(_loop)); 221 | } 222 | void addBody(std::shared_ptr _body) { body = std::move(_body); } 223 | void emit(std::shared_ptr ctx, std::ostream &stream, 224 | std::string offset = "") final; 225 | static std::shared_ptr 226 | generateStructure(std::shared_ptr ctx); 227 | void populate(std::shared_ptr ctx) override; 228 | 229 | bool detectNestedForeach() override { 230 | return std::accumulate( 231 | loops.begin(), loops.end(), false, 232 | [](bool acc, const std::shared_ptr &loop) { 233 | return acc || loop->isForeach(); 234 | }) || 235 | body->detectNestedForeach(); 236 | } 237 | 238 | private: 239 | std::vector> loops; 240 | std::shared_ptr body; 241 | }; 242 | 243 | class IfElseStmt : public Stmt { 244 | public: 245 | IfElseStmt(std::shared_ptr _cond, std::shared_ptr _then_br, 246 | std::shared_ptr _else_br) 247 | : cond(std::move(_cond)), then_br(std::move(_then_br)), 248 | else_br(std::move(_else_br)) {} 249 | IRNodeKind getKind() final { return IRNodeKind::IF_ELSE; } 250 | void emit(std::shared_ptr ctx, std::ostream &stream, 251 | std::string offset = "") final; 252 | static std::shared_ptr 253 | generateStructure(std::shared_ptr ctx); 254 | void populate(std::shared_ptr ctx) final; 255 | 256 | bool detectNestedForeach() override { 257 | return then_br->detectNestedForeach() || 258 | (else_br.use_count() != 0 && else_br->detectNestedForeach()); 259 | } 260 | 261 | private: 262 | std::shared_ptr cond; 263 | std::shared_ptr then_br; 264 | std::shared_ptr else_br; 265 | }; 266 | 267 | class StubStmt : public Stmt { 268 | public: 269 | explicit StubStmt(std::string _text) : text(std::move(_text)) {} 270 | IRNodeKind getKind() final { return IRNodeKind::STUB; } 271 | 272 | void emit(std::shared_ptr ctx, std::ostream &stream, 273 | std::string offset = "") final; 274 | static std::shared_ptr 275 | generateStructure(std::shared_ptr ctx); 276 | 277 | private: 278 | std::string text; 279 | }; 280 | } // namespace yarpgen 281 | -------------------------------------------------------------------------------- /src/type.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015-2020, Intel Corporation 3 | Copyright (c) 2019-2020, University of Utah 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | */ 17 | 18 | ////////////////////////////////////////////////////////////////////////////// 19 | 20 | #include "context.h" 21 | #include 22 | 23 | #include "data.h" 24 | #include "enums.h" 25 | #include "expr.h" 26 | #include "ir_value.h" 27 | #include "type.h" 28 | #include "utils.h" 29 | 30 | using namespace yarpgen; 31 | 32 | std::unordered_map, IntTypeKeyHasher> 33 | yarpgen::IntegralType::int_type_set; 34 | 35 | std::unordered_map, ArrayTypeKeyHasher> 36 | yarpgen::ArrayType::array_type_set; 37 | size_t yarpgen::ArrayType::uid_counter = 0; 38 | 39 | std::shared_ptr yarpgen::IntegralType::init(IntTypeID _type_id) { 40 | return init(_type_id, false, CVQualifier::NONE); 41 | } 42 | 43 | std::shared_ptr IntegralType::init(IntTypeID _type_id, 44 | bool _is_static, 45 | CVQualifier _cv_qual, 46 | bool _is_uniform) { 47 | // Folding set lookup 48 | IntTypeKey key(_type_id, _is_static, _cv_qual, _is_uniform); 49 | auto find_result = int_type_set.find(key); 50 | if (find_result != int_type_set.end()) 51 | return find_result->second; 52 | 53 | // Create type if we can't find it 54 | std::shared_ptr ret; 55 | switch (_type_id) { 56 | case IntTypeID::BOOL: 57 | ret = std::make_shared(TypeBool(_is_static, _cv_qual)); 58 | break; 59 | case IntTypeID::SCHAR: 60 | ret = std::make_shared(TypeSChar(_is_static, _cv_qual)); 61 | break; 62 | case IntTypeID::UCHAR: 63 | ret = std::make_shared(TypeUChar(_is_static, _cv_qual)); 64 | break; 65 | case IntTypeID::SHORT: 66 | ret = 67 | std::make_shared(TypeSShort(_is_static, _cv_qual)); 68 | break; 69 | case IntTypeID::USHORT: 70 | ret = 71 | std::make_shared(TypeUShort(_is_static, _cv_qual)); 72 | break; 73 | case IntTypeID::INT: 74 | ret = std::make_shared(TypeSInt(_is_static, _cv_qual)); 75 | break; 76 | case IntTypeID::UINT: 77 | ret = std::make_shared(TypeUInt(_is_static, _cv_qual)); 78 | break; 79 | case IntTypeID::LLONG: 80 | ret = 81 | std::make_shared(TypeSLLong(_is_static, _cv_qual)); 82 | break; 83 | case IntTypeID::ULLONG: 84 | ret = 85 | std::make_shared(TypeULLong(_is_static, _cv_qual)); 86 | break; 87 | case IntTypeID::MAX_INT_TYPE_ID: 88 | ERROR("Unsupported IntTypeID"); 89 | } 90 | 91 | ret->setIsUniform(_is_uniform); 92 | 93 | int_type_set[key] = ret; 94 | return ret; 95 | } 96 | 97 | bool IntegralType::isSame(std::shared_ptr &lhs, 98 | std::shared_ptr &rhs) { 99 | return (lhs->getIntTypeId() == rhs->getIntTypeId()) && 100 | (lhs->getIsStatic() == rhs->getIsStatic()) && 101 | (lhs->getCVQualifier() == rhs->getCVQualifier() && 102 | lhs->isUniform() == rhs->isUniform()); 103 | } 104 | 105 | // Check if type "b" can represent all the values of type "a" 106 | bool IntegralType::canRepresentType(IntTypeID a, IntTypeID b) { 107 | // This functions should be called only after integral promotions, so we 108 | // don't care about "small" types. Unfortunately, there is no way to enforce 109 | // it, so in case of violation it should fail generated tests. 110 | // TODO: can we do something about it? 111 | 112 | if (a == IntTypeID::INT && b == IntTypeID::LLONG) 113 | return true; 114 | 115 | if (a == IntTypeID::UINT && 116 | (b == IntTypeID::ULLONG || b == IntTypeID::LLONG)) 117 | return true; 118 | 119 | return false; 120 | } 121 | 122 | IntTypeID IntegralType::getCorrUnsigned(IntTypeID id) { 123 | // This functions should be called only after integral promotions, so we 124 | // don't care about "small" types. 125 | switch (id) { 126 | case IntTypeID::INT: 127 | case IntTypeID::UINT: 128 | return IntTypeID::UINT; 129 | case IntTypeID::LLONG: 130 | case IntTypeID::ULLONG: 131 | return IntTypeID::ULLONG; 132 | default: 133 | ERROR( 134 | "This function should be called only after IntegralPromotions"); 135 | } 136 | } 137 | std::shared_ptr IntegralType::makeVarying() { 138 | return init(getIntTypeId(), getIsStatic(), getCVQualifier(), false); 139 | } 140 | 141 | std::string IntegralType::getNameImpl(std::shared_ptr ctx, 142 | std::string raw_name) { 143 | if (!ctx) 144 | ERROR("Can't give a name without a context"); 145 | 146 | std::string ret = std::move(raw_name); 147 | if (ctx->useIspcTypes()) { 148 | ret = getIspcNameHelper(); 149 | if (getIntTypeId() != IntTypeID::BOOL) { 150 | if (!getIsSigned()) 151 | ret += "unsigned "; 152 | ret += "int" + std::to_string(getBitSize()); 153 | } 154 | else 155 | ret += "bool"; 156 | } 157 | return ret; 158 | } 159 | 160 | std::string IntegralType::getLiteralSuffix() { 161 | Options &options = Options::getInstance(); 162 | return !options.isISPC() ? "" : "L"; 163 | } 164 | 165 | template 166 | static void dbgDumpHelper(IntTypeID id, const std::string &name, 167 | const std::string &suffix, size_t bit_size, 168 | bool is_signed, T &min, T &max, bool is_static, 169 | CVQualifier cv_qual, bool is_uniform) { 170 | std::cout << "int type id: " 171 | << static_cast::type>(id) 172 | << std::endl; 173 | std::cout << "name: " << name << std::endl; 174 | std::cout << "bit_size: " << bit_size << std::endl; 175 | std::cout << "is_signed: " << is_signed << std::endl; 176 | std::cout << "min: " << min << suffix << std::endl; 177 | std::cout << "max: " << max << suffix << std::endl; 178 | std::cout << "is_static: " << is_static << std::endl; 179 | std::cout << "cv_qualifier: " 180 | << static_cast::type>(cv_qual) 181 | << std::endl; 182 | std::cout << "is_uniform: " << is_uniform << std::endl; 183 | } 184 | 185 | #define DBG_DUMP_MACROS(type_name) \ 186 | void type_name::dbgDump() { \ 187 | auto ctx = std::make_shared(); \ 188 | dbgDumpHelper(getIntTypeId(), getName(ctx), getLiteralSuffix(), \ 189 | getBitSize(), getIsSigned(), \ 190 | min.getValueRef(), \ 191 | max.getValueRef(), getIsStatic(), \ 192 | getCVQualifier(), isUniform()); \ 193 | } 194 | 195 | DBG_DUMP_MACROS(TypeBool) 196 | DBG_DUMP_MACROS(TypeSChar) 197 | DBG_DUMP_MACROS(TypeUChar) 198 | DBG_DUMP_MACROS(TypeSShort) 199 | DBG_DUMP_MACROS(TypeUShort) 200 | DBG_DUMP_MACROS(TypeSInt) 201 | DBG_DUMP_MACROS(TypeUInt) 202 | DBG_DUMP_MACROS(TypeSLLong) 203 | DBG_DUMP_MACROS(TypeULLong) 204 | 205 | bool ArrayType::isSame(const std::shared_ptr &lhs, 206 | const std::shared_ptr &rhs) { 207 | return lhs->getUID() == rhs->getUID(); 208 | } 209 | 210 | void ArrayType::dbgDump() { 211 | std::cout << "Array: " << std::endl; 212 | std::cout << "Base type: " << std::endl; 213 | base_type->dbgDump(); 214 | std::cout << "Dimensions: ["; 215 | for (const auto &dim : dimensions) { 216 | std::cout << dim << ", "; 217 | } 218 | std::cout << "]" << std::endl; 219 | 220 | std::cout << "Kind: " << static_cast(kind) << std::endl; 221 | std::cout << "UID: " << uid << std::endl; 222 | std::cout << "is_static: " << getIsStatic() << std::endl; 223 | std::cout << "cv_qualifier: " 224 | << static_cast::type>( 225 | getCVQualifier()) 226 | << std::endl; 227 | } 228 | 229 | std::shared_ptr ArrayType::init(std::shared_ptr _base_type, 230 | std::vector _dims) { 231 | return init(std::move(_base_type), std::move(_dims), 232 | /* is static */ false, CVQualifier::NONE); 233 | } 234 | 235 | std::shared_ptr 236 | ArrayType::init(std::shared_ptr _base_type, std::vector _dims, 237 | bool _is_static, CVQualifier _cv_qual, bool _is_uniform) { 238 | ArrayTypeKey key(_base_type, _dims, ArrayKind::MAX_ARRAY_KIND, _is_static, 239 | _cv_qual, _is_uniform); 240 | auto find_res = array_type_set.find(key); 241 | if (find_res != array_type_set.end()) 242 | return find_res->second; 243 | 244 | auto ret = std::make_shared(_base_type, _dims, _is_static, 245 | _cv_qual, uid_counter++); 246 | ret->setIsUniform(_is_uniform); 247 | array_type_set[key] = ret; 248 | return ret; 249 | } 250 | 251 | std::string ArrayType::getName(std::shared_ptr ctx) { 252 | // TODO: we need a more correct way to do it 253 | return base_type->getName(ctx) + " *"; 254 | } 255 | 256 | std::shared_ptr ArrayType::create(std::shared_ptr ctx) { 257 | auto gen_pol = ctx->getGenPolicy(); 258 | IntTypeID base_type_id = rand_val_gen->getRandId(gen_pol->int_type_distr); 259 | auto base_type = IntegralType::init(base_type_id); 260 | 261 | // Determine how many dimensions do we want, relative to the current 262 | // ctx loop depth 263 | auto dims_use_kind = rand_val_gen->getRandId(gen_pol->array_dims_use_kind); 264 | size_t dims_num = ctx->generateNumberOfDims(dims_use_kind); 265 | assert(dims_num <= gen_pol->array_dims_num_limit && 266 | "Arrays can't have more dimensions than the limit"); 267 | std::vector dims(dims_num, ctx->getDimensions().front()); 268 | 269 | return init(base_type, dims); 270 | } 271 | 272 | std::shared_ptr ArrayType::makeVarying() { 273 | return init(getBaseType()->makeVarying(), getDimensions(), getIsStatic(), 274 | getCVQualifier(), false); 275 | } 276 | -------------------------------------------------------------------------------- /src/type.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015-2020, Intel Corporation 3 | Copyright (c) 2019-2020, University of Utah 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | */ 17 | 18 | ////////////////////////////////////////////////////////////////////////////// 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "hash.h" 31 | #include "ir_value.h" 32 | #include "options.h" 33 | 34 | namespace yarpgen { 35 | 36 | class PopulateCtx; 37 | class EmitCtx; 38 | class Iterator; 39 | 40 | // Abstract class that serves as a common ancestor for all types. 41 | // Here by "type" we mean a backend type, which has certain properties 42 | // and may be instantiated as different language types 43 | // (i.e. signed 32 bit integer, which may be int, or int32_t). 44 | // For now we support only one language type per backend type, but 45 | // that may change in future. 46 | class Type { 47 | public: 48 | Type() 49 | : is_static(false), cv_qualifier(CVQualifier::NONE), is_uniform(true) {} 50 | Type(bool _is_static, CVQualifier _cv_qual) 51 | : is_static(_is_static), cv_qualifier(_cv_qual), is_uniform(true) {} 52 | virtual ~Type() = default; 53 | 54 | virtual std::string getName(std::shared_ptr ctx) = 0; 55 | virtual void dbgDump() = 0; 56 | 57 | virtual bool isIntType() { return false; } 58 | virtual bool isArrayType() { return false; } 59 | 60 | bool getIsStatic() { return is_static; } 61 | void setIsStatic(bool _is_static) { is_static = _is_static; } 62 | CVQualifier getCVQualifier() { return cv_qualifier; } 63 | void setCVQualifier(CVQualifier _cv_qual) { cv_qualifier = _cv_qual; } 64 | 65 | bool isUniform() { return is_uniform; } 66 | 67 | virtual std::shared_ptr makeVarying() = 0; 68 | 69 | protected: 70 | void setIsUniform(bool _is_uniform) { is_uniform = _is_uniform; } 71 | 72 | private: 73 | bool is_static; 74 | CVQualifier cv_qualifier; 75 | 76 | // ISPC 77 | // TODO: arrays themselves aren't uniform or varying 78 | bool is_uniform; 79 | 80 | // We don't store name here because for compound types it might be tricky to 81 | // get them. 82 | }; 83 | 84 | // Base class for floating-point and integral types 85 | class ArithmeticType : public Type { 86 | public: 87 | ArithmeticType() : Type() {} 88 | ArithmeticType(bool _is_static, CVQualifier _cv_qual) 89 | : Type(_is_static, _cv_qual) {} 90 | virtual std::string getLiteralSuffix() { return ""; }; 91 | }; 92 | 93 | class FPType : public ArithmeticType { 94 | // TODO: it is a stub for now 95 | }; 96 | 97 | class IntegralType : public ArithmeticType { 98 | public: 99 | IntegralType() : ArithmeticType() {} 100 | IntegralType(bool _is_static, CVQualifier _cv_qual) 101 | : ArithmeticType(_is_static, _cv_qual) {} 102 | bool isIntType() final { return true; } 103 | virtual IntTypeID getIntTypeId() = 0; 104 | virtual size_t getBitSize() = 0; 105 | virtual bool getIsSigned() = 0; 106 | virtual IRValue getMin() = 0; 107 | virtual IRValue getMax() = 0; 108 | 109 | std::string getLiteralSuffix() override; 110 | 111 | // These utility functions take IntegerTypeID and return shared pointer to 112 | // corresponding type 113 | static std::shared_ptr init(IntTypeID _type_id); 114 | static std::shared_ptr init(IntTypeID _type_id, 115 | bool _is_static, 116 | CVQualifier _cv_qual, 117 | bool _is_uniform = true); 118 | 119 | static bool isSame(std::shared_ptr &lhs, 120 | std::shared_ptr &rhs); 121 | 122 | // Auxiliary function for arithmetic conversions that shows if type a can 123 | // represent all the values of type b 124 | static bool canRepresentType(IntTypeID a, IntTypeID b); 125 | // Auxiliary function for arithmetic conversions that find corresponding 126 | // unsigned type 127 | static IntTypeID getCorrUnsigned(IntTypeID id); 128 | 129 | std::shared_ptr makeVarying() override; 130 | 131 | protected: 132 | // ISPC 133 | std::string getIspcNameHelper() { 134 | return (isUniform() ? "uniform" : "varying") + std::string(" "); 135 | } 136 | std::string getNameImpl(std::shared_ptr ctx, std::string raw_name); 137 | 138 | private: 139 | // There is a fixed small number of possible integral types, 140 | // so we use a folding set in order to save memory 141 | static std::unordered_map, 142 | IntTypeKeyHasher> 143 | int_type_set; 144 | }; 145 | 146 | template class IntegralTypeHelper : public IntegralType { 147 | public: 148 | using value_type = T; 149 | IntegralTypeHelper(IntTypeID type_id, bool _is_static, CVQualifier _cv_qual) 150 | : IntegralType(_is_static, _cv_qual) { 151 | min = IRValue(type_id); 152 | min.getValueRef() = std::numeric_limits::min(); 153 | min.setUBCode(UBKind::NoUB); 154 | 155 | max = IRValue(type_id); 156 | max.getValueRef() = std::numeric_limits::max(); 157 | max.setUBCode(UBKind::NoUB); 158 | } 159 | 160 | size_t getBitSize() override { return sizeof(T) * CHAR_BIT; } 161 | bool getIsSigned() override { return std::is_signed::value; } 162 | IRValue getMin() override { return min; } 163 | IRValue getMax() override { return max; } 164 | 165 | protected: 166 | IRValue min; 167 | IRValue max; 168 | }; 169 | 170 | class TypeBool : public IntegralTypeHelper { 171 | public: 172 | TypeBool(bool _is_static, CVQualifier _cv_qual) 173 | : IntegralTypeHelper(getIntTypeId(), _is_static, _cv_qual) {} 174 | 175 | // TODO: decouple language representation of the type from back-end type. 176 | // I.e. for different languages the name of the type and the suffix might be 177 | // different. 178 | IntTypeID getIntTypeId() final { return IntTypeID::BOOL; } 179 | std::string getName(std::shared_ptr ctx) final { 180 | Options &options = Options::getInstance(); 181 | if (options.isC()) 182 | return getNameImpl(ctx, "_Bool"); 183 | return getNameImpl(ctx, "bool"); 184 | } 185 | 186 | // For bool signedness is not defined, so std::is_signed and 187 | // std::is_unsigned return true. We treat them as unsigned 188 | bool getIsSigned() final { return false; } 189 | 190 | void dbgDump() final; 191 | }; 192 | 193 | class TypeSChar : public IntegralTypeHelper { 194 | public: 195 | TypeSChar(bool _is_static, CVQualifier _cv_qual) 196 | : IntegralTypeHelper(getIntTypeId(), _is_static, _cv_qual) {} 197 | 198 | IntTypeID getIntTypeId() final { return IntTypeID::SCHAR; } 199 | std::string getName(std::shared_ptr ctx) final { 200 | return getNameImpl(ctx, "signed char"); 201 | } 202 | 203 | void dbgDump() final; 204 | }; 205 | 206 | class TypeUChar : public IntegralTypeHelper { 207 | public: 208 | TypeUChar(bool _is_static, CVQualifier _cv_qual) 209 | : IntegralTypeHelper(getIntTypeId(), _is_static, _cv_qual) {} 210 | 211 | IntTypeID getIntTypeId() final { return IntTypeID::UCHAR; } 212 | std::string getName(std::shared_ptr ctx) final { 213 | return getNameImpl(ctx, "unsigned char"); 214 | } 215 | 216 | void dbgDump() final; 217 | }; 218 | 219 | class TypeSShort : public IntegralTypeHelper { 220 | public: 221 | TypeSShort(bool _is_static, CVQualifier _cv_qual) 222 | : IntegralTypeHelper(getIntTypeId(), _is_static, _cv_qual) {} 223 | 224 | IntTypeID getIntTypeId() final { return IntTypeID::SHORT; } 225 | std::string getName(std::shared_ptr ctx) final { 226 | return getNameImpl(ctx, "short"); 227 | } 228 | 229 | void dbgDump() final; 230 | }; 231 | 232 | class TypeUShort : public IntegralTypeHelper { 233 | public: 234 | TypeUShort(bool _is_static, CVQualifier _cv_qual) 235 | : IntegralTypeHelper(getIntTypeId(), _is_static, _cv_qual) {} 236 | 237 | IntTypeID getIntTypeId() final { return IntTypeID::USHORT; } 238 | std::string getName(std::shared_ptr ctx) final { 239 | return getNameImpl(ctx, "unsigned short"); 240 | } 241 | 242 | void dbgDump() final; 243 | }; 244 | 245 | class TypeSInt : public IntegralTypeHelper { 246 | public: 247 | TypeSInt(bool _is_static, CVQualifier _cv_qual) 248 | : IntegralTypeHelper(getIntTypeId(), _is_static, _cv_qual) {} 249 | 250 | IntTypeID getIntTypeId() final { return IntTypeID::INT; } 251 | std::string getName(std::shared_ptr ctx) final { 252 | return getNameImpl(ctx, "int"); 253 | } 254 | 255 | void dbgDump() final; 256 | }; 257 | 258 | class TypeUInt : public IntegralTypeHelper { 259 | public: 260 | TypeUInt(bool _is_static, CVQualifier _cv_qual) 261 | : IntegralTypeHelper(getIntTypeId(), _is_static, _cv_qual) {} 262 | 263 | IntTypeID getIntTypeId() final { return IntTypeID::UINT; } 264 | std::string getName(std::shared_ptr ctx) final { 265 | return getNameImpl(ctx, "unsigned int"); 266 | } 267 | std::string getLiteralSuffix() final { return "U"; } 268 | 269 | void dbgDump() final; 270 | }; 271 | 272 | class TypeSLLong : public IntegralTypeHelper { 273 | public: 274 | TypeSLLong(bool _is_static, CVQualifier _cv_qual) 275 | : IntegralTypeHelper(getIntTypeId(), _is_static, _cv_qual) {} 276 | 277 | IntTypeID getIntTypeId() final { return IntTypeID::LLONG; } 278 | std::string getName(std::shared_ptr ctx) final { 279 | return getNameImpl(ctx, "long long int"); 280 | } 281 | std::string getLiteralSuffix() final { return "LL"; } 282 | 283 | void dbgDump() final; 284 | }; 285 | 286 | class TypeULLong : public IntegralTypeHelper { 287 | public: 288 | TypeULLong(bool _is_static, CVQualifier _cv_qual) 289 | : IntegralTypeHelper(getIntTypeId(), _is_static, _cv_qual) {} 290 | 291 | IntTypeID getIntTypeId() final { return IntTypeID::ULLONG; } 292 | std::string getName(std::shared_ptr ctx) final { 293 | return getNameImpl(ctx, "unsigned long long int"); 294 | } 295 | std::string getLiteralSuffix() final { return "ULL"; } 296 | 297 | void dbgDump() final; 298 | }; 299 | 300 | // Base class for all of the array-like types (C-style, Vector, Array, 301 | // ValArray). 302 | class ArrayType : public Type { 303 | public: 304 | ArrayType(std::shared_ptr _base_type, std::vector _dims, 305 | bool _is_static, CVQualifier _cv_qual, size_t _uid) 306 | : Type(_is_static, _cv_qual), base_type(std::move(_base_type)), 307 | dimensions(std::move(_dims)), kind(ArrayKind::MAX_ARRAY_KIND), 308 | uid(_uid) {} 309 | 310 | bool isArrayType() final { return true; } 311 | std::shared_ptr getBaseType() { return base_type; } 312 | std::vector &getDimensions() { return dimensions; } 313 | size_t getUID() { return uid; } 314 | 315 | static bool isSame(const std::shared_ptr &lhs, 316 | const std::shared_ptr &rhs); 317 | 318 | std::string getName(std::shared_ptr ctx) override; 319 | void dbgDump() override; 320 | 321 | static std::shared_ptr 322 | init(std::shared_ptr _base_type, std::vector _dims, 323 | bool _is_static, CVQualifier _cv_qual, bool _is_uniform = true); 324 | static std::shared_ptr init(std::shared_ptr _base_type, 325 | std::vector _dims); 326 | static std::shared_ptr create(std::shared_ptr ctx); 327 | 328 | std::shared_ptr makeVarying() override; 329 | 330 | private: 331 | // Folding set for all of the array types. 332 | static std::unordered_map, 333 | ArrayTypeKeyHasher> 334 | array_type_set; 335 | // The easiest way to compare array types is to assign a unique identifier 336 | // to each of them and then compare it. 337 | static size_t uid_counter; 338 | 339 | std::shared_ptr base_type; 340 | // Number of elements in each dimension 341 | std::vector dimensions; 342 | // The kind of array that we want to use during lowering process 343 | ArrayKind kind; 344 | size_t uid; 345 | }; 346 | 347 | } // namespace yarpgen 348 | -------------------------------------------------------------------------------- /src/utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015-2020, Intel Corporation 3 | Copyright (c) 2019-2020, University of Utah 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | */ 17 | 18 | ////////////////////////////////////////////////////////////////////////////// 19 | 20 | #include "utils.h" 21 | #include "type.h" 22 | #include 23 | 24 | using namespace yarpgen; 25 | 26 | std::shared_ptr yarpgen::rand_val_gen; 27 | 28 | RandValGen::RandValGen(uint64_t _seed) { 29 | if (_seed != 0) { 30 | seed = _seed; 31 | } 32 | else { 33 | std::random_device rd; 34 | seed = rd(); 35 | } 36 | std::cout << "/*SEED " << seed << "*/" << std::endl; 37 | rand_gen = std::mt19937_64(seed); 38 | } 39 | 40 | #define RandValueCase(__type_id__, gen_name, type_name) \ 41 | case __type_id__: \ 42 | do { \ 43 | ret.getValueRef() = gen_name(); \ 44 | ret.setUBCode(UBKind::NoUB); \ 45 | return ret; \ 46 | } while (false) 47 | 48 | IRValue RandValGen::getRandValue(IntTypeID type_id) { 49 | if (type_id == IntTypeID::MAX_INT_TYPE_ID) 50 | ERROR("Bad IntTypeID"); 51 | 52 | IRValue ret(type_id); 53 | switch (type_id) { 54 | // TODO: if we use chains of if we can make it simpler 55 | RandValueCase(IntTypeID::BOOL, getRandValue, TypeBool::value_type); 56 | RandValueCase(IntTypeID::SCHAR, getRandValue, TypeSChar::value_type); 57 | RandValueCase(IntTypeID::UCHAR, getRandUnsignedValue, 58 | TypeUChar::value_type); 59 | RandValueCase(IntTypeID::SHORT, getRandValue, TypeSShort::value_type); 60 | RandValueCase(IntTypeID::USHORT, getRandUnsignedValue, 61 | TypeUShort::value_type); 62 | RandValueCase(IntTypeID::INT, getRandValue, TypeSInt::value_type); 63 | RandValueCase(IntTypeID::UINT, getRandUnsignedValue, 64 | TypeUInt::value_type); 65 | RandValueCase(IntTypeID::LLONG, getRandValue, TypeSLLong::value_type); 66 | RandValueCase(IntTypeID::ULLONG, getRandUnsignedValue, 67 | TypeULLong::value_type); 68 | case IntTypeID::MAX_INT_TYPE_ID: 69 | ERROR("Bad IntTypeID"); 70 | break; 71 | } 72 | return ret; 73 | } 74 | 75 | // Swap random generators that we use to make random decisions 76 | void RandValGen::switchMutationStates() { std::swap(prev_gen, rand_gen); } 77 | 78 | void RandValGen::setSeed(uint64_t new_seed) { 79 | seed = new_seed; 80 | rand_gen = std::mt19937_64(seed); 81 | } 82 | 83 | // Mutations are driven by auxiliary random generator. 84 | // We use a separate mutation seed to set its initial state 85 | void RandValGen::setMutationSeed(uint64_t mutation_seed) { 86 | if (mutation_seed == 0) { 87 | std::random_device rd; 88 | mutation_seed = rd(); 89 | } 90 | std::cout << "/*MUTATION_SEED " << mutation_seed << "*/" << std::endl; 91 | prev_gen = std::mt19937_64(mutation_seed); 92 | } 93 | -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015-2020, Intel Corporation 3 | Copyright (c) 2019-2020, University of Utah 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | */ 17 | 18 | ////////////////////////////////////////////////////////////////////////////// 19 | 20 | #pragma once 21 | 22 | #include "enums.h" 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace yarpgen { 32 | 33 | class IRValue; 34 | 35 | // Macros for error handling 36 | #define ERROR(err_message) \ 37 | do { \ 38 | std::cerr << "ERROR at " << __FILE__ << ":" << __LINE__ \ 39 | << ", function " << __func__ << "():\n " << (err_message) \ 40 | << std::endl; \ 41 | abort(); \ 42 | } while (false) 43 | 44 | // This class links together id (for example, type of unary operator) and its 45 | // probability. Usually it is used in the form of std::vector> 46 | // and defines all possible variants for random decision (probability itself 47 | // measured in parts, similarly to std::discrete_distribution). Preferably, sum 48 | // of all probabilities in vector should be 100 (so we can treat 1 part as 1 49 | // percent). 50 | template class Probability { 51 | public: 52 | Probability(T _id, uint64_t _prob) : id(_id), prob(_prob) {} 53 | T getId() { return id; } 54 | uint64_t getProb() { return prob; } 55 | 56 | void increaseProb(uint64_t add_prob) { prob += add_prob; } 57 | void zeroProb() { prob = 0; } 58 | void setProb(uint64_t _prob) { prob = _prob; } 59 | 60 | template 61 | friend std::ostream &operator<<(std::ostream &os, 62 | const Probability &_prob); 63 | 64 | private: 65 | T id; 66 | uint64_t prob; 67 | }; 68 | 69 | template 70 | typename std::enable_if::value, std::ostream &>::type 71 | operator<<(std::ostream &os, const Probability &_prob) { 72 | os << _prob.id << " : " << _prob.prob; 73 | return os; 74 | } 75 | 76 | template 77 | typename std::enable_if::value, std::ostream &>::type 78 | operator<<(std::ostream &os, const Probability &_prob) { 79 | os << static_cast(_prob.id) << " : " << _prob.prob; 80 | return os; 81 | } 82 | 83 | // According to the agreement, Random Value Generator is the only way to get any 84 | // random value in YARPGen. It is used for different random decisions all over 85 | // the source code. 86 | class RandValGen { 87 | public: 88 | // Specific seed can be passed to constructor to reproduce the test. 89 | // Zero value is reserved (it notifies RandValGen that it can choose any) 90 | explicit RandValGen(uint64_t _seed); 91 | 92 | template T getRandValue(T from, T to) { 93 | assert(from <= to && "Invalid range for random value generation"); 94 | // Using long long instead of T is a hack. 95 | // getRandValue is used with all kind of integer types, including chars. 96 | // While standard is not allowing it to be used with 97 | // uniform_int_distribution<> algorithm. Though, clang and gcc ok with 98 | // it, but VS doesn't compile such code. For details see C++17, 99 | // $26.5.1.1e [rand.req.genl]. This issue is also discussed in issue 100 | // 2326 (closed as not a defect and reopened as feature request N4296). 101 | std::uniform_int_distribution dis(from, to); 102 | return static_cast(dis(rand_gen)); 103 | } 104 | 105 | template T getRandValue() { 106 | // See note above about long long hack 107 | std::uniform_int_distribution dis( 108 | static_cast(std::numeric_limits::min()), 109 | static_cast(std::numeric_limits::max())); 110 | return static_cast(dis(rand_gen)); 111 | } 112 | 113 | template T getRandUnsignedValue() { 114 | // See note above about long long hack 115 | std::uniform_int_distribution dis( 116 | 0, static_cast(std::numeric_limits::max())); 117 | return static_cast(dis(rand_gen)); 118 | } 119 | 120 | IRValue getRandValue(IntTypeID type_id); 121 | 122 | // Randomly chooses one of IDs, basing on std::vector>. 123 | template T getRandId(std::vector> vec) { 124 | std::vector discrete_dis_init; 125 | for (auto i : vec) 126 | discrete_dis_init.push_back(static_cast(i.getProb())); 127 | 128 | std::discrete_distribution discrete_dis( 129 | discrete_dis_init.begin(), discrete_dis_init.end()); 130 | size_t idx = discrete_dis(rand_gen); 131 | return vec.at(idx).getId(); 132 | } 133 | 134 | // Randomly choose element from a vector 135 | template T &getRandElem(std::vector &vec) { 136 | std::uniform_int_distribution distr(0, vec.size() - 1); 137 | size_t idx = distr(rand_gen); 138 | return vec.at(idx); 139 | } 140 | 141 | // Randomly choose elements without replacement from a vector in order 142 | template 143 | std::vector getRandElemsInOrder(const std::vector &vec, size_t num) { 144 | std::vector ret; 145 | ret.reserve(num); 146 | std::sample(vec.begin(), vec.end(), std::back_inserter(ret), num, 147 | rand_gen); 148 | return ret; 149 | } 150 | 151 | // Randomly choose elements without replacement from a vector 152 | template 153 | std::vector getRandElems(const std::vector &vec, size_t num) { 154 | auto ret = getRandElemsInOrder(vec, num); 155 | std::shuffle(ret.begin(), ret.end(), rand_gen); 156 | return ret; 157 | } 158 | 159 | template void shuffleVector(std::vector vec) { 160 | std::shuffle(vec.begin(), vec.end(), rand_gen); 161 | } 162 | 163 | // To improve variety of generated tests, we implement shuffling of 164 | // input probabilities (they are stored in GenPolicy). 165 | // TODO: sometimes this action increases test complexity, and tests becomes 166 | // non-generatable. 167 | template 168 | void shuffleProb(std::vector> &prob_vec) { 169 | uint64_t total_prob = 0; 170 | std::vector discrete_dis_init; 171 | std::vector> new_prob; 172 | for (auto i : prob_vec) { 173 | total_prob += i.getProb(); 174 | discrete_dis_init.push_back(static_cast(i.getProb())); 175 | new_prob.push_back(Probability(i.getId(), 0)); 176 | } 177 | 178 | std::uniform_int_distribution dis(1ULL, total_prob); 179 | auto delta = static_cast( 180 | round(((double)total_prob) / static_cast(dis(rand_gen)))); 181 | 182 | std::discrete_distribution discrete_dis( 183 | discrete_dis_init.begin(), discrete_dis_init.end()); 184 | for (uint64_t i = 0; i < total_prob; i += delta) 185 | new_prob.at(static_cast(discrete_dis(rand_gen))) 186 | .increaseProb(delta); 187 | 188 | prob_vec = new_prob; 189 | } 190 | 191 | uint64_t getSeed() const { return seed; } 192 | void setSeed(uint64_t new_seed); 193 | void switchMutationStates(); 194 | void setMutationSeed(uint64_t mutation_seed); 195 | 196 | private: 197 | uint64_t seed; 198 | std::mt19937_64 rand_gen; 199 | // Auxiliary random generator, used for mutation 200 | std::mt19937_64 prev_gen; 201 | }; 202 | 203 | template <> inline bool RandValGen::getRandValue(bool from, bool to) { 204 | std::uniform_int_distribution dis((int)from, (int)to); 205 | return (bool)dis(rand_gen); 206 | } 207 | 208 | extern std::shared_ptr rand_val_gen; 209 | 210 | class NameHandler { 211 | public: 212 | static NameHandler &getInstance() { 213 | static NameHandler instance; 214 | return instance; 215 | } 216 | NameHandler(const NameHandler &root) = delete; 217 | NameHandler &operator=(const NameHandler &) = delete; 218 | 219 | std::string getStubStmtIdx() { return std::to_string(stub_stmt_idx++); } 220 | std::string getVarName() { return "var_" + std::to_string(var_idx++); } 221 | std::string getArrayName() { return "arr_" + std::to_string(arr_idx++); } 222 | std::string getIterName() { return "i_" + std::to_string(iter_idx++); } 223 | 224 | private: 225 | NameHandler() : var_idx(0), arr_idx(0), iter_idx(0), stub_stmt_idx(0) {} 226 | 227 | uint32_t var_idx; 228 | uint32_t arr_idx; 229 | uint32_t iter_idx; 230 | uint32_t stub_stmt_idx; 231 | }; 232 | } // namespace yarpgen 233 | --------------------------------------------------------------------------------