├── .devcontainer ├── Dockerfile ├── devcontainer.json └── make-pkgconfig.sh ├── .editorconfig ├── .github ├── codecov.yml └── workflows │ └── test.yml ├── .gitignore ├── CMakeLists.txt ├── Coverage.md ├── LICENSE ├── Package.swift ├── README.md ├── Sources ├── CMakeLists.txt ├── SwiftyLLVM │ ├── AddressSpace.swift │ ├── AtomicOrdering.swift │ ├── AtomicRMWBinOp.swift │ ├── BasicBlock.swift │ ├── CodeGenerationResultType.swift │ ├── CodeModel.swift │ ├── DataLayout.swift │ ├── InsertionPoint.swift │ ├── LLVMError.swift │ ├── Linkage.swift │ ├── MemoryBuffer.swift │ ├── Module.swift │ ├── OptimizationLevel.swift │ ├── Refs.swift │ ├── RelocationModel.swift │ ├── Target.swift │ ├── TargetMachine.swift │ ├── Types │ │ ├── AnyType.swift │ │ ├── ArrayType.swift │ │ ├── FloatingPointType.swift │ │ ├── FunctionType.swift │ │ ├── IRType.swift │ │ ├── IntegerType.swift │ │ ├── PointerType.swift │ │ ├── StructType.swift │ │ └── VoidType.swift │ ├── Utils │ │ ├── ManagedPointer.swift │ │ └── String+Extensions.swift │ └── Values │ │ ├── Constants │ │ ├── AggregateConstant.swift │ │ ├── AnyValue.swift │ │ ├── ArrayConstant.swift │ │ ├── Attribute.swift │ │ ├── FloatingPointConstant.swift │ │ ├── Function+Attributes.swift │ │ ├── Function.swift │ │ ├── IntegerConstant.swift │ │ ├── Intrinsic.swift │ │ ├── Parameter+Attributes.swift │ │ ├── Parameter.swift │ │ ├── Poison.swift │ │ ├── StringConstant.swift │ │ ├── StructConstant.swift │ │ └── Undefined.swift │ │ ├── Global.swift │ │ ├── GlobalVariable.swift │ │ ├── IRValue.swift │ │ └── Instructions │ │ ├── Alloca.swift │ │ ├── FloatingPointPredicate.swift │ │ ├── Instruction.swift │ │ ├── IntegerPredicate.swift │ │ └── OverflowBehavior.swift ├── llvmc │ ├── llvmc.h │ └── module.modulemap └── llvmshims │ ├── include │ ├── module.modulemap │ └── shim.h │ └── src │ └── shim.cc ├── Tests ├── CMakeLists.txt └── LLVMTests │ ├── CodeGenerationTests.swift │ ├── DataLayoutTests.swift │ ├── MemoryBufferTests.swift │ ├── ModuleTests.swift │ ├── TargetMachineTests.swift │ ├── TargetTests.swift │ ├── Types │ ├── ArrayTypeTests.swift │ ├── FloatingPointTypeTests.swift │ ├── FunctionTypeTests.swift │ ├── IRTypeTests.swift │ ├── IntegerTypeTests.swift │ ├── PointerTypeTests.swift │ ├── StructTypeTests.swift │ └── VoidTypeTests.swift │ ├── Utils │ └── StringTests.swift │ └── Values │ ├── Constants │ ├── ArrayConstantTests.swift │ ├── AttributeTests.swift │ ├── FloatingPointConstantTests.swift │ ├── FunctionTests.swift │ ├── IntegerConstantTests.swift │ ├── IntrinsicTests.swift │ ├── ParameterTests.swift │ ├── PoisonTests.swift │ ├── StringConstantTests.swift │ ├── StructConstantTests.swift │ └── UndefinedTests.swift │ ├── GlobalVariableTests.swift │ ├── IRValueTests.swift │ └── Instructions │ ├── AllocaTests.swift │ └── SwitchTests.swift ├── Tools └── make-pkgconfig.sh └── cmake └── TopLevelDefaults.cmake /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG SWIFT_VERSION=5.9 2 | # Other ARG declarations must follow FROM 3 | FROM swift:${SWIFT_VERSION} 4 | 5 | ARG HYLO_LLVM_BUILD_TYPE=MinSizeRel 6 | ARG HYLO_LLVM_BUILD_RELEASE=20250603-162600 7 | ARG HYLO_LLVM_VERSION=17.0.6 8 | 9 | ENV HYLO_LLVM_DOWNLOAD_URL="https://github.com/hylo-lang/llvm-build/releases/download" 10 | 11 | RUN apt install -y gnupg 12 | RUN apt update 13 | RUN apt install -y curl libzstd-dev libzstd1 lsb-release make ninja-build tar wget zstd software-properties-common python3-pip 14 | 15 | # Get a recent cmake (https://www.kitware.com//cmake-python-wheels/) 16 | RUN if $(/usr/bin/which cmake) ; then apt purge --auto-remove cmake ; fi 17 | RUN pip3 install --upgrade cmake 18 | 19 | # Get the LLVM builds for the host architecture 20 | RUN < /dev/null 38 | rm /tmp/make-pkgconfig.sh 39 | 40 | EOT 41 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Hylo LLVM", 3 | "build": { 4 | "dockerfile": "Dockerfile", 5 | "args": { 6 | "SWIFT_VERSION" : "5.9", 7 | "HYLO_LLVM_BUILD_TYPE": "${localEnv:HYLO_LLVM_BUILD_TYPE:MinSizeRel}" 8 | } 9 | }, 10 | "features": { 11 | "ghcr.io/devcontainers/features/common-utils:2": { 12 | "installZsh": "false", 13 | "username": "vscode", 14 | "userUid": "1000", 15 | "userGid": "1000", 16 | "upgradePackages": "false" 17 | }, 18 | "ghcr.io/devcontainers/features/git:1": { 19 | "version": "os-provided", 20 | "ppa": "false" 21 | } 22 | }, 23 | "runArgs": [ 24 | "--cap-add=SYS_PTRACE", 25 | "--security-opt", 26 | "seccomp=unconfined", 27 | "--network=host" 28 | ], 29 | // Configure tool-specific properties. 30 | "customizations": { 31 | // Configure properties specific to VS Code. 32 | "vscode": { 33 | // Set *default* container specific settings.json values on container create. 34 | "settings": { 35 | "lldb.library": "/usr/lib/liblldb.so" 36 | }, 37 | // Add the IDs of extensions you want installed when the container is created. 38 | "extensions": [ 39 | "sswg.swift-lang" 40 | ] 41 | } 42 | }, 43 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 44 | // "forwardPorts": [], 45 | "containerEnv": { 46 | "HYLO_LLVM_BUILD_TYPE": "${localEnv:HYLO_LLVM_BUILD_TYPE:MinSizeRel}" 47 | }, 48 | "remoteEnv": { 49 | "PATH": "/opt/llvm-${containerEnv:HYLO_LLVM_BUILD_TYPE}/bin:${containerEnv:PATH}" 50 | }, 51 | // "postCreateCommand": "sudo ./.devcontainer/postCreateCommand.sh", 52 | // Set `remoteUser` to `root` to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. 53 | "remoteUser": "vscode" 54 | } 55 | -------------------------------------------------------------------------------- /.devcontainer/make-pkgconfig.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | set -o pipefail 4 | 5 | # Work around https://github.com/hylo-lang/llvm-build/issues/8 6 | # 7 | # We need to be resilient to no libzstd being found by pkg-config, as it is apparently not on linux. 8 | zstd_dash_L="$(pkg-config --silence-errors --libs-only-L libzstd || true)" 9 | if ! (llvm-config > /dev/null 2>&1); then 10 | if [[ "$OSTYPE" == "linux-gnu"* || "$OSTYPE" == "cygwin" || "$OSTYPE" == "freebsd"* ]]; then 11 | export LD_LIBRARY_PATH="${zstd_dash_L#-L}:$LD_LIBRARY_PATH" 12 | elif [[ "$OSTYPE" == "darwin"* ]]; then 13 | export DYLD_LIBRARY_PATH="${zstd_dash_L#-L}:$DYLD_LIBRARY_PATH" 14 | elif [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]]; then 15 | export PATH="${zstd_dash_L#-L}:$PATH" 16 | fi 17 | fi 18 | 19 | version=$(llvm-config --version) 20 | filename=$1 21 | 22 | mkdir -p `dirname $filename` 23 | touch $filename 24 | 25 | # REVISIT(nickpdemarco): 26 | # Why does macos need the standard library explicitly linked, while linux does not? 27 | # This does not feel like the correct place for this logic. 28 | machine="$(uname -s)" 29 | case "${machine}" in 30 | Darwin*) libs="-lc++";; 31 | *) libs="" 32 | esac 33 | 34 | libs=() 35 | for x in -L$(llvm-config --libdir) ${zstd_dash_L} $(llvm-config --system-libs --libs analysis bitwriter core native passes target); do 36 | libs+=($(printf '%q' "$x")) 37 | done 38 | cflags=() 39 | for x in $(llvm-config --cxxflags); do 40 | cflags+=($(printf '%q' "$x")) 41 | done 42 | 43 | echo Name: LLVM > $filename 44 | echo Description: Low-level Virtual Machine compiler framework >> $filename 45 | echo Version: $(echo ${version} | sed 's/\([0-9.]\+\).*/\1/') >> $filename 46 | echo URL: http://www.llvm.org/ >> $filename 47 | echo Libs: ${libs[@]} >> $filename 48 | echo Cflags: ${cflags[@]} >> $filename 49 | 50 | echo "$filename written:" 51 | cat $filename 52 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # A newline ending every file 7 | [*] 8 | # end_of_line = lf 9 | insert_final_newline = true 10 | charset = utf-8 11 | indent_style = space 12 | indent_size = 2 13 | max_line_length = 100 14 | -------------------------------------------------------------------------------- /.github/codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - '!Sources/' 3 | 4 | comment: 5 | require_changes: true 6 | 7 | coverage: 8 | status: 9 | 10 | project: 11 | default: 12 | threshold: 0% 13 | 14 | patch: 15 | default: 16 | # basic 17 | target: auto 18 | threshold: 0% 19 | base: auto 20 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Test 3 | 4 | on: 5 | push: 6 | branches: [ main ] 7 | paths-ignore: 8 | - "**.md" 9 | - "LICENSE" 10 | - ".gitignore" 11 | - ".editorconfig" 12 | pull_request: 13 | branches: [ "**" ] 14 | paths-ignore: 15 | - "**.md" 16 | - "LICENSE" 17 | - ".gitignore" 18 | - ".editorconfig" 19 | 20 | env: 21 | spm-build-options: -Xswiftc -enable-testing --explicit-target-dependency-import-check error 22 | spm-test-options: --parallel 23 | swift-version: '5.10' 24 | 25 | jobs: 26 | dev-container: 27 | name: "Dev container: ${{ matrix.cmake_build_type }}" 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | cmake_build_type: [Debug, Release] 32 | 33 | include: 34 | - spm_configuration: debug 35 | cmake_build_type: Debug 36 | more-spm-test-options: --enable-code-coverage 37 | HYLO_LLVM_BUILD_TYPE: Debug 38 | 39 | - spm_configuration: release 40 | cmake_build_type: Release 41 | HYLO_LLVM_BUILD_TYPE: MinSizeRel 42 | 43 | runs-on: ubuntu-latest 44 | steps: 45 | - uses: actions/checkout@v4 46 | with: 47 | submodules: true 48 | show-progress: false 49 | 50 | - name: Build and run via SPM 51 | uses: devcontainers/ci@v0.3 52 | env: 53 | HYLO_LLVM_BUILD_TYPE: ${{ matrix.HYLO_LLVM_BUILD_TYPE }} 54 | with: 55 | runCmd: swift test --parallel -c ${{ matrix.spm_configuration }} 56 | push: never 57 | 58 | - name: Build and run via CMake 59 | uses: devcontainers/ci@v0.3 60 | env: 61 | HYLO_LLVM_BUILD_TYPE: ${{ matrix.HYLO_LLVM_BUILD_TYPE }} 62 | with: 63 | runCmd: >- 64 | cmake -GNinja -S . -B .cmake-build 65 | -DCMAKE_BUILD_TYPE=${{ matrix.cmake_build_type }} 66 | -DBUILD_TESTING=YES 67 | -DLLVM_DIR=/opt/llvm-${{ matrix.HYLO_LLVM_BUILD_TYPE }}/lib/cmake/llvm 68 | 69 | cmake --build .cmake-build 70 | 71 | ctest --output-on-failure --parallel --test-dir .cmake-build 72 | push: never 73 | 74 | native: 75 | name: "Native: ${{ matrix.os }}/${{ matrix.spm_configuration }}/${{ matrix.cmake_generator }}" 76 | strategy: 77 | fail-fast: false 78 | matrix: 79 | os: [macos-14, ubuntu-latest, windows-latest] 80 | spm_configuration: [debug, release] 81 | cmake_generator: [Ninja, Xcode] 82 | 83 | exclude: 84 | - os: ubuntu-latest 85 | cmake_generator: Xcode 86 | - os: windows-latest 87 | cmake_generator: Xcode 88 | 89 | include: 90 | - HYLO_LLVM_BUILD_RELEASE: 20250603-162600 91 | - HYLO_LLVM_DOWNLOAD_URL: https://github.com/hylo-lang/llvm-build/releases/download 92 | - HYLO_LLVM_VERSION: '17.0.6' 93 | - llvm_package_suffix: .tar.zst 94 | - unpackage_command: tar -x --zstd -f 95 | - use_spm: true 96 | - triple_cpu: x86_64 97 | 98 | - os: windows-latest 99 | unpackage_command: 7z x -t7z 100 | llvm_package_suffix: .7z 101 | triple_suffix: unknown-windows-msvc17 102 | 103 | - os: windows-latest 104 | use_spm: false 105 | 106 | - os: macos-14 107 | triple_suffix: apple-darwin24.1.0 108 | triple_cpu: arm64 109 | 110 | - os: ubuntu-latest 111 | triple_suffix: unknown-linux-gnu 112 | 113 | - spm_configuration: debug 114 | cmake_build_type: Debug 115 | HYLO_LLVM_BUILD_TYPE: Debug 116 | 117 | - spm_configuration: release 118 | cmake_build_type: Release 119 | HYLO_LLVM_BUILD_TYPE: MinSizeRel 120 | 121 | - cmake_generator: Xcode 122 | use_spm: false 123 | 124 | runs-on: ${{ matrix.os }} 125 | env: 126 | llvm_url_prefix: ${{ matrix.HYLO_LLVM_DOWNLOAD_URL }}/${{ matrix.HYLO_LLVM_BUILD_RELEASE }} 127 | llvm_package_basename: llvm-${{ matrix.HYLO_LLVM_VERSION }}-${{ matrix.triple_cpu }}-${{ matrix.triple_suffix }}-${{ matrix.HYLO_LLVM_BUILD_TYPE }} 128 | 129 | steps: 130 | - name: Checkout 131 | uses: actions/checkout@v4 132 | with: 133 | submodules: true 134 | show-progress: false 135 | path: Swifty-LLVM 136 | 137 | - name: Set up swift (non-Windows) 138 | if: ${{ runner.os != 'Windows' }} 139 | uses: SwiftyLab/setup-swift@latest 140 | with: 141 | swift-version: ${{ env.swift-version }} 142 | 143 | - uses: compnerd/gha-setup-vsdevenv@main 144 | with: 145 | winsdk: "10.0.22621.0" # Workaround for this: https://forums.swift.org/t/swiftpm-plugin-doesnt-work-with-the-latest-visual-studio-version/78183/14 146 | # TL;DR: The Windows SDK had a change in 10.0.26100.0 that the Swift compiler didn't account for. 147 | # The Swift compiler team is aware of the issue and they are going to release a fix some time. 148 | - name: Set up swift (Windows) 149 | if: ${{ runner.os == 'Windows' }} 150 | uses: compnerd/gha-setup-swift@v0.2.2 151 | with: 152 | branch: swift-${{ env.swift-version }}-release 153 | tag: ${{ env.swift-version }}-RELEASE 154 | 155 | - name: Verify swift version 156 | run: swift --version && swift --version | grep -q ${{ env.swift-version }} 157 | shell: bash 158 | 159 | - name: Set up latest CMake and Ninja 160 | uses: lukka/get-cmake@latest 161 | with: 162 | cmakeVersion: latestrc 163 | 164 | - name: Install LLVM 165 | # 7z doesn't support decompressing from a stream or we'd do this all as one statement. Maybe 166 | # we should find a way to use zstd on windows. 167 | run: >- 168 | curl --no-progress-meter -L -O 169 | -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" 170 | ${{ env.llvm_url_prefix }}/${{ env.llvm_package_basename }}${{ matrix.llvm_package_suffix }} 171 | 172 | ${{ matrix.unpackage_command }} ${{ env.llvm_package_basename }}${{ matrix.llvm_package_suffix }} 173 | 174 | - name: Configure (CMake) 175 | # We explicitly point to swiftc in the PATH because otherwise CMake picks up the one in XCode. 176 | run: >- 177 | cmake -G '${{ matrix.cmake_generator }}' -S . -B .cmake-build 178 | ${{ matrix.cmake_generator != 'Xcode' && format('-DCMAKE_BUILD_TYPE={0}', matrix.cmake_build_type) || '' }} 179 | -DBUILD_TESTING=YES 180 | -DLLVM_DIR=${{ github.workspace }}/${{ env.llvm_package_basename }}/lib/cmake/llvm 181 | ${{ runner.os == 'macOS' && '-D CMAKE_Swift_COMPILER=swiftc -DCMAKE_OSX_SYSROOT=$(xcrun --show-sdk-path)' || '' }} 182 | working-directory: Swifty-LLVM 183 | 184 | - name: Build (CMake) 185 | run: cmake --build Swifty-LLVM/.cmake-build ${{ matrix.cmake_generator == 'Xcode' && format('--config {0}', matrix.cmake_build_type) || '' }} 186 | 187 | - name: Test (CMake) 188 | run: ctest --output-on-failure --parallel --test-dir Swifty-LLVM/.cmake-build ${{ matrix.cmake_generator == 'Xcode' && format('-C {0}', matrix.cmake_build_type) || '' }} 189 | 190 | - if: ${{ matrix.use_spm }} 191 | name: Create LLVM pkgconfig file and make it findable 192 | run: >- 193 | set -ex -o pipefail 194 | 195 | mkdir pkg-config 196 | 197 | PATH="${{ github.workspace }}/${{ env.llvm_package_basename }}/bin:$PATH" 198 | Swifty-LLVM/Tools/make-pkgconfig.sh pkg-config/llvm.pc 199 | 200 | echo 'PKG_CONFIG_PATH=${{ github.workspace }}/pkg-config' >> "$GITHUB_ENV" 201 | shell: bash 202 | 203 | - if: ${{ matrix.use_spm }} 204 | # Workaround for https://github.com/actions/cache/issues/1541 205 | uses: actions/cache@v4.2.2 206 | name: SPM cache setup 207 | with: 208 | path: hylo/.build 209 | key: ${{ matrix.os }}-${{ matrix.spm_configuration }}-spm-${{ hashFiles('hylo/**/Package.resolved') }} 210 | restore-keys: | 211 | ${{ matrix.os }}-${{ matrix.spm_configuration }}-spm- 212 | 213 | - if: ${{ matrix.use_spm }} 214 | name: Build and Test via SPM 215 | run: swift test --parallel -v ${{ matrix.swift_test_options }} -c ${{ matrix.spm_configuration }} 216 | working-directory: Swifty-LLVM 217 | 218 | - name: Export Coverage 219 | if: ${{ contains(matrix.swift_test_options, '--enable-code-coverage') }} 220 | working-directory: Swifty-LLVM 221 | run: | 222 | shopt -s nullglob 223 | dot_os=(.build/${{ matrix.spm_configuration }}/*.build/*.o .build/${{ matrix.spm_configuration }}/*.build/**/*.o) 224 | bin_params=("${dot_os[0]}") 225 | for o in "${dot_os[@]:1}"; do 226 | bin_params+=("-object" "${o}") 227 | done 228 | # Note: on mac this command might require a leading xcrun. 229 | llvm-cov export -format="lcov" -instr-profile "$(swift test -c ${{ matrix.spm_configuration }} --show-codecov-path | xargs dirname)"/default.profdata "${bin_params[@]}" > info.lcov 230 | 231 | - name: Upload coverage reports to Codecov 232 | if: ${{ contains(matrix.swift_test_options, '--enable-code-coverage') }} 233 | uses: codecov/codecov-action@v4 234 | with: 235 | token: ${{ secrets.CODECOV_TOKEN }} 236 | fail_ci_if_error: true 237 | directory: ${{ github.workspace }}/Swifty-LLVM 238 | working-directory: ${{ github.workspace }}/Swifty-LLVM 239 | root_dir: ${{ github.workspace }}/Swifty-LLVM 240 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This project 2 | llvm.pc 3 | 4 | # macOS 5 | .DS_Store 6 | 7 | # Xcode 8 | # 9 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 10 | 11 | ## User settings 12 | xcuserdata/ 13 | 14 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 15 | *.xcscmblueprint 16 | *.xccheckout 17 | 18 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 19 | build/ 20 | /.*-build 21 | DerivedData/ 22 | *.moved-aside 23 | *.pbxuser 24 | !default.pbxuser 25 | *.mode1v3 26 | !default.mode1v3 27 | *.mode2v3 28 | !default.mode2v3 29 | *.perspectivev3 30 | !default.perspectivev3 31 | 32 | ## Obj-C/Swift specific 33 | *.hmap 34 | 35 | ## App packaging 36 | *.ipa 37 | *.dSYM.zip 38 | *.dSYM 39 | 40 | ## Playgrounds 41 | timeline.xctimeline 42 | playground.xcworkspace 43 | 44 | # Swift Package Manager 45 | # 46 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 47 | # Packages/ 48 | # Package.pins 49 | # Package.resolved 50 | # *.xcodeproj 51 | # 52 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 53 | # hence it is not needed unless you have added a package configuration file to your project 54 | .swiftpm 55 | 56 | .build/ 57 | /Packages 58 | 59 | # CocoaPods 60 | # 61 | # We recommend against adding the Pods directory to your .gitignore. However 62 | # you should judge for yourself, the pros and cons are mentioned at: 63 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 64 | # 65 | # Pods/ 66 | # 67 | # Add this line if you want to avoid checking in source code from the Xcode workspace 68 | # *.xcworkspace 69 | 70 | # Carthage 71 | # 72 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 73 | # Carthage/Checkouts 74 | 75 | Carthage/Build/ 76 | 77 | # Accio dependency management 78 | Dependencies/ 79 | .accio/ 80 | 81 | # fastlane 82 | # 83 | # It is recommended to not store the screenshots in the git repo. 84 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 85 | # For more information about the recommended setup visit: 86 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 87 | 88 | fastlane/report.xml 89 | fastlane/Preview.html 90 | fastlane/screenshots/**/*.png 91 | fastlane/test_output 92 | 93 | # Code Injection 94 | # 95 | # After new code Injection tools there's a generated folder /iOSInjectionProject 96 | # https://github.com/johnno1962/injectionforxcode 97 | 98 | iOSInjectionProject/ 99 | 100 | /.vscode 101 | /.netrc 102 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Standard project boilerplate 3 | # 4 | cmake_minimum_required(VERSION 3.26) 5 | project(Swifty-LLVM 6 | VERSION 0.1.0 7 | DESCRIPTION "A Swifty interface for the LLVM compiler infrastructure, currently wrapping LLVM's C API." 8 | HOMEPAGE_URL "https://github.com/hylo-lang/Swifty-LLVM" 9 | LANGUAGES C CXX Swift 10 | ) 11 | enable_testing() 12 | list(PREPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules) 13 | if (PROJECT_IS_TOP_LEVEL) 14 | include(cmake/TopLevelDefaults.cmake) 15 | endif() 16 | 17 | add_subdirectory(Sources) 18 | 19 | if(BUILD_TESTING) 20 | add_subdirectory(Tests) 21 | endif() 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2021 Dimitri Racordon 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.9 2 | import PackageDescription 3 | 4 | 5 | // BEGIN: Poor person's pkg-config processing, since SPM doesn't 6 | // fully understand pkg-config files on Windows. 7 | import Foundation 8 | 9 | #if os(Windows) 10 | let osIsWindows = true 11 | #else 12 | let osIsWindows = false 13 | #endif 14 | 15 | /// The text used to separate elements of the PATH environment variable. 16 | let pathSeparator: Character = osIsWindows ? ";" : ":" 17 | 18 | /// Returns the contents of the pkg-config file for `package` if they 19 | /// can be found in `PKG_CONFIG_PATH`. 20 | /// 21 | /// N.B. Does not search the standard locations for the file as 22 | /// pkg-config would. 23 | func pseudoPkgConfigText(_ package: String) -> String? { 24 | guard let pcp = ProcessInfo.processInfo.environment["PKG_CONFIG_PATH"] else { return nil } 25 | 26 | return pcp.split(separator: pathSeparator) 27 | .lazy.compactMap({ try? String(contentsOfFile: "\($0)/\(package).pc") }).first 28 | } 29 | 30 | /// Returns the un-quoted, un-escaped elements in the remainder of the 31 | /// any (logical) lines beginning with `"\(key): "` in pcFileText, the contents 32 | /// of a pkg-config file. 33 | func pkgConfigValues(in pcFileText: String, for key: String) -> [String] { 34 | let keyPattern = NSRegularExpression.escapedPattern(for: key) 35 | let lineHeaders = pcFileText.matches( 36 | forRegex: #"(?m)(? [[Substring?]] { 81 | let r = try! NSRegularExpression(pattern: pattern) 82 | return r.matches( 83 | in: self, 84 | range: NSRange(startIndex.. [LinkerSetting] { 99 | guard let t = pseudoPkgConfigText("llvm") else { return [] } 100 | 101 | let libs = pkgConfigValues(in: t, for: "Libs") 102 | let linkLibraries = libs.lazy.filter { $0.starts(with: "-l") || $0.first != "-" }.map { 103 | let rest = $0.dropFirst($0.first == "-" ? 2 : 0) 104 | let afterSlashes = rest.lastIndex(where: { $0 == "/" || $0 == "\\" }) 105 | .map { rest.index(after: $0) } ?? rest.startIndex 106 | return rest[afterSlashes...] 107 | } 108 | 109 | return Array( 110 | linkLibraries 111 | .filter { $0.hasPrefix("LLVM") && $0.hasSuffix(".lib") } 112 | .map { LinkerSetting.linkedLibrary(String($0.dropLast(4))) }) 113 | } 114 | 115 | let llvmLinkerSettings = osIsWindows ? windowsLinkerSettings() : [] 116 | 117 | let package = Package( 118 | name: "Swifty-LLVM", 119 | products: [ 120 | .library(name: "SwiftyLLVM", targets: ["SwiftyLLVM"]), 121 | ], 122 | targets: [ 123 | // LLVM API Wrappers. 124 | .target( 125 | name: "SwiftyLLVM", 126 | dependencies: ["llvmc", "llvmshims"], 127 | swiftSettings: [.unsafeFlags(["-enable-experimental-feature", "AccessLevelOnImport"])], 128 | linkerSettings: llvmLinkerSettings), 129 | .target( 130 | name: "llvmshims", 131 | dependencies: ["llvmc"], 132 | linkerSettings: llvmLinkerSettings), 133 | 134 | // Tests. 135 | .testTarget(name: "LLVMTests", dependencies: ["SwiftyLLVM"]), 136 | 137 | // LLVM's C API 138 | .systemLibrary(name: "llvmc", pkgConfig: "llvm"), 139 | ], 140 | cxxLanguageStandard: .cxx20) 141 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Swifty-LLVM 2 | 3 | [![codecov](https://codecov.io/gh/hylo-lang/Swifty-LLVM/graph/badge.svg?token=M80FBR8JX8)](https://codecov.io/gh/hylo-lang/Swifty-LLVM) 4 | 5 | **Swifty-LLVM** is a Swifty interface for the [LLVM](https://llvm.org) compiler infrastructure, currently wrapping LLVM's C API. 6 | 7 | See also: [swift-llvm-bindings](https://github.com/apple/swift-llvm-bindings) 8 | 9 | ## Development/Use Requirements 10 | 11 | ### Swift 12 | 13 | This package requires Swift 5.9 14 | 15 | ### LLVM 16 | 17 | This package requires LLVM 17. Major versions of LLVM are not 18 | interchangeable or backward-compatible. 19 | 20 | If you are using this package for development we strongly recommend 21 | the use of an LLVM with assertions enabled such as 22 | [these](https://github.com/hylo-lang/llvm-build); otherwise it's much 23 | too easy to violate LLVM's preconditions without knowing it. This 24 | package's devcontainer (in the `.devcontainer` subdirectory) has 25 | assert-enabled LLVM builds preinstalled in `/opt/llvm-Debug` and 26 | `/opt/llvm-MinSizeRel`. 27 | 28 | *If* you want to build with the Swift Package Manager and you choose 29 | to get LLVM some other way, you'll need an installation with an 30 | `llvm-config` executable, which we will use to create a `pkg-config` 31 | file for LLVM. 32 | 33 | ## Building with CMake and Ninja 34 | 35 | 1. **Configure**: choose a *build-directory* and a CMake *build type* 36 | (usually `Debug` or `Release`) and then, where `` is the path 37 | to the root directory of your LLVM installation, 38 | 39 | ``` 40 | cmake -D CMAKE_BUILD_TYPE= \ 41 | -D LLVM_DIR=/lib/cmake/llvm \ 42 | -G Ninja -S . -B 43 | ``` 44 | 45 | (on Windows substitute your shell's line continuation character 46 | for `\` or just remove the line breaks and backslashes). 47 | 48 | If you want to run tests, add `-DBUILD_TESTING=1`. 49 | 50 | **Note:** on macOS, if you are not using your Xcode's default 51 | toolchain, [you may need `-D 52 | CMAKE_Swift_COMPILER=swiftc`](https://gitlab.kitware.com/cmake/cmake/-/issues/25750) 53 | to prevent CMake from using Xcode's default `swift`. 54 | 55 | If this command fails it could be because you have an LLVM without 56 | CMake support installed; we suggest you try one of 57 | [these](https://github.com/hylo-lang/llvm-build) packages instead. 58 | 59 | 2. **Build**: 60 | 61 | ``` 62 | cmake --build 63 | ``` 64 | 65 | 3. **Test** (requires `-DBUILD_TESTING=1` in step 1): 66 | 67 | ``` 68 | ctest --parallel --test-dir 69 | ``` 70 | 71 | ## Building with CMake and Xcode 72 | 73 | 1. **Generate Xcode project**: choose a *build-directory* and then, 74 | where `` is the path to the root directory of your LLVM 75 | installation, 76 | 77 | ``` 78 | cmake -D LLVM_DIR=/lib/cmake/llvm \ 79 | -G Xcode -S . -B 80 | ``` 81 | 82 | If you want to run tests, add `-DBUILD_TESTING=1`. 83 | 84 | 2. **Profit**: open the `.xcodeproj` file in the *build-directory* and 85 | use Xcode's UI to build and test. 86 | 87 | ## Building with Swift Package Manager 88 | 89 | **Note:** SPM builds are not supported on Windows at least until Swift 90 | 6.0 is released. 91 | 92 | First, you need to create a `pkgconfig` file specific to your 93 | installation and make it visible to your build tools. We use a `bash` 94 | script as follows in the top-level directory of this project: 95 | 96 | ```bash 97 | ./Tools/make-pkgconfig.sh ./llvm.pc 98 | ``` 99 | 100 | if you are on Windows, your `git` installation (which is required for 101 | Swift) contains a `bash` executable so you can do something like: 102 | 103 | ```bash 104 | C:\Program Files\Git\bin\bash ./Tools/make-pkgconfig.sh ./llvm.pc 105 | ``` 106 | 107 | The command above generates `llvm.pc` in the current directory and 108 | prints its contents to the terminal. You can either add its directory 109 | to your `PKG_CONFIG_PATH` environment variable for use with 110 | command-line tools: 111 | 112 | ```bash 113 | export PKG_CONFIG_PATH=$PWD 114 | ``` 115 | 116 | or you can put it somewhere that `pkg_config` already searches (needed 117 | for use with Xcode): 118 | 119 | ```bash 120 | sudo mkdir -p /usr/local/lib/pkgconfig && sudo mv llvm.pc /usr/local/lib/pkgconfig/ 121 | ``` 122 | 123 | Once `llvm.pc` is set up, you should be able to **build this project** 124 | using Swift package manager: 125 | 126 | ```bash 127 | swift build -c release 128 | ``` 129 | 130 | To test your compiler, 131 | 132 | ```bash 133 | swift test -c release --parallel 134 | ``` 135 | 136 | ## Notes to macOS users: 137 | 138 | 1. Add `platforms: [.macOS("xxx")]` to `Package.swift` where `xxx` is 139 | your macOS version to address the warning complaining that an 140 | "object file was built for newer macOS version than being linked". 141 | 2. You may need to add the path to `zstd` library in `llvm.pc`. 142 | -------------------------------------------------------------------------------- /Sources/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(HyloLLVM) 2 | include(HyloUtilities) 3 | 4 | set(CMAKE_CXX_STANDARD 20) 5 | set(CMAKE_Swift_LANGUAGE_VERSION 5) # Needed? Useful? 6 | 7 | # LLVM is built this way, and we must stay compatible with it. 8 | # TODO: Usage requirement? 9 | set(CMAKE_Swift_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY MultiThreadedDLL) 10 | set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreadedDLL) 11 | 12 | set(CMAKE_POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS}) # Needed? 13 | 14 | # The target that exposes the LLVM C API. 15 | add_library(llvmc INTERFACE) 16 | target_include_directories(llvmc INTERFACE 17 | llvmc 18 | ) 19 | 20 | # Our LLVM builds currently only vend support for one target architecture. 21 | string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" target_processor) 22 | if(target_processor STREQUAL "arm64" OR target_processor STREQUAL "aarch64") 23 | set(target_component AArch64) 24 | else() 25 | set(target_component X86) 26 | endif() 27 | llvm_map_components_to_libnames(llvm_libs bitwriter linker passes ${target_component}) 28 | target_link_libraries(llvmc INTERFACE ${llvm_libs}) 29 | 30 | # 31 | # A small library that exposes a few parts of the LLVM C++ API as C. 32 | # 33 | add_library(llvmshims STATIC llvmshims/src/shim.cc) 34 | target_include_directories(llvmshims PUBLIC llvmshims/include) 35 | target_link_libraries(llvmshims PRIVATE llvmc) 36 | # The Ubuntu GitHub runner demands this option: /usr/bin/ld.gold: error: 37 | # lib/libllvmshims.a(shim.cc.o): requires dynamic R_X86_64_PC32 reloc against 38 | # '_ZN4llvm17OptimizationLevel2O0E' which may overflow at runtime; recompile with -fPIC. We don't 39 | # use -fPIC directly because it clang on Windows rejects it. 40 | set_target_properties(llvmshims 41 | PROPERTIES 42 | POSITION_INDEPENDENT_CODE True) 43 | 44 | # 45 | # The Swift module our clients depend on. 46 | # 47 | set_recursive_file_glob(files SwiftyLLVM/*.swift) 48 | add_library(SwiftyLLVM ${files}) 49 | 50 | # This is required in order to be a testee. 51 | set_target_properties(SwiftyLLVM 52 | PROPERTIES FRAMEWORK TRUE 53 | ) 54 | 55 | target_link_libraries(SwiftyLLVM 56 | # TODO: does this really need to be public? Otherwise, I'm getting 57 | # DataLayoutTests.swift:1:8: error: missing required modules: 'llvmc', 'llvmshims' 58 | PUBLIC llvmshims llvmc) 59 | 60 | target_compile_options(SwiftyLLVM 61 | PRIVATE $<$:-enable-testing> -enable-experimental-feature AccessLevelOnImport) 62 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/AddressSpace.swift: -------------------------------------------------------------------------------- 1 | /// Properties of a pointer expressed through the data layout. 2 | public struct AddressSpace: Hashable { 3 | 4 | /// The LLVM representation of this instance. 5 | public let llvm: UInt32 6 | 7 | /// Creates an instance with given `rawValue`. 8 | internal init(_ rawValue: UInt32) { 9 | self.llvm = rawValue 10 | } 11 | 12 | /// The default address space. 13 | public static var `default` = AddressSpace(0) 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/AtomicOrdering.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// The ordering for an atomic operation. 4 | /// 5 | /// See https://en.cppreference.com/w/cpp/atomic/memory_order 6 | public enum AtomicOrdering { 7 | 8 | /// A load or a store operation that is not atomic. 9 | /// 10 | /// Matches C++ memory model for non-atomic shared variables. 11 | case notAtomic 12 | 13 | /// Lowest level of atomicity, guarantees somewhat sane results, lock free. 14 | /// 15 | /// Matches Java memory model for shared variables. 16 | case unordered 17 | 18 | /// Guarantees that if you take all the operations affecting a specific address, a consistent 19 | /// ordering exists. 20 | /// 21 | /// Matches the C++ memory_order_relaxed memory order. 22 | case monotonic 23 | 24 | /// A load that is an *acquire operation*, or a barrier necessary to acquire a lock to access 25 | /// other memory with normal loads and stores. 26 | /// 27 | /// Matches the C++ memory_order_acquire memory order. 28 | case acquire 29 | 30 | /// A store that is a *release operation*, or a barrier necessary to release a lock. 31 | /// 32 | /// Matches the C++ memory_order_release memory order. 33 | case release 34 | 35 | /// A read-modify-write operation with this memory order is both an *acquire operation* and a 36 | /// *release operation*, or a barrier that is both an Acquire and a Release barrier. 37 | /// 38 | /// Matches the C++ memory_order_acq_rel memory order. 39 | case acquireRelease 40 | 41 | /// Same as `acquireRelease`, but also provides a single total order of all modifications. 42 | /// 43 | /// Matches the C++ memory_order_seq_cst memory order. 44 | case sequentiallyConsistent 45 | 46 | /// Creates an instance from its LLVM representation. 47 | internal init(llvm: LLVMAtomicOrdering) { 48 | switch llvm { 49 | case LLVMAtomicOrderingNotAtomic: 50 | self = .notAtomic 51 | case LLVMAtomicOrderingUnordered: 52 | self = .unordered 53 | case LLVMAtomicOrderingMonotonic: 54 | self = .monotonic 55 | case LLVMAtomicOrderingAcquire: 56 | self = .acquire 57 | case LLVMAtomicOrderingRelease: 58 | self = .release 59 | case LLVMAtomicOrderingAcquireRelease: 60 | self = .acquireRelease 61 | case LLVMAtomicOrderingSequentiallyConsistent: 62 | self = .sequentiallyConsistent 63 | default: 64 | fatalError("unsupported atomic ordering") 65 | } 66 | } 67 | 68 | /// The LLVM representation of this instance. 69 | internal var llvm: LLVMAtomicOrdering { 70 | switch self { 71 | case .notAtomic: 72 | return LLVMAtomicOrderingNotAtomic 73 | case .unordered: 74 | return LLVMAtomicOrderingUnordered 75 | case .monotonic: 76 | return LLVMAtomicOrderingMonotonic 77 | case .acquire: 78 | return LLVMAtomicOrderingAcquire 79 | case .release: 80 | return LLVMAtomicOrderingRelease 81 | case .acquireRelease: 82 | return LLVMAtomicOrderingAcquireRelease 83 | case .sequentiallyConsistent: 84 | return LLVMAtomicOrderingSequentiallyConsistent 85 | } 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/AtomicRMWBinOp.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// The type of an atomic read-modify-write binary operation. 4 | public enum AtomicRMWBinOp { 5 | 6 | /// Set the new value and return the one old. 7 | case xchg 8 | /// Add a value and return the old one. 9 | case add 10 | /// Subtract a value and return the old one. 11 | case sub 12 | /// And a value and return the old one. 13 | case and 14 | /// Not-And a value and return the old one. 15 | case nand 16 | /// OR a value and return the old one. 17 | case or 18 | /// Xor a value and return the old one. 19 | case xor 20 | /// Sets the value if it's greater than the original using a signed comparison and return the old one. 21 | case max 22 | /// Sets the value if it's Smaller than the original using a signed comparison and return the old one. 23 | case min 24 | /// Sets the value if it's greater than the original using an unsigned comparison and return the old one. 25 | case uMax 26 | /// Sets the value if it's greater than the original using an unsigned comparison and return the old one. 27 | case uMin 28 | /// Add a floating point value and return the old one. 29 | case fAdd 30 | /// Subtract a floating point value and return the old one. 31 | case fSub 32 | /// Sets the value if it's greater than the original using an floating point comparison and return the old one. 33 | case fMax 34 | /// Sets the value if it's smaller than the original using an floating point comparison and return the old one. 35 | case fMin 36 | 37 | 38 | /// Creates an instance from its LLVM representation. 39 | internal init(llvm: LLVMAtomicRMWBinOp) { 40 | switch llvm { 41 | case LLVMAtomicRMWBinOpXchg: 42 | self = .xchg 43 | case LLVMAtomicRMWBinOpAdd: 44 | self = .add 45 | case LLVMAtomicRMWBinOpSub: 46 | self = .sub 47 | case LLVMAtomicRMWBinOpAnd: 48 | self = .and 49 | case LLVMAtomicRMWBinOpNand: 50 | self = .nand 51 | case LLVMAtomicRMWBinOpOr: 52 | self = .or 53 | case LLVMAtomicRMWBinOpXor: 54 | self = .xor 55 | case LLVMAtomicRMWBinOpMax: 56 | self = .max 57 | case LLVMAtomicRMWBinOpMin: 58 | self = .min 59 | case LLVMAtomicRMWBinOpUMax: 60 | self = .uMax 61 | case LLVMAtomicRMWBinOpUMin: 62 | self = .uMin 63 | case LLVMAtomicRMWBinOpFAdd: 64 | self = .fAdd 65 | case LLVMAtomicRMWBinOpFSub: 66 | self = .fSub 67 | case LLVMAtomicRMWBinOpFMax: 68 | self = .fMax 69 | case LLVMAtomicRMWBinOpFMin: 70 | self = .fMin 71 | default: 72 | fatalError("unsupported atomic RMW binary operation") 73 | } 74 | } 75 | 76 | /// The LLVM representation of this instance. 77 | internal var llvm: LLVMAtomicRMWBinOp { 78 | switch self { 79 | case .xchg: 80 | return LLVMAtomicRMWBinOpXchg 81 | case .add: 82 | return LLVMAtomicRMWBinOpAdd 83 | case .sub: 84 | return LLVMAtomicRMWBinOpSub 85 | case .and: 86 | return LLVMAtomicRMWBinOpAnd 87 | case .nand: 88 | return LLVMAtomicRMWBinOpNand 89 | case .or: 90 | return LLVMAtomicRMWBinOpOr 91 | case .xor: 92 | return LLVMAtomicRMWBinOpXor 93 | case .max: 94 | return LLVMAtomicRMWBinOpMax 95 | case .min: 96 | return LLVMAtomicRMWBinOpMin 97 | case .uMax: 98 | return LLVMAtomicRMWBinOpUMax 99 | case .uMin: 100 | return LLVMAtomicRMWBinOpUMin 101 | case .fAdd: 102 | return LLVMAtomicRMWBinOpFAdd 103 | case .fSub: 104 | return LLVMAtomicRMWBinOpFSub 105 | case .fMax: 106 | return LLVMAtomicRMWBinOpFMax 107 | case .fMin: 108 | return LLVMAtomicRMWBinOpFMin 109 | } 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/BasicBlock.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// A basic block in LLVM IR. 4 | public struct BasicBlock: Hashable { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | public let llvm: BasicBlockRef 8 | 9 | /// Creates an instance wrapping `llvm`. 10 | internal init(_ llvm: LLVMBasicBlockRef) { 11 | self.llvm = .init(llvm) 12 | } 13 | 14 | } 15 | 16 | extension BasicBlock: CustomStringConvertible { 17 | 18 | public var description: String { 19 | guard let s = LLVMGetBasicBlockName(llvm.raw) else { return "" } 20 | return String(cString: s) 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/CodeGenerationResultType.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// The kind of result produced by code generation. 4 | public enum CodeGenerationResultType: Hashable { 5 | 6 | /// Assembly. 7 | case assembly 8 | 9 | /// An object file. 10 | case objectFile 11 | 12 | /// The LLVM representation of this instance. 13 | internal var llvm: LLVMCodeGenFileType { 14 | switch self { 15 | case .assembly: 16 | return LLVMAssemblyFile 17 | case .objectFile: 18 | return LLVMObjectFile 19 | } 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/CodeModel.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// Constraints on address ranges that the program and its symbols may use. 4 | public enum CodeModel: Hashable { 5 | 6 | /// The model default to the target for which code is being generated. 7 | case `default` 8 | 9 | /// The model default to the target for JITed code. 10 | case jit 11 | 12 | /// Tiny code model. 13 | case tiny 14 | 15 | /// Small code model. 16 | case small 17 | 18 | /// Kernel code model. 19 | case kernel 20 | 21 | /// Medium code model. 22 | case medium 23 | 24 | /// Large code model. 25 | case large 26 | 27 | /// The LLVM representation of this instance. 28 | internal var llvm: LLVMCodeModel { 29 | switch self { 30 | case .default: 31 | return LLVMCodeModelDefault 32 | case .jit: 33 | return LLVMCodeModelJITDefault 34 | case .tiny: 35 | return LLVMCodeModelTiny 36 | case .small: 37 | return LLVMCodeModelSmall 38 | case .kernel: 39 | return LLVMCodeModelKernel 40 | case .medium: 41 | return LLVMCodeModelMedium 42 | case .large: 43 | return LLVMCodeModelLarge 44 | } 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/DataLayout.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// How data are represented in memory for a particular target machine. 4 | public struct DataLayout { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | private let wrapped: ManagedPointer 8 | 9 | /// Creates an instance wrapping `llvm`. 10 | internal init(_ llvm: LLVMTargetDataRef) { 11 | self.wrapped = .init(llvm, dispose: LLVMDisposeTargetData(_:)) 12 | } 13 | 14 | /// Creates an instance representing the data layout associated with `machine`. 15 | public init(of machine: TargetMachine) { 16 | let handle = LLVMCreateTargetDataLayout(machine.llvm) 17 | self.wrapped = .init(handle!, dispose: LLVMDisposeTargetData(_:)) 18 | } 19 | 20 | /// A handle to the LLVM object wrapped by this instance. 21 | internal var llvm: LLVMTargetDataRef { wrapped.llvm } 22 | 23 | /// Returns the number of bits in the representation of `type`'s instances. 24 | public func bitWidth(of type: IRType) -> Int { 25 | Int(LLVMSizeOfTypeInBits(llvm, type.llvm.raw)) 26 | } 27 | 28 | /// Returns the storage size of the representation of `type`'s instances in bytes. 29 | public func storageSize(of type: IRType) -> Int { 30 | Int(LLVMStoreSizeOfType(llvm, type.llvm.raw)) 31 | } 32 | 33 | /// Returns the number of bytes from one instance of `type` to the next when stored in contiguous 34 | /// memory. 35 | public func storageStride(of type: IRType) -> Int { 36 | let align = abiAlignment(of: type) 37 | assert(align > 0) 38 | return (storageSize(of: type) + align - 1) / align * align 39 | } 40 | 41 | /// The alignment of `type`'s instances in bytes. 42 | public func preferredAlignment(of type: IRType) -> Int { 43 | Int(LLVMPreferredAlignmentOfType(llvm, type.llvm.raw)) 44 | } 45 | 46 | /// The ABI alignment of `type`'s instances in bytes. 47 | public func abiAlignment(of type: IRType) -> Int { 48 | Int(LLVMABIAlignmentOfType(llvm, type.llvm.raw)) 49 | } 50 | 51 | /// Returns the offset in bytes of the element at given `index`. 52 | /// 53 | /// - Requires: `index` is a valid element index in `type`. 54 | public func offset(of index: Int, in type: StructType) -> Int { 55 | Int(LLVMOffsetOfElement(llvm, type.llvm.raw, UInt32(index))) 56 | } 57 | 58 | /// Returns the index of the element containing the byte at given `offset`. 59 | /// 60 | /// - Requires: `offset` is a valid byte offset in `type`. 61 | public func index(at offset: Int, in type: StructType) -> Int { 62 | Int(LLVMElementAtOffset(llvm, type.llvm.raw, UInt64(offset))) 63 | } 64 | 65 | } 66 | 67 | extension DataLayout: Equatable { 68 | 69 | public static func == (lhs: Self, rhs: Self) -> Bool { 70 | lhs.description == rhs.description 71 | } 72 | 73 | } 74 | 75 | extension DataLayout: Hashable { 76 | 77 | public func hash(into hasher: inout Hasher) { 78 | hasher.combine(description) 79 | } 80 | 81 | } 82 | 83 | extension DataLayout: CustomStringConvertible { 84 | 85 | public var description: String { 86 | guard let s = LLVMCopyStringRepOfTargetData(llvm) else { return "" } 87 | defer { LLVMDisposeMessage(s) } 88 | return .init(cString: s) 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/InsertionPoint.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// A cursor specifying where IR instructions should be inserted. 4 | public struct InsertionPoint { 5 | 6 | /// A pointer the object wrapped by this instance. 7 | private let wrapped: ManagedPointer 8 | 9 | /// Creates an instance wrapping `llvm`. 10 | internal init(_ llvm: LLVMBuilderRef) { 11 | self.wrapped = .init(llvm, dispose: LLVMDisposeBuilder(_:)) 12 | } 13 | 14 | /// A handle to the LLVM object wrapped by this instance. 15 | internal var llvm: LLVMBuilderRef { wrapped.llvm } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/LLVMError.swift: -------------------------------------------------------------------------------- 1 | /// An error that occurred during a LLVM operation. 2 | public struct LLVMError: Error { 3 | 4 | /// A description of the error. 5 | public let description: String 6 | 7 | /// Creates an instance with given `description`. 8 | internal init(_ description: String) { 9 | self.description = description 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Linkage.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// How names can or cannot be referred to. 4 | /// 5 | /// - Note: It is illegal for a global variable or function declaration to have any linkage type 6 | /// other than `external` or `extern_weak`. 7 | public enum Linkage { 8 | 9 | /// The name is externally visible; it participates in linkage and can be used to resolve 10 | /// external symbol references. 11 | case external 12 | 13 | /// The name is never emitted into the object file corresponding to the LLVM module 14 | /// 15 | /// Globals with `available_externally` linkage are allowed to be discarded at will, and allow 16 | /// inlining and other optimizations. This linkage type is only allowed on definitions, not 17 | /// declarations. 18 | case availableExternally 19 | 20 | /// The name is merged with other globals of the same name when linkage occurs. 21 | /// 22 | /// This linkage can be used to implement some forms of inline functions, templates, or other 23 | /// code which must be generated in each translation unit that uses it, but where the body may 24 | /// be overridden with a more definitive definition later. Unreferenced `linkonce` globals are 25 | /// allowed to be discarded. 26 | /// 27 | /// Note that linkonce linkage does not actually allow the optimizer to inline the body of this 28 | /// function into callers because it doesn’t know if this definition of the function is the 29 | /// definitive definition within the program or whether it will be overridden by a stronger 30 | /// definition. To enable inlining and other optimizations, use `linkonce_odr` linkage. 31 | case linkOnce 32 | 33 | /// The name is merged with other globals of the same name when linkage occurs. 34 | /// 35 | /// Some languages allow differing globals to be merged, such as two functions with different 36 | /// semantics. Other languages, such as C++, ensure that only equivalent globals are ever merged 37 | /// (the "one definition rule" — "ODR"). Such languages can use the `linkonce_odr` and `weak_odr` 38 | /// linkage types to indicate that the global will only be merged with equivalent globals. These 39 | /// linkage types are otherwise the same as their non-odr versions. 40 | case linkOnceODR 41 | 42 | /// Same as `linkonce`, except that unreferenced globals with weak linkage may not be discarded. 43 | case weak 44 | 45 | /// Same as `linkonce`, except that unreferenced globals with weak linkage may not be discarded. 46 | /// 47 | /// Some languages allow differing globals to be merged, such as two functions with different 48 | /// semantics. Other languages, such as C++, ensure that only equivalent globals are ever merged 49 | /// (the "one definition rule" — "ODR"). Such languages can use the `linkonce_odr` and `weak_odr` 50 | /// linkage types to indicate that the global will only be merged with equivalent globals. These 51 | /// linkage types are otherwise the same as their non-odr versions. 52 | case weakODR 53 | 54 | /// The value of the names are appended. 55 | /// 56 | /// Only applies to global variables of pointer to array type. 57 | case appending 58 | 59 | /// Similar to `private`, but the value shows as a local symbol (`STB_LOCAL` in the case of 60 | /// `ELF`) in the object file. 61 | case `internal` 62 | 63 | /// The name is only accessible by objects in the current module. 64 | /// 65 | /// Linking code into a module with a private global value may cause the private to be renamed as 66 | /// necessary to avoid collisions. Because the symbol is private to the module, all references 67 | /// can be updated. This doesn’t show up in any symbol table in the object file. 68 | case `private` 69 | 70 | /// The semantics of this linkage follow the ELF object file model: the symbol is weak until 71 | /// linked, if not linked, the symbol becomes null instead of being an undefined reference. 72 | case externWeak 73 | 74 | /// Creates an instance from its LLVM representation. 75 | internal init(llvm: LLVMLinkage) { 76 | switch llvm { 77 | case LLVMExternalLinkage: 78 | self = .external 79 | case LLVMAvailableExternallyLinkage: 80 | self = .availableExternally 81 | case LLVMLinkOnceAnyLinkage: 82 | self = .linkOnce 83 | case LLVMLinkOnceODRLinkage: 84 | self = .linkOnceODR 85 | case LLVMWeakAnyLinkage: 86 | self = .weak 87 | case LLVMWeakODRLinkage: 88 | self = .weakODR 89 | case LLVMAppendingLinkage: 90 | self = .appending 91 | case LLVMInternalLinkage: 92 | self = .internal 93 | case LLVMPrivateLinkage: 94 | self = .private 95 | case LLVMExternalWeakLinkage: 96 | self = .externWeak 97 | default: 98 | fatalError("unsupported linkage type") 99 | } 100 | } 101 | 102 | /// The LLVM representation of this instance. 103 | internal var llvm: LLVMLinkage { 104 | switch self { 105 | case .external: 106 | return LLVMExternalLinkage 107 | case .availableExternally: 108 | return LLVMAvailableExternallyLinkage 109 | case .linkOnce: 110 | return LLVMLinkOnceAnyLinkage 111 | case .linkOnceODR: 112 | return LLVMLinkOnceODRLinkage 113 | case .weak: 114 | return LLVMWeakAnyLinkage 115 | case .weakODR: 116 | return LLVMWeakODRLinkage 117 | case .appending: 118 | return LLVMAppendingLinkage 119 | case .internal: 120 | return LLVMInternalLinkage 121 | case .private: 122 | return LLVMPrivateLinkage 123 | case .externWeak: 124 | return LLVMExternalWeakLinkage 125 | } 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/MemoryBuffer.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// A read-only access to a block of memory. 4 | public struct MemoryBuffer { 5 | 6 | /// A handle to the LLVM object representing a memory buffer. 7 | private final class Handle { 8 | 9 | /// A pointer to a LLVM memory buffer. 10 | let llvm: LLVMMemoryBufferRef 11 | 12 | /// `true` iff this instance is the owner of the memory pointed by `llvm`. 13 | private let isOwner: Bool 14 | 15 | /// Creates an instance wrapping `llvm` and calling `LLVMDisposeMemoryBuffer` on it at the 16 | /// end of its lifetime iff `isOwner` is `true`. 17 | init(_ llvm: LLVMMemoryBufferRef, owned isOwner: Bool) { 18 | self.llvm = llvm 19 | self.isOwner = isOwner 20 | } 21 | 22 | deinit { 23 | if !isOwner { return } 24 | LLVMDisposeMemoryBuffer(llvm) 25 | } 26 | 27 | } 28 | 29 | /// A pointer the object wrapped by this instance. 30 | private let wrapped: Handle 31 | 32 | /// Creates an instance referring to the memory represented by `llvm`, taking ownership of the 33 | /// memory iff `isOwned` is `true`. 34 | internal init(_ llvm: LLVMMemoryBufferRef, owned isOwned: Bool) { 35 | self.wrapped = .init(llvm, owned: isOwned) 36 | } 37 | 38 | /// Creates an instance with given `name`, copying the bytes of `source`. 39 | public init(copying source: UnsafeBufferPointer, named name: String = "") { 40 | let handle = LLVMCreateMemoryBufferWithMemoryRangeCopy(source.baseAddress, source.count, name) 41 | self.init(handle!, owned: true) 42 | } 43 | 44 | /// Creates an instance with the contents at `filepath`. 45 | public init(contentsOf filepath: String) throws { 46 | var handle: LLVMMemoryBufferRef? = nil 47 | var error: UnsafeMutablePointer? = nil 48 | LLVMCreateMemoryBufferWithContentsOfFile(filepath, &handle, &error) 49 | 50 | if let e = error { 51 | defer { LLVMDisposeMessage(e) } 52 | throw LLVMError("read failure: \(String(cString: e))") 53 | } 54 | 55 | self.init(handle!, owned: true) 56 | } 57 | 58 | /// Calls `action` with a memory buffer named `name`, borrowing the bytes of `source`. 59 | public static func withInstanceBorrowing( 60 | _ source: UnsafeBufferPointer, named name: String = "", 61 | _ action: (MemoryBuffer) throws -> T 62 | ) rethrows -> T { 63 | let handle = LLVMCreateMemoryBufferWithMemoryRange(source.baseAddress, source.count, name, 0) 64 | return try action(.init(handle!, owned: false)) 65 | } 66 | 67 | /// The number of bytes in the buffer. 68 | public var count: Int { 69 | LLVMGetBufferSize(llvm) 70 | } 71 | 72 | /// Calls `action` with the contents of the buffer. 73 | public func withUnsafeBytes( 74 | _ action: (UnsafeBufferPointer) throws -> T 75 | ) rethrows -> T { 76 | let start = LLVMGetBufferStart(llvm) 77 | return try action(.init(start: start, count: count)) 78 | } 79 | 80 | /// A handle to the LLVM object wrapped by this instance. 81 | internal var llvm: LLVMMemoryBufferRef { wrapped.llvm } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Module.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | import llvmshims 3 | 4 | /// The top-level structure in an LLVM program. 5 | public struct Module { 6 | 7 | /// The resources wrapped by an instance of `Module`. 8 | private final class Handles { 9 | 10 | /// The context owning the contents of the LLVM module. 11 | let context: LLVMContextRef 12 | 13 | /// The LLVM module. 14 | let module: LLVMModuleRef 15 | 16 | /// Creates an instance with given properties. 17 | init(context: LLVMContextRef, module: LLVMModuleRef) { 18 | self.context = context 19 | self.module = module 20 | } 21 | 22 | /// Dispose of the managed resources. 23 | deinit { 24 | LLVMDisposeModule(module) 25 | LLVMContextDispose(context) 26 | } 27 | 28 | } 29 | 30 | /// Handles to the resources wrapped by this instance. 31 | private let handles: Handles 32 | 33 | /// Creates an instance with given `name`. 34 | public init(_ name: String) { 35 | let c = LLVMContextCreate()! 36 | let m = LLVMModuleCreateWithNameInContext(name, c)! 37 | self.handles = .init(context: c, module: m) 38 | } 39 | 40 | /// A handle to the LLVM object wrapped by this instance. 41 | public var llvm: ModuleRef { .init(handles.module) } 42 | 43 | /// A handle to the LLVM context associated with this module. 44 | internal var context: LLVMContextRef { handles.context } 45 | 46 | /// The name of the module. 47 | public var name: String { 48 | get { 49 | String(from: llvm.raw, readingWith: LLVMGetModuleIdentifier(_:_:)) ?? "" 50 | } 51 | set { 52 | newValue.withCString({ LLVMSetModuleIdentifier(llvm.raw, $0, newValue.utf8.count) }) 53 | } 54 | } 55 | 56 | /// The data layout of the module. 57 | public var layout: DataLayout { 58 | get { 59 | let s = LLVMGetDataLayoutStr(llvm.raw) 60 | let h = LLVMCreateTargetData(s) 61 | return .init(h!) 62 | } 63 | set { 64 | LLVMSetDataLayout(llvm.raw, newValue.description) 65 | } 66 | } 67 | 68 | /// The target of the module. 69 | public var target: Target? { 70 | get { 71 | guard let t = LLVMGetTarget(llvm.raw) else { return nil } 72 | return try? Target(triple: .init(cString: t)) 73 | } 74 | set { 75 | LLVMSetTarget(llvm.raw, newValue?.triple) 76 | } 77 | } 78 | 79 | /// Verifies if the IR in `self` is well formed and throws an error if it isn't. 80 | public func verify() throws { 81 | var message: UnsafeMutablePointer? = nil 82 | defer { LLVMDisposeMessage(message) } 83 | let status = withUnsafeMutablePointer(to: &message, { (m) in 84 | LLVMVerifyModule(llvm.raw, LLVMReturnStatusAction, m) 85 | }) 86 | 87 | if status != 0 { 88 | throw LLVMError(.init(cString: message!)) 89 | } 90 | } 91 | 92 | /// Runs standard optimization passes on `self` tuned for given `optimization` and `machine`. 93 | public mutating func runDefaultModulePasses( 94 | optimization: OptimitzationLevel = .none, 95 | for machine: TargetMachine? = nil 96 | ) { 97 | let o: SwiftyLLVMPassOptimizationLevel 98 | switch optimization { 99 | case .none: 100 | o = SwiftyLLVMPassOptimizationLevelO0 101 | case .less: 102 | o = SwiftyLLVMPassOptimizationLevelO1 103 | case .default: 104 | o = SwiftyLLVMPassOptimizationLevelO2 105 | case .aggressive: 106 | o = SwiftyLLVMPassOptimizationLevelO3 107 | } 108 | SwiftyLLVMRunDefaultModulePasses(llvm.raw, machine?.llvm, o) 109 | } 110 | 111 | /// Writes the LLVM bitcode of this module to `filepath`. 112 | public func writeBitcode(to filepath: String) throws { 113 | guard LLVMWriteBitcodeToFile(llvm.raw, filepath) == 0 else { 114 | throw LLVMError("write failure") 115 | } 116 | } 117 | 118 | /// Returns the LLVM bitcode of this module. 119 | public func bitcode() -> MemoryBuffer { 120 | .init(LLVMWriteBitcodeToMemoryBuffer(llvm.raw), owned: true) 121 | } 122 | 123 | /// Compiles this module for given `machine` and writes a result of kind `type` to `filepath`. 124 | public func write( 125 | _ type: CodeGenerationResultType, 126 | for machine:TargetMachine, 127 | to filepath: String 128 | ) throws { 129 | var error: UnsafeMutablePointer? = nil 130 | LLVMTargetMachineEmitToFile(machine.llvm, llvm.raw, filepath, type.llvm, &error) 131 | 132 | if let e = error { 133 | defer { LLVMDisposeMessage(e) } 134 | throw LLVMError(.init(cString: e)) 135 | } 136 | } 137 | 138 | /// Compiles this module for given `machine` and returns a result of kind `type`. 139 | public func compile( 140 | _ type: CodeGenerationResultType, 141 | for machine: TargetMachine 142 | ) throws -> MemoryBuffer { 143 | var output: LLVMMemoryBufferRef? = nil 144 | var error: UnsafeMutablePointer? = nil 145 | LLVMTargetMachineEmitToMemoryBuffer(machine.llvm, llvm.raw, type.llvm, &error, &output) 146 | 147 | if let e = error { 148 | defer { LLVMDisposeMessage(e) } 149 | throw LLVMError(.init(cString: e)) 150 | } 151 | 152 | return .init(output!, owned: true) 153 | } 154 | 155 | /// Returns the type with given `name`, or `nil` if no such type exists. 156 | public func type(named name: String) -> IRType? { 157 | LLVMGetTypeByName2(context, name).map(AnyType.init(_:)) 158 | } 159 | 160 | /// Returns the function with given `name`, or `nil` if no such function exists. 161 | public func function(named name: String) -> Function? { 162 | LLVMGetNamedFunction(llvm.raw, name).map(Function.init(_:)) 163 | } 164 | 165 | /// Returns the global with given `name`, or `nil` if no such global exists. 166 | public func global(named name: String) -> GlobalVariable? { 167 | LLVMGetNamedGlobal(llvm.raw, name).map(GlobalVariable.init(_:)) 168 | } 169 | 170 | /// Returns the intrinsic with given `name`, specialized for `parameters`, or `nil` if no such 171 | /// intrinsic exists. 172 | public mutating func intrinsic(named name: String, for parameters: [IRType] = []) -> Intrinsic? { 173 | let i = name.withCString({ LLVMLookupIntrinsicID($0, name.utf8.count) }) 174 | guard i != 0 else { return nil } 175 | 176 | let h = parameters.withHandles { (p) in 177 | LLVMGetIntrinsicDeclaration(llvm.raw, i, p.baseAddress, parameters.count) 178 | } 179 | return h.map(Intrinsic.init(_:)) 180 | } 181 | 182 | /// Returns the intrinsic with given `name`, specialized for `parameters`, or `nil` if no such 183 | /// intrinsic exists. 184 | public mutating func intrinsic( 185 | named name: Intrinsic.Name, for parameters: [IRType] = [] 186 | ) -> Intrinsic? { 187 | intrinsic(named: name.value, for: parameters) 188 | } 189 | 190 | /// Creates and returns a global variable with given `name` and `type`. 191 | /// 192 | /// A unique name is generated if `name` is empty or if `self` already contains a global with 193 | /// the same name. 194 | public mutating func addGlobalVariable( 195 | _ name: String = "", 196 | _ type: IRType, 197 | inAddressSpace s: AddressSpace = .default 198 | ) -> GlobalVariable { 199 | .init(LLVMAddGlobalInAddressSpace(llvm.raw, type.llvm.raw, name, s.llvm)) 200 | } 201 | 202 | /// Returns a global variable with given `name` and `type`, declaring it if it doesn't exist. 203 | public mutating func declareGlobalVariable( 204 | _ name: String, 205 | _ type: IRType, 206 | inAddressSpace s: AddressSpace = .default 207 | ) -> GlobalVariable { 208 | if let g = global(named: name) { 209 | precondition(g.valueType == type) 210 | return g 211 | } else { 212 | return .init(LLVMAddGlobalInAddressSpace(llvm.raw, type.llvm.raw, name, s.llvm)) 213 | } 214 | } 215 | 216 | /// Returns a function with given `name` and `type`, declaring it if it doesn't exist. 217 | public mutating func declareFunction(_ name: String, _ type: FunctionType) -> Function { 218 | if let f = function(named: name) { 219 | precondition(f.valueType == type) 220 | return f 221 | } else { 222 | return .init(LLVMAddFunction(llvm.raw, name, type.llvm.raw)) 223 | } 224 | } 225 | 226 | /// Adds attribute `a` to `f`. 227 | public mutating func addAttribute(_ a: Function.Attribute, to f: Function) { 228 | let i = UInt32(bitPattern: Int32(LLVMAttributeFunctionIndex)) 229 | LLVMAddAttributeAtIndex(f.llvm.raw, i, a.llvm) 230 | } 231 | 232 | /// Adds the attribute named `n` to `f` and returns it. 233 | @discardableResult 234 | public mutating func addAttribute( 235 | named n: Function.AttributeName, to f: Function 236 | ) -> Function.Attribute { 237 | let a = Function.Attribute(n, in: &self) 238 | addAttribute(a, to: f) 239 | return a 240 | } 241 | 242 | /// Adds attribute `a` to the return value of `f`. 243 | public mutating func addAttribute(_ a: Function.Return.Attribute, to r: Function.Return) { 244 | LLVMAddAttributeAtIndex(r.parent.llvm.raw, 0, a.llvm) 245 | } 246 | 247 | /// Adds the attribute named `n` to the return value of `f` and returns it. 248 | @discardableResult 249 | public mutating func addAttribute( 250 | named n: Function.Return.AttributeName, to r: Function.Return 251 | ) -> Function.Return.Attribute { 252 | let a = Function.Return.Attribute(n, in: &self) 253 | addAttribute(a, to: r) 254 | return a 255 | } 256 | 257 | /// Adds attribute `a` to `p`. 258 | public mutating func addAttribute(_ a: Parameter.Attribute, to p: Parameter) { 259 | let i = UInt32(p.index + 1) 260 | LLVMAddAttributeAtIndex(p.parent.llvm.raw, i, a.llvm) 261 | } 262 | 263 | /// Adds the attribute named `n` to `p` and returns it. 264 | @discardableResult 265 | public mutating func addAttribute( 266 | named n: Parameter.AttributeName, to p: Parameter 267 | ) -> Parameter.Attribute { 268 | let a = Parameter.Attribute(n, in: &self) 269 | addAttribute(a, to: p) 270 | return a 271 | } 272 | 273 | /// Removes `a` from `f`. 274 | public mutating func removeAttribute(_ a: Function.Attribute, from f: Function) { 275 | switch a { 276 | case .targetIndependent(let h): 277 | let k = LLVMGetEnumAttributeKind(h.raw) 278 | let i = UInt32(bitPattern: Int32(LLVMAttributeFunctionIndex)) 279 | LLVMRemoveEnumAttributeAtIndex(f.llvm.raw, i, k) 280 | } 281 | } 282 | 283 | /// Removes `a` from `p`. 284 | public mutating func removeAttribute(_ a: Parameter.Attribute, from p: Parameter) { 285 | switch a { 286 | case .targetIndependent(let h): 287 | let k = LLVMGetEnumAttributeKind(h.raw) 288 | let i = UInt32(p.index + 1) 289 | LLVMRemoveEnumAttributeAtIndex(p.parent.llvm.raw, i, k) 290 | } 291 | } 292 | 293 | /// Removes `a` from `r`. 294 | public mutating func removeAttribute(_ a: Function.Return.Attribute, from r: Function.Return) { 295 | switch a { 296 | case .targetIndependent(let h): 297 | let k = LLVMGetEnumAttributeKind(h.raw) 298 | LLVMRemoveEnumAttributeAtIndex(r.parent.llvm.raw, 0, k) 299 | } 300 | } 301 | 302 | /// Appends a basic block named `n` to `f` and returns it. 303 | /// 304 | /// A unique name is generated if `n` is empty or if `f` already contains a block named `n`. 305 | @discardableResult 306 | public mutating func appendBlock(named n: String = "", to f: Function) -> BasicBlock { 307 | .init(LLVMAppendBasicBlockInContext(context, f.llvm.raw, n)) 308 | } 309 | 310 | /// Returns an insertion pointing before `i`. 311 | public func before(_ i: Instruction) -> InsertionPoint { 312 | let h = LLVMCreateBuilderInContext(context)! 313 | LLVMPositionBuilderBefore(h, i.llvm.raw) 314 | return .init(h) 315 | } 316 | 317 | /// Returns an insertion point at the start of `b`. 318 | public func startOf(_ b: BasicBlock) -> InsertionPoint { 319 | if let h = LLVMGetFirstInstruction(b.llvm.raw) { 320 | return before(Instruction(h)) 321 | } else { 322 | return endOf(b) 323 | } 324 | } 325 | 326 | /// Returns an insertion point at the end of `b`. 327 | public func endOf(_ b: BasicBlock) -> InsertionPoint { 328 | let h = LLVMCreateBuilderInContext(context)! 329 | LLVMPositionBuilderAtEnd(h, b.llvm.raw) 330 | return .init(h) 331 | } 332 | 333 | /// Sets the name of `v` to `n`. 334 | public mutating func setName(_ n: String, for v: IRValue) { 335 | n.withCString({ LLVMSetValueName2(v.llvm.raw, $0, n.utf8.count) }) 336 | } 337 | 338 | /// Sets the linkage of `g` to `l`. 339 | public mutating func setLinkage(_ l: Linkage, for g: Global) { 340 | LLVMSetLinkage(g.llvm.raw, l.llvm) 341 | } 342 | 343 | /// Configures whether `g` is a global constant. 344 | public mutating func setGlobalConstant(_ newValue: Bool, for g: GlobalVariable) { 345 | LLVMSetGlobalConstant(g.llvm.raw, newValue ? 1 : 0) 346 | } 347 | 348 | /// Configures whether `g` is externally initialized. 349 | public mutating func setExternallyInitialized(_ newValue: Bool, for g: GlobalVariable) { 350 | LLVMSetExternallyInitialized(g.llvm.raw, newValue ? 1 : 0) 351 | } 352 | 353 | /// Sets the initializer of `g` to `v`. 354 | /// 355 | /// - Precondition: if `g` has type pointer-to-`T`, the `newValue` 356 | /// must have type `T`. 357 | public mutating func setInitializer(_ newValue: IRValue, for g: GlobalVariable) { 358 | LLVMSetInitializer(g.llvm.raw, newValue.llvm.raw) 359 | } 360 | 361 | /// Sets the preferred alignment of `v` to `a`. 362 | /// 363 | /// - Requires: `a` is whole power of 2. 364 | public mutating func setAlignment(_ a: Int, for v: Alloca) { 365 | LLVMSetAlignment(v.llvm.raw, UInt32(a)) 366 | } 367 | 368 | // MARK: Basic type instances 369 | 370 | /// The `void` type. 371 | public private(set) lazy var void: VoidType = .init(in: &self) 372 | 373 | /// The `ptr` type in the default address space. 374 | public private(set) lazy var ptr: PointerType = .init(inAddressSpace: .default, in: &self) 375 | 376 | /// The `half` type. 377 | public private(set) lazy var half: FloatingPointType = .half(in: &self) 378 | 379 | /// The `float` type. 380 | public private(set) lazy var float: FloatingPointType = .float(in: &self) 381 | 382 | /// The `double` type. 383 | public private(set) lazy var double: FloatingPointType = .double(in: &self) 384 | 385 | /// The `fp128` type. 386 | public private(set) lazy var fp128: FloatingPointType = .fp128(in: &self) 387 | 388 | /// The 1-bit integer type. 389 | public private(set) lazy var i1: IntegerType = .init(LLVMInt1TypeInContext(context)) 390 | 391 | /// The 8-bit integer type. 392 | public private(set) lazy var i8: IntegerType = .init(LLVMInt8TypeInContext(context)) 393 | 394 | /// The 16-bit integer type. 395 | public private(set) lazy var i16: IntegerType = .init(LLVMInt16TypeInContext(context)) 396 | 397 | /// The 32-bit integer type. 398 | public private(set) lazy var i32: IntegerType = .init(LLVMInt32TypeInContext(context)) 399 | 400 | /// The 64-bit integer type. 401 | public private(set) lazy var i64: IntegerType = .init(LLVMInt64TypeInContext(context)) 402 | 403 | /// The 128-bit integer type. 404 | public private(set) lazy var i128: IntegerType = .init(LLVMInt128TypeInContext(context)) 405 | 406 | // MARK: Arithmetics 407 | 408 | public mutating func insertAdd( 409 | overflow: OverflowBehavior = .ignore, 410 | _ lhs: IRValue, _ rhs: IRValue, 411 | at p: InsertionPoint 412 | ) -> Instruction { 413 | switch overflow { 414 | case .ignore: 415 | return .init(LLVMBuildAdd(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 416 | case .nuw: 417 | return .init(LLVMBuildNUWAdd(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 418 | case .nsw: 419 | return .init(LLVMBuildNSWAdd(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 420 | } 421 | } 422 | 423 | public mutating func insertFAdd( 424 | _ lhs: IRValue, _ rhs: IRValue, 425 | at p: InsertionPoint 426 | ) -> Instruction { 427 | .init(LLVMBuildFAdd(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 428 | } 429 | 430 | public mutating func insertSub( 431 | overflow: OverflowBehavior = .ignore, 432 | _ lhs: IRValue, _ rhs: IRValue, 433 | at p: InsertionPoint 434 | ) -> Instruction { 435 | switch overflow { 436 | case .ignore: 437 | return .init(LLVMBuildSub(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 438 | case .nuw: 439 | return .init(LLVMBuildNUWSub(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 440 | case .nsw: 441 | return .init(LLVMBuildNSWSub(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 442 | } 443 | } 444 | 445 | public mutating func insertFSub( 446 | _ lhs: IRValue, _ rhs: IRValue, 447 | at p: InsertionPoint 448 | ) -> Instruction { 449 | .init(LLVMBuildFSub(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 450 | } 451 | 452 | public mutating func insertMul( 453 | overflow: OverflowBehavior = .ignore, 454 | _ lhs: IRValue, _ rhs: IRValue, 455 | at p: InsertionPoint 456 | ) -> Instruction { 457 | switch overflow { 458 | case .ignore: 459 | return .init(LLVMBuildMul(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 460 | case .nuw: 461 | return .init(LLVMBuildNUWMul(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 462 | case .nsw: 463 | return .init(LLVMBuildNSWMul(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 464 | } 465 | } 466 | 467 | public mutating func insertFMul( 468 | _ lhs: IRValue, _ rhs: IRValue, 469 | at p: InsertionPoint 470 | ) -> Instruction { 471 | .init(LLVMBuildFMul(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 472 | } 473 | 474 | public mutating func insertUnsignedDiv( 475 | exact: Bool = false, 476 | _ lhs: IRValue, _ rhs: IRValue, 477 | at p: InsertionPoint 478 | ) -> Instruction { 479 | if exact { 480 | return .init(LLVMBuildExactUDiv(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 481 | } else { 482 | return .init(LLVMBuildUDiv(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 483 | } 484 | } 485 | 486 | public mutating func insertSignedDiv( 487 | exact: Bool = false, 488 | _ lhs: IRValue, _ rhs: IRValue, 489 | at p: InsertionPoint 490 | ) -> Instruction { 491 | if exact { 492 | return .init(LLVMBuildExactSDiv(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 493 | } else { 494 | return .init(LLVMBuildSDiv(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 495 | } 496 | } 497 | 498 | public mutating func insertFDiv( 499 | _ lhs: IRValue, _ rhs: IRValue, 500 | at p: InsertionPoint 501 | ) -> Instruction { 502 | .init(LLVMBuildFDiv(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 503 | } 504 | 505 | public mutating func insertUnsignedRem( 506 | _ lhs: IRValue, _ rhs: IRValue, 507 | at p: InsertionPoint 508 | ) -> Instruction { 509 | .init(LLVMBuildURem(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 510 | } 511 | 512 | public mutating func insertSignedRem( 513 | _ lhs: IRValue, _ rhs: IRValue, 514 | at p: InsertionPoint 515 | ) -> Instruction { 516 | .init(LLVMBuildSRem(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 517 | } 518 | 519 | public mutating func insertFRem( 520 | _ lhs: IRValue, _ rhs: IRValue, 521 | at p: InsertionPoint 522 | ) -> Instruction { 523 | .init(LLVMBuildFRem(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 524 | } 525 | 526 | public mutating func insertShl( 527 | _ lhs: IRValue, _ rhs: IRValue, 528 | at p: InsertionPoint 529 | ) -> Instruction { 530 | .init(LLVMBuildShl(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 531 | } 532 | 533 | public mutating func insertLShr( 534 | _ lhs: IRValue, _ rhs: IRValue, 535 | at p: InsertionPoint 536 | ) -> Instruction { 537 | .init(LLVMBuildLShr(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 538 | } 539 | 540 | public mutating func insertAShr( 541 | _ lhs: IRValue, _ rhs: IRValue, 542 | at p: InsertionPoint 543 | ) -> Instruction { 544 | .init(LLVMBuildAShr(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 545 | } 546 | 547 | public mutating func insertBitwiseAnd( 548 | _ lhs: IRValue, _ rhs: IRValue, 549 | at p: InsertionPoint 550 | ) -> Instruction { 551 | .init(LLVMBuildAnd(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 552 | } 553 | 554 | public mutating func insertBitwiseOr( 555 | _ lhs: IRValue, _ rhs: IRValue, 556 | at p: InsertionPoint 557 | ) -> Instruction { 558 | .init(LLVMBuildOr(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 559 | } 560 | 561 | public mutating func insertBitwiseXor( 562 | _ lhs: IRValue, _ rhs: IRValue, 563 | at p: InsertionPoint 564 | ) -> Instruction { 565 | .init(LLVMBuildXor(p.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 566 | } 567 | 568 | // MARK: Memory 569 | 570 | public mutating func insertAlloca(_ type: IRType, at p: InsertionPoint) -> Alloca { 571 | .init(LLVMBuildAlloca(p.llvm, type.llvm.raw, "")) 572 | } 573 | 574 | /// Inerts an `alloca` allocating memory on the stack a value of `type`, at the entry of `f`. 575 | /// 576 | /// - Requires: `f` has an entry block. 577 | public mutating func insertAlloca(_ type: IRType, atEntryOf f: Function) -> Alloca { 578 | insertAlloca(type, at: startOf(f.entry!)) 579 | } 580 | 581 | public mutating func insertGetElementPointer( 582 | of base: IRValue, 583 | typed baseType: IRType, 584 | indices: [IRValue], 585 | at p: InsertionPoint 586 | ) -> Instruction { 587 | var i = indices.map({ $0.llvm.raw as Optional }) 588 | let h = LLVMBuildGEP2(p.llvm, baseType.llvm.raw, base.llvm.raw, &i, UInt32(i.count), "")! 589 | return .init(h) 590 | } 591 | 592 | public mutating func insertGetElementPointerInBounds( 593 | of base: IRValue, 594 | typed baseType: IRType, 595 | indices: [IRValue], 596 | at p: InsertionPoint 597 | ) -> Instruction { 598 | var i = indices.map({ $0.llvm.raw as Optional }) 599 | let h = LLVMBuildInBoundsGEP2(p.llvm, baseType.llvm.raw, base.llvm.raw, &i, UInt32(i.count), "")! 600 | return .init(h) 601 | } 602 | 603 | public mutating func insertGetStructElementPointer( 604 | of base: IRValue, 605 | typed baseType: StructType, 606 | index: Int, 607 | at p: InsertionPoint 608 | ) -> Instruction { 609 | .init(LLVMBuildStructGEP2(p.llvm, baseType.llvm.raw, base.llvm.raw, UInt32(index), "")) 610 | } 611 | 612 | public mutating func insertLoad( 613 | _ type: IRType, from source: IRValue, at p: InsertionPoint 614 | ) -> Instruction { 615 | .init(LLVMBuildLoad2(p.llvm, type.llvm.raw, source.llvm.raw, "")) 616 | } 617 | 618 | @discardableResult 619 | public mutating func insertStore( 620 | _ value: IRValue, to location: IRValue, at p: InsertionPoint 621 | ) -> Instruction { 622 | let r = LLVMBuildStore(p.llvm, value.llvm.raw, location.llvm.raw) 623 | LLVMSetAlignment(r, UInt32(layout.preferredAlignment(of: value.type))) 624 | return .init(r!) 625 | } 626 | 627 | // MARK: Atomics 628 | 629 | public mutating func setOrdering(_ ordering: AtomicOrdering, for i: Instruction) { 630 | LLVMSetOrdering(i.llvm.raw, ordering.llvm) 631 | } 632 | 633 | public mutating func setCmpXchgSuccessOrdering(_ ordering: AtomicOrdering, for i: Instruction) { 634 | LLVMSetCmpXchgSuccessOrdering(i.llvm.raw, ordering.llvm) 635 | } 636 | 637 | public mutating func setCmpXchgFailureOrdering(_ ordering: AtomicOrdering, for i: Instruction) { 638 | LLVMSetCmpXchgFailureOrdering(i.llvm.raw, ordering.llvm) 639 | } 640 | 641 | public mutating func setAtomicRMWBinOp(_ binOp: AtomicRMWBinOp, for i: Instruction) { 642 | LLVMSetAtomicRMWBinOp(i.llvm.raw, binOp.llvm) 643 | } 644 | 645 | public mutating func setAtomicSingleThread(for i: Instruction) { 646 | LLVMSetAtomicSingleThread(i.llvm.raw, 1) 647 | } 648 | 649 | public mutating func insertAtomicCmpXchg( 650 | _ atomic: IRValue, 651 | old: IRValue, 652 | new: IRValue, 653 | successOrdering: AtomicOrdering, 654 | failureOrdering: AtomicOrdering, 655 | weak: Bool, 656 | singleThread: Bool, 657 | at p: InsertionPoint 658 | ) -> Instruction { 659 | let i = Instruction(LLVMBuildAtomicCmpXchg(p.llvm, atomic.llvm.raw, old.llvm.raw, new.llvm.raw, successOrdering.llvm, failureOrdering.llvm, singleThread ? 1 : 0)) 660 | if weak { 661 | LLVMSetWeak(i.llvm.raw, 1) 662 | } 663 | return i 664 | } 665 | 666 | public mutating func insertAtomicRMW( 667 | _ atomic: IRValue, 668 | operation: AtomicRMWBinOp, 669 | value: IRValue, 670 | ordering: AtomicOrdering, 671 | singleThread: Bool, 672 | at p: InsertionPoint 673 | ) -> Instruction { 674 | .init(LLVMBuildAtomicRMW(p.llvm, operation.llvm, atomic.llvm.raw, value.llvm.raw, ordering.llvm, singleThread ? 1 : 0)) 675 | } 676 | 677 | @discardableResult 678 | public mutating func insertFence(_ ordering: AtomicOrdering, singleThread: Bool, at p: InsertionPoint) -> Instruction { 679 | .init(LLVMBuildFence(p.llvm, ordering.llvm, singleThread ? 1 : 0, "")) 680 | } 681 | 682 | // MARK: Terminators 683 | 684 | @discardableResult 685 | public mutating func insertBr(to destination: BasicBlock, at p: InsertionPoint) -> Instruction { 686 | .init(LLVMBuildBr(p.llvm, destination.llvm.raw)) 687 | } 688 | 689 | @discardableResult 690 | public mutating func insertCondBr( 691 | if condition: IRValue, then t: BasicBlock, else e: BasicBlock, 692 | at p: InsertionPoint 693 | ) -> Instruction { 694 | .init(LLVMBuildCondBr(p.llvm, condition.llvm.raw, t.llvm.raw, e.llvm.raw)) 695 | } 696 | 697 | @discardableResult 698 | public mutating func insertSwitch>( 699 | on value: IRValue, cases: C, default defaultCase: BasicBlock, at p: InsertionPoint 700 | ) -> Instruction { 701 | let s = LLVMBuildSwitch(p.llvm, value.llvm.raw, defaultCase.llvm.raw, UInt32(cases.count)) 702 | for (value, destination) in cases { 703 | LLVMAddCase(s, value.llvm.raw, destination.llvm.raw) 704 | } 705 | return .init(s!) 706 | } 707 | 708 | @discardableResult 709 | public mutating func insertReturn(at p: InsertionPoint) -> Instruction { 710 | .init(LLVMBuildRetVoid(p.llvm)) 711 | } 712 | 713 | @discardableResult 714 | public mutating func insertReturn(_ value: IRValue, at p: InsertionPoint) -> Instruction { 715 | .init(LLVMBuildRet(p.llvm, value.llvm.raw)) 716 | } 717 | 718 | @discardableResult 719 | public mutating func insertUnreachable(at p: InsertionPoint) -> Instruction { 720 | .init(LLVMBuildUnreachable(p.llvm)) 721 | } 722 | 723 | // MARK: Aggregate operations 724 | 725 | public mutating func insertExtractValue( 726 | from whole: IRValue, 727 | at index: Int, 728 | at p: InsertionPoint 729 | ) -> Instruction { 730 | .init(LLVMBuildExtractValue(p.llvm, whole.llvm.raw, UInt32(index), "")) 731 | } 732 | 733 | public mutating func insertInsertValue( 734 | _ part: IRValue, 735 | at index: Int, 736 | into whole: IRValue, 737 | at p: InsertionPoint 738 | ) -> Instruction { 739 | .init(LLVMBuildInsertValue(p.llvm, whole.llvm.raw, part.llvm.raw, UInt32(index), "")) 740 | } 741 | 742 | // MARK: Conversions 743 | 744 | public mutating func insertTrunc( 745 | _ source: IRValue, to target: IRType, 746 | at p: InsertionPoint 747 | ) -> Instruction { 748 | .init(LLVMBuildTrunc(p.llvm, source.llvm.raw, target.llvm.raw, "")) 749 | } 750 | 751 | public mutating func insertSignExtend( 752 | _ source: IRValue, to target: IRType, 753 | at p: InsertionPoint 754 | ) -> Instruction { 755 | .init(LLVMBuildSExt(p.llvm, source.llvm.raw, target.llvm.raw, "")) 756 | } 757 | 758 | public mutating func insertZeroExtend( 759 | _ source: IRValue, to target: IRType, 760 | at p: InsertionPoint 761 | ) -> Instruction { 762 | .init(LLVMBuildZExt(p.llvm, source.llvm.raw, target.llvm.raw, "")) 763 | } 764 | 765 | public mutating func insertIntToPtr( 766 | _ source: IRValue, to target: IRType? = nil, 767 | at p: InsertionPoint 768 | ) -> Instruction { 769 | let t = target ?? PointerType(in: &self) 770 | return .init(LLVMBuildIntToPtr(p.llvm, source.llvm.raw, t.llvm.raw, "")) 771 | } 772 | 773 | public func insertPtrToInt( 774 | _ source: IRValue, to target: IRType, 775 | at p: InsertionPoint 776 | ) -> Instruction { 777 | .init(LLVMBuildPtrToInt(p.llvm, source.llvm.raw, target.llvm.raw, "")) 778 | } 779 | 780 | public mutating func insertFPTrunc( 781 | _ source: IRValue, to target: IRType, 782 | at p: InsertionPoint 783 | ) -> Instruction { 784 | .init(LLVMBuildFPTrunc(p.llvm, source.llvm.raw, target.llvm.raw, "")) 785 | } 786 | 787 | public mutating func insertFPExtend( 788 | _ source: IRValue, to target: IRType, 789 | at p: InsertionPoint 790 | ) -> Instruction { 791 | .init(LLVMBuildFPExt(p.llvm, source.llvm.raw, target.llvm.raw, "")) 792 | } 793 | 794 | // MARK: Others 795 | 796 | public mutating func insertCall( 797 | _ callee: Function, 798 | on arguments: [IRValue], 799 | at p: InsertionPoint 800 | ) -> Instruction { 801 | insertCall(callee, typed: callee.valueType, on: arguments, at: p) 802 | } 803 | 804 | public mutating func insertCall( 805 | _ callee: IRValue, 806 | typed calleeType: IRType, 807 | on arguments: [IRValue], 808 | at p: InsertionPoint 809 | ) -> Instruction { 810 | var a = arguments.map({ $0.llvm.raw as Optional }) 811 | return .init(LLVMBuildCall2(p.llvm, calleeType.llvm.raw, callee.llvm.raw, &a, UInt32(a.count), "")) 812 | } 813 | 814 | public mutating func insertIntegerComparison( 815 | _ predicate: IntegerPredicate, 816 | _ lhs: IRValue, _ rhs: IRValue, 817 | at p: InsertionPoint 818 | ) -> Instruction { 819 | precondition(lhs.type == rhs.type) 820 | return .init(LLVMBuildICmp(p.llvm, predicate.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 821 | } 822 | 823 | public mutating func insertFloatingPointComparison( 824 | _ predicate: FloatingPointPredicate, 825 | _ lhs: IRValue, _ rhs: IRValue, 826 | at p: InsertionPoint 827 | ) -> Instruction { 828 | precondition(lhs.type == rhs.type) 829 | return .init(LLVMBuildFCmp(p.llvm, predicate.llvm, lhs.llvm.raw, rhs.llvm.raw, "")) 830 | } 831 | 832 | } 833 | 834 | extension Module: CustomStringConvertible { 835 | 836 | public var description: String { 837 | guard let s = LLVMPrintModuleToString(llvm.raw) else { return "" } 838 | defer { LLVMDisposeMessage(s) } 839 | return String(cString: s) 840 | } 841 | 842 | } 843 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/OptimizationLevel.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// The level of optimization used during code generation. 4 | public enum OptimitzationLevel: Hashable { 5 | 6 | /// No optimization (a.k.a. `O0`). 7 | case none 8 | 9 | /// Moderate optimization (a.k.a. `O1`). 10 | case less 11 | 12 | /// Full optimization (a.k.a. `O2`). 13 | case `default` 14 | 15 | /// Full optimization with aggressive inlining and vectorization (a.k.a. `O3`). 16 | case aggressive 17 | 18 | /// The LLVM representation of this instance for code generation. 19 | internal var codegen: LLVMCodeGenOptLevel { 20 | switch self { 21 | case .none: 22 | return LLVMCodeGenLevelNone 23 | case .less: 24 | return LLVMCodeGenLevelLess 25 | case .default: 26 | return LLVMCodeGenLevelDefault 27 | case .aggressive: 28 | return LLVMCodeGenLevelAggressive 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Refs.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | import Foundation 3 | 4 | /// An LLVM type reference. 5 | public struct TypeRef: Hashable { 6 | 7 | /// The underlying LLVM value. 8 | let raw: llvmc.LLVMTypeRef 9 | 10 | /// An instance whose underlying value is `raw`. 11 | init(_ raw: llvmc.LLVMTypeRef) { self.raw = raw } 12 | 13 | } 14 | 15 | /// An LLVM value reference. 16 | public struct ValueRef: Hashable { 17 | 18 | /// The underlying LLVM value; not exposed to avoid rexporting llvmc 19 | let raw: llvmc.LLVMValueRef 20 | 21 | /// An instance whose underlying value is `raw`. 22 | init(_ raw: llvmc.LLVMValueRef) { self.raw = raw } 23 | 24 | } 25 | 26 | /// An LLVM basic block reference. 27 | public struct BasicBlockRef: Hashable { 28 | 29 | /// The underlying LLVM value; not exposed to avoid rexporting llvmc 30 | let raw: llvmc.LLVMBasicBlockRef 31 | 32 | /// An instance whose underlying value is `raw`. 33 | init(_ raw: llvmc.LLVMBasicBlockRef) { self.raw = raw } 34 | 35 | } 36 | 37 | /// An LLVM module reference. 38 | public struct ModuleRef: Hashable { 39 | 40 | /// The underlying LLVM value; not exposed to avoid rexporting llvmc 41 | let raw: llvmc.LLVMModuleRef 42 | 43 | /// An instance whose underlying value is `raw`. 44 | init(_ raw: llvmc.LLVMModuleRef) { self.raw = raw } 45 | 46 | } 47 | 48 | /// An LLVM attribute reference. 49 | public struct AttributeRef: Hashable { 50 | 51 | /// The underlying LLVM value; not exposed to avoid rexporting llvmc 52 | let raw: llvmc.LLVMAttributeRef 53 | 54 | /// An instance whose underlying value is `raw`. 55 | init(_ raw: llvmc.LLVMAttributeRef) { self.raw = raw } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/RelocationModel.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// The settings of position-independent code (PIC) during code generation. 4 | public enum RelocationModel: Hashable { 5 | 6 | /// The model default to the target for which code is being generated. 7 | case `default` 8 | 9 | /// Non-relocatable code, machine instructions may use absolute addressing modes. 10 | case `static` 11 | 12 | /// Fully relocatable position independent code; machine instructions need to use relative 13 | /// addressing modes. 14 | case pic 15 | 16 | /// The LLVM representation of this instance. 17 | internal var llvm: LLVMRelocMode { 18 | switch self { 19 | case .default: 20 | return LLVMRelocDefault 21 | case .static: 22 | return LLVMRelocStatic 23 | case .pic: 24 | return LLVMRelocPIC 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Target.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// The specification of a platform on which code runs. 4 | public struct Target { 5 | 6 | /// The triple of the target. 7 | /// 8 | /// A triple is a string taking the form `---` where: 9 | /// * `arch` = `x86_64`, `i386`, `arm`, `thumb`, `mips`, etc. 10 | /// * `sub` = `v5`, `v6m`, `v7a`, `v7m`, etc. 11 | /// * `vendor` = `pc`, `apple`, `nvidia`, `ibm`, etc. 12 | /// * `sys` = `none`, `linux`, `win32`, `darwin`, `cuda`, etc. 13 | /// * `env` = `eabi`, `gnu`, `android`, `macho`, `elf`, etc. 14 | /// 15 | /// For example, `arm64-apple-darwin22.3.0`. 16 | /// 17 | /// - SeeAlso: https://clang.llvm.org/docs/CrossCompilation.html. 18 | public let triple: String 19 | 20 | /// A handle to the LLVM object wrapped by this instance. 21 | internal let llvm: LLVMTargetRef 22 | 23 | /// Creates an instance wrapping `llvm`, which represents the target associated with `triple`. 24 | private init(wrapping llvm: LLVMTargetRef, for triple: String) { 25 | self.triple = triple 26 | self.llvm = llvm 27 | } 28 | 29 | /// Creates an instance from a triple. 30 | public init(triple: String) throws { 31 | var handle: LLVMTargetRef? = nil 32 | var error: UnsafeMutablePointer? = nil 33 | LLVMGetTargetFromTriple(triple, &handle, &error) 34 | 35 | if let e = error { 36 | defer { LLVMDisposeMessage(e) } 37 | throw LLVMError(.init(cString: e)) 38 | } 39 | 40 | self.init(wrapping: handle!, for: triple) 41 | } 42 | 43 | /// Creates an instance representing the target associated with `machine`. 44 | public init(of machine: TargetMachine) { 45 | let h = LLVMGetTargetMachineTarget(machine.llvm) 46 | self.init(wrapping: h!, for: machine.triple) 47 | } 48 | 49 | /// The name of the target. 50 | public var name: String { 51 | guard let s = LLVMGetTargetName(llvm) else { return "" } 52 | return .init(cString: s) 53 | } 54 | 55 | 56 | /// `true` if the target has a JIT. 57 | public var hasJIT: Bool { 58 | LLVMTargetHasJIT(llvm) != 0 59 | } 60 | 61 | /// `true` if the target has an assembly back-end. 62 | public var hasAssemblyBackEnd: Bool { 63 | LLVMTargetHasAsmBackend(llvm) != 0 64 | } 65 | 66 | /// Returns the target representing the machine host. 67 | public static func host() throws -> Target { 68 | // Ensures LLVM targets are initialized. 69 | _ = initializeHost 70 | 71 | let triple = LLVMGetDefaultTargetTriple() 72 | if let t = triple { 73 | defer { LLVMDisposeMessage(t) } 74 | return try .init(triple: .init(cString: t)) 75 | } else { 76 | return try .init(triple: "") 77 | } 78 | } 79 | 80 | /// The initialization of the native target. 81 | private static let initializeHost: Void = { 82 | LLVMInitializeNativeAsmParser() 83 | LLVMInitializeNativeAsmPrinter() 84 | LLVMInitializeNativeDisassembler() 85 | LLVMInitializeNativeTarget() 86 | }() 87 | 88 | } 89 | 90 | extension Target: Hashable { 91 | 92 | public func hash(into hasher: inout Hasher) { 93 | hasher.combine(llvm) 94 | } 95 | 96 | public static func == (lhs: Self, rhs: Self) -> Bool { 97 | lhs.llvm == rhs.llvm 98 | } 99 | 100 | } 101 | 102 | extension Target: CustomStringConvertible { 103 | 104 | public var description: String { 105 | .init(cString: LLVMGetTargetDescription(llvm)) 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/TargetMachine.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// The settings necessary for code generation, including target information and compiler options. 4 | public struct TargetMachine { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | private let wrapped: ManagedPointer 8 | 9 | /// Creates an instance with given properties. 10 | /// 11 | /// - Parameters: 12 | /// - target: The platform for which code is generated. 13 | /// - cpu: The type of CPU to target. Defaults to the CPU of the host machine. 14 | /// - features: The features a of the target. 15 | /// - optimization: The level of optimization used during code generation. Defaults to `.none`. 16 | /// - relocation: The relocation model used during code generation. Defaults to `.default`. 17 | /// - code: The code model used during code generation. Defaults to `.default`. 18 | public init( 19 | for target: Target, 20 | cpu: String = "", 21 | features: String = "", 22 | optimization: OptimitzationLevel = .none, 23 | relocation: RelocationModel = .default, 24 | code: CodeModel = .default 25 | ) { 26 | let handle = LLVMCreateTargetMachine( 27 | target.llvm, target.triple, cpu, features, optimization.codegen, relocation.llvm, code.llvm) 28 | self.wrapped = .init(handle!, dispose: LLVMDisposeTargetMachine(_:)) 29 | } 30 | 31 | /// The triple of the machine. 32 | public var triple: String { 33 | guard let s = LLVMGetTargetMachineTriple(llvm) else { return "" } 34 | defer { LLVMDisposeMessage(s) } 35 | return .init(cString: s) 36 | } 37 | 38 | /// The CPU of the machine. 39 | public var cpu: String { 40 | guard let s = LLVMGetTargetMachineCPU(llvm) else { return "" } 41 | defer { LLVMDisposeMessage(s) } 42 | return .init(cString: s) 43 | } 44 | 45 | /// The features of the machine. 46 | public var features: String { 47 | guard let s = LLVMGetTargetMachineFeatureString(llvm) else { return "" } 48 | defer { LLVMDisposeMessage(s) } 49 | return .init(cString: s) 50 | } 51 | 52 | /// The target associated with the machine. 53 | public var target: Target { 54 | .init(of: self) 55 | } 56 | 57 | /// The data layout of the machine. 58 | public var layout: DataLayout { 59 | .init(of: self) 60 | } 61 | 62 | /// A handle to the LLVM object wrapped by this instance. 63 | internal var llvm: LLVMTargetMachineRef { wrapped.llvm } 64 | 65 | } 66 | 67 | extension TargetMachine: CustomStringConvertible { 68 | 69 | public var description: String { triple } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Types/AnyType.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// The type of a value in LLVM IR. 4 | internal struct AnyType: IRType, Hashable { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | public let llvm: TypeRef 8 | 9 | /// Creates an instance wrapping `llvm`. 10 | internal init(_ llvm: LLVMTypeRef) { 11 | self.llvm = .init(llvm) 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Types/ArrayType.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// An array type in LLVM IR. 4 | public struct ArrayType: IRType, Hashable { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | public let llvm: TypeRef 8 | 9 | /// Creates an instance representing arrays of `count` `element`s in `module`. 10 | public init(_ count: Int, _ element: IRType, in module: inout Module) { 11 | precondition(LLVMGetTypeContext(element.llvm.raw) == module.context) 12 | self.llvm = .init(LLVMArrayType(element.llvm.raw, UInt32(count))) 13 | } 14 | 15 | /// Creates an instance with `t`, failing iff `t` isn't a void type. 16 | public init?(_ t: IRType) { 17 | if LLVMGetTypeKind(t.llvm.raw) == LLVMArrayTypeKind { 18 | self.llvm = t.llvm 19 | } else { 20 | return nil 21 | } 22 | } 23 | 24 | /// The type of an element in instances of this type. 25 | public var element: IRType { AnyType(LLVMGetElementType(llvm.raw)) } 26 | 27 | /// The number of elements in instances of this type. 28 | public var count: Int { Int(LLVMGetArrayLength(llvm.raw)) } 29 | 30 | /// Returns a constant whose LLVM IR type is `self` and whose value is aggregating `elements`. 31 | public func constant( 32 | contentsOf elements: S, in module: inout Module 33 | ) -> ArrayConstant where S.Element == IRValue { 34 | .init(of: self, containing: elements, in: &module) 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Types/FloatingPointType.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// A floating-point type in LLVM IR. 4 | public struct FloatingPointType: IRType, Hashable { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | public let llvm: TypeRef 8 | 9 | /// Creates an instance wrapping `llvm`. 10 | private init(_ llvm: LLVMTypeRef) { 11 | self.llvm = .init(llvm) 12 | } 13 | 14 | /// Creates an instance with `t`, failing iff `t` isn't a floating point type. 15 | public init?(_ t: IRType) { 16 | switch LLVMGetTypeKind(t.llvm.raw) { 17 | case LLVMHalfTypeKind, LLVMFloatTypeKind, LLVMDoubleTypeKind, LLVMFP128TypeKind: 18 | self.llvm = t.llvm 19 | default: 20 | return nil 21 | } 22 | } 23 | 24 | /// Returns the type `half` in `module` 25 | public static func half(in module: inout Module) -> Self { 26 | .init(LLVMHalfTypeInContext(module.context)) 27 | } 28 | 29 | /// Returns the type `float` in `module`. 30 | public static func float(in module: inout Module) -> Self { 31 | .init(LLVMFloatTypeInContext(module.context)) 32 | } 33 | 34 | /// Returns the type `double` in `module` 35 | public static func double(in module: inout Module) -> Self { 36 | .init(LLVMDoubleTypeInContext(module.context)) 37 | } 38 | 39 | /// Returns the type `fp128` in `module` 40 | public static func fp128(in module: inout Module) -> Self { 41 | .init(LLVMFP128TypeInContext(module.context)) 42 | } 43 | 44 | /// Returns a constant whose LLVM IR type is `self` and whose value is `v`. 45 | public func callAsFunction(_ v: Double) -> FloatingPointConstant { 46 | constant(v) 47 | } 48 | 49 | /// Returns a constant whose LLVM IR type is `self` and whose value is `v`. 50 | public func constant(_ v: Double) -> FloatingPointConstant { 51 | .init(LLVMConstReal(llvm.raw, v)) 52 | } 53 | 54 | /// Returns a constant whose LLVM IR type is `self` and whose value is parsed from `text`. 55 | /// 56 | /// Zero is returned if `text` is not a valid floating-point value. 57 | public func constant(parsing text: String) -> FloatingPointConstant { 58 | .init(text.withCString({ LLVMConstRealOfStringAndSize(llvm.raw, $0, UInt32(text.utf8.count)) })) 59 | } 60 | 61 | /// The zero value of this type. 62 | public var zero: FloatingPointConstant { 63 | .init(LLVMConstNull(llvm.raw)) 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Types/FunctionType.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// A function type in LLVM IR. 4 | public struct FunctionType: IRType, Hashable { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | public let llvm: TypeRef 8 | 9 | /// Creates an instance with given `parameters` and `returnType` in `module`. 10 | /// 11 | /// The return type is `void` if `returnType` is passed `nil`. 12 | public init(from parameters: [IRType], to returnType: IRType? = nil, in module: inout Module) { 13 | let r = returnType ?? VoidType(in: &module) 14 | self.llvm = parameters.withHandles { (p) in 15 | .init(LLVMFunctionType(r.llvm.raw, p.baseAddress, UInt32(p.count), 0)) 16 | } 17 | } 18 | 19 | /// Creates an instance with `t`, failing iff `t` isn't a function type. 20 | public init?(_ t: IRType) { 21 | if LLVMGetTypeKind(t.llvm.raw) == LLVMFunctionTypeKind { 22 | self.llvm = t.llvm 23 | } else { 24 | return nil 25 | } 26 | } 27 | 28 | /// The return type of the function. 29 | public var returnType: IRType { AnyType(LLVMGetReturnType(llvm.raw)) } 30 | 31 | /// The parameters of the function. 32 | public var parameters: [IRType] { 33 | let n = LLVMCountParamTypes(llvm.raw) 34 | var handles: [LLVMAttributeRef?] = .init(repeating: nil, count: Int(n)) 35 | LLVMGetParamTypes(llvm.raw, &handles) 36 | return handles.map({ AnyType($0!) as IRType }) 37 | } 38 | 39 | } 40 | 41 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Types/IRType.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// The type of a value in LLVM IR. 4 | public protocol IRType: CustomStringConvertible { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | var llvm: TypeRef { get } 8 | 9 | } 10 | 11 | extension IRType { 12 | 13 | /// A string representation of the type. 14 | public var description: String { 15 | guard let s = LLVMPrintTypeToString(llvm.raw) else { return "" } 16 | defer { LLVMDisposeMessage(s) } 17 | return String(cString: s) 18 | } 19 | 20 | /// `true` if the size of the type is known. 21 | public var isSized: Bool { LLVMTypeIsSized(llvm.raw) != 0 } 22 | 23 | /// The `null` instance of this type (e.g., the zero of `i32`). 24 | public var null: IRValue { AnyValue(LLVMConstNull(llvm.raw)) } 25 | 26 | /// Returns `true` iff `lhs` is equal to `rhs`. 27 | public static func == (lhs: Self, rhs: R) -> Bool { 28 | lhs.llvm == rhs.llvm 29 | } 30 | 31 | /// Returns `true` iff `lhs` is equal to `rhs`. 32 | public static func == (lhs: IRType, rhs: Self) -> Bool { 33 | lhs.llvm == rhs.llvm 34 | } 35 | 36 | /// Returns `true` iff `lhs` is equal to `rhs`. 37 | public static func == (lhs: Self, rhs: IRType) -> Bool { 38 | lhs.llvm == rhs.llvm 39 | } 40 | 41 | /// Returns `true` iff `lhs` is not equal to `rhs`. 42 | public static func != (lhs: IRType, rhs: Self) -> Bool { 43 | lhs.llvm != rhs.llvm 44 | } 45 | 46 | /// Returns `true` iff `lhs` is not equal to `rhs`. 47 | public static func != (lhs: Self, rhs: IRType) -> Bool { 48 | lhs.llvm != rhs.llvm 49 | } 50 | 51 | } 52 | 53 | /// Returns `true` iff `lhs` is equal to `rhs`. 54 | public func == (lhs: IRType, rhs: IRType) -> Bool { 55 | lhs.llvm == rhs.llvm 56 | } 57 | 58 | /// Returns `true` iff `lhs` is not equal to `rhs`. 59 | public func != (lhs: IRType, rhs: IRType) -> Bool { 60 | lhs.llvm != rhs.llvm 61 | } 62 | 63 | extension Array where Element == IRType { 64 | 65 | func withHandles(_ action: (UnsafeMutableBufferPointer) -> T) -> T { 66 | let p = UnsafeMutablePointer.allocate(capacity: count) 67 | defer { p.deallocate() } 68 | for (i, t) in enumerated() { 69 | p.advanced(by: i).initialize(to: t.llvm.raw) 70 | } 71 | return action(.init(start: p, count: count)) 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Types/IntegerType.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// An integer type in LLVM IR. 4 | public struct IntegerType: IRType, Hashable { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | public let llvm: TypeRef 8 | 9 | /// Creates an instance with given `bitWidth` in `module`. 10 | /// 11 | /// - Requires: `bitWidth` is greater than 0. 12 | public init(_ bitWidth: Int, in module: inout Module) { 13 | self.llvm = .init(LLVMIntTypeInContext(module.context, UInt32(bitWidth))) 14 | } 15 | 16 | /// Creates an instance with `t`, failing iff `t` isn't an integer type. 17 | public init?(_ t: IRType) { 18 | guard LLVMGetTypeKind(t.llvm.raw) == LLVMIntegerTypeKind else { return nil } 19 | self.llvm = t.llvm 20 | } 21 | 22 | /// Creates an instance wrapping `llvm`. 23 | internal init(_ llvm: LLVMTypeRef) { 24 | self.llvm = .init(llvm) 25 | } 26 | 27 | /// The number of bits in the representation of the type's instances. 28 | public var bitWidth: Int { Int(LLVMGetIntTypeWidth(llvm.raw)) } 29 | 30 | /// Returns a constant whose LLVM IR type is `self` and whose value is `v`, truncating or 31 | /// sign-extending if needed to fit `self.bitWidth`. 32 | /// 33 | /// - Requires: `v` must be representable in `self.` 34 | public func callAsFunction(_ v: Int) -> IntegerConstant { 35 | constant(v) 36 | } 37 | 38 | /// Returns a constant whose LLVM IR type is `self` and whose value is `v`, truncating or 39 | /// sign-extending if needed to fit `self.bitWidth`. 40 | public func constant(_ v: T) -> SwiftyLLVM.IntegerConstant { 41 | .init(LLVMConstInt(llvm.raw, UInt64(truncatingIfNeeded: v), 0)) 42 | } 43 | 44 | /// Returns a constant whose LLVM IR type is `self` and whose value is parsed from `text` with 45 | /// given `radix`. 46 | /// 47 | /// Zero is returned if `text` is not a valid integer value. 48 | /// 49 | /// - Requires: `radix` must be in the range `2...36`. 50 | public func constant(parsing text: String, radix: Int = 10) -> IntegerConstant { 51 | let h = text.withCString { (s) in 52 | LLVMConstIntOfStringAndSize(llvm.raw, s, UInt32(text.utf8.count), UInt8(radix))! 53 | } 54 | return .init(h) 55 | } 56 | 57 | /// Returns a constant whose LLVM IR type is `self` and whose value's binary presentation is 58 | /// `words`, from least to most significant. 59 | public func constant>(words: Words) -> IntegerConstant { 60 | let w = Array(words) 61 | return .init(LLVMConstIntOfArbitraryPrecision(llvm.raw, UInt32(w.count), w)) 62 | } 63 | 64 | /// The zero value of this type. 65 | public var zero: IntegerConstant { 66 | .init(LLVMConstNull(llvm.raw)) 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Types/PointerType.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// An pointer type in LLVM IR. 4 | public struct PointerType: IRType, Hashable { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | public let llvm: TypeRef 8 | 9 | /// Creates an instance wrapping `llvm`. 10 | private init(_ llvm: LLVMTypeRef) { 11 | self.llvm = .init(llvm) 12 | } 13 | 14 | /// Creates an instance with `t`, failing iff `t` isn't a pointer type. 15 | public init?(_ t: IRType) { 16 | if LLVMGetTypeKind(t.llvm.raw) == LLVMPointerTypeKind { 17 | self.llvm = t.llvm 18 | } else { 19 | return nil 20 | } 21 | } 22 | 23 | /// Creates an opaque pointer type in address space `s` in `module`. 24 | public init(inAddressSpace s: AddressSpace = .default, in module: inout Module) { 25 | self.init(LLVMPointerTypeInContext(module.context, s.llvm)) 26 | } 27 | 28 | /// The address space of the pointer. 29 | public var addressSpace: AddressSpace { .init(LLVMGetPointerAddressSpace(llvm.raw)) } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Types/StructType.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// A struct type in LLVM IR. 4 | public struct StructType: IRType, Hashable { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | public let llvm: TypeRef 8 | 9 | /// Creates an instance with given `fields` in `module`, packed iff `packed` is `true`. 10 | public init(_ fields: [IRType], packed: Bool = false, in module: inout Module) { 11 | self.llvm = fields.withHandles { (f) in 12 | .init(LLVMStructTypeInContext(module.context, f.baseAddress, UInt32(f.count), packed ? 1 : 0)) 13 | } 14 | } 15 | 16 | /// Creates a struct with given `name` and `fields` in `module`, packed iff `packed` is `true`. 17 | /// 18 | /// A unique name is generated if `name` is empty or if `module` already contains a struct with 19 | /// the same name. 20 | public init( 21 | named name: String, _ fields: [IRType], packed: Bool = false, in module: inout Module 22 | ) { 23 | self.llvm = .init(LLVMStructCreateNamed(module.context, name)) 24 | fields.withHandles { (f) in 25 | LLVMStructSetBody(self.llvm.raw, f.baseAddress, UInt32(f.count), packed ? 1 : 0) 26 | } 27 | } 28 | 29 | /// Creates an instance with `t`, failing iff `t` isn't a struct type. 30 | public init?(_ t: IRType) { 31 | if LLVMGetTypeKind(t.llvm.raw) == LLVMStructTypeKind { 32 | self.llvm = t.llvm 33 | } else { 34 | return nil 35 | } 36 | } 37 | 38 | /// The name of the struct. 39 | public var name: String? { 40 | guard let s = LLVMGetStructName(llvm.raw) else { return nil } 41 | return String(cString: s) 42 | } 43 | 44 | /// `true` iff the fields of the struct are packed. 45 | public var isPacked: Bool { LLVMIsPackedStruct(llvm.raw) != 0 } 46 | 47 | /// `true` iff the struct is opaque. 48 | public var isOpaque: Bool { LLVMIsOpaqueStruct(llvm.raw) != 0 } 49 | 50 | /// `true` iff the struct is literal. 51 | public var isLiteral: Bool { LLVMIsLiteralStruct(llvm.raw) != 0 } 52 | 53 | /// The fields of the struct. 54 | public var fields: Fields { .init(of: self) } 55 | 56 | /// Returns a constant whose LLVM IR type is `self` and whose value is aggregating `parts`. 57 | public func constant( 58 | aggregating elements: S, in module: inout Module 59 | ) -> StructConstant where S.Element == IRValue { 60 | .init(of: self, aggregating: elements, in: &module) 61 | } 62 | 63 | } 64 | 65 | extension StructType { 66 | 67 | /// A collection containing the fields of a struct type in LLVM IR. 68 | public struct Fields: BidirectionalCollection { 69 | 70 | public typealias Index = Int 71 | 72 | public typealias Element = IRType 73 | 74 | /// The struct type containing the elements of the collection. 75 | private let parent: StructType 76 | 77 | /// Creates a collection containing the fields of `t`. 78 | fileprivate init(of t: StructType) { 79 | self.parent = t 80 | } 81 | 82 | /// The number of fields in the collection. 83 | public var count: Int { 84 | Int(LLVMCountStructElementTypes(parent.llvm.raw)) 85 | } 86 | 87 | public var startIndex: Int { 0 } 88 | 89 | public var endIndex: Int { count } 90 | 91 | public func index(after position: Int) -> Int { 92 | precondition(position < count, "index is out of bounds") 93 | return position + 1 94 | } 95 | 96 | public func index(before position: Int) -> Int { 97 | precondition(position > 0, "index is out of bounds") 98 | return position - 1 99 | } 100 | 101 | public subscript(position: Int) -> IRType { 102 | precondition(position >= 0 && position < count, "index is out of bounds") 103 | return AnyType(LLVMStructGetTypeAtIndex(parent.llvm.raw, UInt32(position))) 104 | } 105 | 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Types/VoidType.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// A `void` type in LLVM IR. 4 | public struct VoidType: IRType, Hashable { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | public let llvm: TypeRef 8 | 9 | /// Creates an instance in `module`. 10 | public init(in module: inout Module) { 11 | self.llvm = .init(LLVMVoidTypeInContext(module.context)) 12 | } 13 | 14 | /// Creates an instance with `t`, failing iff `t` isn't a void type. 15 | public init?(_ t: IRType) { 16 | if LLVMGetTypeKind(t.llvm.raw) == LLVMVoidTypeKind { 17 | self.llvm = t.llvm 18 | } else { 19 | return nil 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Utils/ManagedPointer.swift: -------------------------------------------------------------------------------- 1 | /// A pointer to a LLVM object that disposes of its pointee when it's no longer accessible. 2 | final class ManagedPointer { 3 | 4 | /// A pointer to a LLVM object. 5 | let llvm: T 6 | 7 | /// A closure that disposes of an instance pointed by `T`. 8 | private let dispose: (T) -> Void 9 | 10 | /// Creates an instance managing `p` and calling `dispose(p)` at the end of its lifetime. 11 | init(_ p: T, dispose: @escaping (T) -> Void) { 12 | self.llvm = p 13 | self.dispose = dispose 14 | } 15 | 16 | deinit { 17 | dispose(llvm) 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Utils/String+Extensions.swift: -------------------------------------------------------------------------------- 1 | extension String { 2 | 3 | /// Creates an instance calling `getter` on `llvm` to read its value. 4 | init?( 5 | from llvm: T, 6 | readingWith getter: (T, UnsafeMutablePointer?) -> UnsafePointer? 7 | ) { 8 | var n = 0 9 | guard let s = getter(llvm, &n) else { return nil } 10 | self.init( 11 | decoding: UnsafeBufferPointer(start: s, count: n).lazy.map(UInt8.init(bitPattern:)), 12 | as: UTF8.self) 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Values/Constants/AggregateConstant.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// A constant aggregate (e.g., a constant array) in LLVM IR. 4 | public protocol AggregateConstant: IRValue, BidirectionalCollection { 5 | 6 | /// The number of elements in this value. 7 | var count: Int { get } 8 | 9 | } 10 | 11 | extension AggregateConstant where Index == Int, Element == IRValue { 12 | 13 | public var startIndex: Int { 0 } 14 | 15 | public var endIndex: Int { count } 16 | 17 | public func index(after position: Int) -> Int { 18 | precondition(position < count, "index is out of bounds") 19 | return position + 1 20 | } 21 | 22 | public func index(before position: Int) -> Int { 23 | precondition(position > 0, "index is out of bounds") 24 | return position - 1 25 | } 26 | 27 | public subscript(position: Int) -> IRValue { 28 | precondition(position >= 0 && position < count, "index is out of bounds") 29 | return AnyValue(LLVMGetAggregateElement(llvm.raw, UInt32(position))) 30 | } 31 | 32 | } 33 | 34 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Values/Constants/AnyValue.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// A value in LLVM IR. 4 | internal struct AnyValue: IRValue { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | public let llvm: ValueRef 8 | 9 | /// Creates an instance wrapping `llvm`. 10 | internal init(_ llvm: LLVMValueRef) { 11 | self.llvm = .init(llvm) 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Values/Constants/ArrayConstant.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// A constant array in LLVM IR. 4 | public struct ArrayConstant: Hashable { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | public let llvm: ValueRef 8 | 9 | /// The number of elements in the array. 10 | public let count: Int 11 | 12 | /// Creates a constant array of `type` in `module`, filled with the contents of `elements`. 13 | /// 14 | /// - Requires: The type of each element in `contents` is `type`. 15 | public init( 16 | of type: IRType, containing elements: S, in module: inout Module 17 | ) where S.Element == IRValue { 18 | var values = elements.map({ $0.llvm.raw as Optional }) 19 | self.llvm = .init(LLVMConstArray(type.llvm.raw, &values, UInt32(values.count))) 20 | self.count = values.count 21 | } 22 | 23 | /// Creates a constant array of `i8` in `module`, filled with the contents of `bytes`. 24 | public init(bytes: S, in module: inout Module) where S.Element == UInt8 { 25 | let i8 = IntegerType(8, in: &module) 26 | self.init(of: i8, containing: bytes.map({ i8.constant($0) }), in: &module) 27 | } 28 | 29 | } 30 | 31 | extension ArrayConstant: AggregateConstant { 32 | 33 | public typealias Index = Int 34 | 35 | public typealias Element = IRValue 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Values/Constants/Attribute.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// An entity capable of holding attributes. 4 | /// 5 | /// Do not declare new conformances to `AttributeHolder`. Only `Function`, `Function.Return`, and 6 | /// `Parameter` are valid conforming types. 7 | public protocol AttributeHolder { 8 | 9 | /// The name of targe-independent attributes for this holder. 10 | associatedtype AttributeName: AttributeNameProtocol 11 | 12 | } 13 | 14 | /// A target-independent attribute name. 15 | public protocol AttributeNameProtocol: RawRepresentable where RawValue == String {} 16 | 17 | extension AttributeNameProtocol { 18 | 19 | /// The unique kind identifier corresponding to this name. 20 | internal var id: UInt32 { 21 | return LLVMGetEnumAttributeKindForName(rawValue, rawValue.count) 22 | } 23 | 24 | } 25 | 26 | /// An attribute on a function, return value, or parameter in LLVM IR. 27 | public enum Attribute: Hashable { 28 | 29 | /// A target-independent attribute. 30 | case targetIndependent(llvm: AttributeRef) 31 | 32 | /// Creates an instance wrapping `llvm`. 33 | internal init(_ llvm: LLVMAttributeRef?) { 34 | if LLVMIsEnumAttribute(llvm) != 0 { 35 | self = .targetIndependent(llvm: .init(llvm!)) 36 | } else { 37 | fatalError() 38 | } 39 | } 40 | 41 | /// Creates a target-independent attribute with given `name` and optional `value` in `module`. 42 | public init(_ name: T.AttributeName, _ value: UInt64 = 0, in module: inout Module) { 43 | self = .targetIndependent(llvm: .init(LLVMCreateEnumAttribute(module.context, name.id, value)!)) 44 | } 45 | 46 | /// The value of the attribute if it is target-independent. 47 | public var value: UInt64? { 48 | if case .targetIndependent(let h) = self { 49 | return LLVMGetEnumAttributeValue(h.raw) 50 | } else { 51 | return nil 52 | } 53 | } 54 | 55 | /// A handle to the LLVM object wrapped by this instance. 56 | internal var llvm: LLVMAttributeRef { 57 | switch self { 58 | case .targetIndependent(let h): 59 | return h.raw 60 | } 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Values/Constants/FloatingPointConstant.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// A constant floating-point number in LLVM IR. 4 | public struct FloatingPointConstant: IRValue, Hashable { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | public let llvm: ValueRef 8 | 9 | /// Creates an instance wrapping `llvm`. 10 | internal init(_ llvm: LLVMValueRef) { 11 | self.llvm = .init(llvm) 12 | } 13 | 14 | /// Creates an instance with `v`, failing iff `v` isn't a constant floating-point number. 15 | public init?(_ v: IRValue) { 16 | if let h = LLVMIsAConstantFP(v.llvm.raw) { 17 | self.llvm = .init(h) 18 | } else { 19 | return nil 20 | } 21 | } 22 | 23 | /// A pair `(v, l)` where `v` is the value of this constant and `l` is `true` iff 24 | /// precision was lost in the conversion. 25 | public var value: (value: Double, lostPrecision: Bool) { 26 | var l: Int32 = 0 27 | let v = LLVMConstRealGetDouble(llvm.raw, &l) 28 | return (v, l != 0) 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Values/Constants/Function+Attributes.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | extension Function: AttributeHolder { 4 | 5 | /// An attribute on a function in LLVM IR. 6 | public typealias Attribute = SwiftyLLVM.Attribute 7 | 8 | /// The name of an attribute on a function in LLVM IR. 9 | public enum AttributeName: String, AttributeNameProtocol { 10 | 11 | /// Indicates that the inliner should attempt to inline this function into callers whenever 12 | /// possible, ignoring any active inlining size threshold for this caller. 13 | case alwaysinline 14 | 15 | /// Indicates that this function is rarely called. 16 | case cold 17 | 18 | /// Indicates that this function is a hot spot of the program execution. 19 | case hot 20 | 21 | /// Indicates that the inliner should never inline this function in any situation. 22 | /// 23 | /// - Note: This attribute may not be used together with the `alwaysinline` attribute. 24 | case noinline 25 | 26 | /// Indicates that the function never returns normally. 27 | /// 28 | /// If the function ever does dynamically return, its run-time behavior is undefined. Annotated 29 | /// functions may still raise an exception, i.e., `nounwind` is not implied. 30 | case noreturn 31 | 32 | /// Indicates that the function does not call itself either directly or indirectly down any 33 | /// possible call path. 34 | /// 35 | /// If the function ever does recurse, its run-time behavior is undefined. 36 | case norecurse 37 | 38 | /// Indicates that the function never raises an exception. 39 | /// 40 | /// If the function does raise an exception, its run-time behavior is undefined. However, 41 | /// functions marked nounwind may still trap or generate asynchronous exceptions. Exception 42 | /// handling schemes that are recognized by LLVM to handle asynchronous exceptions, such as 43 | /// `SEH`, will still provide their implementation defined semantics. 44 | case nounwind 45 | 46 | } 47 | 48 | /// The attributes of the function. 49 | public var attributes: [Attribute] { 50 | let i = UInt32(bitPattern: Int32(LLVMAttributeFunctionIndex)) 51 | let n = LLVMGetAttributeCountAtIndex(llvm.raw, i) 52 | var handles: [LLVMAttributeRef?] = .init(repeating: nil, count: Int(n)) 53 | LLVMGetAttributesAtIndex(llvm.raw, i, &handles) 54 | return handles.map(Attribute.init(_:)) 55 | } 56 | 57 | } 58 | 59 | extension Function.Return: AttributeHolder { 60 | 61 | /// An attribute on a function in LLVM IR. 62 | public typealias Attribute = SwiftyLLVM.Attribute 63 | 64 | /// The name of an attribute on a return value in LLVM IR. 65 | public typealias AttributeName = Parameter.AttributeName 66 | 67 | /// The attributes of the return value. 68 | public var attributes: [Attribute] { 69 | let n = LLVMGetAttributeCountAtIndex(parent.llvm.raw, 0) 70 | var handles: [LLVMAttributeRef?] = .init(repeating: nil, count: Int(n)) 71 | LLVMGetAttributesAtIndex(parent.llvm.raw, 0, &handles) 72 | return handles.map(Attribute.init(_:)) 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Values/Constants/Function.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// A function in LLVM IR. 4 | public struct Function: Global, Hashable { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | public let llvm: ValueRef 8 | 9 | /// Creates an instance wrapping `llvm`. 10 | internal init(_ llvm: LLVMValueRef) { 11 | self.llvm = .init(llvm) 12 | } 13 | 14 | /// Creates an instance with `v`, failing iff `v` isn't a function. 15 | public init?(_ v: IRValue) { 16 | if let h = LLVMIsAFunction(v.llvm.raw) { 17 | self.llvm = .init(h) 18 | } else { 19 | return nil 20 | } 21 | } 22 | 23 | /// The parameters of the function. 24 | public var parameters: Parameters { .init(of: self) } 25 | 26 | /// The basic blocks of the function. 27 | public var basicBlocks: [BasicBlock] { 28 | let n = LLVMCountBasicBlocks(llvm.raw) 29 | var handles: [LLVMBasicBlockRef?] = .init(repeating: nil, count: Int(n)) 30 | LLVMGetBasicBlocks(llvm.raw, &handles) 31 | return handles.map({ .init($0!) }) 32 | } 33 | 34 | /// The the function's entry, if any. 35 | public var entry: BasicBlock? { 36 | guard LLVMCountBasicBlocks(llvm.raw) > 0 else { return nil } 37 | return .init(LLVMGetEntryBasicBlock(llvm.raw)) 38 | } 39 | 40 | /// Returns `true` iff the IR in `self` is well formed. 41 | public func isWellFormed() -> Bool { 42 | LLVMVerifyFunction(llvm.raw, LLVMReturnStatusAction) == 0 43 | } 44 | 45 | } 46 | 47 | extension Function { 48 | 49 | 50 | /// The return value of a LLVM IR function. 51 | public struct Return: Hashable { 52 | 53 | /// The function defining the return value. 54 | public let parent: Function 55 | 56 | /// Creates an instance representing the return value of `parent`. 57 | fileprivate init(_ parent: Function) { 58 | self.parent = parent 59 | } 60 | 61 | } 62 | 63 | /// The return value of the function. 64 | public var returnValue: Return { .init(self) } 65 | 66 | } 67 | 68 | extension Function { 69 | 70 | /// A collection containing the parameters of a LLVM IR function. 71 | public struct Parameters: BidirectionalCollection { 72 | 73 | public typealias Index = Int 74 | 75 | public typealias Element = Parameter 76 | 77 | /// The function containing the elements of the collection. 78 | private let parent: Function 79 | 80 | /// Creates a collection containing the parameters of `f`. 81 | fileprivate init(of f: Function) { 82 | self.parent = f 83 | } 84 | 85 | /// The number of parameters in the collection. 86 | public var count: Int { 87 | Int(LLVMCountParams(parent.llvm.raw)) 88 | } 89 | 90 | public var startIndex: Int { 0 } 91 | 92 | public var endIndex: Int { count } 93 | 94 | public func index(after position: Int) -> Int { 95 | precondition(position < count, "index is out of bounds") 96 | return position + 1 97 | } 98 | 99 | public func index(before position: Int) -> Int { 100 | precondition(position > 0, "index is out of bounds") 101 | return position - 1 102 | } 103 | 104 | public subscript(position: Int) -> Parameter { 105 | precondition(position >= 0 && position < count, "index is out of bounds") 106 | return .init(LLVMGetParam(parent.llvm.raw, UInt32(position)), position) 107 | } 108 | 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Values/Constants/IntegerConstant.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// A constant integer value in LLVM IR. 4 | public struct IntegerConstant: IRValue, Hashable { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | public let llvm: ValueRef 8 | 9 | /// Creates an instance wrapping `llvm`. 10 | internal init(_ llvm: LLVMValueRef) { 11 | self.llvm = .init(llvm) 12 | } 13 | 14 | /// Creates an instance with `v`, failing iff `v` isn't a constant integer value. 15 | public init?(_ v: IRValue) { 16 | if let h = LLVMIsAConstantInt(v.llvm.raw) { 17 | self.llvm = .init(h) 18 | } else { 19 | return nil 20 | } 21 | } 22 | 23 | /// The sign extended value of this constant. 24 | public var sext: Int64 { 25 | LLVMConstIntGetSExtValue(llvm.raw) 26 | } 27 | 28 | /// The zero extended value of this constant. 29 | public var zext: UInt64 { 30 | LLVMConstIntGetZExtValue(llvm.raw) 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Values/Constants/Intrinsic.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | import Foundation 3 | 4 | /// An intrinsic function known to LLVM. 5 | /// 6 | /// Intrinsic functions have well known names and semantics and are required to follow certain 7 | /// restrictions. Overall, these intrinsics represent an extension mechanism for the LLVM language 8 | /// that does not require changing all of the transformations in LLVM when adding to the language. 9 | public struct Intrinsic: Global, Hashable { 10 | 11 | /// A handle to the LLVM object wrapped by this instance. 12 | public let llvm: ValueRef 13 | 14 | /// Creates an instance wrapping `llvm`. 15 | internal init(_ llvm: LLVMValueRef) { 16 | self.llvm = .init(llvm) 17 | } 18 | 19 | /// The intrinsic's identifier. 20 | public var identifier: UInt32 { 21 | LLVMGetIntrinsicID(llvm.raw) 22 | } 23 | 24 | /// `true` iff the intrinsic is overloaded. 25 | public var isOverloaded: Bool { 26 | LLVMIntrinsicIsOverloaded(identifier) != 0 27 | } 28 | 29 | /// The name of the intrinsic. 30 | public var name: String { 31 | String(from: identifier, readingWith: LLVMIntrinsicGetName(_:_:)) ?? "" 32 | } 33 | 34 | } 35 | 36 | extension Intrinsic { 37 | 38 | /// The name of an intrinsic. 39 | @dynamicMemberLookup 40 | public struct Name { 41 | 42 | /// The value of this instance. 43 | public let value: String 44 | 45 | /// Creates an instance with name `n`. 46 | fileprivate init(_ n: String) { 47 | self.value = n 48 | } 49 | 50 | /// Returns `self` with `n` appended. 51 | public subscript(dynamicMember n: String) -> Name { 52 | Name(value + "." + n) 53 | } 54 | 55 | } 56 | 57 | /// The prefix of all intrinsics. 58 | public static var llvm = Name("llvm") 59 | 60 | } 61 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Values/Constants/Parameter+Attributes.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | extension Parameter: AttributeHolder { 4 | 5 | /// An attribute on a parameter in LLVM IR. 6 | public typealias Attribute = SwiftyLLVM.Attribute 7 | 8 | /// The name of an attribute on a parameter in LLVM IR. 9 | public enum AttributeName: String, AttributeNameProtocol { 10 | 11 | /// Indicates to the code generator that the parameter or return value should be sign-extended 12 | /// to the extent required by the target’s ABI (which is usually 32-bits) by the caller (for a 13 | /// parameter) or the callee (for a return value). 14 | case signext 15 | 16 | /// Indicates to the code generator that the parameter or return value should be zero-extended 17 | /// to the extent required by the target’s ABI by the caller (for a parameter) or the callee 18 | /// (for a return value). 19 | case zeroext 20 | 21 | /// Indicates that this parameter or return value should be treated in a special 22 | /// target-dependent fashion while emitting code for a function call or return (usually, by 23 | /// putting it in a register as opposed to memory, though some targets use it to distinguish 24 | /// between two different kinds of registers). Use of this attribute is target-specific. 25 | case inreg 26 | 27 | /// Indicates that the pointer value or vector of pointers has the specified alignment. 28 | case align 29 | 30 | /// Indicates that the alignment that should be considered by the backend when assigning this 31 | /// parameter to a stack slot during calling convention lowering 32 | case alignstack 33 | 34 | /// Indicates that the function parameter marked with this attribute is is the alignment in 35 | /// bytes of the newly allocated block returned by this function. 36 | case allocalign 37 | 38 | /// Indicates that the function parameter marked with this attribute is the pointer that will 39 | /// be manipulated by the allocator. 40 | case allocptr 41 | 42 | /// Indicates that memory locations accessed via pointer values based on the argument or return 43 | /// value are not also accessed, during the execution of the function, via pointer values not 44 | /// *based* on the argument or return value. 45 | case noalias 46 | 47 | /// Indicates that the callee does not capture the pointer. This is not a valid attribute for 48 | /// return values. 49 | case nocapture 50 | 51 | /// Indicates that callee does not free the pointer argument. 52 | /// 53 | /// This attribute is not valid for return values. 54 | case nofree 55 | 56 | /// Indicates that the function always returns the argument as its return value. 57 | case returned 58 | 59 | /// Indicates that the parameter or return pointer is not null. This attribute may only be 60 | /// applied to pointer typed parameters 61 | case nonnull 62 | 63 | /// Indicates that the parameter or return value is not undefined. 64 | case noundef 65 | 66 | /// Indicates that the function does not dereference that pointer argument, even though it may 67 | /// read or write the memory that the pointer points to if accessed through other pointers. 68 | case readnone 69 | 70 | /// Indicates that the function does not write through this pointer argument, even though it 71 | /// may write to the memory that the pointer points to. 72 | case readonly 73 | 74 | /// Indicates that the function may write to, but does not read through this pointer argument 75 | /// (even though it may read from the memory that the pointer points to). 76 | case writeonly 77 | 78 | /// Indicates that the parameter or return pointer is dereferenceable. 79 | case dereferenceable 80 | 81 | /// Indicates that the parameter or return value isn’t both non-null and non-dereferenceable 82 | /// (up to *n* bytes) at the same time. 83 | case dereferenceable_or_null 84 | 85 | /// Indicates that the parameter is required to be an immediate value. 86 | case immarg 87 | 88 | } 89 | 90 | /// The attributes of the parameter. 91 | public var attributes: [Attribute] { 92 | let i = UInt32(index + 1) 93 | let n = LLVMGetAttributeCountAtIndex(parent.llvm.raw, i) 94 | var handles: [LLVMAttributeRef?] = .init(repeating: nil, count: Int(n)) 95 | LLVMGetAttributesAtIndex(parent.llvm.raw, i, &handles) 96 | return handles.map(Attribute.init(_:)) 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Values/Constants/Parameter.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// A parameter in a LLVM IR function. 4 | public struct Parameter: IRValue { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | public let llvm: ValueRef 8 | 9 | /// The index of the parameter in its function. 10 | public let index: Int 11 | 12 | /// Creates an instance wrapping `llvm`, which represents the `i`-th parameter of a function. 13 | internal init(_ llvm: LLVMValueRef, _ i: Int) { 14 | self.llvm = .init(llvm) 15 | self.index = i 16 | } 17 | 18 | /// Creates an intance with `v`, failing iff `v` is not a parameter. 19 | public init?(_ v: IRValue) { 20 | if let h = LLVMIsAArgument(v.llvm.raw) { 21 | self.llvm = .init(h) 22 | self.index = Function(LLVMGetParamParent(h)).parameters.firstIndex(where: { $0.llvm.raw == h })! 23 | } else { 24 | return nil 25 | } 26 | } 27 | 28 | /// The function containing the parameter. 29 | public var parent: Function { .init(LLVMGetParamParent(llvm.raw)) } 30 | 31 | } 32 | 33 | extension Parameter: Hashable { 34 | 35 | public func hash(into hasher: inout Hasher) { 36 | hasher.combine(llvm) 37 | } 38 | 39 | public static func == (lhs: Self, rhs: Self) -> Bool { 40 | lhs.llvm == rhs.llvm 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Values/Constants/Poison.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// A poison value in LLVM IR. 4 | public struct Poison: IRValue, Hashable { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | public let llvm: ValueRef 8 | 9 | /// Creates the poison value of `t`. 10 | public init(of t: IRType) { 11 | self.llvm = .init(LLVMGetPoison(t.llvm.raw)) 12 | } 13 | 14 | /// Creates an intance with `v`, failing iff `v` is not a poison value. 15 | public init?(_ v: IRValue) { 16 | if let h = LLVMIsAPoisonValue(v.llvm.raw) { 17 | self.llvm = .init(h) 18 | } else { 19 | return nil 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Values/Constants/StringConstant.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// A constant character string in LLVM IR. 4 | public struct StringConstant: IRValue, Hashable { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | public let llvm: ValueRef 8 | 9 | /// Creates an instance with `text` in `module`, appending a null terminator to the string iff 10 | /// `nullTerminated` is `true`. 11 | public init(_ text: String, nullTerminated: Bool = true, in module: inout Module) { 12 | self.llvm = text.withCString { (s) in 13 | .init(LLVMConstStringInContext(module.context, s, UInt32(text.utf8.count), nullTerminated ? 0 : 1)) 14 | } 15 | } 16 | 17 | /// Creates an instance with `v`, failing iff `v` is not a constant string value. 18 | public init?(_ v: IRValue) { 19 | if LLVMIsAConstantDataSequential(v.llvm.raw) != nil && LLVMIsConstantString(v.llvm.raw) != 0 { 20 | self.llvm = v.llvm 21 | } else { 22 | return nil 23 | } 24 | } 25 | 26 | /// The value of this constant. 27 | public var value: String { 28 | .init(from: llvm) { (h, count) in 29 | // Decrement `count` if the string is null-terminated. 30 | guard let s = LLVMGetAsString(h.raw, count) else { return nil } 31 | if s[count!.pointee - 1] == 0 { count!.pointee -= 1 } 32 | return s 33 | } ?? "" 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Values/Constants/StructConstant.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// A constant struct in LLVM IR. 4 | public struct StructConstant: Hashable { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | public let llvm: ValueRef 8 | 9 | /// The number of elements in the struct. 10 | public let count: Int 11 | 12 | /// Creates a constant struct of `type` in `module` aggregating `elements`. 13 | /// 14 | /// - Requires: The type of `contents[i]` has the same type as the `i`-th element of `type`. 15 | public init( 16 | of type: StructType, aggregating elements: S, in module: inout Module 17 | ) where S.Element == IRValue { 18 | var values = elements.map({ $0.llvm.raw as Optional }) 19 | self.llvm = .init(LLVMConstNamedStruct(type.llvm.raw, &values, UInt32(values.count))) 20 | self.count = values.count 21 | } 22 | 23 | /// Creates a constant struct in `module` aggregating `elements`, packing these elemnts them if 24 | /// `isPacked` is `true`. 25 | public init( 26 | aggregating elements: S, packed isPacked: Bool = false, in module: inout Module 27 | ) where S.Element == IRValue { 28 | var values = elements.map({ $0.llvm.raw as Optional }) 29 | self.llvm = .init(LLVMConstStructInContext( 30 | module.context, &values, UInt32(values.count), isPacked ? 1 : 0)) 31 | self.count = values.count 32 | } 33 | 34 | } 35 | 36 | extension StructConstant: AggregateConstant { 37 | 38 | public typealias Index = Int 39 | 40 | public typealias Element = IRValue 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Values/Constants/Undefined.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// An undefined value in LLVM IR. 4 | public struct Undefined: IRValue, Hashable { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | public let llvm: ValueRef 8 | 9 | /// Creates an undefined value of type `t`. 10 | public init(of t: IRType) { 11 | self.llvm = .init(LLVMGetUndef(t.llvm.raw)) 12 | } 13 | 14 | /// Creates an instance with `v`, failing iff `v` is not an undefined value. 15 | public init?(_ v: IRValue) { 16 | if let h = LLVMIsAUndefValue(v.llvm.raw) { 17 | self.llvm = .init(h) 18 | } else { 19 | return nil 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Values/Global.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// A global value in LLVM IR. 4 | public protocol Global: IRValue {} 5 | 6 | extension Global { 7 | 8 | /// The LLVM IR "value type" of this global. 9 | /// 10 | /// This "value type" of a global differs from its formal type, which is always a pointer type. 11 | public var valueType: IRType { 12 | AnyType(LLVMGlobalGetValueType(llvm.raw)) 13 | } 14 | 15 | /// The linkage of this global. 16 | public var linkage: Linkage { 17 | .init(llvm: LLVMGetLinkage(llvm.raw)) 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Values/GlobalVariable.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// A global value in LLVM IR. 4 | public struct GlobalVariable: Global { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | public let llvm: ValueRef 8 | 9 | /// Creates an instance wrapping `llvm`. 10 | internal init(_ llvm: LLVMValueRef) { 11 | self.llvm = .init(llvm) 12 | } 13 | 14 | /// `true` if this value is constant. 15 | /// 16 | /// If this value is a global constant, its value is immutable throughout the runtime execution 17 | /// of the program. Assigning a value into it leads to undefined behavior. 18 | /// 19 | /// - Note: This property should not be confused with `IRValue.isConstant`, which indicates 20 | /// whether a value is a constant user, as opposed to an instruction. 21 | public var isGlobalConstant: Bool { LLVMIsGlobalConstant(llvm.raw) != 0 } 22 | 23 | /// `true` is this value is initialized externally. 24 | public var isExternallyInitialized: Bool { LLVMIsExternallyInitialized(llvm.raw) != 0 } 25 | 26 | /// The initial value of this global. 27 | public var initializer: IRValue? { LLVMGetInitializer(llvm.raw).map(AnyValue.init(_:)) } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Values/IRValue.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// A value in LLVM IR. 4 | public protocol IRValue: CustomStringConvertible { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | var llvm: ValueRef { get } 8 | 9 | } 10 | 11 | extension IRValue { 12 | 13 | /// A string representation of the value. 14 | public var description: String { 15 | guard let s = LLVMPrintValueToString(llvm.raw) else { return "" } 16 | defer { LLVMDisposeMessage(s) } 17 | return String(cString: s) 18 | } 19 | 20 | /// The LLVM IR type of this value. 21 | public var type: IRType { AnyType(LLVMTypeOf(llvm.raw)) } 22 | 23 | /// The name of this value. 24 | public var name: String { String(from: llvm.raw, readingWith: LLVMGetValueName2(_:_:)) ?? "" } 25 | 26 | /// `true` iff this value is the `null` instance of its type. 27 | public var isNull: Bool { LLVMIsNull(llvm.raw) != 0 } 28 | 29 | /// `true` iff this value is constant. 30 | public var isConstant: Bool { LLVMIsConstant(llvm.raw) != 0 } 31 | 32 | /// `true` iff this value is a terminator instruction. 33 | public var isTerminator: Bool { LLVMIsATerminatorInst(llvm.raw) != nil } 34 | 35 | /// Returns `true` iff `lhs` is equal to `rhs`. 36 | public static func == (lhs: Self, rhs: R) -> Bool { 37 | lhs.llvm == rhs.llvm 38 | } 39 | 40 | /// Returns `true` iff `lhs` is equal to `rhs`. 41 | public static func == (lhs: IRValue, rhs: Self) -> Bool { 42 | lhs.llvm == rhs.llvm 43 | } 44 | 45 | /// Returns `true` iff `lhs` is equal to `rhs`. 46 | public static func == (lhs: Self, rhs: IRValue) -> Bool { 47 | lhs.llvm == rhs.llvm 48 | } 49 | 50 | /// Returns `true` iff `lhs` is not equal to `rhs`. 51 | public static func != (lhs: IRValue, rhs: Self) -> Bool { 52 | lhs.llvm != rhs.llvm 53 | } 54 | 55 | /// Returns `true` iff `lhs` is not equal to `rhs`. 56 | public static func != (lhs: Self, rhs: IRValue) -> Bool { 57 | lhs.llvm != rhs.llvm 58 | } 59 | 60 | } 61 | 62 | /// Returns `true` iff `lhs` is equal to `rhs`. 63 | public func == (lhs: IRValue, rhs: IRValue) -> Bool { 64 | lhs.llvm == rhs.llvm 65 | } 66 | 67 | /// Returns `true` iff `lhs` is not equal to `rhs`. 68 | public func != (lhs: IRValue, rhs: IRValue) -> Bool { 69 | lhs.llvm != rhs.llvm 70 | } 71 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Values/Instructions/Alloca.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// LLVM's `alloca` instruction. 4 | public struct Alloca: IRValue { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | public let llvm: ValueRef 8 | 9 | /// Creates an instance wrapping `llvm`. 10 | internal init(_ llvm: LLVMValueRef) { 11 | self.llvm = .init(llvm) 12 | } 13 | 14 | /// Creates an instance with `s`, failing iff `s` isn't an `alloca` 15 | public init?(_ s: IRValue) { 16 | if let h = LLVMIsAAllocaInst(s.llvm.raw) { 17 | self.llvm = .init(h) 18 | } else { 19 | return nil 20 | } 21 | } 22 | 23 | /// The type of the value allocated by the instruction. 24 | public var allocatedType: IRType { AnyType(LLVMGetAllocatedType(llvm.raw)) } 25 | 26 | /// The preferred alignment of the allocated memory. 27 | public var alignment: Int { Int(LLVMGetAlignment(llvm.raw)) } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Values/Instructions/FloatingPointPredicate.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// The predicate of an integer comparison. 4 | /// 5 | /// - Note: Ordered means that neither operand is a QNAN while unordered means that either operand 6 | /// may be a QNAN. 7 | public enum FloatingPointPredicate: String, Hashable { 8 | 9 | /// No comparison; always false. 10 | case alwaysFalse = "false" 11 | 12 | /// No comparison; always true. 13 | case alwaysTrue = "true" 14 | 15 | /// Values are ordered and equal. 16 | case oeq 17 | 18 | /// Values are ordered and not equal. 19 | case one 20 | 21 | /// Values are ordered and LHS is greater than RHS. 22 | case ogt 23 | 24 | /// Values are ordered and LHS greater than or equal to RHS. 25 | case oge 26 | 27 | /// Values are ordered and LHS is less than RHS. 28 | case olt 29 | 30 | /// Values are ordered and LHS is less than or equal to RHS. 31 | case ole 32 | 33 | /// Values are ordered (no nans). 34 | case ord 35 | 36 | /// Values are unordered or equal. 37 | case ueq 38 | 39 | /// Values are unordered or not equal. 40 | case une 41 | 42 | /// Values are unordered or LHS is greater than RHS. 43 | case ugt 44 | 45 | /// Values are unordered or LHS is greater than or equal to RHS. 46 | case uge 47 | 48 | /// Values are unordered or LHS is less than RHS. 49 | case ult 50 | 51 | /// Values are unordered or LHS is less than or equal to RHS. 52 | case ule 53 | 54 | /// Values are unordered (either nans). 55 | case uno 56 | 57 | /// The LLVM identifier of the predicate. 58 | internal var llvm: LLVMRealPredicate { 59 | switch self { 60 | case .alwaysFalse: 61 | return LLVMRealPredicateFalse 62 | case .alwaysTrue: 63 | return LLVMRealPredicateTrue 64 | case .oeq: 65 | return LLVMRealOEQ 66 | case .one: 67 | return LLVMRealONE 68 | case .ogt: 69 | return LLVMRealOGT 70 | case .oge: 71 | return LLVMRealOGE 72 | case .olt: 73 | return LLVMRealOLT 74 | case .ole: 75 | return LLVMRealOLE 76 | case .ord: 77 | return LLVMRealORD 78 | case .ueq: 79 | return LLVMRealUEQ 80 | case .une: 81 | return LLVMRealUNE 82 | case .ugt: 83 | return LLVMRealUGT 84 | case .uge: 85 | return LLVMRealUGE 86 | case .ult: 87 | return LLVMRealULT 88 | case .ule: 89 | return LLVMRealULE 90 | case .uno: 91 | return LLVMRealUNO 92 | } 93 | } 94 | 95 | } 96 | 97 | extension FloatingPointPredicate: LosslessStringConvertible { 98 | 99 | public init?(_ description: String) { 100 | self.init(rawValue: description) 101 | } 102 | 103 | public var description: String { self.rawValue } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Values/Instructions/Instruction.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// An instruction in LLVM IR. 4 | public struct Instruction: IRValue, Hashable { 5 | 6 | /// A handle to the LLVM object wrapped by this instance. 7 | public let llvm: ValueRef 8 | 9 | /// Creates an instance wrapping `llvm`. 10 | internal init(_ llvm: LLVMValueRef) { 11 | self.llvm = .init(llvm) 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Values/Instructions/IntegerPredicate.swift: -------------------------------------------------------------------------------- 1 | internal import llvmc 2 | 3 | /// The predicate of an integer comparison. 4 | public enum IntegerPredicate: String, Hashable { 5 | 6 | /// Values are equal. 7 | case eq 8 | 9 | /// Values are not equal. 10 | case ne 11 | 12 | /// LHS is greater than RHS, by unsigned comparison. 13 | case ugt 14 | 15 | /// LHS is greater than or equal to RHS, by unsigned comparison. 16 | case uge 17 | 18 | /// LHS is less than RHS, by unsigned comparison. 19 | case ult 20 | 21 | /// LHS is less than or equal to RHS, by unsigned comparison. 22 | case ule 23 | 24 | /// LHS is less than RHS, by signed comparison. 25 | case slt 26 | 27 | /// LHS is greater than or equal to RHS, by signed comparison. 28 | case sge 29 | 30 | /// LHS is greater than RHS, by signed comparison. 31 | case sgt 32 | 33 | /// LHS is less than or equal to RHS, by signed comparison. 34 | case sle 35 | 36 | /// The LLVM identifier of the predicate. 37 | internal var llvm: LLVMIntPredicate { 38 | switch self { 39 | case .eq: 40 | return LLVMIntEQ 41 | case .ne: 42 | return LLVMIntNE 43 | case .ugt: 44 | return LLVMIntUGT 45 | case .uge: 46 | return LLVMIntUGE 47 | case .ult: 48 | return LLVMIntULT 49 | case .ule: 50 | return LLVMIntULE 51 | case .sgt: 52 | return LLVMIntSGT 53 | case .sge: 54 | return LLVMIntSGE 55 | case .slt: 56 | return LLVMIntSLT 57 | case .sle: 58 | return LLVMIntSLE 59 | } 60 | } 61 | 62 | } 63 | 64 | extension IntegerPredicate: LosslessStringConvertible { 65 | 66 | public init?(_ description: String) { 67 | self.init(rawValue: description) 68 | } 69 | 70 | public var description: String { self.rawValue } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /Sources/SwiftyLLVM/Values/Instructions/OverflowBehavior.swift: -------------------------------------------------------------------------------- 1 | /// The behavior that should occur on overflow during mathematical operations. 2 | public enum OverflowBehavior { 3 | 4 | /// Overflow is ignored. 5 | case ignore 6 | 7 | /// The result is a poison value should unsigned overflow occur. 8 | case nuw 9 | 10 | /// The result is a poison value should signed overflow occur. 11 | case nsw 12 | 13 | } 14 | -------------------------------------------------------------------------------- /Sources/llvmc/llvmc.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | -------------------------------------------------------------------------------- /Sources/llvmc/module.modulemap: -------------------------------------------------------------------------------- 1 | module llvmc { 2 | umbrella header "llvmc.h" 3 | export * 4 | } 5 | -------------------------------------------------------------------------------- /Sources/llvmshims/include/module.modulemap: -------------------------------------------------------------------------------- 1 | module llvmshims { 2 | header "shim.h" 3 | export * 4 | } 5 | -------------------------------------------------------------------------------- /Sources/llvmshims/include/shim.h: -------------------------------------------------------------------------------- 1 | #ifndef SWIFTYLLVM_LLVMSHIMS_H 2 | #define SWIFTYLLVM_LLVMSHIMS_H 3 | 4 | #include "llvm-c/Transforms/PassBuilder.h" 5 | #include "llvm-c/ExternC.h" 6 | 7 | LLVM_C_EXTERN_C_BEGIN 8 | 9 | /// Optimization level of a pass. 10 | /// 11 | /// - See: llvm::OptimizationLevel 12 | typedef enum { 13 | SwiftyLLVMPassOptimizationLevelO0, 14 | SwiftyLLVMPassOptimizationLevelO1, 15 | SwiftyLLVMPassOptimizationLevelO2, 16 | SwiftyLLVMPassOptimizationLevelO3, 17 | SwiftyLLVMPassOptimizationLevelOs, 18 | SwiftyLLVMPassOptimizationLevelOz, 19 | } SwiftyLLVMPassOptimizationLevel; 20 | 21 | void SwiftyLLVMRunDefaultModulePasses( 22 | LLVMModuleRef self, 23 | LLVMTargetMachineRef t, 24 | SwiftyLLVMPassOptimizationLevel optimization); 25 | 26 | LLVM_C_EXTERN_C_END 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /Sources/llvmshims/src/shim.cc: -------------------------------------------------------------------------------- 1 | #ifdef _MSC_VER 2 | #pragma warning(push) 3 | #pragma warning(disable: 4624 4244) 4 | 5 | // According to compnerd, “a Microsoft update requires a newer clang 6 | // than what swift ships. That’s a second chance that they pushed that 7 | // breaks after working around this. The best option is to use a 6.0 8 | // pre release.” We don't want to impose that on downstream clients, 9 | // so we use this workaround, which incidentally isn't compatible with 10 | // Swift/C++ interop. 11 | #define _ALLOW_COMPILER_AND_STL_VERSION_MISMATCH 1 12 | 13 | #endif 14 | 15 | #include "llvm-c/TargetMachine.h" 16 | #include "llvm-c/Transforms/PassBuilder.h" 17 | #include "llvm/Passes/PassBuilder.h" 18 | #include "llvm/Passes/StandardInstrumentations.h" 19 | #include "shim.h" 20 | #ifdef _MSC_VER 21 | #pragma warning(pop) 22 | #endif 23 | 24 | // Used to create a fatal error in this file. Must follow all other #includes 25 | #undef NDEBUG 26 | #include 27 | // Used to create a fatal error in this file. Must follow all other 28 | // #includes 29 | 30 | using namespace llvm; 31 | 32 | template 33 | T* unsafe_as(U* s) { 34 | return static_cast(static_cast(s)); 35 | } 36 | 37 | llvm::OptimizationLevel as_llvm(SwiftyLLVMPassOptimizationLevel x) { 38 | switch (x) { 39 | case SwiftyLLVMPassOptimizationLevelO0: 40 | return llvm::OptimizationLevel::O0; 41 | case SwiftyLLVMPassOptimizationLevelO1: 42 | return llvm::OptimizationLevel::O1; 43 | case SwiftyLLVMPassOptimizationLevelO2: 44 | return llvm::OptimizationLevel::O2; 45 | case SwiftyLLVMPassOptimizationLevelO3: 46 | return llvm::OptimizationLevel::O3; 47 | case SwiftyLLVMPassOptimizationLevelOs: 48 | return llvm::OptimizationLevel::Os; 49 | case SwiftyLLVMPassOptimizationLevelOz: 50 | return llvm::OptimizationLevel::Oz; 51 | default: 52 | assert(!"fatal error: unhandled optimization level"); 53 | return llvm::OptimizationLevel::O0; 54 | } 55 | } 56 | 57 | extern "C" { 58 | 59 | void SwiftyLLVMRunDefaultModulePasses( 60 | LLVMModuleRef self, 61 | LLVMTargetMachineRef t, 62 | SwiftyLLVMPassOptimizationLevel optimization 63 | ) { 64 | // Create the analysis managers. 65 | LoopAnalysisManager lam; 66 | FunctionAnalysisManager fam; 67 | CGSCCAnalysisManager cgam; 68 | ModuleAnalysisManager mam; 69 | 70 | // Create a new pass manager builder. 71 | PassBuilder p(unsafe_as(t)); 72 | 73 | // Register all the basic analyses with the managers. 74 | p.registerModuleAnalyses(mam); 75 | p.registerCGSCCAnalyses(cgam); 76 | p.registerFunctionAnalyses(fam); 77 | p.registerLoopAnalyses(lam); 78 | p.crossRegisterProxies(lam, fam, cgam, mam); 79 | 80 | ModulePassManager mpm; 81 | if (optimization == SwiftyLLVMPassOptimizationLevelO0) { 82 | mpm = p.buildO0DefaultPipeline(OptimizationLevel::O0); 83 | } else { 84 | mpm = p.buildPerModuleDefaultPipeline(as_llvm(optimization)); 85 | } 86 | 87 | // Run the passes. 88 | mpm.run(*unwrap(self), mam); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /Tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(HyloUtilities) 2 | 3 | if(NOT APPLE) 4 | find_package(GenerateSwiftXCTestMain) 5 | endif() 6 | 7 | find_package(SwiftXCTest) 8 | 9 | set_recursive_file_glob(test_files LLVMTests/*.swift) 10 | add_swift_xctest(SwiftyLLVMTests SwiftyLLVM ${test_files}) 11 | -------------------------------------------------------------------------------- /Tests/LLVMTests/DataLayoutTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class DataLayoutTests: XCTestCase { 5 | 6 | func testBitWidth() throws { 7 | var m = Module("foo") 8 | let t = try TargetMachine(for: .host()) 9 | 10 | let i32 = IntegerType(32, in: &m) 11 | XCTAssertEqual(t.layout.bitWidth(of: i32), 32) 12 | } 13 | 14 | func testStorageSize() throws { 15 | var m = Module("foo") 16 | let t = try TargetMachine(for: .host()) 17 | 18 | let i32 = IntegerType(32, in: &m) 19 | XCTAssertEqual(t.layout.storageSize(of: i32), 4) 20 | } 21 | 22 | func testStorageStride() throws { 23 | var m = Module("foo") 24 | let t = try TargetMachine(for: .host()) 25 | 26 | let i32 = IntegerType(32, in: &m) 27 | XCTAssertEqual(t.layout.storageStride(of: i32), 4) 28 | } 29 | 30 | func testABIAlignment() throws { 31 | var m = Module("foo") 32 | let t = try TargetMachine(for: .host()) 33 | 34 | let i32 = IntegerType(32, in: &m) 35 | XCTAssertEqual(t.layout.abiAlignment(of: i32), 4) 36 | } 37 | 38 | func testOffset() throws { 39 | var m = Module("foo") 40 | let t = try TargetMachine(for: .host()) 41 | 42 | let i32 = IntegerType(32, in: &m) 43 | let s = StructType([i32, i32], in: &m) 44 | XCTAssertEqual(t.layout.offset(of: 1, in: s), 4) 45 | } 46 | 47 | func testIndex() throws { 48 | var m = Module("foo") 49 | let t = try TargetMachine(for: .host()) 50 | 51 | let i32 = IntegerType(32, in: &m) 52 | let s = StructType([i32, i32], in: &m) 53 | XCTAssertEqual(t.layout.index(at: 5, in: s), 1) 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /Tests/LLVMTests/MemoryBufferTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class MemoryBufferTests: XCTestCase { 5 | 6 | func testInitCopyingData() { 7 | let s = "Hello, World!" 8 | s.withCString({ (d) in 9 | let b = MemoryBuffer(copying: .init(start: d, count: s.utf8.count)) 10 | XCTAssertEqual(s, String(decoding: b)) 11 | }) 12 | } 13 | 14 | func testInitBorrowingData() { 15 | let s = "Hello, World!" 16 | s.withCString({ (d) in 17 | MemoryBuffer.withInstanceBorrowing(.init(start: d, count: s.utf8.count), { (b) in 18 | XCTAssertEqual(s, String(decoding: b)) 19 | }) 20 | }) 21 | } 22 | 23 | func testInitWithContentsOfFile() throws { 24 | let s = "Hello, World!" 25 | let f = FileManager.default.temporaryDirectory.appendingPathComponent("\(UUID())") 26 | try s.write(to: f, atomically: true, encoding: .utf8) 27 | 28 | let b = try MemoryBuffer(contentsOf: f.path) 29 | XCTAssertEqual(s, String(decoding: b)) 30 | } 31 | 32 | } 33 | 34 | extension String { 35 | 36 | /// Creates an instance with the contents of `b`. 37 | fileprivate init(decoding b: MemoryBuffer) { 38 | self = b.withUnsafeBytes({ (contents) in 39 | contents.withMemoryRebound(to: UInt8.self, { (b) in String(bytes: b, encoding: .utf8)! }) 40 | }) 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /Tests/LLVMTests/ModuleTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class ModuleTests: XCTestCase { 5 | 6 | func testModuleName() { 7 | var m = Module("foo") 8 | XCTAssertEqual(m.name, "foo") 9 | m.name = "bar" 10 | XCTAssertEqual(m.name, "bar") 11 | } 12 | 13 | func testTypeNamed() throws { 14 | var m = Module("foo") 15 | let t = StructType(named: "T", [], in: &m) 16 | let u = try XCTUnwrap(m.type(named: "T")) 17 | XCTAssert(t == u) 18 | XCTAssertNil(m.type(named: "U")) 19 | } 20 | 21 | func testFunctionNamed() throws { 22 | var m = Module("foo") 23 | let f = m.declareFunction("fn", FunctionType(from: [], in: &m)) 24 | let g = try XCTUnwrap(m.function(named: "fn")) 25 | XCTAssert(f == g) 26 | XCTAssertNil(m.type(named: "gn")) 27 | } 28 | 29 | func testGlobalNamed() throws { 30 | var m = Module("foo") 31 | let x = m.declareGlobalVariable("gl", PointerType(in: &m)) 32 | let y = try XCTUnwrap(m.global(named: "gl")) 33 | XCTAssert(x == y) 34 | XCTAssertNil(m.type(named: "gn")) 35 | } 36 | 37 | func testAddGlobalVariable() { 38 | var m = Module("foo") 39 | let x = m.addGlobalVariable("g", PointerType(in: &m)) 40 | let y = m.addGlobalVariable("g", PointerType(in: &m)) 41 | XCTAssert(x != y) 42 | } 43 | 44 | func testVerify() { 45 | var m = Module("foo") 46 | XCTAssertNoThrow(try m.verify()) 47 | 48 | let f = m.declareFunction("fn", .init(from: [], in: &m)) 49 | m.appendBlock(to: f) 50 | XCTAssertThrowsError(try m.verify()) 51 | } 52 | 53 | func testCompile() throws { 54 | var m = Module("foo") 55 | let i32 = IntegerType(32, in: &m) 56 | 57 | let f = m.declareFunction("main", .init(from: [], to: i32, in: &m)) 58 | let b = m.appendBlock(to: f) 59 | m.insertReturn(i32.zero, at: m.endOf(b)) 60 | 61 | let t = try TargetMachine(for: .host()) 62 | let a = try m.compile(.assembly, for: t) 63 | XCTAssert(a.count != 0) 64 | } 65 | 66 | func testStandardModulePasses() throws { 67 | var m = Module("foo") 68 | let i32 = IntegerType(32, in: &m) 69 | 70 | let f = m.declareFunction("main", .init(from: [], to: i32, in: &m)) 71 | let b = m.appendBlock(to: f) 72 | m.insertReturn(i32.zero, at: m.endOf(b)) 73 | 74 | let h = try Target.host() 75 | m.runDefaultModulePasses(for: TargetMachine(for: h)) 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /Tests/LLVMTests/TargetMachineTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class TargetMachineTests: XCTestCase { 5 | 6 | func testTarget() throws { 7 | let h = try Target.host() 8 | let t = TargetMachine(for: h) 9 | XCTAssertEqual(t.target, h) 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /Tests/LLVMTests/TargetTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class TargetTests: XCTestCase { 5 | 6 | func testHostTargetNameCopyValidity() throws { 7 | // Check that a copy of the target name can still be used after the lifetime 8 | // of the Target ends. 9 | let h = try Target.host() 10 | let n = h.name 11 | XCTAssertFalse(n.isEmpty) 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /Tests/LLVMTests/Types/ArrayTypeTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class ArrayTypeTests: XCTestCase { 5 | 6 | func testCount() { 7 | var m = Module("foo") 8 | let i16 = IntegerType(16, in: &m) 9 | XCTAssertEqual(ArrayType(8, i16, in: &m).count, 8) 10 | } 11 | 12 | func testElement() { 13 | var m = Module("foo") 14 | let i16 = IntegerType(16, in: &m) 15 | XCTAssertEqual(IntegerType(ArrayType(8, i16, in: &m).element), i16) 16 | } 17 | 18 | func testConversion() { 19 | var m = Module("foo") 20 | let i16 = IntegerType(16, in: &m) 21 | let t: IRType = ArrayType(8, i16, in: &m) 22 | XCTAssertNotNil(ArrayType(t)) 23 | let u: IRType = IntegerType(64, in: &m) 24 | XCTAssertNil(ArrayType(u)) 25 | } 26 | 27 | func testEquality() { 28 | var m = Module("foo") 29 | let i16 = IntegerType(16, in: &m) 30 | 31 | let t = ArrayType(8, i16, in: &m) 32 | let u = ArrayType(8, i16, in: &m) 33 | XCTAssertEqual(t, u) 34 | 35 | let v = ArrayType(16, i16, in: &m) 36 | XCTAssertNotEqual(t, v) 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /Tests/LLVMTests/Types/FloatingPointTypeTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class FloatingPointTypeTests: XCTestCase { 5 | 6 | func testConversion() { 7 | var m = Module("foo") 8 | 9 | let t0: IRType = FloatingPointType.half(in: &m) 10 | let t1: IRType = FloatingPointType.float(in: &m) 11 | let t2: IRType = FloatingPointType.double(in: &m) 12 | let t3: IRType = FloatingPointType.fp128(in: &m) 13 | for t in [t0, t1, t2, t3] { 14 | XCTAssertNotNil(FloatingPointType(t)) 15 | } 16 | 17 | let u: IRType = IntegerType(64, in: &m) 18 | XCTAssertNil(FloatingPointType(u)) 19 | } 20 | 21 | func testCallSyntax() { 22 | var m = Module("foo") 23 | let double = FloatingPointType.double(in: &m) 24 | XCTAssertEqual(double(1).value.value, 1, accuracy: .ulpOfOne) 25 | } 26 | 27 | func testEquality() { 28 | var m = Module("foo") 29 | let t = FloatingPointType.double(in: &m) 30 | let u = FloatingPointType.double(in: &m) 31 | XCTAssertEqual(t, u) 32 | 33 | let v = FloatingPointType.float(in: &m) 34 | XCTAssertNotEqual(t, v) 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Tests/LLVMTests/Types/FunctionTypeTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class FunctionTypeTests: XCTestCase { 5 | 6 | func testDefaultReturnType() { 7 | var m = Module("foo") 8 | XCTAssert(FunctionType(from: [], in: &m).returnType == VoidType(in: &m)) 9 | } 10 | 11 | func testReturnType() { 12 | var m = Module("foo") 13 | let t = IntegerType(64, in: &m) 14 | XCTAssert(FunctionType(from: [], to: t, in: &m).returnType == t) 15 | } 16 | 17 | func testParameters() { 18 | var m = Module("foo") 19 | let t = IntegerType(64, in: &m) 20 | let u = IntegerType(32, in: &m) 21 | 22 | let f0 = FunctionType(from: [], in: &m) 23 | XCTAssertEqual(f0.parameters.count, 0) 24 | 25 | let f1 = FunctionType(from: [t], in: &m) 26 | XCTAssertEqual(f1.parameters.count, 1) 27 | XCTAssert(f1.parameters[0] == t) 28 | 29 | let f2 = FunctionType(from: [t, u], in: &m) 30 | XCTAssertEqual(f2.parameters.count, 2) 31 | XCTAssert(f2.parameters[0] == t) 32 | XCTAssert(f2.parameters[1] == u) 33 | } 34 | 35 | func testConversion() { 36 | var m = Module("foo") 37 | let t: IRType = FunctionType(from: [], in: &m) 38 | XCTAssertNotNil(FunctionType(t)) 39 | let u: IRType = IntegerType(64, in: &m) 40 | XCTAssertNil(FunctionType(u)) 41 | } 42 | 43 | func testEquality() { 44 | var m = Module("foo") 45 | let t = IntegerType(64, in: &m) 46 | let u = IntegerType(32, in: &m) 47 | 48 | let f0 = FunctionType(from: [t, u], in: &m) 49 | let f1 = FunctionType(from: [t, u], in: &m) 50 | XCTAssertEqual(f0, f1) 51 | 52 | let f2 = FunctionType(from: [u, t], in: &m) 53 | XCTAssertNotEqual(f0, f2) 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /Tests/LLVMTests/Types/IRTypeTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class IRTypeTests: XCTestCase { 5 | 6 | func testIsSized() { 7 | var m = Module("foo") 8 | XCTAssert(IntegerType(64, in: &m).isSized) 9 | XCTAssertFalse(FunctionType(from: [], in: &m).isSized) 10 | } 11 | 12 | func testEqualty() { 13 | var m = Module("foo") 14 | let t = IntegerType(64, in: &m) 15 | let u = IntegerType(32, in: &m) 16 | 17 | XCTAssert(t == (t as IRType)) 18 | XCTAssert((t as IRType) == t) 19 | XCTAssert((t as IRType) == (t as IRType)) 20 | 21 | XCTAssert(t != (u as IRType)) 22 | XCTAssert((t as IRType) != u) 23 | XCTAssert((t as IRType) != (u as IRType)) 24 | } 25 | 26 | func testStringConvertible() { 27 | var m = Module("foo") 28 | let t = IntegerType(64, in: &m) 29 | XCTAssertEqual("\(t)", "\(t)", "Unstable string representation!") 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /Tests/LLVMTests/Types/IntegerTypeTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class IntegerTypeTests: XCTestCase { 5 | 6 | func testBitWidth() { 7 | var m = Module("foo") 8 | XCTAssertEqual(IntegerType(64, in: &m).bitWidth, 64) 9 | XCTAssertEqual(IntegerType(32, in: &m).bitWidth, 32) 10 | } 11 | 12 | func testCallSyntax() { 13 | var m = Module("foo") 14 | let i64 = IntegerType(64, in: &m) 15 | XCTAssertEqual(i64(1).sext, 1) 16 | } 17 | 18 | func testConversion() { 19 | var m = Module("foo") 20 | let t: IRType = IntegerType(64, in: &m) 21 | XCTAssertNotNil(IntegerType(t)) 22 | let u: IRType = FloatingPointType.float(in: &m) 23 | XCTAssertNil(IntegerType(u)) 24 | } 25 | 26 | func testEquality() { 27 | var m = Module("foo") 28 | let t = IntegerType(64, in: &m) 29 | let u = IntegerType(64, in: &m) 30 | XCTAssertEqual(t, u) 31 | 32 | let v = IntegerType(32, in: &m) 33 | XCTAssertNotEqual(t, v) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Tests/LLVMTests/Types/PointerTypeTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class PointerTypeTests: XCTestCase { 5 | 6 | func testDefaultAddressSpace() { 7 | var m = Module("foo") 8 | XCTAssertEqual(PointerType(in: &m).addressSpace, .default) 9 | } 10 | 11 | func testConversion() { 12 | var m = Module("foo") 13 | let t: IRType = PointerType(in: &m) 14 | XCTAssertNotNil(PointerType(t)) 15 | let u: IRType = IntegerType(64, in: &m) 16 | XCTAssertNil(PointerType(u)) 17 | } 18 | 19 | func testEquality() { 20 | var m = Module("foo") 21 | let t = PointerType(in: &m) 22 | let u = PointerType(in: &m) 23 | XCTAssertEqual(t, u) 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Tests/LLVMTests/Types/StructTypeTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class StructTypeTests: XCTestCase { 5 | 6 | func testInlineStruct() { 7 | var m = Module("foo") 8 | let t = IntegerType(64, in: &m) 9 | let s = StructType([t, t], in: &m) 10 | XCTAssert(s.isLiteral) 11 | XCTAssertFalse(s.isPacked) 12 | XCTAssertFalse(s.isOpaque) 13 | XCTAssertNil(s.name) 14 | } 15 | 16 | func testNamedStruct() { 17 | var m = Module("foo") 18 | let t = IntegerType(64, in: &m) 19 | let s = StructType(named: "S", [t, t], in: &m) 20 | XCTAssertFalse(s.isLiteral) 21 | XCTAssertFalse(s.isPacked) 22 | XCTAssertFalse(s.isOpaque) 23 | XCTAssertEqual(s.name, "S") 24 | } 25 | 26 | func testPackedStruct() { 27 | var m = Module("foo") 28 | let t = IntegerType(64, in: &m) 29 | XCTAssert(StructType([t, t], packed: true, in: &m).isPacked) 30 | XCTAssert(StructType(named: "S", [t, t], packed: true, in: &m).isPacked) 31 | } 32 | 33 | func testFields() { 34 | var m = Module("foo") 35 | let t = IntegerType(64, in: &m) 36 | let u = IntegerType(32, in: &m) 37 | 38 | let s0 = StructType([], in: &m) 39 | XCTAssertEqual(s0.fields.count, 0) 40 | 41 | let s1 = StructType([t], in: &m) 42 | XCTAssertEqual(s1.fields.count, 1) 43 | XCTAssert(s1.fields[0] == t) 44 | 45 | let s2 = StructType([t, u], in: &m) 46 | XCTAssertEqual(s2.fields.count, 2) 47 | XCTAssert(s2.fields[0] == t) 48 | XCTAssert(s2.fields[1] == u) 49 | } 50 | 51 | func testConversion() { 52 | var m = Module("foo") 53 | let t: IRType = StructType([], in: &m) 54 | XCTAssertNotNil(StructType(t)) 55 | let u: IRType = IntegerType(64, in: &m) 56 | XCTAssertNil(StructType(u)) 57 | } 58 | 59 | func testEquality() { 60 | var m = Module("foo") 61 | let t = IntegerType(64, in: &m) 62 | let u = IntegerType(32, in: &m) 63 | 64 | let s0 = StructType([t, u], in: &m) 65 | let s1 = StructType([t, u], in: &m) 66 | XCTAssertEqual(s0, s1) 67 | 68 | let s2 = StructType([u, t], in: &m) 69 | XCTAssertNotEqual(s0, s2) 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /Tests/LLVMTests/Types/VoidTypeTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class VoidTypeTests: XCTestCase { 5 | 6 | func testBitWidth() { 7 | var m = Module("foo") 8 | XCTAssertEqual(IntegerType(64, in: &m).bitWidth, 64) 9 | XCTAssertEqual(IntegerType(32, in: &m).bitWidth, 32) 10 | } 11 | 12 | func testConversion() { 13 | var m = Module("foo") 14 | let t: IRType = VoidType(in: &m) 15 | XCTAssertNotNil(VoidType(t)) 16 | let u: IRType = IntegerType(64, in: &m) 17 | XCTAssertNil(VoidType(u)) 18 | } 19 | 20 | func testEquality() { 21 | var m = Module("foo") 22 | let t = VoidType(in: &m) 23 | let u = VoidType(in: &m) 24 | XCTAssertEqual(t, u) 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Tests/LLVMTests/Utils/StringTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | @testable import SwiftyLLVM 4 | 5 | final class StringTests: XCTestCase { 6 | 7 | func testInitFromLLVM() { 8 | let text = UnsafeMutableBufferPointer.allocate(capacity: 2) 9 | defer { text.deallocate() } 10 | text.initialize(repeating: 65) 11 | 12 | func getter(source: Int, count: UnsafeMutablePointer?) -> UnsafePointer? { 13 | count?.pointee = source 14 | return UnsafePointer(text.baseAddress) 15 | } 16 | 17 | XCTAssertEqual(String(from: 0, readingWith: getter(source:count:)), "") 18 | XCTAssertEqual(String(from: 1, readingWith: getter(source:count:)), "A") 19 | XCTAssertEqual(String(from: 2, readingWith: getter(source:count:)), "AA") 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /Tests/LLVMTests/Values/Constants/ArrayConstantTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class ArrayConstantTests: XCTestCase { 5 | 6 | func testInit() { 7 | var m = Module("foo") 8 | let i32 = IntegerType(32, in: &m) 9 | 10 | let a = ArrayConstant( 11 | of: i32, containing: (0 ..< 5).map({ i32.constant($0) }), in: &m) 12 | XCTAssertEqual(a.count, 5) 13 | XCTAssertEqual(IntegerConstant(a[1]), i32.constant(1)) 14 | XCTAssertEqual(IntegerConstant(a[2]), i32.constant(2)) 15 | } 16 | 17 | func testInitFromBytes() { 18 | var m = Module("foo") 19 | 20 | let i8 = IntegerType(8, in: &m) 21 | let a = ArrayConstant(bytes: [0, 1, 2, 3, 4], in: &m) 22 | XCTAssertEqual(a.count, 5) 23 | XCTAssertEqual(IntegerConstant(a[1]), i8.constant(1)) 24 | XCTAssertEqual(IntegerConstant(a[2]), i8.constant(2)) 25 | } 26 | 27 | func testEquality() { 28 | var m = Module("foo") 29 | let i32 = IntegerType(32, in: &m) 30 | 31 | let a = ArrayConstant( 32 | of: i32, containing: (0 ..< 5).map({ i32.constant($0) }), in: &m) 33 | let b = ArrayConstant( 34 | of: i32, containing: (0 ..< 5).map({ i32.constant($0) }), in: &m) 35 | XCTAssertEqual(a, b) 36 | 37 | let c = ArrayConstant( 38 | of: i32, containing: (0 ..< 5).map({ i32.constant($0 + 1) }), in: &m) 39 | XCTAssertNotEqual(a, c) 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Tests/LLVMTests/Values/Constants/AttributeTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class AttributeTests: XCTestCase { 5 | 6 | func testEquality() { 7 | var m = Module("foo") 8 | let a = Function.Attribute(.cold, in: &m) 9 | let b = Function.Attribute(.cold, in: &m) 10 | XCTAssertEqual(a, b) 11 | 12 | let c = Function.Attribute(.hot, in: &m) 13 | XCTAssertNotEqual(a, c) 14 | } 15 | 16 | func testValue() { 17 | var m = Module("foo") 18 | XCTAssertEqual(Parameter.Attribute(.dereferenceable_or_null, 64, in: &m).value, 64) 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /Tests/LLVMTests/Values/Constants/FloatingPointConstantTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class FloatingPointConstantTests: XCTestCase { 5 | 6 | func testZero() { 7 | var m = Module("foo") 8 | let x = FloatingPointType.double(in: &m).zero 9 | XCTAssertEqual(x.value.value, 0.0, accuracy: .ulpOfOne) 10 | } 11 | 12 | func testInitWithDouble() { 13 | var m = Module("foo") 14 | let x = FloatingPointType.double(in: &m).constant(4.2) 15 | XCTAssertEqual(x.value.value, 4.2, accuracy: .ulpOfOne) 16 | } 17 | 18 | func testInitWithText() { 19 | var m = Module("foo") 20 | let x = FloatingPointType.double(in: &m).constant(parsing: "4.2") 21 | XCTAssertEqual(x.value.value, 4.2, accuracy: .ulpOfOne) 22 | } 23 | 24 | func testConversion() { 25 | var m = Module("foo") 26 | let t: IRValue = FloatingPointType.float(in: &m).zero 27 | XCTAssertNotNil(FloatingPointConstant(t)) 28 | let u: IRValue = IntegerType(64, in: &m).zero 29 | XCTAssertNil(FloatingPointConstant(u)) 30 | } 31 | 32 | func testEquality() { 33 | var m = Module("foo") 34 | let t = FloatingPointType.double(in: &m).zero 35 | let u = FloatingPointType.double(in: &m).zero 36 | XCTAssertEqual(t, u) 37 | 38 | let v = FloatingPointType.double(in: &m).constant(4.2) 39 | XCTAssertNotEqual(t, v) 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Tests/LLVMTests/Values/Constants/FunctionTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class FunctionTests: XCTestCase { 5 | 6 | func testWellFormed() { 7 | var m = Module("foo") 8 | let f = m.declareFunction("fn", .init(from: [], in: &m)) 9 | XCTAssert(f.isWellFormed()) 10 | m.appendBlock(to: f) 11 | XCTAssertFalse(f.isWellFormed()) 12 | } 13 | 14 | func testEntry() { 15 | var m = Module("foo") 16 | let f = m.declareFunction("fn", .init(from: [], in: &m)) 17 | XCTAssertNil(f.entry) 18 | m.appendBlock(to: f) 19 | XCTAssertNotNil(f.entry) 20 | } 21 | 22 | func testParameters() { 23 | var m = Module("foo") 24 | let t = IntegerType(64, in: &m) 25 | let u = IntegerType(32, in: &m) 26 | 27 | let f0 = m.declareFunction("f0", .init(from: [], in: &m)) 28 | XCTAssertEqual(f0.parameters.count, 0) 29 | 30 | let f1 = m.declareFunction("f1", .init(from: [t], in: &m)) 31 | XCTAssertEqual(f1.parameters.count, 1) 32 | XCTAssert(f1.parameters[0].type == t) 33 | 34 | let f2 = m.declareFunction("f2", .init(from: [t, u], in: &m)) 35 | XCTAssertEqual(f2.parameters.count, 2) 36 | XCTAssert(f2.parameters[0].type == t) 37 | XCTAssert(f2.parameters[1].type == u) 38 | } 39 | 40 | func testBasicBlocks() { 41 | var m = Module("foo") 42 | 43 | let f = m.declareFunction("f", .init(from: [], in: &m)) 44 | XCTAssertEqual(f.basicBlocks.count, 0) 45 | XCTAssert(f.basicBlocks.elementsEqual([])) 46 | 47 | let b0 = m.appendBlock(to: f) 48 | XCTAssertEqual(f.basicBlocks.count, 1) 49 | XCTAssert(f.basicBlocks.elementsEqual([b0])) 50 | 51 | let b1 = m.appendBlock(to: f) 52 | XCTAssertEqual(f.basicBlocks.count, 2) 53 | XCTAssert(f.basicBlocks.contains(b0)) 54 | XCTAssert(f.basicBlocks.contains(b1)) 55 | } 56 | 57 | func testBasicBlockIndices() { 58 | var m = Module("foo") 59 | let f = m.declareFunction("f", .init(from: [], in: &m)) 60 | XCTAssertEqual(f.basicBlocks.startIndex, f.basicBlocks.endIndex) 61 | 62 | m.appendBlock(to: f) 63 | XCTAssertEqual(f.basicBlocks.index(after: f.basicBlocks.startIndex), f.basicBlocks.endIndex) 64 | XCTAssertEqual(f.basicBlocks.index(before: f.basicBlocks.endIndex), f.basicBlocks.startIndex) 65 | 66 | m.appendBlock(to: f) 67 | let middle = f.basicBlocks.index(after: f.basicBlocks.startIndex) 68 | XCTAssertEqual(f.basicBlocks.index(after: middle), f.basicBlocks.endIndex) 69 | XCTAssertEqual(f.basicBlocks.index(before: f.basicBlocks.endIndex), middle) 70 | } 71 | 72 | func testAttributes() { 73 | var m = Module("foo") 74 | let f = m.declareFunction("f", .init(from: [], in: &m)) 75 | let a = Function.Attribute(.alwaysinline, in: &m) 76 | let b = Function.Attribute(.hot, in: &m) 77 | 78 | m.addAttribute(a, to: f) 79 | m.addAttribute(b, to: f) 80 | XCTAssertEqual(f.attributes.count, 2) 81 | XCTAssert(f.attributes.contains(a)) 82 | XCTAssert(f.attributes.contains(b)) 83 | 84 | XCTAssertEqual(m.addAttribute(named: .alwaysinline, to: f), a) 85 | 86 | m.removeAttribute(a, from: f) 87 | XCTAssertEqual(f.attributes, [b]) 88 | } 89 | 90 | func testReturnAttributes() { 91 | var m = Module("foo") 92 | let f = m.declareFunction("f", .init(from: [], to: PointerType(in: &m), in: &m)) 93 | let r = f.returnValue 94 | let a = Function.Return.Attribute(.noalias, in: &m) 95 | let b = Parameter.Attribute(.dereferenceable_or_null, 8, in: &m) 96 | 97 | m.addAttribute(a, to: r) 98 | m.addAttribute(b, to: r) 99 | XCTAssertEqual(r.attributes.count, 2) 100 | XCTAssert(r.attributes.contains(a)) 101 | XCTAssert(r.attributes.contains(b)) 102 | 103 | XCTAssertEqual(m.addAttribute(named: .noalias, to: r), a) 104 | 105 | m.removeAttribute(a, from: r) 106 | XCTAssertEqual(r.attributes, [b]) 107 | } 108 | 109 | func testConversion() { 110 | var m = Module("foo") 111 | let t: IRValue = m.declareFunction("fn", .init(from: [], in: &m)) 112 | XCTAssertNotNil(Function(t)) 113 | let u: IRValue = IntegerType(64, in: &m).zero 114 | XCTAssertNil(Function(u)) 115 | } 116 | 117 | func testEquality() { 118 | var m = Module("foo") 119 | let f = m.declareFunction("fn", .init(from: [], in: &m)) 120 | let g = m.declareFunction("fn", .init(from: [], in: &m)) 121 | XCTAssertEqual(f, g) 122 | 123 | let h = m.declareFunction("fn1", .init(from: [], in: &m)) 124 | XCTAssertNotEqual(f, h) 125 | } 126 | 127 | func testReturnEquality() { 128 | var m = Module("foo") 129 | let f = m.declareFunction("fn", .init(from: [], in: &m)).returnValue 130 | let g = m.declareFunction("fn", .init(from: [], in: &m)).returnValue 131 | XCTAssertEqual(f, g) 132 | 133 | let h = m.declareFunction("fn1", .init(from: [], in: &m)).returnValue 134 | XCTAssertNotEqual(f, h) 135 | } 136 | 137 | } 138 | -------------------------------------------------------------------------------- /Tests/LLVMTests/Values/Constants/IntegerConstantTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class IntegerConstantTests: XCTestCase { 5 | 6 | func testZero() { 7 | var m = Module("foo") 8 | let x = IntegerType(64, in: &m).zero 9 | XCTAssertEqual(x.sext, 0) 10 | XCTAssertEqual(x.zext, 0) 11 | } 12 | 13 | func testInitWithBitPattern() { 14 | var m = Module("foo") 15 | let x = IntegerType(8, in: &m).constant(255) 16 | XCTAssertEqual(x.sext, -1) 17 | XCTAssertEqual(x.zext, 255) 18 | } 19 | 20 | func testInitWithSignedValue() { 21 | var m = Module("foo") 22 | let x = IntegerType(8, in: &m).constant(-128) 23 | XCTAssertEqual(x.sext, -128) 24 | XCTAssertEqual(x.zext, 128) 25 | } 26 | 27 | func testInitWithWords() { 28 | var m = Module("foo") 29 | let x = IntegerType(8, in: &m).constant(words: [255]) 30 | XCTAssertEqual(x.sext, -1) 31 | XCTAssertEqual(x.zext, 255) 32 | } 33 | 34 | func testInitWithText() { 35 | var m = Module("foo") 36 | let x = IntegerType(8, in: &m).constant(parsing: "11111111", radix: 2) 37 | XCTAssertEqual(x.sext, -1) 38 | XCTAssertEqual(x.zext, 255) 39 | } 40 | 41 | func testConversion() { 42 | var m = Module("foo") 43 | let t: IRValue = IntegerType(64, in: &m).zero 44 | XCTAssertNotNil(IntegerConstant(t)) 45 | let u: IRValue = FloatingPointType.float(in: &m).zero 46 | XCTAssertNil(IntegerConstant(u)) 47 | } 48 | 49 | func testEquality() { 50 | var m = Module("foo") 51 | let t = IntegerType(64, in: &m).zero 52 | let u = IntegerType(64, in: &m).zero 53 | XCTAssertEqual(t, u) 54 | 55 | let v = IntegerType(64, in: &m).constant(255) 56 | XCTAssertNotEqual(t, v) 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /Tests/LLVMTests/Values/Constants/IntrinsicTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class IntinsicTests: XCTestCase { 5 | 6 | func testInit() { 7 | var m = Module("foo") 8 | XCTAssertNotNil(m.intrinsic(named: Intrinsic.llvm.va_start)) 9 | XCTAssertNil(m.intrinsic(named: Intrinsic.llvm.does_not_exist)) 10 | } 11 | 12 | func testIsOverloaded() throws { 13 | var m = Module("foo") 14 | let f = try XCTUnwrap(m.intrinsic(named: Intrinsic.llvm.va_start)) 15 | XCTAssertFalse(f.isOverloaded) 16 | 17 | let i16 = IntegerType(16, in: &m) 18 | let g = try XCTUnwrap(m.intrinsic(named: Intrinsic.llvm.smax, for: [i16])) 19 | XCTAssert(g.isOverloaded) 20 | } 21 | 22 | func testName() throws { 23 | var m = Module("foo") 24 | let f = try XCTUnwrap(m.intrinsic(named: Intrinsic.llvm.va_start)) 25 | XCTAssertEqual(f.name, "llvm.va_start") 26 | } 27 | 28 | func testEquality() throws { 29 | var m = Module("foo") 30 | let f = try XCTUnwrap(m.intrinsic(named: Intrinsic.llvm.va_start)) 31 | let g = try XCTUnwrap(m.intrinsic(named: Intrinsic.llvm.va_start)) 32 | XCTAssertEqual(f, g) 33 | 34 | let h = try XCTUnwrap(m.intrinsic(named: Intrinsic.llvm.va_end)) 35 | XCTAssertNotEqual(f, h) 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /Tests/LLVMTests/Values/Constants/ParameterTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class ParameterTests: XCTestCase { 5 | 6 | func testIndex() { 7 | var m = Module("foo") 8 | let i64 = IntegerType(64, in: &m) 9 | 10 | let f = m.declareFunction("fn", .init(from: [i64, i64], in: &m)) 11 | XCTAssertEqual(f.parameters[0].index, 0) 12 | XCTAssertEqual(f.parameters[1].index, 1) 13 | 14 | let p = Parameter(f.parameters[1] as IRValue) 15 | XCTAssertEqual(p?.index, 1) 16 | } 17 | 18 | func testParent() { 19 | var m = Module("foo") 20 | let i64 = IntegerType(64, in: &m) 21 | 22 | let f = m.declareFunction("fn", .init(from: [i64, i64], in: &m)) 23 | XCTAssertEqual(f.parameters[0].parent, f) 24 | } 25 | 26 | func testAttributes() { 27 | var m = Module("foo") 28 | let f = m.declareFunction("f", .init(from: [PointerType(in: &m)], in: &m)) 29 | let p = f.parameters[0] 30 | let a = Parameter.Attribute(.nofree, in: &m) 31 | let b = Parameter.Attribute(.dereferenceable_or_null, 8, in: &m) 32 | 33 | m.addAttribute(a, to: p) 34 | m.addAttribute(b, to: p) 35 | XCTAssertEqual(p.attributes.count, 2) 36 | XCTAssert(p.attributes.contains(a)) 37 | XCTAssert(p.attributes.contains(b)) 38 | 39 | XCTAssertEqual(m.addAttribute(named: .nofree, to: p), a) 40 | 41 | m.removeAttribute(a, from: p) 42 | XCTAssertEqual(p.attributes, [b]) 43 | } 44 | 45 | func testConversion() { 46 | var m = Module("foo") 47 | let i64 = IntegerType(64, in: &m) 48 | 49 | let p: IRValue = m.declareFunction("fn", .init(from: [i64], in: &m)).parameters[0] 50 | XCTAssertNotNil(Parameter(p)) 51 | let q: IRValue = IntegerType(64, in: &m).zero 52 | XCTAssertNil(Parameter(q)) 53 | } 54 | 55 | func testEquality() { 56 | var m = Module("foo") 57 | let i64 = IntegerType(64, in: &m) 58 | 59 | let p = m.declareFunction("fn", .init(from: [i64], in: &m)).parameters[0] 60 | let q = m.declareFunction("fn", .init(from: [i64], in: &m)).parameters[0] 61 | XCTAssertEqual(p, q) 62 | 63 | let r = m.declareFunction("fn1", .init(from: [i64], in: &m)).parameters[0] 64 | XCTAssertNotEqual(p, r) 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /Tests/LLVMTests/Values/Constants/PoisonTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class PoisonTests: XCTestCase { 5 | 6 | func testConversion() { 7 | var m = Module("foo") 8 | let t: IRValue = Poison(of: FloatingPointType.float(in: &m)) 9 | XCTAssertNotNil(Poison(t)) 10 | let u: IRValue = IntegerType(64, in: &m).zero 11 | XCTAssertNil(Poison(u)) 12 | } 13 | 14 | func testEquality() { 15 | var m = Module("foo") 16 | let t = Poison(of: FloatingPointType.double(in: &m)) 17 | let u = Poison(of: FloatingPointType.double(in: &m)) 18 | XCTAssertEqual(t, u) 19 | 20 | let v = Poison(of: FloatingPointType.float(in: &m)) 21 | XCTAssertNotEqual(t, v) 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /Tests/LLVMTests/Values/Constants/StringConstantTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class StringConstantTests: XCTestCase { 5 | 6 | func testInit() { 7 | var m = Module("foo") 8 | let t = StringConstant("Bonjour!", in: &m) 9 | XCTAssertEqual(t.value, "Bonjour!") 10 | } 11 | 12 | func testInitWithoutNullTerminator() { 13 | var m = Module("foo") 14 | let t = StringConstant("Bonjour!", nullTerminated: false, in: &m) 15 | XCTAssertEqual(t.value, "Bonjour!") 16 | } 17 | 18 | func testConversion() { 19 | var m = Module("foo") 20 | let t: IRValue = StringConstant("Bonjour!", in: &m) 21 | XCTAssertNotNil(StringConstant(t)) 22 | let u: IRValue = IntegerType(64, in: &m).zero 23 | XCTAssertNil(StringConstant(u)) 24 | } 25 | 26 | func testEquality() { 27 | var m = Module("foo") 28 | let t = StringConstant("Bonjour!", in: &m) 29 | let u = StringConstant("Bonjour!", in: &m) 30 | XCTAssertEqual(t, u) 31 | 32 | let v = StringConstant("Guten Tag!", in: &m) 33 | XCTAssertNotEqual(t, v) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Tests/LLVMTests/Values/Constants/StructConstantTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class StructConstantTests: XCTestCase { 5 | 6 | func testInitNamed() { 7 | var m = Module("foo") 8 | let i32 = IntegerType(32, in: &m) 9 | 10 | let t = StructType([i32, i32], in: &m) 11 | let a = StructConstant(of: t, aggregating: [i32.constant(4), i32.constant(2)], in: &m) 12 | XCTAssertEqual(a.count, 2) 13 | XCTAssertEqual(StructType(a.type), t) 14 | XCTAssertEqual(IntegerConstant(a[0]), i32.constant(4)) 15 | XCTAssertEqual(IntegerConstant(a[1]), i32.constant(2)) 16 | } 17 | 18 | func testInitFromValues() { 19 | var m = Module("foo") 20 | let i32 = IntegerType(32, in: &m) 21 | 22 | let a = StructConstant(aggregating: [i32.constant(4), i32.constant(2)], in: &m) 23 | XCTAssertEqual(a.count, 2) 24 | XCTAssertEqual(StructType(a.type)!.isPacked, false) 25 | XCTAssertEqual(IntegerConstant(a[0]), i32.constant(4)) 26 | XCTAssertEqual(IntegerConstant(a[1]), i32.constant(2)) 27 | } 28 | 29 | func testInitFromValuesPacked() { 30 | var m = Module("foo") 31 | let i32 = IntegerType(32, in: &m) 32 | 33 | let a = StructConstant(aggregating: [i32.constant(4), i32.constant(2)], packed: true, in: &m) 34 | XCTAssertEqual(a.count, 2) 35 | XCTAssertEqual(StructType(a.type)!.isPacked, true) 36 | XCTAssertEqual(IntegerConstant(a[0]), i32.constant(4)) 37 | XCTAssertEqual(IntegerConstant(a[1]), i32.constant(2)) 38 | } 39 | 40 | func testEquality() { 41 | var m = Module("foo") 42 | let i32 = IntegerType(32, in: &m) 43 | 44 | let a = StructConstant(aggregating: [i32.constant(4), i32.constant(2)], in: &m) 45 | let b = StructConstant(aggregating: [i32.constant(4), i32.constant(2)], in: &m) 46 | XCTAssertEqual(a, b) 47 | 48 | let c = StructConstant(aggregating: [i32.constant(2), i32.constant(4)], in: &m) 49 | XCTAssertNotEqual(a, c) 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /Tests/LLVMTests/Values/Constants/UndefinedTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class UndefinedTests: XCTestCase { 5 | 6 | func testConversion() { 7 | var m = Module("foo") 8 | let t: IRValue = Undefined(of: FloatingPointType.float(in: &m)) 9 | XCTAssertNotNil(Undefined(t)) 10 | let u: IRValue = IntegerType(64, in: &m).zero 11 | XCTAssertNil(Undefined(u)) 12 | } 13 | 14 | func testEquality() { 15 | var m = Module("foo") 16 | let t = Undefined(of: FloatingPointType.double(in: &m)) 17 | let u = Undefined(of: FloatingPointType.double(in: &m)) 18 | XCTAssertEqual(t, u) 19 | 20 | let v = Undefined(of: FloatingPointType.float(in: &m)) 21 | XCTAssertNotEqual(t, v) 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /Tests/LLVMTests/Values/GlobalVariableTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class GlobalVariableTests: XCTestCase { 5 | 6 | func testIsGlobalConstant() { 7 | var m = Module("foo") 8 | let g = m.declareGlobalVariable("gl", PointerType(in: &m)) 9 | XCTAssertFalse(g.isGlobalConstant) 10 | m.setGlobalConstant(true, for: g) 11 | XCTAssert(g.isGlobalConstant) 12 | } 13 | 14 | func testIsExternallyInitialized() { 15 | var m = Module("foo") 16 | let g = m.declareGlobalVariable("gl", PointerType(in: &m)) 17 | XCTAssertFalse(g.isExternallyInitialized) 18 | m.setExternallyInitialized(true, for: g) 19 | XCTAssert(g.isExternallyInitialized) 20 | } 21 | 22 | func testLinkage() { 23 | var m = Module("foo") 24 | let g = m.declareGlobalVariable("gl", PointerType(in: &m)) 25 | m.setLinkage(.private, for: g) 26 | XCTAssertEqual(g.linkage, .private) 27 | } 28 | 29 | func testInitializer() { 30 | var m = Module("foo") 31 | let i8 = IntegerType(8, in: &m) 32 | let g = m.declareGlobalVariable("x", i8) 33 | 34 | XCTAssertNil(g.initializer) 35 | m.setInitializer(i8.zero, for: g) 36 | XCTAssertEqual(g.initializer.map(IntegerConstant.init(_:)), i8.zero) 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /Tests/LLVMTests/Values/IRValueTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class IRValueTests: XCTestCase { 5 | 6 | func testName() { 7 | var m = Module("foo") 8 | let g = m.declareGlobalVariable("x", PointerType(in: &m)) 9 | XCTAssertEqual(g.name, "x") 10 | m.setName("y", for: g) 11 | XCTAssertEqual(g.name, "y") 12 | } 13 | 14 | func testIsNull() { 15 | var m = Module("foo") 16 | XCTAssert(IntegerType(64, in: &m).null.isNull) 17 | XCTAssertFalse(IntegerType(64, in: &m).constant(42).isNull) 18 | } 19 | 20 | func testIsConstant() { 21 | var m = Module("foo") 22 | XCTAssert(IntegerType(64, in: &m).null.isConstant) 23 | 24 | let f = m.declareFunction("fn", .init(from: [], in: &m)) 25 | let b = m.appendBlock(to: f) 26 | let i = m.insertAlloca(IntegerType(64, in: &m), at: m.endOf(b)) 27 | XCTAssertFalse(i.isConstant) 28 | } 29 | 30 | func testIsTerminator() { 31 | var m = Module("foo") 32 | let f = m.declareFunction("fn", .init(from: [], in: &m)) 33 | let b = m.appendBlock(to: f) 34 | 35 | let p = m.endOf(b) 36 | let i = m.insertAlloca(IntegerType(64, in: &m), at: p) 37 | XCTAssertFalse(i.isTerminator) 38 | let j = m.insertReturn(at: p) 39 | XCTAssert(j.isTerminator) 40 | } 41 | 42 | func testEqualty() { 43 | var m = Module("foo") 44 | let t = IntegerType(64, in: &m).null 45 | let u = IntegerType(32, in: &m).null 46 | 47 | XCTAssert(t == (t as IRValue)) 48 | XCTAssert((t as IRValue) == t) 49 | XCTAssert((t as IRValue) == (t as IRValue)) 50 | 51 | XCTAssert(t != (u as IRValue)) 52 | XCTAssert((t as IRValue) != u) 53 | XCTAssert((t as IRValue) != (u as IRValue)) 54 | } 55 | 56 | func testStringConvertible() { 57 | var m = Module("foo") 58 | let t = IntegerType(64, in: &m).null 59 | XCTAssertEqual("\(t)", "\(t)", "Unstable string representation!") 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /Tests/LLVMTests/Values/Instructions/AllocaTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class AllocaTests: XCTestCase { 5 | 6 | func testAllocatedType() { 7 | var m = Module("foo") 8 | let f = m.declareFunction("fn", .init(from: [], in: &m)) 9 | let b = m.appendBlock(to: f) 10 | let i = m.insertAlloca(IntegerType(64, in: &m), at: m.endOf(b)) 11 | XCTAssert(i.allocatedType == IntegerType(64, in: &m)) 12 | } 13 | 14 | func testConversion() { 15 | var m = Module("foo") 16 | let f = m.declareFunction("fn", .init(from: [], in: &m)) 17 | let b = m.appendBlock(to: f) 18 | let i: IRValue = m.insertAlloca(IntegerType(64, in: &m), at: m.endOf(b)) 19 | XCTAssertNotNil(Alloca(i)) 20 | let u: IRValue = IntegerType(64, in: &m).zero 21 | XCTAssertNil(Alloca(u)) 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /Tests/LLVMTests/Values/Instructions/SwitchTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftyLLVM 2 | import XCTest 3 | 4 | final class SwitchTests: XCTestCase { 5 | 6 | func testSwitch() { 7 | var m = Module("foo") 8 | let f = m.declareFunction("fn", .init(from: [], in: &m)) 9 | let b = m.appendBlock(to: f) 10 | 11 | let c0 = m.appendBlock(to: f) 12 | let c1 = m.appendBlock(to: f) 13 | let c2 = m.appendBlock(to: f) 14 | 15 | _ = m.insertSwitch( 16 | on: m.i16(0), 17 | cases: [(m.i16(0), c0), (m.i16(1), c1)], 18 | default: c2, 19 | at: m.endOf(b)) 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /Tools/make-pkgconfig.sh: -------------------------------------------------------------------------------- 1 | ../.devcontainer/make-pkgconfig.sh -------------------------------------------------------------------------------- /cmake/TopLevelDefaults.cmake: -------------------------------------------------------------------------------- 1 | # Commands used to create an easy development environment when 2 | # building this project directly (not as a dependency). 3 | 4 | # Without this, generated Xcode projects aren't debuggable. 5 | set(CMAKE_XCODE_GENERATE_SCHEME YES) 6 | 7 | # 8 | # Hylo-standard dependency resolution. 9 | # 10 | include(FetchContent) 11 | 12 | block() 13 | 14 | set(FETCHCONTENT_TRY_FIND_PACKAGE_MODE NEVER) 15 | FetchContent_Declare(Hylo-CMakeModules 16 | GIT_REPOSITORY https://github.com/hylo-lang/CMakeModules.git 17 | GIT_TAG 6577fca 18 | OVERRIDE_FIND_PACKAGE 19 | ) 20 | 21 | endblock() 22 | FetchContent_MakeAvailable(Hylo-CMakeModules) 23 | 24 | list(PREPEND CMAKE_MODULE_PATH ${hylo-cmakemodules_SOURCE_DIR}) 25 | --------------------------------------------------------------------------------