├── .gitignore ├── LICENSE ├── README.md ├── Vagrantfile ├── compiler ├── CMakeLists.txt ├── LICENSE.TXT ├── Makefile ├── README.txt └── projects │ ├── CMakeLists.txt │ ├── include │ ├── DAE │ │ └── Utils │ │ │ └── SkelUtils │ │ │ └── headers.h │ ├── SWOOP │ │ └── Transform │ │ │ └── SwoopDAE │ │ │ └── BasicSwoop.h │ └── Util │ │ ├── Analysis │ │ ├── AliasUtils.h │ │ ├── LoopCarriedDependencyAnalysis.h │ │ └── LoopDependency.h │ │ ├── Annotation │ │ └── MetadataInfo.h │ │ ├── DAE │ │ └── DAEUtils.h │ │ └── Transform │ │ └── BranchMerge │ │ └── BranchMerge.h │ └── src │ ├── CMakeLists.txt │ ├── DAE │ ├── CMakeLists.txt │ └── Utils │ │ ├── CMakeLists.txt │ │ ├── LoopExtract │ │ ├── CMakeLists.txt │ │ └── LoopExtract.cpp │ │ └── SkelUtils │ │ ├── LoopUtils.cpp │ │ └── Utils.cpp │ ├── SWOOP │ ├── CMakeLists.txt │ ├── Transform │ │ ├── CMakeLists.txt │ │ ├── OptimisticSwoop │ │ │ ├── CMakeLists.txt │ │ │ └── OptimisticSwoop.cpp │ │ ├── PhaseStitching.cpp │ │ ├── PhaseStitching.h │ │ └── SwoopDAE │ │ │ ├── CMakeLists.txt │ │ │ ├── FindInstructions.cpp │ │ │ ├── FindInstructions.h │ │ │ ├── LCDHandler.cpp │ │ │ ├── LCDHandler.h │ │ │ └── SwoopDAE.cpp │ └── Utils │ │ ├── CMakeLists.txt │ │ ├── DCEutils.cpp │ │ ├── LongLatency.cpp │ │ └── MarkLoopsToSwoopify │ │ ├── CMakeLists.txt │ │ └── MarkLoopsToSwoopify.cpp │ └── Util │ ├── Analysis │ ├── AliasUtils.cpp │ ├── BasicLCDAnalysis.cpp │ ├── LoopDependency.cpp │ └── MarkLCD.cpp │ ├── Annotation │ ├── BranchAnnotate │ │ ├── CMakeLists.txt │ │ ├── Replace.cpp │ │ └── SBPAnnotator.cpp │ ├── CFGIndirectionCount │ │ ├── CFGIndirectionCount.cpp │ │ └── CMakeLists.txt │ ├── CMakeLists.txt │ └── MetadataInfo.cpp │ ├── CMakeLists.txt │ ├── DAE │ └── DAEUtils.cpp │ ├── Loops │ ├── CMakeLists.txt │ └── ForcedLoopUnroll.cpp │ └── Transform │ └── BranchMerge │ └── BranchMerge.cpp ├── experiments └── swoop │ └── sources │ ├── Makefile │ ├── common │ ├── Makefile.environment │ └── SWOOP │ │ ├── Makefile.defaults │ │ └── Makefile.targets │ └── myBenchmark │ └── src │ ├── Makefile │ └── small_benchmark.cpp └── setup.sh /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | #==============================================================================# 3 | # Directories to ignore (do not add trailing '/'s, they skip symlinks). 4 | #==============================================================================# 5 | # Build directory 6 | build 7 | 8 | #==============================================================================# 9 | # File extensions to be ignored anywhere in the tree. 10 | #==============================================================================# 11 | # Temp files created by most text editors. 12 | *~ 13 | \#* 14 | # Merge files created by git. 15 | *.orig 16 | # Byte compiled python modules. 17 | *.pyc 18 | # vim swap files 19 | .*.swp 20 | .sw? 21 | #OS X specific files. 22 | .DS_store 23 | 24 | 25 | *.ll -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Eta Scale Open Source License 2 | 3 | By accessing or using the software that is licensed under the terms of this 4 | document ("Eta Scale Software") in any form you expressly undertake to be bound 5 | by these license terms. If you use the code on behalf of a business, you agree 6 | to these license terms both in person and on behalf of that business and you 7 | represent that you have the authority to do so. 8 | 9 | 1) Alternative License 10 | 11 | Eta Scale Software is distributed under a dual-license scheme, 12 | an open source license for academic research and a commercial license 13 | for any commercial setting or commercial application. 14 | This document is the open source license for academic research. 15 | 16 | If you are interested in the commercial license, please contact 17 | Eta Scale AB by email: contact@etascale.com 18 | 19 | 2) No warranties 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 24 | PARTICULAE PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 25 | SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 26 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 30 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 31 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | POSSIBILITY OF SUCH DAMAGE. 33 | 34 | 3) Copyleft for Software Distribution 35 | 36 | Redistribution and use in source and binary forms, with or without 37 | modification, are permitted provided that the following conditions 38 | are met: 39 | 40 | Redistributions of source code must retain all conditions of the 41 | Eta Scale Open Source License. Redistributions in binary form must 42 | reproduce the terms of the Eta Scale Open Source License in the 43 | documentation and/or other materials provided with the distribution. 44 | Neither redistributions in source code or in binary form may impose 45 | any further restrictions on the exercise of the rights granted or 46 | affirmed under the Eta Scale Open Source License. 47 | 48 | Redistributions in any form must be accompanied by information on how to 49 | obtain complete source code for the Eta Scale Software and any 50 | accompanying software that uses the Eta Scale Software. The source code 51 | must either be included in the distribution or be available for no 52 | more than the cost of distribution. For an executable file, complete 53 | source code means the source code for all modules it contains. It does 54 | not include source code for modules or files that typically accompany 55 | the major components of the operating system on which the executable 56 | file runs. 57 | 58 | Neither the name Eta Scale, nor the names of any of its projects or 59 | contributors may be used to endorse or promote products derived from 60 | Eta Scale Software without specific prior written permission. 61 | 62 | 4) Copyleft for Software Users 63 | 64 | Notwithstanding any other provision of the Eta Scale Open Source 65 | License, if you modify the Eta Scale Software, your modified version 66 | must prominently offer all users interacting with it an opportunity to 67 | receive the corresponding source code of your version. 68 | If the interaction happens remotely through a computer network (if 69 | your version supports such interaction) an opportunity to receive the 70 | corresponding source code of your version by providing access to the 71 | corresponding source code from a network server at no charge, through 72 | some standard or customary means of facilitating copying of software. 73 | 74 | 5) License for Contributions 75 | 76 | For any of your modifications or other derivations of the Eta Scale 77 | Software source code ("your Contributions"), you grant Eta Scale AB a 78 | non-exclusive, irrevocable, worldwide, no-charge, transferable license 79 | to use, execute, create derivative works of, and distribute 80 | (internally and externally) or otherwise use commercially or 81 | non-commercially your Contributions, in any form (including, but not 82 | limited to binary and source code forms). 83 | Except for the rights granted to Eta Scale AB in this paragraph, you 84 | reserve all rights, title and interest in and to your Contributions. 85 | 86 | 6) Non-Severability of the Eta Scale Open Source License 87 | 88 | If any part of the Eta Scale Open Source License is invalid, or becomes 89 | invalid, then the entire license shall become invalid, and any rights 90 | you derived from the Eta Scale Open Source License shall be null and 91 | void. This shall not affect the License for your Contributions that you 92 | have given according to Section 5 of the Eta Scale Open Source License, 93 | which shall remain valid even if the Eta Scale Open Source License 94 | itself is invalid, or becomes invalid. 95 | 96 | 7) Choice of Law 97 | 98 | This license shall be governed by the laws of Sweden, excluding choice 99 | of law provisions. 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Clairvoyance 2 | 3 | Clairvoyance1 provides passes for instruction scheduling targeting long latency loads. 4 | It is currently being developed at Uppsala University. 5 | 6 | More infos to come. 7 | 8 | [1] Clairvoyance: Look-ahead Compile-Time Scheduling 9 | 10 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # All Vagrant configuration is done below. The "2" in Vagrant.configure 5 | # configures the configuration version (we support older styles for 6 | # backwards compatibility). Please don't change it unless you know what 7 | # you're doing. 8 | Vagrant.configure("2") do |config| 9 | # The most common configuration options are documented and commented below. 10 | # For a complete reference, please see the online documentation at 11 | # https://docs.vagrantup.com. 12 | 13 | # Every Vagrant development environment requires a box. You can search for 14 | # boxes at https://atlas.hashicorp.com/search. 15 | config.vm.box = "bento/ubuntu-16.04" 16 | 17 | # Disable automatic box update checking. If you disable this, then 18 | # boxes will only be checked for updates when the user runs 19 | # `vagrant box outdated`. This is not recommended. 20 | # config.vm.box_check_update = false 21 | 22 | # Create a forwarded port mapping which allows access to a specific port 23 | # within the machine from a port on the host machine. In the example below, 24 | # accessing "localhost:8080" will access port 80 on the guest machine. 25 | # config.vm.network "forwarded_port", guest: 80, host: 8080 26 | 27 | # Create a private network, which allows host-only access to the machine 28 | # using a specific IP. 29 | # config.vm.network "private_network", ip: "192.168.33.10" 30 | 31 | # Create a public network, which generally matched to bridged network. 32 | # Bridged networks make the machine appear as another physical device on 33 | # your network. 34 | # config.vm.network "public_network" 35 | 36 | # Share an additional folder to the guest VM. The first argument is 37 | # the path on the host to the actual folder. The second argument is 38 | # the path on the guest to mount the folder. And the optional third 39 | # argument is a set of non-required options. 40 | # config.vm.synced_folder "../data", "/vagrant_data" 41 | 42 | # Provider-specific configuration so you can fine-tune various 43 | # backing providers for Vagrant. These expose provider-specific options. 44 | # Example for VirtualBox: 45 | # 46 | config.vm.provider "virtualbox" do |vb| 47 | # # Display the VirtualBox GUI when booting the machine 48 | # vb.gui = true 49 | 50 | # # Customize the amount of memory on the VM: 51 | vb.memory = 4096 52 | vb.cpus = 2 53 | end 54 | # 55 | # View the documentation for the provider you are using for more 56 | # information on available options. 57 | 58 | # Define a Vagrant Push strategy for pushing to Atlas. Other push strategies 59 | # such as FTP and Heroku are also available. See the documentation at 60 | # https://docs.vagrantup.com/v2/push/atlas.html for more information. 61 | # config.push.define "atlas" do |push| 62 | # push.app = "YOUR_ATLAS_USERNAME/YOUR_APPLICATION_NAME" 63 | # end 64 | 65 | # Enable provisioning with a shell script. Additional provisioners such as 66 | # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the 67 | # documentation for more information about their specific syntax and use. 68 | # config.vm.provision "shell", inline: <<-SHELL 69 | # apt-get update 70 | # apt-get install -y apache2 71 | # SHELL 72 | 73 | config.vm.provision :shell, :path => "setup.sh" 74 | end 75 | -------------------------------------------------------------------------------- /compiler/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) Eta Scale AB. Licensed under the Eta Scale Open Source License. See the LICENSE file for details. 2 | 3 | #------------------------------------------------------------------------------ 4 | # CMakeLists.txt 5 | #------------------------------------------------------------------------------ 6 | # This file was taken and adapted from a tutorial at the Imperial College London 7 | # 8 | # [1] https://github.com/delcypher/srg-llvm-pass-tutorial 9 | # 10 | cmake_minimum_required(VERSION 2.8.12) 11 | 12 | #------------------------------------------------------------------------------ 13 | # FindLLVM 14 | #------------------------------------------------------------------------------ 15 | # If building against a locally built version of LLVM (this must be built with 16 | # CMake not and not the Autoconf/Makefile build system) you need to set the 17 | # LLVM_DIR cache variable that find_package(LLVM ...) introduces. 18 | # E.g. 19 | # cmake -DLLVM_DIR:PATH=/path/to/llvm/build/share/llvm/cmake /path/to/this_projects_source_directory 20 | find_package(LLVM REQUIRED) 21 | 22 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 23 | 24 | if ( "${LLVM_PACKAGE_VERSION}" VERSION_LESS "3.5" ) 25 | message(FATAL_ERROR "Need LLVM >=3.5") 26 | endif() 27 | 28 | include_directories("${LLVM_INCLUDE_DIRS}") 29 | message(STATUS "LLVM_INCLUDE_DIRS is ${LLVM_INCLUDE_DIRS}") 30 | 31 | message(STATUS "LLVM_TOOLS_BINARY_DIR is ${LLVM_TOOLS_BINARY_DIR}") 32 | 33 | #------------------------------------------------------------------------------ 34 | # Set compiler flags 35 | #------------------------------------------------------------------------------ 36 | # This unfortunately doesn't add much 37 | add_definitions(${LLVM_DEFINITIONS}) 38 | 39 | include(CheckCXXCompilerFlag) 40 | macro(add_cxx_flag flag name) 41 | CHECK_CXX_COMPILER_FLAG(${flag} "${name}_SUPPORTED") 42 | if("${name}_SUPPORTED") 43 | add_definitions(${flag}) 44 | else() 45 | message(FATAL_ERROR "${flag} flag is not supported by ${CMAKE_CXX_COMPILER}") 46 | endif() 47 | endmacro() 48 | 49 | # FIXME: Setting flags this way isn't very portable 50 | if (NOT LLVM_ENABLE_RTTI) 51 | message(STATUS "LLVM was built without RTTI, so we must disable it too for linking to work properly") 52 | add_cxx_flag(-fno-rtti RTTI) # Can't use LLVMSupport properly if we have rtti 53 | endif() 54 | add_cxx_flag(-std=c++11 CXX11) 55 | 56 | #------------------------------------------------------------------------------ 57 | # Handy macro to copy files matching a globbing pattern in the current source 58 | # source directory to the current build directory 59 | #------------------------------------------------------------------------------ 60 | macro(copy_files_to_build_dir GLOBS) 61 | file(GLOB ABSOLUTE_PATH_TO_FILES_TO_COPY ${ARGV}) 62 | 63 | foreach(file ${ABSOLUTE_PATH_TO_FILES_TO_COPY}) 64 | get_filename_component(filename ${file} NAME) 65 | configure_file(${filename} ${filename} COPYONLY) 66 | endforeach() 67 | endmacro() 68 | 69 | #------------------------------------------------------------------------------ 70 | # Warn if clang is not available 71 | #------------------------------------------------------------------------------ 72 | if (NOT EXISTS "${LLVM_TOOLS_BINARY_DIR}/clang") 73 | message(WARNING "Clang was not found in LLVM_TOOLS_BINARY_DIR. Many of the demo scripts won't work without this") 74 | endif() 75 | 76 | #------------------------------------------------------------------------------ 77 | # Manage library output directories 78 | #------------------------------------------------------------------------------ 79 | 80 | set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib ) 81 | set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib ) 82 | 83 | #------------------------------------------------------------------------------ 84 | # Projects 85 | #------------------------------------------------------------------------------ 86 | 87 | add_subdirectory(projects) 88 | # add_subdirectory(tools) # remove for artifact evaluation 89 | -------------------------------------------------------------------------------- /compiler/LICENSE.TXT: -------------------------------------------------------------------------------- 1 | ============================================================================== 2 | LLVM Release License 3 | ============================================================================== 4 | University of Illinois/NCSA 5 | Open Source License 6 | 7 | Copyright (c) 2003-2015 University of Illinois at Urbana-Champaign. 8 | All rights reserved. 9 | 10 | Developed by: 11 | 12 | LLVM Team 13 | 14 | University of Illinois at Urbana-Champaign 15 | 16 | http://llvm.org 17 | 18 | Permission is hereby granted, free of charge, to any person obtaining a copy of 19 | this software and associated documentation files (the "Software"), to deal with 20 | the Software without restriction, including without limitation the rights to 21 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 22 | of the Software, and to permit persons to whom the Software is furnished to do 23 | so, subject to the following conditions: 24 | 25 | * Redistributions of source code must retain the above copyright notice, 26 | this list of conditions and the following disclaimers. 27 | 28 | * Redistributions in binary form must reproduce the above copyright notice, 29 | this list of conditions and the following disclaimers in the 30 | documentation and/or other materials provided with the distribution. 31 | 32 | * Neither the names of the LLVM Team, University of Illinois at 33 | Urbana-Champaign, nor the names of its contributors may be used to 34 | endorse or promote products derived from this Software without specific 35 | prior written permission. 36 | 37 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 38 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 39 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 40 | CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 41 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 42 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE 43 | SOFTWARE. 44 | 45 | ============================================================================== 46 | Copyrights and Licenses for Third Party Software Distributed with LLVM: 47 | ============================================================================== 48 | The LLVM software contains code written by third parties. Such software will 49 | have its own individual LICENSE.TXT file in the directory in which it appears. 50 | This file will describe the copyrights, license, and restrictions which apply 51 | to that code. 52 | 53 | The disclaimer of warranty in the University of Illinois Open Source License 54 | applies to all code in the LLVM Distribution, and nothing in any of the 55 | other licenses gives permission to use the names of the LLVM Team or the 56 | University of Illinois to endorse or promote products derived from this 57 | Software. 58 | 59 | The following pieces of software have additional or alternate copyrights, 60 | licenses, and/or restrictions: 61 | 62 | Program Directory 63 | ------- --------- 64 | Autoconf llvm/autoconf 65 | llvm/projects/ModuleMaker/autoconf 66 | Google Test llvm/utils/unittest/googletest 67 | OpenBSD regex llvm/lib/Support/{reg*, COPYRIGHT.regex} 68 | pyyaml tests llvm/test/YAMLParser/{*.data, LICENSE.TXT} 69 | ARM contributions llvm/lib/Target/ARM/LICENSE.TXT 70 | md5 contributions llvm/lib/Support/MD5.cpp llvm/include/llvm/Support/MD5.h 71 | -------------------------------------------------------------------------------- /compiler/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) Eta Scale AB. Licensed under the Eta Scale Open Source License. See the LICENSE file for details. 2 | 3 | #------------------------------------------------------------------------------ 4 | # Makefile 5 | #------------------------------------------------------------------------------ 6 | # Building the swoop project 7 | # 8 | COMPILER_DIR=$(shell pwd) 9 | BUILD_DIR=$(COMPILER_DIR)/build 10 | 11 | LLVM_DIR=$(COMPILER_DIR)/llvm 12 | LLVM_BUILD_DIR=$(BUILD_DIR)/llvm-build 13 | LLVM_LIB_DIR=$(LLVM_BUILD_DIR)/lib 14 | LLVM_BUILD_MAKEFILE=$(LLVM_BUILD_DIR)/Makefile 15 | LLVM_CMAKE_PATH=$(LLVM_BUILD_DIR)/share/llvm/cmake/ 16 | 17 | CLANG_LIB=$(LLVM_LIB_DIR)/libclang.so 18 | 19 | BUILD_TYPE?=MinSizeRel 20 | 21 | GIT_MAJOR:=$(shell git --version | cut -d ' ' -f 3 | cut -d '.' -f 1) 22 | ifeq ($(shell test $(GIT_MAJOR) -ge 2; echo $$?),0) 23 | GIT_SHALLOW=1 24 | else 25 | GIT_SHALLOW=0 26 | endif 27 | 28 | #------------------------------------------------------------------------------ 29 | # LLVM tools: Clang, Compiler-rt 30 | #------------------------------------------------------------------------------ 31 | # 32 | 33 | LLVM_REPOSITORY=https://github.com/llvm-mirror/llvm.git 34 | LLVM_RELEASE=release_38 35 | 36 | LLVM_TOOLS=$(LLVM_DIR)/tools 37 | CLANG=$(LLVM_TOOLS)/clang 38 | CLANG_REPOSITORY=http://llvm.org/git/clang.git 39 | 40 | LLVM_PROJECTS=$(LLVM_DIR)/projects 41 | COMPILER_RT=$(LLVM_PROJECTS)/compiler-rt 42 | COMPILER_RT_REPOSITORY=http://llvm.org/git/compiler-rt.git 43 | 44 | OMP=$(LLVM_PROJECTS)/openmp 45 | OMP_REPOSITORY=https://github.com/llvm-mirror/openmp.git 46 | 47 | TOOL_RELEASE=release_38 48 | 49 | #------------------------------------------------------------------------------ 50 | # Projects 51 | #------------------------------------------------------------------------------ 52 | # 53 | PROJECTS_DIR=$(COMPILER_DIR) 54 | PROJECTS_BUILD_DIR=$(BUILD_DIR)/projects-build 55 | PROJECTS_BUILD_MAKEFILE=$(PROJECTS_BUILD_DIR)/Makefile 56 | 57 | #------------------------------------------------------------------------------ 58 | # OTHERS 59 | #------------------------------------------------------------------------------ 60 | # 61 | 62 | all: $(PROJECTS_BUILD_MAKEFILE) 63 | $(MAKE) -C $(PROJECTS_BUILD_DIR) 64 | 65 | $(CLANG_LIB): $(LLVM_BUILD_MAKEFILE) 66 | $(MAKE) -C $(LLVM_BUILD_DIR) 67 | 68 | $(LLVM_BUILD_MAKEFILE): $(LLVM_DIR)/Makefile $(CLANG) $(COMPILER_RT) $(OMP) 69 | mkdir -p $(LLVM_BUILD_DIR) 70 | cd $(LLVM_BUILD_DIR); cmake -D CMAKE_BUILD_TYPE=$(BUILD_TYPE) -DLLVM_BINUTILS_INCDIR=/usr/include $(LLVM_DIR); 71 | 72 | $(LLVM_DIR)/Makefile: 73 | ifeq ($(GIT_SHALLOW),1) 74 | # # Disable shallow cloning of a specific version 75 | # # This should be fixed with Git 2.5+ 76 | # # From http://stackoverflow.com/a/30701724 http://stackoverflow.com/questions/14872486/pull-a-specific-commit-from-a-remote-git-repository 77 | git clone -b $(LLVM_RELEASE) --depth 1 $(LLVM_REPOSITORY) $(LLVM_DIR); 78 | # # From http://stackoverflow.com/questions/3489173/how-to-clone-git-repository-with-specific-revision-changeset 79 | # mkdir $(LLVM_DIR) 80 | # git init $(LLVM_DIR) 81 | # git --git-dir=$(LLVM_DIR)/.git --work-tree=$(LLVM_DIR) remote add origin $(LLVM_REPOSITORY) 82 | # git --git-dir=$(LLVM_DIR)/.git --work-tree=$(LLVM_DIR) fetch --depth 1 origin $(LLVM_RELEASE) 83 | # git --git-dir=$(LLVM_DIR)/.git --work_tree=$(LLVM_DIR) reset --hard FETCH_HEAD 84 | else 85 | git clone $(LLVM_REPOSITORY) $(LLVM_DIR) -b $(LLVM_RELEASE); 86 | endif 87 | 88 | $(CLANG): $(LLVM_DIR)/CMakeLists.txt 89 | ifeq ($(GIT_SHALLOW),1) 90 | cd $(LLVM_TOOLS); git clone -b $(TOOL_RELEASE) --depth 1 $(CLANG_REPOSITORY); 91 | else 92 | cd $(LLVM_TOOLS); git clone $(CLANG_REPOSITORY) -b $(TOOL_RELEASE); 93 | endif 94 | 95 | $(COMPILER_RT): $(LLVM_DIR)/CMakeLists.txt 96 | ifeq ($(GIT_SHALLOW),1) 97 | cd $(LLVM_PROJECTS); git clone -b $(TOOL_RELEASE) --depth 1 $(COMPILER_RT_REPOSITORY); 98 | else 99 | cd $(LLVM_PROJECTS); git clone $(COMPILER_RT_REPOSITORY) -b $(TOOL_RELEASE); 100 | endif 101 | 102 | $(OMP): $(LLVM_DIR)/CMakeLists.txt 103 | ifeq ($(GIT_SHALLOW),1) 104 | cd $(LLVM_PROJECTS); git clone -b $(TOOL_RELEASE) --depth 1 $(OMP_REPOSITORY); 105 | else 106 | cd $(LLVM_PROJECTS); git clone $(OMP_REPOSITORY) -b $(TOOL_RELEASE); 107 | endif 108 | 109 | 110 | $(PROJECTS_BUILD_MAKEFILE): $(CLANG_LIB) 111 | mkdir -p $(PROJECTS_BUILD_DIR) 112 | cd $(PROJECTS_BUILD_DIR); cmake -DLLVM_DIR:STRING=$(LLVM_CMAKE_PATH) -D CMAKE_BUILD_TYPE=$(BUILD_TYPE) -DLLVM_TARGETS_TO_BUILD=$(TARGETS_TO_BUILD) $(PROJECTS_DIR); 113 | clean: 114 | rm -rf $(PROJECTS_BUILD_DIR) 115 | 116 | veryclean: 117 | rm -rf $(BUILD_DIR) 118 | -------------------------------------------------------------------------------- /compiler/README.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) Eta Scale AB. Licensed under the Eta Scale Open Source License. See the LICENSE file for details. 2 | 3 | Compiler Repository 4 | 5 | Installation 6 | ------------ 7 | Run: 8 | make 9 | 10 | Running make will generate a separate build directory that 11 | contains all binaries for llvm and the projects. 12 | 13 | Packages 14 | -------- 15 | o llvm - llvm source code 16 | o projects - llvm passes for different projects 17 | 18 | Other 19 | ------- 20 | o setup.sh - for build system (ignore) 21 | o package.sh - for build system (ignore) 22 | 23 | Contact 24 | ------- 25 | Kim-Anh Tran : kim-anh.tran@it.uu.se 26 | -------------------------------------------------------------------------------- /compiler/projects/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) Eta Scale AB. Licensed under the Eta Scale Open Source License. See the LICENSE file for details. 3 | set(PROJECTS_MAIN_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src) 4 | set(PROJECTS_MAIN_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) 5 | 6 | include_directories(${PROJECTS_MAIN_INCLUDE_DIR}) 7 | 8 | add_subdirectory(src) 9 | -------------------------------------------------------------------------------- /compiler/projects/include/DAE/Utils/SkelUtils/headers.h: -------------------------------------------------------------------------------- 1 | //===- headers.h - General includes for DAE ---------- --------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file headers.h 10 | /// 11 | /// \brief General includes for DAE 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | //===----------------------------------------------------------------------===// 16 | #include "llvm/ADT/SmallVector.h" 17 | #include "llvm/ADT/Statistic.h" 18 | #include "llvm/Analysis/LoopPass.h" 19 | #include "llvm/Analysis/ScalarEvolution.h" 20 | #include "llvm/IR/Dominators.h" 21 | #include "llvm/Pass.h" 22 | #include "llvm/Support/CommandLine.h" 23 | #include "llvm/Support/Debug.h" 24 | #include "llvm/Support/FileSystem.h" 25 | #include "llvm/Transforms/Scalar.h" 26 | #include "llvm/Transforms/Utils/Local.h" 27 | #include "llvm/Transforms/Utils/SSAUpdater.h" 28 | 29 | #include "llvm/Analysis/LoopInfo.h" 30 | #include "llvm/IR/Argument.h" 31 | #include "llvm/IR/Attributes.h" 32 | #include "llvm/IR/BasicBlock.h" 33 | #include "llvm/IR/CallingConv.h" 34 | #include "llvm/IR/DerivedTypes.h" 35 | #include "llvm/IR/Function.h" 36 | #include "llvm/IR/GlobalValue.h" 37 | #include "llvm/IR/IRBuilder.h" 38 | #include "llvm/IR/InlineAsm.h" 39 | #include "llvm/IR/InstIterator.h" 40 | #include "llvm/IR/Instruction.h" 41 | #include "llvm/IR/Instructions.h" 42 | #include "llvm/IR/LLVMContext.h" 43 | #include "llvm/IR/Metadata.h" 44 | #include "llvm/IR/Module.h" 45 | #include "llvm/IR/Type.h" 46 | #include "llvm/Support/Compiler.h" 47 | #include "llvm/Support/raw_ostream.h" 48 | 49 | #include "llvm/IR/AssemblyAnnotationWriter.h" 50 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" 51 | #include "llvm/Transforms/Utils/Cloning.h" 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | -------------------------------------------------------------------------------- /compiler/projects/include/SWOOP/Transform/SwoopDAE/BasicSwoop.h: -------------------------------------------------------------------------------- 1 | //===------- BasicSwoop.h - basic and conservative swoop ------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file BasicSwoop.h 10 | /// 11 | /// \brief Basic and conservative Swoop version. 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | // 16 | // Basic swoop: conservatively hoisting & reusing loads. 17 | // 18 | //===----------------------------------------------------------------------===// 19 | 20 | #ifndef SWOOP_BASICSWOOP_H 21 | #define SWOOP_BASICSWOOP_H 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "Util/Analysis/LoopCarriedDependencyAnalysis.h" 31 | #include "Util/Annotation/MetadataInfo.h" 32 | #include "Util/DAE/DAEUtils.h" 33 | #include "Util/Analysis/LoopDependency.h" 34 | 35 | #include 36 | #include 37 | #include "llvm/Analysis/PostDominators.h" 38 | #include "llvm/Analysis/CFG.h" 39 | #include "llvm/IR/InlineAsm.h" 40 | #include "llvm/IR/Instructions.h" 41 | #include "llvm/IR/IRBuilder.h" 42 | #include "llvm/Transforms/Utils/ValueMapper.h" 43 | 44 | using namespace llvm; 45 | using namespace std; 46 | using namespace util; 47 | 48 | namespace swoop { 49 | 50 | // Helper struct: represents a phase (in multi-access) 51 | struct Phase { 52 | public: 53 | // The function clone 54 | Function *F; 55 | 56 | // The mapping between the cloned function and F (and backwards) 57 | ValueToValueMapTy VMap; 58 | ValueToValueMapTy VMapRev; 59 | 60 | // Keeps track of which loads in F should be reused (A: load, E: use), 61 | // prefetched (A: prefetch, E: load), or just loaded (A: load, E: load). 62 | list ToReuse; 63 | list ToPref; 64 | list ToLoad; 65 | }; 66 | 67 | struct SwoopDAE : public ModulePass{ 68 | static char ID; 69 | SwoopDAE() : ModulePass(ID) {} 70 | 71 | public: 72 | virtual bool runOnModule(Module &M); 73 | virtual void getAnalysisUsage(AnalysisUsage &AU) const override; 74 | 75 | // Main functionality: swoopifying function F 76 | bool swoopify(Function &F); 77 | 78 | protected: 79 | LoopInfo *LI; 80 | 81 | // Alias Analysis 82 | AliasAnalysis *AA; 83 | 84 | // Dominator Tree 85 | DominatorTree *DT; 86 | 87 | // Postdom Tree 88 | PostDominatorTree *PDT; 89 | 90 | //////// 91 | // Heuristic: is it worth transforming? 92 | //////// 93 | bool isWorthTransforming(Function &F, list &Loads); 94 | 95 | // Divide loads into each category: prefetch, reuse or load 96 | virtual void divideLoads(list &toHoist, 97 | list &toPref, 98 | list &toReuse, 99 | list &toLoad, 100 | unsigned int UnrollCount); 101 | 102 | // Returns true iff F is a swoop kernel. 103 | virtual bool isSwoopKernel(Function &F); 104 | 105 | // Returns which instructions to reuse in terms of lcd 106 | virtual LCDResult acceptedForReuse(); 107 | 108 | // Determines which instructions to reuse in the execute phase 109 | virtual void selectInstructionsToReuseInExecute(Function *F, set *toKeep, set *toUpdateForNextPhases, LCDResult MinLCDRequirement, bool ReuseAll, bool ReuseBranchCondition); 110 | 111 | //////// 112 | // Filtering on Loop-carried dependencies 113 | //////// 114 | virtual void filterLoadsOnLCD(AliasAnalysis *AA, 115 | LoopInfo *LI, 116 | list &Loads, 117 | list &FilteredLoads, 118 | unsigned int UnrollCount); 119 | 120 | private: 121 | 122 | //////// 123 | // Reusing functionality: 124 | // //// 125 | 126 | // Find redundant instructions in toKeep and insert them into remove. 127 | // Update VMapRev accordingly. 128 | void findRedundantInsts(ValueToValueMapTy &VMap, 129 | ValueToValueMapTy &VMapRev, 130 | set &toKeep, 131 | set &toRemove); 132 | 133 | // Remove toRemove in function F 134 | void removeListed(Function &F, set &toRemove, ValueToValueMapTy &VMap); 135 | 136 | // Returns true if I should be reused in the execute phase 137 | bool IsReuseInstruction(Instruction *I, bool ReuseAll, bool ReuseBranchCondition); 138 | 139 | //////// 140 | // Inserting prefetches, reuses, loads 141 | //////// 142 | 143 | int insertPrefetches(list &toPref, set &toKeep, 144 | bool printRes = false, bool onlyPrintOnSuccess = false); 145 | int insertReuse(list &toReuse, set &toKeep); 146 | 147 | // Removes all instructions marked as a reuse helper. See insertReuse. 148 | void removeReuseHelper(Function &F); 149 | 150 | // Selects which instructions toKeep from the phase that starts at the bloc PhaseEntryBB 151 | void selectInstructionsToReuseWithinAccess(Function *F, set *toKeep, set *toUpdateForNextPhases, 152 | LCDResult MinLCDRequirement, bool ReuseAll = true, bool ReuseBranchCondition = false); 153 | 154 | //////// 155 | // Creating phases 156 | //////// 157 | 158 | // Swoopify function F with loads in toHoist. Expects all 159 | // analysis data to be set up. 160 | bool swoopifyCore(Function &F, list toHoist); 161 | 162 | Phase* createAccessExecuteFunction(Function &F, 163 | list> &toHoist, 164 | vector &PhaseRoots, 165 | AllocaInst *branch_cond, 166 | bool mergeBranches); 167 | 168 | Phase * createAccessPhases(vector &AccessPhases, 169 | Phase &ExecutePhase, 170 | vector &PhaseRoots); 171 | 172 | bool createAndAppendExecutePhase(Phase *MainPhase, Phase *ExecutePhase, vector &PhaseRoots); 173 | 174 | // Initializes AccessPhases for function F and the set of loads in toHoist 175 | void initAccessPhases(Function &F, list &toHoist, vector &AccessPhases, AllocaInst *branch_cond, bool mergeBranches); 176 | 177 | // Splits up the laods in toHoist into separate sets, each representing a phase 178 | void identifyPhaseLoads(list &toHoist, vector *> &AccessPhases, AllocaInst *branch_cond, bool mergeBranches); 179 | 180 | // Creates a phase with all loads in Loads that are required for the loop's CFG 181 | bool CreatePhaseWithCFGLoads(set &Loads, set &NewPhase, AllocaInst *branch_cond, bool mergeBranches); 182 | 183 | // Creates the access phase P: according to its list of loads to prefetch, reuse and load 184 | bool createAccessPhase(Phase &P, bool isMain); 185 | 186 | // Append one phase to the other; thereby reusing the values in toKeep that are already 187 | // computed in Access 188 | void combinePhases(Phase &Access, Phase &ToAppend, set &toKeep, 189 | string type, int phaseCount); 190 | 191 | // Update the VMaps for all values in toKeep and each following 192 | // phase to map to the values that P maps to. 193 | bool updateSucceedingAccessMaps(Phase &P, vector &PhasesToUpdate, 194 | set &toKeep); 195 | }; 196 | } 197 | 198 | #endif 199 | -------------------------------------------------------------------------------- /compiler/projects/include/Util/Analysis/AliasUtils.h: -------------------------------------------------------------------------------- 1 | //===------ AliasUtils.h - Utils for alias analysis ---------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file AliasUtils.hy 10 | /// 11 | /// \brief Utilities for alias analysis 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | // 16 | // 17 | //===----------------------------------------------------------------------===// 18 | 19 | #ifndef UTIL_ANALYSIS_ALIASUTILS_H 20 | #define UTIL_ANALYSIS_ALIASUTILS_H 21 | 22 | #include 23 | 24 | #include "Util/Annotation/MetadataInfo.h" 25 | 26 | #include 27 | #include 28 | 29 | using namespace std; 30 | using namespace llvm; 31 | 32 | namespace util { 33 | // Checks if two pointers alias 34 | AliasResult pointerAlias(AliasAnalysis *AA, Value *P1, Value *P2, const DataLayout &DL); 35 | 36 | // Returns the closest alias between store and any of the LoadInsts 37 | // in toPref. 38 | AliasResult crossCheck(AliasAnalysis *AA, StoreInst *store, list &toPref); 39 | 40 | // Anotates stores in fun with the closest alias type to 41 | // any of the loads in toPref. (To be clear alias analysis are 42 | // performed between the address of each store and the address 43 | // of each load.) Results are annotated as metadata. 44 | void anotateStores(AliasAnalysis *AA, Function &fun, list &toPref); 45 | } 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /compiler/projects/include/Util/Analysis/LoopCarriedDependencyAnalysis.h: -------------------------------------------------------------------------------- 1 | //===- LoopCarriedDependencyAnalysis.h - LCD Analysis Interface -*- C++ -*-===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file LoopCarriedDependencyAnalysis.h 10 | /// 11 | /// \brief LCD Analysis Interface 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | // 16 | // This file defines the generic LoopCarriedDependencyAnalysis interface, which 17 | // is used as the common interface used by all clients of loop carried 18 | // dependency 19 | // information, and implemented by all loop carried dependency analysis 20 | // implementations. 21 | // 22 | //===----------------------------------------------------------------------===// 23 | 24 | #ifndef UTIL_ANALYSIS_LCDANALYSIS_H 25 | #define UTIL_ANALYSIS_LCDANALYSIS_H 26 | 27 | #include "llvm/Analysis/DependenceAnalysis.h" 28 | #include "llvm/Analysis/LoopInfo.h" 29 | #include "llvm/IR/Instructions.h" 30 | #include "llvm/IR/ValueMap.h" 31 | #include "llvm/PassRegistry.h" 32 | #include 33 | 34 | using namespace llvm; 35 | 36 | namespace util { 37 | 38 | enum LCDResult { 39 | NoLCD = 0, 40 | 41 | MayLCD, 42 | 43 | MustLCD, 44 | 45 | END 46 | 47 | }; 48 | 49 | static const int LCDResultCount = LCDResult::END - LCDResult::NoLCD; 50 | static const std::string LCDStrings[] = {"NoLCD", "MayLCD", "MustLCD"}; 51 | static const std::string getStringRep(int enumVal) { return LCDStrings[enumVal]; } 52 | 53 | static LCDResult fromString(std::string representation) { 54 | for (int i = 0; i < LCDResultCount; ++i) { 55 | if (LCDStrings[i].compare(representation) == 0) { 56 | return static_cast(i); 57 | } 58 | } 59 | 60 | return LCDResult::END; 61 | } 62 | 63 | class LoopCarriedDependencyAnalysis { 64 | 65 | public: 66 | bool isNoLCD(Instruction *I, const Loop *L) { 67 | return checkLCD(I, L) == NoLCD; 68 | } 69 | 70 | bool isMustLCD(Instruction *I, const Loop *L) { 71 | return checkLCD(I, L) == MustLCD; 72 | } 73 | 74 | bool isMayLCD(Instruction *I, const Loop *L) { 75 | return checkLCD(I, L) == MayLCD; 76 | } 77 | 78 | static LCDResult combineLCD(LCDResult A, LCDResult B) { 79 | return static_cast(std::max(A, B)); 80 | } 81 | 82 | virtual const LCDResult checkLCD(Instruction *I, const Loop *L) = 0; 83 | virtual bool getLCDDistance(Instruction *I, const Loop *L, 84 | long int &Distance) = 0; 85 | virtual void setup(Function &F) = 0; 86 | 87 | protected: 88 | bool collectMemInst(const Loop &L, SmallVectorImpl &MemInst) { 89 | for (Loop::block_iterator BB = L.block_begin(), BE = L.block_end(); BB != BE; 90 | ++BB) { 91 | for (BasicBlock::iterator I = (*BB)->begin(), E = (*BB)->end(); I != E; 92 | ++I) { 93 | Instruction *Ins = dyn_cast(I); 94 | if (!Ins) { 95 | continue; 96 | } 97 | 98 | if (isa(I) || isa(I)) { 99 | MemInst.push_back(&*I); 100 | } 101 | } 102 | } 103 | 104 | return true; 105 | } 106 | }; 107 | 108 | class LoopCarriedDependencyAnalysisWrapperPass : public FunctionPass { 109 | private: 110 | LoopCarriedDependencyAnalysis *LCDAnalysis; 111 | 112 | public: 113 | static char ID; 114 | 115 | LoopCarriedDependencyAnalysisWrapperPass() 116 | : FunctionPass(ID), LCDAnalysis(NULL) { 117 | initializeLoopCarriedDependencyAnalysisWrapperPass(); 118 | } 119 | 120 | ~LoopCarriedDependencyAnalysisWrapperPass() { 121 | if (LCDAnalysis) { 122 | delete LCDAnalysis; 123 | } 124 | } 125 | 126 | LoopCarriedDependencyAnalysis &getLCDAnalysis() { return *LCDAnalysis; }; 127 | const LoopCarriedDependencyAnalysis &getLCDAnalysis() const { 128 | return *LCDAnalysis; 129 | }; 130 | 131 | bool runOnFunction(Function &F) override; 132 | void getAnalysisUsage(AnalysisUsage &AU) const override; 133 | 134 | private: 135 | virtual void initializeLoopCarriedDependencyAnalysisWrapperPass(); 136 | }; 137 | 138 | } // End namespace 139 | 140 | #endif 141 | -------------------------------------------------------------------------------- /compiler/projects/include/Util/Analysis/LoopDependency.h: -------------------------------------------------------------------------------- 1 | //===-------- LoopDependency.h - Requirements in Loop Iteration --===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file LoopDependency.h 10 | /// 11 | /// \brief 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | // 16 | // This file contains utility function to retrieve the requirements 17 | // of an instruction _within_ a loop iteration. Requirements include: 18 | // 1) data dependencies 19 | // 2) control dependencies (mandatory control dependencies) 20 | // 21 | //===----------------------------------------------------------------------===// 22 | 23 | #ifndef UTIL_ANALYSIS_LOOPDEPENDENCY_H 24 | #define UTIL_ANALYSIS_LOOPDEPENDENCY_H 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "llvm/Transforms/Utils/Cloning.h" 36 | 37 | #include "Util/Annotation/MetadataInfo.h" 38 | #include "Util/Analysis/AliasUtils.h" 39 | #include "Util/Analysis/LoopDependency.h" 40 | #include "Util/DAE/DAEUtils.h" 41 | 42 | #include "llvm/Analysis/PostDominators.h" 43 | #include "llvm/IR/IRBuilder.h" 44 | #include "llvm/Analysis/CFG.h" 45 | #include "llvm/Analysis/LoopInfo.h" 46 | 47 | using namespace std; 48 | using namespace llvm; 49 | 50 | namespace util { 51 | 52 | // Computes the _mandatory_ data dependencies for instruction I n_within_ a loop iteration 53 | void getDeps(AliasAnalysis *AA, LoopInfo *LI, Instruction *I, set &DepSet, bool followStores = true); 54 | 55 | // Computes the _mandatory_ control dependencies for instruction I _within_ a loop iteration 56 | void getControlDeps(AliasAnalysis *AA, LoopInfo *LI, Instruction *I, set &Deps); 57 | 58 | // Computes the _mandatory_ control and data dependencies for instruction I _within_ a loop iteration 59 | void getRequirementsInIteration(AliasAnalysis *AA, LoopInfo *LI, Instruction *I, set &DepSet, bool followStores = true); 60 | 61 | // Adds dependencies of the Instructions in Set to DepSet. 62 | // Dependencies are considered to be the operators of an Instruction 63 | // with the exceptions of calls. In case a LoadInst is a dependency 64 | // the coresponding StoreInst is also considered as a dependency 65 | // as long it does not operate on visible memory. 66 | // Retrurns false iff a prohibited instruction are required. 67 | // The contents of Set and DepSet are only reliable if the result 68 | // is true. 69 | bool followDeps(AliasAnalysis *AA, set &Set, set &DepSet, bool followStores = true, bool followCalls = true); 70 | 71 | // Convenience call 72 | bool followDeps(AliasAnalysis *AA, Instruction *Inst, set &DepSet); 73 | 74 | // Adds the Instructions in F that terminates a BasicBlock to CfgSet. 75 | void findTerminators(Function &F, set &CfgSet); 76 | } 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /compiler/projects/include/Util/Annotation/MetadataInfo.h: -------------------------------------------------------------------------------- 1 | //===- Util/Annotation/MetadataInfo.h - MetadataInfo Interface -*- C++ -*-===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file MetadataInfo.h 10 | /// 11 | /// \brief MetadataInfo Interface 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | // 16 | // This file defines utilities to read and attach metadata to instructions. 17 | //===----------------------------------------------------------------------===// 18 | 19 | #ifndef UTIL_ANNOTATION_METADATAINFO_H 20 | #define UTIL_ANNOTATION_METADATAINFO_H 21 | 22 | #include "llvm/ADT/SmallVector.h" 23 | #include "llvm/ADT/Statistic.h" 24 | #include "llvm/Analysis/LoopPass.h" 25 | #include "llvm/Analysis/ScalarEvolution.h" 26 | #include "llvm/IR/Dominators.h" 27 | #include "llvm/Pass.h" 28 | #include "llvm/Support/CommandLine.h" 29 | #include "llvm/Support/Debug.h" 30 | #include "llvm/Support/FileSystem.h" 31 | #include "llvm/Transforms/Scalar.h" 32 | #include "llvm/Transforms/Utils/Local.h" 33 | #include "llvm/Transforms/Utils/SSAUpdater.h" 34 | 35 | #include "llvm/Analysis/LoopInfo.h" 36 | #include "llvm/IR/Argument.h" 37 | #include "llvm/IR/Attributes.h" 38 | #include "llvm/IR/BasicBlock.h" 39 | #include "llvm/IR/CallingConv.h" 40 | #include "llvm/IR/DerivedTypes.h" 41 | #include "llvm/IR/Function.h" 42 | #include "llvm/IR/GlobalValue.h" 43 | #include "llvm/IR/IRBuilder.h" 44 | #include "llvm/IR/InlineAsm.h" 45 | #include "llvm/IR/InstIterator.h" 46 | #include "llvm/IR/Instruction.h" 47 | #include "llvm/IR/Instructions.h" 48 | #include "llvm/IR/LLVMContext.h" 49 | #include "llvm/IR/Metadata.h" 50 | #include "llvm/IR/Module.h" 51 | #include "llvm/IR/Type.h" 52 | #include "llvm/Support/Compiler.h" 53 | #include "llvm/Support/raw_ostream.h" 54 | 55 | #include "llvm/IR/AssemblyAnnotationWriter.h" 56 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" 57 | #include "llvm/Transforms/Utils/Cloning.h" 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | 70 | using namespace llvm; 71 | 72 | namespace util { 73 | 74 | bool InstrhasMetadataKind(Instruction *ii, std::string mdt); 75 | bool InstrhasMetadata(Instruction *ii, std::string mdt, std::string mdv); 76 | bool InstrhasMetadataSubstring(Instruction *ii, std::string mdt, 77 | std::string mdv); 78 | void AttachMetadata(Instruction *inst, std::string mdtype, std::string str); 79 | 80 | void AttachMetadataToAllInBlock(BasicBlock *b, std::string mdtype, 81 | std::string str); 82 | 83 | /* if I is a memory instruction it has an ID attached */ 84 | std::string getInstructionID(Instruction *I); 85 | 86 | /* if I is a memory instruction it has an IDphi attached */ 87 | std::string getInstructionIDphi(Instruction *I); 88 | 89 | std::string getInstructionMD(Instruction *I, const char *MDty); 90 | } 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /compiler/projects/include/Util/DAE/DAEUtils.h: -------------------------------------------------------------------------------- 1 | //===-------- DAEUtils.h - Utils for creating DAE-like loops -------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file DAEUtils.h 10 | /// 11 | /// \brief 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | // 16 | //===----------------------------------------------------------------------===// 17 | 18 | #ifndef UTIL_DAE_DAEUTILS_H 19 | #define UTIL_DAE_DAEUTILS_H 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "llvm/Transforms/Utils/Cloning.h" 31 | 32 | #include "Util/Annotation/MetadataInfo.h" 33 | #include "Util/Analysis/AliasUtils.h" 34 | #include "Util/Analysis/LoopDependency.h" 35 | #include "Util/DAE/DAEUtils.h" 36 | 37 | #include "llvm/IR/IRBuilder.h" 38 | #include "llvm/Analysis/CFG.h" 39 | 40 | using namespace std; 41 | 42 | #define F_KERNEL_SUBSTR "__kernel__" 43 | #define CLONE_SUFFIX "_clone" 44 | 45 | namespace util { 46 | enum PrefInsertResult { Inserted, BadDeps, IndirLimit, Redundant }; 47 | 48 | // Remove all instructions from F that are in KeepSet 49 | void removeUnlisted(Function &F, set &KeepSet); 50 | 51 | // Clones Function F to its parent Module. A pointer to the 52 | // clone is returned. 53 | Function* cloneFunction(Function *F); 54 | 55 | // Same as cloneFunction(F), but initialize the value mapping of the clone 56 | // in VMap 57 | Function* cloneFunction(Function *F, ValueToValueMapTy &VMap); 58 | 59 | // Replaces arguments of E by A's arguments 60 | void replaceArgs(Function *E, Function *A); 61 | 62 | // Inserts a prefetch for LInst as early as possible 63 | // (i.e. as soon as the adress has been computed). 64 | // The prefetch and all its dependencies will also 65 | // be inserted in toKeep. 66 | // Returns the result of the insertion. 67 | PrefInsertResult 68 | insertPrefetch(AliasAnalysis *AA, LoadInst *LInst, set &toKeep, 69 | map> &prefs, 70 | unsigned Threshold); 71 | 72 | // Adds pointer to all LoadInsts in F to LoadList. 73 | void findLoads(Function &F, list &LoadList); 74 | 75 | // Adds LoadInsts in LoadList to VisList if they 76 | // operate on visible data. 77 | void findVisibleLoads(list &LoadList, list &VisList); 78 | 79 | // Returns true 80 | bool isUnderThreshold(set Deps, unsigned Threshold); 81 | 82 | // Returns true if value is a function argument 83 | Value *isFunArgument(Function *E, Function *A, Value *arg); 84 | 85 | // Returns true if Pointer is a global pointer 86 | bool isNonLocalPointer(Value *Pointer); 87 | 88 | // Returns true iff Pointer does have a local destination. 89 | bool isLocalPointer(Value *Pointer); 90 | } 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /compiler/projects/include/Util/Transform/BranchMerge/BranchMerge.h: -------------------------------------------------------------------------------- 1 | //===----BranchMerge.h - Early evaluation of branches and later merge----===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file BranchMerge.h 10 | /// 11 | /// \brief 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | // 16 | // This file provides functions to evaluate branches at an early stage, 17 | // and to decide whether to run the optimized (merged branches) or unoptimized 18 | // (original) version. 19 | // 20 | //===----------------------------------------------------------------------===// 21 | 22 | #ifndef COMPILER_BRANCHMERGE_H 23 | #define COMPILER_BRANCHMERGE_H 24 | 25 | #include 26 | #include 27 | 28 | #include "Util/Annotation/MetadataInfo.h" 29 | 30 | using namespace util; 31 | 32 | 33 | static std::pair getProbabilityBranch(BranchInst *BI) { 34 | if (BI->getNumSuccessors() < 2) { 35 | return std::make_pair("1.0", "0.0"); 36 | } 37 | std::string string_bp0 = getInstructionMD(&*BI, "BranchProb0"); 38 | std::string string_bp1 = getInstructionMD(&*BI, "BranchProb1"); 39 | if (string_bp0.length() > 0 && string_bp1.length() > 0 ) { 40 | return std::make_pair(string_bp0, string_bp1); 41 | } 42 | return std::make_pair("0.0", "0.0"); 43 | }; 44 | 45 | 46 | 47 | // pair represents: 48 | static std::pair isReducableBranch(BranchInst *BI, double THRESHOLD) { 49 | if (BI->getNumSuccessors() < 2) { 50 | return std::make_pair(false, 0); 51 | } 52 | // We don't want to minimize the branches generated through 53 | // loopChunk ("stdin" tag represents the global virtual iterator) 54 | if (BI->isConditional()) { 55 | if (Value *vbi = dyn_cast(BI->getCondition())) { 56 | if (vbi->getName().str().find("stdin") != std::string::npos) { 57 | return std::make_pair(false, 0); 58 | } 59 | } 60 | } 61 | 62 | std::string string_bp0 = getInstructionMD(&*BI, "BranchProb0"); 63 | std::string string_bp1 = getInstructionMD(&*BI, "BranchProb1"); 64 | if (string_bp0.length() > 0 && string_bp1.length() > 0 ) { 65 | double bp0 = std::stod(string_bp0); 66 | double bp1 = std::stod(string_bp1); 67 | if (bp0 > THRESHOLD) { 68 | return std::make_pair(true, 0); 69 | } else if (bp1 > THRESHOLD) { 70 | return std::make_pair(true, 1); 71 | } 72 | } 73 | return std::make_pair(false, 0); 74 | } 75 | 76 | static StoreInst* insertFlagCheck(BranchInst *BI, AllocaInst *branch_cond, float BranchProbThreshold) { 77 | IRBuilder<> Builder(BI); 78 | float threshold = BranchProbThreshold; 79 | std::pair res = isReducableBranch(BI, threshold); 80 | if (res.first) { 81 | Value *new_cond; 82 | LoadInst *branch_value = Builder.CreateLoad(branch_cond); 83 | std::pair bp = getProbabilityBranch(BI); 84 | if (res.second == 0) { 85 | errs() << "Assuming probably true: " << *BI << "\n"; 86 | errs() << "With probability: " << bp.first << "\n"; 87 | new_cond = Builder.CreateAnd(branch_value, BI->getCondition()); 88 | } else if (res.second == 1) { 89 | errs() << "Assuming probably false: " << *BI << "\n"; 90 | errs() << "With probability: " << bp.second << "\n"; 91 | Value *n = Builder.CreateNot(BI->getCondition()); 92 | new_cond = Builder.CreateAnd(branch_value, n); 93 | } else { 94 | assert(false && "Couldn't get branch probability.\n"); 95 | } 96 | return Builder.CreateStore(new_cond, branch_cond); 97 | } 98 | } 99 | 100 | bool minimizeFunctionFromBranchPred(LoopInfo *LI, Function *cF, double threshold); 101 | #endif //COMPILER_BRANCHMERGE_H 102 | -------------------------------------------------------------------------------- /compiler/projects/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) Eta Scale AB. Licensed under the Eta Scale Open Source License. See the LICENSE file for details. 3 | add_subdirectory(SWOOP) 4 | add_subdirectory(DAE) 5 | add_subdirectory(Util) 6 | -------------------------------------------------------------------------------- /compiler/projects/src/DAE/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) Eta Scale AB. Licensed under the Eta Scale Open Source License. See the LICENSE file for details. 3 | add_subdirectory(Utils) 4 | 5 | -------------------------------------------------------------------------------- /compiler/projects/src/DAE/Utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) Eta Scale AB. Licensed under the Eta Scale Open Source License. See the LICENSE file for details. 3 | add_subdirectory(LoopExtract) 4 | 5 | 6 | -------------------------------------------------------------------------------- /compiler/projects/src/DAE/Utils/LoopExtract/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) Eta Scale AB. Licensed under the Eta Scale Open Source License. See the LICENSE file for details. 3 | add_library(LoopExtract MODULE LoopExtract.cpp) 4 | 5 | get_property(MODULE_FILE TARGET LoopExtract PROPERTY LOCATION) 6 | #configure_file(run.sh.in run.sh @ONLY) 7 | -------------------------------------------------------------------------------- /compiler/projects/src/DAE/Utils/LoopExtract/LoopExtract.cpp: -------------------------------------------------------------------------------- 1 | //===- LoopExtract.cpp - Extracts DAE-targeted loop---- 2 | //--------------------===// 3 | // 4 | // The LLVM Compiler Infrastructure 5 | // 6 | // This file is distributed under the University of Illinois Open Source 7 | // License. See LICENSE.TXT for details. 8 | // 9 | //===----------------------------------------------------------------------===// 10 | /// \file LoopExtract.cpp 11 | /// 12 | /// \brief Extracts DAE-targeted loop 13 | /// 14 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 15 | /// the LICENSE file for details. 16 | //===----------------------------------------------------------------------===// 17 | #include "llvm/Analysis/LoopPass.h" 18 | #include "llvm/IR/Dominators.h" 19 | #include "llvm/IR/Instructions.h" 20 | #include "llvm/IR/Module.h" 21 | #include "llvm/Transforms/IPO.h" 22 | #include "llvm/Transforms/Scalar.h" 23 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" 24 | #include "llvm/Transforms/Utils/CodeExtractor.h" 25 | 26 | #include 27 | 28 | #define F_KERNEL_SUBSTR "__kernel__" 29 | #define PROLOGUE_SUBSTR "prol" 30 | 31 | using namespace llvm; 32 | 33 | #include "../SkelUtils/Utils.cpp" 34 | 35 | static cl::opt BenchName("bench-name", 36 | cl::desc("The benchmark name"), 37 | cl::value_desc("name")); 38 | 39 | static cl::opt IsDae("is-dae", 40 | cl::desc("Use depth-based DAE loop detection")); 41 | 42 | namespace { 43 | struct LoopExtract : public LoopPass { 44 | static char ID; // Pass identification, replacement for typeid 45 | 46 | LoopExtract() : LoopPass(ID) {} 47 | unsigned NumLoops; 48 | 49 | virtual bool runOnLoop(Loop *L, LPPassManager &LPM); 50 | 51 | virtual void getAnalysisUsage(AnalysisUsage &AU) const { 52 | AU.addRequiredID(BreakCriticalEdgesID); 53 | AU.addRequiredID(LoopSimplifyID); 54 | AU.addRequired(); 55 | AU.addRequired(); 56 | } 57 | 58 | void PrintModule(Function *F); 59 | void PrintFunction(Function *F, std::string suf); 60 | BasicBlock *getCaller(Function *F); 61 | bool toBeExtracted(Loop *L); 62 | }; 63 | } 64 | 65 | char LoopExtract::ID = 0; 66 | static RegisterPass 67 | X("second-loop-extract", "Extract second level loops into new functions", 68 | true, true); 69 | 70 | bool LoopExtract::runOnLoop(Loop *L, LPPassManager &LPM) { 71 | // if already extracted 72 | Function *F = L->getHeader()->getParent(); 73 | if (!toBeDAE(F)) { 74 | return false; 75 | } 76 | 77 | // find the chunked loops 78 | if (IsDae) { 79 | // parent loop has to be marked 80 | bool isMarked = L->getParentLoop() && 81 | L->getParentLoop()->getHeader()->getName().str().find(F_KERNEL_SUBSTR) != string::npos; 82 | if (!isMarked) { 83 | return false; 84 | } 85 | } else { 86 | if (!toBeExtracted(L)) { 87 | return false; 88 | } 89 | } 90 | 91 | // If LoopSimplify form is not available, stay out of trouble. 92 | if (!L->isLoopSimplifyForm()) { 93 | return false; 94 | } 95 | 96 | DominatorTree &DT = getAnalysis().getDomTree(); 97 | bool Changed = false; 98 | 99 | // If there is more than one top-level loop in this function, extract all of 100 | // the loops. Otherwise there is exactly one top-level loop; in this case if 101 | // this function is more than a minimal wrapper around the loop, extract 102 | // the loop. 103 | bool ShouldExtractLoop = false; 104 | 105 | // Extract the loop if the entry block doesn't branch to the loop header. 106 | TerminatorInst *EntryTI = 107 | L->getHeader()->getParent()->getEntryBlock().getTerminator(); 108 | if (!isa(EntryTI) || 109 | !cast(EntryTI)->isUnconditional() || 110 | EntryTI->getSuccessor(0) != L->getHeader()) { 111 | ShouldExtractLoop = true; 112 | } else { 113 | // Check to see if any exits from the loop are more than just return 114 | // blocks. 115 | SmallVector ExitBlocks; 116 | L->getExitBlocks(ExitBlocks); 117 | for (unsigned i = 0, e = ExitBlocks.size(); i != e; ++i) 118 | if (!isa(ExitBlocks[i]->getTerminator())) { 119 | ShouldExtractLoop = true; 120 | break; 121 | } 122 | } 123 | 124 | if (!ShouldExtractLoop) { 125 | // Loop is already a function, it is actually not necessary to extract the 126 | // loop. 127 | ShouldExtractLoop = true; 128 | } 129 | 130 | if (ShouldExtractLoop) { 131 | // We must omit landing pads. Landing pads must accompany the invoke 132 | // instruction. But this would result in a loop in the extracted 133 | // function. An infinite cycle occurs when it tries to extract that loop as 134 | // well. 135 | SmallVector ExitBlocks; 136 | L->getExitBlocks(ExitBlocks); 137 | for (unsigned i = 0, e = ExitBlocks.size(); i != e; ++i) 138 | if (ExitBlocks[i]->isLandingPad()) { 139 | ShouldExtractLoop = false; 140 | break; 141 | } 142 | } 143 | 144 | if (ShouldExtractLoop) { 145 | 146 | CodeExtractor Extractor(DT, *L); 147 | Function *nF = Extractor.extractCodeRegion(); 148 | if (nF != 0) { 149 | BasicBlock *codeRepl = getCaller(nF); 150 | nF->addFnAttr(Attribute::AlwaysInline); 151 | 152 | Changed = true; 153 | 154 | LoopInfo *LI = &getAnalysis().getLoopInfo(); 155 | if (L->getParentLoop()) { 156 | L->getParentLoop()->addBasicBlockToLoop(codeRepl, *LI); 157 | } 158 | 159 | // After extraction, the loop is replaced by a function call, so 160 | // we shouldn't try to run any more loop passes on it. 161 | LI->markAsRemoved(L); 162 | } 163 | } 164 | 165 | return Changed; 166 | } 167 | 168 | bool LoopExtract::toBeExtracted(Loop *L) { 169 | bool isMarked = 170 | L->getHeader()->getName().str().find(F_KERNEL_SUBSTR) != string::npos; 171 | bool isOriginalLoop = 172 | L->getHeader()->getName().str().find(PROLOGUE_SUBSTR) == string::npos; 173 | bool functionNotYetExtracted = 174 | L->getHeader()->getParent()->getName().str().find(F_KERNEL_SUBSTR) == 175 | string::npos; 176 | 177 | if (!isMarked || !isOriginalLoop || !functionNotYetExtracted) { 178 | return false; 179 | } 180 | return true; 181 | } 182 | 183 | BasicBlock *LoopExtract::getCaller(Function *F) { 184 | for (Value::user_iterator I = F->user_begin(), E = F->user_end(); I != E; 185 | ++I) { 186 | if (isa(*I) || isa(*I)) { 187 | Instruction *User = dyn_cast(*I); 188 | return User->getParent(); 189 | } 190 | } 191 | return 0; 192 | } 193 | -------------------------------------------------------------------------------- /compiler/projects/src/DAE/Utils/SkelUtils/LoopUtils.cpp: -------------------------------------------------------------------------------- 1 | //===- LoopUtils.cpp - Utility for LoopChunking----------------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file LoopUtils.cpp 10 | /// 11 | /// \brief Utility for LoopChunking 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | //===----------------------------------------------------------------------===// 16 | #include "DAE/Utils/SkelUtils/headers.h" 17 | #include "HandleVirtualIterators.cpp" 18 | #include "Util/Annotation/MetadataInfo.h" 19 | 20 | using namespace llvm; 21 | using namespace std; 22 | using namespace util; 23 | 24 | #ifndef LoopUtils_ 25 | #define LoopUtils_ 26 | 27 | BasicBlock *insertArtificialLoopLatch(Loop *L, LoopInfo *LI); 28 | bool isGuaranteedToExecute(Instruction *Inst, Loop *CurLoop, DominatorTree *DT); 29 | void updatePHInodes(BasicBlock *b, BasicBlock *oldP, BasicBlock *newP); 30 | void replaceBrupdatePhi(BasicBlock *&BB, BasicBlock *&o, BasicBlock *&n); 31 | 32 | /* to treat while and for loops unitary, create an artificial loop latch IF 33 | * NECESSARY*/ 34 | BasicBlock *insertArtificialLoopLatch(Loop *L, LoopInfo *LI) { 35 | BasicBlock *oldB = L->getLoopLatch(); 36 | if (oldB) 37 | return oldB; 38 | 39 | // avoid duplicates: do not insert an artificial latch if there is already one 40 | size_t found; 41 | std::string text = "_latch"; 42 | if (oldB != 0) { 43 | found = oldB->getName().find(text); 44 | if (found != std::string::npos) 45 | return oldB; 46 | } 47 | 48 | BasicBlock *latchBB = 49 | BasicBlock::Create(L->getHeader()->getContext(), 50 | Twine(L->getHeader()->getName().str() + "_latch"), 51 | L->getHeader()->getParent(), L->getHeader()); 52 | std::vector oldLat; 53 | 54 | // if there is more than one BB latches, getLoopLatch() returns O 55 | if (oldB == 0) { 56 | 57 | BranchInst::Create(L->getHeader(), latchBB); 58 | std::vector v = L->getBlocks(); 59 | BasicBlock *header = L->getHeader(); 60 | 61 | pred_iterator PI = pred_begin(L->getHeader()), E = pred_end(L->getHeader()); 62 | while (PI != E) { 63 | if (belongs(v, *PI)) { 64 | BasicBlock *bpi = dyn_cast(*PI); 65 | replaceBrupdatePhi(bpi, header, latchBB); 66 | oldLat.push_back(*PI); 67 | updatePHInodes(L->getHeader(), *PI, latchBB); 68 | PI = pred_begin(L->getHeader()); 69 | } else 70 | ++PI; 71 | } 72 | } 73 | // update loop info 74 | 75 | L->addBasicBlockToLoop(latchBB, *LI); 76 | 77 | return latchBB; 78 | } 79 | 80 | /* update the PHI nodes whenever a terminating instruction is changed*/ 81 | void updatePHInodes(BasicBlock *b, BasicBlock *oldP, BasicBlock *newP) { 82 | BasicBlock::iterator i = b->begin(); 83 | 84 | while (isa(i)) { 85 | i->replaceUsesOfWith(oldP, newP); 86 | i++; 87 | } 88 | } 89 | 90 | /* 91 | BB 92 | | 93 | | 94 | x--- 95 | | | 96 | o n 97 | */ 98 | void replaceBrupdatePhi(BasicBlock *&BB, BasicBlock *&o, BasicBlock *&n) { 99 | // o->removePredecessor(BB, false); 100 | BB->getTerminator()->replaceUsesOfWith(o, n); 101 | // updateDT(BB, n); 102 | BasicBlock::iterator i = n->begin(); 103 | 104 | while (isa(i)) { 105 | errs() << "TODO update PHI !! \n\n\n"; 106 | // how to add a new pred, if there is no entry for it in the PHI node 107 | i++; 108 | } 109 | } 110 | 111 | bool isGuaranteedToExecute(Instruction *Inst, Loop *CurLoop, 112 | DominatorTree *DT) { 113 | if (!CurLoop) 114 | return true; 115 | 116 | // Otherwise we have to check to make sure that the instruction dominates all 117 | // of the exit blocks. If it doesn't, then there is a path out of the loop 118 | // which does not execute this instruction, so we can't hoist it. 119 | 120 | // If the instruction is in the header block for the loop (which is very 121 | // common), it is always guaranteed to dominate the exit blocks. Since this 122 | // is a common case, and can save some work, check it now. 123 | if (Inst->getParent() == CurLoop->getHeader()) 124 | return true; 125 | 126 | // Get the exit blocks for the current loop. 127 | SmallVector ExitBlocks; 128 | CurLoop->getExitBlocks(ExitBlocks); 129 | 130 | // Verify that the block dominates each of the exit blocks of the loop. 131 | for (unsigned i = 0, e = ExitBlocks.size(); i != e; ++i) 132 | if (!DT->dominates(Inst->getParent(), ExitBlocks[i])) 133 | return false; 134 | 135 | // As a degenerate case, if the loop is statically infinite then we haven't 136 | // proven anything since there are no exit blocks. 137 | if (ExitBlocks.empty()) 138 | return false; 139 | 140 | return true; 141 | } 142 | 143 | #endif 144 | -------------------------------------------------------------------------------- /compiler/projects/src/DAE/Utils/SkelUtils/Utils.cpp: -------------------------------------------------------------------------------- 1 | //===- Utils.cpp - Determines which functions to target for DAE------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file Utils.cpp 10 | /// 11 | /// \brief Determines which functions to target for DAE 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | //===----------------------------------------------------------------------===// 16 | using namespace llvm; 17 | using namespace std; 18 | 19 | #ifndef Utils_ 20 | #define Utils_ 21 | #include "llvm/Analysis/LoopAccessAnalysis.h" 22 | #include "../../../SWOOP/Utils/LongLatency.cpp" 23 | #include "DAE/Utils/SkelUtils/headers.h" 24 | #include 25 | #include 26 | 27 | void declareExternalGlobal(Value *v, int val); 28 | bool toBeDAE(Function *F); 29 | bool isDAEkernel(Function *F); 30 | bool isMain(Function *F); 31 | 32 | bool isDAEkernel(Function *F) { 33 | bool ok = false; 34 | size_t found = F->getName().str().find("_clone"); 35 | size_t found1 = F->getName().str().find("__kernel__"); 36 | if ((found == std::string::npos) && (found1 != std::string::npos)) 37 | ok = true; 38 | return ok; 39 | } 40 | 41 | void declareExternalGlobal(Value *v, int val) { 42 | std::string path = "Globals.ll"; 43 | std::error_code err; 44 | llvm::raw_fd_ostream out(path.c_str(), err, llvm::sys::fs::F_Append); 45 | 46 | out << "\n@\"" << v->getName() << "\" = global i64 " << val << " \n"; 47 | out.close(); 48 | } 49 | 50 | ///////////////////////////////////////////////////////////// 51 | // 52 | // From LoopVectorize.cpp 53 | // 54 | ///////////////////////////////////////////////////////////// 55 | 56 | 57 | /// Utility class for getting and setting loop vectorizer hints in the form 58 | /// of loop metadata. 59 | /// This class keeps a number of loop annotations locally (as member variables) 60 | /// and can, upon request, write them back as metadata on the loop. It will 61 | /// initially scan the loop for existing metadata, and will update the local 62 | /// values based on information in the loop. 63 | /// We cannot write all values to metadata, as the mere presence of some info, 64 | /// for example 'force', means a decision has been made. So, we need to be 65 | /// careful NOT to add them if the user hasn't specifically asked so. 66 | class LoopVectorizeHints { 67 | enum HintKind { 68 | HK_WIDTH, 69 | HK_UNROLL, 70 | HK_FORCE 71 | }; 72 | 73 | /// Hint - associates name and validation with the hint value. 74 | struct Hint { 75 | const char * Name; 76 | unsigned Value; // This may have to change for non-numeric values. 77 | HintKind Kind; 78 | 79 | Hint(const char * Name, unsigned Value, HintKind Kind) 80 | : Name(Name), Value(Value), Kind(Kind) { } 81 | 82 | bool validate(unsigned Val) { 83 | switch (Kind) { 84 | case HK_WIDTH: 85 | return true; //isPowerOf2_32(Val) && Val <= VectorizerParams::MaxVectorWidth; 86 | case HK_UNROLL: 87 | return true; //isPowerOf2_32(Val) && Val <= MaxInterleaveFactor; 88 | case HK_FORCE: 89 | return (Val <= 1); 90 | } 91 | return false; 92 | } 93 | 94 | }; 95 | 96 | /// Vectorization width. 97 | Hint Width; 98 | /// Vectorization interleave factor. 99 | Hint Interleave; 100 | /// Vectorization forced 101 | Hint Force; 102 | 103 | /// Return the loop metadata prefix. 104 | static StringRef Prefix() { return "llvm.loop."; } 105 | 106 | public: 107 | enum ForceKind { 108 | FK_Undefined = -1, ///< Not selected. 109 | FK_Disabled = 0, ///< Forcing disabled. 110 | FK_Enabled = 1, ///< Forcing enabled. 111 | }; 112 | 113 | LoopVectorizeHints(const Loop *L, bool DisableInterleaving) 114 | : Width("vectorize.width", VectorizerParams::VectorizationFactor, 115 | HK_WIDTH), 116 | Interleave("interleave.count", DisableInterleaving, HK_UNROLL), 117 | Force("vectorize.enable", FK_Undefined, HK_FORCE), 118 | TheLoop(L) { 119 | // Populate values with existing loop metadata. 120 | getHintsFromMetadata(); 121 | 122 | // force-vector-interleave overrides DisableInterleaving. 123 | if (VectorizerParams::isInterleaveForced()) 124 | Interleave.Value = VectorizerParams::VectorizationInterleave; 125 | 126 | //DEBUG(if (DisableInterleaving && Interleave.Value == 1) dbgs() 127 | // << "LV: Interleaving disabled by the pass manager\n"); 128 | } 129 | 130 | unsigned getWidth() const { return Width.Value; } 131 | unsigned getInterleave() const { return Interleave.Value; } 132 | enum ForceKind getForce() const { return (ForceKind)Force.Value; } 133 | private: 134 | /// Find hints specified in the loop metadata and update local values. 135 | void getHintsFromMetadata() { 136 | MDNode *LoopID = TheLoop->getLoopID(); 137 | if (!LoopID) 138 | return; 139 | 140 | // First operand should refer to the loop id itself. 141 | assert(LoopID->getNumOperands() > 0 && "requires at least one operand"); 142 | assert(LoopID->getOperand(0) == LoopID && "invalid loop id"); 143 | 144 | for (unsigned i = 1, ie = LoopID->getNumOperands(); i < ie; ++i) { 145 | const MDString *S = nullptr; 146 | SmallVector Args; 147 | 148 | // The expected hint is either a MDString or a MDNode with the first 149 | // operand a MDString. 150 | if (const MDNode *MD = dyn_cast(LoopID->getOperand(i))) { 151 | if (!MD || MD->getNumOperands() == 0) 152 | continue; 153 | S = dyn_cast(MD->getOperand(0)); 154 | for (unsigned i = 1, ie = MD->getNumOperands(); i < ie; ++i) 155 | Args.push_back(MD->getOperand(i)); 156 | } else { 157 | S = dyn_cast(LoopID->getOperand(i)); 158 | assert(Args.size() == 0 && "too many arguments for MDString"); 159 | } 160 | 161 | if (!S) 162 | continue; 163 | 164 | // Check if the hint starts with the loop metadata prefix. 165 | StringRef Name = S->getString(); 166 | if (Args.size() == 1) 167 | setHint(Name, Args[0]); 168 | } 169 | } 170 | 171 | // /// Checks string hint with one operand and set value if valid. 172 | void setHint(StringRef Name, Metadata *Arg) { 173 | if (!Name.startswith(Prefix())) 174 | return; 175 | Name = Name.substr(Prefix().size(), StringRef::npos); 176 | 177 | const ConstantInt *C = mdconst::dyn_extract(Arg); 178 | if (!C) return; 179 | unsigned Val = C->getZExtValue(); 180 | 181 | Hint *Hints[] = {&Width, &Interleave, &Force}; 182 | for (auto H : Hints) { 183 | if (Name == H->Name) { 184 | if (H->validate(Val)) 185 | H->Value = Val; 186 | else 187 | // DEBUG(dbgs() << "LV: ignoring invalid hint '" << Name << "'\n"); 188 | break; 189 | } 190 | } 191 | } 192 | 193 | /// The loop these hints belong to. 194 | const Loop *TheLoop; 195 | }; 196 | 197 | int loopToBeDAE(Loop *L, std::string benchmarkName, 198 | bool requireDelinquent = true) { 199 | 200 | // Only accept inner-most loops 201 | if (L->getSubLoops().size() != 0) { 202 | return false; 203 | } 204 | 205 | int MAGIC_TRANSFORM = 1337; 206 | 207 | // If any of the parent loops has a hint, 208 | // it is a loop to be transformed 209 | Loop *Parent = L; 210 | while (Parent) { 211 | LoopVectorizeHints Hints(Parent, false); 212 | if (Hints.getWidth() >= MAGIC_TRANSFORM) { 213 | return true; 214 | } 215 | Parent = Parent->getParentLoop(); 216 | } 217 | 218 | return false; 219 | } 220 | 221 | bool isMain(Function *F) { return F->getName().str().compare("main") == 0; } 222 | 223 | bool toBeDAE(Function *F) { 224 | bool ok = false; 225 | 226 | /*401.bzip*/ 227 | if (F->getName().str().compare("BZ2_compressBlock") == 0) // 13% generateMTFValues 228 | ok = true; 229 | if (F->getName().str().compare("BZ2_decompress") == 0) // 12% 230 | ok = true; 231 | // if (F->getName().str().compare("mainGtU") == 0) // 16% no loads found 232 | // ok = true; 233 | 234 | /*429.mcf*/ 235 | if (F->getName().str().compare("primal_bea_mpp") == 0) // 38% 236 | ok = true; 237 | 238 | /*433.milc*/ 239 | if (F->getName().str().compare("mult_su3_na") == 0) // 15% 240 | ok = true; 241 | 242 | /*450.soplex*/ 243 | if (F->getName().str().compare("_ZN6soplex8SSVector19assign2productShortERKNS_5SVSetERKS0_") == 0) // 19% 244 | ok = true; 245 | if (F->getName().str().compare( 246 | "_ZN6soplex10SPxSteepPR9entered4XENS_5SPxIdEiiiii") == 0) // 14% 247 | ok = true; 248 | if (F->getName().str().compare("_ZN6soplex8SSVector5setupEv") == 0) // 11% 249 | ok = true; 250 | 251 | /*456.hmmer*/ 252 | if (F->getName().str().compare("P7Viterbi") == 0) // 87% 253 | ok = true; 254 | 255 | /*458.sjeng*/ 256 | if (F->getName().str().compare("std_eval") == 0) // 17% 257 | ok = true; 258 | 259 | /*462.libQ*/ 260 | if (F->getName().str().compare("quantum_toffoli") == 0) // 60% 261 | ok = true; 262 | if (F->getName().str().compare("quantum_sigma_x") == 0) // 23% 263 | ok = true; 264 | if (F->getName().str().compare("quantum_cnot") == 0) // 12% 265 | ok = true; 266 | 267 | 268 | /*470.lbm*/ 269 | if (F->getName().str().compare("LBM_performStreamCollide") == 0) // 99% 270 | ok = true; 271 | 272 | /*464.h264ref*/ 273 | if (F->getName().str().compare("SetupFastFullPelSearch") == 0) // 18% 274 | ok = true; 275 | if (F->getName().str().compare("BlockMotionSearch") == 0) // 13% 276 | ok = true; 277 | 278 | /*473.astar*/ 279 | if (F->getName().str().compare("_ZN6wayobj10makebound2EPiiS0_") == 0) // 22% 280 | ok = true; 281 | if (F->getName().str().compare("_ZN7way2obj12releaseboundEv") == 0) // 34% 282 | ok = true; 283 | 284 | /*482.sphinx3*/ 285 | if (F->getName().str().compare("mgau_eval") == 0) // 39% 286 | ok = true; 287 | 288 | /*403.gcc*/ 289 | if (F->getName().str().compare("reg_is_remote_constant_p") == 0) // 16% 290 | ok = true; 291 | 292 | /*400.perlbench*/ 293 | if (F->getName().str().compare("S_regmatch") == 0) // 35% 294 | ok = true; 295 | 296 | /*445.gobmk*/ 297 | if (F->getName().str().compare("fastlib") == 0) // 5% - no loop 298 | ok = true; 299 | if (F->getName().str().compare("do_play_move") == 0) //5% - no loop 300 | ok = true; 301 | if (F->getName().str().compare("do_dfa_matchpat") == 0) //4% 302 | ok = true; 303 | if (F->getName().str().compare("dfa_matchpat_loop") == 0) //4% 304 | ok = true; 305 | if (F->getName().str().compare("incremental_order_moves") == 0) //4% 306 | ok = true; 307 | 308 | 309 | 310 | /*471.omnetpp*/ 311 | if (F->getName().str().compare("getFirst") == 0) // 13% no loop 312 | ok = true; 313 | if (F->getName().str().compare("_ZN12cMessageHeap7shiftupEi") == 0) // part of getFirst 314 | ok = true; 315 | 316 | 317 | /*473.xalancbmk*/ 318 | if (F->getName().str().compare("_ZN11xercesc_2_510ValueStore13isDuplicateOfEPNS_17DatatypeValidatorEPKtS2_S4_") == 0) // 6% 319 | ok = true; 320 | if (F->getName().str().compare("_ZN11xercesc_2_510ValueStore8containsEPKNS_13FieldValueMapE") == 0) // 17% - not swoopifiable loops 321 | ok = true; 322 | 323 | /*444.namd*/ 324 | if (F->getName().str().compare("_ZN20ComputeNonbondedUtil26calc_pair_energy_fullelectEP9nonbonded") == 0) // 11% 325 | ok = true; 326 | if (F->getName().str().compare("_ZN20ComputeNonbondedUtil16calc_pair_energyEP9nonbonded") == 0) // 11% 327 | ok = true; 328 | if (F->getName().str().compare("_ZN20ComputeNonbondedUtil32calc_pair_energy_merge_fullelectEP9nonbonded") == 0) // 11% 329 | ok = true; 330 | if (F->getName().str().compare("_ZN20ComputeNonbondedUtil19calc_pair_fullelectEP9nonbonded") == 0) // 11% 331 | ok = true; 332 | 333 | /*447.dealII*/ 334 | if (F->getName().str().compare("_ZNK13LaplaceSolver6SolverILi3EE15assemble_matrixERNS1_12LinearSystemERK18TriaActiveIteratorILi3E15DoFCellAccessorILi3EEES9_RN7Threads16DummyThreadMutexE") == 0) // 11% 335 | ok = true; 336 | 337 | /*453.povray*/ 338 | if (F->getName().str().compare("_ZN3povL31All_CSG_Intersect_IntersectionsEPNS_13Object_StructEPNS_10Ray_StructEPNS_13istack_structE") == 0) // 14% 339 | ok = true; 340 | 341 | /*331.art_l*/ 342 | if (F->getName().str().compare("compute_train_match") == 0) // 14% 343 | ok = true; 344 | if (F->getName().str().compare("compute_values_match") == 0) // 14% 345 | ok = true; 346 | 347 | /*CG*/ 348 | if (F->getName().str().compare("conj_grad") == 0) // 6% 349 | ok = true; 350 | 351 | /*LU*/ 352 | if (F->getName().str().compare("blts") == 0) // 14% 353 | ok = true; 354 | if (F->getName().str().compare("buts") == 0) // 14% 355 | ok = true; 356 | 357 | /*UA*/ 358 | if (F->getName().str().compare("diffusion") == 0) // 12% 359 | ok = true; 360 | if (F->getName().str().compare("transfb") == 0) // 6% 361 | ok = true; 362 | 363 | 364 | //return ok; 365 | return true; // for artifact evaluation, making it easier 366 | } 367 | 368 | 369 | 370 | #endif 371 | -------------------------------------------------------------------------------- /compiler/projects/src/SWOOP/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) Eta Scale AB. Licensed under the Eta Scale Open Source License. See the LICENSE file for details. 3 | add_subdirectory(Transform) 4 | add_subdirectory(Utils) 5 | 6 | -------------------------------------------------------------------------------- /compiler/projects/src/SWOOP/Transform/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) Eta Scale AB. Licensed under the Eta Scale Open Source License. See the LICENSE file for details. 3 | add_subdirectory(SwoopDAE) 4 | add_subdirectory(OptimisticSwoop) 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /compiler/projects/src/SWOOP/Transform/OptimisticSwoop/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) Eta Scale AB. Licensed under the Eta Scale Open Source License. See the LICENSE file for details. 3 | add_library(OptimisticSwoop SHARED 4 | ../SwoopDAE/SwoopDAE.cpp 5 | OptimisticSwoop.cpp 6 | ${PROJECTS_MAIN_SRC_DIR}/Util/Annotation/MetadataInfo.cpp 7 | ${PROJECTS_MAIN_SRC_DIR}/Util/Analysis/AliasUtils.cpp 8 | ${PROJECTS_MAIN_SRC_DIR}/Util/DAE/DAEUtils.cpp 9 | ${PROJECTS_MAIN_SRC_DIR}/Util/Analysis/LoopDependency.cpp 10 | ${PROJECTS_MAIN_SRC_DIR}/Util/Transform/BranchMerge/BranchMerge.cpp 11 | ${SWOOP_MAIN_INCLUDE_DIR} 12 | ${PROJECTS_MAIN_INCLUDE_DIR} 13 | ../PhaseStitching.cpp 14 | ../SwoopDAE/LCDHandler.cpp 15 | ../SwoopDAE/FindInstructions.cpp 16 | ../ 17 | ) 18 | 19 | target_compile_options(OptimisticSwoop PRIVATE -fPIC) 20 | add_dependencies(OptimisticSwoop SwoopDAE) 21 | -------------------------------------------------------------------------------- /compiler/projects/src/SWOOP/Transform/OptimisticSwoop/OptimisticSwoop.cpp: -------------------------------------------------------------------------------- 1 | //===---- OptimisticSwoop.cpp - optimistic hoist & reuse ------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file OptimisticSwoop.cpp 10 | /// 11 | /// \brief Optimistic version of Swoop. Hoists no- and may-aliases. 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | // 16 | // Optimistic version of Swoop. Hoists no- and may-aliases. Which loads 17 | // are hoisted depends on the flavour: 18 | // - Aggressive Swoop 19 | // - Speculative Swoop 20 | // 21 | //===----------------------------------------------------------------------===// 22 | 23 | #include "SWOOP/Transform/SwoopDAE/BasicSwoop.h" 24 | #include "../SwoopDAE/LCDHandler.h" 25 | #include "../SwoopDAE/FindInstructions.h" 26 | 27 | 28 | using namespace util; 29 | 30 | namespace swoop { 31 | 32 | typedef SmallVector accLCDTy; 33 | 34 | struct OptimisticSwoop : public SwoopDAE { 35 | static char ID; 36 | OptimisticSwoop(int maxMayLCDInChain = INT_MAX) : SwoopDAE() { 37 | maxMayLCD = maxMayLCDInChain; 38 | } 39 | 40 | protected: 41 | void filterLoadsOnLCD(AliasAnalysis *AA, 42 | LoopInfo *LI, 43 | list &Loads, 44 | list &FilteredLoads, 45 | unsigned int UnrollCount) override; 46 | void divideLoads(list &toHoist, 47 | list &toPref, 48 | list &toReuse, 49 | list &toLoad, 50 | unsigned int UnrollCount) override; 51 | 52 | private: 53 | std::map AccLCDInfo; 54 | 55 | int maxMayLCD; 56 | void exploreDepsOnLCD(Instruction *I, accLCDTy &accumulatedLCD, unsigned int UnrollCount); 57 | }; 58 | 59 | 60 | void OptimisticSwoop::divideLoads(list &toHoist, 61 | list &toPref, 62 | list &toReuse, 63 | list &toLoad, 64 | unsigned int UnrollCount) { 65 | int numUnsafePrefetch = 0, numUnsafeLoad = 0; 66 | set AllDeps; 67 | for (auto L : toHoist) { 68 | getRequirementsInIteration(AA, LI, L, AllDeps); 69 | } 70 | 71 | for (auto L : toHoist) { 72 | set Deps; 73 | getRequirementsInIteration(AA, LI, L, Deps); 74 | 75 | bool depNoLCD = expectAtLeast(AA, LI, Deps, LCDResult::NoLCD); 76 | LCDResult SelfLCDRes = getLCDInfo(AA, LI, L, UnrollCount); 77 | 78 | if (SelfLCDRes == LCDResult::NoLCD && depNoLCD) { 79 | // reuse everything that has no mayLCDs 80 | // in its requirements 81 | toReuse.push_back(L); 82 | } else if (AllDeps.find(L) != AllDeps.end()) { 83 | // load everything that is required for any 84 | // other load to hoist 85 | toLoad.push_back(L); 86 | } else { 87 | // otherwise prefetch: some mayLcd in its 88 | // requirements 89 | toPref.push_back(L); 90 | } 91 | } 92 | } 93 | 94 | void OptimisticSwoop::filterLoadsOnLCD(AliasAnalysis *AA, 95 | LoopInfo *LI, 96 | list &Loads, 97 | list &FilteredLoads, 98 | unsigned int UnrollCount) { 99 | list::iterator L = Loads.begin(); 100 | while (L != Loads.end()) { 101 | 102 | set Deps; 103 | getRequirementsInIteration(AA, LI, *L, Deps); 104 | LCDResult selfLCD = getLCDInfo(AA, LI, *L, UnrollCount); 105 | bool depsNoLCD = expectAtLeast(AA, LI, Deps, LCDResult::NoLCD); 106 | 107 | if (selfLCD == LCDResult::MustLCD) { 108 | ++L; 109 | continue; 110 | } 111 | 112 | // If dependencies are no LCDs, and this load is a 113 | // may or no lcd, it can be reused/prefetched 114 | if (depsNoLCD && selfLCD < LCDResult::MustLCD) { 115 | FilteredLoads.push_back(*L); 116 | ++L; 117 | continue; 118 | } 119 | 120 | bool depsMayOrNoLCD = expectAtLeast(AA, LI, Deps, LCDResult::MayLCD); 121 | if (!depsMayOrNoLCD) { 122 | // dependencies contain must lcd, don't include load 123 | ++L; 124 | continue; 125 | } 126 | 127 | // Optimistic hoisting. 128 | bool operandsMeetReq = true; 129 | for (User::value_op_iterator I = (*L)->value_op_begin(), 130 | IE = (*L)->value_op_end(); 131 | I != IE; ++I) { 132 | if (!Instruction::classof(*I)) { 133 | continue; 134 | } 135 | 136 | Instruction *Inst = (Instruction *)(*I); 137 | LCDResult LCDRes = getLCDInfo(AA, LI, Inst, UnrollCount); 138 | 139 | accLCDTy accLCDInfo; 140 | exploreDepsOnLCD(Inst, accLCDInfo, UnrollCount); 141 | 142 | // Compute number of may lcds on the chain 143 | int maxMayLCDInChain = 144 | *std::max_element(accLCDInfo.begin(), accLCDInfo.end()); 145 | if (LCDRes != LCDResult::NoLCD) { 146 | ++maxMayLCDInChain; 147 | } 148 | 149 | // Check if chain meets requirements of max maylcds 150 | if (maxMayLCDInChain > maxMayLCD) { 151 | operandsMeetReq = false; 152 | break; 153 | } 154 | } 155 | 156 | if (operandsMeetReq) { 157 | FilteredLoads.push_back(*L); 158 | } 159 | 160 | ++L; 161 | } 162 | } 163 | 164 | void OptimisticSwoop::exploreDepsOnLCD(Instruction *I, accLCDTy &accumulatedLCD, unsigned int UnrollCount) { 165 | LCDResult LCDRes = getLCDInfo(AA, LI, I, UnrollCount); 166 | assert(LCDRes != LCDResult::MustLCD && 167 | "No Must lcd is allowed to pass this!"); 168 | 169 | int addLCD = 0; 170 | if (LCDRes == LCDResult::MayLCD) { 171 | addLCD = 1; 172 | } 173 | 174 | int index = 0; 175 | for (User::value_op_iterator U = I->value_op_begin(), UE = I->value_op_end(); 176 | U != UE; ++U, ++index) { 177 | if (isa(*U) && !isa(*U)) { 178 | Instruction *Inst = (Instruction *)*U; 179 | accLCDTy operandAccInfo; 180 | if (AccLCDInfo.find(Inst) != AccLCDInfo.end()) { 181 | operandAccInfo = *(AccLCDInfo[Inst]); 182 | } else { 183 | exploreDepsOnLCD(Inst, operandAccInfo, UnrollCount); 184 | AccLCDInfo[Inst] = 185 | new accLCDTy{operandAccInfo.begin(), operandAccInfo.end()}; 186 | } 187 | 188 | accumulatedLCD.push_back( 189 | *std::max_element(operandAccInfo.begin(), operandAccInfo.end()) + 190 | addLCD); 191 | } 192 | } 193 | 194 | if (accumulatedLCD.size() == 0) { 195 | accumulatedLCD.push_back(addLCD); 196 | } 197 | } 198 | 199 | char OptimisticSwoop::ID = 0; 200 | static RegisterPass 201 | C("optimistic-swoop", "Optimistically hoisting loads into access phase.", 202 | false, false); 203 | 204 | //===----------------------------------------------------------------------===// 205 | // AggressiveSwoop implementation: hoist all no & may LCDs, and only reuse the 206 | // safe ones. 207 | 208 | namespace { 209 | struct AggressiveSwoop : public OptimisticSwoop { 210 | static char ID; 211 | AggressiveSwoop() : OptimisticSwoop(INT_MAX) {} 212 | }; 213 | } 214 | 215 | char AggressiveSwoop::ID = 0; 216 | static RegisterPass D("aggressive-swoop", 217 | "Hoisting all loads.", false, false); 218 | 219 | //===----------------------------------------------------------------------===// 220 | // SpeculativeSwoop implementation: hoist all no & may LCDs, and reuse all. 221 | 222 | namespace { 223 | struct SpeculativeSwoop : public OptimisticSwoop { 224 | static char ID; 225 | SpeculativeSwoop() : OptimisticSwoop(INT_MAX) {} 226 | 227 | protected: 228 | void divideLoads(list &toHoist, 229 | list &toPref, 230 | list &toReuse, 231 | list &toLoad, 232 | unsigned int UnrollCount) override; 233 | LCDResult acceptedForReuse() override; 234 | }; 235 | } 236 | 237 | void SpeculativeSwoop::divideLoads(list &toHoist, 238 | list &toPref, 239 | list &toReuse, 240 | list &toLoad, 241 | unsigned int UnrollCount) { 242 | toReuse.insert(toReuse.end(), toHoist.begin(), toHoist.end()); 243 | } 244 | 245 | LCDResult SpeculativeSwoop::acceptedForReuse() { 246 | return LCDResult::MayLCD; 247 | } 248 | 249 | char SpeculativeSwoop::ID = 0; 250 | static RegisterPass 251 | E("speculative-swoop", "Hoisting and reusing all loads.", false, false); 252 | 253 | //===----------------------------------------------------------------------===// 254 | // SmartDAE implementation: hoist all no & may LCDs, prefetch all, and reuse none. 255 | 256 | namespace { 257 | struct SmartDAE : public OptimisticSwoop { 258 | static char ID; 259 | SmartDAE() : OptimisticSwoop(INT_MAX) {} 260 | 261 | protected: 262 | void divideLoads(list &toHoist, 263 | list &toPref, 264 | list &toReuse, 265 | list &toLoad, 266 | unsigned int UnrollCount) override; 267 | void selectInstructionsToReuseInExecute(Function *F, set *toKeep, set *toUpdateForNextPhases, 268 | LCDResult MinLCDRequirement, bool ReuseAll, bool ReuseBranchCondition) override ; 269 | 270 | }; 271 | } 272 | 273 | void SmartDAE::divideLoads(list &toHoist, 274 | list &toPref, 275 | list &toReuse, 276 | list &toLoad, 277 | unsigned int UnrollCount) { 278 | toPref.insert(toPref.end(), toHoist.begin(), toHoist.end()); 279 | } 280 | 281 | void SmartDAE::selectInstructionsToReuseInExecute(Function *F, set *toKeep, set *toUpdateForNextPhases, 282 | LCDResult MinLCDRequirement, bool ReuseAll, bool ReuseBranchCondition) { 283 | BasicBlock &EntryBlock = F->getEntryBlock(); 284 | for (BasicBlock::iterator I = EntryBlock.begin(), IE = EntryBlock.end(); I != IE; ++I) { 285 | if (toKeep->insert(&*I).second) { 286 | toUpdateForNextPhases->insert(&*I); 287 | } 288 | } 289 | } 290 | 291 | char SmartDAE::ID = 0; 292 | static RegisterPass 293 | F("smartdae", "Hoisting and prefetching all may & no aliases. Reuse none.", false, false); 294 | } 295 | 296 | -------------------------------------------------------------------------------- /compiler/projects/src/SWOOP/Transform/PhaseStitching.cpp: -------------------------------------------------------------------------------- 1 | //===--------------- PhaseStitching.cpp - Utils to stitch Access/Execute Phases 2 | //---------------------===// 3 | // 4 | // The LLVM Compiler Infrastructure 5 | // 6 | // This file is distributed under the University of Illinois Open Source 7 | // License. See LICENSE.TXT for details. 8 | // 9 | //===----------------------------------------------------------------------===// 10 | /// \file PhaseStitching.cpp 11 | /// 12 | /// \brief 13 | /// 14 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 15 | /// the LICENSE file for details. 16 | // 17 | // 18 | //===----------------------------------------------------------------------===// 19 | 20 | #include "PhaseStitching.h" 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "llvm/Analysis/AliasAnalysis.h" 27 | 28 | #include "llvm/Transforms/Utils/Cloning.h" 29 | 30 | #include "llvm/Analysis/Interval.h" 31 | #include "llvm/Analysis/LoopPass.h" 32 | #include "llvm/IR/Constants.h" 33 | #include "llvm/IR/IRBuilder.h" 34 | #include "llvm/IR/InlineAsm.h" 35 | #include "llvm/IR/Intrinsics.h" 36 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" 37 | 38 | #define PRINTSTREAM errs() // raw_ostream 39 | 40 | using namespace llvm; 41 | using namespace std; 42 | 43 | static std::string ASSEMBLY_SIDE_EFFECT_CONSTRAINT = 44 | "~{dirflag},~{fpsr},~{flags},~{memory}"; 45 | 46 | BasicBlock *getExecuteRoot(Function *F); 47 | BasicBlock *getExecuteLatch(BasicBlock *executeRoot, BasicBlock *executeBody); 48 | 49 | Value *findInsertionPoint(DominatorTree *DT, BasicBlock *Use, Instruction *Def, 50 | set &RelevantBlocks, 51 | map &ValToUseCache); 52 | void collectPhiNodes(BasicBlock *bb, vector &bbPN); 53 | void insertMissingPhiForAccess(BasicBlock *accessBody, BasicBlock *executeBody, 54 | BasicBlock *accessRoot, BasicBlock *executeRoot); 55 | void insertMissingIncomingForOriginal(BasicBlock *accessBody, BasicBlock *executeBody, 56 | BasicBlock *accessRoot, 57 | BasicBlock *executeRoot, 58 | ValueToValueMapTy &VMapRev); 59 | void replaceDuplicatePhiNodes(Loop *L); 60 | 61 | BasicBlock *getExitingBlock(BasicBlock *latch); 62 | 63 | void insertMissingPhiNodesForDomination(Loop *L, DominatorTree *DT, 64 | vector &executeBlocks, 65 | BasicBlock *root); 66 | bool simplifyLoopLatch(Loop *L, LoopInfo *LI, DominatorTree *DT); 67 | 68 | void insertInlineAssembly(LLVMContext &context, std::string &asmString, 69 | Instruction *insertBeforeInstruction, 70 | std::string &constraints); 71 | void makeLabel(string prefix, string stage, string *label, int phaseCount); 72 | void replaceSuccessor(BasicBlock *B, BasicBlock *toReplace, BasicBlock *toUse); 73 | 74 | struct equivalentPhiNode { 75 | public: 76 | equivalentPhiNode(const PHINode *wantedPN) : wanted(wantedPN) {} 77 | 78 | bool operator()(const PHINode *PN) { 79 | if (wanted->getType() != PN->getType()) { 80 | return false; 81 | } 82 | 83 | 84 | bool SameRootVal = false; 85 | for (int i = 0; i < wanted->getNumIncomingValues(); ++i) { 86 | for (int j = 0; j < PN->getNumIncomingValues(); ++j) { 87 | if (wanted->getIncomingValue(i) == PN->getIncomingValue(j)) { 88 | SameRootVal = true; 89 | } 90 | if (wanted->getIncomingBlock(i) == PN->getIncomingBlock(j)) { 91 | return false; 92 | } 93 | } 94 | } 95 | 96 | return SameRootVal; 97 | } 98 | 99 | private: 100 | const PHINode *wanted; 101 | }; 102 | 103 | struct samePhiNode { 104 | public: 105 | samePhiNode(const PHINode *wantedPN) : wanted(wantedPN) {} 106 | 107 | bool operator()(const PHINode *PN) { 108 | bool sameType = wanted->getType() == PN->getType(); 109 | bool sameNumIncoming = 110 | wanted->getNumIncomingValues() == PN->getNumIncomingValues(); 111 | 112 | if (!sameType || !sameNumIncoming) { 113 | return false; 114 | } 115 | 116 | for (int i = 0; i < wanted->getNumIncomingValues(); ++i) { 117 | bool sameIncomingBlock = 118 | wanted->getIncomingBlock(i) == PN->getIncomingBlock(i); 119 | bool sameIncomingValue = 120 | wanted->getIncomingValue(i) == PN->getIncomingValue(i); 121 | 122 | if (!sameIncomingValue || !sameIncomingValue) { 123 | return false; 124 | } 125 | } 126 | 127 | return true; 128 | } 129 | 130 | private: 131 | const PHINode *wanted; 132 | }; 133 | 134 | void replaceSuccessor(BasicBlock *B, BasicBlock *toReplace, BasicBlock *toUse) { 135 | BranchInst *EBI = dyn_cast(B->getTerminator()); 136 | int indexOfSuccessorToReplace = 0; 137 | 138 | while (EBI->getSuccessor(indexOfSuccessorToReplace) != toReplace) { 139 | ++indexOfSuccessorToReplace; 140 | } 141 | EBI->setSuccessor(indexOfSuccessorToReplace, toUse); 142 | } 143 | 144 | void makeLabel(string prefix, string stage, string *label, int phaseCount) { 145 | *label = to_string(phaseCount) + ":"; 146 | } 147 | 148 | BasicBlock *getExitingBlock(BasicBlock *latch) { 149 | BasicBlock *executeBodyEnd; 150 | TerminatorInst *TI = latch->getTerminator(); 151 | 152 | if (TI->getNumSuccessors() == 1) { 153 | executeBodyEnd = latch->getSinglePredecessor(); 154 | } else { 155 | executeBodyEnd = latch; 156 | } 157 | return executeBodyEnd; 158 | } 159 | 160 | void insertInlineAssembly(LLVMContext &context, string &asmString, 161 | Instruction *insertBeforeInstruction, 162 | string &constraints) { 163 | FunctionType *AsmFTy = FunctionType::get(Type::getVoidTy(context), false); 164 | InlineAsm *IA = InlineAsm::get(AsmFTy, asmString, constraints, true, false); 165 | vector AsmArgs; 166 | CallInst::Create(IA, Twine(""), insertBeforeInstruction); 167 | } 168 | 169 | void gatherSuccessorsWithinLoop(BasicBlock *B, set &Succs, 170 | Loop *L) { 171 | std::queue ToVisit; 172 | 173 | ToVisit.push(B); 174 | Succs.insert(B); 175 | 176 | while (!ToVisit.empty()) { 177 | BasicBlock *Succ = ToVisit.front(); 178 | ToVisit.pop(); 179 | 180 | for (auto S = succ_begin(Succ), SE = succ_end(Succ); S != SE; ++S) { 181 | // Do not take back edges when adding successors 182 | if ((*S) != L->getHeader() && Succs.insert(*S).second) { 183 | ToVisit.push(*S); 184 | } 185 | } 186 | } 187 | } 188 | 189 | void insertMissingPhiNodesForDomination( 190 | Loop *L, DominatorTree *DT, vector &blocksMissingPhiNodes, 191 | BasicBlock *root) { 192 | DT->recalculate(*(L->getHeader()->getParent())); 193 | 194 | for (auto BI = blocksMissingPhiNodes.begin(), 195 | BE = blocksMissingPhiNodes.end(); 196 | BI != BE; ++BI) { 197 | BasicBlock *bb = *BI; 198 | 199 | for (BasicBlock::iterator II = bb->begin(), IE = bb->end(); II != IE; 200 | ++II) { 201 | Instruction *I = &*II; 202 | PHINode *PN = dyn_cast(I); 203 | for (User::op_iterator OI = I->op_begin(), OE = I->op_end(); OI != OE; 204 | ++OI) { 205 | 206 | if (*OI == nullptr) { 207 | continue; 208 | } 209 | 210 | if (Instruction *VI = dyn_cast(*OI)) { 211 | BasicBlock *ToDominate = bb; 212 | if (PN) { 213 | // In case of Phi Nodes, the definition needs to 214 | // dominate the incoming block instead 215 | ToDominate = PN->getIncomingBlock(*OI); 216 | } 217 | if (VI->getParent() != ToDominate && !DT->dominates(VI, ToDominate)) { 218 | map ValToUseCache; 219 | std::set Succs; 220 | gatherSuccessorsWithinLoop(VI->getParent(), Succs, L); 221 | Value *instructionToUse = 222 | findInsertionPoint(DT, root, VI, Succs, ValToUseCache); 223 | I->replaceUsesOfWith(*OI, instructionToUse); 224 | } 225 | } 226 | } 227 | } 228 | } 229 | } 230 | 231 | void replaceDuplicatePhiNodes(Loop *L) { 232 | for (auto BI = L->block_begin(), BE = L->block_end(); BI != BE; ++BI) { 233 | vector uniquePhiNodes; 234 | vector toDelete; 235 | 236 | for (BasicBlock::iterator aI = (*BI)->begin(); isa(aI); ++aI) { 237 | PHINode *aPN = dyn_cast(&*aI); 238 | 239 | auto foundPN = find_if(uniquePhiNodes.begin(), uniquePhiNodes.end(), 240 | samePhiNode(aPN)); 241 | if (foundPN == uniquePhiNodes.end()) { 242 | 243 | // If a phi node is unique, keep it 244 | uniquePhiNodes.push_back(aPN); 245 | } else { 246 | 247 | // Otherwise, replace all uses of this phi node with the duplicate 248 | aPN->replaceAllUsesWith(*foundPN); 249 | toDelete.push_back(aPN); 250 | } 251 | } 252 | 253 | // Remove all duplicate phi nodes 254 | for (auto PNI = toDelete.begin(), PNE = toDelete.end(); PNI != PNE; ++PNI) { 255 | (*PNI)->eraseFromParent(); 256 | } 257 | } 258 | } 259 | 260 | bool simplifyLoopLatch(Loop *L, LoopInfo *LI, DominatorTree *DT) { 261 | BasicBlock *Latch = L->getLoopLatch(); 262 | if (!Latch || Latch->hasAddressTaken()) 263 | return false; 264 | 265 | BranchInst *Jmp = dyn_cast(Latch->getTerminator()); 266 | if (!Jmp || !Jmp->isUnconditional()) 267 | return false; 268 | 269 | BasicBlock *LastExit = Latch->getSinglePredecessor(); 270 | if (!LastExit || !L->isLoopExiting(LastExit)) 271 | return false; 272 | 273 | BranchInst *BI = dyn_cast(LastExit->getTerminator()); 274 | if (!BI) 275 | return false; 276 | 277 | // Hoist the instructions from Latch into LastExit. 278 | LastExit->getInstList().splice(BI->getIterator(), Latch->getInstList(), 279 | Latch->begin(), Jmp->getIterator()); 280 | 281 | unsigned FallThruPath = BI->getSuccessor(0) == Latch ? 0 : 1; 282 | BasicBlock *Header = Jmp->getSuccessor(0); 283 | assert(Header == L->getHeader() && "expected a backward branch"); 284 | 285 | // Remove Latch from the CFG so that LastExit becomes the new Latch. 286 | BI->setSuccessor(FallThruPath, Header); 287 | Latch->replaceSuccessorsPhiUsesWith(LastExit); 288 | Jmp->eraseFromParent(); 289 | 290 | // Nuke the Latch block. 291 | assert(Latch->empty() && "unable to evacuate Latch"); 292 | LI->removeBlock(Latch); 293 | DT->eraseNode(Latch); 294 | Latch->eraseFromParent(); 295 | return true; 296 | } 297 | 298 | void insertMissingIncomingForOriginal(BasicBlock *accessBody, BasicBlock *executeBody, 299 | BasicBlock *accessRoot, 300 | BasicBlock *executeRoot, 301 | ValueToValueMapTy &VMapRev) { 302 | vector executePN; 303 | collectPhiNodes(executeBody, executePN); 304 | 305 | vector accessPN; 306 | collectPhiNodes(accessBody, accessPN); 307 | 308 | 309 | for (vector::iterator P = executePN.begin(), PE = executePN.end(); 310 | P != PE; ++P) { 311 | PHINode *PN = *P; 312 | Value *MappedValue = VMapRev[PN]; 313 | 314 | if (MappedValue) { 315 | PHINode *AccessEquivPN = dyn_cast(MappedValue); 316 | for (int i = 0; i < PN->getNumIncomingValues(); ++i) { 317 | BasicBlock *IncomingBlock = PN->getIncomingBlock(i); 318 | if (IncomingBlock != executeRoot) { 319 | AccessEquivPN->addIncoming(PN->getIncomingValue(i), IncomingBlock); 320 | } 321 | } 322 | PN->replaceAllUsesWith(AccessEquivPN); 323 | PN->eraseFromParent(); 324 | } 325 | } 326 | } 327 | 328 | void collectPhiNodes(BasicBlock *bb, vector &bbPN) { 329 | for (BasicBlock::iterator aI = bb->begin(); isa(aI); ++aI) { 330 | PHINode *aPN = dyn_cast(&*aI); 331 | bbPN.push_back(aPN); 332 | } 333 | } 334 | 335 | Value *findInsertionPoint(DominatorTree *DT, BasicBlock *UseBB, 336 | Instruction *Def, set &RelevantBlocks, 337 | map &ValToUseCache) { 338 | BasicBlock *Use = UseBB; 339 | bool firstRun = true; 340 | do { 341 | if (!firstRun) { 342 | Use = Use->getSinglePredecessor(); 343 | } 344 | 345 | if (ValToUseCache.find(Use) != ValToUseCache.end()) { 346 | return ValToUseCache[Use]; 347 | } 348 | 349 | if (RelevantBlocks.find(Use) == RelevantBlocks.end()) { 350 | Value *ToUse = UndefValue::get(Def->getType()); 351 | ValToUseCache[Use] = ToUse; 352 | return ToUse; 353 | } 354 | 355 | if (Def->getParent() == Use || DT->dominates(Def, Use)) { 356 | ValToUseCache[Use] = Def; 357 | return Def; 358 | } 359 | 360 | // Unnecessary (?): because it won't be in RelevantBlocks 361 | // if (DT->dominates(Use, Def->getParent())) { 362 | // // No definition could be found for this path 363 | // return UndefValue::get(Def->getType()); 364 | // } 365 | 366 | if (pred_begin(Use) == pred_end(Use)) { 367 | // Nowhere to search anymore. 368 | Value *ToUse = UndefValue::get(Def->getType()); 369 | ValToUseCache[Use] = ToUse; 370 | return ToUse; 371 | } 372 | 373 | firstRun = false; 374 | } while (Use->getSinglePredecessor()); 375 | 376 | // Otherwise, a PHI might be necessary 377 | list> IncomingVals; 378 | bool allIncomingAreEqual = true; 379 | Value *Incoming; 380 | 381 | auto PI = pred_begin(Use), PE = pred_end(Use); 382 | Incoming = findInsertionPoint(DT, *PI, Def, RelevantBlocks, ValToUseCache); 383 | IncomingVals.push_back(make_pair(*PI, Incoming)); 384 | ++PI; 385 | 386 | while (PI != PE) { 387 | Value *IncomingForPred = 388 | findInsertionPoint(DT, *PI, Def, RelevantBlocks, ValToUseCache); 389 | IncomingVals.push_back(make_pair(*PI, IncomingForPred)); 390 | if (IncomingForPred != Incoming) { 391 | allIncomingAreEqual = false; 392 | } 393 | ++PI; 394 | } 395 | 396 | Value *ToUse; 397 | if (allIncomingAreEqual) { 398 | ToUse = Incoming; 399 | } else { 400 | PHINode *newPHI = 401 | PHINode::Create(Def->getType(), 0, Twine(Def->getName().str() + ".phi"), 402 | &(Use->front())); 403 | for (auto V = IncomingVals.begin(), VE = IncomingVals.end(); V != VE; ++V) { 404 | newPHI->addIncoming((*V).second, (*V).first); 405 | } 406 | ToUse = newPHI; 407 | } 408 | 409 | ValToUseCache[Use] = ToUse; 410 | return ToUse; 411 | } 412 | 413 | BasicBlock *getExecuteLatch(BasicBlock *executeRoot, BasicBlock *executeBody) { 414 | BasicBlock *executeLatch; 415 | for (auto it = pred_begin(executeBody); it != pred_end(executeBody); ++it) { 416 | BasicBlock *b = *it; 417 | if (b != executeRoot) { 418 | executeLatch = b; 419 | break; 420 | } 421 | } 422 | return executeLatch; 423 | } 424 | 425 | BasicBlock *getExecuteRoot(Function *F) { 426 | BasicBlock *executeRoot = nullptr; 427 | for (Function::iterator i = F->begin(), e = F->end(); i != e; ++i) { 428 | if (i->hasNUses(0) && &*i != &(F->getEntryBlock())) { 429 | executeRoot = &*i; 430 | break; 431 | } 432 | } 433 | return executeRoot; 434 | } 435 | 436 | // bool toAdaptForOracle(Loop *L) { 437 | // Function *F = L->getHeader()->getParent(); 438 | // if (F->getName().str().find(F_KERNEL_SUBSTR) != std::string::npos && 439 | // L->getLoopPreheader() && &(F->getEntryBlock()) == 440 | // L->getLoopPreheader()) { 441 | // return true; 442 | // } 443 | // return false; 444 | // } 445 | 446 | Loop *getLoop(Function &F, LoopInfo &LI) { 447 | return LI.getLoopFor(F.getEntryBlock().getTerminator()->getSuccessor(0)); 448 | } 449 | 450 | bool stitch(Function &F, Function &ToAppend, ValueToValueMapTy &VMap, ValueToValueMapTy &VMapRev, LoopInfo &LI, DominatorTree &DT, 451 | bool forceIncrement, string type, int phaseCount) { 452 | Loop *L = getLoop(F, LI); 453 | BasicBlock *accessLatch = L->getLoopLatch(); 454 | BasicBlock *accessExit = L->getUniqueExitBlock(); 455 | BasicBlock *accessBody = L->getHeader(); 456 | BasicBlock *accessRoot = L->getLoopPredecessor(); 457 | 458 | BasicBlock *executeRoot = &(ToAppend.getEntryBlock()); 459 | TerminatorInst *executeRootEnd = executeRoot->getTerminator(); 460 | if (executeRootEnd->getNumSuccessors() != 1) { 461 | errs() << "Expected unconditional jump in execute root.\n"; 462 | return false; 463 | } 464 | 465 | BasicBlock *executeBody = executeRootEnd->getSuccessor(0); 466 | BasicBlock *executeLatch = getExecuteLatch(executeRoot, executeBody); 467 | BasicBlock *executeBodyEnd = getExitingBlock(executeLatch); 468 | BasicBlock *executeExit; 469 | 470 | F.getBasicBlockList().splice(F.end(), ToAppend.getBasicBlockList()); 471 | ToAppend.removeFromParent(); 472 | 473 | // Find exiting block 474 | BasicBlock *accessBodyEnd = NULL; 475 | SmallVector AccessExitingBlocks; 476 | L->getExitingBlocks(AccessExitingBlocks); 477 | 478 | // Gather all execute blocks 479 | vector executeBlocks; 480 | 481 | for (Function::iterator i = F.begin(), e = F.end(); i != e; ++i) { 482 | BasicBlock *BB = &*i; 483 | if (!L->contains(BB) && BB != accessExit && 484 | BB != accessRoot) { // Do not re-add access blocks 485 | if (isa(BB->getTerminator())) { 486 | 487 | // do not add to loop - it's already part of the function 488 | executeExit = BB; 489 | } else { 490 | L->addBasicBlockToLoop(BB, LI); 491 | executeBlocks.push_back(BB); 492 | } 493 | } 494 | } 495 | 496 | // Remove jump from execute latch to execute body 497 | replaceSuccessor(executeLatch, executeBody, accessBody); 498 | 499 | if (AccessExitingBlocks.size() == 1) { 500 | accessBodyEnd = *(AccessExitingBlocks.begin()); 501 | } else { 502 | // We assume: if several exiting blocks exist, the loop was unrolled 503 | for (SmallVectorImpl::iterator 504 | BB = AccessExitingBlocks.begin(), 505 | BE = AccessExitingBlocks.end(); 506 | BB != BE; ++BB) { 507 | BasicBlock *B = *BB; 508 | TerminatorInst *TI = B->getTerminator(); 509 | bool isIntermediate = false; 510 | for (int i = 0; i < TI->getNumSuccessors(); ++i) { 511 | BasicBlock *S = TI->getSuccessor(i); 512 | if (S != accessBody && S != accessExit) { 513 | isIntermediate = true; 514 | } 515 | } 516 | 517 | if (!isIntermediate) { 518 | // there should only be one 519 | accessBodyEnd = B; 520 | } 521 | } 522 | } 523 | 524 | // Remove jump to access exit/access latch 525 | TerminatorInst *TI = accessLatch->getTerminator(); 526 | TI->eraseFromParent(); 527 | 528 | if (forceIncrement) { 529 | // for now, this is hw-swoop 530 | IRBuilder<> builder(accessLatch); 531 | FunctionType *AsmFTy = 532 | FunctionType::get(Type::getInt1Ty(accessBodyEnd->getContext()), false); 533 | std::string condition = "=r" + ASSEMBLY_SIDE_EFFECT_CONSTRAINT; 534 | InlineAsm *IA = 535 | InlineAsm::get(AsmFTy, "movb $$0, $0", condition, true, false); 536 | 537 | vector AsmArgs; 538 | CallInst *callInst = CallInst::Create(IA, Twine("ckmiss"), accessLatch); 539 | 540 | BranchInst::Create(accessBody, accessExit, callInst, accessLatch); 541 | } else { 542 | BranchInst::Create(accessExit, accessLatch); 543 | } 544 | 545 | Instruction *AccessReturnI = accessExit->getTerminator(); 546 | BranchInst *AccessExitBI = BranchInst::Create(executeRoot); 547 | ReplaceInstWithInst(AccessReturnI, AccessExitBI); 548 | L->addBasicBlockToLoop(accessExit, LI); 549 | 550 | // Replace phi nodes in execute phase by values that should be used 551 | vector accessReplaceWith, executeReplace; 552 | accessReplaceWith.push_back(accessBody); 553 | executeReplace.push_back(executeBody); 554 | 555 | insertMissingIncomingForOriginal(accessBody, executeBody, accessRoot, executeRoot, VMapRev); 556 | 557 | // For all other values that are already computed in the access phase to 558 | // be transferred from execute -> access, insert a phi value 559 | for (BasicBlock::iterator aI = (accessBody)->begin(); isa(aI); 560 | ++aI) { 561 | PHINode *PN = dyn_cast(&*aI); 562 | 563 | if (PN->getBasicBlockIndex(accessLatch) != -1 && 564 | PN->getBasicBlockIndex(executeLatch) == -1) { 565 | Value *AccessPhiVal = PN->getIncomingValueForBlock(accessLatch); 566 | PN->addIncoming(AccessPhiVal, executeLatch); 567 | 568 | if (!forceIncrement) { 569 | PN->removeIncomingValue(accessLatch); 570 | } 571 | } 572 | 573 | Value *Undef = UndefValue::get(PN->getType()); 574 | for (int i = 0; i < PN->getNumIncomingValues(); ++i) { 575 | // Remove all incoming values that are undef 576 | if (PN->getIncomingValue(i) == Undef) { 577 | PN->removeIncomingValue(i); 578 | } 579 | } 580 | } 581 | 582 | // clean up phi nodes after removing the jump from the latch 583 | vector accessPN; 584 | collectPhiNodes(accessBody, accessPN); 585 | 586 | for (vector::iterator P = accessPN.begin(), PE = accessPN.end(); 587 | P != PE; ++P) { 588 | PHINode *PN = *P; 589 | int LatchIndex = PN->getBasicBlockIndex(accessLatch); 590 | if (LatchIndex >= 0) { 591 | PN->removeIncomingValue(LatchIndex); 592 | } 593 | } 594 | 595 | // Insert inline assembly labels and separator between access and execute 596 | std::string prefix = F.getName().str() + "_"; 597 | std::string accessLabel, accessEndLabel; 598 | std::string executeLabel, executeEndLabel; 599 | 600 | makeLabel(prefix, type, &executeLabel, phaseCount); 601 | makeLabel(prefix, type + "_end", &executeEndLabel, phaseCount); 602 | LLVMContext &context = F.getContext(); 603 | 604 | insertInlineAssembly(context, executeLabel, &*(executeRoot->begin()), 605 | ASSEMBLY_SIDE_EFFECT_CONSTRAINT); 606 | insertInlineAssembly(context, executeEndLabel, 607 | executeBodyEnd->getTerminator(), 608 | ASSEMBLY_SIDE_EFFECT_CONSTRAINT); 609 | 610 | // Now that we're done with combining access + execute, make sure that 611 | // all added basic blocks to the Loop are actually part of the loop.. 612 | DT.recalculate(*(L->getHeader()->getParent())); 613 | 614 | for (auto P = pred_begin(executeExit), PE = pred_end(executeExit); P != PE; 615 | ++P) { 616 | BasicBlock *Pred = *P; 617 | if (!DT.dominates(Pred, executeExit) && L->contains(Pred)) { 618 | vector MissingPNBlock; 619 | MissingPNBlock.push_back(Pred); 620 | insertMissingPhiNodesForDomination(L, &DT, MissingPNBlock, executeRoot); 621 | 622 | L->removeBlockFromLoop(Pred); 623 | } 624 | } 625 | 626 | return true; 627 | } 628 | 629 | bool stitchAEDecision(Function &F, Function &Optimized, ValueToValueMapTy &VMapRev, AllocaInst *branch_cond, 630 | BasicBlock *DecisionBlock, 631 | LoopInfo &LI, DominatorTree &DT, 632 | string type, int phaseCount) { 633 | Loop *L = getLoop(F, LI); 634 | BasicBlock *accessLatch = L->getLoopLatch(); 635 | BasicBlock *accessExit = L->getUniqueExitBlock(); 636 | BasicBlock *accessBody = L->getHeader(); 637 | BasicBlock *accessRoot = L->getLoopPredecessor(); 638 | 639 | BasicBlock *executeRoot = &(Optimized.getEntryBlock()); 640 | TerminatorInst *executeRootEnd = executeRoot->getTerminator(); 641 | if (executeRootEnd->getNumSuccessors() != 1) { 642 | errs() << "Expected unconditional jump in execute root.\n"; 643 | return false; 644 | } 645 | 646 | BasicBlock *executeBody = executeRootEnd->getSuccessor(0); 647 | BasicBlock *executeLatch = getExecuteLatch(executeRoot, executeBody); 648 | BasicBlock *executeBodyEnd = getExitingBlock(executeLatch); 649 | BasicBlock *executeExit; 650 | 651 | F.getBasicBlockList().splice(F.end(), Optimized.getBasicBlockList()); 652 | Optimized.removeFromParent(); 653 | 654 | // Find exiting block 655 | BasicBlock *accessBodyEnd = NULL; 656 | SmallVector AccessExitingBlocks; 657 | L->getExitingBlocks(AccessExitingBlocks); 658 | 659 | // Gather all execute blocks 660 | vector executeBlocks; 661 | 662 | for (Function::iterator i = F.begin(), e = F.end(); i != e; ++i) { 663 | BasicBlock *BB = &*i; 664 | if (!L->contains(BB) && BB != accessExit && 665 | BB != accessRoot) { // Do not re-add access blocks 666 | if (isa(BB->getTerminator())) { 667 | 668 | // do not add to loop - it's already part of the function 669 | executeExit = BB; 670 | } else { 671 | L->addBasicBlockToLoop(BB, LI); 672 | executeBlocks.push_back(BB); 673 | } 674 | } 675 | } 676 | 677 | // Remove jump from execute latch to execute body 678 | replaceSuccessor(executeLatch, executeBody, accessBody); 679 | 680 | if (AccessExitingBlocks.size() == 1) { 681 | accessBodyEnd = *(AccessExitingBlocks.begin()); 682 | } else { 683 | // We assume: if several exiting blocks exist, the loop was unrolled 684 | for (SmallVectorImpl::iterator 685 | BB = AccessExitingBlocks.begin(), 686 | BE = AccessExitingBlocks.end(); 687 | BB != BE; ++BB) { 688 | BasicBlock *B = *BB; 689 | TerminatorInst *TI = B->getTerminator(); 690 | bool isIntermediate = false; 691 | for (int i = 0; i < TI->getNumSuccessors(); ++i) { 692 | BasicBlock *S = TI->getSuccessor(i); 693 | if (S != accessBody && S != accessExit) { 694 | isIntermediate = true; 695 | } 696 | } 697 | 698 | if (!isIntermediate) { 699 | // there should only be one 700 | accessBodyEnd = B; 701 | } 702 | } 703 | } 704 | 705 | TerminatorInst *DecisionBlockTI = DecisionBlock->getTerminator(); 706 | IRBuilder<> Builder(DecisionBlockTI); 707 | BasicBlock *OptimizedAccessBB = DecisionBlockTI->getSuccessor(0); 708 | LoadInst *branch_value = Builder.CreateLoad(branch_cond); 709 | Builder.CreateCondBr(branch_value, OptimizedAccessBB, executeRoot); 710 | DecisionBlockTI->eraseFromParent(); 711 | 712 | // Replace phi nodes in execute phase by values that should be used 713 | vector accessReplaceWith, executeReplace; 714 | accessReplaceWith.push_back(accessBody); 715 | executeReplace.push_back(executeBody); 716 | 717 | insertMissingIncomingForOriginal(accessBody, executeBody, accessRoot, executeRoot, VMapRev); 718 | 719 | // For all other values that are already computed in the access phase to 720 | // be transferred from execute -> access, insert a phi value 721 | for (BasicBlock::iterator aI = (accessBody)->begin(); isa(aI); 722 | ++aI) { 723 | PHINode *PN = dyn_cast(&*aI); 724 | 725 | if (PN->getBasicBlockIndex(accessLatch) != -1 && 726 | PN->getBasicBlockIndex(executeLatch) == -1) { 727 | Value *AccessPhiVal = PN->getIncomingValueForBlock(accessLatch); 728 | PN->addIncoming(AccessPhiVal, executeLatch); 729 | 730 | //PN->removeIncomingValue(accessLatch); 731 | } 732 | 733 | Value *Undef = UndefValue::get(PN->getType()); 734 | for (int i = 0; i < PN->getNumIncomingValues(); ++i) { 735 | // Remove all incoming values that are undef 736 | if (PN->getIncomingValue(i) == Undef) { 737 | PN->removeIncomingValue(i); 738 | } 739 | } 740 | } 741 | 742 | 743 | 744 | 745 | // Insert inline assembly labels and separator between access and execute 746 | std::string prefix = F.getName().str() + "_"; 747 | std::string accessLabel, accessEndLabel; 748 | std::string executeLabel, executeEndLabel; 749 | 750 | makeLabel(prefix, type, &executeLabel, phaseCount); 751 | makeLabel(prefix, type + "_end", &executeEndLabel, phaseCount); 752 | LLVMContext &context = F.getContext(); 753 | 754 | insertInlineAssembly(context, executeLabel, &*(executeRoot->begin()), 755 | ASSEMBLY_SIDE_EFFECT_CONSTRAINT); 756 | insertInlineAssembly(context, executeEndLabel, 757 | executeBodyEnd->getTerminator(), 758 | ASSEMBLY_SIDE_EFFECT_CONSTRAINT); 759 | 760 | // Now that we're done with combining access + execute, make sure that 761 | // all added basic blocks to the Loop are actually part of the loop.. 762 | DT.recalculate(*(L->getHeader()->getParent())); 763 | 764 | for (auto P = pred_begin(executeExit), PE = pred_end(executeExit); P != PE; 765 | ++P) { 766 | BasicBlock *Pred = *P; 767 | if (!DT.dominates(Pred, executeExit) && L->contains(Pred)) { 768 | vector MissingPNBlock; 769 | MissingPNBlock.push_back(Pred); 770 | insertMissingPhiNodesForDomination(L, &DT, MissingPNBlock, executeRoot); 771 | 772 | L->removeBlockFromLoop(Pred); 773 | } 774 | } 775 | 776 | return true; 777 | } 778 | 779 | void ensureStrictSSA(Function &F, LoopInfo &LI, DominatorTree &DT, 780 | vector &PhaseRoots) { 781 | // Insert lacking phi nodes: if a value defined during the access phase 782 | // is used in the execute phase, but its definition does not 783 | // dominate all paths to 784 | // that usage, phi nodes with undefined values need to be introduced. 785 | // This is acceptable, as we assume here that a value is only used, 786 | // if the path including its definition was taken. 787 | Loop *L = getLoop(F, LI); 788 | 789 | int numberOfPhases = PhaseRoots.size(); 790 | for (int i = 0; i < numberOfPhases; ++i) { 791 | set PotentiallyMissingPN; 792 | queue BBQ; 793 | 794 | 795 | BBQ.push(PhaseRoots[i]); 796 | PotentiallyMissingPN.insert(PhaseRoots[i]); 797 | while (!BBQ.empty()) { 798 | BasicBlock *B = BBQ.front(); 799 | BBQ.pop(); 800 | if (!LI.getLoopFor(B) || (i < numberOfPhases - 1) && B == PhaseRoots[i + 1]) { 801 | continue; 802 | } 803 | 804 | for (auto S = succ_begin(B), SE = succ_end(B); S != SE; ++S) { 805 | if (PotentiallyMissingPN.insert(*S).second && (*S) != L->getHeader()) { 806 | BBQ.push(*S); 807 | } 808 | } 809 | } 810 | 811 | vector BlocksToProcess = vector( 812 | PotentiallyMissingPN.begin(), PotentiallyMissingPN.end()); 813 | insertMissingPhiNodesForDomination(L, &DT, BlocksToProcess, PhaseRoots[i]); 814 | } 815 | 816 | // replace phi nodes with the same incoming values, 817 | // that were added due to the previous step 818 | replaceDuplicatePhiNodes(L); 819 | } 820 | -------------------------------------------------------------------------------- /compiler/projects/src/SWOOP/Transform/PhaseStitching.h: -------------------------------------------------------------------------------- 1 | 2 | //===- Phase Stitching -*- C++ -*-===// 3 | // 4 | // The LLVM Compiler Infrastructure 5 | // 6 | // This file is distributed under the University of Illinois Open Source 7 | // License. See LICENSE.TXT for details. 8 | // 9 | /// \file PhaseStitching.h 10 | /// 11 | /// \brief 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | //===----------------------------------------------------------------------===// 16 | // 17 | // 18 | //===----------------------------------------------------------------------===// 19 | 20 | #ifndef SWOOP_TRANSFORM_PHASE_STITCHING_H 21 | #define SWOOP_TRANSFORM_PHASE_STITCHING_H 22 | 23 | #include "llvm/Analysis/LoopInfo.h" 24 | #include "llvm/IR/Dominators.h" 25 | #include "llvm/IR/Function.h" 26 | #include "llvm/Support/GenericDomTree.h" 27 | #include "llvm/Transforms/Utils/ValueMapper.h" 28 | #include 29 | 30 | using namespace std; 31 | using namespace llvm; 32 | 33 | 34 | bool stitchAEDecision(Function &F, Function &Optimized, ValueToValueMapTy &VMapRev, AllocaInst *branch_cond, 35 | BasicBlock *DecisionBlock, 36 | LoopInfo &LI, DominatorTree &DT, 37 | string type, int phaseCount); 38 | 39 | bool stitch(Function &F, Function &ToAppend, ValueToValueMapTy &VMap, ValueToValueMapTy &VMapRev, LoopInfo &LI, DominatorTree &DT, 40 | bool forceIncrement, string type, int phaseCount); 41 | void ensureStrictSSA(Function &F, LoopInfo &LI, DominatorTree &DT, 42 | vector &PhaseRoots); 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /compiler/projects/src/SWOOP/Transform/SwoopDAE/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) Eta Scale AB. Licensed under the Eta Scale Open Source License. See the LICENSE file for details. 3 | add_library(SwoopDAE SHARED 4 | SwoopDAE.cpp 5 | ${PROJECTS_MAIN_SRC_DIR}/Util/Annotation/MetadataInfo.cpp 6 | ${PROJECTS_MAIN_SRC_DIR}/Util/Analysis/AliasUtils.cpp 7 | ${PROJECTS_MAIN_SRC_DIR}/Util/DAE/DAEUtils.cpp 8 | ${PROJECTS_MAIN_SRC_DIR}/Util/Analysis/LoopDependency.cpp 9 | ${PROJECTS_MAIN_SRC_DIR}/Util/Transform/BranchMerge/BranchMerge.cpp 10 | ${SWOOP_MAIN_INCLUDE_DIR} 11 | ${PROJECTS_MAIN_INCLUDE_DIR} 12 | LCDHandler.cpp 13 | FindInstructions.cpp 14 | ../PhaseStitching.cpp 15 | ../ 16 | ) 17 | 18 | target_compile_options(SwoopDAE PRIVATE -fPIC) 19 | -------------------------------------------------------------------------------- /compiler/projects/src/SWOOP/Transform/SwoopDAE/FindInstructions.cpp: -------------------------------------------------------------------------------- 1 | //===--------------- FindInstructions.cpp - Finding load insts-------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file FindInstructions.cpp 10 | /// 11 | /// \brief 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | // 16 | // This file is a helper class containing functionality to find instructions 17 | // to hoist. 18 | // 19 | //===----------------------------------------------------------------------===// 20 | #include "FindInstructions.h" 21 | 22 | #include "Util/DAE/DAEUtils.h" 23 | #include "../../Utils/LongLatency.cpp" 24 | #include "Util/Analysis/LoopCarriedDependencyAnalysis.h" 25 | #include "LCDHandler.h" 26 | 27 | void filterLoadsOnInterferingDeps(AliasAnalysis *AA, LoopInfo *LI, list &Loads, 28 | list &Hoistable, Function &F); 29 | void filterLoadsOnIndir(AliasAnalysis *AA, LoopInfo *LI, list &LoadList, list &IndirList, 30 | unsigned int IndirThresh); 31 | 32 | 33 | // Overwrite to only pick delinquent loads 34 | void findRelevantLoads(Function &F, list &LoadList, bool HoistDelinquent) { 35 | if (HoistDelinquent) { 36 | findDelinquentLoads(F, LoadList); 37 | } else { 38 | findLoads(F, LoadList); 39 | } 40 | } 41 | 42 | void filterLoadsOnInterferingDeps(AliasAnalysis *AA, LoopInfo *LI, list &Loads, 43 | list &Hoistable, Function &F) { 44 | // Hoistable, if CFG to this block doesn't require global stores / calls 45 | for (auto L = Loads.begin(), LE = Loads.end(); L != LE; ++L) { 46 | // this loads immediate deps 47 | set Deps; 48 | 49 | // this laads populated deps in followDeps 50 | set DepSet; 51 | getRequirementsInIteration(AA, LI, *L, Deps); 52 | if (followDeps(AA, Deps, DepSet)) { 53 | Hoistable.push_back(*L); 54 | } 55 | } 56 | } 57 | 58 | void filterLoadsOnIndir(AliasAnalysis *AA, LoopInfo *LI, list &LoadList, list &IndirList, 59 | unsigned int IndirThresh) { 60 | for (list::iterator I = LoadList.begin(), E = LoadList.end(); I != E; ++I) { 61 | set Deps; 62 | getDeps(AA, LI, *I, Deps); 63 | int DataIndirCount = count_if(Deps.begin(), Deps.end(), 64 | [&](Instruction *DepI){return isa(DepI) && LI->getLoopFor(DepI->getParent());}); 65 | bool UnderDataThreshold = DataIndirCount <= IndirThresh; 66 | bool UnderCFGThreshold = !InstrhasMetadataKind(*I, "CFGIndir") || 67 | stoi(getInstructionMD(*I, "CFGIndir")) <= IndirThresh; 68 | 69 | if (UnderDataThreshold && UnderCFGThreshold) { 70 | IndirList.push_back(*I); 71 | } 72 | // else: hits indir threshold 73 | } 74 | } 75 | 76 | void findAccessInsts(AliasAnalysis *AA, LoopInfo *LI, Function &fun, list &toHoist, bool HoistDelinquent, 77 | unsigned int IndirThresh) { 78 | list LoadList, VisibleList, IndirLoads; 79 | 80 | unsigned int BadDeps, Indir; 81 | 82 | // Find all existing load instructions 83 | findRelevantLoads(fun, LoadList, HoistDelinquent); 84 | 85 | findVisibleLoads(LoadList, VisibleList); 86 | 87 | // Filter on the number of allowed indirections to hoist 88 | filterLoadsOnIndir(AA, LI, VisibleList, IndirLoads, IndirThresh); 89 | Indir = VisibleList.size() - IndirLoads.size(); 90 | 91 | anotateStores(AA, fun, IndirLoads); 92 | 93 | // Hoistable depending on terminator instructions 94 | filterLoadsOnInterferingDeps(AA, LI, IndirLoads, toHoist, fun); 95 | 96 | BadDeps = IndirLoads.size() - toHoist.size(); 97 | 98 | errs() << "(BadDeps: " << BadDeps << ", Indir: " << Indir << ")\n"; 99 | } 100 | -------------------------------------------------------------------------------- /compiler/projects/src/SWOOP/Transform/SwoopDAE/FindInstructions.h: -------------------------------------------------------------------------------- 1 | //===----------------------- FindInstructions.h --------------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file FindInstructions.h 10 | /// 11 | /// \brief 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | // 16 | // This file is a helper class containing functionality to find instructions 17 | // to hoist. 18 | // 19 | //===----------------------------------------------------------------------===//// 20 | #ifndef PROJECT_FINDINSTRUCTIONS_H 21 | #define PROJECT_FINDINSTRUCTIONS_H 22 | 23 | #include 24 | #include "llvm/IR/Function.h" 25 | #include "llvm/IR/Instructions.h" 26 | #include 27 | #include "SWOOP/Transform/SwoopDAE/BasicSwoop.h" 28 | 29 | using namespace llvm; 30 | using namespace std; 31 | 32 | void findAccessInsts(AliasAnalysis *AA, LoopInfo *LI, Function &fun, list &toHoist, bool HoistDelinquent, 33 | unsigned int IndirThresh); 34 | void findRelevantLoads(Function &F, list &LoadList, bool HoistDelinquent); 35 | 36 | #endif //PROJECT_FINDINSTRUCTIONS_H 37 | -------------------------------------------------------------------------------- /compiler/projects/src/SWOOP/Transform/SwoopDAE/LCDHandler.cpp: -------------------------------------------------------------------------------- 1 | //===--------------- LCDHandler.cpp - LCD Helper fro SWOOP-----------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file LCDHandler.cpp 10 | /// 11 | /// \brief 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | // 16 | // This file is a helper class containing functionality to handle LCD. 17 | // 18 | //===----------------------------------------------------------------------===// 19 | #include "LCDHandler.h" 20 | 21 | #include 22 | #include "Util/Analysis/AliasUtils.h" 23 | 24 | #undef LCD_BASED_DISAMBIGUATION 25 | 26 | #ifdef LCD_BASED_DISAMBIGUATION 27 | static const char *LCD_TAG = "LCD"; 28 | static const char *LCD_DISTANCE_TAG = "Distance"; 29 | #endif 30 | 31 | 32 | AliasResult aliasWithStore(AliasAnalysis *AA, LoadInst *LInst, Loop *L) { 33 | BasicBlock *loadBB = LInst->getParent(); 34 | Value *Pointer = LInst->getPointerOperand(); 35 | AliasResult AliasRes = AliasResult::NoAlias; 36 | 37 | // Keep track of which blocks we already visited 38 | queue < BasicBlock * > BBQ; 39 | set < BasicBlock * > BBSet; 40 | BBQ.push(loadBB); 41 | bool first = true; 42 | 43 | // While the aliasing is not a MustAlias yet (strongest alias) 44 | while (!BBQ.empty() && AliasRes != AliasResult::MustAlias) { 45 | BasicBlock *BB = BBQ.front(); 46 | BBQ.pop(); 47 | 48 | // Analyze all store instructions that precede the load 49 | // in this block 50 | BasicBlock::reverse_iterator RI(LInst->getIterator()); 51 | for (BasicBlock::reverse_iterator iI = first ? RI : BB->rbegin(), 52 | iE = BB->rend(); 53 | iI != iE; ++iI) { 54 | if (StoreInst::classof(&(*iI))) { 55 | StoreInst *SInst = (StoreInst * ) & (*iI); 56 | 57 | switch (pointerAlias(AA, SInst->getPointerOperand(), Pointer, 58 | iI->getModule()->getDataLayout())) { 59 | case AliasResult::NoAlias:break; // Already default value. 60 | case AliasResult::MayAlias: 61 | if (AliasRes == AliasResult::NoAlias) { 62 | AliasRes = AliasResult::MayAlias; 63 | } 64 | break; 65 | case AliasResult::PartialAlias: 66 | if (AliasRes == AliasResult::NoAlias || 67 | AliasRes == AliasResult::MayAlias) { 68 | AliasRes = AliasResult::PartialAlias; 69 | } 70 | break; 71 | case AliasResult::MustAlias:AliasRes = AliasResult::MustAlias; // Highest value. 72 | break; 73 | } 74 | } 75 | } 76 | 77 | // Insert all predecessors of BB 78 | if (BB != L->getHeader()) { 79 | for (pred_iterator pI = pred_begin(BB), pE = pred_end(BB); pI != pE; 80 | ++pI) { 81 | if (BBSet.insert(*pI).second) { 82 | BBQ.push(*pI); 83 | } 84 | } 85 | } 86 | first = false; 87 | } 88 | return AliasRes; 89 | } 90 | 91 | // Returns true if the combined LCD from toCheck is at least the value of toExpect (or even 92 | // more flexible). I.e. MayAlias + NoAlias are MayAlias in combination, which in turn 93 | // is too unflexible for NoAlias, but would return true for MayAlias and MustAlias. 94 | bool expectAtLeast(AliasAnalysis *AA, LoopInfo *LI, set &toCheck, LCDResult toExpect) { 95 | set::iterator I, IE; 96 | for (I = toCheck.begin(), IE = toCheck.end(); I != IE; ++I) { 97 | if (LI->getLoopFor((*I)->getParent())) { 98 | if (getLCDInfo(AA, LI, *I, 0) > toExpect) { 99 | return false; 100 | } 101 | } 102 | } 103 | return true; 104 | } 105 | 106 | LCDResult getLCDInfo(AliasAnalysis *AA, LoopInfo *LI, Instruction *I, unsigned int UnrollCount) { 107 | LCDResult LCDRes = LCDResult::NoLCD; 108 | 109 | // There is no loop around this instruction - so there cannot 110 | // be an lcd 111 | if (!LI->getLoopFor(I->getParent())) { 112 | return LCDResult::NoLCD; 113 | } 114 | 115 | if (!isa(I)) { 116 | return LCDResult::NoLCD; 117 | } 118 | 119 | #ifdef LCD_BASED_DISAMBIGUATION 120 | // Do not consider the lcd analysis for now - only the alias 121 | // analysis 122 | if (InstrhasMetadataKind(I, LCD_TAG)) { 123 | if (InstrhasMetadataKind(I, LCD_DISTANCE_TAG)) { 124 | long int distance = stol(getInstructionMD(I, LCD_DISTANCE_TAG)); 125 | if (distance <= UnrollCount) { 126 | LCDRes = fromString(getInstructionMD(I, LCD_TAG)); 127 | } 128 | } 129 | else { 130 | LCDRes = fromString(getInstructionMD(I, LCD_TAG)); 131 | } 132 | } 133 | 134 | if (LCDRes == LCDResult::MustLCD) { 135 | return LCDRes; 136 | } 137 | #endif 138 | 139 | AliasResult Alias = 140 | aliasWithStore(AA, (LoadInst *)I, LI->getLoopFor(I->getParent())); 141 | LCDResult LCDStore; 142 | switch (Alias) { 143 | case NoAlias: 144 | LCDStore = LCDResult::NoLCD; 145 | break; 146 | case MayAlias: 147 | LCDStore = LCDResult::MayLCD; 148 | break; 149 | case PartialAlias: 150 | case MustAlias: 151 | LCDStore = LCDResult::MustLCD; 152 | break; 153 | default: 154 | // None existing: something went wrong? Be conservative. 155 | LCDStore = LCDResult::MustLCD; 156 | break; 157 | } 158 | 159 | LCDRes = LoopCarriedDependencyAnalysis::combineLCD(LCDRes, LCDStore); 160 | return LCDRes; 161 | } 162 | 163 | 164 | LCDResult getLCDUnion(AliasAnalysis *AA, LoopInfo *LI, set &toCombine) { 165 | LCDResult Res = LCDResult::NoLCD; 166 | set::iterator I, IE; 167 | for (I = toCombine.begin(), IE = toCombine.end(); I != IE; ++I) { 168 | if (LI->getLoopFor((*I)->getParent())) { 169 | Res = LoopCarriedDependencyAnalysis::combineLCD(getLCDInfo(AA, LI, *I, 0), Res); 170 | } 171 | } 172 | 173 | return Res; 174 | } 175 | -------------------------------------------------------------------------------- /compiler/projects/src/SWOOP/Transform/SwoopDAE/LCDHandler.h: -------------------------------------------------------------------------------- 1 | //===--------------- LCDHandler.h - LCD Helper fro SWOOP-----------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file LCDHandler.h 10 | /// 11 | /// \brief 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | // 16 | // This file is a helper class containing functionality to handle LCD. 17 | // 18 | //===----------------------------------------------------------------------===// 19 | #ifndef PROJECT_LCDHANDLER_H 20 | #define PROJECT_LCDHANDLER_H 21 | 22 | #include 23 | #include "llvm/Analysis/LoopInfo.h" 24 | 25 | #include "Util/Analysis/LoopCarriedDependencyAnalysis.h" 26 | 27 | 28 | using namespace llvm; 29 | using namespace std; 30 | using namespace util; 31 | 32 | bool expectAtLeast(AliasAnalysis *AA, LoopInfo *LI, set &toCheck, LCDResult toExpect); 33 | LCDResult getLCDInfo(AliasAnalysis *AA, LoopInfo *LI, Instruction *I, unsigned int UnrollCount); 34 | LCDResult getLCDUnion(AliasAnalysis *AA, LoopInfo *LI, set &toCombine); 35 | 36 | 37 | #endif //PROJECT_LCDHANDLER_H 38 | -------------------------------------------------------------------------------- /compiler/projects/src/SWOOP/Utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) Eta Scale AB. Licensed under the Eta Scale Open Source License. See the LICENSE file for details. 3 | add_subdirectory(MarkLoopsToSwoopify) 4 | 5 | 6 | -------------------------------------------------------------------------------- /compiler/projects/src/SWOOP/Utils/DCEutils.cpp: -------------------------------------------------------------------------------- 1 | //===- DCEutils.cpp - Kill unsafe stores with backups --------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file DCEutils.cpp 10 | /// 11 | /// \brief 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | // 16 | // Description of pass ... 17 | // 18 | //===----------------------------------------------------------------------===// 19 | #include "llvm/Transforms/Utils/Local.h" 20 | 21 | bool SimplifyCFGperFunction(Function *F, TargetTransformInfo &TTI, 22 | unsigned bonusInstThreshold) { 23 | 24 | bool modif = false; 25 | Function::iterator bbI = F->begin(), bbE = F->end(); 26 | while (bbI != bbE) { 27 | // Function::iterator helper(bbI); 28 | modif = SimplifyCFG(&*bbI, TTI, bonusInstThreshold); 29 | if (modif) 30 | bbI = F->begin(); // helper; 31 | else 32 | bbI++; 33 | } 34 | } 35 | 36 | bool SimplifyCFGExclude(Function *F, TargetTransformInfo &TTI, 37 | unsigned bonusInstThreshold, 38 | vector excludeList) { 39 | 40 | bool modif = false; 41 | Function::iterator bbI = F->begin(), bbE = F->end(); 42 | while (bbI != bbE) { 43 | if (std::find(excludeList.begin(), excludeList.end(), &*bbI) == 44 | excludeList.end()) { 45 | modif = SimplifyCFG(&*bbI, TTI, bonusInstThreshold); 46 | } else { 47 | modif = false; 48 | } 49 | if (modif) 50 | bbI = F->begin(); // helper; 51 | else 52 | bbI++; 53 | } 54 | } 55 | 56 | void simplifyCFG(Function *F, TargetTransformInfo &TTI) { 57 | // simplify the CFG of A to remove dead code 58 | vector excludeInCfg; 59 | excludeInCfg.push_back(&(F->getEntryBlock())); 60 | excludeInCfg.push_back(F->getEntryBlock().getTerminator()->getSuccessor(0)); 61 | 62 | SimplifyCFGExclude(F, TTI, 0, excludeInCfg); 63 | } 64 | 65 | -------------------------------------------------------------------------------- /compiler/projects/src/SWOOP/Utils/LongLatency.cpp: -------------------------------------------------------------------------------- 1 | //===- LongLatency.cpp - Kill unsafe stores with backups 2 | //--------------------===// 3 | // 4 | // The LLVM Compiler Infrastructure 5 | // 6 | // This file is distributed under the University of Illinois Open Source 7 | // License. See LICENSE.TXT for details. 8 | // 9 | //===----------------------------------------------------------------------===// 10 | /// \file LongLatency.cpp 11 | /// 12 | /// \brief 13 | /// 14 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 15 | /// the LICENSE file for details. 16 | // 17 | // Description of pass ... 18 | // 19 | //===----------------------------------------------------------------------===// 20 | #ifndef LongLatency_ 21 | #define LongLatency_ 22 | 23 | #include "Util/Annotation/MetadataInfo.h" 24 | #include 25 | 26 | using namespace util; 27 | 28 | // Instructions are marked as Long Latency I with metadata information 29 | bool isLongLatency(Instruction *I) { 30 | return InstrhasMetadata(I, "Latency", "Long"); 31 | } 32 | 33 | // Adds pointer to all long latency LoadInsts in F to LoadList. 34 | void findDelinquentLoads(Function &F, list &LoadList) { 35 | for (inst_iterator iI = inst_begin(F), iE = inst_end(F); iI != iE; ++iI) { 36 | if (LoadInst::classof(&(*iI)) && isLongLatency(&(*iI))) { 37 | LoadList.push_back((LoadInst *)&(*iI)); 38 | } 39 | } 40 | } 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /compiler/projects/src/SWOOP/Utils/MarkLoopsToSwoopify/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) Eta Scale AB. Licensed under the Eta Scale Open Source License. See the LICENSE file for details. 3 | add_library(MarkLoopsToSwoopify 4 | SHARED 5 | MarkLoopsToSwoopify.cpp 6 | ${PROJECTS_MAIN_SRC_DIR}/Util/Annotation/MetadataInfo.cpp 7 | ${PROJECTS_MAIN_INCLUDE_DIR}/Util/Annotation ) 8 | 9 | -------------------------------------------------------------------------------- /compiler/projects/src/SWOOP/Utils/MarkLoopsToSwoopify/MarkLoopsToSwoopify.cpp: -------------------------------------------------------------------------------- 1 | //===- MarkLoopsToSwoopify.cpp - Kill unsafe stores with backups 2 | //--------------------===// 3 | // 4 | // The LLVM Compiler Infrastructure 5 | // 6 | // This file is distributed under the University of Illinois Open Source 7 | // License. See LICENSE.TXT for details. 8 | // 9 | //===----------------------------------------------------------------------===// 10 | /// \file MarkLoopsToSwoopify.cpp 11 | /// 12 | /// \brief 13 | /// 14 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 15 | /// the LICENSE file for details. 16 | // 17 | // Description of pass ... 18 | // 19 | //===----------------------------------------------------------------------===// 20 | #include "llvm/Analysis/LoopPass.h" 21 | 22 | #include "../../../DAE/Utils/SkelUtils/Utils.cpp" 23 | 24 | #define KERNEL_MARKING "__kernel__" 25 | 26 | using namespace llvm; 27 | 28 | static cl::opt BenchName("bench-name", 29 | cl::desc("The benchmark name"), 30 | cl::value_desc("name")); 31 | 32 | static cl::opt RequireDelinquent( 33 | "require-delinquent", 34 | cl::desc("Loop has to contain delinquent loads to be marked"), 35 | cl::init(true)); 36 | 37 | namespace { 38 | struct MarkLoopsToSwoopify : public FunctionPass { 39 | public: 40 | static char ID; 41 | MarkLoopsToSwoopify() : FunctionPass(ID) {} 42 | 43 | virtual void getAnalysisUsage(AnalysisUsage &AU) const { 44 | AU.addRequired(); 45 | AU.addRequired(); 46 | } 47 | 48 | bool runOnFunction(Function &F); 49 | 50 | private: 51 | unsigned loopCounter = 0; 52 | bool markLoops(std::vector Loops, DominatorTree &DT); 53 | }; 54 | } 55 | 56 | bool MarkLoopsToSwoopify::runOnFunction(Function &F) { 57 | if (!toBeDAE(&F)) { 58 | return false; 59 | } 60 | 61 | DominatorTree &DT = getAnalysis().getDomTree(); 62 | LoopInfo &LI = getAnalysis().getLoopInfo(); 63 | std::vector Loops(LI.begin(), LI.end()); 64 | 65 | return markLoops(Loops, DT); 66 | } 67 | 68 | bool MarkLoopsToSwoopify::markLoops(std::vector Loops, 69 | DominatorTree &DT) { 70 | bool markedLoop = false; 71 | 72 | for (auto I = Loops.begin(), IE = Loops.end(); I != IE; ++I) { 73 | Loop *L = *I; 74 | if (loopToBeDAE(L, BenchName, RequireDelinquent)) { 75 | BasicBlock *H = L->getHeader(); 76 | H->setName(Twine(KERNEL_MARKING + H->getParent()->getName().str() + 77 | std::to_string(loopCounter))); 78 | loopCounter++; 79 | markedLoop = true; 80 | } 81 | 82 | std::vector subLoops = L->getSubLoops(); 83 | bool subLoopsMarked = markLoops(subLoops, DT); 84 | markedLoop = markedLoop || subLoopsMarked; 85 | } 86 | 87 | return markedLoop; 88 | } 89 | 90 | char MarkLoopsToSwoopify::ID = 1; 91 | static RegisterPass 92 | X("mark-loops", "Mark loops to swoopify pass", true, false); 93 | -------------------------------------------------------------------------------- /compiler/projects/src/Util/Analysis/AliasUtils.cpp: -------------------------------------------------------------------------------- 1 | //===------ AliasUtils.cpp - Utils for alias analysis ---------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file AliasUtils.cpp 10 | /// 11 | /// \brief Utilities for alias analysis 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | // 16 | // 17 | //===----------------------------------------------------------------------===// 18 | #include "Util/Analysis/AliasUtils.h" 19 | 20 | namespace util { 21 | static void findStores(Function &F, list &StoreList) { 22 | for (inst_iterator iI = inst_begin(F), iE = inst_end(F); iI != iE; ++iI) { 23 | if (StoreInst::classof(&(*iI))) { 24 | StoreList.push_back((StoreInst *)&(*iI)); 25 | } 26 | } 27 | } 28 | 29 | AliasResult pointerAlias(AliasAnalysis *AA, Value *P1, Value *P2, const DataLayout &DL) { 30 | uint64_t P1Size = MemoryLocation::UnknownSize; 31 | Type *P1ElTy = cast(P1->getType())->getElementType(); 32 | if (P1ElTy->isSized()) { 33 | P1Size = DL.getTypeStoreSize(P1ElTy); 34 | } 35 | 36 | uint64_t P2Size = MemoryLocation::UnknownSize; 37 | Type *P2ElTy = cast(P2->getType())->getElementType(); 38 | if (P2ElTy->isSized()) { 39 | P2Size = DL.getTypeStoreSize(P2ElTy); 40 | 41 | return AA->alias(P1, P1Size, P2, P2Size); 42 | } 43 | } 44 | 45 | // Returns the closest alias between store and any of the LoadInsts 46 | // in toPref. 47 | AliasResult crossCheck(AliasAnalysis *AA, StoreInst *store, list &toPref) { 48 | AliasResult closest = AliasResult::NoAlias; 49 | Value *storePointer = store->getPointerOperand(); 50 | for (list::iterator I = toPref.begin(), E = toPref.end(); 51 | I != E && closest != AliasResult::MustAlias; ++I) { 52 | Value *loadPointer = (*I)->getPointerOperand(); 53 | switch (pointerAlias(AA, storePointer, loadPointer, 54 | (*I)->getModule()->getDataLayout())) { 55 | case AliasResult::NoAlias: 56 | break; // Already default value. 57 | case AliasResult::MayAlias: 58 | if (closest == AliasResult::NoAlias) { 59 | closest = AliasResult::MayAlias; 60 | } 61 | break; 62 | case AliasResult::PartialAlias: 63 | if (closest == AliasResult::NoAlias || 64 | closest == AliasResult::MayAlias) { 65 | closest = AliasResult::PartialAlias; 66 | } 67 | break; 68 | case AliasResult::MustAlias: 69 | closest = AliasResult::MustAlias; // Highest value. 70 | break; 71 | } 72 | } 73 | return closest; 74 | } 75 | 76 | // Anotates stores in fun with the closest alias type to 77 | // any of the loads in toPref. (To be clear alias analysis are 78 | // performed between the address of each store and the address 79 | // of each load.) Results are annotated as metadata. 80 | void anotateStores(AliasAnalysis *AA, Function &fun, list &toPref) { 81 | list StoreList; 82 | findStores(fun, StoreList); 83 | for (list::iterator I = StoreList.begin(), E = StoreList.end(); 84 | I != E; I++) { 85 | string aliasLevel; 86 | switch (crossCheck(AA, *I, toPref)) { 87 | case AliasResult::NoAlias: 88 | aliasLevel = "NoAlias"; 89 | break; 90 | case AliasResult::MayAlias: 91 | aliasLevel = "MayAlias"; 92 | break; 93 | case AliasResult::PartialAlias: 94 | aliasLevel = "PartialAlias"; 95 | break; 96 | case AliasResult::MustAlias: 97 | aliasLevel = "MustAlias"; 98 | break; 99 | } 100 | AttachMetadata(*I, "GlobalAlias", aliasLevel); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /compiler/projects/src/Util/Analysis/BasicLCDAnalysis.cpp: -------------------------------------------------------------------------------- 1 | //===- LoopCarriedDependencyAnalysis - LCD Analysis based on LLVM DA ------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file BasicLCDAnalysis.cpp 10 | /// 11 | /// \brief 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | // 16 | // This file defines the loop carried dependency analysis based on information 17 | // gained from LLVM's dependence analysis. 18 | // 19 | //===----------------------------------------------------------------------===// 20 | 21 | #include "Util/Analysis/LoopCarriedDependencyAnalysis.h" 22 | #include "llvm/Analysis/AliasAnalysis.h" 23 | #include "llvm/Analysis/DependenceAnalysis.h" 24 | #include "llvm/Analysis/LoopInfo.h" 25 | #include "llvm/Analysis/ScalarEvolution.h" 26 | #include "llvm/Analysis/ScalarEvolutionExpressions.h" 27 | #include "llvm/IR/CFG.h" 28 | #include "llvm/IR/Instructions.h" 29 | #include "llvm/IR/ValueMap.h" 30 | #include "llvm/Pass.h" 31 | #include "llvm/PassRegistry.h" 32 | #include "llvm/Support/Debug.h" 33 | #include "llvm/Support/raw_ostream.h" 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #define DEBUG_TYPE "-lcd-analysis" 41 | 42 | using namespace llvm; 43 | using namespace util; 44 | 45 | namespace util { 46 | class BasicLCDAnalysis : public LoopCarriedDependencyAnalysis { 47 | public: 48 | BasicLCDAnalysis(DependenceAnalysis *DepA, LoopInfo *LoopI) 49 | : DA(DepA), LI(LoopI) {} 50 | 51 | ~BasicLCDAnalysis() { 52 | // std::map*>::iterator M, ME; 53 | // for (M = LoopToMemInst.begin(), ME = LoopToMemInst.end(); 54 | // M != ME; ++M) { 55 | // delete M->second; 56 | // } 57 | } 58 | 59 | const LCDResult checkLCD(Instruction *I, const Loop *L); 60 | bool getLCDDistance(Instruction *I, const Loop *L, long int &Distance); 61 | void setup(Function &F); 62 | 63 | private: 64 | DependenceAnalysis *DA; 65 | LoopInfo *LI; 66 | 67 | typedef std::pair DependenceKey; 68 | typedef SmallVector, 16> Dependences; 69 | typedef std::map> *> 71 | LCDCacheTy; 72 | LCDCacheTy LCDCache; 73 | 74 | typedef SmallVector InstVectorTy; 75 | std::map *> LoopToMemInst; 76 | 77 | SmallVectorImpl> * 78 | getLCDInfo(Instruction *I, SmallVectorImpl *MemInst, 79 | const Loop *L); 80 | 81 | SmallVectorImpl> *getDependencies(Instruction *I, 82 | const Loop *L); 83 | }; 84 | } 85 | 86 | void BasicLCDAnalysis::setup(Function &F) { 87 | std::queue Loops; 88 | 89 | for (LoopInfo::iterator L = LI->begin(), LE = LI->end(); L != LE; ++L) { 90 | Loops.push(*L); 91 | } 92 | 93 | while (!Loops.empty()) { 94 | const Loop *LP = Loops.front(); 95 | Loops.pop(); 96 | 97 | InstVectorTy *MemInst = new InstVectorTy(); 98 | collectMemInst(*LP, *MemInst); 99 | LoopToMemInst[LP] = MemInst; 100 | 101 | std::vector subLoops = LP->getSubLoops(); 102 | for (auto SL : subLoops) { 103 | Loops.push(SL); 104 | } 105 | } 106 | } 107 | 108 | bool BasicLCDAnalysis::getLCDDistance(Instruction *I, const Loop *L, 109 | long int &Distance) { 110 | SmallVectorImpl> *Deps = getDependencies(I, L); 111 | Distance = LONG_MAX; 112 | if (Deps->size() == 0) { 113 | // No dependencies existing 114 | return true; 115 | } 116 | 117 | bool ValidDistance = true; 118 | unsigned LoopLevel = L->getLoopDepth(); 119 | SmallVectorImpl>::iterator D = Deps->begin(); 120 | 121 | while (D != Deps->end()) { 122 | unsigned Levels = (*D)->getLevels(); 123 | if (Levels >= LoopLevel) { 124 | 125 | if ((*D)->isConfused()) { 126 | ValidDistance = false; 127 | break; 128 | } 129 | 130 | const SCEV *Dist = (*D)->getDistance(LoopLevel); 131 | const SCEVConstant *SCEVConst = dyn_cast_or_null(Dist); 132 | if (SCEVConst) { 133 | Distance = std::min(SCEVConst->getValue()->getSExtValue(), Distance); 134 | } else { 135 | ValidDistance = false; 136 | break; 137 | } 138 | } 139 | 140 | ++D; 141 | } 142 | 143 | return ValidDistance; 144 | } 145 | 146 | SmallVectorImpl> * 147 | BasicLCDAnalysis::getDependencies(Instruction *I, const Loop *L) { 148 | DependenceKey Key = std::make_pair(L, I); 149 | LCDCacheTy::iterator DepI = LCDCache.find(Key); 150 | 151 | SmallVectorImpl> *Deps; 152 | if (DepI == LCDCache.end()) { 153 | SmallVectorImpl *MemInst = LoopToMemInst[L]; 154 | Deps = getLCDInfo(I, MemInst, L); 155 | } else { 156 | Deps = DepI->second; 157 | } 158 | 159 | return Deps; 160 | } 161 | 162 | const LCDResult BasicLCDAnalysis::checkLCD(Instruction *I, const Loop *L) { 163 | if (!isa(I) && !isa(I)) { 164 | return LCDResult::NoLCD; 165 | } 166 | 167 | SmallVectorImpl> *Deps = getDependencies(I, L); 168 | unsigned LoopLevel = L->getLoopDepth(); 169 | SmallVectorImpl>::iterator D = Deps->begin(); 170 | LCDResult LCDRes = LCDResult::NoLCD; 171 | 172 | while (D != Deps->end() && LCDRes != LCDResult::MustLCD) { 173 | unsigned Levels = (*D)->getLevels(); 174 | if (Levels < LoopLevel) { 175 | ++D; 176 | continue; 177 | } 178 | 179 | if ((*D)->isConfused()) { 180 | LCDRes = LCDResult::MayLCD; 181 | ++D; 182 | continue; 183 | } 184 | 185 | unsigned Dir = (*D)->getDirection(LoopLevel); 186 | if (Dir == Dependence::DVEntry::EQ) { 187 | LCDRes = LCDResult::NoLCD; 188 | } else if (isa(I) && Dir == Dependence::DVEntry::LT) { 189 | LCDRes = LCDResult::NoLCD; 190 | } else if ((*D)->isOutput() || (*D)->isInput()) { 191 | LCDRes = LCDResult::NoLCD; 192 | } else { 193 | LCDRes = LCDResult::MustLCD; 194 | } 195 | ++D; 196 | } 197 | 198 | return LCDRes; 199 | } 200 | 201 | SmallVectorImpl> *BasicLCDAnalysis::getLCDInfo( 202 | Instruction *I, SmallVectorImpl *MemInst, const Loop *L) { 203 | 204 | LCDResult LCDRes = LCDResult::NoLCD; 205 | 206 | SmallVectorImpl> *Dependences = 207 | new SmallVector, 16>(); 208 | 209 | SmallVectorImpl::iterator MI, ME; 210 | Instruction *Src = I; 211 | for (MI = MemInst->begin(), ME = MemInst->end(); MI != ME; ++MI) { 212 | Instruction *Des = dyn_cast(*MI); 213 | 214 | if (Src == Des) { 215 | continue; 216 | } 217 | 218 | if (isa(Src) && isa(Des) || 219 | isa(Src) && isa(Des)) { 220 | continue; 221 | } 222 | 223 | bool PossiblyLoopIndependent = true; 224 | std::unique_ptr D = 225 | DA->depends(Src, Des, PossiblyLoopIndependent); 226 | if (D) { 227 | Dependences->push_back(std::unique_ptr(std::move(D))); 228 | } 229 | } 230 | 231 | LCDCache[std::make_pair(L, I)] = Dependences; 232 | return Dependences; 233 | } 234 | 235 | //===----------------------------------------------------------------------===// 236 | // BasicLCDAnalysis implementation 237 | // 238 | 239 | char LoopCarriedDependencyAnalysisWrapperPass::ID = 0; 240 | 241 | bool LoopCarriedDependencyAnalysisWrapperPass::runOnFunction(Function &F) { 242 | if (LCDAnalysis) { 243 | delete LCDAnalysis; 244 | } 245 | 246 | LCDAnalysis = 247 | new BasicLCDAnalysis(&getAnalysis(), 248 | &getAnalysis().getLoopInfo()); 249 | LCDAnalysis->setup(F); 250 | return false; 251 | } 252 | 253 | void LoopCarriedDependencyAnalysisWrapperPass::getAnalysisUsage( 254 | AnalysisUsage &AU) const { 255 | AU.setPreservesAll(); 256 | AU.addRequired(); 257 | AU.addRequired(); 258 | } 259 | 260 | void LoopCarriedDependencyAnalysisWrapperPass:: 261 | initializeLoopCarriedDependencyAnalysisWrapperPass() {} 262 | 263 | static RegisterPass 264 | X("lcd-analysis", "Loop-carried dependency analysis", true, true); 265 | -------------------------------------------------------------------------------- /compiler/projects/src/Util/Analysis/LoopDependency.cpp: -------------------------------------------------------------------------------- 1 | //===-------- LoopDependency.cpp - Requirements in Loop Iteration --===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file LoopDependency.cpp 10 | /// 11 | /// \brief 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | // 16 | // Implementation of LoopDependency.h 17 | //===----------------------------------------------------------------------===// 18 | 19 | #include "Util/Analysis/LoopDependency.h" 20 | #include "Util/Annotation/MetadataInfo.h" 21 | 22 | // Set the minimum alias requirement to follow a store. 23 | // Without flag stores are not followed at all. 24 | static cl::opt 25 | FollowMay("follow-may", 26 | cl::desc("Require at least MayAlias to follow store")); 27 | static cl::opt 28 | FollowPartial("follow-partial", 29 | cl::desc("Require at least PartialAlias to follow store")); 30 | static cl::opt 31 | FollowMust("follow-must", cl::desc("Require at MustAlias to follow store")); 32 | 33 | namespace util { 34 | // Adds Val to Set and Q provided it is an Instruction that has 35 | // never before been enqued to Q. This assumes that an Instruction 36 | // is present in Set iff it has been added to Q. 37 | static void enqueueInst(Value *Val, set &Set, 38 | queue &Q) { 39 | if (Instruction::classof(Val)) { 40 | Instruction *Inst = (Instruction *)Val; 41 | if (Set.insert(Inst).second) { // true if Inst was inserted 42 | Q.push(Inst); 43 | } 44 | } 45 | } 46 | 47 | // Enques the operands of Inst. 48 | static void enqueueOperands(Instruction *Inst, set &Set, 49 | queue &Q) { 50 | for (User::value_op_iterator I = Inst->value_op_begin(), 51 | E = Inst->value_op_end(); 52 | I != E; ++I) { 53 | enqueueInst(*I, Set, Q); 54 | } 55 | } 56 | 57 | 58 | // Adds all StoreInsts that could be responsible for the value read 59 | // by LInst to Set and Q under the same condition as in enqueueInst. 60 | void enqueueStores(AliasAnalysis *AA, LoadInst *LInst, set &Set, 61 | queue &Q) { 62 | BasicBlock *loadBB = LInst->getParent(); 63 | Value *Pointer = LInst->getPointerOperand(); 64 | queue BBQ; 65 | set BBSet; 66 | BBQ.push(loadBB); 67 | bool first = true; 68 | bool found; 69 | while (!BBQ.empty()) { 70 | BasicBlock *BB = BBQ.front(); 71 | BBQ.pop(); 72 | found = false; 73 | 74 | BasicBlock::reverse_iterator RI(LInst->getIterator()); 75 | for (BasicBlock::reverse_iterator iI = first ? RI : BB->rbegin(), 76 | iE = BB->rend(); 77 | iI != iE; ++iI) { 78 | if (StoreInst::classof(&(*iI))) { 79 | StoreInst *SInst = (StoreInst *)&(*iI); 80 | switch (pointerAlias(AA, SInst->getPointerOperand(), Pointer, 81 | iI->getModule()->getDataLayout())) { 82 | case AliasResult::MustAlias: 83 | if (FollowMust || FollowPartial || FollowMay) { 84 | found = true; 85 | enqueueInst(SInst, Set, Q); 86 | } 87 | break; 88 | case AliasResult::PartialAlias: 89 | if (FollowPartial || FollowMay) { 90 | enqueueInst(SInst, Set, Q); 91 | } 92 | break; 93 | case AliasResult::MayAlias: 94 | if (FollowMay) { 95 | enqueueInst(SInst, Set, Q); 96 | } 97 | break; 98 | case AliasResult::NoAlias: 99 | break; 100 | } 101 | } else if (Pointer == &(*iI)) { 102 | found = true; 103 | } 104 | } 105 | if (!found) { 106 | for (pred_iterator pI = pred_begin(BB), pE = pred_end(BB); pI != pE; 107 | ++pI) { 108 | if (BBSet.insert(*pI).second) { 109 | BBQ.push(*pI); 110 | } 111 | } 112 | } 113 | first = false; 114 | } 115 | } 116 | 117 | bool checkCalls(Instruction *I) { 118 | bool hasNoModifyingCalls = true; 119 | 120 | BasicBlock *InstBB = I->getParent(); 121 | std::queue BBQ; 122 | std::set BBSet; 123 | 124 | BBQ.push(InstBB); 125 | // Collect all predecessor blocks 126 | while (!BBQ.empty()) { 127 | BasicBlock *BB = BBQ.front(); 128 | BBQ.pop(); 129 | for (pred_iterator pI = pred_begin(BB), pE = pred_end(BB); pI != pE; 130 | ++pI) { 131 | if (BBSet.insert(*pI).second) { 132 | BBQ.push(*pI); 133 | } 134 | } 135 | } 136 | 137 | for (Value::user_iterator U = I->user_begin(), UE = I->user_end(); 138 | U != UE && hasNoModifyingCalls; ++U) { 139 | Instruction *UserInst = (Instruction *)*U; 140 | for (Value::user_iterator UU = UserInst->user_begin(), 141 | UUE = UserInst->user_end(); 142 | UU != UUE && hasNoModifyingCalls; ++UU) { 143 | if (!CallInst::classof(*UU)) { 144 | continue; 145 | } 146 | 147 | if (BBSet.find(((Instruction *)(*UU))->getParent()) == BBSet.end()) { 148 | continue; 149 | } 150 | 151 | CallInst *Call = (CallInst *)*UU; 152 | hasNoModifyingCalls = Call->onlyReadsMemory(); 153 | 154 | // Allow prefetches 155 | if (!hasNoModifyingCalls && isa(Call) && 156 | ((IntrinsicInst *)Call)->getIntrinsicID() == Intrinsic::prefetch) { 157 | hasNoModifyingCalls = true; 158 | } 159 | 160 | // Allow swoop types 161 | if (InstrhasMetadataKind(Call, "SwoopType")) { 162 | if ("ReuseHelper" == getInstructionMD(Call, "SwoopType")) { 163 | hasNoModifyingCalls = true; 164 | } 165 | } 166 | } 167 | } 168 | 169 | return hasNoModifyingCalls; 170 | } 171 | 172 | 173 | void getRequirementsInIteration(AliasAnalysis *AA, LoopInfo *LI, Instruction *I, set &DepSet, bool followStores) { 174 | set DataDeps; 175 | getDeps(AA, LI, I, DataDeps, followStores); 176 | for (Instruction *DataDep : DataDeps) { 177 | getControlDeps(AA, LI, DataDep, DepSet); 178 | } 179 | DepSet.insert(DataDeps.begin(), DataDeps.end()); 180 | } 181 | 182 | void getDeps(AliasAnalysis *AA, LoopInfo *LI, Instruction *I, set &DepSet, bool followStores) { 183 | queue Q; 184 | Q.push(I); 185 | 186 | // get enclosing loop 187 | const Loop *L = LI->getLoopFor(I->getParent()); 188 | BasicBlock *H; 189 | 190 | if (L) { 191 | H = L->getHeader(); 192 | } 193 | 194 | while (!Q.empty()) { 195 | Instruction *Inst = Q.front(); 196 | Q.pop(); 197 | 198 | // TODO: consider: do we want to include deps that are 199 | // in the entry block? 200 | if (L && Inst->getParent() == H && isa(Inst)) { 201 | // do not follow backedges to the head of the loop; 202 | // here we only consider requirements within _one_ 203 | // iteration 204 | continue; 205 | } 206 | 207 | enqueueOperands(Inst, DepSet, Q); 208 | if (followStores && LoadInst::classof(Inst)) { 209 | enqueueStores(AA, (LoadInst *)Inst, DepSet, Q); 210 | } 211 | } 212 | } 213 | 214 | void getControlDeps(AliasAnalysis *AA, LoopInfo *LI, Instruction *I, set &Deps) { 215 | set Starred; 216 | BasicBlock *BB = I->getParent(); 217 | std::queue Ancestors; 218 | 219 | const Loop *L = LI->getLoopFor(BB); 220 | if (!L || BB == L->getHeader()) { 221 | return; 222 | } 223 | 224 | // 1. Find all ancestors of the parent block that are 225 | // contained in the loop. 226 | Starred.insert(BB); 227 | Ancestors.push(BB); 228 | while (!Ancestors.empty()) { 229 | BasicBlock *B = Ancestors.front(); 230 | Ancestors.pop(); 231 | 232 | const Loop *L = LI->getLoopFor(B); 233 | if (!L || B == L->getHeader()) { 234 | continue; 235 | } 236 | 237 | for (auto P = pred_begin(B), PE = pred_end(B); P != PE; ++P) { 238 | if (Starred.insert(*P).second) { // succeeded inserting it 239 | Ancestors.push(*P); 240 | } 241 | } 242 | } 243 | 244 | 245 | // 2. Find all terminator instructions that are crucial to the 246 | // execution of I 247 | for (auto Ancestor : Starred) { 248 | 249 | bool isMandatory = false; 250 | for (succ_iterator S = succ_begin(Ancestor), SE = succ_end(Ancestor); S != SE && !isMandatory; ++S) { 251 | if (Ancestor == BB) { 252 | continue; 253 | } 254 | 255 | // If a successor is not one of the blocks ancestor's, then this 256 | // terminator instruction determines whether the instruction 257 | // will be executed or not 258 | isMandatory = Starred.find(*S) == Starred.end(); 259 | } 260 | 261 | if (isMandatory) { 262 | Deps.insert(Ancestor->getTerminator()); 263 | getDeps(AA, LI, Ancestor->getTerminator(), Deps); 264 | } 265 | } 266 | } 267 | 268 | bool followDeps(AliasAnalysis *AA, set &Set, set &DepSet, bool followStores, bool followCalls) { 269 | bool valid = true; 270 | queue Q; 271 | for (set::iterator I = Set.begin(), E = Set.end(); 272 | I != E; ++I) { 273 | enqueueOperands(*I, DepSet, Q); 274 | } 275 | 276 | while (!Q.empty()) { 277 | bool res = true; 278 | Instruction *Inst = Q.front(); 279 | Q.pop(); 280 | 281 | // Calls and non-local stores are prohibited. 282 | if (CallInst::classof(Inst)) { 283 | bool onlyReadsMemory = ((CallInst *)Inst)->onlyReadsMemory(); 284 | bool annotatedToBeLocal = InstrhasMetadata(Inst, "Call", "Local"); 285 | 286 | res = onlyReadsMemory || annotatedToBeLocal; 287 | if (!res) { 288 | errs() << " !call " << *Inst << "!>\n"; 289 | } 290 | } else if (StoreInst::classof(Inst)) { 291 | res = isLocalPointer(((StoreInst *)Inst)->getPointerOperand()); 292 | if (!res) { 293 | errs() << " \n"; 294 | } 295 | } 296 | if (res) { 297 | enqueueOperands(Inst, DepSet, Q); 298 | // Follow load/store 299 | if (followStores && LoadInst::classof(Inst)) { 300 | enqueueStores(AA, (LoadInst *)Inst, DepSet, Q); 301 | } 302 | if (followCalls) { 303 | res = checkCalls(Inst); 304 | } 305 | } else { 306 | valid = false; 307 | } 308 | 309 | } 310 | return valid; 311 | } 312 | 313 | bool followDeps(AliasAnalysis *AA, Instruction *Inst, set &DepSet) { 314 | set Set; 315 | Set.insert(Inst); 316 | return followDeps(AA, Set, DepSet); 317 | } 318 | 319 | void findTerminators(Function &F, set &CfgSet) { 320 | for (Function::iterator bbI = F.begin(), bbE = F.end(); bbI != bbE; ++bbI) { 321 | TerminatorInst *TInst = bbI->getTerminator(); 322 | if (TInst != NULL) { 323 | CfgSet.insert(TInst); 324 | } 325 | } 326 | } 327 | } 328 | -------------------------------------------------------------------------------- /compiler/projects/src/Util/Analysis/MarkLCD.cpp: -------------------------------------------------------------------------------- 1 | //===--------------- MarkLCD.cpp - Marking loop carried dependencies-------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file MarkLCD.cpp 10 | /// 11 | /// \brief 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | // 16 | // This file annotates memory operations in respect of loop carried 17 | // dependencies: 18 | // NoLCD, MayLCD, MustLCD. 19 | // 20 | // 21 | //===----------------------------------------------------------------------===// 22 | 23 | #include "Util/Analysis/LoopCarriedDependencyAnalysis.h" 24 | #include "Util/Annotation/MetadataInfo.h" 25 | #include "llvm/Analysis/AliasAnalysis.h" 26 | #include "llvm/Analysis/LoopPass.h" 27 | #include "llvm/IR/BasicBlock.h" 28 | #include "llvm/IR/Instructions.h" 29 | #include "llvm/Pass.h" 30 | 31 | using namespace llvm; 32 | using namespace std; 33 | using namespace util; 34 | 35 | #define F_KERNEL_SUBSTR "__kernel__" 36 | 37 | namespace { 38 | struct MarkLCD : public FunctionPass { 39 | static char ID; 40 | MarkLCD() : FunctionPass(ID) {} 41 | 42 | public: 43 | virtual void getAnalysisUsage(AnalysisUsage &AU) const { 44 | AU.addRequired(); 45 | AU.addRequired(); 46 | } 47 | 48 | bool runOnFunction(Function &F); 49 | 50 | private: 51 | LoopInfo *LI; 52 | LoopCarriedDependencyAnalysis *LCDAnalysis; 53 | }; 54 | } 55 | 56 | bool MarkLCD::runOnFunction(Function &F) { 57 | LI = &getAnalysis().getLoopInfo(); 58 | LCDAnalysis = 59 | &getAnalysis().getLCDAnalysis(); 60 | bool changed = false; 61 | 62 | std::queue loops; 63 | for (LoopInfo::iterator L = LI->begin(), LE = LI->end(); L != LE; ++L) { 64 | loops.push((*L)); 65 | } 66 | 67 | while (!loops.empty()) { 68 | Loop *L = loops.front(); 69 | loops.pop(); 70 | 71 | for (auto SL : L->getSubLoops()) { 72 | loops.push(SL); 73 | } 74 | 75 | if (L->getHeader()->getName().find(F_KERNEL_SUBSTR) == string::npos) { 76 | continue; 77 | } 78 | 79 | changed = true; 80 | 81 | for (Loop::block_iterator B = L->block_begin(), BE = L->block_end(); 82 | B != BE; ++B) { 83 | for (BasicBlock::iterator I = (*B)->begin(), IE = (*B)->end(); I != IE; 84 | ++I) { 85 | LCDResult LCDRes = LCDAnalysis->checkLCD(&(*I), L); 86 | AttachMetadata(&(*I), "LCD", getStringRep(LCDRes)); 87 | long int Distance; 88 | bool distanceCorrect = LCDAnalysis->getLCDDistance(&(*I), L, Distance); 89 | if (distanceCorrect) { 90 | AttachMetadata(&(*I), "Distance", to_string(Distance)); 91 | } 92 | } 93 | } 94 | } 95 | return changed; 96 | } 97 | 98 | char MarkLCD::ID = 0; 99 | static RegisterPass A("mark-lcd", 100 | "Marking memory operations with LCD information", 101 | false, false); 102 | -------------------------------------------------------------------------------- /compiler/projects/src/Util/Annotation/BranchAnnotate/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) Eta Scale AB. Licensed under the Eta Scale Open Source License. See the LICENSE file for details. 3 | add_library(BranchAnnotate MODULE 4 | SBPAnnotator.cpp 5 | ${PROJECTS_MAIN_SRC_DIR}/Util/Annotation/MetadataInfo.cpp 6 | ) 7 | -------------------------------------------------------------------------------- /compiler/projects/src/Util/Annotation/BranchAnnotate/Replace.cpp: -------------------------------------------------------------------------------- 1 | //===--------------- Replace.cpp - Replaces conditional branch------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file Replace.cpp 10 | /// 11 | /// \brief 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | // 16 | //===----------------------------------------------------------------------===// 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "llvm/Analysis/BranchProbabilityInfo.h" 25 | #include "llvm/ADT/PostOrderIterator.h" 26 | #include "llvm/Analysis/LoopInfo.h" 27 | #include "llvm/IR/CFG.h" 28 | #include "llvm/IR/Constants.h" 29 | #include "llvm/IR/Function.h" 30 | #include "llvm/IR/Instruction.h" 31 | #include "llvm/IR/Instructions.h" 32 | #include "llvm/IR/LLVMContext.h" 33 | #include "llvm/IR/Metadata.h" 34 | #include "llvm/Support/Debug.h" 35 | #include "llvm/Support/raw_ostream.h" 36 | #include "llvm/Support/FileSystem.h" 37 | 38 | #include "llvm/Transforms/Utils/Cloning.h" 39 | 40 | 41 | #include "llvm/IR/LLVMContext.h" 42 | #include "llvm/IR/Module.h" 43 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" 44 | #include "Util/Annotation/MetadataInfo.h" 45 | 46 | #define F_KERNEL_SUBSTR "__kernel__" 47 | #define EXECUTE_SUFFIX "_execute" 48 | #define CLONE_SUFFIX "_clone" 49 | 50 | BasicBlock *deepCopyBB(BasicBlock *src) { 51 | BasicBlock *dst = BasicBlock::Create(src->getContext()); 52 | for (BasicBlock::iterator iI = src->begin(), iE = src->end(); iI != iE; ++iI) { 53 | Instruction *c = iI->clone(); 54 | dst->getInstList().push_back(c); 55 | } 56 | return dst; 57 | } 58 | 59 | std::pair getProbabilityBranch(BranchInst *BI) { 60 | if (BI->getNumSuccessors() < 2) { 61 | return std::make_pair("1.0", "0.0"); 62 | } 63 | std::string string_bp0 = getBranchProb(BI, "BranchProb0"); 64 | std::string string_bp1 = getBranchProb(BI, "BranchProb1"); 65 | if (string_bp0.length() > 0 && string_bp1.length() > 0 ) { 66 | return std::make_pair(string_bp0, string_bp1); 67 | } 68 | return std::make_pair("0.0", "0.0"); 69 | } 70 | 71 | // pair represents: 72 | std::pair isReducableBranch(BranchInst *BI, double THRESHOLD) { 73 | if (BI->getNumSuccessors() < 2) { 74 | return std::make_pair(false, 0); 75 | } 76 | // We don't want to minimize the branches generated through 77 | // loopChunk ("stdin" tag represents the global virtual iterator) 78 | if (BI->isConditional()) { 79 | if (Value *vbi = dyn_cast(BI->getCondition())) { 80 | if (vbi->getName().str().find("stdin") != string::npos) { 81 | return std::make_pair(false, 0); 82 | } 83 | } 84 | } 85 | std::string string_bp0 = getBranchProb(BI, "BranchProb0"); 86 | std::string string_bp1 = getBranchProb(BI, "BranchProb1"); 87 | if (string_bp0.length() > 0 && string_bp1.length() > 0 ) { 88 | double bp0 = std::stod(string_bp0); 89 | double bp1 = std::stod(string_bp1); 90 | if (bp0 > THRESHOLD) { 91 | return std::make_pair(true, 0); 92 | } else if (bp1 > THRESHOLD) { 93 | return std::make_pair(true, 1); 94 | } 95 | } 96 | return std::make_pair(false, 0); 97 | } 98 | 99 | void replaceBranch(BasicBlock *block, double THRESHOLD) { 100 | TerminatorInst *TInst = block->getTerminator(); 101 | IRBuilder<> Builder(TInst); 102 | BranchInst *uncondBI; 103 | BasicBlock *dst, *comp; 104 | if (BranchInst *BI = dyn_cast(TInst)) { 105 | std::pair res = isReducableBranch(BI, THRESHOLD); 106 | if (res.first) { 107 | if (res.second == 0) { 108 | dst = BI->getSuccessor(0); 109 | comp = BI->getSuccessor(1); 110 | uncondBI = BranchInst::Create(dst); 111 | AttachMetadata(uncondBI, "BranchProb0", "1"); 112 | AttachMetadata(uncondBI, "BranchProb1", "0"); 113 | comp->removePredecessor(block); 114 | ReplaceInstWithInst(TInst, uncondBI); 115 | } else if (res.second == 1) { 116 | dst = BI->getSuccessor(1); 117 | comp = BI->getSuccessor(0); 118 | uncondBI = BranchInst::Create(dst); 119 | AttachMetadata(uncondBI, "BranchProb0", "0"); 120 | AttachMetadata(uncondBI, "BranchProb1", "1"); 121 | comp->removePredecessor(block); 122 | ReplaceInstWithInst(TInst, uncondBI); 123 | } 124 | } 125 | } 126 | } 127 | 128 | bool hasEnding (std::string fullString, std::string ending) { 129 | if (fullString.length() >= ending.length()) { 130 | return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending)); 131 | } else { 132 | return false; 133 | } 134 | } 135 | 136 | /* 137 | bool nameContains(Function &F, std::string s) { 138 | return 139 | F.getName().str().find(s) != std::string::npos; 140 | } 141 | */ 142 | 143 | bool minimizeFunctionFromBranchPred(Function *cF, double threshold) { 144 | errs() << "Optimizing function: " << cF->getName().str() << "\n"; 145 | for (Function::iterator block = cF->begin(), blockEnd = cF->end(); block != blockEnd; ++block) { 146 | replaceBranch(block, threshold); 147 | } 148 | return true; 149 | } 150 | 151 | bool isFKernel(Function &F) { 152 | return 153 | F.getName().str().find(F_KERNEL_SUBSTR) != std::string::npos; 154 | } 155 | -------------------------------------------------------------------------------- /compiler/projects/src/Util/Annotation/BranchAnnotate/SBPAnnotator.cpp: -------------------------------------------------------------------------------- 1 | //===--------------- SBPAnnotator.cpp - Annotator for branch merging ------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file SBPAnnotator.cpp 10 | /// 11 | /// \brief 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | // 16 | // Annotates branches with their static probability to be taken. 17 | // 18 | //===----------------------------------------------------------------------===// 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "llvm/Analysis/BranchProbabilityInfo.h" 28 | #include "llvm/ADT/PostOrderIterator.h" 29 | #include "llvm/Analysis/LoopInfo.h" 30 | #include "llvm/IR/CFG.h" 31 | #include "llvm/IR/Constants.h" 32 | #include "llvm/IR/Function.h" 33 | #include "llvm/IR/Instructions.h" 34 | #include "llvm/IR/LLVMContext.h" 35 | #include "llvm/IR/Metadata.h" 36 | #include "llvm/Support/Debug.h" 37 | #include "llvm/Support/raw_ostream.h" 38 | 39 | 40 | #include "llvm/IR/LLVMContext.h" 41 | #include "llvm/IR/Module.h" 42 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" 43 | #include "Util/Annotation/MetadataInfo.h" 44 | 45 | #define F_KERNEL_SUBSTR "__kernel__" 46 | 47 | using namespace llvm; 48 | using namespace util; 49 | 50 | namespace { 51 | struct SBPAnnotate : public FunctionPass { 52 | static char ID; 53 | SBPAnnotate() : FunctionPass(ID) {} 54 | BranchProbabilityInfo *BPI; 55 | 56 | virtual void getAnalysisUsage(AnalysisUsage &AU) const { 57 | AU.addRequired(); 58 | } 59 | 60 | std::string floatToString(float val) { 61 | std::ostringstream strs; 62 | strs << val; 63 | std::string s = strs.str(); 64 | if (s.length() == 0) { 65 | return "0"; 66 | } 67 | return s; 68 | } 69 | 70 | void saveToFile(std::string filename, std::string data) { 71 | std::ofstream file; 72 | file.open(filename, std::ios::app); 73 | file << data << "\n"; 74 | file.close(); 75 | } 76 | 77 | void getBranchProbabilities(Function &F) { 78 | /* This function is used to gather the probabilities for each branch. 79 | * If the terminator instruction has a conditional jump (two successors), 80 | * it will save the probability of the most likely taken branch to a file called "branchProbabilities.txt" 81 | * in the current folder 82 | */ 83 | for (Function::iterator block = F.begin(), blockEnd = F.end(); block != blockEnd; ++block) { 84 | TerminatorInst *TInst = block->getTerminator(); 85 | int numSuccessors = TInst->getNumSuccessors(); 86 | if (numSuccessors == 2) { 87 | BasicBlock *dst = TInst->getSuccessor(0); 88 | BranchProbability result = BPI->getEdgeProbability(&*block, dst); 89 | BranchProbability comp = result.getCompl(); 90 | float r = result.getNumerator() / ((float)result.getDenominator()); 91 | float r2 = result.getCompl().getNumerator() / ((float)result.getCompl().getDenominator()); 92 | if (r >= r2) { 93 | saveToFile("branchProbabilities.txt", floatToString(r)); 94 | } else { 95 | saveToFile("branchProbabilities.txt", floatToString(r2)); 96 | } 97 | } 98 | } 99 | } 100 | 101 | void annotateBranches(Function &F) { 102 | /* This function annotates each branch with two meta data fields: 103 | * BranchProb0: the probability that the first branch is taken from the branch instruction 104 | * BranchProb1: the probability that the second branch is taken from the branch instruction 105 | * If there's one successor, BranchProb0 will be 1, and BranchProb1 will be 0. 106 | * If there's no successor, BranchProb0 will be 0, and BranchProb0 will be 0. 107 | */ 108 | float r; 109 | for (Function::iterator block = F.begin(), blockEnd = F.end(); block != blockEnd; ++block) { 110 | TerminatorInst *TInst = block->getTerminator(); 111 | if (BranchInst *BI = dyn_cast(TInst)) { 112 | if (BI->isConditional()) { 113 | if (Value *vbi = dyn_cast(BI->getCondition())) { 114 | if (vbi->getName().str().find("stdin") != std::string::npos) { 115 | return; 116 | } 117 | } 118 | } 119 | } 120 | int numSuccessors = TInst->getNumSuccessors(); 121 | AttachMetadata(TInst, "BranchProb0", "0"); 122 | AttachMetadata(TInst, "BranchProb1", "0"); 123 | if (numSuccessors >= 1) { 124 | BasicBlock *dst = TInst->getSuccessor(0); 125 | BranchProbability result = BPI->getEdgeProbability(&*block, dst); 126 | r = result.getNumerator() / ((float)result.getDenominator()); 127 | AttachMetadata(TInst, "BranchProb0", floatToString(r)); 128 | } 129 | if (numSuccessors == 2) { 130 | BasicBlock *dst = TInst->getSuccessor(1); 131 | BranchProbability result = BPI->getEdgeProbability(&*block, dst); 132 | r = result.getNumerator() / ((float)result.getDenominator()); 133 | AttachMetadata(TInst, "BranchProb1", floatToString(r)); 134 | } 135 | } 136 | } 137 | 138 | bool runOnFunction(Function &F) override { 139 | // If it doesn't contain the FOR_TARGET_SUFFIX 140 | if (!isFKernel(F)) 141 | return false; 142 | errs() << "Running BranchAnnotate on F:" << F.getName().str() << "\n"; 143 | BPI = &getAnalysis().getBPI(); 144 | annotateBranches(F); 145 | getBranchProbabilities(F); 146 | 147 | return false; 148 | } 149 | 150 | bool isFKernel(Function &F) { 151 | return F.getName().str().find(F_KERNEL_SUBSTR) != std::string::npos; 152 | } 153 | }; 154 | } 155 | 156 | char SBPAnnotate::ID = 0; 157 | static RegisterPass X("branchannotate", "Branch Annotate Pass", false, false); 158 | -------------------------------------------------------------------------------- /compiler/projects/src/Util/Annotation/CFGIndirectionCount/CFGIndirectionCount.cpp: -------------------------------------------------------------------------------- 1 | //===--------------- CFGIndirectionCount.cpp - Annotating CFG Indirection--===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file ForcedLoopUnroll.cpp 10 | /// 11 | /// \brief 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | // 16 | // This loop pass annotates mandatory CFG indirection count of all loads. 17 | // 18 | //===----------------------------------------------------------------------===// 19 | #include "llvm/ADT/Statistic.h" 20 | #include "llvm/Analysis/AssumptionCache.h" 21 | #include "llvm/Analysis/LoopPass.h" 22 | #include "llvm/Analysis/ScalarEvolution.h" 23 | #include "llvm/Transforms/Scalar.h" 24 | #include "llvm/Transforms/Utils/UnrollLoop.h" 25 | #include "llvm/IR/Dominators.h" 26 | 27 | #include 28 | #include 29 | 30 | #include "Util/Annotation/MetadataInfo.h" 31 | #include "Util/Analysis/LoopDependency.h" 32 | 33 | #define DEBUG_TYPE "CFGIndirectionCount" 34 | 35 | using namespace llvm; 36 | using namespace std; 37 | using namespace util; 38 | 39 | static cl::opt 40 | LoopName("loop-name", 41 | cl::desc("The keyword identifying the loop header to annotate"), 42 | cl::value_desc("name")); 43 | 44 | namespace { 45 | struct CFGIndirectionCount : public LoopPass { 46 | static char ID; 47 | 48 | CFGIndirectionCount() : LoopPass(ID) {} 49 | 50 | public: 51 | virtual void getAnalysisUsage(AnalysisUsage &AU) const { 52 | AU.addRequired(); 53 | AU.addRequired(); 54 | AU.addRequired(); 55 | AU.addRequired(); 56 | } 57 | 58 | virtual bool runOnLoop(Loop *L, LPPassManager &LPM); 59 | }; 60 | } 61 | 62 | static void markIndirCount(Instruction *I, set CFGDeps) { 63 | int LoadCount = count_if(CFGDeps.begin(), CFGDeps.end(), [](Instruction *DepI) {return isa(DepI);}); 64 | AttachMetadata(&(*I), "CFGIndir", to_string(LoadCount)); 65 | } 66 | 67 | bool CFGIndirectionCount::runOnLoop(Loop *L, LPPassManager &LPM) { 68 | if (L->getHeader()->getName().find(LoopName) == string::npos) { 69 | return false; 70 | } 71 | 72 | // Check if it's a prologue loop. If so, it doesn't make sense to unroll 73 | if (L->getHeader()->getName().find(".prol") != string::npos) { 74 | return false; 75 | } 76 | 77 | // We need to manually construct BasicAA directly in order to disable 78 | // its use of other function analyses. 79 | BasicAAResult BAR(createLegacyPMBasicAAResult(*this, *(L->getHeader()->getParent()))); 80 | 81 | // Construct our own AA results for this function. We do this manually to 82 | // work around the limitations of the legacy pass manager. 83 | AAResults AAR(createLegacyPMAAResults(*this, *(L->getHeader()->getParent()), BAR)); 84 | AliasAnalysis *AA = &AAR; 85 | 86 | LoopInfo *LI = &getAnalysis().getLoopInfo(); 87 | 88 | for (Loop::block_iterator B = L->block_begin(), BE = L->block_end(); 89 | B != BE; ++B) { 90 | for (BasicBlock::iterator I = (*B)->begin(), IE = (*B)->end(); I != IE; 91 | ++I) { 92 | if (isa(&*I)) { 93 | set CFGDeps; 94 | getControlDeps(AA, LI, &*I, CFGDeps); 95 | markIndirCount(&*I, CFGDeps); 96 | } 97 | } 98 | } 99 | 100 | set Deps; 101 | } 102 | 103 | char CFGIndirectionCount::ID = 0; 104 | static RegisterPass X("annotate-cfg-indir", 105 | "CFGIndirectionCount_pass", 106 | true /* does not change CFG */, 107 | false /* not an analysis pass */); 108 | -------------------------------------------------------------------------------- /compiler/projects/src/Util/Annotation/CFGIndirectionCount/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) Eta Scale AB. Licensed under the Eta Scale Open Source License. See the LICENSE file for details. 3 | add_library(CFGIndirectionCount MODULE 4 | CFGIndirectionCount.cpp 5 | ${PROJECTS_MAIN_SRC_DIR}/Util/Annotation/MetadataInfo.cpp 6 | ${PROJECTS_MAIN_SRC_DIR}/Util/Analysis/LoopDependency.cpp 7 | ${PROJECTS_MAIN_SRC_DIR}/Util/Analysis/AliasUtils.cpp 8 | ) 9 | -------------------------------------------------------------------------------- /compiler/projects/src/Util/Annotation/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) Eta Scale AB. Licensed under the Eta Scale Open Source License. See the LICENSE file for details. 3 | add_subdirectory(BranchAnnotate) 4 | add_subdirectory(CFGIndirectionCount) 5 | -------------------------------------------------------------------------------- /compiler/projects/src/Util/Annotation/MetadataInfo.cpp: -------------------------------------------------------------------------------- 1 | //===- MetadataInfo.cpp - Kill unsafe stores with backups 2 | //--------------------===// 3 | // 4 | // The LLVM Compiler Infrastructure 5 | // 6 | // This file is distributed under the University of Illinois Open Source 7 | // License. See LICENSE.TXT for details. 8 | // 9 | //===----------------------------------------------------------------------===// 10 | /// \file MetadataInfo.cpp 11 | /// 12 | /// \brief 13 | /// 14 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 15 | /// the LICENSE file for details. 16 | // 17 | // Description of pass ... 18 | // 19 | //===----------------------------------------------------------------------===// 20 | #include "llvm/Analysis/LoopPass.h" 21 | #include "llvm/Analysis/ScalarEvolution.h" 22 | #include "llvm/IR/Dominators.h" 23 | #include "llvm/Pass.h" 24 | #include "llvm/Support/FileSystem.h" 25 | #include "llvm/Transforms/Scalar.h" 26 | #include "llvm/Transforms/Utils/Local.h" 27 | #include "llvm/Transforms/Utils/SSAUpdater.h" 28 | 29 | #include "Util/Annotation/MetadataInfo.h" 30 | #include "llvm/IR/AssemblyAnnotationWriter.h" 31 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" 32 | #include "llvm/Transforms/Utils/Cloning.h" 33 | 34 | using namespace llvm; 35 | 36 | namespace util { 37 | 38 | bool InstrhasMetadataKind(Instruction *ii, std::string mdt) { 39 | unsigned mk = ii->getContext().getMDKindID(mdt); 40 | if (mk) { 41 | MDNode *mdn = ii->getMetadata(mk); 42 | if (mdn) 43 | return true; 44 | } 45 | 46 | return false; 47 | } 48 | 49 | bool InstrhasMetadata(Instruction *ii, std::string mdt, std::string mdv) { 50 | unsigned mk = ii->getContext().getMDKindID(mdt); 51 | if (mk) { 52 | MDNode *mdn = ii->getMetadata(mk); 53 | if (mdn) { 54 | Metadata *mds = mdn->getOperand(0); 55 | StringRef str; 56 | if (MDString::classof(mds)) 57 | str = (cast(*mds)).getString(); 58 | if (str == mdv) 59 | return true; 60 | } 61 | } 62 | 63 | return false; 64 | } 65 | 66 | bool InstrhasMetadataSubstring(Instruction *ii, std::string mdt, 67 | std::string mdv) { 68 | unsigned mk = ii->getContext().getMDKindID(mdt); 69 | if (mk) { 70 | MDNode *mdn = ii->getMetadata(mk); 71 | if (mdn) { 72 | Metadata *mds = mdn->getOperand(0); 73 | StringRef str; 74 | if (MDString::classof(mds)) { 75 | str = (cast(*mds)).getString(); 76 | size_t found = mdv.find(str.str()); 77 | if (found != std::string::npos) 78 | return true; 79 | } 80 | } 81 | } 82 | 83 | return false; 84 | } 85 | 86 | void AttachMetadata(Instruction *inst, std::string mdtype, std::string str) { 87 | // attach pragma as metadata 88 | unsigned mk = inst->getContext().getMDKindID(mdtype); 89 | Metadata *V = MDString::get(inst->getContext(), StringRef(str)); 90 | MDNode *n = MDNode::get(inst->getContext(), V); 91 | inst->setMetadata(mk, n); 92 | } 93 | 94 | void AttachMetadataToAllInBlock(BasicBlock *b, std::string mdtype, 95 | std::string str) { 96 | for (BasicBlock::iterator it = b->begin(); it != b->end(); it++) 97 | AttachMetadata(&*it, mdtype, str); 98 | } 99 | 100 | /* if I is a memory instruction it has an ID attached */ 101 | std::string getInstructionID(Instruction *I) { 102 | std::string str = "empty"; 103 | MDNode *mdn = I->getMetadata("ID"); 104 | if (mdn) { 105 | Metadata *mds = mdn->getOperand(0); 106 | StringRef str; 107 | if (MDString::classof(mds)) 108 | str = (cast(*mds)).getString(); 109 | return str; 110 | } 111 | return str; 112 | } 113 | 114 | /* if I is a memory instruction it has an IDphi attached */ 115 | std::string getInstructionIDphi(Instruction *I) { 116 | std::string str = "empty"; 117 | MDNode *mdn = I->getMetadata("IDphi"); 118 | if (mdn) { 119 | Metadata *mds = mdn->getOperand(0); 120 | StringRef str; 121 | if (MDString::classof(mds)) 122 | str = (cast(*mds)).getString(); 123 | return str; 124 | } 125 | return str; 126 | } 127 | 128 | std::string getInstructionMD(Instruction *I, const char *MDty) { 129 | std::string str = ""; 130 | MDNode *mdn = I->getMetadata(MDty); 131 | if (mdn) { 132 | Metadata *mds = mdn->getOperand(0); 133 | StringRef str; 134 | if (MDString::classof(mds)) 135 | str = (cast(*mds)).getString(); 136 | return str; 137 | } 138 | return str; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /compiler/projects/src/Util/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) Eta Scale AB. Licensed under the Eta Scale Open Source License. See the LICENSE file for details. 3 | add_subdirectory(Loops) 4 | add_subdirectory(Annotation) 5 | -------------------------------------------------------------------------------- /compiler/projects/src/Util/DAE/DAEUtils.cpp: -------------------------------------------------------------------------------- 1 | //===-------- DAEUtils.cpp - Utils for creating DAE-like loops -------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file DAEUtils.cpp 10 | /// 11 | /// \brief 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | // 16 | //===----------------------------------------------------------------------===// 17 | 18 | #include "Util/DAE/DAEUtils.h" 19 | 20 | namespace util { 21 | void removeUnlisted(Function &F, set &KeepSet) { 22 | set::iterator ksI = KeepSet.begin(), ksE = KeepSet.end(); 23 | for (inst_iterator iI = inst_begin(F), iE = inst_end(F); iI != iE;) { 24 | Instruction *Inst = &(*iI); 25 | ++iI; 26 | if (find(ksI, ksE, Inst) == ksE) { 27 | Inst->replaceAllUsesWith(UndefValue::get(Inst->getType())); 28 | Inst->eraseFromParent(); 29 | } 30 | } 31 | } 32 | 33 | Function* cloneFunction(Function *F, ValueToValueMapTy &VMap) { 34 | Function *cF = Function::Create(F->getFunctionType(), F->getLinkage(), 35 | F->getName() + CLONE_SUFFIX, F->getParent()); 36 | for (Function::arg_iterator aI = F->arg_begin(), aE = F->arg_end(), 37 | acI = cF->arg_begin(), acE = cF->arg_end(); 38 | aI != aE; ++aI, ++acI) { 39 | assert(acI != acE); 40 | acI->setName(aI->getName()); 41 | VMap.insert(std::pair(&*aI, &*acI)); 42 | } 43 | SmallVector Returns; // Ignored 44 | CloneFunctionInto(cF, F, VMap, false, Returns); 45 | return cF; 46 | } 47 | 48 | Function* cloneFunction(Function *F) { 49 | ValueToValueMapTy VMap; 50 | return cloneFunction(F, VMap); 51 | } 52 | 53 | void replaceArgs(Function *E, Function *A) { 54 | Instruction *Inst; 55 | Value *val; 56 | for (inst_iterator iI = inst_begin(E), iE = inst_end(E); iI != iE; ++iI) { 57 | Inst = &(*iI); 58 | 59 | for (User::value_op_iterator uI = Inst->value_op_begin(), 60 | uE = Inst->value_op_end(); 61 | uI != uE; ++uI) { 62 | val = isFunArgument(E, A, *uI); 63 | if (val) { 64 | Inst->replaceUsesOfWith(*uI, val); 65 | } 66 | } 67 | } 68 | } 69 | 70 | // Inserts a prefetch for LInst as early as possible 71 | // (i.e. as soon as the adress has been computed). 72 | // The prefetch and all its dependencies will also 73 | // be inserted in toKeep. 74 | // Returns the result of the insertion. 75 | PrefInsertResult 76 | insertPrefetch(AliasAnalysis *AA, LoadInst *LInst, set &toKeep, 77 | map> &prefs, 78 | unsigned threshold) { 79 | 80 | // Follow dependencies 81 | set Deps; 82 | if (followDeps(AA, LInst, Deps)) { 83 | if (isUnderThreshold(Deps, threshold)) { 84 | toKeep.insert(Deps.begin(), Deps.end()); 85 | } else { 86 | return IndirLimit; 87 | } 88 | } else { 89 | return BadDeps; 90 | } 91 | 92 | // Extract usefull information 93 | bool prefetchExists = false; 94 | Value *DataPtr = LInst->getPointerOperand(); 95 | BasicBlock *BB = LInst->getParent(); 96 | BasicBlock *EntryBlock = 97 | &(LInst->getParent()->getParent()->getEntryBlock()); 98 | for (map>::iterator 99 | I = prefs.begin(), 100 | E = prefs.end(); 101 | I != E; ++I) { 102 | LoadInst *LD = I->first; 103 | if (LD->getPointerOperand() == DataPtr) { 104 | // Might also be nullptr 105 | BasicBlock *LDBB = LD->getParent(); 106 | if (BB == EntryBlock && LDBB == EntryBlock || 107 | BB != EntryBlock && LDBB != EntryBlock) { 108 | prefetchExists = true; 109 | break; 110 | } 111 | } 112 | } 113 | 114 | if (prefetchExists) { 115 | return Redundant; 116 | } 117 | 118 | unsigned PtrAS = LInst->getPointerAddressSpace(); 119 | LLVMContext &Context = DataPtr->getContext(); 120 | 121 | // Make sure type is correct 122 | Instruction *InsertPoint = LInst; 123 | Type *I8Ptr = Type::getInt8PtrTy(Context, PtrAS); 124 | CastInst *Cast = 125 | CastInst::CreatePointerCast(DataPtr, I8Ptr, "", InsertPoint); 126 | 127 | // Insert prefetch 128 | IRBuilder<> Builder(InsertPoint); 129 | Module *M = LInst->getParent()->getParent()->getParent(); 130 | Type *I32 = Type::getInt32Ty(LInst->getContext()); 131 | Value *PrefFun = Intrinsic::getDeclaration(M, Intrinsic::prefetch); 132 | CallInst *Prefetch = Builder.CreateCall( 133 | PrefFun, {Cast, ConstantInt::get(I32, 0), // read 134 | ConstantInt::get(I32, 3), ConstantInt::get(I32, 1)}); // data 135 | 136 | // Inset prefetch instructions into book keeping 137 | toKeep.insert(Cast); 138 | toKeep.insert(Prefetch); 139 | prefs.insert(make_pair(LInst, make_pair(Cast, Prefetch))); 140 | 141 | return Inserted; 142 | } 143 | 144 | void findLoads(Function &F, list &LoadList) { 145 | for (inst_iterator iI = inst_begin(F), iE = inst_end(F); iI != iE; ++iI) { 146 | if (LoadInst::classof(&(*iI))) { 147 | LoadList.push_back((LoadInst *)&(*iI)); 148 | } 149 | } 150 | } 151 | 152 | void findVisibleLoads(list &LoadList, list &VisList) { 153 | for (list::iterator I = LoadList.begin(), E = LoadList.end(); 154 | I != E; ++I) { 155 | if (isNonLocalPointer((*I)->getPointerOperand())) { 156 | VisList.push_back(*I); 157 | } 158 | } 159 | } 160 | 161 | bool isUnderThreshold(set Deps, unsigned Threshold) { 162 | unsigned count = 0; 163 | for (set::iterator dI = Deps.begin(), dE = Deps.end(); 164 | dI != dE && count <= Threshold; ++dI) { 165 | if (LoadInst::classof(*dI)) { 166 | ++count; 167 | } 168 | } 169 | return count <= Threshold; 170 | } 171 | 172 | Value* isFunArgument(Function *E, Function *A, Value *arg) { 173 | for (Function::arg_iterator aI = E->arg_begin(), aE = E->arg_end(), 174 | acI = A->arg_begin(); 175 | aI != aE; ++aI, ++acI) { 176 | if ((Value *)arg == &*aI) 177 | return &*acI; 178 | } 179 | return 0; 180 | } 181 | 182 | bool isNonLocalPointer(Value *Pointer) { return !isLocalPointer(Pointer); } 183 | 184 | bool isLocalPointer(Value *Pointer) { 185 | if (!Instruction::classof(Pointer)) { 186 | return false; 187 | } 188 | Instruction *PtrInst = (Instruction *)Pointer; 189 | if (AllocaInst::classof(Pointer)) { 190 | // A locally defined memory location 191 | return true; 192 | } 193 | unsigned poi; 194 | if (GetElementPtrInst::classof(Pointer)) { 195 | poi = GetElementPtrInst::getPointerOperandIndex(); 196 | } else if (CastInst::classof(Pointer)) { 197 | poi = 0; // The only operand 198 | } else if (LoadInst::classof(Pointer)) { 199 | // Assumes that global pointers are never stored in local 200 | // structures. Otherwise this could produce false positives. 201 | poi = LoadInst::getPointerOperandIndex(); 202 | } else { 203 | return false; 204 | } 205 | Value *Pointer2 = PtrInst->getOperand(poi); 206 | return isLocalPointer(Pointer2); 207 | } 208 | 209 | 210 | } 211 | 212 | -------------------------------------------------------------------------------- /compiler/projects/src/Util/Loops/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | # Copyright (C) Eta Scale AB. Licensed under the Eta Scale Open Source License. See the LICENSE file for details. 3 | add_library(UtilLoops MODULE ForcedLoopUnroll.cpp) 4 | -------------------------------------------------------------------------------- /compiler/projects/src/Util/Loops/ForcedLoopUnroll.cpp: -------------------------------------------------------------------------------- 1 | //===--------------- ForcedLoopUnroll.cpp - Loop Unroll Util 2 | //---------------------===// 3 | // 4 | // The LLVM Compiler Infrastructure 5 | // 6 | // This file is distributed under the University of Illinois Open Source 7 | // License. See LICENSE.TXT for details. 8 | // 9 | //===----------------------------------------------------------------------===// 10 | /// \file ForcedLoopUnroll.cpp 11 | /// 12 | /// \brief 13 | /// 14 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 15 | /// the LICENSE file for details. 16 | // This loop pass unrolls a certain loop specified by a keyword. It unrolls 17 | // regardless of any unroll cost. 18 | // 19 | //===----------------------------------------------------------------------===// 20 | #include "llvm/ADT/Statistic.h" 21 | #include "llvm/Analysis/AssumptionCache.h" 22 | #include "llvm/Analysis/LoopPass.h" 23 | #include "llvm/Analysis/ScalarEvolution.h" 24 | #include "llvm/Transforms/Scalar.h" 25 | #include "llvm/Transforms/Utils/UnrollLoop.h" 26 | #include 27 | #include 28 | #include 29 | 30 | #define DEBUG_TYPE "forceunroll" 31 | 32 | STATISTIC(NumStatic, "Number of statically unrolled loops."); 33 | STATISTIC(NumRuntime, "Number of runtime unrolled loops."); 34 | STATISTIC(NumBranch, "Number of unrolled loops with conditions."); 35 | STATISTIC(NumFailed, "Number of failed unrolled loops."); 36 | 37 | using namespace llvm; 38 | using namespace std; 39 | 40 | static cl::opt 41 | LoopName("loop-name", 42 | cl::desc("The keyword identifying the loop header to unroll"), 43 | cl::value_desc("name")); 44 | 45 | static cl::opt 46 | UnrollCount("unroll", cl::desc("Max number of unrolled iterations"), 47 | cl::value_desc("unsigned")); 48 | 49 | namespace { 50 | struct ForcedLoopUnroll : public LoopPass { 51 | static char ID; 52 | 53 | ForcedLoopUnroll() : LoopPass(ID) {} 54 | 55 | public: 56 | virtual void getAnalysisUsage(AnalysisUsage &AU) const { 57 | AU.addRequired(); 58 | AU.addRequired(); 59 | AU.addRequired(); 60 | AU.addRequired(); 61 | } 62 | 63 | virtual bool runOnLoop(Loop *L, LPPassManager &LPM); 64 | }; 65 | } 66 | 67 | bool ForcedLoopUnroll::runOnLoop(Loop *L, LPPassManager &LPM) { 68 | if (L->getHeader()->getName().find(LoopName) == string::npos) { 69 | return false; 70 | } 71 | 72 | if (UnrollCount <= 1) { 73 | return false; 74 | } 75 | 76 | // Check if it's a prologue loop. If so, it doesn't make sense to unroll 77 | if (L->getHeader()->getName().find(".prol") != string::npos) { 78 | return false; 79 | } 80 | 81 | ScalarEvolution *SE = &getAnalysis().getSE(); 82 | unsigned Count = UnrollCount; 83 | unsigned TripCount = 0; 84 | unsigned TripMultiple = 1; 85 | 86 | // 87 | BasicBlock *ExitingBlock = L->getLoopLatch(); 88 | if (!ExitingBlock || !L->isLoopExiting(ExitingBlock)) 89 | ExitingBlock = L->getExitingBlock(); 90 | 91 | // Find trip count and trip multiple 92 | if (ExitingBlock) { 93 | TripCount = SE->getSmallConstantTripCount(L, ExitingBlock); 94 | TripMultiple = SE->getSmallConstantTripMultiple(L, ExitingBlock); 95 | } 96 | 97 | if (TripCount != 0 && Count > TripCount) 98 | Count = TripCount; 99 | 100 | assert(Count > 0); 101 | assert(TripMultiple > 0); 102 | assert(TripCount == 0 || TripCount % TripMultiple == 0); 103 | 104 | LoopInfo *LI = &getAnalysis().getLoopInfo(); 105 | AssumptionCache *AC = 106 | &getAnalysis().getAssumptionCache( 107 | *L->getHeader()->getParent()); 108 | DominatorTree *DT = &getAnalysis().getDomTree(); 109 | 110 | errs() << "Unrolling .. : " << L->getHeader()->getName() << "\n"; 111 | bool AllowRuntimeUnroll = false; 112 | bool AllowExpensiveTripCount = true; 113 | bool PreserveLCSSA = mustPreserveAnalysisID(LCSSAID); 114 | bool UnrollSucceeded; 115 | 116 | // Unroll loop. Will unroll dynamically if trip count is not known (i.e. 117 | // TripCount = 0) 118 | UnrollSucceeded = UnrollLoop(L, Count, TripCount, AllowRuntimeUnroll, 119 | AllowExpensiveTripCount, TripMultiple, LI, SE, 120 | DT, AC, PreserveLCSSA); 121 | 122 | if (UnrollSucceeded) { 123 | ++NumStatic; 124 | errs() << "Succeeded with static unrolling\n"; 125 | } else { 126 | AllowRuntimeUnroll = true; 127 | UnrollSucceeded = UnrollLoop(L, Count, TripCount, AllowRuntimeUnroll, 128 | AllowExpensiveTripCount, TripMultiple, LI, SE, 129 | DT, AC, PreserveLCSSA); 130 | 131 | if (UnrollSucceeded) { 132 | ++NumRuntime; 133 | errs() << "Succeeded with runtime unrolling\n"; 134 | } 135 | } 136 | 137 | if (!UnrollSucceeded) { 138 | AllowRuntimeUnroll = false; 139 | UnrollSucceeded = UnrollLoop(L, Count, TripCount, AllowRuntimeUnroll, 140 | AllowExpensiveTripCount, TripMultiple, LI, SE, 141 | DT, AC, PreserveLCSSA); 142 | 143 | if (UnrollSucceeded) { 144 | ++NumBranch; 145 | errs() << "Succeeded with forced unrolling (including branches)\n"; 146 | } else { 147 | ++NumFailed; 148 | } 149 | } 150 | 151 | return UnrollSucceeded; 152 | } 153 | 154 | char ForcedLoopUnroll::ID = 0; 155 | static RegisterPass X("single-loop-unroll", 156 | "LoopUnrollUtil_pass", true, true); 157 | -------------------------------------------------------------------------------- /compiler/projects/src/Util/Transform/BranchMerge/BranchMerge.cpp: -------------------------------------------------------------------------------- 1 | //===----BranchMerge.cpp - Early evaluation of branches and later merge----===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | /// \file BranchMerge.cpp 10 | /// 11 | /// \brief 12 | /// 13 | /// \copyright Eta Scale AB. Licensed under the Eta Scale Open Source License. See 14 | /// the LICENSE file for details. 15 | // 16 | // This file provides functionality to evaluate branches at an early stage, 17 | // and to decide whether to run the optimized (merged branches) or unoptimized 18 | // (original) version. 19 | // 20 | //===----------------------------------------------------------------------===// 21 | 22 | #include "llvm/Analysis/BranchProbabilityInfo.h" 23 | #include "llvm/ADT/PostOrderIterator.h" 24 | #include "llvm/Analysis/LoopInfo.h" 25 | #include "llvm/IR/CFG.h" 26 | #include "llvm/IR/Constants.h" 27 | #include "llvm/IR/Function.h" 28 | #include "llvm/IR/Instruction.h" 29 | #include "llvm/IR/Instructions.h" 30 | #include "llvm/IR/LLVMContext.h" 31 | #include "llvm/IR/Metadata.h" 32 | #include "llvm/Support/Debug.h" 33 | #include "llvm/Support/raw_ostream.h" 34 | #include "llvm/Support/FileSystem.h" 35 | 36 | #include "llvm/Transforms/Utils/Cloning.h" 37 | 38 | 39 | #include "llvm/IR/LLVMContext.h" 40 | #include "llvm/IR/Module.h" 41 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" 42 | 43 | #include "Util/Transform/BranchMerge/BranchMerge.h" 44 | 45 | #define F_KERNEL_SUBSTR "__kernel__" 46 | #define EXECUTE_SUFFIX "_execute" 47 | #define CLONE_SUFFIX "_clone" 48 | 49 | BasicBlock *deepCopyBB(BasicBlock *src) { 50 | BasicBlock *dst = BasicBlock::Create(src->getContext()); 51 | for (BasicBlock::iterator iI = src->begin(), iE = src->end(); iI != iE; ++iI) { 52 | Instruction *c = iI->clone(); 53 | dst->getInstList().push_back(c); 54 | } 55 | return dst; 56 | } 57 | 58 | void replaceBranch(BasicBlock *block, double THRESHOLD) { 59 | TerminatorInst *TInst = block->getTerminator(); 60 | IRBuilder<> Builder(TInst); 61 | BranchInst *uncondBI; 62 | BasicBlock *dst, *comp; 63 | if (BranchInst *BI = dyn_cast(TInst)) { 64 | std::pair res = isReducableBranch(BI, THRESHOLD); 65 | if (res.first) { 66 | if (res.second == 0) { 67 | dst = BI->getSuccessor(0); 68 | comp = BI->getSuccessor(1); 69 | uncondBI = BranchInst::Create(dst); 70 | AttachMetadata(uncondBI, "BranchProb0", "1"); 71 | AttachMetadata(uncondBI, "BranchProb1", "0"); 72 | comp->removePredecessor(block); 73 | ReplaceInstWithInst(TInst, uncondBI); 74 | } else if (res.second == 1) { 75 | dst = BI->getSuccessor(1); 76 | comp = BI->getSuccessor(0); 77 | uncondBI = BranchInst::Create(dst); 78 | AttachMetadata(uncondBI, "BranchProb0", "0"); 79 | AttachMetadata(uncondBI, "BranchProb1", "1"); 80 | comp->removePredecessor(block); 81 | ReplaceInstWithInst(TInst, uncondBI); 82 | } 83 | } 84 | } 85 | } 86 | 87 | bool hasEnding (std::string fullString, std::string ending) { 88 | if (fullString.length() >= ending.length()) { 89 | return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending)); 90 | } else { 91 | return false; 92 | } 93 | } 94 | 95 | bool minimizeFunctionFromBranchPred(LoopInfo *LI, Function *cF, double threshold) { 96 | errs() << "Optimizing function: " << cF->getName().str() << "\n"; 97 | 98 | std::vector Loops(LI->begin(), LI->end()); 99 | assert("Only expecting one loop." && Loops.size() == 1); 100 | Loop *L = *(Loops.begin()); 101 | BasicBlock *Latch = L->getLoopLatch(); 102 | BasicBlock *CondBranchBB = (Latch->getUniquePredecessor()) ? Latch->getUniquePredecessor() : Latch; 103 | 104 | for (Function::iterator block = cF->begin(), blockEnd = cF->end(); block != blockEnd; ++block) { 105 | BasicBlock *BB = &*block; 106 | if (CondBranchBB == BB) { 107 | continue; 108 | } 109 | 110 | for (BasicBlock::iterator I = BB->begin(), IE = BB->end(); I != IE; ++I) { 111 | if (InstrhasMetadataKind(&*I, "SwoopType") && "DecisionBlock" == getInstructionMD(&*I, "SwoopType")) { 112 | replaceBranch(BB, threshold); 113 | break; 114 | } 115 | } 116 | } 117 | return true; 118 | } 119 | 120 | bool isFKernel(Function &F) { 121 | return 122 | F.getName().str().find(F_KERNEL_SUBSTR) != std::string::npos; 123 | } 124 | -------------------------------------------------------------------------------- /experiments/swoop/sources/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) Eta Scale AB. Licensed under the Eta Scale Open Source License. See the LICENSE file for details. 2 | BENCHMARKS= myBenchmark 3 | 4 | 5 | .SECONDEXPANSION: 6 | 7 | SWOOP: BINDIR 8 | $(foreach bench, $(BENCHMARKS), \ 9 | $(MAKE) -C $(bench)/src 2>&1 | tee $(bench)/bin/log.txt;) 10 | 11 | BINDIR: $$(foreach bench, $$(BENCHMARKS), $$(bench)/bin) 12 | 13 | %/bin: 14 | mkdir -p $@ 15 | 16 | clean: 17 | $(foreach bench, $(BENCHMARKS), \ 18 | $(MAKE) -C $(bench)/src clean;) 19 | -------------------------------------------------------------------------------- /experiments/swoop/sources/common/Makefile.environment: -------------------------------------------------------------------------------- 1 | ###### 2 | # Setting the environment variables 3 | # 4 | 5 | COMPILER_LIB=var/www/compiler/build/projects-build/lib 6 | LLVM_BIN=/var/www/compiler/build/llvm-build/bin 7 | -------------------------------------------------------------------------------- /experiments/swoop/sources/common/SWOOP/Makefile.defaults: -------------------------------------------------------------------------------- 1 | ###### 2 | # Makefile for Clairvoyance Code (latest updated April 2017). 3 | # 4 | 5 | include $(LEVEL)/common/Makefile.environment 6 | 7 | ###### 8 | # Environment 9 | # 10 | 11 | # LLVM tools 12 | OPT=$(LLVM_BIN)/opt 13 | CLANG=$(LLVM_BIN)/clang 14 | CLANGCPP=$(LLVM_BIN)/clang++ 15 | LLC=$(LLVM_BIN)/llc 16 | EXTRACT=$(LLVM_BIN)/llvm-extract 17 | LINK=$(LLVM_BIN)/llvm-link 18 | 19 | LIBS_FLAGS= 20 | 21 | # SWOOP Marking 22 | SWOOP_MARKER='__kernel__' 23 | 24 | ###### 25 | # Helper definitions 26 | # 27 | 28 | # Retrieving information from target file name 29 | get_unroll=$(shell echo $@ | sed -n 's/.*\.unr\([0-9]*\)\..*/\1/p') 30 | get_indir=$(shell echo $@ | sed -n 's/.*\.indir\([0-9]*\)\..*/\1/p') 31 | get_swoop_type=$(shell echo $@ | sed -n 's/.*\.\([a-z]*\)\.ll/\1/p') 32 | get_scheduling=$$(shell echo $$@ | sed -n 's/.*\.sched\([a-z]*\)\..*/\1/p') 33 | 34 | # Helper to generate prerequisites of rules 35 | get_objects=$$(addprefix $(BINDIR)/, $$(addsuffix .O3.ll, $$(basename $$(SRCS)))) 36 | get_swoop_prerequisites=$$(shell echo $$@ | sed 's/indir.*/extract.ll/g') 37 | get_marked=$$(addprefix $(BINDIR)/, $$(addsuffix .marked.ll,$$(basename $$(SRCS)))) 38 | 39 | get_kernel_marked_files=$$(shell find $(BINDIR) -iname "*.marked.ll" | xargs grep -l '__kernel__\|define.*@main' | sed 's/.marked.ll/.$$*.O3.ll/g') 40 | get_unmodified_files=$$(shell find $(BINDIR) -iname "*.marked.ll" | xargs grep -l -L '__kernel__\|define.*@main' | sed 's/.marked/.marked.O3/g') 41 | 42 | get_sched_marked_files=$$(shell find $(BINDIR) -iname "*.marked.ll" | xargs grep -l '__kernel__' | sed 's/.marked.ll/.$$*.o/g') 43 | get_sched_unmodified_files=$$(shell find $(BINDIR) -iname "*.marked.ll"| xargs grep -l -L '__kernel__' | sed 's/.marked.ll/.marked.O3.ll/g') 44 | 45 | # Options for swoop pass 46 | consv_options=-dae-swoop -hoist-delinquent=false 47 | specsafe_options=-aggressive-swoop -hoist-delinquent=false 48 | spec_options=-speculative-swoop -hoist-delinquent=false 49 | 50 | multispecsafe_options=-aggressive-swoop -hoist-delinquent=false -multi-access 51 | multispec_options=-speculative-swoop -hoist-delinquent=false -multi-access 52 | 53 | # Options for marking 54 | opt_marking=-require-delinquent=true 55 | 56 | # Debugging purposes: print variable using make print-$(VARIABLE) 57 | #print-%: ; @echo $*=$($*) 58 | 59 | # Debugging purposes: keep all generated ll files 60 | .PRECIOUS: %.ll 61 | .SECONDARY: 62 | 63 | .SECONDEXPANSION: 64 | # 65 | # Create marked files first (marked whether to swoopify or not), then 66 | # evaluate how to build the targets 67 | all: $(get_marked) 68 | $(MAKE) $(TARGETS) 69 | 70 | define create_swoop 71 | $(eval $@_UNR:=$(get_unroll)) 72 | $(eval $@_INDIR:=$(get_indir)) 73 | $(eval $@_OPTIONS:=$($(get_swoop_type)_options)) 74 | $(OPT) -S -tbaa -basicaa -globals-aa -scev-aa \ 75 | -load $(COMPILER_LIB)/libOptimisticSwoop.so $($@_OPTIONS) -merge-branches -branch-prob-threshold 0.9 \ 76 | -indir-thresh $($@_INDIR) \ 77 | -unroll $($@_UNR) -mem2reg -o $@ $<; 78 | endef 79 | 80 | # remove DVFS output 81 | # -load $(COMPILER_LIB)/libTimeOrig.so \ 82 | 83 | # Main makefile rules 84 | # 85 | $(BINDIR)/%.$(ORIGINAL_SUFFIX): $(get_objects) 86 | $(CLANGCPP) $(CXXFLAGS) $(CFLAGS) $^ $(LDFLAGS) $(LIBS_FLAGS) -o $@ 87 | 88 | $(BINDIR)/$(BENCHMARK).sched%.$(SCHEDULING_SUFFIX): $(get_sched_marked_files) $(get_sched_unmodified_files) 89 | $(CLANGCPP) $(CXXFLAGS) $(CFLAGS) $^ $(LDFLAGS) $(LIBS_FLAGS) -o $@ 90 | 91 | $(BINDIR)/$(BENCHMARK).%: $(get_unmodified_files) $(get_kernel_marked_files) 92 | $(CLANGCPP) $(CXXFLAGS) $(CFLAGS) $^ $(LDFLAGS) $(LIBS_FLAGS) -o $@ 93 | 94 | $(BINDIR)/$(BENCHMARK).cae: $(get_sched_marked_files) $(get_sched_unmodified_files) 95 | $(CLANGCPP) $(CXXFLAGS) $(CFLAGS) $^ $(LDFLAGS) $(LIBS_FLAGS) -o $@ 96 | 97 | %.smart.ll: $(get_swoop_prerequisites) 98 | ${create_swoop} 99 | 100 | %.consv.ll: $(get_swoop_prerequisites) 101 | ${create_swoop} 102 | 103 | %.specsafe.ll: $(get_swoop_prerequisites) 104 | ${create_swoop} 105 | %.spec.ll: $(get_swoop_prerequisites) 106 | ${create_swoop} 107 | 108 | %.multispecsafe.ll: $(get_swoop_prerequisites) 109 | ${create_swoop} 110 | %.multispec.ll: $(get_swoop_prerequisites) 111 | ${create_swoop} 112 | 113 | %.list-ilp.o: %.O3.ll 114 | $(LLC) -O3 -filetype=obj -pre-RA-sched=list-ilp $^ -o $@ 115 | %.list-burr.o: %.O3.ll 116 | $(LLC) -O3 -filetype=obj -pre-RA-sched=list-burr $^ -o $@ 117 | %.list-hybrid.o: %.O3.ll 118 | $(LLC) -O3 -filetype=obj -pre-RA-sched=list-hybrid $^ -o $@ 119 | 120 | # General object rules 121 | # 122 | $(BINDIR)/%.ll: %.c 123 | mkdir -p $(BINDIR)/$(shell dirname $^) 124 | $(CLANG) $(CFLAGS) $^ -S -emit-llvm -o $@ 125 | 126 | $(BINDIR)/%.ll: %.cpp 127 | mkdir -p $(BINDIR)/$(shell dirname $<) 128 | $(CLANGCPP) $(CXXFLAGS) $^ -S -emit-llvm -o $@ 129 | 130 | $(BINDIR)/%.ll: %.cc 131 | mkdir -p $(BINDIR)/$(shell dirname $<) 132 | $(CLANGCPP) $(CXXFLAGS) $^ -S -emit-llvm -o $@ 133 | 134 | $(BINDIR)/%.ll: %.C 135 | mkdir -p $(BINDIR)/$(shell dirname $<) 136 | $(CLANGCPP) $(CXXFLAGS) $^ -S -emit-llvm -o $@ 137 | 138 | 139 | # Do not run O3 on unrolling - otherwise the effect is diminished 140 | #%.unroll.O3.ll: %.unroll.ll 141 | # cp $< $@ 142 | 143 | 144 | %.O3.ll: %.ll 145 | $(OPT) -S -O3 $^ -o $@ 146 | 147 | # SWOOP related rules 148 | # 149 | %.marked.ll: %.stats.ll 150 | $(OPT) -S -load $(COMPILER_LIB)/libMarkLoopsToSwoopify.so \ 151 | -mark-loops -require-delinquent=false -bench-name $(BENCHMARK) \ 152 | -o $@ $<; \ 153 | 154 | %.annotated.ll: %.marked.ll 155 | $(OPT) -S -load $(COMPILER_LIB)/libCFGIndirectionCount.so -annotate-cfg-indir \ 156 | -loop-name $(SWOOP_MARKER) -o $@ $<; \ 157 | 158 | %.unroll.ll: $$(shell echo $$@ | sed 's/.unr[0-9]\+.*/.annotated.ll/g') 159 | $(eval $@_UNR:=$(get_unroll)) 160 | $(OPT) -S -loop-unswitch -instcombine -loops -lcssa \ 161 | -loop-simplify -loop-rotate -indvars -scalar-evolution -licm -lcssa \ 162 | -load $(COMPILER_LIB)/libUtilLoops.so -single-loop-unroll \ 163 | -loop-name $(SWOOP_MARKER) -unroll $($@_UNR) -o $@ $<; 164 | 165 | %.extract.ll: %.unroll.ll 166 | $(OPT) -S -load $(COMPILER_LIB)/libLoopExtract.so \ 167 | -aggregate-extracted-args -second-loop-extract -bench-name $(BENCHMARK) -mergereturn \ 168 | -load $(COMPILER_LIB)/libBranchAnnotate.so -branchannotate \ 169 | -o $@ $<; 170 | 171 | %.stats.ll: %.ll 172 | cp $< $@ 173 | 174 | %.cae.ll: %.extract.ll 175 | $(OPT) -S -load $(COMPILER_LIB)/libTimeOrig.so -papi-orig -always-inline -o $@ $<; 176 | 177 | clean: 178 | rm -rf $(BINDIR)/* 179 | -------------------------------------------------------------------------------- /experiments/swoop/sources/common/SWOOP/Makefile.targets: -------------------------------------------------------------------------------- 1 | ###### 2 | # Setting the targets to build 3 | # 4 | 5 | # Targets to build 6 | UNROLL_COUNT= 1 2 4 7 | INDIR_COUNT= 0 1 2 3 8 | INSTR_SCHED=list-ilp list-hybrid list-burr 9 | 10 | # Swoop filename suffixes 11 | ORIGINAL_SUFFIX=original 12 | SCHEDULING_SUFFIX=sched 13 | UNROLL_SUFFIX=unroll 14 | SWOOP_TYPE=consv spec specsafe multispec multispecsafe 15 | 16 | # Targets 17 | ORIGINAL_TARGETS=$(BENCHMARK).$(ORIGINAL_SUFFIX) 18 | SWOOP_TARGETS=$(foreach type, $(SWOOP_TYPE), \ 19 | $(foreach indir, $(INDIR_COUNT), \ 20 | $(foreach unr, $(UNROLL_COUNT), \ 21 | $(BENCHMARK).unr$(unr).indir$(indir).$(type)))) 22 | 23 | CAE_TARGETS=$(foreach unr, $(UNROLL_COUNT), $(BENCHMARK).unr$(unr).cae) 24 | UNROLL_TARGETS=$(foreach unr, $(UNROLL_COUNT), $(BENCHMARK).unr$(unr).unroll) 25 | 26 | 27 | SCHEDULING_TARGETS=$(foreach type, $(INSTR_SCHED), \ 28 | $(BENCHMARK).sched$(type).$(SCHEDULING_SUFFIX)) 29 | 30 | ALLTARGETS=$(SWOOP_TARGETS) $(ORIGINAL_TARGETS) $(SCHEDULING_TARGETS) 31 | 32 | # Output directory 33 | BINDIR=../bin 34 | 35 | # TARGETS 36 | TARGETS=$(addprefix $(BINDIR)/, $(ALLTARGETS)) 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /experiments/swoop/sources/myBenchmark/src/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) Eta Scale AB. Licensed under the Eta Scale Open Source License. See the LICENSE file for details. 2 | 3 | LEVEL=../../ 4 | BENCHMARK=myBenchmark 5 | 6 | UNROLL_COUNT= 7 | 8 | SRCS=small_benchmark.cpp 9 | 10 | CFLAGS= 11 | CXXFLAGS=-O3 12 | LDFLAGS= 13 | 14 | include $(LEVEL)/common/SWOOP/Makefile.targets 15 | include $(LEVEL)/common/SWOOP/Makefile.defaults 16 | -------------------------------------------------------------------------------- /experiments/swoop/sources/myBenchmark/src/small_benchmark.cpp: -------------------------------------------------------------------------------- 1 | /** # Copyright (C) Eta Scale AB. Licensed under the Eta Scale Open Source License. See the LICENSE file for details. 2 | * 3 | * # This is a small example benchmark */ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | /** Person struct holds 3 attributes which all null initialized: ID, attr, contactPerson. 12 | * ID is of type unsigned int, unique identifier 13 | * attr is of type int, descriptor for some feature 14 | * contactPerson is a pointer of struct Person. 15 | */ 16 | struct Person{ 17 | unsigned int ID; 18 | int attr; 19 | Person* contactPerson; 20 | Person(): ID(0),attr(0), contactPerson(NULL){} //initial null 21 | }; 22 | 23 | 24 | int main(int argc, char* argv[]){ 25 | int vecSize, seed; 26 | 27 | //if no argument is given, default setting is used 28 | if(argc == 1){ 29 | vecSize = 100000; 30 | seed = 0; 31 | } 32 | else if(argc == 2){ 33 | vecSize = atoi(argv[1]); 34 | seed = time(NULL); 35 | cout << "default random with time..." << endl; 36 | } 37 | else{ 38 | vecSize = atoi(argv[1]); 39 | seed = atoi(argv[2]); 40 | } 41 | srand(seed); 42 | std::vector record; 43 | 44 | //create Person vector, and set IDs 45 | for(int i = 0; i < vecSize; i++){ 46 | Person p; 47 | p.ID = i+1; 48 | //p.attr = rand()%(vecSize); 49 | record.push_back(p); 50 | } 51 | 52 | //assign contactPerson randomly but not oneself 53 | for (int i = 0; i < vecSize; ++i){ 54 | unsigned int rd = rand() % vecSize; 55 | if (rd == (unsigned int)i){ 56 | rd += 2; 57 | rd = rd%vecSize; 58 | } 59 | record[i].contactPerson = &record[rd]; 60 | 61 | 62 | } 63 | //Person's attr is changed to 1 if the contactPerson of this Person's contactPerson is this Person oneself. 64 | //loop with 5 indirections 65 | #pragma clang loop vectorize_width(1337) 66 | for(int i = 0; i < vecSize; ++i){ 67 | if ((record[(record[i].contactPerson->ID)-1].contactPerson->ID)-1 == i){ 68 | record[i].attr = 1; 69 | record[(record[i].contactPerson->ID)-1].attr = 1; 70 | } 71 | } 72 | 73 | //print information on all Person in vector 74 | for(int i = 0; i < vecSize; i++){ 75 | cout << "Person " << i << ": ID=" << record[i].ID << ", "; 76 | cout << "ID=" << record[i].contactPerson->ID << ", "; 77 | cout << "attr=" << record[i].attr << endl; 78 | } 79 | // std::cout << std::endl; 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | apt-get update 4 | apt-get install -y emacs 5 | apt-get install -y git 6 | apt-get install -y cmake 7 | apt-get install -y make 8 | apt-get install -y g++ 9 | apt-get install -y wget 10 | apt-get install -y binutils-gold binutils-dev 11 | apt-get install -y linux-tools-generic 12 | apt-get install -y python-dev 13 | apt-get install -y python-tk 14 | wget https://bootstrap.pypa.io/get-pip.py 15 | python ./get-pip.py 16 | pip install matplotlib 17 | pip install numpy 18 | pip install pandas 19 | pip install seaborn 20 | 21 | if ! [ -L /var/www ]; then 22 | rm -rf /var/www 23 | ln -fs /vagrant /var/www 24 | fi 25 | --------------------------------------------------------------------------------