├── .github ├── actions │ └── build-opencl-clang │ │ └── action.yml ├── dependabot.yml └── workflows │ ├── codeql.yml │ ├── on-demand-verification.yml │ ├── on-push-verification-in-tree.yml │ ├── on-push-verification-out-of-tree.yml │ ├── patch-release.yml │ └── scheduled-verification.yml ├── .travis.yml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── SECURITY.md ├── binary_result.h ├── cl_headers ├── CMakeLists.txt ├── OpenCL.rc ├── module.modulemap └── resource.h ├── cmake └── modules │ └── CMakeFunctions.cmake ├── linux_linker ├── CMakeLists.txt └── linux_resource_linker.cpp ├── opencl_clang.cpp ├── opencl_clang.h ├── opencl_clang.map ├── opencl_clang_options.td ├── options.cpp ├── options.h ├── options_compile.cpp ├── pch_mgr.cpp └── pch_mgr.h /.github/actions/build-opencl-clang/action.yml: -------------------------------------------------------------------------------- 1 | # ===--- 2 | # Main opencl-clang building script 3 | # ===--- 4 | 5 | name: Build opencl-clang 6 | inputs: 7 | ref_llvm: 8 | description: 'LLVM ref to build with' 9 | required: true 10 | ref_translator: 11 | description: 'SPIRV-LLVM-Translator ref to build with' 12 | required: true 13 | ref_opencl-clang: 14 | description: 'opencl-clang ref to build with' 15 | required: true 16 | build_type: 17 | description: 'Build type to pass to CMake' 18 | required: false 19 | default: Release 20 | 21 | runs: 22 | using: 'composite' 23 | steps: 24 | 25 | # Setup git credentials to make applying patches possible 26 | - run: | 27 | git config --global user.email "action@intel.com" 28 | git config --global user.name "Action Bot" 29 | shell: bash 30 | 31 | - name: Checkout LLVM 32 | uses: actions/checkout@v3 33 | with: 34 | repository: llvm/llvm-project 35 | path: llvm-project 36 | ref: ${{ inputs.ref_llvm }} 37 | 38 | - name: Checkout SPIRV-LLVM-Translator 39 | uses: actions/checkout@v3 40 | with: 41 | repository: KhronosGroup/SPIRV-LLVM-Translator 42 | path: llvm-project/SPIRV-LLVM-Translator 43 | ref: ${{ inputs.ref_translator }} 44 | 45 | - name: Checkout opencl-clang 46 | uses: actions/checkout@v3 47 | with: 48 | path: llvm-project/opencl-clang 49 | ref: ${{ inputs.ref_opencl-clang }} 50 | 51 | - name: Configure 52 | shell: bash 53 | run: | 54 | mkdir build && cd build 55 | cmake ${{ github.workspace }}/llvm-project/llvm \ 56 | -DLLVM_ENABLE_PROJECTS="clang" \ 57 | -DLLVM_EXTERNAL_PROJECTS="llvm-spirv;opencl-clang" \ 58 | -DLLVM_EXTERNAL_LLVM_SPIRV_SOURCE_DIR=${{ github.workspace }}/llvm-project/SPIRV-LLVM-Translator \ 59 | -DLLVM_EXTERNAL_OPENCL_CLANG_SOURCE_DIR=${{ github.workspace }}/llvm-project/opencl-clang \ 60 | -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} \ 61 | -DLLVM_TARGETS_TO_BUILD="X86" \ 62 | -G "Unix Makefiles" 63 | 64 | - name: Build 65 | shell: bash 66 | run: | 67 | cd build 68 | make opencl-clang -j8 69 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Set update schedule for GitHub Actions 2 | 3 | version: 2 4 | updates: 5 | 6 | - package-ecosystem: "github-actions" 7 | directory: "/" 8 | schedule: 9 | interval: "monthly" 10 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | permissions: 10 | contents: read 11 | 12 | env: 13 | LLVM_VERSION: 21 14 | LLVM_VERSION_MINOR: 0 15 | 16 | jobs: 17 | analyze: 18 | name: Analyze 19 | 20 | runs-on: ubuntu-latest 21 | 22 | permissions: 23 | # required for all workflows 24 | security-events: write 25 | 26 | # required to fetch internal or private CodeQL packs 27 | packages: read 28 | 29 | strategy: 30 | fail-fast: false 31 | matrix: 32 | include: 33 | - language: c-cpp 34 | build-mode: manual 35 | 36 | steps: 37 | 38 | - name: Install llvm and its dependencies 39 | run: | 40 | curl -L "https://apt.llvm.org/llvm-snapshot.gpg.key" | sudo apt-key add - 41 | curl -L "https://packages.lunarg.com/lunarg-signing-key-pub.asc" | sudo apt-key add - 42 | echo "deb https://apt.llvm.org/jammy/ llvm-toolchain-jammy main" | sudo tee -a /etc/apt/sources.list 43 | echo "deb https://packages.lunarg.com/vulkan jammy main" | sudo tee -a /etc/apt/sources.list 44 | sudo apt-get update 45 | sudo apt-get -yq --no-install-suggests --no-install-recommends install \ 46 | clang-${{ env.LLVM_VERSION }} \ 47 | clang-tools-${{ env.LLVM_VERSION }} \ 48 | llvm-${{ env.LLVM_VERSION }}-dev \ 49 | libllvmlibc-${{ env.LLVM_VERSION }}-dev \ 50 | libclang-${{ env.LLVM_VERSION }}-dev \ 51 | libclang-cpp${{ env.LLVM_VERSION }}-dev \ 52 | libpolly-${{ env.LLVM_VERSION }}-dev \ 53 | libzstd-dev \ 54 | libedit-dev \ 55 | mlir-${{ env.LLVM_VERSION }}-tools 56 | 57 | - name: Checkout opencl-clang sources for action files 58 | uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 59 | with: 60 | ref: ${{ github.ref }} 61 | 62 | - name: Checkout SPIRV-LLVM-Translator sources 63 | uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 64 | with: 65 | repository: KhronosGroup/SPIRV-LLVM-Translator 66 | path: SPIRV-LLVM-Translator 67 | ref: main 68 | 69 | - name: Build SPIRV-LLVM-Translator 70 | run: | 71 | builddir=${{ github.workspace }}/SPIRV-LLVM-Translator/build 72 | cmake -B "$builddir" \ 73 | ${{ github.workspace }}/SPIRV-LLVM-Translator \ 74 | -DLLVM_INCLUDE_TESTS=OFF \ 75 | -DCMAKE_INSTALL_PREFIX="$builddir"/install \ 76 | -DCMAKE_BUILD_TYPE=Release 77 | cmake --build "$builddir" -j $(nproc) 78 | cmake --install "$builddir" 79 | echo "spirv-translator-dir=${builddir}/install" >> $GITHUB_ENV 80 | 81 | - name: Initialize CodeQL 82 | uses: github/codeql-action/init@f079b8493333aace61c81488f8bd40919487bd9f # v3.25.7 83 | with: 84 | languages: ${{ matrix.language }} 85 | build-mode: ${{ matrix.build-mode }} 86 | 87 | - name: Build opencl-clang 88 | run: | 89 | mkdir build && cd build 90 | cmake ${{ github.workspace }} \ 91 | -DPREFERRED_LLVM_VERSION="${{ env.LLVM_VERSION }}.${{ env.LLVM_VERSION_MINOR }}" \ 92 | -DLLVMSPIRV_INCLUDED_IN_LLVM=OFF \ 93 | -DSPIRV_TRANSLATOR_DIR=${{ env.spirv-translator-dir }} \ 94 | -DCMAKE_BUILD_TYPE=Release 95 | cmake --build . -j $(nproc) 96 | 97 | - name: Perform CodeQL Analysis 98 | uses: github/codeql-action/analyze@f079b8493333aace61c81488f8bd40919487bd9f # v3.25.7 99 | with: 100 | category: "/language:${{matrix.language}}" 101 | -------------------------------------------------------------------------------- /.github/workflows/on-demand-verification.yml: -------------------------------------------------------------------------------- 1 | # ===--- 2 | # To be run manually by maintainers 3 | # ===--- 4 | 5 | name: On demand verification 6 | run-name: 'On demand by ${{ github.actor }}' 7 | 8 | permissions: 9 | contents: read 10 | 11 | on: 12 | workflow_dispatch: 13 | inputs: 14 | ref_llvm: 15 | description: 'LLVM ref to build with' 16 | required: true 17 | default: main 18 | ref_translator: 19 | description: 'SPIRV-LLVM-Translator ref to build with' 20 | required: true 21 | default: main 22 | ref_opencl-clang: 23 | description: 'opencl-clang ref to build with' 24 | required: true 25 | default: main 26 | build_type: 27 | description: 'Build type to pass to CMake' 28 | required: true 29 | default: Release 30 | type: choice 31 | options: 32 | - Release 33 | - Debug 34 | - RelWithDebInfo 35 | 36 | jobs: 37 | 38 | verify_on_demand: 39 | runs-on: ubuntu-22.04 40 | steps: 41 | 42 | - name: Checkout opencl-clang sources for action files availabilty 43 | uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 44 | 45 | - name: Run build-opencl-clang action 46 | uses: ./.github/actions/build-opencl-clang 47 | with: 48 | ref_llvm: ${{ inputs.ref_llvm }} 49 | ref_translator: ${{ inputs.ref_translator }} 50 | ref_opencl-clang: ${{ inputs.ref_opencl-clang }} 51 | -------------------------------------------------------------------------------- /.github/workflows/on-push-verification-in-tree.yml: -------------------------------------------------------------------------------- 1 | # ===--- 2 | # Running on push & pull_request. 3 | # This workflow parses the destination branch 4 | # to choose correct dependencies revisions 5 | # ===--- 6 | 7 | name: In-tree build 8 | run-name: '${{ github.event_name }}: ${{ github.base_ref }} ${{ github.ref_name }}' # github.base_ref null for 'on: push' 9 | 10 | permissions: 11 | contents: read 12 | 13 | on: 14 | push: 15 | branches: 16 | - main 17 | - ocl-open-* 18 | pull_request: 19 | branches: 20 | - main 21 | - ocl-open-* 22 | types: 23 | - opened 24 | - reopened 25 | - synchronize # commit pushed to the PR 26 | - ready_for_review # moved from draft state 27 | 28 | jobs: 29 | 30 | verify_default_branch: 31 | name: Linux 32 | # ref_name for 'on: push' 33 | # base_ref for 'on: pull_request' 34 | runs-on: ubuntu-22.04 35 | steps: 36 | 37 | - name: Checkout opencl-clang sources for action files 38 | uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 39 | 40 | - name: Run build-opencl-clang action 41 | uses: ./.github/actions/build-opencl-clang 42 | with: 43 | ref_llvm: main 44 | ref_translator: main 45 | ref_opencl-clang: ${{ github.ref }} 46 | -------------------------------------------------------------------------------- /.github/workflows/on-push-verification-out-of-tree.yml: -------------------------------------------------------------------------------- 1 | # ===--- 2 | # Running on push & pull_request. 3 | # ===--- 4 | 5 | name: Out-of-tree build 6 | run-name: '${{ github.event_name }}: ${{ github.base_ref }} ${{ github.ref_name }}' # github.base_ref null for 'on: push' 7 | 8 | permissions: 9 | contents: read 10 | 11 | env: 12 | LLVM_VERSION: 21 13 | LLVM_VERSION_MINOR: 0 14 | 15 | on: 16 | push: 17 | branches: 18 | - main 19 | pull_request: 20 | branches: 21 | - main 22 | types: 23 | - opened 24 | - reopened 25 | - synchronize # commit pushed to the PR 26 | - ready_for_review # moved from draft state 27 | 28 | jobs: 29 | 30 | verify_default_branch: 31 | name: linux 32 | # ref_name for 'on: push' 33 | # base_ref for 'on: pull_request' 34 | runs-on: ubuntu-22.04 35 | steps: 36 | 37 | - name: Install llvm and its dependencies 38 | run: | 39 | curl -L "https://apt.llvm.org/llvm-snapshot.gpg.key" | sudo apt-key add - 40 | curl -L "https://packages.lunarg.com/lunarg-signing-key-pub.asc" | sudo apt-key add - 41 | echo "deb https://apt.llvm.org/jammy/ llvm-toolchain-jammy main" | sudo tee -a /etc/apt/sources.list 42 | echo "deb https://packages.lunarg.com/vulkan jammy main" | sudo tee -a /etc/apt/sources.list 43 | sudo apt-get update 44 | sudo apt-get -yq --no-install-suggests --no-install-recommends install \ 45 | clang-${{ env.LLVM_VERSION }} \ 46 | clang-tools-${{ env.LLVM_VERSION }} \ 47 | llvm-${{ env.LLVM_VERSION }}-dev \ 48 | libllvmlibc-${{ env.LLVM_VERSION }}-dev \ 49 | libclang-${{ env.LLVM_VERSION }}-dev \ 50 | libclang-cpp${{ env.LLVM_VERSION }}-dev \ 51 | libpolly-${{ env.LLVM_VERSION }}-dev \ 52 | libzstd-dev \ 53 | libedit-dev \ 54 | mlir-${{ env.LLVM_VERSION }}-tools 55 | 56 | - name: Checkout SPIRV-LLVM-Translator sources 57 | uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 58 | with: 59 | repository: KhronosGroup/SPIRV-LLVM-Translator 60 | path: SPIRV-LLVM-Translator 61 | ref: main 62 | 63 | - name: Build SPIRV-LLVM-Translator 64 | run: | 65 | builddir=${{ github.workspace }}/SPIRV-LLVM-Translator/build 66 | cmake -B "$builddir" \ 67 | ${{ github.workspace }}/SPIRV-LLVM-Translator \ 68 | -DLLVM_INCLUDE_TESTS=OFF \ 69 | -DCMAKE_INSTALL_PREFIX="$builddir"/install \ 70 | -DCMAKE_BUILD_TYPE=Release 71 | cmake --build "$builddir" -j $(nproc) 72 | cmake --install "$builddir" 73 | echo "spirv-translator-dir=${builddir}/install" >> $GITHUB_ENV 74 | 75 | - name: Checkout opencl-clang sources 76 | uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 77 | with: 78 | path: opencl-clang 79 | ref: ${{ github.ref }} 80 | 81 | - name: Build opencl-clang 82 | run: | 83 | mkdir build && cd build 84 | cmake ${{ github.workspace }}/opencl-clang \ 85 | -DPREFERRED_LLVM_VERSION="${{ env.LLVM_VERSION }}.${{ env.LLVM_VERSION_MINOR }}" \ 86 | -DLLVMSPIRV_INCLUDED_IN_LLVM=OFF \ 87 | -DSPIRV_TRANSLATOR_DIR=${{ env.spirv-translator-dir }} \ 88 | -DCMAKE_BUILD_TYPE=Release 89 | cmake --build . -j $(nproc) 90 | -------------------------------------------------------------------------------- /.github/workflows/patch-release.yml: -------------------------------------------------------------------------------- 1 | name: Generate patch releases 2 | 3 | permissions: 4 | contents: read 5 | 6 | on: 7 | workflow_dispatch: 8 | schedule: 9 | # First day of every month 10 | - cron: '0 0 1 * *' 11 | 12 | jobs: 13 | setup: 14 | runs-on: ubuntu-latest 15 | outputs: 16 | latest_branch: ${{steps.latest_branch.outputs.latest_branch}} 17 | branches_json: ${{steps.release_branches.outputs.branches_json}} 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v4 21 | with: 22 | fetch-depth: 0 23 | - name: Get latest llvm_release branch 24 | id: latest_branch 25 | run: | 26 | git branch -r \ 27 | | grep 'ocl-open-' \ 28 | | sed -E 's/.*\/ocl-open-([0-9]+)/\1/' \ 29 | | sort -n -r \ 30 | | head -1 \ 31 | | xargs printf "latest_branch=ocl-open-%s" \ 32 | >> $GITHUB_OUTPUT 33 | - name: Get branch list 34 | id: release_branches 35 | run: | 36 | git branch -r \ 37 | | grep "origin/ocl-open-" \ 38 | | sed -E 's/\ *origin\/([^\ ]*)/\"\1\"/' \ 39 | | paste -sd',' \ 40 | | xargs -0 -d"\n" printf 'branches_json={"branch":[%s]}' \ 41 | >> $GITHUB_OUTPUT 42 | release: 43 | permissions: 44 | # required by softprops/action-gh-release to create a release 45 | contents: write 46 | runs-on: ubuntu-latest 47 | needs: setup 48 | strategy: 49 | matrix: ${{fromJson(needs.setup.outputs.branches_json)}} 50 | steps: 51 | - name: Checkout 52 | uses: actions/checkout@v4 53 | with: 54 | ref: ${{ matrix.branch }} 55 | fetch-depth: 0 56 | - name: Get commits info 57 | id: versions 58 | run: | 59 | export LATEST_VERSION=\ 60 | "$(git describe --tags --abbrev=0 --match 'v*')" 61 | export LLVM_VERSION=$(echo $LATEST_VERSION \ 62 | | sed -E 's/v([0-9]+\.[0-9]+)\.([0-9]+).*/\1/') 63 | export PATCH=$(echo $LATEST_VERSION \ 64 | | sed -E 's/(v[0-9]+\.[0-9]+)\.([0-9]+).*/\2/') 65 | echo "llvm_version=$LLVM_VERSION" >> $GITHUB_OUTPUT 66 | echo "patch=$PATCH" >> $GITHUB_OUTPUT 67 | echo "latest_version=${LATEST_VERSION}" >> $GITHUB_OUTPUT 68 | echo "release_version=${LLVM_VERSION}.$((${PATCH}+1))" \ 69 | >> $GITHUB_OUTPUT 70 | git rev-list ${LATEST_VERSION}..HEAD --count \ 71 | | xargs printf "commits_since_last_release=%d\n" >> $GITHUB_OUTPUT 72 | git rev-parse HEAD | xargs printf "last_commit=%s\n" >> $GITHUB_OUTPUT 73 | - name: Get SPIRV-LLVM-Translator and llvm-project latest tags 74 | id: llvm-spirv-versions 75 | run: | 76 | export SPIRV_PATCH=\ 77 | $(git ls-remote --tags \ 78 | "https://github.com/KhronosGroup/SPIRV-LLVM-Translator" \ 79 | "refs/tags/v${{ steps.versions.outputs.llvm_version }}.[0-9]" \ 80 | "refs/tags/v${{ steps.versions.outputs.llvm_version }}.[0-9][0-9]" \ 81 | | awk '{print $2}' \ 82 | | sed -E 's/refs\/tags\/v${{ steps.versions.outputs.llvm_version }}.([0-9]+)/\1/' \ 83 | | sort -n \ 84 | | tail -1) 85 | echo "spirv_patch=${SPIRV_PATCH}" >> $GITHUB_OUTPUT 86 | export LLVM_PATCH=\ 87 | $(git ls-remote --tags \ 88 | "https://github.com/llvm/llvm-project" \ 89 | "refs/tags/llvmorg-${{ steps.versions.outputs.llvm_version }}.[0-9]" \ 90 | "refs/tags/llvmorg-${{ steps.versions.outputs.llvm_version }}.[0-9][0-9]" \ 91 | | awk '{print $2}' \ 92 | | sed -E 's/refs\/tags\/llvmorg-${{ steps.versions.outputs.llvm_version }}.([0-9]+)/\1/' \ 93 | | sort -n \ 94 | | tail -1) 95 | echo "llvm_patch=${LLVM_PATCH}" >> $GITHUB_OUTPUT 96 | - name: Release 97 | uses: softprops/action-gh-release@v2 98 | if: ${{ steps.versions.outputs.commits_since_last_release != 0 }} 99 | with: 100 | # Setting tag to have format: 101 | # %latest llvm version%.%latest patch + 1% 102 | tag_name: v${{ steps.versions.outputs.release_version }} 103 | # We have to set this so tag is set on the branch we are releasing 104 | target_commitish: ${{ steps.versions.outputs.last_commit }} 105 | # We don't want to mark patch releases latest unless it is latest 106 | # major version 107 | make_latest: >- 108 | ${{ needs.setup.outputs.latest_branch == matrix.branch }} 109 | name: > 110 | opencl-clang linked against LLVM 111 | v${{ steps.versions.outputs.llvm_version }} 112 | libraries 113 | # TODO: update 114 | body: "This release is linked against LLVM \ 115 | v${{ steps.versions.outputs.llvm_version }}.${{ steps.llvm-spirv-versions.outputs.llvm_patch }} \ 116 | and SPIR-V LLVM translator \ 117 | v${{ steps.versions.outputs.llvm_version }}.${{ steps.llvm-spirv-versions.outputs.spirv_patch }}. \ 118 | Full Changelog: ${{ github.server_url }}/\ 119 | ${{ github.repository }}/compare/\ 120 | ${{ steps.versions.outputs.latest_version }}...\ 121 | v${{ steps.versions.outputs.release_version }}" 122 | -------------------------------------------------------------------------------- /.github/workflows/scheduled-verification.yml: -------------------------------------------------------------------------------- 1 | # ===--- 2 | # Workflow run for regular SPIRV-LLVM-Translator and LLVM compatibility check 3 | # ===--- 4 | 5 | name: Scheduled verification 6 | run-name: Scheduled verification 7 | 8 | permissions: 9 | contents: read 10 | 11 | on: 12 | schedule: 13 | # Run Sunday & Wednesday at 00:00 14 | - cron: 0 0 * * 0,3 15 | 16 | jobs: 17 | 18 | verify-default-branches: 19 | name: Verify `main` branch 20 | runs-on: ubuntu-22.04 21 | steps: 22 | 23 | - name: Checkout opencl-clang sources for action files availabilty 24 | uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 25 | 26 | - name: Run build-opencl-clang action 27 | uses: ./.github/actions/build-opencl-clang 28 | with: 29 | ref_llvm: main 30 | ref_translator: main 31 | ref_opencl-clang: main 32 | 33 | verify-release-branches: 34 | name: Verify `ocl-open-${{ matrix.llvm_version }}` release branch 35 | strategy: 36 | matrix: 37 | llvm_version: [ 14, 15, 16, 17, 18, 19, 20 ] 38 | runs-on: ubuntu-22.04 39 | steps: 40 | 41 | - name: Checkout opencl-clang sources for action files availabilty 42 | uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 43 | 44 | - name: Run build-opencl-clang action 45 | uses: ./.github/actions/build-opencl-clang 46 | with: 47 | ref_llvm: release/${{ matrix.llvm_version }}.x 48 | ref_translator: llvm_release_${{ matrix.llvm_version }}0 49 | ref_opencl-clang: ocl-open-${{ matrix.llvm_version }}0 50 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | os: 4 | - linux 5 | 6 | # Use Ubuntu 18.04 LTS (Bionic) as the Linux testing environment. 7 | dist: bionic 8 | 9 | git: 10 | depth: 1 11 | 12 | branches: 13 | only: 14 | - master 15 | 16 | env: 17 | global: 18 | - LLVM_VERSION=12 19 | matrix: 20 | - BUILD_TYPE=Release 21 | - BUILD_TYPE=Debug 22 | 23 | before_install: 24 | - curl -L "https://apt.llvm.org/llvm-snapshot.gpg.key" | sudo apt-key add - 25 | - echo "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic main" | sudo tee -a ${TRAVIS_ROOT}/etc/apt/sources.list 26 | - sudo apt-get update 27 | - sudo apt-get -yq --no-install-suggests --no-install-recommends install 28 | llvm-${LLVM_VERSION}-dev 29 | llvm-${LLVM_VERSION}-tools 30 | libclang-${LLVM_VERSION}-dev 31 | libclang-cpp${LLVM_VERSION}-dev 32 | 33 | install: 34 | - wget https://github.com/KhronosGroup/SPIRV-LLVM-Translator/releases/download/dev-build/SPIRV-LLVM-Translator-dev-build-linux-Release.zip -O /tmp/SPIRV-LLVM-Translator-dev-build-linux-${BUILD_TYPE}.zip 35 | - unzip /tmp/SPIRV-LLVM-Translator-dev-build-linux-${BUILD_TYPE}.zip -d spirv-llvm-translator 36 | 37 | compiler: 38 | - gcc 39 | - clang 40 | 41 | script: 42 | - mkdir build && cd build 43 | - cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DLLVM_NO_DEAD_STRIP=ON -DLLVMSPIRV_INCLUDED_IN_LLVM=OFF -DSPIRV_TRANSLATOR_DIR=./spirv-llvm-translator -DCMAKE_INSTALL_PREFIX=./install .. 44 | - make install 45 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13.4) 2 | 3 | if(NOT DEFINED OPENCL_CLANG_BUILD_EXTERNAL) 4 | # check if we build inside llvm or not 5 | if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) 6 | set(OPENCL_CLANG_BUILD_EXTERNAL YES) 7 | endif(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) 8 | endif(NOT DEFINED OPENCL_CLANG_BUILD_EXTERNAL) 9 | 10 | if(OPENCL_CLANG_BUILD_EXTERNAL) 11 | project(OPENCL_CLANG 12 | LANGUAGES 13 | CXX 14 | C 15 | ) 16 | endif() 17 | 18 | # Do not omit TARGET_OBJECTS expression from the SOURCES target 19 | # property 20 | # `cmake --help-policy CMP0051` for details. 21 | cmake_policy(SET CMP0051 NEW) 22 | cmake_policy(SET CMP0057 NEW) 23 | cmake_policy(SET CMP0022 NEW) 24 | 25 | set(CMAKE_MODULE_PATH 26 | ${CMAKE_MODULE_PATH} 27 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules") 28 | 29 | include(CMakeFunctions) 30 | 31 | if(CMAKE_CROSSCOMPILING AND OPENCL_CLANG_BUILD_EXTERNAL) 32 | include(CrossCompile) 33 | llvm_create_cross_target(${PROJECT_NAME} NATIVE "" Release) 34 | endif() 35 | 36 | if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) 37 | set(USE_PREBUILT_LLVM ON) 38 | 39 | add_definitions(-DUSE_PREBUILT_LLVM) 40 | 41 | if(NOT PREFERRED_LLVM_VERSION) 42 | set(PREFERRED_LLVM_VERSION "21.0") 43 | endif(NOT PREFERRED_LLVM_VERSION) 44 | message(STATUS "[OPENCL-CLANG] Looking for LLVM version ${PREFERRED_LLVM_VERSION}") 45 | find_package(LLVM ${PREFERRED_LLVM_VERSION} REQUIRED) 46 | 47 | message(STATUS "[OPENCL-CLANG] Using LLVMConfig.cmake in: ${LLVM_DIR}") 48 | message(STATUS "[OPENCL-CLANG] Found LLVM ${LLVM_PACKAGE_VERSION}") 49 | 50 | set(CMAKE_MODULE_PATH 51 | ${CMAKE_MODULE_PATH} 52 | ${LLVM_CMAKE_DIR}) 53 | 54 | set(CMAKE_CXX_STANDARD 17) 55 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 56 | 57 | option(LLVMSPIRV_INCLUDED_IN_LLVM 58 | "Set to ON if libLLVMSPIRVLib is linked into libLLVM" ON) 59 | if(LLVMSPIRV_INCLUDED_IN_LLVM) 60 | message(STATUS "[OPENCL-CLANG] Assuming that libLLVMSPIRVLib is linked into libLLVM") 61 | else(LLVMSPIRV_INCLUDED_IN_LLVM) 62 | message(STATUS 63 | "[OPENCL-CLANG] Assuming that libLLVMSPIRVLib is NOT linked into libLLVM") 64 | if(NOT SPIRV_TRANSLATOR_DIR) 65 | message(FATAL_ERROR "[OPENCL-CLANG] SPIRV_TRANSLATOR_DIR is required") 66 | endif(NOT SPIRV_TRANSLATOR_DIR) 67 | endif(LLVMSPIRV_INCLUDED_IN_LLVM) 68 | else(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) 69 | set(USE_PREBUILT_LLVM OFF) 70 | find_package(Git REQUIRED) 71 | endif(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) 72 | 73 | include(AddLLVM) 74 | include(TableGen) 75 | 76 | if (NOT WIN32) 77 | add_subdirectory( linux_linker bin) 78 | endif() 79 | 80 | use_rtti(FALSE) 81 | use_eh(TRUE) 82 | 83 | if (CMAKE_SIZEOF_VOID_P EQUAL 4) 84 | set(ADDR 32) 85 | elseif (CMAKE_SIZEOF_VOID_P EQUAL 8) 86 | set(ADDR 64) 87 | else () 88 | # CMAKE_SIZEOF_VOID_P might not be set on windows x86 in in-tree build 89 | message(WARNING "[OPENCL-CLANG] CMAKE_SIZEOF_VOID_P is not set") 90 | if (WIN32 AND LLVM_BUILD_32_BITS) 91 | set(ADDR 32) 92 | endif() 93 | endif (CMAKE_SIZEOF_VOID_P EQUAL 4) 94 | 95 | # set windows binary suffix 96 | if (WIN32) 97 | set (BUILD_PLATFORM ${ADDR}) 98 | else (WIN32) 99 | set (BUILD_PLATFORM "") 100 | endif (WIN32) 101 | 102 | # set that name of the main output file as a target name 103 | if (NOT DEFINED OPENCL_CLANG_LIBRARY_NAME) 104 | set(OPENCL_CLANG_LIBRARY_NAME "opencl-clang") 105 | endif() 106 | set(TARGET_NAME ${OPENCL_CLANG_LIBRARY_NAME}${BUILD_PLATFORM} ) 107 | 108 | # OPENCL_CLANG_PCH_EXTENSION can override PCH extension map in options_compile.cpp. 109 | # Example: "cl_khr_3d_image_writes,cl_khr_depth_images" 110 | set(OPENCL_CLANG_PCH_EXTENSION "" CACHE STRING "Comma-separated list of OpenCL extensions") 111 | if (NOT "${OPENCL_CLANG_PCH_EXTENSION}" STREQUAL "") 112 | add_definitions(-DPCH_EXTENSION="${OPENCL_CLANG_PCH_EXTENSION}") 113 | endif() 114 | 115 | if(NOT USE_PREBUILT_LLVM) 116 | 117 | if(NOT LLVM_EXTERNAL_CLANG_SOURCE_DIR) 118 | set(CLANG_SOURCE_DIR ${LLVM_SOURCE_DIR}/tools/clang) 119 | elseif(EXISTS "${LLVM_EXTERNAL_CLANG_SOURCE_DIR}/CMakeLists.txt") 120 | set(CLANG_SOURCE_DIR "${LLVM_EXTERNAL_CLANG_SOURCE_DIR}") 121 | endif() 122 | if(EXISTS ${CLANG_SOURCE_DIR}) 123 | message(STATUS "[OPENCL-CLANG] Using Clang source code direcotry: ${CLANG_SOURCE_DIR}") 124 | else() 125 | message(FATAL_ERROR 126 | "[OPENCL-CLANG] Can't find Clang source code directory!\n" 127 | "If you are using LLVM monorepo:\n" 128 | " 1. Clean CMake cache: `rm CMakeCache.txt`\n" 129 | " 2. Enable Clang project with `-DLLVM_ENABLE_PROJECTS=\"clang\"` option\n" 130 | "If Clang is used as a separate repository (not monorepo), it should " 131 | "be checked out at `llvm/tools/clang`." 132 | ) 133 | endif() 134 | 135 | if(NOT LLVM_EXTERNAL_LLVM_SPIRV_SOURCE_DIR) 136 | set(SPIRV_SOURCE_DIR ${LLVM_SOURCE_DIR}/projects/llvm-spirv) 137 | elseif(EXISTS "${LLVM_EXTERNAL_LLVM_SPIRV_SOURCE_DIR}/CMakeLists.txt") 138 | set(SPIRV_SOURCE_DIR ${LLVM_EXTERNAL_LLVM_SPIRV_SOURCE_DIR}) 139 | endif() 140 | if(EXISTS ${SPIRV_SOURCE_DIR}) 141 | message(STATUS "[OPENCL-CLANG] Using SPIRV-LLVM-Translator source code directory: ${SPIRV_SOURCE_DIR}") 142 | else() 143 | message(FATAL_ERROR 144 | "[OPENCL-CLANG] Can't find SPIRV-LLVM-Translator source code dir!\n" 145 | "If you are using LLVM monorepo, SPIRV-LLVM-Translator should be checked out " 146 | "at '/llvm-spirv' and it should be enabled as an external LLVM " 147 | "project using the following 2 options:\n" 148 | " -DLLVM_EXTERNAL_PROJECTS=\"opencl-clang;llvm-spirv\"\n" 149 | " -DLLVM_EXTERNAL_LLVM_SPIRV_SOURCE_DIR=\"/llvm-spirv\"\n" 150 | "If you are not using LLVM monorepo, SPIRV-LLVM-Translator should be checked " 151 | "out at `llvm/projects/llvm-spirv`" 152 | ) 153 | endif() 154 | 155 | set(CLANG_BASE_REVISION master) 156 | set(SPIRV_BASE_REVISION master) 157 | set(TARGET_BRANCH "ocl-open-110") 158 | 159 | apply_patches(${CLANG_SOURCE_DIR} 160 | ${CMAKE_CURRENT_SOURCE_DIR}/patches/clang 161 | ${CLANG_BASE_REVISION} 162 | ${TARGET_BRANCH}) 163 | apply_patches(${SPIRV_SOURCE_DIR} 164 | ${CMAKE_CURRENT_SOURCE_DIR}/patches/spirv 165 | ${SPIRV_BASE_REVISION} 166 | ${TARGET_BRANCH}) 167 | endif(NOT USE_PREBUILT_LLVM) 168 | 169 | # 170 | # TblGen the options include file 171 | # 172 | set (COMPILE_OPTIONS_TD opencl_clang_options.td) 173 | set (COMPILE_OPTIONS_INC opencl_clang_options.inc) 174 | 175 | find_program(LLVM_TABLEGEN_EXE "llvm-tblgen" ${LLVM_TOOLS_BINARY_DIR}) 176 | set(LLVM_TARGET_DEFINITIONS ${COMPILE_OPTIONS_TD}) 177 | if(USE_PREBUILT_LLVM) 178 | set(TABLEGEN_ADDITIONAL -I ${LLVM_INCLUDE_DIRS}) 179 | else(USE_PREBUILT_LLVM) 180 | set(TABLEGEN_ADDITIONAL "") 181 | endif(USE_PREBUILT_LLVM) 182 | tablegen(LLVM ${COMPILE_OPTIONS_INC} -gen-opt-parser-defs ${TABLEGEN_ADDITIONAL}) 183 | add_public_tablegen_target(CClangCompileOptions) 184 | 185 | # 186 | # Source code 187 | # 188 | set(TARGET_INCLUDE_FILES 189 | opencl_clang.h 190 | options.h 191 | binary_result.h 192 | pch_mgr.h 193 | ${COMPILE_OPTIONS_TD} 194 | ${COMPILE_OPTIONS_INC} 195 | ) 196 | 197 | set(TARGET_SOURCE_FILES 198 | opencl_clang.cpp 199 | options.cpp 200 | pch_mgr.cpp 201 | options_compile.cpp 202 | ) 203 | 204 | # 205 | # Resources 206 | # 207 | 208 | set( PRODUCT_VER_MAJOR 2 ) 209 | set( PRODUCT_VER_MINOR 0 ) 210 | set (LLVM_VER_MAJOR ${LLVM_VERSION_MAJOR} ) 211 | set (LLVM_VER_MINOR ${LLVM_VERSION_MINOR} ) 212 | 213 | add_definitions( -D__STDC_LIMIT_MACROS ) 214 | add_definitions( -D__STDC_CONSTANT_MACROS ) 215 | add_definitions( -DOPENCL_CLANG_EXPORTS ) 216 | 217 | # 218 | # Include directories 219 | # 220 | 221 | if(NOT USE_PREBUILT_LLVM) 222 | set(CLANG_BINARY_DIR ${LLVM_BINARY_DIR}/tools/clang/) 223 | include_directories( 224 | ${CLANG_BINARY_DIR}/include # for tablegened includes 225 | ${CLANG_SOURCE_DIR}/include # for basic headers 226 | ${SPIRV_SOURCE_DIR}/include) # for SPIRV headers 227 | endif(NOT USE_PREBUILT_LLVM) 228 | 229 | if(USE_PREBUILT_LLVM AND NOT LLVMSPIRV_INCLUDED_IN_LLVM) 230 | include_directories(${SPIRV_TRANSLATOR_DIR}/include) 231 | link_directories(${SPIRV_TRANSLATOR_DIR}/lib${LLVM_LIBDIR_SUFFIX}) 232 | endif(USE_PREBUILT_LLVM AND NOT LLVMSPIRV_INCLUDED_IN_LLVM) 233 | 234 | include_directories( AFTER 235 | ${LLVM_INCLUDE_DIRS} 236 | ${CMAKE_CURRENT_BINARY_DIR} 237 | ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} 238 | ) 239 | 240 | link_directories( 241 | ${LLVM_LIBRARY_DIRS} 242 | ) 243 | 244 | set(OPENCL_CLANG_LINK_LIBS ${CMAKE_DL_LIBS}) 245 | 246 | if(NOT LLVMSPIRVLib IN_LIST LLVM_AVAILABLE_LIBS OR (USE_PREBUILT_LLVM AND LLVM_LINK_LLVM_DYLIB)) 247 | # SPIRV-LLVM-Translator is not included into LLVM as a component. 248 | # So, we need to list it here explicitly as an external library 249 | list(APPEND OPENCL_CLANG_LINK_LIBS LLVMSPIRVLib) 250 | endif() 251 | 252 | add_subdirectory(cl_headers) 253 | 254 | set(LLVM_REQUIRES_EH ON) 255 | 256 | if(USE_PREBUILT_LLVM OR CLANG_LINK_CLANG_DYLIB) 257 | list(APPEND OPENCL_CLANG_LINK_LIBS clang-cpp) 258 | else() 259 | list(APPEND OPENCL_CLANG_LINK_LIBS 260 | clangBasic 261 | clangFrontend 262 | clangFrontendTool 263 | clangSerialization 264 | ) 265 | endif() 266 | 267 | if(USE_PREBUILT_LLVM AND UNIX) 268 | # llvm_map_components_to_libnames(... all) returns empty string if llvm is 269 | # pre-built locally in either static or shared type in Ubuntu 22.04 container. 270 | find_program(LLVM_CONFIG_EXE 271 | NAMES llvm-config-${PREFERRED_LLVM_VERSION} llvm-config 272 | PATHS ${LLVM_BINARY_DIR} ${LLVM_BINARY_DIR}/bin) 273 | if(NOT LLVM_CONFIG_EXE) 274 | message(FATAL_ERROR "[OPENCL-CLANG] llvm-config is not found") 275 | endif() 276 | 277 | execute_process(COMMAND ${LLVM_CONFIG_EXE} --libs all OUTPUT_VARIABLE ALL_LIBS) 278 | string(REGEX REPLACE "( |\r|\n|-l)+" ";" ALL_LLVM_LIBS ${ALL_LIBS}) 279 | set(ALL_LLVM_LIBS "LLVMSPIRVLib${ALL_LLVM_LIBS}") 280 | else() 281 | llvm_map_components_to_libnames(ALL_LLVM_LIBS all) 282 | endif() 283 | set(OPENCL_CLANG_EXCLUDE_LIBS_FROM_ALL "" CACHE STRING "Space-separated list of LLVM libraries to exclude from all") 284 | if (NOT "${OPENCL_CLANG_EXCLUDE_LIBS_FROM_ALL}" STREQUAL "") 285 | list(REMOVE_ITEM ALL_LLVM_LIBS ${OPENCL_CLANG_EXCLUDE_LIBS_FROM_ALL}) 286 | endif() 287 | list(APPEND OPENCL_CLANG_LINK_LIBS ${ALL_LLVM_LIBS}) 288 | 289 | add_llvm_library(${TARGET_NAME} SHARED 290 | ${TARGET_INCLUDE_FILES} 291 | ${TARGET_SOURCE_FILES} 292 | $ 293 | 294 | DEPENDS CClangCompileOptions 295 | 296 | LINK_LIBS 297 | ${OPENCL_CLANG_LINK_LIBS} 298 | ) 299 | 300 | if (WIN32) 301 | # Enable compiler generation of Control Flow Guard security checks. 302 | target_compile_options(${TARGET_NAME} PUBLIC "/guard:cf") 303 | set_property(TARGET ${TARGET_NAME} APPEND PROPERTY 304 | LINK_OPTIONS "LINKER:/DYNAMICBASE" "LINKER:/GUARD:CF") 305 | 306 | elseif(UNIX) 307 | set_property(TARGET ${TARGET_NAME} APPEND_STRING PROPERTY 308 | COMPILE_DEFINITIONS LIBOPENCL_CLANG_NAME="$") 309 | 310 | # Sanitizers do not support this flag, disable this when under sanitizer build 311 | if(NOT LLVM_USE_SANITIZER) 312 | set_property(TARGET ${TARGET_NAME} APPEND_STRING PROPERTY 313 | LINK_FLAGS " -Wl,--no-undefined") 314 | endif() 315 | endif(WIN32) 316 | 317 | install(FILES opencl_clang.h 318 | DESTINATION include/cclang 319 | COMPONENT ${TARGET_NAME}) 320 | 321 | # 322 | # Stripped PDB files 323 | # 324 | if (WIN32) 325 | get_target_property(RT_OUTPUT_DIRECTORY ${TARGET_NAME} RUNTIME_OUTPUT_DIRECTORY) 326 | file(TO_NATIVE_PATH ${RT_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/${TARGET_NAME}_stripped.pdb PDB_NAME) 327 | if (${MSVC_VERSION} EQUAL 1500) 328 | # Visual Studio 2008 329 | set_property(TARGET ${TARGET_NAME} APPEND PROPERTY LINK_OPTIONS "LINKER:/PDBSTRIPPED:${PDB_NAME}") 330 | else (${MSVC_VERSION} EQUAL 1500) 331 | # Visual Studio 2010 (assumed if not Visual Studio 2008) 332 | # This is a fix due to a bug in CMake, Does not add the flag /DEBUG to the linker flags in Release mode. 333 | # The /DEBUG flag is required in order to create stripped pdbs. 334 | set_property(TARGET ${TARGET_NAME} APPEND PROPERTY LINK_OPTIONS $<$:LINKER:/DEBUG> "$<$:LINKER:/PDBSTRIPPED:${PDB_NAME}>") 335 | endif (${MSVC_VERSION} EQUAL 1500) 336 | if (INSTALL_PDBS) 337 | install(FILES ${RT_OUTPUT_DIRECTORY}/\${BUILD_TYPE}/${TARGET_NAME}.pdb DESTINATION bin) 338 | endif(INSTALL_PDBS) 339 | install(FILES ${RT_OUTPUT_DIRECTORY}/\${BUILD_TYPE}/${TARGET_NAME}_stripped.pdb DESTINATION bin) 340 | else (WIN32) 341 | SET_LINUX_EXPORTS_FILE( ${TARGET_NAME} opencl_clang.map ) 342 | endif(WIN32) 343 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ============================================================================== 2 | The LLVM Project is under the Apache License v2.0 with LLVM Exceptions: 3 | ============================================================================== 4 | 5 | Apache License 6 | Version 2.0, January 2004 7 | http://www.apache.org/licenses/ 8 | 9 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 10 | 11 | 1. Definitions. 12 | 13 | "License" shall mean the terms and conditions for use, reproduction, 14 | and distribution as defined by Sections 1 through 9 of this document. 15 | 16 | "Licensor" shall mean the copyright owner or entity authorized by 17 | the copyright owner that is granting the License. 18 | 19 | "Legal Entity" shall mean the union of the acting entity and all 20 | other entities that control, are controlled by, or are under common 21 | control with that entity. For the purposes of this definition, 22 | "control" means (i) the power, direct or indirect, to cause the 23 | direction or management of such entity, whether by contract or 24 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 25 | outstanding shares, or (iii) beneficial ownership of such entity. 26 | 27 | "You" (or "Your") shall mean an individual or Legal Entity 28 | exercising permissions granted by this License. 29 | 30 | "Source" form shall mean the preferred form for making modifications, 31 | including but not limited to software source code, documentation 32 | source, and configuration files. 33 | 34 | "Object" form shall mean any form resulting from mechanical 35 | transformation or translation of a Source form, including but 36 | not limited to compiled object code, generated documentation, 37 | and conversions to other media types. 38 | 39 | "Work" shall mean the work of authorship, whether in Source or 40 | Object form, made available under the License, as indicated by a 41 | copyright notice that is included in or attached to the work 42 | (an example is provided in the Appendix below). 43 | 44 | "Derivative Works" shall mean any work, whether in Source or Object 45 | form, that is based on (or derived from) the Work and for which the 46 | editorial revisions, annotations, elaborations, or other modifications 47 | represent, as a whole, an original work of authorship. For the purposes 48 | of this License, Derivative Works shall not include works that remain 49 | separable from, or merely link (or bind by name) to the interfaces of, 50 | the Work and Derivative Works thereof. 51 | 52 | "Contribution" shall mean any work of authorship, including 53 | the original version of the Work and any modifications or additions 54 | to that Work or Derivative Works thereof, that is intentionally 55 | submitted to Licensor for inclusion in the Work by the copyright owner 56 | or by an individual or Legal Entity authorized to submit on behalf of 57 | the copyright owner. For the purposes of this definition, "submitted" 58 | means any form of electronic, verbal, or written communication sent 59 | to the Licensor or its representatives, including but not limited to 60 | communication on electronic mailing lists, source code control systems, 61 | and issue tracking systems that are managed by, or on behalf of, the 62 | Licensor for the purpose of discussing and improving the Work, but 63 | excluding communication that is conspicuously marked or otherwise 64 | designated in writing by the copyright owner as "Not a Contribution." 65 | 66 | "Contributor" shall mean Licensor and any individual or Legal Entity 67 | on behalf of whom a Contribution has been received by Licensor and 68 | subsequently incorporated within the Work. 69 | 70 | 2. Grant of Copyright License. Subject to the terms and conditions of 71 | this License, each Contributor hereby grants to You a perpetual, 72 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 73 | copyright license to reproduce, prepare Derivative Works of, 74 | publicly display, publicly perform, sublicense, and distribute the 75 | Work and such Derivative Works in Source or Object form. 76 | 77 | 3. Grant of Patent License. Subject to the terms and conditions of 78 | this License, each Contributor hereby grants to You a perpetual, 79 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 80 | (except as stated in this section) patent license to make, have made, 81 | use, offer to sell, sell, import, and otherwise transfer the Work, 82 | where such license applies only to those patent claims licensable 83 | by such Contributor that are necessarily infringed by their 84 | Contribution(s) alone or by combination of their Contribution(s) 85 | with the Work to which such Contribution(s) was submitted. If You 86 | institute patent litigation against any entity (including a 87 | cross-claim or counterclaim in a lawsuit) alleging that the Work 88 | or a Contribution incorporated within the Work constitutes direct 89 | or contributory patent infringement, then any patent licenses 90 | granted to You under this License for that Work shall terminate 91 | as of the date such litigation is filed. 92 | 93 | 4. Redistribution. You may reproduce and distribute copies of the 94 | Work or Derivative Works thereof in any medium, with or without 95 | modifications, and in Source or Object form, provided that You 96 | meet the following conditions: 97 | 98 | (a) You must give any other recipients of the Work or 99 | Derivative Works a copy of this License; and 100 | 101 | (b) You must cause any modified files to carry prominent notices 102 | stating that You changed the files; and 103 | 104 | (c) You must retain, in the Source form of any Derivative Works 105 | that You distribute, all copyright, patent, trademark, and 106 | attribution notices from the Source form of the Work, 107 | excluding those notices that do not pertain to any part of 108 | the Derivative Works; and 109 | 110 | (d) If the Work includes a "NOTICE" text file as part of its 111 | distribution, then any Derivative Works that You distribute must 112 | include a readable copy of the attribution notices contained 113 | within such NOTICE file, excluding those notices that do not 114 | pertain to any part of the Derivative Works, in at least one 115 | of the following places: within a NOTICE text file distributed 116 | as part of the Derivative Works; within the Source form or 117 | documentation, if provided along with the Derivative Works; or, 118 | within a display generated by the Derivative Works, if and 119 | wherever such third-party notices normally appear. The contents 120 | of the NOTICE file are for informational purposes only and 121 | do not modify the License. You may add Your own attribution 122 | notices within Derivative Works that You distribute, alongside 123 | or as an addendum to the NOTICE text from the Work, provided 124 | that such additional attribution notices cannot be construed 125 | as modifying the License. 126 | 127 | You may add Your own copyright statement to Your modifications and 128 | may provide additional or different license terms and conditions 129 | for use, reproduction, or distribution of Your modifications, or 130 | for any such Derivative Works as a whole, provided Your use, 131 | reproduction, and distribution of the Work otherwise complies with 132 | the conditions stated in this License. 133 | 134 | 5. Submission of Contributions. Unless You explicitly state otherwise, 135 | any Contribution intentionally submitted for inclusion in the Work 136 | by You to the Licensor shall be under the terms and conditions of 137 | this License, without any additional terms or conditions. 138 | Notwithstanding the above, nothing herein shall supersede or modify 139 | the terms of any separate license agreement you may have executed 140 | with Licensor regarding such Contributions. 141 | 142 | 6. Trademarks. This License does not grant permission to use the trade 143 | names, trademarks, service marks, or product names of the Licensor, 144 | except as required for reasonable and customary use in describing the 145 | origin of the Work and reproducing the content of the NOTICE file. 146 | 147 | 7. Disclaimer of Warranty. Unless required by applicable law or 148 | agreed to in writing, Licensor provides the Work (and each 149 | Contributor provides its Contributions) on an "AS IS" BASIS, 150 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 151 | implied, including, without limitation, any warranties or conditions 152 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 153 | PARTICULAR PURPOSE. You are solely responsible for determining the 154 | appropriateness of using or redistributing the Work and assume any 155 | risks associated with Your exercise of permissions under this License. 156 | 157 | 8. Limitation of Liability. In no event and under no legal theory, 158 | whether in tort (including negligence), contract, or otherwise, 159 | unless required by applicable law (such as deliberate and grossly 160 | negligent acts) or agreed to in writing, shall any Contributor be 161 | liable to You for damages, including any direct, indirect, special, 162 | incidental, or consequential damages of any character arising as a 163 | result of this License or out of the use or inability to use the 164 | Work (including but not limited to damages for loss of goodwill, 165 | work stoppage, computer failure or malfunction, or any and all 166 | other commercial damages or losses), even if such Contributor 167 | has been advised of the possibility of such damages. 168 | 169 | 9. Accepting Warranty or Additional Liability. While redistributing 170 | the Work or Derivative Works thereof, You may choose to offer, 171 | and charge a fee for, acceptance of support, warranty, indemnity, 172 | or other liability obligations and/or rights consistent with this 173 | License. However, in accepting such obligations, You may act only 174 | on Your own behalf and on Your sole responsibility, not on behalf 175 | of any other Contributor, and only if You agree to indemnify, 176 | defend, and hold each Contributor harmless for any liability 177 | incurred by, or claims asserted against, such Contributor by reason 178 | of your accepting any such warranty or additional liability. 179 | 180 | END OF TERMS AND CONDITIONS 181 | 182 | APPENDIX: How to apply the Apache License to your work. 183 | 184 | To apply the Apache License to your work, attach the following 185 | boilerplate notice, with the fields enclosed by brackets "[]" 186 | replaced with your own identifying information. (Don't include 187 | the brackets!) The text should be enclosed in the appropriate 188 | comment syntax for the file format. We also recommend that a 189 | file or class name and description of purpose be included on the 190 | same "printed page" as the copyright notice for easier 191 | identification within third-party archives. 192 | 193 | Copyright [yyyy] [name of copyright owner] 194 | 195 | Licensed under the Apache License, Version 2.0 (the "License"); 196 | you may not use this file except in compliance with the License. 197 | You may obtain a copy of the License at 198 | 199 | http://www.apache.org/licenses/LICENSE-2.0 200 | 201 | Unless required by applicable law or agreed to in writing, software 202 | distributed under the License is distributed on an "AS IS" BASIS, 203 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 204 | See the License for the specific language governing permissions and 205 | limitations under the License. 206 | 207 | 208 | ---- LLVM Exceptions to the Apache 2.0 License ---- 209 | 210 | As an exception, if, as a result of your compiling your source code, portions 211 | of this Software are embedded into an Object form of such source code, you 212 | may redistribute such embedded portions in such Object form without complying 213 | with the conditions of Sections 4(a), 4(b) and 4(d) of the License. 214 | 215 | In addition, if you combine or link compiled forms of this Software with 216 | software that is licensed under the GPLv2 ("Combined Software") and if a 217 | court of competent jurisdiction determines that the patent provision (Section 218 | 3), the indemnity provision (Section 9) or other Section of the License 219 | conflicts with the conditions of the GPLv2, you may retroactively and 220 | prospectively choose to deem waived or otherwise exclude such Section(s) of 221 | the License, but only in their entirety and only with respect to the Combined 222 | Software. 223 | 224 | ============================================================================== 225 | Software from third parties included in the LLVM Project: 226 | ============================================================================== 227 | The LLVM Project contains third party software which is under different license 228 | terms. All such code will be identified clearly using at least one of two 229 | mechanisms: 230 | 1) It will be in a separate directory tree with its own `LICENSE.txt` or 231 | `LICENSE` file at the top containing the specific license and restrictions 232 | which apply to that software, or 233 | 2) It will contain specific license and restriction terms at the top of every 234 | file. 235 | 236 | ============================================================================== 237 | Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy): 238 | ============================================================================== 239 | University of Illinois/NCSA 240 | Open Source License 241 | 242 | Copyright (c) 2003-2019 University of Illinois at Urbana-Champaign. 243 | All rights reserved. 244 | 245 | Developed by: 246 | 247 | LLVM Team 248 | 249 | University of Illinois at Urbana-Champaign 250 | 251 | http://llvm.org 252 | 253 | Permission is hereby granted, free of charge, to any person obtaining a copy of 254 | this software and associated documentation files (the "Software"), to deal with 255 | the Software without restriction, including without limitation the rights to 256 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 257 | of the Software, and to permit persons to whom the Software is furnished to do 258 | so, subject to the following conditions: 259 | 260 | * Redistributions of source code must retain the above copyright notice, 261 | this list of conditions and the following disclaimers. 262 | 263 | * Redistributions in binary form must reproduce the above copyright notice, 264 | this list of conditions and the following disclaimers in the 265 | documentation and/or other materials provided with the distribution. 266 | 267 | * Neither the names of the LLVM Team, University of Illinois at 268 | Urbana-Champaign, nor the names of its contributors may be used to 269 | endorse or promote products derived from this Software without specific 270 | prior written permission. 271 | 272 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 273 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 274 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 275 | CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 276 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 277 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE 278 | SOFTWARE. 279 | 280 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Scheduled verification](https://github.com/intel/opencl-clang/actions/workflows/scheduled-verification.yml/badge.svg)](https://github.com/intel/opencl-clang/actions/workflows/scheduled-verification.yml) 2 | [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/9059/badge)](https://www.bestpractices.dev/projects/9059) 3 | 4 | opencl-clang is a thin wrapper library around clang. The library has 5 | OpenCL-oriented API and is capable to compile OpenCL C kernels to SPIR-V 6 | modules. 7 | 8 | ## Build 9 | 10 | Source code in this repo can be built in different manners: 11 | * in-tree as an LLVM project 12 | * out-of-tree using pre-built LLVM 13 | 14 | ### In-tree build 15 | 16 | Before the build all dependencies must be downloaded and laid out as follows: 17 | 18 | ``` 19 | 20 | |-- llvm 21 | |-- clang 22 | |-- SPIRV-LLVM-Translator 23 | `-- opencl-clang 24 | ``` 25 | 26 | This can be done using the following commands: 27 | ```bash 28 | cd 29 | git clone https://github.com/llvm/llvm-project.git . 30 | git clone https://github.com/KhronosGroup/SPIRV-LLVM-Translator.git 31 | git clone https://github.com/intel/opencl-clang.git 32 | ``` 33 | 34 | Then we need to create a build directory and run the build: 35 | ```bash 36 | export OCL_CLANG_WS= 37 | cd $OCL_CLANG_WS 38 | mkdir build && cd build 39 | cmake -DLLVM_TARGETS_TO_BUILD="X86" -DLLVM_ENABLE_PROJECTS="clang" \ 40 | -DLLVM_EXTERNAL_PROJECTS="llvm-spirv;opencl-clang" \ 41 | -DLLVM_EXTERNAL_LLVM_SPIRV_SOURCE_DIR="$OCL_CLANG_WS/SPIRV-LLVM-Translator" \ 42 | -DLLVM_EXTERNAL_OPENCL_CLANG_SOURCE_DIR="$OCL_CLANG_WS/opencl-clang" \ 43 | -DCMAKE_BUILD_TYPE=Release $OCL_CLANG_WS/llvm 44 | make opencl-clang -j`nproc` 45 | ``` 46 | 47 | For sanity check of the build please run `make check-clang` and 48 | `make check-llvm-spirv` 49 | 50 | ### Out-of-tree build 51 | 52 | To build opencl-clang as a standalone project, you need to obtain pre-built LLVM 53 | and SPIR-V Translator libraries. **Note:** currently this kind of build is 54 | supported on Linux only. 55 | 56 | If opencl-clang is used as part of another CMake project, you will need to define `OPENCL_CLANG_BUILD_EXTERNAL`. 57 | 58 | Integration with pre-built LLVM is done using standard `find_package` way as 59 | documented in [Embedding LLVM in your project](https://llvm.org/docs/CMake.html#embedding-llvm-in-your-project). 60 | 61 | Commands to checkout sources and build: 62 | ```bash 63 | cd 64 | git clone https://github.com/intel/opencl-clang.git 65 | mkdir build && cd build 66 | cmake ../opencl-clang 67 | make all -j`nproc` 68 | ``` 69 | 70 | #### Configuration options 71 | 72 | ##### Preferred LLVM version 73 | 74 | By default, opencl-clang's cmake script is searching for LLVM which is built 75 | based on the latest verion of current branch. You can override target version of 76 | LLVM by using the `PREFERRED_LLVM_VERSION` cmake option: 77 | 78 | Example: 79 | ```bash 80 | cmake -DPREFERRED_LLVM_VERSION="21.0" ../opencl-clang 81 | ``` 82 | 83 | ##### Custom LLVM installation 84 | 85 | If LLVM is installed somewhere in custom (non-system directories) location, you 86 | could point to it using the `LLVM_DIR` cmake option. **Note**: You need to 87 | specify the path to a directory containing the `LLVMConfig.cmake` file. 88 | 89 | This file is available in two different locations. 90 | * `/lib/cmake/llvm/LLVMConfig.cmake` where `` 91 | is the install prefix of an installed version of LLVM. On Linux this is 92 | typically `/usr/lib/cmake/llvm/LLVMConfig.cmake`. 93 | * `/lib/cmake/llvm/LLVMConfig.cmake` where `` 94 | is the root of the LLVM build tree. 95 | **Note: this is only available when building LLVM with CMake.** 96 | 97 | Example: 98 | ```bash 99 | cmake -DLLVM_DIR=/path/to/installed/llvm/lib/cmake/llvm ../opencl-clang 100 | ``` 101 | 102 | ##### Location of SPIR-V Translator library 103 | 104 | By default, opencl-clang's cmake script assumes that SPIR-V Translator library 105 | is built as part of LLVM, installed in the same place and libLLVMSPIRVLib is 106 | linked into libLLVM. 107 | 108 | If that is not true for you, you can override this: firstly, you need to set 109 | `LLVMSPIRV_INCLUDED_IN_LLVM` cmake option to `OFF`. Then you need to specify 110 | directory where SPIR-V Translator is installed by using `SPIRV_TRANSLATOR_DIR` 111 | cmake option. 112 | 113 | Example: 114 | ```bash 115 | cmake -DLLVMSPIRV_INCLUDED_IN_LLVM=OFF -DSPIRV_TRANSLATOR_DIR=/path/to/installed/spirv/translator ../opencl-clang 116 | ``` 117 | 118 | There is a known issue (linker crash) for this kind of build on Ubuntu 16.04 119 | Xenial. 120 | In this case the following cmake option should fix it: 121 | ``` 122 | -DLLVM_NO_DEAD_STRIP=ON 123 | ``` 124 | 125 | Installation directory of SPIR-V Translator is expected to contain the 126 | following files: 127 | ``` 128 | 129 | |-- include 130 | | `-- LLVMSPIRVLib 131 | | `-- LLVMSPIRVLib.h 132 | `-- lib64 133 | `-- libLLVMSPIRVLib.so 134 | ``` 135 | 136 | ## Contribution 137 | Please submit a pull request to contribute. 138 | 139 | Please follow [LLVM coding standards](https://llvm.org/docs/CodingStandards.html) 140 | 141 | ## Report a problem 142 | Please submit an [issue](https://github.com/intel/opencl-clang/issues) 143 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | Intel is committed to rapidly addressing security vulnerabilities affecting our customers and providing clear guidance on the solution, impact, severity and mitigation. 3 | 4 | ## Reporting a Vulnerability 5 | Please report any security vulnerabilities in this project utilizing the guidelines [here](https://www.intel.com/content/www/us/en/security-center/vulnerability-handling-guidelines.html). 6 | -------------------------------------------------------------------------------- /binary_result.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | 3 | Copyright (c) Intel Corporation (2009-2017). 4 | 5 | INTEL MAKES NO WARRANTY OF ANY KIND REGARDING THE CODE. THIS CODE IS 6 | LICENSED ON AN "AS IS" BASIS AND INTEL WILL NOT PROVIDE ANY SUPPORT, 7 | ASSISTANCE, INSTALLATION, TRAINING OR OTHER SERVICES. INTEL DOES NOT 8 | PROVIDE ANY UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY 9 | DISCLAIMS ANY WARRANTY OF MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR ANY 10 | PARTICULAR PURPOSE, OR ANY OTHER WARRANTY. Intel disclaims all liability, 11 | including liability for infringement of any proprietary rights, relating to 12 | use of the code. No license, express or implied, by estoppel or otherwise, 13 | to any intellectual property rights is granted herein. 14 | 15 | \file binary_result.h 16 | 17 | \*****************************************************************************/ 18 | 19 | #pragma once 20 | 21 | #include "opencl_clang.h" 22 | #include "llvm/ADT/SmallVector.h" 23 | #include 24 | 25 | // The following #define is taken from 26 | // https://github.com/KhronosGroup/OpenCL-Headers/blob/master/CL/cl.h 27 | #define CL_SUCCESS 0 28 | 29 | class OCLFEBinaryResult : public Intel::OpenCL::ClangFE::IOCLFEBinaryResult { 30 | // IOCLFEBinaryResult 31 | public: 32 | size_t GetIRSize() const override { return m_IRBuffer.size(); } 33 | 34 | const void *GetIR() const override { return m_IRBuffer.data(); } 35 | 36 | const char *GetIRName() const override { return m_IRName.c_str(); } 37 | 38 | Intel::OpenCL::ClangFE::IR_TYPE GetIRType() const override { return m_type; } 39 | 40 | const char *GetErrorLog() const override { return m_log.c_str(); } 41 | 42 | void Release() override { delete this; } 43 | // OCLFEBinaryResult 44 | public: 45 | OCLFEBinaryResult() 46 | : m_type(Intel::OpenCL::ClangFE::IR_TYPE_UNKNOWN), m_result(CL_SUCCESS) {} 47 | 48 | llvm::SmallVectorImpl &getIRBufferRef() { return m_IRBuffer; } 49 | 50 | std::string &getLogRef() { return m_log; } 51 | 52 | void setLog(const std::string &log) { m_log = log; } 53 | 54 | void setIRName(const std::string &name) { m_IRName = name; } 55 | 56 | void setIRType(Intel::OpenCL::ClangFE::IR_TYPE type) { m_type = type; } 57 | 58 | void setResult(int result) { m_result = result; } 59 | 60 | int getResult(void) const { return m_result; } 61 | 62 | private: 63 | llvm::SmallVector m_IRBuffer; 64 | std::string m_log; 65 | std::string m_IRName; 66 | Intel::OpenCL::ClangFE::IR_TYPE m_type; 67 | int m_result; 68 | }; 69 | -------------------------------------------------------------------------------- /cl_headers/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(CL_HEADERS_LIB cl_headers) 2 | if(USE_PREBUILT_LLVM) 3 | find_program(CLANG_COMMAND clang PATHS ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH) 4 | else() 5 | set(CLANG_COMMAND $) 6 | endif() 7 | if(CMAKE_CROSSCOMPILING AND NOT OPENCL_CLANG_BUILD_EXTERNAL) 8 | build_native_tool(clang CLANG_COMMAND) 9 | endif() 10 | set(LINUX_RESOURCE_LINKER_COMMAND linux_resource_linker) 11 | 12 | function(copy_file SRC DST) 13 | add_custom_command( 14 | OUTPUT ${DST} 15 | MAIN_DEPENDENCY ${SRC} 16 | COMMAND ${CMAKE_COMMAND} -E copy "${SRC}" "${DST}" 17 | COMMENT "Copying '${SRC}' to ${DST}" 18 | ) 19 | endfunction(copy_file) 20 | 21 | if(USE_PREBUILT_LLVM) 22 | if(EXISTS "${LLVM_LIBRARY_DIRS}/clang/${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}/") 23 | set(OPENCL_HEADERS_DIR 24 | "${LLVM_LIBRARY_DIRS}/clang/${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}/include/") 25 | elseif(EXISTS "${LLVM_LIBRARY_DIRS}/clang/${LLVM_VERSION_MAJOR}/") 26 | set(OPENCL_HEADERS_DIR 27 | "${LLVM_LIBRARY_DIRS}/clang/${LLVM_VERSION_MAJOR}/include/") 28 | else() 29 | message(FATAL_ERROR "[OPENCL-CLANG] Couldn't find prebuilt LLVM include directory.") 30 | endif() 31 | else(USE_PREBUILT_LLVM) 32 | set(OPENCL_HEADERS_DIR "${CLANG_SOURCE_DIR}/lib/Headers") 33 | endif(USE_PREBUILT_LLVM) 34 | copy_file(${OPENCL_HEADERS_DIR}/opencl-c.h opencl-c.h) 35 | copy_file(${OPENCL_HEADERS_DIR}/opencl-c-base.h opencl-c-base.h) 36 | copy_file(${CMAKE_CURRENT_SOURCE_DIR}/module.modulemap module.modulemap) 37 | 38 | add_custom_target ( 39 | opencl.headers.target 40 | DEPENDS 41 | module.modulemap 42 | opencl-c.h 43 | opencl-c-base.h 44 | ) 45 | 46 | function(create_pcm DST MODULE HEADER OPTS DEPS) 47 | add_custom_command ( 48 | OUTPUT ${DST} 49 | MAIN_DEPENDENCY ${MODMAP} 50 | DEPENDS ${HEADER} ${DEPS} ${CLANG_COMMAND} 51 | COMMAND 52 | ${CLANG_COMMAND} -cc1 -x cl 53 | -I. -O0 ${OPTS} 54 | -fmodules -fmodule-name=${MODULE} -fmodule-map-file-home-is-cwd 55 | -emit-module "module.modulemap" 56 | -fno-validate-pch 57 | -o ${DST} 58 | VERBATIM 59 | COMMENT "Generating ${DST}" 60 | ) 61 | endfunction(create_pcm) 62 | 63 | set(CL12 "-cl-std=CL1.2") 64 | set(CL20 "-cl-std=CL2.0") 65 | set(CL30 "-cl-std=CL3.0") 66 | # Add OpenCL C 3.0 Optional features 67 | set(OPTS30 "-cl-ext=+__opencl_c_3d_image_writes,+__opencl_c_atomic_order_acq_rel,+__opencl_c_atomic_order_seq_cst,+__opencl_c_atomic_scope_device,+__opencl_c_atomic_scope_all_devices,+__opencl_c_device_enqueue,+__opencl_c_generic_address_space,+__opencl_c_images,+__opencl_c_int64,+__opencl_c_pipes,+__opencl_c_program_scope_global_variables,+__opencl_c_read_write_images,+__opencl_c_subgroups,+__opencl_c_work_group_collective_functions") 68 | set(OPTS30_FP64 "-D__opencl_c_fp64=1") 69 | 70 | set(SPIR_TRIPLE "-triple;spir-unknown-unknown") 71 | set(SPIR64_TRIPLE "-triple;spir64-unknown-unknown") 72 | 73 | if (BUILD_X64) 74 | set(HOST_TRIPLE "${SPIR64_TRIPLE}") 75 | else() 76 | set(HOST_TRIPLE "${SPIR_TRIPLE}") 77 | endif() 78 | 79 | set(OPTS -cl-ext=+all,-cl_khr_fp64,-__opencl_c_fp64) 80 | create_pcm(opencl-c-12-spir.pcm cl12spir opencl-c-base.h "${SPIR_TRIPLE};${CL12};${OPTS}" "${DEPS}") 81 | create_pcm(opencl-c-20-spir.pcm cl20spir opencl-c-base.h "${SPIR_TRIPLE};${CL20};${OPTS}" "${DEPS}") 82 | create_pcm(opencl-c-30-spir.pcm cl30spir opencl-c-base.h "${SPIR_TRIPLE};${CL30};${OPTS};${OPTS30}" "${DEPS}") 83 | create_pcm(opencl-c-12-spir64.pcm cl12spir64 opencl-c-base.h "${SPIR64_TRIPLE};${CL12};${OPTS}" "${DEPS}") 84 | create_pcm(opencl-c-20-spir64.pcm cl20spir64 opencl-c-base.h "${SPIR64_TRIPLE};${CL20};${OPTS}" "${DEPS}") 85 | create_pcm(opencl-c-30-spir64.pcm cl30spir64 opencl-c-base.h "${SPIR64_TRIPLE};${CL30};${OPTS};${OPTS30}" "${DEPS}") 86 | set(OPTS -cl-ext=+all) 87 | create_pcm(opencl-c-12-spir-fp64.pcm cl12spirfp64 opencl-c-base.h "${SPIR_TRIPLE};${CL12};${OPTS}" "${DEPS}") 88 | create_pcm(opencl-c-20-spir-fp64.pcm cl20spirfp64 opencl-c-base.h "${SPIR_TRIPLE};${CL20};${OPTS}" "${DEPS}") 89 | create_pcm(opencl-c-30-spir-fp64.pcm cl30spirfp64 opencl-c-base.h "${SPIR_TRIPLE};${CL30};${OPTS};${OPTS30};${OPTS30_FP64}" "${DEPS}") 90 | create_pcm(opencl-c-12-spir64-fp64.pcm cl12spir64fp64 opencl-c-base.h "${SPIR64_TRIPLE};${CL12};${OPTS}" "${DEPS}") 91 | create_pcm(opencl-c-20-spir64-fp64.pcm cl20spir64fp64 opencl-c-base.h "${SPIR64_TRIPLE};${CL20};${OPTS}" "${DEPS}") 92 | create_pcm(opencl-c-30-spir64-fp64.pcm cl30spir64fp64 opencl-c-base.h "${SPIR64_TRIPLE};${CL30};${OPTS};${OPTS30};${OPTS30_FP64}" "${DEPS}") 93 | 94 | add_custom_target ( 95 | opencl.pcm.target 96 | DEPENDS 97 | opencl.headers.target 98 | opencl-c-12-spir.pcm 99 | opencl-c-20-spir.pcm 100 | opencl-c-30-spir.pcm 101 | opencl-c-12-spir64.pcm 102 | opencl-c-20-spir64.pcm 103 | opencl-c-30-spir64.pcm 104 | opencl-c-12-spir-fp64.pcm 105 | opencl-c-20-spir-fp64.pcm 106 | opencl-c-30-spir-fp64.pcm 107 | opencl-c-12-spir64-fp64.pcm 108 | opencl-c-20-spir64-fp64.pcm 109 | opencl-c-30-spir64-fp64.pcm 110 | ) 111 | 112 | function(pack_to_obj SRC DST TAG) 113 | add_custom_command ( 114 | OUTPUT ${DST} 115 | DEPENDS ${SRC} ${LINUX_RESOURCE_LINKER_COMMAND} 116 | COMMAND ${LINUX_RESOURCE_LINKER_COMMAND} "${SRC}" "${DST}" "${TAG}" 117 | COMMENT "Packing ${SRC}" 118 | ) 119 | endfunction(pack_to_obj) 120 | 121 | if(WIN32) 122 | list(APPEND CL_HEADERS_SRC OpenCL.rc) 123 | else() 124 | pack_to_obj(opencl-c.h opencl-c.h.cpp "PCM_OPENCL_C_H") 125 | pack_to_obj(opencl-c-base.h opencl-c-base.h.cpp "PCM_OPENCL_C_BASE_H") 126 | list(APPEND CL_HEADERS_SRC 127 | opencl-c.h.cpp 128 | opencl-c-base.h.cpp 129 | opencl-c-12-spir.mod.cpp 130 | opencl-c-20-spir.mod.cpp 131 | opencl-c-30-spir.mod.cpp 132 | opencl-c-12-spir64.mod.cpp 133 | opencl-c-20-spir64.mod.cpp 134 | opencl-c-30-spir64.mod.cpp 135 | opencl-c-12-spir-fp64.mod.cpp 136 | opencl-c-20-spir-fp64.mod.cpp 137 | opencl-c-30-spir-fp64.mod.cpp 138 | opencl-c-12-spir64-fp64.mod.cpp 139 | opencl-c-20-spir64-fp64.mod.cpp 140 | opencl-c-30-spir64-fp64.mod.cpp 141 | module.modulemap.cpp 142 | ) 143 | # note the .pcm -> .mod extension change 144 | # this is a workaround for CMake bug that caused 145 | # dependency cycle in generated build rules 146 | pack_to_obj(opencl-c-12-spir.pcm opencl-c-12-spir.mod.cpp "PCM_OPENCL_C_12_SPIR_PCM") 147 | pack_to_obj(opencl-c-20-spir.pcm opencl-c-20-spir.mod.cpp "PCM_OPENCL_C_20_SPIR_PCM") 148 | pack_to_obj(opencl-c-30-spir.pcm opencl-c-30-spir.mod.cpp "PCM_OPENCL_C_30_SPIR_PCM") 149 | pack_to_obj(opencl-c-12-spir64.pcm opencl-c-12-spir64.mod.cpp "PCM_OPENCL_C_12_SPIR64_PCM") 150 | pack_to_obj(opencl-c-20-spir64.pcm opencl-c-20-spir64.mod.cpp "PCM_OPENCL_C_20_SPIR64_PCM") 151 | pack_to_obj(opencl-c-30-spir64.pcm opencl-c-30-spir64.mod.cpp "PCM_OPENCL_C_30_SPIR64_PCM") 152 | pack_to_obj(opencl-c-12-spir-fp64.pcm opencl-c-12-spir-fp64.mod.cpp "PCM_OPENCL_C_12_SPIR_FP64_PCM") 153 | pack_to_obj(opencl-c-20-spir-fp64.pcm opencl-c-20-spir-fp64.mod.cpp "PCM_OPENCL_C_20_SPIR_FP64_PCM") 154 | pack_to_obj(opencl-c-30-spir-fp64.pcm opencl-c-30-spir-fp64.mod.cpp "PCM_OPENCL_C_30_SPIR_FP64_PCM") 155 | pack_to_obj(opencl-c-12-spir64-fp64.pcm opencl-c-12-spir64-fp64.mod.cpp "PCM_OPENCL_C_12_SPIR64_FP64_PCM") 156 | pack_to_obj(opencl-c-20-spir64-fp64.pcm opencl-c-20-spir64-fp64.mod.cpp "PCM_OPENCL_C_20_SPIR64_FP64_PCM") 157 | pack_to_obj(opencl-c-30-spir64-fp64.pcm opencl-c-30-spir64-fp64.mod.cpp "PCM_OPENCL_C_30_SPIR64_FP64_PCM") 158 | pack_to_obj(module.modulemap module.modulemap.cpp "PCM_OPENCL_C_MODULE_MAP") 159 | endif() 160 | 161 | add_library(${CL_HEADERS_LIB} OBJECT 162 | ${CL_HEADERS_SRC} 163 | ) 164 | 165 | add_dependencies(${CL_HEADERS_LIB} opencl.pcm.target) 166 | install(FILES 167 | ${CMAKE_CURRENT_BINARY_DIR}/opencl-c.h 168 | ${CMAKE_CURRENT_BINARY_DIR}/opencl-c-base.h 169 | ${CMAKE_CURRENT_BINARY_DIR}/module.modulemap 170 | DESTINATION include/cclang 171 | ) 172 | -------------------------------------------------------------------------------- /cl_headers/OpenCL.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #include "resource.h" 4 | 5 | 1 TEXTINCLUDE 6 | BEGIN 7 | "resource.h\0" 8 | END 9 | 10 | // 11 | // Module with OpenCL C declarations with corresponding headers 12 | // 13 | 14 | OPENCL_C_H PCM "opencl-c.h" 15 | OPENCL_C_BASE_H PCM "opencl-c-base.h" 16 | OPENCL_C_12_SPIR_PCM PCM "opencl-c-12-spir.pcm" 17 | OPENCL_C_20_SPIR_PCM PCM "opencl-c-20-spir.pcm" 18 | OPENCL_C_30_SPIR_PCM PCM "opencl-c-30-spir.pcm" 19 | OPENCL_C_12_SPIR64_PCM PCM "opencl-c-12-spir64.pcm" 20 | OPENCL_C_20_SPIR64_PCM PCM "opencl-c-20-spir64.pcm" 21 | OPENCL_C_30_SPIR64_PCM PCM "opencl-c-30-spir64.pcm" 22 | OPENCL_C_12_SPIR_FP64_PCM PCM "opencl-c-12-spir-fp64.pcm" 23 | OPENCL_C_20_SPIR_FP64_PCM PCM "opencl-c-20-spir-fp64.pcm" 24 | OPENCL_C_30_SPIR_FP64_PCM PCM "opencl-c-30-spir-fp64.pcm" 25 | OPENCL_C_12_SPIR64_FP64_PCM PCM "opencl-c-12-spir64-fp64.pcm" 26 | OPENCL_C_20_SPIR64_FP64_PCM PCM "opencl-c-20-spir64-fp64.pcm" 27 | OPENCL_C_30_SPIR64_FP64_PCM PCM "opencl-c-30-spir64-fp64.pcm" 28 | OPENCL_C_MODULE_MAP PCM "module.modulemap" 29 | -------------------------------------------------------------------------------- /cl_headers/module.modulemap: -------------------------------------------------------------------------------- 1 | module cl12spir { 2 | header "opencl-c.h" 3 | header "opencl-c-base.h" 4 | export * 5 | } 6 | module cl20spir { 7 | header "opencl-c.h" 8 | header "opencl-c-base.h" 9 | export * 10 | } 11 | module cl30spir { 12 | header "opencl-c.h" 13 | header "opencl-c-base.h" 14 | export * 15 | } 16 | module cl12spir64 { 17 | header "opencl-c.h" 18 | header "opencl-c-base.h" 19 | export * 20 | } 21 | module cl20spir64 { 22 | header "opencl-c.h" 23 | header "opencl-c-base.h" 24 | export * 25 | } 26 | module cl30spir64 { 27 | header "opencl-c.h" 28 | header "opencl-c-base.h" 29 | export * 30 | } 31 | module cl12spirfp64 { 32 | header "opencl-c.h" 33 | header "opencl-c-base.h" 34 | export * 35 | } 36 | module cl20spirfp64 { 37 | header "opencl-c.h" 38 | header "opencl-c-base.h" 39 | export * 40 | } 41 | module cl30spirfp64 { 42 | header "opencl-c.h" 43 | header "opencl-c-base.h" 44 | export * 45 | } 46 | module cl12spir64fp64 { 47 | header "opencl-c.h" 48 | header "opencl-c-base.h" 49 | export * 50 | } 51 | module cl20spir64fp64 { 52 | header "opencl-c.h" 53 | header "opencl-c-base.h" 54 | export * 55 | } 56 | module cl30spir64fp64 { 57 | header "opencl-c.h" 58 | header "opencl-c-base.h" 59 | export * 60 | } 61 | -------------------------------------------------------------------------------- /cl_headers/resource.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | 3 | Copyright (c) Intel Corporation (2009-2017). 4 | 5 | INTEL MAKES NO WARRANTY OF ANY KIND REGARDING THE CODE. THIS CODE IS 6 | LICENSED ON AN "AS IS" BASIS AND INTEL WILL NOT PROVIDE ANY SUPPORT, 7 | ASSISTANCE, INSTALLATION, TRAINING OR OTHER SERVICES. INTEL DOES NOT 8 | PROVIDE ANY UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY 9 | DISCLAIMS ANY WARRANTY OF MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR ANY 10 | PARTICULAR PURPOSE, OR ANY OTHER WARRANTY. Intel disclaims all liability, 11 | including liability for infringement of any proprietary rights, relating to 12 | use of the code. No license, express or implied, by estoppel or otherwise, 13 | to any intellectual property rights is granted herein. 14 | 15 | \file resource.h 16 | 17 | \*****************************************************************************/ 18 | 19 | #ifndef __RESOURCE__ 20 | #define __RESOURCE__ 21 | 22 | #define OPENCL_C_H "OPENCL_C_H" 23 | #define OPENCL_C_BASE_H "OPENCL_C_BASE_H" 24 | #define OPENCL_C_12_SPIR_PCM "OPENCL_C_12_SPIR_PCM" 25 | #define OPENCL_C_20_SPIR_PCM "OPENCL_C_20_SPIR_PCM" 26 | #define OPENCL_C_30_SPIR_PCM "OPENCL_C_30_SPIR_PCM" 27 | #define OPENCL_C_12_SPIR64_PCM "OPENCL_C_12_SPIR64_PCM" 28 | #define OPENCL_C_20_SPIR64_PCM "OPENCL_C_20_SPIR64_PCM" 29 | #define OPENCL_C_30_SPIR64_PCM "OPENCL_C_30_SPIR64_PCM" 30 | #define OPENCL_C_12_SPIR_FP64_PCM "OPENCL_C_12_SPIR_FP64_PCM" 31 | #define OPENCL_C_20_SPIR_FP64_PCM "OPENCL_C_20_SPIR_FP64_PCM" 32 | #define OPENCL_C_30_SPIR_FP64_PCM "OPENCL_C_30_SPIR_FP64_PCM" 33 | #define OPENCL_C_12_SPIR64_FP64_PCM "OPENCL_C_12_SPIR64_FP64_PCM" 34 | #define OPENCL_C_20_SPIR64_FP64_PCM "OPENCL_C_20_SPIR64_FP64_PCM" 35 | #define OPENCL_C_30_SPIR64_FP64_PCM "OPENCL_C_30_SPIR64_FP64_PCM" 36 | #define OPENCL_C_MODULE_MAP "OPENCL_C_MODULE_MAP" 37 | 38 | #endif /* __RESOURCE__ */ 39 | -------------------------------------------------------------------------------- /cmake/modules/CMakeFunctions.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Set compiler RTTI options according to the given flag 3 | # 4 | macro(use_rtti val) 5 | if (MSVC) 6 | if( ${val} ) 7 | llvm_replace_compiler_option(CMAKE_CXX_FLAGS "/GR-" "/GR") 8 | else() 9 | llvm_replace_compiler_option(CMAKE_CXX_FLAGS "/GR" "/GR-" ) 10 | endif() 11 | else () # G++ or clang or icx 12 | if( ${val} ) 13 | llvm_replace_compiler_option(CMAKE_CXX_FLAGS "-fno-rtti" "-frtti") 14 | else() 15 | llvm_replace_compiler_option(CMAKE_CXX_FLAGS "-frtti" "-fno-rtti" ) 16 | endif() 17 | endif() 18 | endmacro(use_rtti) 19 | 20 | # 21 | # Set compiler Exception Handling options according to the given flag 22 | # 23 | macro(use_eh val) 24 | if (MSVC) 25 | if( ${val} ) 26 | llvm_replace_compiler_option(CMAKE_CXX_FLAGS "/EHs-c-" "/EHsc" ) 27 | add_definitions( /D_HAS_EXCEPTIONS=1 ) 28 | else() 29 | llvm_replace_compiler_option(CMAKE_CXX_FLAGS "/EHsc" "/EHs-c-") 30 | add_definitions( /D_HAS_EXCEPTIONS=0 ) 31 | endif() 32 | else () # G++ or clang or icx 33 | if( ${val} ) 34 | remove_definitions( -fno-exceptions ) 35 | else() 36 | add_definitions( -fno-exceptions ) 37 | endif() 38 | endif() 39 | endmacro(use_eh) 40 | 41 | # Reads hash-commit from backported patch 42 | # This function assumes that each of files starts with (for example): 43 | # From 1a400928bf8fc86fa0f062524c25d0985c94ac6f Mon Sep 17 00:00:00 2001 44 | function(get_backport_patch_hash patch_path patch_hash) 45 | file(READ ${patch_path} first_line LIMIT 40 OFFSET 5) 46 | string(STRIP ${first_line} first_line_strip) 47 | set(patch_hash ${first_line_strip} PARENT_SCOPE) 48 | endfunction() 49 | 50 | # Checks if the the patch is present in current local branch 51 | function(is_backport_patch_present patch_path repo_dir patch_in_branch) 52 | get_backport_patch_hash(${patch_path} patch_hash) 53 | message(STATUS "[OPENCL-CLANG] Checking if patch ${patch_hash} is present in repository") 54 | execute_process( 55 | COMMAND ${GIT_EXECUTABLE} merge-base --is-ancestor ${patch_hash} HEAD 56 | WORKING_DIRECTORY ${repo_dir} 57 | RESULT_VARIABLE patch_not_in_branches 58 | OUTPUT_QUIET 59 | ) 60 | if(patch_not_in_branches) 61 | set(patch_in_branch False PARENT_SCOPE) # The patch is not present in local branch 62 | else() 63 | set(patch_in_branch True PARENT_SCOPE) # The patch is not present in local branch 64 | endif() 65 | endfunction() 66 | 67 | # Validates if given SHA1/tag/branch name exists in local repo 68 | function(is_valid_revision repo_dir revision return_val) 69 | message(STATUS "[OPENCL-CLANG] Validating ${revision} in repository") 70 | # Check if we have under revision existing branch/tag/SHA1 in this repo 71 | execute_process( 72 | COMMAND ${GIT_EXECUTABLE} log -1 ${revision} 73 | WORKING_DIRECTORY ${repo_dir} 74 | RESULT_VARIABLE output_var 75 | OUTPUT_QUIET 76 | ) 77 | if(${output_var} EQUAL 0) 78 | set(${return_val} True PARENT_SCOPE) # this tag/branch/sha1 exists in repo 79 | else() 80 | set(${return_val} False PARENT_SCOPE) # this tag/branch/sha1 not exists in repo 81 | endif() 82 | endfunction() 83 | 84 | # 85 | # Creates `target_branch` starting at the `base_revision` in the `repo_dir`. 86 | # Then all patches from the `patches_dir` are committed to the `target_branch`. 87 | # Does nothing if the `target_branch` is already checked out in the `repo_dir`. 88 | # 89 | function(apply_patches repo_dir patches_dir base_revision target_branch) 90 | file(GLOB patches ${patches_dir}/*.patch) 91 | if(NOT patches) 92 | message(STATUS "[OPENCL-CLANG] No patches in ${patches_dir}") 93 | return() 94 | endif() 95 | 96 | message(STATUS "[OPENCL-CLANG] Patching repository ${repo_dir}") 97 | # Check if the target branch already exists 98 | execute_process( 99 | COMMAND ${GIT_EXECUTABLE} rev-parse --verify --no-revs -q ${target_branch} 100 | WORKING_DIRECTORY ${repo_dir} 101 | RESULT_VARIABLE patches_needed 102 | OUTPUT_QUIET 103 | ) 104 | if(patches_needed EQUAL 128) 105 | message(STATUS "[OPENCL-CLANG][Warning] ${repo_dir} is not a git repository, therefore, local patches are not applied") 106 | return() 107 | endif() 108 | if(patches_needed EQUAL 1) # The target branch doesn't exist 109 | list(SORT patches) 110 | is_valid_revision(${repo_dir} ${base_revision} exists_base_rev) 111 | 112 | if(NOT ${exists_base_rev}) 113 | execute_process( # take SHA1 from HEAD 114 | COMMAND ${GIT_EXECUTABLE} rev-parse HEAD 115 | WORKING_DIRECTORY ${repo_dir} 116 | OUTPUT_VARIABLE repo_head 117 | OUTPUT_STRIP_TRAILING_WHITESPACE 118 | ) 119 | message(STATUS "[OPENCL-CLANG] ref ${base_revision} not exists in repository, using current HEAD:${repo_head}") 120 | set(base_revision ${repo_head}) 121 | endif() 122 | execute_process( # Create the target branch 123 | COMMAND ${GIT_EXECUTABLE} checkout -b ${target_branch} ${base_revision} 124 | WORKING_DIRECTORY ${repo_dir} 125 | RESULT_VARIABLE ret_check_out 126 | ERROR_STRIP_TRAILING_WHITESPACE 127 | ERROR_VARIABLE checkout_log 128 | OUTPUT_QUIET 129 | ) 130 | message(STATUS "[OPENCL-CLANG] ${checkout_log} which starts from ref : ${base_revision}") 131 | foreach(patch ${patches}) 132 | is_backport_patch_present(${patch} ${repo_dir} patch_in_branch) 133 | if(${patch_in_branch}) 134 | message(STATUS "[OPENCL-CLANG] Patch ${patch} is already in local branch - ignore patching") 135 | else() 136 | execute_process( # Apply the patch 137 | COMMAND ${GIT_EXECUTABLE} am --3way --ignore-whitespace ${patch} 138 | WORKING_DIRECTORY ${repo_dir} 139 | OUTPUT_VARIABLE patching_log 140 | ) 141 | message(STATUS "[OPENCL-CLANG] Not present - ${patching_log}") 142 | endif() 143 | endforeach(patch) 144 | elsef(patches_needed EQUAL 0) # The target branch already exists 145 | execute_process( # Check it out 146 | COMMAND ${GIT_EXECUTABLE} checkout ${target_branch} 147 | WORKING_DIRECTORY ${repo_dir} 148 | OUTPUT_QUIET 149 | ) 150 | endif() 151 | if (ret_check_out OR ret_apply_patch) 152 | message(FATAL_ERROR "[OPENCL-CLANG] Failed to apply patch!") 153 | endif() 154 | endfunction() 155 | 156 | # Usage 157 | # SET_LINUX_EXPORTS_FILE( TARGET FILE_NAME ) 158 | # This function provides special linkage options for OCL Back-End. These options 159 | # prevents exposure of function symbols externally (except functions which are 160 | # explicitly listed in version script) 161 | function ( SET_LINUX_EXPORTS_FILE TARGET FILE_NAME ) 162 | if(NOT WIN32) 163 | get_target_property( SOURCE_FILES ${TARGET_NAME} SOURCES ) 164 | list( GET SOURCE_FILES 0 FIRST_SOURCE ) 165 | set_source_files_properties( ${FIRST_SOURCE} PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${FILE_NAME} ) 166 | set_property( TARGET ${TARGET_NAME} APPEND_STRING PROPERTY 167 | LINK_FLAGS " -Wl,-Bsymbolic -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/${FILE_NAME}" ) 168 | endif(NOT WIN32) 169 | endfunction ( SET_LINUX_EXPORTS_FILE ) 170 | -------------------------------------------------------------------------------- /linux_linker/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(linux_resource_linker linux_resource_linker.cpp) 2 | 3 | if(LLVM_USE_HOST_TOOLS) 4 | build_native_tool(linux_resource_linker LINUX_RESOURCE_LINKER_COMMAND) 5 | add_custom_target(linux_resource_linker-host DEPENDS ${LINUX_RESOURCE_LINKER_COMMAND} ) 6 | add_dependencies(linux_resource_linker linux_resource_linker-host) 7 | else() 8 | set(LINUX_RESOURCE_LINKER_COMMAND linux_resource_linker) 9 | endif() 10 | 11 | set(LINUX_RESOURCE_LINKER_COMMAND ${LINUX_RESOURCE_LINKER_COMMAND} PARENT_SCOPE) 12 | -------------------------------------------------------------------------------- /linux_linker/linux_resource_linker.cpp: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | 3 | Copyright (c) Intel Corporation (2009-2017). 4 | 5 | INTEL MAKES NO WARRANTY OF ANY KIND REGARDING THE CODE. THIS CODE IS 6 | LICENSED ON AN "AS IS" BASIS AND INTEL WILL NOT PROVIDE ANY SUPPORT, 7 | ASSISTANCE, INSTALLATION, TRAINING OR OTHER SERVICES. INTEL DOES NOT 8 | PROVIDE ANY UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY 9 | DISCLAIMS ANY WARRANTY OF MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR ANY 10 | PARTICULAR PURPOSE, OR ANY OTHER WARRANTY. Intel disclaims all liability, 11 | including liability for infringement of any proprietary rights, relating to 12 | use of the code. No license, express or implied, by estoppel or otherwise, 13 | to any intellectual property rights is granted herein. 14 | 15 | \file linux_resource_linker.cpp 16 | 17 | \*****************************************************************************/ 18 | 19 | #include 20 | #include 21 | 22 | int main(int argc, char **argv) 23 | { 24 | FILE *input; 25 | FILE *output; 26 | 27 | if (!argv[1] || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help") || !argv[2] || !argv[3]) 28 | { 29 | printf("Usage: bif_linker [input file] [output file] [symbol base name]\n"); 30 | return 0; 31 | } 32 | 33 | input = fopen(argv[1], "rb"); 34 | if (!input) 35 | { 36 | printf("Unable to open input file for reading (%s)\n", argv[1]); 37 | return 1; 38 | } 39 | 40 | output = fopen(argv[2], "wb"); 41 | if (!output) 42 | { 43 | printf("Unable to open output file for writing (%s)\n", argv[2]); 44 | return 1; 45 | } 46 | 47 | fprintf(output, "// This file is auto generated by bo_linker, DO NOT EDIT\n\n"); 48 | fprintf(output, "unsigned char __attribute__((visibility(\"default\"))) %s[] =\n{\n ", argv[3]); 49 | 50 | int count = 0; 51 | int is_eol; 52 | unsigned char data; 53 | while(fread(&data, 1, 1, input)) 54 | { 55 | is_eol = count ? !(count % 20) : 0; 56 | fprintf(output, "%s0x%.2x, ", is_eol? "\n ":"", data); 57 | count++; 58 | } 59 | fprintf(output, "0x00\n};\n\n"); 60 | 61 | fprintf(output, "unsigned int __attribute__((visibility(\"default\"))) %s_size = %d;\n\n", argv[3], count); 62 | fclose(input); 63 | fclose(output); 64 | 65 | } 66 | -------------------------------------------------------------------------------- /opencl_clang.cpp: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | 3 | Copyright (c) Intel Corporation (2009-2017). 4 | 5 | INTEL MAKES NO WARRANTY OF ANY KIND REGARDING THE CODE. THIS CODE IS 6 | LICENSED ON AN "AS IS" BASIS AND INTEL WILL NOT PROVIDE ANY SUPPORT, 7 | ASSISTANCE, INSTALLATION, TRAINING OR OTHER SERVICES. INTEL DOES NOT 8 | PROVIDE ANY UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY 9 | DISCLAIMS ANY WARRANTY OF MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR ANY 10 | PARTICULAR PURPOSE, OR ANY OTHER WARRANTY. Intel disclaims all liability, 11 | including liability for infringement of any proprietary rights, relating to 12 | use of the code. No license, express or implied, by estoppel or otherwise, 13 | to any intellectual property rights is granted herein. 14 | 15 | \file opencl_clang.cpp 16 | 17 | \*****************************************************************************/ 18 | 19 | #include "opencl_clang.h" 20 | #include "pch_mgr.h" 21 | #include "cl_headers/resource.h" 22 | #include "binary_result.h" 23 | #include "options.h" 24 | 25 | #include "llvm/ADT/SmallVector.h" 26 | #include "llvm/ADT/ArrayRef.h" 27 | #include "llvm/ADT/Twine.h" 28 | #include "llvm/IR/Constants.h" 29 | #include "llvm/IR/Module.h" 30 | #include "llvm/IR/LLVMContext.h" 31 | #include "llvm/IR/Metadata.h" 32 | #include "llvm/Bitcode/BitcodeWriter.h" 33 | #include "llvm/Bitcode/BitcodeReader.h" 34 | #include "llvm/Support/MemoryBuffer.h" 35 | #include "llvm/Support/raw_ostream.h" 36 | #include "llvm/Support/Casting.h" 37 | #include "llvm/Support/Path.h" 38 | #include "llvm/Support/Threading.h" 39 | #include "llvm/Support/ManagedStatic.h" 40 | #include "llvm/Support/Mutex.h" 41 | #include "clang/Basic/LangOptions.h" 42 | #include "clang/Basic/Diagnostic.h" 43 | #include "clang/Basic/DiagnosticIDs.h" 44 | #include "clang/Basic/DiagnosticOptions.h" 45 | #include "clang/Frontend/TextDiagnosticPrinter.h" 46 | #include "clang/Frontend/CompilerInstance.h" 47 | #include "clang/FrontendTool/Utils.h" 48 | #ifdef USE_PREBUILT_LLVM 49 | #include "LLVMSPIRVLib/LLVMSPIRVLib.h" 50 | #else // USE_PREBUILT_LLVM 51 | #include "LLVMSPIRVLib.h" 52 | #endif // USE_PREBUILT_LLVM 53 | 54 | // The following #defines are used as return value of Compile() API and defined 55 | // in https://github.com/KhronosGroup/OpenCL-Headers/blob/master/CL/cl.h 56 | #define CL_SUCCESS 0 57 | #define CL_COMPILE_PROGRAM_FAILURE -15 58 | #define CL_OUT_OF_HOST_MEMORY -6 59 | 60 | #include "assert.h" 61 | #include 62 | #include 63 | #ifdef _WIN32 64 | #include 65 | #endif 66 | 67 | #if defined _DEBUG 68 | #include 69 | #include 70 | #include 71 | #include 72 | #endif 73 | 74 | using namespace Intel::OpenCL::ClangFE; 75 | 76 | llvm::ManagedStatic> compileMutex; 77 | 78 | void OpenCLClangTerminate() { llvm::llvm_shutdown(); } 79 | 80 | // This function mustn't be invoked from a static object constructor, 81 | // from a DllMain function (Windows specific), or from a function 82 | // w\ __attribute__ ((constructor)) (Linux specific). 83 | void OpenCLClangInitialize() { 84 | // OpenCLClangTerminate calls llvm_shutdown to deallocate resources used 85 | // by LLVM libraries. llvm_shutdown uses static mutex to make it safe for 86 | // multi-threaded envirounment and LLVM libraries user is expected call 87 | // llvm_shutdown before static object are destroyed, so we use atexit to 88 | // satisfy this requirement. 89 | llvm::once_flag OnceFlag; 90 | llvm::call_once(OnceFlag, []() { atexit(OpenCLClangTerminate); }); 91 | } 92 | 93 | static bool GetHeaders(std::vector &Result) { 94 | struct { 95 | const char *ID; 96 | const char *Name; 97 | } Headers[] = {{OPENCL_C_H, "opencl-c.h"}, 98 | {OPENCL_C_BASE_H, "opencl-c-base.h"}, 99 | {OPENCL_C_12_SPIR_PCM, "opencl-c-12-spir.pcm"}, 100 | {OPENCL_C_20_SPIR_PCM, "opencl-c-20-spir.pcm"}, 101 | {OPENCL_C_30_SPIR_PCM, "opencl-c-30-spir.pcm"}, 102 | {OPENCL_C_12_SPIR64_PCM, "opencl-c-12-spir64.pcm"}, 103 | {OPENCL_C_20_SPIR64_PCM, "opencl-c-20-spir64.pcm"}, 104 | {OPENCL_C_30_SPIR64_PCM, "opencl-c-30-spir64.pcm"}, 105 | {OPENCL_C_12_SPIR_FP64_PCM, "opencl-c-12-spir-fp64.pcm"}, 106 | {OPENCL_C_20_SPIR_FP64_PCM, "opencl-c-20-spir-fp64.pcm"}, 107 | {OPENCL_C_30_SPIR_FP64_PCM, "opencl-c-30-spir-fp64.pcm"}, 108 | {OPENCL_C_12_SPIR64_FP64_PCM, "opencl-c-12-spir64-fp64.pcm"}, 109 | {OPENCL_C_20_SPIR64_FP64_PCM, "opencl-c-20-spir64-fp64.pcm"}, 110 | {OPENCL_C_30_SPIR64_FP64_PCM, "opencl-c-30-spir64-fp64.pcm"}, 111 | {OPENCL_C_MODULE_MAP, "module.modulemap"}}; 112 | 113 | Result.clear(); 114 | Result.reserve(sizeof(Headers) / sizeof(*Headers)); 115 | 116 | ResourceManager &RM = ResourceManager::instance(); 117 | for (auto Header : Headers) { 118 | Resource R = RM.get_resource(Header.Name, Header.ID, "PCM", true); 119 | if (!R) { 120 | assert(false && "Resource not found"); 121 | return false; 122 | } 123 | 124 | Result.push_back(R); 125 | } 126 | 127 | return true; 128 | } 129 | 130 | static void PrintCompileOptions(const char *pszOptions, const char *pszOptionsEx, 131 | const char *pszOpenCLVer, const char * pszSource) { 132 | #ifdef _DEBUG 133 | static int ID = 0; 134 | 135 | if (!getenv("CCLANG_OPTIONS_DIR")) return; 136 | 137 | std::string OptionsDir = getenv("CCLANG_OPTIONS_DIR"); 138 | 139 | std::stringstream logPath; 140 | logPath << OptionsDir << "/log_" << std::this_thread::get_id() << "_" << ID << ".txt"; 141 | std::cout << logPath.str() << std::endl; 142 | 143 | // Creating log file 144 | std::ofstream logFile(logPath.str(), std::ios::out); 145 | 146 | if (!logFile.is_open()) { 147 | std::cout << "[ERROR] Can't create log file" << std::endl; 148 | return; 149 | } 150 | 151 | logFile << "pszOptions=" << pszOptions << std::endl; 152 | logFile << "pszOptionsEx=" << pszOptionsEx << std::endl; 153 | logFile << "pszOpenCLVer=" << pszOpenCLVer << std::endl; 154 | logFile << pszSource; 155 | ++ID; 156 | logFile.close(); 157 | #endif 158 | } 159 | 160 | class SmallVectorBuffer : public std::streambuf 161 | { 162 | // All memory management is delegated to llvm::SmallVectorImpl 163 | llvm::SmallVectorImpl &OS; 164 | 165 | // Since we don't touch any pointer in streambuf(pbase, pptr, epptr) this is 166 | // the only method we need to override. 167 | virtual std::streamsize xsputn(const char *s, std::streamsize n) override { 168 | OS.append(s, s + n); 169 | return n; 170 | } 171 | 172 | public: 173 | SmallVectorBuffer() = delete; 174 | SmallVectorBuffer(const SmallVectorBuffer&) = delete; 175 | SmallVectorBuffer &operator=(const SmallVectorBuffer&) = delete; 176 | SmallVectorBuffer(llvm::SmallVectorImpl &O) : OS(O) {} 177 | }; 178 | 179 | extern "C" CC_DLL_EXPORT int 180 | Compile(const char *pszProgramSource, const char **pInputHeaders, 181 | unsigned int uiNumInputHeaders, const char **pInputHeadersNames, 182 | const char *pPCHBuffer, size_t uiPCHBufferSize, const char *pszOptions, 183 | const char *pszOptionsEx, const char *pszOpenCLVer, 184 | IOCLFEBinaryResult **pBinaryResult) { 185 | 186 | // Capturing cclang compile options 187 | PrintCompileOptions(pszOptions, pszOptionsEx, pszOpenCLVer, pszProgramSource); 188 | 189 | // Lazy initialization 190 | OpenCLClangInitialize(); 191 | 192 | try { 193 | #ifdef _WIN32 194 | llvm::sys::SmartScopedLock compileGuard{*compileMutex}; 195 | #endif 196 | std::unique_ptr pResult(new OCLFEBinaryResult()); 197 | 198 | // Create the clang compiler 199 | std::unique_ptr compiler( 200 | new clang::CompilerInstance()); 201 | 202 | CompileOptionsParser optionsParser(pszOpenCLVer); 203 | 204 | // Prepare error log 205 | llvm::raw_string_ostream err_ostream(pResult->getLogRef()); 206 | { 207 | #ifndef _WIN32 208 | llvm::sys::SmartScopedLock compileGuard{*compileMutex}; 209 | #endif 210 | // Parse options 211 | optionsParser.processOptions(pszOptions, pszOptionsEx); 212 | 213 | // Prepare our diagnostic client. 214 | llvm::IntrusiveRefCntPtr DiagID( 215 | new clang::DiagnosticIDs()); 216 | clang::DiagnosticOptions DiagOpts; 217 | DiagOpts.ShowPresumedLoc = true; 218 | clang::TextDiagnosticPrinter *DiagsPrinter = 219 | new clang::TextDiagnosticPrinter(err_ostream, DiagOpts); 220 | llvm::IntrusiveRefCntPtr Diags( 221 | new clang::DiagnosticsEngine(DiagID, DiagOpts, DiagsPrinter)); 222 | 223 | // Prepare output buffer 224 | std::unique_ptr 225 | ir_ostream(new llvm::raw_svector_ostream(pResult->getIRBufferRef())); 226 | // Set buffers 227 | // CompilerInstance takes ownership over output stream 228 | compiler->setOutputStream(std::move(ir_ostream)); 229 | 230 | compiler->setDiagnostics(&*Diags); 231 | 232 | llvm::IntrusiveRefCntPtr OverlayFS( 233 | new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem())); 234 | llvm::IntrusiveRefCntPtr MemFS( 235 | new llvm::vfs::InMemoryFileSystem); 236 | OverlayFS->pushOverlay(MemFS); 237 | 238 | compiler->createFileManager(std::move(OverlayFS)); 239 | compiler->createSourceManager(compiler->getFileManager()); 240 | 241 | // Create compiler invocation from user args before trickering with it 242 | clang::CompilerInvocation::CreateFromArgs(compiler->getInvocation(), 243 | optionsParser.args(), *Diags); 244 | 245 | // Configure our handling of diagnostics. 246 | ProcessWarningOptions(*Diags, compiler->getDiagnosticOpts(), 247 | compiler->getFileManager().getVirtualFileSystem()); 248 | 249 | // Map memory buffers to a virtual file system 250 | MemFS->addFile( 251 | optionsParser.getSourceName(), (time_t)0, 252 | llvm::MemoryBuffer::getMemBuffer( 253 | llvm::StringRef(pszProgramSource), optionsParser.getSourceName())); 254 | 255 | // Input header with OpenCL defines. 256 | std::vector vHeaderWithDefs; 257 | if (!GetHeaders(vHeaderWithDefs)) { 258 | return CL_COMPILE_PROGRAM_FAILURE; 259 | } 260 | 261 | for (const auto &Header:vHeaderWithDefs) { 262 | auto Buf = llvm::MemoryBuffer::getMemBuffer( 263 | llvm::StringRef(Header.m_data, Header.m_size), 264 | Header.m_name); 265 | 266 | MemFS->addFile(Header.m_name,(time_t)0, std::move(Buf)); 267 | } 268 | 269 | // Input Headers 270 | for (unsigned int i = 0; i < uiNumInputHeaders; ++i) { 271 | auto Header = llvm::MemoryBuffer::getMemBuffer( 272 | pInputHeaders[i], pInputHeadersNames[i]); 273 | MemFS->addFile(pInputHeadersNames[i], (time_t)0, std::move(Header)); 274 | } 275 | } 276 | // Execute the frontend actions. 277 | bool success = false; 278 | try { 279 | success = clang::ExecuteCompilerInvocation(compiler.get()); 280 | } catch (const std::exception &) { 281 | } 282 | pResult->setIRType(IR_TYPE_COMPILED_OBJECT); 283 | pResult->setIRName(optionsParser.getSourceName()); 284 | 285 | // Our error handler depends on the Diagnostics object, which we're 286 | // potentially about to delete. Uninstall the handler now so that any 287 | // later errors use the default handling behavior instead. 288 | // (currently commented out since setting the llvm error handling in 289 | // multi-threaded environment is unsupported) 290 | // llvm::remove_fatal_error_handler(); 291 | err_ostream.flush(); 292 | 293 | if (success && optionsParser.hasEmitSPIRV()) { 294 | // Translate LLVM IR to SPIR-V. 295 | llvm::StringRef LLVM_IR(static_cast(pResult->GetIR()), 296 | pResult->GetIRSize()); 297 | std::unique_ptr MB = llvm::MemoryBuffer::getMemBuffer(LLVM_IR, pResult->GetIRName(), false); 298 | llvm::LLVMContext Context; 299 | auto E = llvm::getOwningLazyBitcodeModule(std::move(MB), Context, 300 | /*ShouldLazyLoadMetadata=*/true); 301 | llvm::logAllUnhandledErrors(E.takeError(), err_ostream, "error: "); 302 | std::unique_ptr M = std::move(*E); 303 | 304 | if (M->materializeAll()) { 305 | if (pBinaryResult) { 306 | *pBinaryResult = nullptr; 307 | } 308 | assert(false && "Failed to read just compiled LLVM IR!"); 309 | return CL_COMPILE_PROGRAM_FAILURE; 310 | } 311 | pResult->getIRBufferRef().clear(); 312 | SmallVectorBuffer StreamBuf(pResult->getIRBufferRef()); 313 | std::ostream OS(&StreamBuf); 314 | std::string Err; 315 | SPIRV::TranslatorOpts SPIRVOpts; 316 | SPIRVOpts.enableAllExtensions(); 317 | if (!optionsParser.hasOptDisable()) { 318 | SPIRVOpts.setMemToRegEnabled(true); 319 | } 320 | SPIRVOpts.setPreserveOCLKernelArgTypeMetadataThroughString(true); 321 | success = llvm::writeSpirv(M.get(), SPIRVOpts, OS, Err); 322 | err_ostream << Err.c_str(); 323 | err_ostream.flush(); 324 | } 325 | { 326 | #ifndef _WIN32 327 | llvm::sys::SmartScopedLock compileGuard{*compileMutex}; 328 | #endif 329 | if (pBinaryResult) { 330 | *pBinaryResult = pResult.release(); 331 | } 332 | } 333 | return success ? CL_SUCCESS : CL_COMPILE_PROGRAM_FAILURE; 334 | } catch (std::bad_alloc &) { 335 | if (pBinaryResult) { 336 | *pBinaryResult = NULL; 337 | } 338 | return CL_OUT_OF_HOST_MEMORY; 339 | } 340 | } 341 | -------------------------------------------------------------------------------- /opencl_clang.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | 3 | Copyright (c) Intel Corporation (2009-2017). 4 | 5 | INTEL MAKES NO WARRANTY OF ANY KIND REGARDING THE CODE. THIS CODE IS 6 | LICENSED ON AN "AS IS" BASIS AND INTEL WILL NOT PROVIDE ANY SUPPORT, 7 | ASSISTANCE, INSTALLATION, TRAINING OR OTHER SERVICES. INTEL DOES NOT 8 | PROVIDE ANY UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY 9 | DISCLAIMS ANY WARRANTY OF MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR ANY 10 | PARTICULAR PURPOSE, OR ANY OTHER WARRANTY. Intel disclaims all liability, 11 | including liability for infringement of any proprietary rights, relating to 12 | use of the code. No license, express or implied, by estoppel or otherwise, 13 | to any intellectual property rights is granted herein. 14 | 15 | \file opencl_clang.h 16 | 17 | \*****************************************************************************/ 18 | 19 | #pragma once 20 | #include "assert.h" 21 | #include "cstddef" // size_t 22 | 23 | #if defined(_WIN32) 24 | #if defined(OPENCL_CLANG_EXPORTS) 25 | #define CC_DLL_EXPORT _declspec(dllexport) 26 | #else 27 | #define CC_DLL_EXPORT _declspec(dllimport) 28 | #endif 29 | #else 30 | #define CC_DLL_EXPORT 31 | #endif 32 | 33 | namespace Intel { 34 | namespace OpenCL { 35 | namespace ClangFE { 36 | // 37 | // Type of the binary returned after compilation and/or link 38 | // 39 | enum IR_TYPE { 40 | IR_TYPE_UNKNOWN, 41 | IR_TYPE_EXECUTABLE, 42 | IR_TYPE_LIBRARY, 43 | IR_TYPE_COMPILED_OBJECT 44 | }; 45 | 46 | // 47 | // Compilation results interface 48 | // Returned by Compile method 49 | // 50 | struct IOCLFEBinaryResult { 51 | // Returns the size in bytes of the IR buffer 52 | virtual size_t GetIRSize() const = 0; 53 | // Returns the pointer to the IR buffer or NULL if no IR buffer is present 54 | virtual const void *GetIR() const = 0; 55 | // Returns the name of the program 56 | virtual const char *GetIRName() const = 0; 57 | // Returns the type of the resulted binary 58 | virtual IR_TYPE GetIRType() const = 0; 59 | // Returns the pointer to the compilation log string or NULL if not log was 60 | // created 61 | virtual const char *GetErrorLog() const = 0; 62 | // Releases the result object 63 | virtual void Release() = 0; 64 | 65 | protected: 66 | virtual ~IOCLFEBinaryResult() {} 67 | }; 68 | } 69 | } 70 | } 71 | 72 | // 73 | // Verifies the given OpenCL application supplied compilation options 74 | // Params: 75 | // pszOptions - compilation options string 76 | // pszUnknownOptions - optional outbound pointer to the space separated 77 | // unrecognized options 78 | // uiUnknownOptionsSize - size of the pszUnknownOptions buffer 79 | // Returns: 80 | // true if the options verification was successful, false otherwise 81 | // 82 | extern "C" CC_DLL_EXPORT bool CheckCompileOptions( 83 | // A string for compile options 84 | const char *pszOptions, 85 | // buffer to get the list of unknown options 86 | char *pszUnknownOptions, 87 | // size of the buffer for unknown options 88 | size_t uiUnknownOptionsSize); 89 | 90 | // 91 | // Compiles the given OpenCL program to the LLVM IR 92 | // Params: 93 | // pProgramSource - OpenCL source program to compile 94 | // pInputHeaders - array of the header buffers 95 | // uiNumInputHeader - size of the pInputHeaders array 96 | // pszInputHeadersNames - array of the headers names 97 | // pPCHBuffer - optional pointer to the pch buffer 98 | // uiPCHBufferSize - size of the pch buffer 99 | // pszOptions - OpenCL application supplied options 100 | // pszOptionsEx - optional extra options string usually supplied by runtime 101 | // pszOpenCLVer - OpenCL version supported by the device, also defines 102 | // __OPENCL_VERSION__ macro - "120" for OpenCL 1.2, "200" for OpenCL 2.0, ... 103 | // pBinaryResult - optional outbound pointer to the compilation results 104 | // Returns: 105 | // Compilation Result as int: 0 - success, error otherwise. 106 | // 107 | extern "C" CC_DLL_EXPORT int Compile( 108 | // A pointer to main program's source (null terminated string) 109 | const char *pszProgramSource, 110 | // array of additional input headers to be passed in memory (each null 111 | // terminated) 112 | const char **pInputHeaders, 113 | // the number of input headers in pInputHeaders 114 | unsigned int uiNumInputHeaders, 115 | // array of input headers names corresponding to pInputHeaders 116 | const char **pInputHeadersNames, 117 | // optional pointer to the pch buffer 118 | const char *pPCHBuffer, 119 | // size of the pch buffer 120 | size_t uiPCHBufferSize, 121 | // OpenCL application supplied options 122 | const char *pszOptions, 123 | // optional extra options string usually supplied by runtime 124 | const char *pszOptionsEx, 125 | // OpenCL version string - "120" for OpenCL 1.2, "200" for OpenCL 2.0, ... 126 | const char *pszOpenCLVer, 127 | // optional outbound pointer to the compilation results 128 | Intel::OpenCL::ClangFE::IOCLFEBinaryResult **pBinaryResult); 129 | 130 | -------------------------------------------------------------------------------- /opencl_clang.map: -------------------------------------------------------------------------------- 1 | { 2 | global: 3 | extern "C" { 4 | CheckCompileOptions; 5 | CheckLinkOptions; 6 | Compile; 7 | Link; 8 | GetKernelArgInfo; 9 | PCM_OPENCL_C_H*; 10 | PCM_OPENCL_C_BASE_H*; 11 | PCM_OPENCL_C_12_SPIR_PCM*; 12 | PCM_OPENCL_C_20_SPIR_PCM*; 13 | PCM_OPENCL_C_30_SPIR_PCM*; 14 | PCM_OPENCL_C_12_SPIR64_PCM*; 15 | PCM_OPENCL_C_20_SPIR64_PCM*; 16 | PCM_OPENCL_C_30_SPIR64_PCM*; 17 | PCM_OPENCL_C_12_SPIR_FP64_PCM*; 18 | PCM_OPENCL_C_20_SPIR_FP64_PCM*; 19 | PCM_OPENCL_C_30_SPIR_FP64_PCM*; 20 | PCM_OPENCL_C_12_SPIR64_FP64_PCM*; 21 | PCM_OPENCL_C_20_SPIR64_FP64_PCM*; 22 | PCM_OPENCL_C_30_SPIR64_FP64_PCM*; 23 | PCM_OPENCL_C_MODULE_MAP*; 24 | }; 25 | local: *; 26 | }; 27 | -------------------------------------------------------------------------------- /opencl_clang_options.td: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // This file defines the options accepted by opencl_clang. 4 | // 5 | //===----------------------------------------------------------------------===// 6 | 7 | // Include the common option parsing interfaces. 8 | include "llvm/Option/OptParser.td" 9 | 10 | 11 | //===----------------------------------------------------------------------===// 12 | // OpenCL Options 13 | //===----------------------------------------------------------------------===// 14 | def g_Flag : Flag<["-"], "g">, HelpText<"Generate source level debug information">; 15 | def gline_tables_only_Flag : Flag<["-"], "gline-tables-only">; 16 | def profiling : Flag<["-"], "profiling">, HelpText<"Allow profiling">; 17 | def coverage: Flag<["-"], "coverage">, HelpText<"Enable source level coverage analysis">; 18 | def w : Flag<["-"], "w">, HelpText<"Suppress all warnings">; 19 | def D : JoinedOrSeparate<["-"], "D">; 20 | def I : JoinedOrSeparate<["-"], "I">, Flags<[RenderJoined]>, HelpText<"Add directory to include search path">; 21 | def s : Separate<["-"], "s">; 22 | def Werror : Flag<["-"], "Werror">; 23 | def cl_single_precision_constant : Flag<["-"], "cl-single-precision-constant">; 24 | def cl_denorms_are_zero : Flag<["-"], "cl-denorms-are-zero">; 25 | def cl_fp32_correctly_rounded_divide_sqrt : Flag<["-"], "cl-fp32-correctly-rounded-divide-sqrt">; 26 | def cl_opt_disable : Flag<["-"], "cl-opt-disable">; 27 | def cl_mad_enable : Flag<["-"], "cl-mad-enable">; 28 | def cl_no_signed_zeros : Flag<["-"], "cl-no-signed-zeros">; 29 | def cl_unsafe_math_optimizations: Flag<["-"], "cl-unsafe-math-optimizations">; 30 | def cl_finite_math_only: Flag<["-"], "cl-finite-math-only">; 31 | def cl_fast_relaxed_math: Flag<["-"], "cl-fast-relaxed-math">; 32 | def cl_kernel_arg_info: Flag<["-"], "cl-kernel-arg-info">; 33 | def cl_std_CL1_1: Flag<["-"], "cl-std=CL1.1">; 34 | def cl_std_CL1_2: Flag<["-"], "cl-std=CL1.2">; 35 | def cl_std_CL2_0: Flag<["-"], "cl-std=CL2.0">; 36 | def cl_std_CL3_0: Flag<["-"], "cl-std=CL3.0">; 37 | def cl_std_CLCxx: Flag<["-"], "cl-std=CLC++">; 38 | def cl_std_CLCxx1_0: Flag<["-"], "cl-std=CLC++1.0">; 39 | def cl_std_CLCxx2021: Flag<["-"], "cl-std=CLC++2021">; 40 | def cl_uniform_work_group_size: Flag<["-"], "cl-uniform-work-group-size">; 41 | def cl_no_subgroup_ifp: Flag<["-"], "cl-no-subgroup-ifp">; 42 | def triple : Separate<["-"], "triple">, HelpText<"Specify target triple (e.g. i686-apple-darwin9)">; 43 | def target_triple : Separate<["-"], "target-triple">, HelpText<"Specify target triple for spir">; 44 | def spir_std_1_0: Flag<["-"], "spir-std=1.0">; 45 | def spir_std_1_2: Flag<["-"], "spir-std=1.2">; 46 | def x : Separate<["-"], "x">; 47 | -------------------------------------------------------------------------------- /options.cpp: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | 3 | Copyright (c) Intel Corporation (2009-2017). 4 | 5 | INTEL MAKES NO WARRANTY OF ANY KIND REGARDING THE CODE. THIS CODE IS 6 | LICENSED ON AN "AS IS" BASIS AND INTEL WILL NOT PROVIDE ANY SUPPORT, 7 | ASSISTANCE, INSTALLATION, TRAINING OR OTHER SERVICES. INTEL DOES NOT 8 | PROVIDE ANY UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY 9 | DISCLAIMS ANY WARRANTY OF MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR ANY 10 | PARTICULAR PURPOSE, OR ANY OTHER WARRANTY. Intel disclaims all liability, 11 | including liability for infringement of any proprietary rights, relating to 12 | use of the code. No license, express or implied, by estoppel or otherwise, 13 | to any intellectual property rights is granted herein. 14 | 15 | \file options.cpp 16 | 17 | \*****************************************************************************/ 18 | 19 | #include "options.h" 20 | 21 | #include "llvm/Option/Arg.h" 22 | #include "clang/Driver/Options.h" 23 | 24 | #include 25 | #include 26 | 27 | using namespace llvm::opt; 28 | 29 | OpenCLArgList::OpenCLArgList(const char *pszOptions) { 30 | std::back_insert_iterator it( 31 | std::back_inserter(m_synthesizedStrings)); 32 | quoted_tokenize(it, pszOptions, " \t", '"', '\\'); 33 | 34 | // need to be careful about the reallocation that could happen in 35 | // m_synthesizedStrings upon push_back 36 | for (ArgsVector::const_iterator it = m_synthesizedStrings.begin(), 37 | end = m_synthesizedStrings.end(); 38 | it != end; ++it) { 39 | m_argStrings.push_back(it->c_str()); 40 | } 41 | m_uiOriginalArgsCount = m_argStrings.size(); 42 | } 43 | 44 | unsigned OpenCLArgList::MakeIndex(llvm::StringRef str) const { 45 | unsigned index = m_argStrings.size(); 46 | 47 | // Tuck away so we have a reliable const char *. 48 | m_synthesizedStrings.push_back(std::string(str)); 49 | m_argStrings.push_back(m_synthesizedStrings.back().c_str()); 50 | 51 | return index; 52 | } 53 | 54 | unsigned OpenCLArgList::MakeIndex(llvm::StringRef str0, 55 | llvm::StringRef str1) const { 56 | unsigned index0 = MakeIndex(str0); 57 | unsigned index1 = MakeIndex(str1); 58 | assert(index0 + 1 == index1 && "Unexpected non-consecutive indices!"); 59 | (void)index1; 60 | return index0; 61 | } 62 | 63 | const char *OpenCLArgList::MakeArgStringRef(llvm::StringRef str) const { 64 | return getArgString(MakeIndex(str)); 65 | } 66 | 67 | std::string OpenCLArgList::getFilteredArgs(int id) const { 68 | std::stringstream ss; 69 | for (const auto &I : filtered(id)) { 70 | ss << I->getAsString(*this) << ' '; 71 | } 72 | return ss.str(); 73 | } 74 | 75 | OpenCLArgList *OpenCLOptTable::ParseArgs(const char *szOptions, 76 | unsigned &missingArgIndex, 77 | unsigned &missingArgCount) const { 78 | std::unique_ptr pArgs(new OpenCLArgList(szOptions)); 79 | 80 | // FIXME: Handle '@' args (or at least error on them). 81 | 82 | missingArgIndex = missingArgCount = 0; 83 | unsigned index = 0, argsCount = pArgs->getNumInputArgStrings(); 84 | while (index < argsCount) { 85 | // Ignore empty arguments (other things may still take them as arguments). 86 | if (pArgs->getArgString(index)[0] == '\0') { 87 | ++index; 88 | continue; 89 | } 90 | 91 | unsigned prev = index; 92 | std::unique_ptr pArg = ParseOneArg(*pArgs, index); 93 | assert(index > prev && "Parser failed to consume argument."); 94 | 95 | // Check for missing argument error. 96 | if (!pArg) { 97 | assert(index >= argsCount && "Unexpected parser error."); 98 | assert(index - prev - 1 && "No missing arguments!"); 99 | missingArgIndex = prev; 100 | missingArgCount = index - prev - 1; 101 | break; 102 | } 103 | 104 | pArgs->append(pArg.get()); 105 | m_synthesizedArgs.emplace_back(std::move(pArg)); 106 | } 107 | return pArgs.release(); 108 | } 109 | -------------------------------------------------------------------------------- /options.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | 3 | Copyright (c) Intel Corporation (2009-2017). 4 | 5 | INTEL MAKES NO WARRANTY OF ANY KIND REGARDING THE CODE. THIS CODE IS 6 | LICENSED ON AN "AS IS" BASIS AND INTEL WILL NOT PROVIDE ANY SUPPORT, 7 | ASSISTANCE, INSTALLATION, TRAINING OR OTHER SERVICES. INTEL DOES NOT 8 | PROVIDE ANY UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY 9 | DISCLAIMS ANY WARRANTY OF MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR ANY 10 | PARTICULAR PURPOSE, OR ANY OTHER WARRANTY. Intel disclaims all liability, 11 | including liability for infringement of any proprietary rights, relating to 12 | use of the code. No license, express or implied, by estoppel or otherwise, 13 | to any intellectual property rights is granted herein. 14 | 15 | \file opencl_clang.h 16 | 17 | \brief Defines the common structures for both compile and link options parsing 18 | 19 | \*****************************************************************************/ 20 | 21 | #ifndef OPENCL_CLANG_OPTIONS_H 22 | #define OPENCL_CLANG_OPTIONS_H 23 | 24 | #include "llvm/Option/Arg.h" 25 | #include "llvm/ADT/ArrayRef.h" 26 | #include "llvm/ADT/StringRef.h" 27 | #include "llvm/Option/ArgList.h" 28 | #include "llvm/Option/Option.h" 29 | #include "clang/Basic/OpenCLOptions.h" 30 | 31 | #include 32 | 33 | enum COMPILE_OPT_ID { 34 | OPT_COMPILE_INVALID = 0, // This is not an option ID. 35 | #define PREFIX(NAME, VALUE) 36 | #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \ 37 | VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR, \ 38 | VALUES) \ 39 | OPT_COMPILE_##ID, 40 | #include "opencl_clang_options.inc" 41 | OPT_COMPILE_LAST_OPTION 42 | #undef OPTION 43 | #undef PREFIX 44 | }; 45 | 46 | #define OPTTABLE_STR_TABLE_CODE 47 | #include "opencl_clang_options.inc" 48 | #undef OPTTABLE_STR_TABLE_CODE 49 | 50 | #define OPTTABLE_PREFIXES_TABLE_CODE 51 | #include "opencl_clang_options.inc" 52 | #undef OPTTABLE_PREFIXES_TABLE_CODE 53 | 54 | typedef std::list ArgsVector; 55 | 56 | // 57 | // Extend the ArgList to allow the argument parsing from single string. 58 | // 59 | // Originally llvm::opt::ArgList allowed only parsing or array of options 60 | // string. 61 | // 62 | class OpenCLArgList : public llvm::opt::ArgList { 63 | public: 64 | OpenCLArgList(const char *pszOptions); 65 | 66 | const char *getArgString(unsigned index) const override { 67 | return m_argStrings[index]; 68 | } 69 | 70 | unsigned getNumInputArgStrings() const override { 71 | return m_uiOriginalArgsCount; 72 | } 73 | 74 | std::string getFilteredArgs(int id) const; 75 | 76 | public: 77 | /// MakeIndex - Get an index for the given string(s). 78 | unsigned MakeIndex(llvm::StringRef str) const; 79 | unsigned MakeIndex(llvm::StringRef str0, llvm::StringRef str1) const; 80 | 81 | const char *MakeArgStringRef(llvm::StringRef str) const override; 82 | 83 | virtual ~OpenCLArgList() {} 84 | 85 | private: 86 | /// List of argument strings used by the contained Args. 87 | /// 88 | /// This is mutable since we treat the ArgList as being the list 89 | /// of Args, and allow routines to add new strings (to have a 90 | /// convenient place to store the memory) via MakeIndex. 91 | mutable llvm::opt::ArgStringList m_argStrings; 92 | 93 | /// Strings for synthesized arguments. 94 | /// 95 | /// This is mutable since we treat the ArgList as being the list 96 | /// of Args, and allow routines to add new strings (to have a 97 | /// convenient place to store the memory) via MakeIndex. 98 | mutable std::list m_synthesizedStrings; 99 | 100 | /// The number of original input argument strings. 101 | unsigned m_uiOriginalArgsCount; 102 | }; 103 | 104 | // 105 | // OpenCL specific OptTable 106 | // 107 | class OpenCLOptTable : public llvm::opt::GenericOptTable { 108 | public: 109 | OpenCLOptTable(llvm::ArrayRef pOptionInfos) 110 | : llvm::opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, pOptionInfos) {} 111 | 112 | OpenCLArgList *ParseArgs(const char *szOptions, unsigned &missingArgIndex, 113 | unsigned &missingArgCount) const; 114 | 115 | private: 116 | /// Synthesized arguments - owned to avoid memory leaks. 117 | mutable std::vector> m_synthesizedArgs; 118 | }; 119 | 120 | // OpenCL OptTable for compile options 121 | class OpenCLCompileOptTable : public OpenCLOptTable { 122 | public: 123 | OpenCLCompileOptTable(); 124 | }; 125 | 126 | // OpenCL OptTable for link options 127 | class OpenCLLinkOptTable : public OpenCLOptTable { 128 | public: 129 | OpenCLLinkOptTable(); 130 | }; 131 | 132 | /// 133 | // Options filter that validates the opencl used options 134 | // 135 | class EffectiveOptionsFilter { 136 | public: 137 | EffectiveOptionsFilter(const char *pszOpenCLVer) 138 | : m_opencl_ver(pszOpenCLVer) { 139 | assert(pszOpenCLVer != NULL); 140 | } 141 | 142 | std::string processOptions(const OpenCLArgList &args, 143 | const char *pszOptionsEx, 144 | ArgsVector &effectiveArgs); 145 | 146 | private: 147 | std::string m_opencl_ver; 148 | static int s_progID; 149 | }; 150 | 151 | /// 152 | // Options parser for the Compile function 153 | // 154 | class CompileOptionsParser { 155 | public: 156 | CompileOptionsParser(const char *pszOpenCLVersion) 157 | : m_commonFilter(pszOpenCLVersion), m_emitSPIRV(false), m_optDisable(false) {} 158 | 159 | // 160 | // Validates and prepares the effective options to pass to clang upon 161 | // compilation 162 | // 163 | void processOptions(const char *pszOptions, const char *pszOptionsEx); 164 | 165 | // 166 | // Just validates the user supplied OpenCL compile options 167 | // 168 | bool checkOptions(const char *pszOptions, char *pszUnknownOptions, 169 | size_t uiUnknownOptionsSize); 170 | 171 | // 172 | // Returns the calculated source name for the input source 173 | // 174 | std::string getSourceName() const { return m_sourceName; } 175 | 176 | const char *const *beginArgs() const { return m_effectiveArgsRaw.data(); } 177 | 178 | const char *const *endArgs() const { 179 | return beginArgs() + m_effectiveArgsRaw.size(); 180 | } 181 | 182 | llvm::ArrayRef args() { 183 | return m_effectiveArgsRaw; 184 | } 185 | 186 | std::string getEffectiveOptionsAsString() const; 187 | 188 | bool hasEmitSPIRV() const { return m_emitSPIRV; } 189 | bool hasOptDisable() const { return m_optDisable; } 190 | 191 | private: 192 | OpenCLCompileOptTable m_optTbl; 193 | EffectiveOptionsFilter m_commonFilter; 194 | ArgsVector m_effectiveArgs; 195 | llvm::SmallVector m_effectiveArgsRaw; 196 | std::string m_sourceName; 197 | bool m_emitSPIRV; 198 | bool m_optDisable; 199 | }; 200 | 201 | // Tokenize a string into tokens separated by any char in 'delims'. 202 | // Support quoting to allow some tokens to contain delimiters, with possible 203 | // escape characters to support quotes inside quotes. 204 | // To disable quoting or escaping, set relevant chars to '\x00'. 205 | // Unescaped quotes are dropped. 206 | 207 | template 208 | void quoted_tokenize(OutIt dest, llvm::StringRef str, llvm::StringRef delims, 209 | char quote, char escape) { 210 | llvm::StringRef::size_type ptr = str.find_first_not_of(delims); 211 | llvm::StringRef::size_type end = str.size(); 212 | 213 | if (ptr == llvm::StringRef::npos) 214 | return; 215 | 216 | // pArg state machine, with the following state vars: 217 | // 218 | // ptr - points to the current char in the string 219 | // is_escaped - is the current char escaped (i.e. was the 220 | // previous char = escape, inside a quote) 221 | // in_quote - are we in a quote now (i.e. a quote character 222 | // appeared without a matching closing quote) 223 | // tok - accumulates the current token. once an unquoted 224 | // delimiter or end of string is encountered, tok 225 | // is added to the return vector and re-initialized 226 | // 227 | bool is_escaped = false; 228 | bool in_quote = false; 229 | std::string tok; 230 | 231 | while (ptr < end) { 232 | char c = str[ptr]; 233 | if (c == escape) { 234 | tok += c; 235 | is_escaped = is_escaped ? false : true; 236 | } else if (c == quote) { 237 | if (is_escaped) { 238 | tok += c; 239 | is_escaped = false; 240 | } else { 241 | in_quote = in_quote ? false : true; 242 | } 243 | } else if (delims.find(c) != llvm::StringRef::npos) { 244 | is_escaped = false; 245 | if (in_quote) { 246 | tok += c; 247 | } else { 248 | *(dest++) = tok; 249 | tok.clear(); 250 | ptr = str.find_first_not_of(delims, ptr); 251 | if (ptr != llvm::StringRef::npos) { 252 | continue; 253 | } else { 254 | break; 255 | } 256 | } 257 | } else { 258 | is_escaped = false; 259 | tok += c; 260 | } 261 | ++ptr; 262 | } 263 | if (!tok.empty()) { 264 | *(dest++) = tok; 265 | } 266 | } 267 | 268 | #endif 269 | -------------------------------------------------------------------------------- /options_compile.cpp: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | 3 | Copyright (c) Intel Corporation (2009-2017). 4 | 5 | INTEL MAKES NO WARRANTY OF ANY KIND REGARDING THE CODE. THIS CODE IS 6 | LICENSED ON AN "AS IS" BASIS AND INTEL WILL NOT PROVIDE ANY SUPPORT, 7 | ASSISTANCE, INSTALLATION, TRAINING OR OTHER SERVICES. INTEL DOES NOT 8 | PROVIDE ANY UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY 9 | DISCLAIMS ANY WARRANTY OF MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR ANY 10 | PARTICULAR PURPOSE, OR ANY OTHER WARRANTY. Intel disclaims all liability, 11 | including liability for infringement of any proprietary rights, relating to 12 | use of the code. No license, express or implied, by estoppel or otherwise, 13 | to any intellectual property rights is granted herein. 14 | 15 | \file options_compile.cpp 16 | 17 | \*****************************************************************************/ 18 | 19 | #include "opencl_clang.h" 20 | #include "options.h" 21 | 22 | #include "clang/Driver/Options.h" 23 | #include "llvm/ADT/SmallSet.h" 24 | #include "llvm/ADT/StringExtras.h" 25 | #include "llvm/Option/Arg.h" 26 | #include "llvm/Option/ArgList.h" 27 | #include "llvm/Support/ManagedStatic.h" 28 | #include "llvm/Support/Mutex.h" 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | using namespace llvm::opt; 35 | 36 | extern llvm::ManagedStatic> compileMutex; 37 | 38 | static constexpr OptTable::Info ClangOptionsInfoTable[] = { 39 | #define PREFIX(NAME, VALUE) 40 | #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \ 41 | VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR, \ 42 | VALUES) \ 43 | {PREFIX, \ 44 | NAME, \ 45 | HELPTEXT, \ 46 | HELPTEXTSFORVARIANTS, \ 47 | METAVAR, \ 48 | OPT_COMPILE_##ID, \ 49 | llvm::opt::Option::KIND##Class, \ 50 | PARAM, \ 51 | FLAGS, \ 52 | VISIBILITY, \ 53 | OPT_COMPILE_##GROUP, \ 54 | OPT_COMPILE_##ALIAS, \ 55 | ALIASARGS, \ 56 | VALUES}, 57 | #include "opencl_clang_options.inc" 58 | }; 59 | 60 | OpenCLCompileOptTable::OpenCLCompileOptTable() 61 | : OpenCLOptTable(ClangOptionsInfoTable) {} 62 | 63 | int EffectiveOptionsFilter::s_progID = 1; 64 | 65 | /// 66 | // Options filter that validates the opencl used options 67 | // 68 | std::string EffectiveOptionsFilter::processOptions(const OpenCLArgList &args, 69 | const char *pszOptionsEx, 70 | ArgsVector &effectiveArgs) { 71 | // Reset args 72 | int iCLStdSet = 0; 73 | bool isCpp = false; 74 | bool fp64Enabled = false; 75 | std::string szTriple; 76 | std::string sourceName(llvm::Twine(s_progID++).str()); 77 | 78 | for (OpenCLArgList::const_iterator it = args.begin(), ie = args.end(); 79 | it != ie; ++it) { 80 | switch ((*it)->getOption().getID()) { 81 | case OPT_COMPILE_w: 82 | case OPT_COMPILE_D: 83 | case OPT_COMPILE_I: 84 | case OPT_COMPILE_Werror: 85 | case OPT_COMPILE_cl_single_precision_constant: 86 | case OPT_COMPILE_cl_fp32_correctly_rounded_divide_sqrt: 87 | case OPT_COMPILE_cl_opt_disable: 88 | case OPT_COMPILE_cl_mad_enable: 89 | case OPT_COMPILE_cl_no_signed_zeros: 90 | case OPT_COMPILE_cl_uniform_work_group_size: 91 | case OPT_COMPILE_cl_unsafe_math_optimizations: 92 | effectiveArgs.push_back((*it)->getAsString(args)); 93 | break; 94 | case OPT_COMPILE_cl_denorms_are_zero: 95 | effectiveArgs.push_back("-fdenormal-fp-math=preserve-sign"); 96 | break; 97 | case OPT_COMPILE_s: { 98 | std::string newSourceName = (*it)->getValue(); 99 | if (!newSourceName.empty()) { 100 | sourceName = newSourceName; 101 | // Normalize path to contain forward slashes 102 | replace(sourceName.begin(), sourceName.end(), '\\', '/'); 103 | 104 | #ifdef _WIN32 105 | // On Windows only, normalize the file name to lower case, since 106 | // LLVM saves buffer names in a case-sensitive manner, while 107 | // other Windows tools don't. 108 | // 109 | std::transform(sourceName.begin(), sourceName.end(), sourceName.begin(), 110 | ::tolower); 111 | #endif 112 | } 113 | effectiveArgs.push_back("-main-file-name"); 114 | effectiveArgs.push_back(sourceName.substr(sourceName.rfind('/') + 1)); 115 | break; 116 | } 117 | case OPT_COMPILE_cl_finite_math_only: 118 | effectiveArgs.push_back((*it)->getAsString(args)); 119 | effectiveArgs.push_back("-D"); 120 | effectiveArgs.push_back("__FINITE_MATH_ONLY__=1"); 121 | break; 122 | case OPT_COMPILE_cl_fast_relaxed_math: 123 | effectiveArgs.push_back((*it)->getAsString(args)); 124 | effectiveArgs.push_back("-D"); 125 | effectiveArgs.push_back("__FAST_RELAXED_MATH__=1"); 126 | break; 127 | case OPT_COMPILE_cl_std_CL1_1: 128 | iCLStdSet = 110; 129 | effectiveArgs.push_back((*it)->getAsString(args)); 130 | break; 131 | case OPT_COMPILE_cl_std_CL1_2: 132 | iCLStdSet = 120; 133 | effectiveArgs.push_back((*it)->getAsString(args)); 134 | break; 135 | case OPT_COMPILE_cl_std_CL2_0: 136 | iCLStdSet = 200; 137 | effectiveArgs.push_back((*it)->getAsString(args)); 138 | break; 139 | case OPT_COMPILE_cl_std_CL3_0: 140 | iCLStdSet = 300; 141 | effectiveArgs.push_back((*it)->getAsString(args)); 142 | break; 143 | case OPT_COMPILE_cl_std_CLCxx: 144 | case OPT_COMPILE_cl_std_CLCxx1_0: 145 | iCLStdSet = 200; 146 | isCpp = true; 147 | effectiveArgs.push_back((*it)->getAsString(args)); 148 | break; 149 | case OPT_COMPILE_cl_std_CLCxx2021: 150 | iCLStdSet = 300; 151 | isCpp = true; 152 | effectiveArgs.push_back((*it)->getAsString(args)); 153 | break; 154 | case OPT_COMPILE_triple: 155 | szTriple = (*it)->getValue(); 156 | break; 157 | case OPT_COMPILE_cl_no_subgroup_ifp: 158 | case OPT_COMPILE_target_triple: 159 | case OPT_COMPILE_spir_std_1_0: 160 | case OPT_COMPILE_spir_std_1_2: // ignore for now 161 | case OPT_COMPILE_cl_kernel_arg_info: // For SPIR, we always create kernel 162 | // arg info, so ignoring it here 163 | break; 164 | case OPT_COMPILE_x: 165 | // ensure that the value is spir 166 | assert((*it)->getValue() == std::string("spir")); 167 | // TODO: move the validation of the value to the check section of the 168 | // option processing to be reported as an unknown option 169 | break; 170 | // Just ignore the unknown options ( they will be listed in the unknown 171 | // list inside the ArgsList anyway) 172 | // The below assert is usable for manual debugging only 173 | // default: 174 | // assert(false && "some unknown argument"); 175 | case OPT_COMPILE_coverage: 176 | case OPT_COMPILE_profiling: 177 | case OPT_COMPILE_gline_tables_only_Flag: 178 | effectiveArgs.push_back("-debug-info-kind=line-tables-only"); 179 | effectiveArgs.push_back("-dwarf-version=4"); 180 | break; 181 | case OPT_COMPILE_g_Flag: 182 | effectiveArgs.push_back("-debug-info-kind=limited"); 183 | effectiveArgs.push_back("-dwarf-version=4"); 184 | #ifdef _WIN32 185 | // Do not use column information on Windows. 186 | effectiveArgs.push_back("-gno-column-info"); 187 | #endif 188 | break; 189 | } 190 | } 191 | 192 | if (!iCLStdSet) { 193 | effectiveArgs.push_back("-cl-std=CL1.2"); 194 | iCLStdSet = 120; 195 | } 196 | 197 | effectiveArgs.push_back("-D"); 198 | effectiveArgs.push_back("__OPENCL_VERSION__=" + m_opencl_ver); 199 | effectiveArgs.push_back("-x"); 200 | effectiveArgs.push_back("cl"); 201 | 202 | effectiveArgs.push_back("-cl-kernel-arg-info"); 203 | effectiveArgs.push_back("-fno-validate-pch"); 204 | effectiveArgs.push_back("-fno-caret-diagnostics"); 205 | 206 | if (std::find_if(effectiveArgs.begin(), effectiveArgs.end(), 207 | [](const ArgsVector::value_type& a) { 208 | return a == "-S" || a.find("-emit") == 0; 209 | }) == effectiveArgs.end()) { 210 | effectiveArgs.push_back("-emit-llvm-bc"); 211 | } 212 | 213 | effectiveArgs.push_back("-triple"); 214 | if (szTriple.empty()) { 215 | #if defined(_M_X64) || defined(__LP64__) 216 | szTriple = "spir64-unknown-unknown"; 217 | #else 218 | szTriple = "spir-unknown-unknown"; 219 | #endif 220 | } 221 | 222 | effectiveArgs.push_back(szTriple); 223 | 224 | effectiveArgs.push_back("-include"); 225 | effectiveArgs.push_back("opencl-c.h"); 226 | 227 | // Don't optimize in the frontend 228 | // clang defaults to -O0, and in that mode, does not produce IR that is 229 | // intended to be optimized (e.g. produces 'optnone' attribute), so we are 230 | // using '-disable-llvm-passes' to get out the unoptimized IR. 231 | effectiveArgs.push_back("-disable-llvm-passes"); 232 | 233 | // Specifying the option makes clang emit function body for functions 234 | // marked with inline keyword. 235 | if (!isCpp) { 236 | effectiveArgs.push_back("-fgnu89-inline"); 237 | } 238 | 239 | // Do not support all extensions by default. Support for a particular 240 | // extension should be enabled by passing a '-cl-ext' option in pszOptionsEx. 241 | effectiveArgs.push_back("-cl-ext=-all"); 242 | 243 | // OpenCL v2.0 s6.9.u - Implicit function declaration is not supported. 244 | // Behavior of clang is changed and now there is only warning about 245 | // implicit function declarations. To be more user friendly and avoid 246 | // unexpected indirect function calls in BE, let's force this warning to 247 | // error. 248 | effectiveArgs.push_back("-Werror=implicit-function-declaration"); 249 | 250 | // add the extended options verbatim 251 | std::back_insert_iterator it(std::back_inserter(effectiveArgs)); 252 | quoted_tokenize(it, pszOptionsEx, " \t", '"', '\x00'); 253 | 254 | for (auto it = effectiveArgs.begin(), end = effectiveArgs.end(); it != end; 255 | ++it) { 256 | if (it->compare("-Dcl_khr_fp64") == 0 || it->compare("-D cl_khr_fp64=1") == 0) 257 | fp64Enabled = true; 258 | else if (it->compare("-U cl_khr_fp64") == 0) 259 | fp64Enabled = false; 260 | // Find last position that enables or disables cl_khr_fp64 261 | else if (it->find("cl_khr_fp64") != std::string::npos) { 262 | auto NegFp64 = it->rfind("-cl_khr_fp64"); 263 | auto PosFp64 = it->rfind("+cl_khr_fp64"); 264 | if(NegFp64 != std::string::npos && PosFp64 != std::string::npos) 265 | fp64Enabled = PosFp64 > NegFp64; 266 | else if(NegFp64 != std::string::npos) 267 | fp64Enabled = false; 268 | else 269 | fp64Enabled = true; 270 | } 271 | } 272 | 273 | #ifdef PCH_EXTENSION 274 | std::map extMap; 275 | llvm::SmallVector extVec; 276 | llvm::SplitString(PCH_EXTENSION, extVec, ","); 277 | for (auto &ext : extVec) 278 | extMap.insert({ext.str(), true}); 279 | #else 280 | std::map extMap{ 281 | {"cl_khr_3d_image_writes", true}, 282 | {"cl_khr_depth_images", true}, 283 | {"cl_khr_fp16", true}, 284 | #ifdef _WIN32 285 | // cl_khr_gl_msaa_sharing is only supported on Windows [NEO]. 286 | {"cl_khr_gl_msaa_sharing", true}, 287 | #endif 288 | {"cl_khr_global_int32_base_atomics", true}, 289 | {"cl_khr_global_int32_extended_atomics", true}, 290 | {"cl_khr_int64_base_atomics", true}, 291 | {"cl_khr_int64_extended_atomics", true}, 292 | {"cl_khr_local_int32_base_atomics", true}, 293 | {"cl_khr_local_int32_extended_atomics", true}, 294 | {"cl_khr_mipmap_image", true}, 295 | {"cl_khr_mipmap_image_writes", true}, 296 | {"cl_khr_subgroups", true}, 297 | {"cl_intel_device_side_avc_motion_estimation", true}, 298 | {"cl_intel_planar_yuv", true}, 299 | {"cl_intel_subgroups", true}, 300 | {"cl_intel_subgroups_short", true}}; 301 | #endif 302 | 303 | auto parseClExt = [&](const std::string &clExtStr) { 304 | llvm::StringRef clExtRef(clExtStr); 305 | bool hasPrefix = clExtRef.consume_front("-cl-ext="); 306 | assert(hasPrefix && "clExtRef doesn't start with \"-cl-ext\" prefix"); 307 | (void)hasPrefix; 308 | llvm::SmallVector parsedExt; 309 | clExtRef.split(parsedExt, ','); 310 | for (auto &ext : parsedExt) { 311 | char sign = ext.front(); 312 | bool enabled = sign != '-'; 313 | llvm::StringRef extName = ext; 314 | if (sign == '+' || sign == '-') 315 | extName = extName.drop_front(); 316 | if (extName == "all") { 317 | for (auto &p : extMap) 318 | p.second = enabled; 319 | continue; 320 | } 321 | auto it = extMap.find(extName.str()); 322 | if (it != extMap.end()) 323 | it->second = enabled; 324 | } 325 | }; 326 | llvm::SmallSet parsedOclCFeatures; 327 | std::for_each(effectiveArgs.begin(), effectiveArgs.end(), 328 | [&](const ArgsVector::value_type &a) { 329 | if (a.find("-cl-ext=") == 0) 330 | parseClExt(a); 331 | else if (a.find("-D__opencl_c_") == 0) 332 | parsedOclCFeatures.insert(a); 333 | }); 334 | 335 | // "opencl-c-base.h" unconditionally enables a list of so-called "optional 336 | // core" language features. We need to undef those that aren't explicitly 337 | // defined within the compilation command (which would suggest that the 338 | // target platform supports the corresponding feature). 339 | const char* optionalCoreOclCFeaturesList[] = { 340 | "__opencl_c_work_group_collective_functions", 341 | "__opencl_c_atomic_order_seq_cst", 342 | "__opencl_c_atomic_scope_device", 343 | "__opencl_c_atomic_scope_all_devices", 344 | "__opencl_c_read_write_images" }; 345 | for (std::string OclCFeature : optionalCoreOclCFeaturesList) { 346 | if (!parsedOclCFeatures.contains(std::string("-D") + OclCFeature)) 347 | effectiveArgs.push_back(std::string("-D__undef_") + OclCFeature); 348 | } 349 | 350 | // extension is enabled in PCH but disabled or not specifed in options => 351 | // disable pch 352 | bool useModules = 353 | !std::any_of(extMap.begin(), extMap.end(), 354 | [](const auto &p) { return p.second == false; }); 355 | 356 | if (useModules) { 357 | effectiveArgs.push_back("-fmodules"); 358 | if (!fp64Enabled) { 359 | if (szTriple.find("spir64") != szTriple.npos) { 360 | if (iCLStdSet <= 120) 361 | effectiveArgs.push_back("-fmodule-file=opencl-c-12-spir64.pcm"); 362 | else if (iCLStdSet == 200) 363 | effectiveArgs.push_back("-fmodule-file=opencl-c-20-spir64.pcm"); 364 | else if (iCLStdSet == 300) 365 | effectiveArgs.push_back("-fmodule-file=opencl-c-30-spir64.pcm"); 366 | } else if (szTriple.find("spir") != szTriple.npos) { 367 | if (iCLStdSet <= 120) 368 | effectiveArgs.push_back("-fmodule-file=opencl-c-12-spir.pcm"); 369 | else if (iCLStdSet == 200) 370 | effectiveArgs.push_back("-fmodule-file=opencl-c-20-spir.pcm"); 371 | else if (iCLStdSet == 300) 372 | effectiveArgs.push_back("-fmodule-file=opencl-c-30-spir.pcm"); 373 | } 374 | } else { 375 | if (szTriple.find("spir64") != szTriple.npos) { 376 | if (iCLStdSet <= 120) 377 | effectiveArgs.push_back("-fmodule-file=opencl-c-12-spir64-fp64.pcm"); 378 | else if (iCLStdSet == 200) 379 | effectiveArgs.push_back("-fmodule-file=opencl-c-20-spir64-fp64.pcm"); 380 | else if (iCLStdSet == 300) 381 | effectiveArgs.push_back("-fmodule-file=opencl-c-30-spir64-fp64.pcm"); 382 | } else if (szTriple.find("spir") != szTriple.npos) { 383 | if (iCLStdSet <= 120) 384 | effectiveArgs.push_back("-fmodule-file=opencl-c-12-spir-fp64.pcm"); 385 | else if (iCLStdSet == 200) 386 | effectiveArgs.push_back("-fmodule-file=opencl-c-20-spir-fp64.pcm"); 387 | else if (iCLStdSet == 300) 388 | effectiveArgs.push_back("-fmodule-file=opencl-c-30-spir-fp64.pcm"); 389 | } 390 | } 391 | } 392 | 393 | // add source name to options as an input file 394 | assert(!sourceName.empty() && "Empty source name."); 395 | effectiveArgs.push_back(sourceName); 396 | 397 | return sourceName; 398 | } 399 | 400 | void CompileOptionsParser::processOptions(const char *pszOptions, 401 | const char *pszOptionsEx) { 402 | // parse options 403 | unsigned missingArgIndex, missingArgCount; 404 | std::unique_ptr pArgs( 405 | m_optTbl.ParseArgs(pszOptions, missingArgIndex, missingArgCount)); 406 | 407 | // post process logic 408 | m_sourceName = 409 | m_commonFilter.processOptions(*pArgs, pszOptionsEx, m_effectiveArgs); 410 | 411 | // build the raw options array 412 | for (ArgsVector::iterator it = m_effectiveArgs.begin(), 413 | end = m_effectiveArgs.end(); 414 | it != end; ++it) { 415 | if (it->compare("-cl-opt-disable") == 0) { 416 | m_optDisable = true; 417 | } 418 | else if (it->compare("-emit-spirv") == 0) { 419 | m_effectiveArgsRaw.push_back("-emit-llvm-bc"); 420 | m_emitSPIRV = true; 421 | continue; 422 | } 423 | m_effectiveArgsRaw.push_back(it->c_str()); 424 | } 425 | } 426 | 427 | bool CompileOptionsParser::checkOptions(const char *pszOptions, 428 | char *pszUnknownOptions, 429 | size_t uiUnknownOptionsSize) { 430 | // Parse the arguments. 431 | unsigned missingArgIndex, missingArgCount; 432 | std::unique_ptr pArgs( 433 | m_optTbl.ParseArgs(pszOptions, missingArgIndex, missingArgCount)); 434 | 435 | // Check for missing argument error. 436 | if (missingArgCount) { 437 | std::fill_n(pszUnknownOptions, uiUnknownOptionsSize, '\0'); 438 | std::string missingArg(pArgs->getArgString(missingArgIndex)); 439 | missingArg.copy(pszUnknownOptions, uiUnknownOptionsSize - 1); 440 | return false; 441 | } 442 | 443 | std::string unknownOptions = pArgs->getFilteredArgs(OPT_COMPILE_UNKNOWN); 444 | if (!unknownOptions.empty()) { 445 | std::fill_n(pszUnknownOptions, uiUnknownOptionsSize, '\0'); 446 | unknownOptions.copy(pszUnknownOptions, uiUnknownOptionsSize - 1); 447 | return false; 448 | } 449 | 450 | // we do not support input options 451 | std::string inputOptions = pArgs->getFilteredArgs(OPT_COMPILE_INPUT); 452 | if (!inputOptions.empty()) { 453 | std::fill_n(pszUnknownOptions, uiUnknownOptionsSize, '\0'); 454 | inputOptions.copy(pszUnknownOptions, uiUnknownOptionsSize - 1); 455 | return false; 456 | } 457 | 458 | return true; 459 | } 460 | 461 | std::string CompileOptionsParser::getEffectiveOptionsAsString() const { 462 | std::stringstream ss; 463 | 464 | const char *const *it = beginArgs(); 465 | const char *const *ie = endArgs(); 466 | 467 | for (; it != ie; ++it) { 468 | ss << *it << " "; 469 | } 470 | return ss.str(); 471 | } 472 | 473 | extern "C" CC_DLL_EXPORT bool CheckCompileOptions(const char *pszOptions, 474 | char *pszUnknownOptions, 475 | size_t uiUnknownOptionsSize) { 476 | // LLVM doesn't guarantee thread safety, 477 | // therefore we serialize execution of LLVM code. 478 | llvm::sys::SmartScopedLock compileOptionsGuard{*compileMutex}; 479 | 480 | try { 481 | CompileOptionsParser optionsParser("200"); 482 | return optionsParser.checkOptions(pszOptions, pszUnknownOptions, 483 | uiUnknownOptionsSize); 484 | } catch (std::bad_alloc &) { 485 | if (pszUnknownOptions && uiUnknownOptionsSize > 0) { 486 | std::fill_n(pszUnknownOptions, uiUnknownOptionsSize, '\0'); 487 | } 488 | return false; 489 | } 490 | } 491 | -------------------------------------------------------------------------------- /pch_mgr.cpp: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | 3 | Copyright (c) Intel Corporation (2009-2017). 4 | 5 | INTEL MAKES NO WARRANTY OF ANY KIND REGARDING THE CODE. THIS CODE IS 6 | LICENSED ON AN "AS IS" BASIS AND INTEL WILL NOT PROVIDE ANY SUPPORT, 7 | ASSISTANCE, INSTALLATION, TRAINING OR OTHER SERVICES. INTEL DOES NOT 8 | PROVIDE ANY UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY 9 | DISCLAIMS ANY WARRANTY OF MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR ANY 10 | PARTICULAR PURPOSE, OR ANY OTHER WARRANTY. Intel disclaims all liability, 11 | including liability for infringement of any proprietary rights, relating to 12 | use of the code. No license, express or implied, by estoppel or otherwise, 13 | to any intellectual property rights is granted herein. 14 | 15 | \file pch_mgr.cpp 16 | 17 | \*****************************************************************************/ 18 | 19 | #include "pch_mgr.h" 20 | 21 | #include "llvm/ADT/Twine.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #ifdef _WIN32 28 | #include 29 | #else 30 | #include 31 | #include 32 | 33 | struct auto_dlclose { 34 | auto_dlclose(void *module) : m_pModule(module) {} 35 | 36 | ~auto_dlclose() { 37 | if (m_pModule) 38 | dlclose(m_pModule); 39 | } 40 | 41 | void *get() { return m_pModule; } 42 | 43 | bool operator!() { return !m_pModule; } 44 | 45 | operator bool() { return m_pModule != NULL; } 46 | 47 | void *release() { 48 | void *pTemp = m_pModule; 49 | m_pModule = NULL; 50 | return pTemp; 51 | } 52 | 53 | private: 54 | auto_dlclose(const auto_dlclose &); 55 | 56 | void *m_pModule; 57 | }; 58 | #endif 59 | 60 | ResourceManager ResourceManager::g_instance; 61 | 62 | void dummy() {} 63 | 64 | // returns the pointer to the buffer loaded from the resource with the given id 65 | Resource ResourceManager::get_resource(const char *name, const char *id, 66 | const char *type, 67 | bool requireNullTerminate) { 68 | llvm::sys::ScopedLock mutexGuard(m_lock); 69 | 70 | auto res = m_buffers.find(id); 71 | if (res == m_buffers.end()) { 72 | // lazy load the resource if not found in the cache 73 | if (!load_resource(id, type, requireNullTerminate)) { 74 | return Resource(); 75 | } 76 | } 77 | 78 | res = m_buffers.find(id); 79 | assert(res != m_buffers.end()); 80 | 81 | const char *data = res->second.first; 82 | size_t size = res->second.second; 83 | return Resource(data, size, name); 84 | } 85 | 86 | const char *ResourceManager::get_file(const char *path, bool binary, 87 | bool requireNullTerminate, 88 | size_t &out_size) { 89 | llvm::sys::ScopedLock mutexGuard(m_lock); 90 | 91 | std::string key(path); 92 | 93 | if (m_buffers.find(key) == m_buffers.end()) { 94 | // lazy load the resource if not found in the cache 95 | load_file(path, binary, requireNullTerminate); 96 | } 97 | 98 | assert(m_buffers.find(key) != m_buffers.end()); 99 | out_size = m_buffers[key].second; 100 | return m_buffers[key].first; 101 | } 102 | 103 | const char* ResourceManager::realloc_buffer(const char *id, 104 | const char* buf, size_t size, 105 | bool requireNullTerminate) { 106 | std::vector &buffer = m_allocations[id]; 107 | 108 | size_t alloc_size = requireNullTerminate ? size + 1 : size; 109 | buffer.resize(alloc_size); 110 | buffer.assign(buf, buf + size); 111 | // The data in the buffer will be eventually passed to llvm::MemoryBufferMem 112 | // ctor via argument of StringRef type. The Length of this StringRef will be 113 | // = the 'size' argument of this function. There is an assert in 114 | // llvm::MemoryBuffer::init checking that element *past the end* of the memory 115 | // range passed via the ctor is '\0'. So we add it here. 116 | buffer.push_back('\0'); 117 | 118 | return &buffer[0]; 119 | } 120 | 121 | #ifdef _WIN32 122 | bool ResourceManager::GetResourceWin32(const char *id, const char *pszType, 123 | const char *&res, size_t &size) { 124 | HMODULE hMod = NULL; 125 | // Get the handle to the current module 126 | if (!GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | 127 | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, 128 | (LPCSTR)dummy, &hMod)) 129 | return false; 130 | 131 | if (!hMod) { 132 | return false; 133 | } 134 | 135 | std::string ResName = ("\"" + llvm::Twine(id) + "\"").str(); 136 | // Locate the resource 137 | HRSRC hRes = FindResourceA(hMod, ResName.c_str(), pszType); 138 | if (!hRes) { 139 | return false; 140 | } 141 | 142 | // Load the resource 143 | HGLOBAL hBytes = LoadResource(hMod, hRes); 144 | if (!hBytes) { 145 | return false; 146 | } 147 | 148 | // Get the base address to the resource. This call doesn't really lock it 149 | res = (const char*) LockResource(hBytes); 150 | if (!res) { 151 | return false; 152 | } 153 | 154 | // Get the buffer size 155 | size = SizeofResource(hMod, hRes); 156 | if (!size) { 157 | return false; 158 | } 159 | 160 | return true; 161 | } 162 | #else // WIN32 163 | 164 | /** 165 | * GetResourceUnix loads resource from shared library `lib`. 166 | * 167 | * If `relocate` argument is `false`, returned resource is only valid if: 168 | * 1) library `lib` is loaded into memory before use of this function 169 | * 2) resource will be used only while library is still loaded 170 | * 171 | * If relocate is `true`, resource will be memcpy'ed into an internal buffer, 172 | * i.e. no resource will be valid as long as the ResourceManager is alive. 173 | */ 174 | bool ResourceManager::GetResourceUnix(const char *id, const char *pszType, 175 | const char *lib, bool relocate, 176 | const char *&res, size_t &size) { 177 | 178 | void *handle = dlopen(lib, RTLD_NOW); 179 | if (!handle) { 180 | return false; 181 | } 182 | 183 | auto_dlclose module(handle); 184 | 185 | std::string name = (pszType + llvm::Twine("_") + llvm::Twine(id)).str(); 186 | std::string size_name = (name.c_str() + llvm::Twine("_size")).str(); 187 | 188 | const void *size_ptr = dlsym(module.get(), size_name.c_str()); 189 | if (!size_ptr) { 190 | return false; 191 | } 192 | 193 | size = *(const uint32_t *)size_ptr; 194 | res = (const char *)dlsym(module.get(), name.c_str()); 195 | 196 | if (!res) { 197 | return false; 198 | } 199 | 200 | return true; 201 | } 202 | #endif // WIN32 203 | 204 | bool ResourceManager::load_resource(const char *id, const char *pszType, 205 | bool requireNullTerminate) { 206 | // this function is called under lock 207 | assert(m_buffers.find(id) == m_buffers.end()); 208 | 209 | const char *res = nullptr; 210 | size_t size = 0; 211 | #ifdef WIN32 212 | bool ok = GetResourceWin32(id, pszType, res, size); 213 | #else 214 | bool ok = GetResourceUnix(id, pszType, LIBOPENCL_CLANG_NAME, 215 | false, res, size); 216 | #endif 217 | 218 | if (!ok) { 219 | return false; 220 | } 221 | 222 | if (requireNullTerminate && res[size] != '\0') { 223 | // reallocate the buffer to ensure the null termination 224 | res = realloc_buffer(id, res, size, requireNullTerminate); 225 | } 226 | 227 | m_buffers[id] = std::pair(res, size); 228 | return true; 229 | } 230 | 231 | // cache the content of the file to the internal buffers 232 | void ResourceManager::load_file(const char *path, bool binary, 233 | bool requireNullTerminate) { 234 | std::string key(path); 235 | std::ifstream fs(path, binary ? std::ios::binary : std::ios::in); 236 | std::vector &buffer = m_allocations[key]; 237 | 238 | buffer.assign(std::istreambuf_iterator(fs), 239 | std::istreambuf_iterator()); 240 | 241 | if (requireNullTerminate && buffer.size() > 0 && buffer.back() != '\0') { 242 | buffer.push_back('\0'); 243 | } 244 | m_buffers[key] = 245 | std::pair(buffer.data(), buffer.size()); 246 | } 247 | -------------------------------------------------------------------------------- /pch_mgr.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | 3 | Copyright (c) Intel Corporation (2009-2017). 4 | 5 | INTEL MAKES NO WARRANTY OF ANY KIND REGARDING THE CODE. THIS CODE IS 6 | LICENSED ON AN "AS IS" BASIS AND INTEL WILL NOT PROVIDE ANY SUPPORT, 7 | ASSISTANCE, INSTALLATION, TRAINING OR OTHER SERVICES. INTEL DOES NOT 8 | PROVIDE ANY UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY 9 | DISCLAIMS ANY WARRANTY OF MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR ANY 10 | PARTICULAR PURPOSE, OR ANY OTHER WARRANTY. Intel disclaims all liability, 11 | including liability for infringement of any proprietary rights, relating to 12 | use of the code. No license, express or implied, by estoppel or otherwise, 13 | to any intellectual property rights is granted herein. 14 | 15 | \file pch_mgr.h 16 | 17 | \*****************************************************************************/ 18 | 19 | #include "llvm/Support/Mutex.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | struct Resource 28 | { 29 | const char* m_data; 30 | size_t m_size; 31 | std::string m_name; 32 | 33 | Resource() { 34 | m_data = nullptr; 35 | m_size = 0; 36 | m_name = ""; 37 | } 38 | 39 | Resource(const char* data, size_t size, const std::string& name): 40 | m_data(data), m_size(size), m_name(name) {} 41 | 42 | bool operator!() { 43 | return m_data == nullptr; 44 | } 45 | }; 46 | 47 | 48 | // Singleton class for resource management 49 | // Its main purpose is to cache the buffers loaded from the resources 50 | // but it could be easely extended to support file based buffers as well 51 | class ResourceManager { 52 | public: 53 | static ResourceManager &instance() { return g_instance; } 54 | 55 | Resource get_resource(const char *name, const char *id, 56 | const char *type, bool requireNullTerminate); 57 | 58 | const char *get_file(const char *path, bool binary, bool requireNullTerminate, 59 | size_t &out_size); 60 | 61 | private: 62 | ResourceManager() {} 63 | 64 | bool load_resource(const char *id, const char *pszType, 65 | bool requireNullTerminate); 66 | 67 | void load_file(const char *path, bool binary, bool requireNullTerminate); 68 | 69 | const char* realloc_buffer(const char *id, const char* buf, size_t size, 70 | bool requireNullTerminate); 71 | 72 | #ifdef _WIN32 73 | bool GetResourceWin32(const char *id, const char *pszType, 74 | const char *&res, size_t &size); 75 | 76 | #else 77 | bool GetResourceUnix(const char *id, const char *pszType, 78 | const char *lib, bool relocate, 79 | const char *&res, size_t &size); 80 | 81 | #endif 82 | 83 | private: 84 | static ResourceManager g_instance; 85 | llvm::sys::Mutex m_lock; 86 | // map that caches the pointers to the loaded buffers and their sizes 87 | // those buffers could be either the pointer to the loaded 88 | // resource or to the cached buffers (stored in the m_allocations var below) 89 | std::map> m_buffers; 90 | std::map> m_allocations; 91 | }; 92 | --------------------------------------------------------------------------------