diff --git a/.github/ISSUE_TEMPLATE/release.md b/.github/ISSUE_TEMPLATE/release.md index 7dca900f2d..cff54cdea4 100644 --- a/.github/ISSUE_TEMPLATE/release.md +++ b/.github/ISSUE_TEMPLATE/release.md @@ -7,6 +7,13 @@ assignees: '' --- + + + # Schedule - [ ] MM/DD/YYYY - Release branch forks from `main` @@ -20,6 +27,7 @@ assignees: '' # Tasks + ## Before Fork This part of the release process is to 'prime the pump' - that is to make sure @@ -35,6 +43,8 @@ we are confident we can generate builds for the new branch - [ ] Zip files for github release - [ ] NuGet package - [ ] VPack +- [ ] Update SPIRV-Headers and SPIRV-Tools submodules, in the release branch, + to target the commits specified by LunarG. - [ ] Final merge of `main` into the release branch ## After Fork @@ -45,12 +55,14 @@ we are confident we can generate builds for the new branch ## Quality Sign Off - [ ] Microsoft Testing Sign-off (@damyanp) -- [ ] Google Testing Sign-off (@s-perron / @Keenuts) +- [ ] NVIDIA Testing Sign-off (@dnovillo / @pow2clk) ## Release - [ ] Tag final release and post binaries - [ ] Add the new compiler to Compiler Explorer +- [ ] Email LunarG the release tag and update the release spreadsheet. +- [ ] Publish the new compiler NuGet package. [^1]: [Ask Mode](https://devblogs.microsoft.com/oldnewthing/20140722-00/?p=433) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 5a1d17f132..ff7a758d2d 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -16,10 +16,17 @@ How to comment when release notes are missing: - If it is not obvious whether one is required, leave only a gentle prompt: **"Did you consider adding a release note?"** When to skip a release note comment: -- If the PR already updates `docs/ReleaseNotes.md`, do not ask for an additional release note. -- If the PR is docs-only, do not leave a release note comment. +- If the PR already updates `docs/ReleaseNotes.md`, review the entry's placement and content instead of asking for an additional release note. +- If the PR is docs-only and does not modify `docs/ReleaseNotes.md`, do not leave a release note comment. - If the PR is a dependency bump (for example, a "Bump ..." PR), do not leave a release note comment. +When reviewing an existing release note: +- Check it against the release note policy and entry rules in `CONTRIBUTING.md`. +- Review the PR as merged with the current base branch, not only the head branch's file contents. If the head branch is behind or diverged from the base branch, account for newer release headings already on the base branch and flag the PR for an update when the stale branch makes the entry's final placement ambiguous or incorrect. +- Put changes targeting the next release under `### Upcoming Release`. +- Use `### Upcoming Preview Release` only for changes that apply exclusively to experimental preview shader models. +- Do not add entries to an already named release unless the change explicitly targets that release. + Comment tone: - Use a stronger ask when the PR clearly appears to be a user-visible bug fix or feature. - If release-note coverage may come in a related PR (including a future PR), ask the author to point to that planned coverage. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..2c48305b7e --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + groups: + github-actions: + patterns: ["*"] + schedule: + interval: "weekly" + cooldown: + default-days: 7 diff --git a/.github/skills/cherry-pick/SKILL.md b/.github/skills/cherry-pick/SKILL.md new file mode 100644 index 0000000000..d06868b940 --- /dev/null +++ b/.github/skills/cherry-pick/SKILL.md @@ -0,0 +1,10 @@ +--- +name: cherry-pick +description: Cherry-pick a commit onto another branch and open the PR. Use when the user asks to cherry-pick or backport a commit or PR to a release branch. +--- + +# Cherry-picking commits + +Cherry-pick the commit with `git cherry-pick -x ` so the source SHA is +recorded in git's standard format. Keep the commit message as git generates it +by default. Prefix the PR title with `[Cherry-Pick]`. \ No newline at end of file diff --git a/.github/workflows/clang-format-checker.yml b/.github/workflows/clang-format-checker.yml index f026e25348..3a2aea849a 100644 --- a/.github/workflows/clang-format-checker.yml +++ b/.github/workflows/clang-format-checker.yml @@ -1,21 +1,26 @@ name: "Check code formatting" -on: - pull_request_target: - types: [opened,synchronize] - issue_comment: - types: edited + +on: + pull_request: + types: [opened, synchronize] + +permissions: + contents: read + +concurrency: + group: clang-format-${{ github.event.pull_request.number }} + cancel-in-progress: true jobs: code_formatter: - if: github.event_name == 'pull_request_target' runs-on: ubuntu-latest - permissions: - pull-requests: write + timeout-minutes: 30 steps: - name: Fetch DirectXShaderCompiler sources - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: ref: ${{ github.event.pull_request.head.sha }} + persist-credentials: false - name: Checkout through merge base uses: rmacklin/fetch-through-merge-base@bfe4d03a86f9afa52bc1a70e9814fc92a07f7b75 # v0.3.0 @@ -24,139 +29,58 @@ jobs: head_ref: ${{ github.event.pull_request.head.sha }} deepen_length: 500 - - name: Get changed files - id: changed-files - uses: step-security/changed-files@3dbe17c78367e7d60f00d78ae6781a35be47b4a1 # v45.0.1 - with: - separator: "," - skip_initial_fetch: true - - # We need to pull the script from the main branch, so that we ensure - # we get the latest version of this script. - - name: Fetch code formatting utils - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - repository: microsoft/DirectXShaderCompiler - ref: ${{ github.event.repository.default_branch }} - sparse-checkout: | - utils/git/requirements_formatting.txt - utils/git/code-format-helper.py - utils/git/code-format-save-diff.py - sparse-checkout-cone-mode: false - path: code-format-tools - - - name: "Listed files" - env: - LISTED_FILES: ${{ steps.changed-files.outputs.all_changed_files }} - run: | - echo "Formatting files:" - echo "$LISTED_FILES" - - name: Install clang-format - uses: aminya/setup-cpp@v1 + uses: aminya/setup-cpp@8170d66c458f4a045220b7b0966c10940bb2a15d # v1.8.1 with: clangformat: 17.0.1 - - name: Setup Python env - uses: actions/setup-python@v4 - with: - python-version: '3.11' - cache: 'pip' - cache-dependency-path: 'code-format-tools/utils/git/requirements_formatting.txt' - - - name: Install python dependencies - run: pip install -r code-format-tools/utils/git/requirements_formatting.txt - - - name: Run code formatter - id: formatter + - name: Check code formatting env: - GITHUB_PR_NUMBER: ${{ github.event.pull_request.number }} START_REV: ${{ github.event.pull_request.base.sha }} END_REV: ${{ github.event.pull_request.head.sha }} - CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }} + shell: bash run: | - python code-format-tools/utils/git/code-format-helper.py \ - --token ${{ secrets.GITHUB_TOKEN }} \ - --issue-number $GITHUB_PR_NUMBER \ - --start-rev $START_REV \ - --end-rev $END_REV \ - --changed-files "$CHANGED_FILES" - apply_diff: - if: ${{ github.event_name == 'issue_comment' && github.event.comment.user.login == 'github-actions[bot]' && endsWith(github.event.comment.body, '- [x] Check this box to apply formatting changes to this branch.') }} - runs-on: ubuntu-latest - env: - TMP_DIFF_FILE: /tmp/diff.patch - permissions: - pull-requests: write - contents: write - steps: - - uses: actions/github-script@v3 - id: get-pr - with: - script: | - const request = { - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: context.issue.number - } - core.info(`Getting PR #${request.pull_number} from ${request.owner}/${request.repo}`) - try { - const result = await github.pulls.get(request) - return result.data - } catch (err) { - core.setFailed(`Request failed with error ${err}`) - } - - # We need to pull the script from the main branch, so that we ensure - # we get the latest version of this script. - - name: Fetch code formatting utils - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - repository: microsoft/DirectXShaderCompiler - ref: ${{ github.event.repository.default_branch }} - sparse-checkout: | - utils/git/requirements_formatting.txt - utils/git/code-format-helper.py - utils/git/code-format-save-diff.py - sparse-checkout-cone-mode: false - path: code-format-tools + set -euo pipefail - - name: Setup Python env - uses: actions/setup-python@v4 - with: - python-version: '3.11' - cache: 'pip' - cache-dependency-path: 'code-format-tools/utils/git/requirements_formatting.txt' + patch_file="$RUNNER_TEMP/clang-format.patch" + rm -f "$patch_file" - - name: Install python dependencies - run: pip install -r code-format-tools/utils/git/requirements_formatting.txt + merge_base="$(git merge-base "$START_REV" "$END_REV")" - - name: Apply code diff - env: - GITHUB_PR_NUMBER: ${{ github.event.issue.number }} - COMMENT_ID: ${{ github.event.comment.id }} - run: | - python code-format-tools/utils/git/code-format-save-diff.py \ - --token ${{ secrets.GITHUB_TOKEN }} \ - --issue-number $GITHUB_PR_NUMBER \ - --tmp-diff-file $TMP_DIFF_FILE \ - --comment-id $COMMENT_ID + formatter_status=0 + git-clang-format \ + --verbose \ + --diff \ + "$merge_base" \ + "$END_REV" || formatter_status=$? - - name: Fetch LLVM sources for head - uses: actions/checkout@v4 - with: - fetch-depth: 2 - ref: ${{ fromJSON(steps.get-pr.outputs.result).head.ref }} - repository: ${{ fromJSON(steps.get-pr.outputs.result).head.repo.full_name }} + if [[ "$formatter_status" -gt 1 ]]; then + echo "::error::git-clang-format failed: $formatter_status" + exit "$formatter_status" + fi - - name: apply diff - run: | - git apply $TMP_DIFF_FILE - git add . + if [[ "$formatter_status" -eq 1 ]]; then + patch_status=0 + git-clang-format \ + --diff \ + "$merge_base" \ + "$END_REV" >"$patch_file" || patch_status=$? + if [[ "$patch_status" -ne 1 ]]; then + rm -f "$patch_file" + echo "::error::Could not create the clang-format patch." + exit 2 + fi + + echo "::error::C/C++ formatting changes are required." + echo "Download clang-format-patch from this run or run 'git clang-format $merge_base' locally." >&2 + exit 1 + fi - - name: Commit & Push changes - uses: actions-js/push@master + - name: Upload formatting patch + if: ${{ failure() }} + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: - branch: ${{ fromJSON(steps.get-pr.outputs.result).head.ref }} - repository: ${{ fromJSON(steps.get-pr.outputs.result).head.repo.full_name }} - github_token: ${{ secrets.GITHUB_TOKEN }} + name: clang-format-patch + path: ${{ runner.temp }}/clang-format.patch + if-no-files-found: ignore + retention-days: 7 diff --git a/.github/workflows/coverage-gh-pages.yml b/.github/workflows/coverage-gh-pages.yml index 07e63584e3..aa14ef2a93 100644 --- a/.github/workflows/coverage-gh-pages.yml +++ b/.github/workflows/coverage-gh-pages.yml @@ -26,11 +26,11 @@ jobs: timeout-minutes: 240 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 with: submodules: true - name: Setup Pages - uses: actions/configure-pages@v5 + uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0 - name: Install dependencies run: sudo apt install -y ninja-build - name: Configure @@ -44,7 +44,7 @@ jobs: - name: Force artifact permissions run: chmod -c -R +rX ${{github.workspace}}/build/report - name: Upload artifact - uses: actions/upload-pages-artifact@v3 + uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1 with: path: ${{github.workspace}}/build/report @@ -60,4 +60,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 + uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5 diff --git a/.github/workflows/pr-description-checker.yml b/.github/workflows/pr-description-checker.yml index e7cfb917fe..e35c3941ab 100644 --- a/.github/workflows/pr-description-checker.yml +++ b/.github/workflows/pr-description-checker.yml @@ -11,8 +11,8 @@ jobs: check-pr-description: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: jadrol/pr-description-checker-action@v1.0.0 + - uses: actions/checkout@0717577d45739eb3c851188b29f50ed6c0b2194e # v2.8.0 + - uses: jadrol/pr-description-checker-action@c659fed338a52d657d34462c8bc7fc1f65d25758 # v1.0.0 id: description-checker with: repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 0b0f59ed28..09b20311f4 100644 --- a/.gitignore +++ b/.gitignore @@ -53,6 +53,7 @@ autoconf/autom4te.cache #==============================================================================# # Build directories /build*/ +/out # External projects that are tracked independently. external/* # Clang, which is tracked independently. diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..36d0d7841d --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,49 @@ +# DXC agent guidance + +## Investigating compile-time regressions and miscompiles + +- Start from evidence. Identify the exact pass, hot function, and triggering + operation before proposing a fix. Enumerate every limit, cutoff, cache, and + heuristic on that path. +- Check this fork before assuming an LLVM design flaw. DXC is based on LLVM + 3.7, and local divergences are commonly, but not always, marked + `HLSL Change`. Reconstruct the local pre-change behavior before reaching + outside the repository. +- Inspect local history before designing a new mechanism. Run `git blame` on + the hot line and use `git log -p -- ` and + `git log -S -- ` to find when and why it changed. Treat a + surprising tuning constant as a regression candidate first. Use + `git show ^:` to inspect the pre-change file. If a pristine + upstream comparison is still needed, consult the `llvmorg-3.7.1` tag in + `llvm/llvm-project`. +- Check the scope of shared analysis settings. A file-scope limit changed for + one pass can affect every consumer of that analysis. Enumerate the users and + state the affected passes in the PR. +- Prefer restoring an upstream default over adding a DXC-specific limit or + heuristic to core LLVM code. Require stronger evidence for a new mechanism + because this fork has limited regression coverage for LLVM analyses and + transforms. +- Account for the test gap. `test/Transforms/lit.local.cfg` and + `test/Analysis/lit.local.cfg` disable discovery with + `config.suffixes = []`, including the ordinary GVN and + MemoryDependenceAnalysis suites. Add focused coverage under + `tools/clang/test/DXC/Passes/`, but do not mistake a targeted test for broad + pass-regression coverage. +- Build reproducers from the original failure's structural characteristics, + not from the proposed fix. Verify that the repro has the same sensitivity to + relevant limits and options before trusting it. +- Treat surprising experimental results as new evidence. If an unrelated knob + outperforms the proposed fix, stop and re-derive the root cause instead of + continuing the existing plan. +- Use cross-fork comparisons for "how does upstream work now?" and local + history for "what did DXC change?" Do the cheaper local-history check first. + +### Example + +`MemoryDependenceAnalysis` used a file-scope `BlockScanLimit` of 500 after +commit `08f3100f2503b8d6750c1b65b31fe6ae055be84f` / #2725 raised LLVM 3.7's +default of 100 for a DSE case. The accompanying `-memdep-block-scan-limit` +option was routed to DSE, but the shared default also affected GVN's +memory-dependence queries. #9003 restores the upstream default and adds a +focused GVN test after the divergence caused a severe compile-time regression +on a large generated compute shader. diff --git a/CMakeLists.txt b/CMakeLists.txt index 5210718005..50b21e943f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,6 +98,8 @@ mark_as_advanced(DXC_DISABLE_ALLOCATOR_OVERRIDES) option(DXC_CODEGEN_EXCEPTIONS_TRAP "An exception in code generation generates a trap, ending the compiler process" OFF) mark_as_advanced(DXC_CODEGEN_EXCEPTIONS_TRAP) +option(DXC_OPTIMIZE_FOR_SIZE "Use MSVC /Os for Windows Release builds" OFF) + # adjust link option to enable debugging from kernel mode; not compatible with incremental linking if(NOT CMAKE_VERSION VERSION_LESS "3.13" AND MSVC AND NOT CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "ARM64EC") add_link_options(/DEBUGTYPE:CV,FIXUP,PDATA /INCREMENTAL:NO) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index e863652250..991367226d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -15,6 +15,7 @@ trigger: pr: - main - release* + - users/* resources: - repo: self @@ -39,19 +40,34 @@ stages: configuration: Release spirvBuildFlag: -spirvtest artifactName: dxc_spirv_release + offloadCandidate: true VS2022_Debug: configuration: Debug spirvBuildFlag: -spirvtest - artifactName: '' VS2022_Release_NoSPIRV: configuration: Release spirvBuildFlag: '' - artifactName: '' steps: - checkout: self clean: true submodules: true + - pwsh: | + $run = $true + if ("$(Build.Reason)" -eq "PullRequest") { + $run = $false + try { + $labels = Invoke-RestMethod "https://api.github.com/repos/$(Build.Repository.Name)/issues/$(System.PullRequest.PullRequestNumber)/labels" -ErrorAction Stop + if ($labels.name -contains "run-offload-tests") { $run = $true } + } catch { + Write-Warning "Unable to check pull request labels; skipping offload tests: $_" + } + } + Write-Host "Build.Reason=$(Build.Reason) runOffloadTests=$run" + Write-Host "##vso[task.setvariable variable=runOffloadTests;isOutput=true]$($run.ToString().ToLower())" + name: decide + displayName: 'Decide whether to run offload tests' + condition: and(succeeded(), eq(variables['offloadCandidate'], 'true')) - script: | call utils\hct\hctstart.cmd %HLSL_SRC_DIR% %HLSL_BLD_DIR% call utils\hct\hctbuild.cmd -vs2022 -$(platform) -$(configuration) -show-cmake-log $(spirvBuildFlag) -warp-nuget-version 1.0.16.1 @@ -102,10 +118,10 @@ stages: if (Test-Path "$bin\$f") { Copy-Item "$bin\$f" $dst } else { throw "Required file not found: $bin\$f" } } displayName: 'Stage DXC binaries' - condition: and(succeeded(), ne(variables['artifactName'], '')) + condition: and(succeeded(), eq(variables['decide.runOffloadTests'], 'true')) - task: PublishPipelineArtifact@1 displayName: 'Publish DXC binaries' - condition: and(succeeded(), ne(variables['artifactName'], '')) + condition: and(succeeded(), eq(variables['decide.runOffloadTests'], 'true')) inputs: targetPath: '$(Build.ArtifactStagingDirectory)\dxc' artifact: '$(artifactName)' @@ -211,34 +227,9 @@ stages: testResultsFiles: '**/testresults.xunit.xml' condition: succeededOrFailed() -- stage: OffloadGate - dependsOn: [] - jobs: - - job: gate - pool: - vmImage: ubuntu-latest - steps: - - checkout: none - - bash: | - run=true - if [ "$(Build.Reason)" = "PullRequest" ]; then - run=false - labels=$(curl -sf "https://api.github.com/repos/$(Build.Repository.Name)/issues/$(System.PullRequest.PullRequestNumber)/labels" | python3 -c "import sys, json; print(' '.join(l['name'] for l in json.load(sys.stdin)))") - for l in $labels; do [ "$l" = "run-offload-tests" ] && run=true; done - fi - echo "Build.Reason=$(Build.Reason) run=$run" - echo "##vso[task.setvariable variable=run;isOutput=true]$run" - name: decide - -- stage: OffloadTests - displayName: 'Offload tests' - dependsOn: - - Build - - OffloadGate - condition: and(succeededOrFailed(), eq(dependencies.OffloadGate.outputs['gate.decide.run'], 'true')) - - jobs: - job: Offload + dependsOn: Windows + condition: and(succeededOrFailed(), eq(dependencies.Windows.outputs['VS2022_Release.decide.runOffloadTests'], 'true')) timeoutInMinutes: 180 pool: vmImage: windows-2025 diff --git a/cmake/modules/ChooseMSVCCRT.cmake b/cmake/modules/ChooseMSVCCRT.cmake index 0e6e1aa552..b89ea6efa5 100644 --- a/cmake/modules/ChooseMSVCCRT.cmake +++ b/cmake/modules/ChooseMSVCCRT.cmake @@ -4,15 +4,7 @@ # # The macro is invoked at the end of the file. # -# CMake already sets CRT flags in the CMAKE_CXX_FLAGS_* and -# CMAKE_C_FLAGS_* variables by default. To let the user -# override that for each build type: -# 1. Detect which CRT is already selected, and reflect this in -# LLVM_USE_CRT_* so the user can have a better idea of what -# changes they're making. -# 2. Replace the flags in both variables with the new flag via a regex. -# 3. set() the variables back into the cache so the changes -# are user-visible. +# HLSL Change - removed outdated flag-rewriting description. ### Helper macros: ### macro(make_crt_regex regex crts) @@ -33,23 +25,7 @@ macro(get_current_crt crt_current regex flagsvar) string(STRIP "${${crt_current}}" ${crt_current}) endmacro(get_current_crt) -# Replaces or adds a flag to a variable. -# Expects 'flag' to be padded with spaces. -macro(set_flag_in_var flagsvar regex flag) - string(REGEX MATCH "${${regex}}" current_flag "${${flagsvar}}") - if("${current_flag}" STREQUAL "") - set(${flagsvar} "${${flagsvar}}${${flag}}") - else() - string(REGEX REPLACE "${${regex}}" "${${flag}}" ${flagsvar} "${${flagsvar}}") - endif() - string(STRIP "${${flagsvar}}" ${flagsvar}) - # Make sure this change gets reflected in the cache/gui. - # CMake requires the docstring parameter whenever set() touches the cache, - # so get the existing docstring and re-use that. - get_property(flagsvar_docs CACHE ${flagsvar} PROPERTY HELPSTRING) - set(${flagsvar} "${${flagsvar}}" CACHE STRING "${flagsvar_docs}" FORCE) -endmacro(set_flag_in_var) - +# HLSL Change - removed set_flag_in_var(). macro(choose_msvc_crt MSVC_CRT) if(LLVM_USE_CRT) @@ -60,7 +36,11 @@ variables (LLVM_USE_CRT_DEBUG, etc) instead.") make_crt_regex(MSVC_CRT_REGEX ${MSVC_CRT}) - foreach(build_type ${CMAKE_CONFIGURATION_TYPES} ${CMAKE_BUILD_TYPE}) + # HLSL Change Starts + set(llvm_crt_build_types ${CMAKE_CONFIGURATION_TYPES} ${CMAKE_BUILD_TYPE}) + list(REMOVE_DUPLICATES llvm_crt_build_types) + + foreach(build_type ${llvm_crt_build_types}) string(TOUPPER "${build_type}" build) if (NOT LLVM_USE_CRT_${build}) get_current_crt(LLVM_USE_CRT_${build} @@ -75,12 +55,11 @@ variables (LLVM_USE_CRT_DEBUG, etc) instead.") endif(NOT LLVM_USE_CRT_${build}) endforeach(build_type) - foreach(build_type ${CMAKE_CONFIGURATION_TYPES} ${CMAKE_BUILD_TYPE}) + set(llvm_crt_override_requested FALSE) + foreach(build_type ${llvm_crt_build_types}) string(TOUPPER "${build_type}" build) - if ("${LLVM_USE_CRT_${build}}" STREQUAL "") - set(flag_string " ") - else() - set(flag_string " /${LLVM_USE_CRT_${build}} ") + if (NOT "${LLVM_USE_CRT_${build}}" STREQUAL "") + set(llvm_crt_override_requested TRUE) list(FIND ${MSVC_CRT} ${LLVM_USE_CRT_${build}} idx) if (idx LESS 0) message(FATAL_ERROR @@ -88,10 +67,36 @@ variables (LLVM_USE_CRT_DEBUG, etc) instead.") endif (idx LESS 0) message(STATUS "Using ${build_type} VC++ CRT: ${LLVM_USE_CRT_${build}}") endif() - foreach(lang C CXX) - set_flag_in_var(CMAKE_${lang}_FLAGS_${build} MSVC_CRT_REGEX flag_string) - endforeach(lang) endforeach(build_type) + + if (llvm_crt_override_requested) + set(cmake_msvc_runtime_library "") + foreach(build_type ${llvm_crt_build_types}) + string(TOUPPER "${build_type}" build) + set(crt "${LLVM_USE_CRT_${build}}") + if ("${crt}" STREQUAL "") + if ("${build}" STREQUAL "DEBUG") + set(crt "MDd") + else() + set(crt "MD") + endif() + endif() + + if ("${crt}" STREQUAL "MD") + set(runtime_library "MultiThreadedDLL") + elseif ("${crt}" STREQUAL "MDd") + set(runtime_library "MultiThreadedDebugDLL") + elseif ("${crt}" STREQUAL "MT") + set(runtime_library "MultiThreaded") + elseif ("${crt}" STREQUAL "MTd") + set(runtime_library "MultiThreadedDebug") + endif() + string(APPEND cmake_msvc_runtime_library + "$<$:${runtime_library}>") + endforeach(build_type) + set(CMAKE_MSVC_RUNTIME_LIBRARY "${cmake_msvc_runtime_library}") + endif() + # HLSL Change Ends endmacro(choose_msvc_crt MSVC_CRT) @@ -103,4 +108,3 @@ set(MSVC_CRT MTd) choose_msvc_crt(MSVC_CRT) - diff --git a/cmake/modules/HandleLLVMOptions.cmake b/cmake/modules/HandleLLVMOptions.cmake index d5769abce7..8fdff83e3f 100644 --- a/cmake/modules/HandleLLVMOptions.cmake +++ b/cmake/modules/HandleLLVMOptions.cmake @@ -362,14 +362,19 @@ if( MSVC ) append("/analyze" CMAKE_CXX_FLAGS) endif () - # Change release to always build debug information out-of-line, but - # also enable Reference optimization, ie dead function elimination. + # Change release to always build debug information out-of-line and enable + # function-level dead code elimination. + append("/Gy" CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE) if (NOT CMAKE_MSVC_DEBUG_INFORMATION_FORMAT) append("/Zi" CMAKE_CXX_FLAGS_RELEASE) append("/DEBUG /OPT:REF" CMAKE_SHARED_LINKER_FLAGS_RELEASE) append("/DEBUG /OPT:REF" CMAKE_EXE_LINKER_FLAGS_RELEASE) endif() + if (DXC_OPTIMIZE_FOR_SIZE) + append("/Os" CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE) + endif() + # HLSL Changes End # Enable warnings @@ -609,9 +614,7 @@ endif() # HLSL Change Ends # Add flags for add_dead_strip(). -# FIXME: With MSVS, consider compiling with /Gy and linking with /OPT:REF? -# But MinSizeRel seems to add that automatically, so maybe disable these -# flags instead if LLVM_NO_DEAD_STRIP is set. +# HLSL Change - deleted outdated comment about /Gy. if(NOT CYGWIN AND NOT WIN32) if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND NOT uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG") diff --git a/docs/DXIL.rst b/docs/DXIL.rst index 15bf3af730..37e4556f70 100644 --- a/docs/DXIL.rst +++ b/docs/DXIL.rst @@ -2053,6 +2053,7 @@ ExtractElement extracts from vector InsertElement inserts into vector ShuffleVector Shuffle two vectors ExtractValue extracts from aggregate +InsertValue inserts into aggregate ============== ======================================================================= ================= @@ -2447,6 +2448,39 @@ ID Name Description 309 VectorReduceAnd Bitwise AND reduction of the vector returning a scalar 310 VectorReduceOr Bitwise OR reduction of the vector returning a scalar 311 FDot computes the n-dimensional vector dot-product +312 GetGroupWaveIndex returns the index of the wave in the thread group +313 GetGroupWaveCount returns the number of waves in the thread group +314 ClusterID returns the user-defined ClusterID of the intersected CLAS +315 RayQuery_CandidateClusterID returns candidate hit cluster ID +316 RayQuery_CommittedClusterID returns committed hit cluster ID +317 HitObject_ClusterID returns the cluster ID of this committed hit +318 TriangleObjectPosition returns triangle vertices in object space as <9 x float> +319 RayQuery_CandidateTriangleObjectPosition returns candidate triangle vertices in object space as <9 x float> +320 RayQuery_CommittedTriangleObjectPosition returns committed triangle vertices in object space as <9 x float> +321 HitObject_TriangleObjectPosition returns triangle vertices in object space as <9 x float> +322 LinAlgMatrixMultiplyAccumulate Returns the resulting matrix from multiplying A and B and accumulating into C +323 LinAlgFillMatrix fills a matrix with a scalar value +324 LinAlgCopyConvertMatrix Converts and copies the element and use type of the source matrix to the destination matrix with optional transpose +325 LinAlgMatrixLoadFromDescriptor fills a matrix with data from a [RW]ByteAddressBuffer +326 LinAlgMatrixLoadFromMemory fills a matrix with data from a groupshared array +327 LinAlgMatrixLength returns the number of elements stored in thread-local storage on the active thread for the provided matrix +328 LinAlgMatrixGetCoordinate returns a two element vector containing the column and row of the matrix that the thread-local index corresponds to +329 LinAlgMatrixGetElement returns the element of the matrix corresponding to the provided thread-local index +330 LinAlgMatrixSetElement sets the element of the matrix corresponding to the provided thread-local index +331 LinAlgMatrixStoreToDescriptor stores a matrix to a RWByteAddressBuffer +332 LinAlgMatrixStoreToMemory stores a matrix to groupshared memory +333 LinAlgMatrixQueryAccumulatorLayout returns comptime 0 when accumulator matrix are A layout, 1 when B layout +334 LinAlgMatrixMultiply Returns the resulting matrix from multiplying A and B +335 LinAlgMatrixAccumulate accumulate A or B matrix into Accumulator matrix following LHS += RHS +336 LinAlgMatVecMul Multiplies a MxK dimension matrix and a K sized input vector +337 LinAlgMatVecMulAdd Multiplies a MxK dimension matrix and a K sized input vector then adds a M sized bias vector +338 LinAlgMatrixAccumulateToDescriptor accumulates a matrix to a RWByteAddressBuffer +339 LinAlgMatrixAccumulateToMemory accumulates a matrix to groupshared memory +340 LinAlgMatrixOuterProduct Outer products an M sized vector and a N sized vector producing an MxN matrix +341 LinAlgConvert Convert vector components from one interpretation to another +342 LinAlgVectorAccumulateToDescriptor Accumulates given vector to the buffer at the given offset +343 DebugBreak triggers a breakpoint if debugging is enabled +344 IsDebuggingEnabled returns true if debugging is enabled === ===================================================== ======================================================================================================================================================================================================================= @@ -3081,45 +3115,45 @@ Given width, offset: Opcode Table ExperimentalOps, id=32768: Experimental DXIL operations -========== ======================================== =================================================================================================================== -ID Name Description -========== ======================================== =================================================================================================================== -2147483648 ExperimentalNop nop does nothing -2147483649 GetGroupWaveIndex returns the index of the wave in the thread group -2147483650 GetGroupWaveCount returns the number of waves in the thread group -2147483651 ClusterID returns the user-defined ClusterID of the intersected CLAS -2147483652 RayQuery_CandidateClusterID returns candidate hit cluster ID -2147483653 RayQuery_CommittedClusterID returns committed hit cluster ID -2147483654 HitObject_ClusterID returns the cluster ID of this committed hit -2147483655 TriangleObjectPosition returns triangle vertices in object space as <9 x float> -2147483656 RayQuery_CandidateTriangleObjectPosition returns candidate triangle vertices in object space as <9 x float> -2147483657 RayQuery_CommittedTriangleObjectPosition returns committed triangle vertices in object space as <9 x float> -2147483658 HitObject_TriangleObjectPosition returns triangle vertices in object space as <9 x float> -2147483659 LinAlgMatrixMultiplyAccumulate Returns the resulting matrix from multiplying A and B and accumulating into C -2147483660 LinAlgFillMatrix fills a matrix with a scalar value -2147483661 LinAlgCopyConvertMatrix Converts and copies the element and use type of the source matrix to the destination matrix with optional transpose -2147483662 LinAlgMatrixLoadFromDescriptor fills a matrix with data from a [RW]ByteAddressBuffer -2147483663 LinAlgMatrixLoadFromMemory fills a matrix with data from a groupshared array -2147483664 LinAlgMatrixLength returns the number of elements stored in thread-local storage on the active thread for the provided matrix -2147483665 LinAlgMatrixGetCoordinate returns a two element vector containing the column and row of the matrix that the thread-local index corresponds to -2147483666 LinAlgMatrixGetElement returns the element of the matrix corresponding to the provided thread-local index -2147483667 LinAlgMatrixSetElement sets the element of the matrix corresponding to the provided thread-local index -2147483668 LinAlgMatrixStoreToDescriptor stores a matrix to a RWByteAddressBuffer -2147483669 LinAlgMatrixStoreToMemory stores a matrix to groupshared memory -2147483670 LinAlgMatrixQueryAccumulatorLayout returns comptime 0 when accumulator matrix are A layout, 1 when B layout -2147483671 LinAlgMatrixMultiply Returns the resulting matrix from multiplying A and B -2147483672 LinAlgMatrixAccumulate accumulate A or B matrix into Accumulator matrix following LHS += RHS -2147483673 LinAlgMatVecMul Multiplies a MxK dimension matrix and a K sized input vector -2147483674 LinAlgMatVecMulAdd Multiplies a MxK dimension matrix and a K sized input vector then adds a M sized bias vector -2147483675 LinAlgMatrixAccumulateToDescriptor accumulates a matrix to a RWByteAddressBuffer -2147483676 LinAlgMatrixAccumulateToMemory accumulates a matrix to groupshared memory -2147483677 LinAlgMatrixOuterProduct Outer products an M sized vector and a N sized vector producing an MxN matrix -2147483678 LinAlgConvert Convert vector components from one interpretation to another -2147483679 LinAlgVectorAccumulateToDescriptor Accumulates given vector to the buffer at the given offset -2147483680 ReservedE0 reserved -2147483681 DebugBreak triggers a breakpoint if debugging is enabled -2147483682 IsDebuggingEnabled returns true if debugging is enabled -========== ======================================== =================================================================================================================== +========== =============== ================ +ID Name Description +========== =============== ================ +2147483648 ExperimentalNop nop does nothing +2147483649 ReservedE0 reserved +2147483650 ReservedE1 reserved +2147483651 ReservedE2 reserved +2147483652 ReservedE3 reserved +2147483653 ReservedE4 reserved +2147483654 ReservedE5 reserved +2147483655 ReservedE6 reserved +2147483656 ReservedE7 reserved +2147483657 ReservedE8 reserved +2147483658 ReservedE9 reserved +2147483659 ReservedE10 reserved +2147483660 ReservedE11 reserved +2147483661 ReservedE12 reserved +2147483662 ReservedE13 reserved +2147483663 ReservedE14 reserved +2147483664 ReservedE15 reserved +2147483665 ReservedE16 reserved +2147483666 ReservedE17 reserved +2147483667 ReservedE18 reserved +2147483668 ReservedE19 reserved +2147483669 ReservedE20 reserved +2147483670 ReservedE21 reserved +2147483671 ReservedE22 reserved +2147483672 ReservedE23 reserved +2147483673 ReservedE24 reserved +2147483674 ReservedE25 reserved +2147483675 ReservedE26 reserved +2147483676 ReservedE27 reserved +2147483677 ReservedE28 reserved +2147483678 ReservedE29 reserved +2147483679 ReservedE30 reserved +2147483680 ReservedE31 reserved +2147483681 ReservedE32 reserved +2147483682 ReservedE33 reserved +========== =============== ================ .. OPCODES-RST:END @@ -3209,16 +3243,34 @@ INSTR.ILLEGALDXILOPCODE DXILOpCode must be valid o INSTR.ILLEGALDXILOPFUNCTION '%0' is not a DXILOpFuncition for DXILOpcode '%1'. INSTR.IMMBIASFORSAMPLEB bias amount for sample_b must be in the range [%0,%1], but %2 was specified as an immediate. INSTR.INBOUNDSACCESS Access to out-of-bounds memory is disallowed. -INSTR.LINALGILLEGALCOMPONENTTYPE Matrix Component Type '%0' not allowed in LinAlg Matrix. -INSTR.LINALGILLEGALKDIM Matrix K Dimension out of bounds. K=%0 must be >= %1 and <= %2. -INSTR.LINALGMATRIXDIMMISMATCH Matrix Dimension '%0x%1' does not match expected dimension %2x%3. -INSTR.LINALGMATRIXLAYOUTREQSTRIDE Matrix layout '%0' requires stride 0. -INSTR.LINALGMATRIXNOTEXACTMATCH Matrix '%0' must exactly match matrix '%1'. -INSTR.LINALGMATRIXSCOPEMISMATCH Matrix Scope '%0' does not match expected scope %1. -INSTR.LINALGMATRIXSCOPENOTALLOWED Matrix Scope '%0' not allowed in %1 operation. -INSTR.LINALGMATRIXSCOPEREQLAYOUT2 Matrix scope '%0' requires layout %1 or %2. -INSTR.LINALGMATRIXUSEMISMATCH Matrix Use '%0' does not match expected use %1. -INSTR.LINALGMATRIXUSEMISMATCH2 Matrix Use '%0' does not match expected use %1 or %2. +INSTR.LINALGILLEGALCOMPONENTTYPE Component type '%0' from %1 not allowed in LinAlg Matrix operations. +INSTR.LINALGILLEGALKDIM %0 matrix K dimension out of bounds. K=%1 must be >= %2 and <= %3. +INSTR.LINALGMATRIX2PARTSMUSTMATCH %0 matrix %1 '%2' must match %3 matrix %4 '%5'. +INSTR.LINALGMATRIXBYTEWISEMUSTBEMULTIPLE Parameter '%0' in bytes must be a multiple of %1, got %2 (%3 elements * %4 bytes per element). +INSTR.LINALGMATRIXDIMKVECKMISMATCH %0 vector size '%1' must be %2 for input matrix with K '%3' and Type '%4' +INSTR.LINALGMATRIXDIMVECTORMISMATCH %0 vector size '%1' must match input matrix M dimension '%2' +INSTR.LINALGMATRIXGSMEMMUSTBELARGEENOUGH Groupshared memory holds '%0' scalars but must hold at least '%1' scalars. +INSTR.LINALGMATRIXGSMEMTYPEMUSTMATCH Groupshared memory inner type '%0' must match %1 type '%2'. +INSTR.LINALGMATRIXLAYOUTREQSTRIDE %0 with layout '%1' requires stride 0. +INSTR.LINALGMATRIXLOADTHREADREQUIRESBAB Loading matrix with Thread scope requires ByteAddressBuffer. +INSTR.LINALGMATRIXMATRIXKDIMMUSTMATCH K dim of A matrix '%0' must match K dim of B matrix '%1'. %2 != %3. +INSTR.LINALGMATRIXMATRIXRESDIMMUSTMATCH %0 matrix dimension '%1' must match A.MxB.N '%2'. +INSTR.LINALGMATRIXNOTEXACTMATCH %0 matrix '%1' must exactly match %2 matrix '%3'. +INSTR.LINALGMATRIXREQUIRESLAYOUT2 %0 requires layout %1 or %2. +INSTR.LINALGMATRIXREQUIRESRWBAB %0 requires RWByteAddressBuffer. +INSTR.LINALGMATRIXSCOPEMISMATCH %0 matrix scope '%1' does not match expected scope %2. +INSTR.LINALGMATRIXSCOPEMISMATCH2 %0 matrix scope '%1' does not match expected scope %2 or %3. +INSTR.LINALGMATRIXSCOPEMUSTMATCH3 Matrix scope must be the same for all matrices. %0 '%1', %2 '%3', %4 '%5'. +INSTR.LINALGMATRIXSCOPEMUSTMATCH4 Matrix scope must be the same for all matrices. %0 '%1', %2 '%3', %4 '%5', %6 '%7'. +INSTR.LINALGMATRIXSCOPEREQLAYOUT2 %0 matrix with scope '%1' requires layout %2 or %3 for %4. +INSTR.LINALGMATRIXUNSIGNEDFLOATTYPENOTALLOWED Float-like type '%0' must be signed +INSTR.LINALGMATRIXUSEMISMATCH %0 matrix use '%1' does not match expected use %2. +INSTR.LINALGMATRIXUSEMISMATCH2 %0 matrix use '%1' does not match expected use %2 or %3. +INSTR.LINALGMATRIXVECELEMCOUNTMISMATCH Return vector size '%0' must match size '%1' derived from input vector size and type. +INSTR.LINALGMATRIXVECELEMENTTYPEMISMATCH %0 vector element type '%1' must match %2 vector element type '%3' +INSTR.LINALGMATRIXVECTORTYPEMUSTMATCH %0 vector element type '%1' must match %2 matrix element type '%3'. +INSTR.LINALGMATRIXVECTORTYPEMUSTMATCHPACKED %0 vector element type '%1' must be i32 for %2 matrix with non-native element type '%3'. +INSTR.LINALGMETADATAMISSING %0 matrix must have well-formed metadata. INSTR.MAYREORDERTHREADUNDEFCOHERENCEHINTPARAM Use of undef coherence hint or num coherence hint bits in MaybeReorderThread. INSTR.MINPRECISIONNOTPRECISE Instructions marked precise may not refer to minprecision values. INSTR.MINPRECISONBITCAST Bitcast on minprecison types is not allowed. @@ -3246,6 +3298,7 @@ INSTR.OPCODERESERVED Instructions must not refe INSTR.OPCONST DXIL intrinsic requires an immediate constant operand INSTR.OPCONSTRANGE Constant values must be in-range for operation. INSTR.OPERANDRANGE DXIL intrinsic operand must be within defined range +INSTR.PARAMMINIMUMVALUE Parameter must be greater than a minimum value INSTR.PARAMMULTIPLE Parameter must be a valid multiple INSTR.PTRBITCAST Pointer type bitcast must be have same size. INSTR.REORDERCOHERENTREQUIRESSM69 reordercoherent requires SM 6.9 or later. @@ -3405,6 +3458,7 @@ SM.RESOURCERANGEOVERLAP Resource ranges must not o SM.ROVONLYINPS RasterizerOrdered objects are only allowed in 5.0+ pixel shaders. SM.SAMPLECOUNTONLYON2DMS Only Texture2DMS/2DMSArray could has sample count. SM.SEMANTIC Semantic must be defined in target shader model +SM.SHADERSTAGE Shader stage must be supported by the target shader model SM.STREAMINDEXRANGE Stream index (%0) must between 0 and %1. SM.TESSFACTORFORDOMAIN Required TessFactor for domain not found declared anywhere in Patch Constant data. SM.TESSFACTORSIZEMATCHDOMAIN TessFactor rows, columns (%0, %1) invalid for domain %2. Expected %3 rows and 1 column. diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index a9232d4e29..84fecb8cb2 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -22,42 +22,127 @@ The included licenses apply to the following files: Place release notes for the upcoming release below this line and remove this line upon naming the release. Refer to previous for appropriate section names. -#### Bug Fixes - -- Fixed derivative operations being moved into divergent control flow, which - could produce incorrect results - [#8001](https://github.com/microsoft/DirectXShaderCompiler/issues/8001). +#### Shader Model 6.10 + +- Shader Model 6.10 and DXIL 1.10 are now available in retail, introducing + LinAlg Matrix, WaveGroup Index and Count, DebugBreak, Clustered Geometry, and + Triangle Object Positions, with detailed blog posts to be linked here once + available. +- Removed work graph support from Shader Model 6.10, and DXIL 1.10 + [microsoft/hlsl-specs#915](https://github.com/microsoft/hlsl-specs/issues/915). +- Fixed the set of numeric types allowed in LinAlg matrix intrinsics + [#8271](https://github.com/microsoft/DirectXShaderCompiler/issues/8271). +- Corrected the parameter order of `InterlockedAccumulate` + [microsoft/hlsl-specs#869](https://github.com/microsoft/hlsl-specs/issues/869). +- Added validation of LinAlg matrix builtin parameters and result K dimension + [#8491](https://github.com/microsoft/DirectXShaderCompiler/issues/8491). +- Restricted the component types allowed in LinAlg matrices + [#8494](https://github.com/microsoft/DirectXShaderCompiler/issues/8494). +- Added `BFloat16` to the ComponentType enum in DxilConstants and the linalg + header [#8722](https://github.com/microsoft/DirectXShaderCompiler/issues/8722). #### HLSL Language -- Casting a scalar to a struct or array containing a resource is now an error - instead of crashing - [#6661](https://github.com/microsoft/DirectXShaderCompiler/issues/6661). +- The `shared` and `uniform` keywords are removed in HLSL 202x, with + compatibility warnings available for earlier language versions + [#8482](https://github.com/microsoft/DirectXShaderCompiler/issues/8482). +- Added support for `auto` return types for normal functions aligning with C++14 + [#8903](https://github.com/microsoft/DirectXShaderCompiler/issues/8903). +- HLSL 202x now supports variadic templates and template function parameter + packs, pack expansions, and `sizeof...()` + [#8905](https://github.com/microsoft/DirectXShaderCompiler/issues/8905). +- HLSL 202x disallows initializers on variables in explicit and implicit + constant buffers and texture buffers + [#8483](https://github.com/microsoft/DirectXShaderCompiler/issues/8483). +- HLSL 202x disallows putting cbuffer, tbuffer, or namespace declarations inside + a cbuffer or tbuffer + [#8484](https://github.com/microsoft/DirectXShaderCompiler/issues/8484). +- Starting with HLSL 202x, `cbuffer` and `tbuffer` declarations and their + members belong to their enclosing namespace. +- HLSL 202x supports `const`-qualified instance methods and rejects calls + to non-`const` methods on `const` objects, including objects in constant + buffers + [#8964](https://github.com/microsoft/DirectXShaderCompiler/issues/8964). +- Add `static_assert` matching C++11 and C++17 under HLSL 202x + ([#8910](https://github.com/microsoft/DirectXShaderCompiler/issues/8910)). +- Fix HLSL 202x conforming literals false-positive warning for hex literal + signedness + ([#7864](https://github.com/microsoft/DirectXShaderCompiler/issues/7864)). #### Bug Fixes -- Fixed internal compiler errors when a member method is called on a ray payload - or on one of its fields with payload access qualifiers enabled - [#6464](https://github.com/microsoft/DirectXShaderCompiler/issues/6464). +- Fixed an optimizer crash when scalarizing an out-of-bounds vector access + [#8940](https://github.com/microsoft/DirectXShaderCompiler/issues/8940). ### Upcoming Preview Release These changes apply to experimental preview shader models only and will not be part of the next non-preview release. -#### Experimental Shader Model 6.10 +#### Experimental Shader Model 6.11 -These are incremental changes to the experimental Shader Model 6.10 features that -first shipped in the 1.10.2605 preview. +- Added experimental Shader Model 6.11 target profiles. -- Fixed the set of numeric types allowed in LinAlg matrix intrinsics - [#8271](https://github.com/microsoft/DirectXShaderCompiler/issues/8271). -- Corrected the parameter order of `InterlockedAccumulate` - [#8459](https://github.com/microsoft/DirectXShaderCompiler/pull/8459). -- Added validation of LinAlg matrix builtin parameters and result K dimension - [#8588](https://github.com/microsoft/DirectXShaderCompiler/pull/8588). -- Restricted the component types allowed in LinAlg matrices - [#8608](https://github.com/microsoft/DirectXShaderCompiler/pull/8608). +### Version 1.9.2609 + +#### Bug Fixes + +- Fixed derivative operations being moved into divergent control flow, which + could produce incorrect results + [#8001](https://github.com/microsoft/DirectXShaderCompiler/issues/8001). +- Fixed a bug in template instantiations involving functions with an + out parameter, which could lead to an assert or a bad memory access. + [#5293](https://github.com/microsoft/DirectXShaderCompiler/issues/5293), + [#8310](https://github.com/microsoft/DirectXShaderCompiler/issues/8310). +- SPIR-V: Fixed an invalid `OpSelect` being generated when optimizing for + SPIR-V 1.3 and earlier + [#8603](https://github.com/microsoft/DirectXShaderCompiler/issues/8603). +- Fix a crash generating DXIL from sources containing a dynamic resource heap + access that was discarded. Identified during development of SPIR-V support for + [descriptor heaps](https://github.com/microsoft/DirectXShaderCompiler/pull/8517#discussion_r3752113078). +- SPIR-V: Fixed a crash when writing to a bitfield member through a + `vk::BufferPointer` + [#8402](https://github.com/microsoft/DirectXShaderCompiler/issues/8402). +- Prevented an assertion from hiding the original fatal error when Clang skips + template specialization + [#6615](https://github.com/microsoft/DirectXShaderCompiler/issues/6615), + [#4875](https://github.com/microsoft/DirectXShaderCompiler/issues/4875). +- Fixed internal compiler errors when a member method is called on a ray payload + or on one of its fields with payload access qualifiers enabled + [#6464](https://github.com/microsoft/DirectXShaderCompiler/issues/6464). +- Fixed undefined behavior in DXC IntelliSense caused by the uninitialized + `ExpandTokPastingArg` preprocessor option, which made token-pasting + behavior indeterminate. + +#### HLSL Language + +- Starting with HLSL 202x, the count in `[unroll(N)]` is a partial-unroll hint + and no longer limits the number of loop iterations + [#8789](https://github.com/microsoft/DirectXShaderCompiler/issues/8789). +- Casting a scalar to a struct or array containing a resource is now an error + instead of crashing + [#6661](https://github.com/microsoft/DirectXShaderCompiler/issues/6661). +- Added the `-Whlsl-2026-compat` warning group for identifying issues + with language changes introduced in HLSL 2026. +- The legacy effects syntax support is removed in HLSL 202x + [#8480](https://github.com/microsoft/DirectXShaderCompiler/issues/8480). + +#### SPIR-V + +- Inline `[[vk::ext_decorate]]`, `[[vk::ext_capability]]`, and + `[[vk::ext_extension]]` attributes are now honored on ordinary functions + [#8616](https://github.com/microsoft/DirectXShaderCompiler/pull/8616). +- `globallycoherent` is now supported on `ResourceDescriptorHeap` accesses + [#7740](https://github.com/microsoft/DirectXShaderCompiler/issues/7740). +- Fixed a crash when a user-defined type named `RayQuery` shadows the intrinsic + type [#8601](https://github.com/microsoft/DirectXShaderCompiler/issues/8601). +- Fixed a crash from `static` members of a `cbuffer`/`tbuffer`, which were + incorrectly counted as buffer members and shifted the member indices of the + members declared after them + [#8537](https://github.com/microsoft/DirectXShaderCompiler/issues/8537). +- Fixed incorrect alignment of 64-bit elements in `vk::RawBufferLoad` and + `vk::RawBufferStore` intrinsics + [#8572](https://github.com/microsoft/DirectXShaderCompiler/issues/8572). ### Version 1.9.2607 diff --git a/docs/SPIRV-Cookbook.rst b/docs/SPIRV-Cookbook.rst index 42346e3b47..0fbfe4b773 100644 --- a/docs/SPIRV-Cookbook.rst +++ b/docs/SPIRV-Cookbook.rst @@ -42,8 +42,8 @@ examples will not work with Glslang. All of the examples are available in the DXC repository, at https://github.com/Microsoft/DirectXShaderCompiler/tree/main/tools/clang/test/CodeGenSPIRV/legal-examples -. To open a link to Tim Jones' Shader Playground for an example, you can -follow the url in the comments of each example. +. To open an interactive session on Compiler Explorer for an example, you +can follow the url in the comments of each example. Examples for structured buffers =============================== @@ -54,7 +54,7 @@ Desired code .. code-block:: hlsl // 0-copy-sbuf-ok.hlsl - // http://shader-playground.timjones.io/e6af2bdce0c61ed07d3a826aa8a95d45 + // https://godbolt.org/z/PEfooc9Kx struct S { float4 f; @@ -93,7 +93,7 @@ Initialization of a static .. code-block:: hlsl // 1-copy-global-static-ok.hlsl - // http://shader-playground.timjones.io/815543dc91a4e6855a8d0c6a345d4a5a + // https://godbolt.org/z/jTGE8Tnzn struct S { float4 f; @@ -122,7 +122,7 @@ This example can be legalized because the compiler is able to see that .. code-block:: hlsl // 2-write-global-static-ok.hlsl - // http://shader-playground.timjones.io/1c65c467e395383945d219a60edbe10c + // https://godbolt.org/z/hPbzf1v76 struct S { float4 f; @@ -150,7 +150,7 @@ Copy to function scope .. code-block:: hlsl // 3-copy-local-struct-ok.hlsl - // http://shader-playground.timjones.io/77dd20774e4943044c2f1b630c539f07 + // https://godbolt.org/z/G4neKP8ce struct S { float4 f; @@ -186,7 +186,7 @@ The following is a move complicated example. .. code-block:: hlsl // 4-copy-local-nested-struct-ok.hlsl - // http://shader-playground.timjones.io/14f59ff2a28c0a0180daf6ce4393cf6b + // https://godbolt.org/z/z7vvbhzrY struct S { float4 f; @@ -223,7 +223,7 @@ Function parameters .. code-block:: hlsl // 5-func-param-sbuf-ok.hlsl - // http://shader-playground.timjones.io/aeb06f527c5390d82d63bdb4eafc9ae7 + // https://godbolt.org/z/WGs5b95nr struct S { float4 f; @@ -256,7 +256,7 @@ same way that arrays work in C/C++. .. code-block:: hlsl // 6-func-param-rwsbuf-ok.hlsl - // http://shader-playground.timjones.io/f4e0194ce78118c0a709d85080ccea93 + // https://godbolt.org/z/f6ae1fKqq struct S { float4 f; @@ -290,7 +290,7 @@ to the global resource. .. code-block:: hlsl // 7-func-ret-tmp-var-ok.hlsl - // http://shader-playground.timjones.io/d6b706423f02dad58fbb01841282c6a1 + // https://godbolt.org/z/YdozvhqrE struct S { float4 f; @@ -316,7 +316,7 @@ to the global resource. .. code-block:: hlsl // 8-func-ret-direct-ok.hlsl - // http://shader-playground.timjones.io/6edbbc1aa6c6b6533c5a728135f87fb9 + // https://godbolt.org/z/cn94xccbP struct S { float4 f; @@ -360,7 +360,7 @@ resource is actually being accessed. .. code-block:: hlsl // 9-if-stmt-select-fail.hlsl - // http://shader-playground.timjones.io/2896e95627fd8a6689ca96c81a5c7c68 + // https://godbolt.org/z/anbjo5WoW struct S { float4 f; @@ -403,7 +403,7 @@ code into the following: .. code-block:: hlsl // 10-if-stmt-select-ok.hlsl - // http://shader-playground.timjones.io/5063d8a0a7ad1f9d0839cd34a6d94dd2 + // https://godbolt.org/z/WcsP3jfb3 struct S { float4 f; @@ -450,7 +450,7 @@ and knows that is always false. .. code-block:: hlsl // 11-if-stmt-const-ok.hlsl - // http://shader-playground.timjones.io/7ef5b89b3ec3d56c22e1bca45b40516a + // https://godbolt.org/z/oG69bG87n struct S { float4 f; @@ -511,7 +511,7 @@ constant, then the compiler will be able to propagate the copies. .. code-block:: hlsl // 12-switch-stmt-select-fail.hlsl - // http://shader-playground.timjones.io/b079f878daeba5d77842725b90a476ca + // https://godbolt.org/z/Y3KjTdGEa struct S { float4 f; @@ -551,7 +551,7 @@ does not know the value of ``i`` at compile time. .. code-block:: hlsl // 13-switch-stmt-const-ok.hlsl - // http://shader-playground.timjones.io/a46dd1f1a84eba38c047439741ec08ab + // https://godbolt.org/z/4GGn6cY4K struct S { float4 f; @@ -598,7 +598,7 @@ iteration of the loop. Consider this example. .. code-block:: hlsl // 14-loop-var-fail.hlsl - // http://shader-playground.timjones.io/8df364770e3f425e6321e71f817bcd1a + // https://godbolt.org/z/KexMWYKbY struct S { float4 f; @@ -641,7 +641,7 @@ attribute. The following example can be legalized by the compiler: .. code-block:: hlsl // 15-loop-var-unroll-ok.hlsl - // http://shader-playground.timjones.io/3d0f6f830fc4a5102714e19c748e81c7 + // https://godbolt.org/z/fMvjWa15T struct S { float4 f; @@ -691,7 +691,7 @@ because the number of iterations cannot be known at compile time. .. code-block:: hlsl // 16-loop-var-range-fail.hlsl - // http://shader-playground.timjones.io/376f5f985c3ceceea004ab58edb336f2 + // https://godbolt.org/z/vdrqz3qv7 struct S { float4 f; @@ -776,7 +776,7 @@ integral type. .. code-block:: hlsl // 17-loop-var-float-fail.hlsl - // http://shader-playground.timjones.io/d5d2598699378688684a4a074553dddf + // https://godbolt.org/z/GvdTn98c9 struct S { float4 f; @@ -819,7 +819,7 @@ Multiple calls to a function .. code-block:: hlsl // 18-multi-func-call-ok.hlsl - // http://shader-playground.timjones.io/e7b3ac1262a291c92902fd3f1fd3343c + // https://godbolt.org/z/hz7hbdG97 struct S { float4 f; @@ -858,7 +858,7 @@ returns. .. code-block:: hlsl // 19-multi-func-ret-fail.hlsl - // http://shader-playground.timjones.io/922facb688a5ba09b153d64cf1fc4557 + // https://godbolt.org/z/qPbEs36Ge struct S { float4 f; @@ -891,7 +891,7 @@ determine which path will be taken, then it can be legalized. .. code-block:: hlsl // 20-multi-func-ret-const-ok.hlsl - // http://shader-playground.timjones.io/84b093c7cf9e3932c5f0d9691533bafe + // https://godbolt.org/z/rhGP39brc struct S { float4 f; @@ -930,7 +930,7 @@ source code. .. code-block:: hlsl // 21-combined-ok.hlsl - // http://shader-playground.timjones.io/9f00d2d359da0731cdf8d0b68520e2c4 + // https://godbolt.org/z/nGT3sYhse struct S { float4 f; diff --git a/external/SPIRV-Tools b/external/SPIRV-Tools index b707790a89..1c33617264 160000 --- a/external/SPIRV-Tools +++ b/external/SPIRV-Tools @@ -1 +1 @@ -Subproject commit b707790a898e44038547df54580022fc1cf89c3d +Subproject commit 1c336172641682bab6e066767d09fdff1d826467 diff --git a/include/dxc/DXIL/DxilConstants.h b/include/dxc/DXIL/DxilConstants.h index 0e114a2bd3..a47fc89d53 100644 --- a/include/dxc/DXIL/DxilConstants.h +++ b/include/dxc/DXIL/DxilConstants.h @@ -29,8 +29,8 @@ namespace DXIL { const unsigned kDxilMajor = 1; /* hctdb_instrhelp.get_dxil_version_minor()*/ // VALRULE-TEXT:BEGIN -const unsigned kDxilMinor = 10; -const unsigned kDxilReleasedMinor = 9; +const unsigned kDxilMinor = 11; +const unsigned kDxilReleasedMinor = 10; // VALRULE-TEXT:END inline unsigned MakeDxilVersion(unsigned DxilMajor, unsigned DxilMinor) { @@ -199,6 +199,10 @@ enum class ComponentType : uint32_t { F8_E5M2 = 22, // END + // BEGIN NEW FOR SM 6.10 + BFloat16 = 23, + // END + LastEntry }; @@ -543,87 +547,44 @@ static const OpCodeTableID TableID = OpCodeTableID::ExperimentalOps; // Enumeration for ExperimentalOps DXIL operations enum class OpCode : unsigned { // - ReservedE0 = 32, // reserved - - // Debugging - DebugBreak = 33, // triggers a breakpoint if debugging is enabled - IsDebuggingEnabled = 34, // returns true if debugging is enabled - - // Group Wave Ops - GetGroupWaveCount = 2, // returns the number of waves in the thread group - GetGroupWaveIndex = 1, // returns the index of the wave in the thread group - - // Inline Ray Query - RayQuery_CandidateClusterID = 4, // returns candidate hit cluster ID - RayQuery_CandidateTriangleObjectPosition = - 8, // returns candidate triangle vertices in object space as <9 x float> - RayQuery_CommittedClusterID = 5, // returns committed hit cluster ID - RayQuery_CommittedTriangleObjectPosition = - 9, // returns committed triangle vertices in object space as <9 x float> - - // Linear Algebra Operations - LinAlgConvert = - 30, // Convert vector components from one interpretation to another - LinAlgCopyConvertMatrix = - 13, // Converts and copies the element and use type of the source matrix - // to the destination matrix with optional transpose - LinAlgFillMatrix = 12, // fills a matrix with a scalar value - LinAlgMatVecMul = - 25, // Multiplies a MxK dimension matrix and a K sized input vector - LinAlgMatVecMulAdd = 26, // Multiplies a MxK dimension matrix and a K sized - // input vector then adds a M sized bias vector - LinAlgMatrixAccumulate = 24, // accumulate A or B matrix into Accumulator - // matrix following LHS += RHS - LinAlgMatrixAccumulateToDescriptor = - 27, // accumulates a matrix to a RWByteAddressBuffer - LinAlgMatrixAccumulateToMemory = - 28, // accumulates a matrix to groupshared memory - LinAlgMatrixGetCoordinate = - 17, // returns a two element vector containing the column and row of the - // matrix that the thread-local index corresponds to - LinAlgMatrixGetElement = - 18, // returns the element of the matrix corresponding to the provided - // thread-local index - LinAlgMatrixLength = - 16, // returns the number of elements stored in thread-local storage on - // the active thread for the provided matrix - LinAlgMatrixLoadFromDescriptor = - 14, // fills a matrix with data from a [RW]ByteAddressBuffer - LinAlgMatrixLoadFromMemory = - 15, // fills a matrix with data from a groupshared array - LinAlgMatrixMultiply = - 23, // Returns the resulting matrix from multiplying A and B - LinAlgMatrixMultiplyAccumulate = - 11, // Returns the resulting matrix from multiplying A and B and - // accumulating into C - LinAlgMatrixOuterProduct = 29, // Outer products an M sized vector and a N - // sized vector producing an MxN matrix - LinAlgMatrixQueryAccumulatorLayout = - 22, // returns comptime 0 when accumulator matrix are A layout, 1 when B - // layout - LinAlgMatrixSetElement = 19, // sets the element of the matrix corresponding - // to the provided thread-local index - LinAlgMatrixStoreToDescriptor = - 20, // stores a matrix to a RWByteAddressBuffer - LinAlgMatrixStoreToMemory = 21, // stores a matrix to groupshared memory - LinAlgVectorAccumulateToDescriptor = - 31, // Accumulates given vector to the buffer at the given offset + ReservedE0 = 1, // reserved + ReservedE1 = 2, // reserved + ReservedE10 = 11, // reserved + ReservedE11 = 12, // reserved + ReservedE12 = 13, // reserved + ReservedE13 = 14, // reserved + ReservedE14 = 15, // reserved + ReservedE15 = 16, // reserved + ReservedE16 = 17, // reserved + ReservedE17 = 18, // reserved + ReservedE18 = 19, // reserved + ReservedE19 = 20, // reserved + ReservedE2 = 3, // reserved + ReservedE20 = 21, // reserved + ReservedE21 = 22, // reserved + ReservedE22 = 23, // reserved + ReservedE23 = 24, // reserved + ReservedE24 = 25, // reserved + ReservedE25 = 26, // reserved + ReservedE26 = 27, // reserved + ReservedE27 = 28, // reserved + ReservedE28 = 29, // reserved + ReservedE29 = 30, // reserved + ReservedE3 = 4, // reserved + ReservedE30 = 31, // reserved + ReservedE31 = 32, // reserved + ReservedE32 = 33, // reserved + ReservedE33 = 34, // reserved + ReservedE4 = 5, // reserved + ReservedE5 = 6, // reserved + ReservedE6 = 7, // reserved + ReservedE7 = 8, // reserved + ReservedE8 = 9, // reserved + ReservedE9 = 10, // reserved // No-op ExperimentalNop = 0, // nop does nothing - // Raytracing System Values - TriangleObjectPosition = - 7, // returns triangle vertices in object space as <9 x float> - - // Raytracing uint System Values - ClusterID = 3, // returns the user-defined ClusterID of the intersected CLAS - - // Shader Execution Reordering - HitObject_ClusterID = 6, // returns the cluster ID of this committed hit - HitObject_TriangleObjectPosition = - 10, // returns triangle vertices in object space as <9 x float> - NumOpCodes = 35, // exclusive last value of enumeration }; } // namespace ExperimentalOps @@ -744,6 +705,10 @@ enum class OpCode : unsigned { IndexNodeHandle = 248, // returns the handle for the location in the output // node array at the indicated index + // Debugging + DebugBreak = 343, // triggers a breakpoint if debugging is enabled + IsDebuggingEnabled = 344, // returns true if debugging is enabled + // Derivatives CalculateLOD = 81, // calculates the level of detail DerivCoarseX = 83, // computes the rate of change per stamp in x direction. @@ -804,6 +769,10 @@ enum class OpCode : unsigned { // Graphics shader ViewID = 138, // returns the view index + // Group Wave Ops + GetGroupWaveCount = 313, // returns the number of waves in the thread group + GetGroupWaveIndex = 312, // returns the index of the wave in the thread group + // Helper Lanes IsHelperLane = 221, // returns true on helper lanes in pixel shaders @@ -824,6 +793,7 @@ enum class OpCode : unsigned { AllocateRayQuery = 178, // allocates space for RayQuery and return handle AllocateRayQuery2 = 258, // allocates space for RayQuery and return handle RayQuery_Abort = 181, // aborts a ray query + RayQuery_CandidateClusterID = 315, // returns candidate hit cluster ID RayQuery_CandidateGeometryIndex = 203, // returns candidate hit geometry index RayQuery_CandidateInstanceContributionToHitGroupIndex = 214, // returns candidate hit InstanceContributionToHitGroupIndex @@ -844,6 +814,8 @@ enum class OpCode : unsigned { 193, // returns candidate triangle hit barycentrics RayQuery_CandidateTriangleFrontFace = 191, // returns if current candidate triangle is front facing + RayQuery_CandidateTriangleObjectPosition = + 319, // returns candidate triangle vertices in object space as <9 x float> RayQuery_CandidateTriangleRayT = 199, // returns float representing the parametric point on the ray for the // current candidate triangle hit. @@ -857,6 +829,7 @@ enum class OpCode : unsigned { 182, // commits a non opaque triangle hit RayQuery_CommitProceduralPrimitiveHit = 183, // commits a procedural primitive hit + RayQuery_CommittedClusterID = 316, // returns committed hit cluster ID RayQuery_CommittedGeometryIndex = 209, // returns committed hit geometry index RayQuery_CommittedInstanceContributionToHitGroupIndex = 215, // returns committed hit InstanceContributionToHitGroupIndex @@ -880,6 +853,8 @@ enum class OpCode : unsigned { 194, // returns committed triangle hit barycentrics RayQuery_CommittedTriangleFrontFace = 192, // returns if current committed triangle is front facing + RayQuery_CommittedTriangleObjectPosition = + 320, // returns committed triangle vertices in object space as <9 x float> RayQuery_CommittedWorldToObject3x4 = 189, // returns matrix for transforming from world-space to object-space // for a Committed hit. @@ -901,6 +876,54 @@ enum class OpCode : unsigned { CreateHandleForLib = 160, // create resource handle from resource struct for library + // Linear Algebra Operations + LinAlgConvert = + 341, // Convert vector components from one interpretation to another + LinAlgCopyConvertMatrix = + 324, // Converts and copies the element and use type of the source matrix + // to the destination matrix with optional transpose + LinAlgFillMatrix = 323, // fills a matrix with a scalar value + LinAlgMatVecMul = + 336, // Multiplies a MxK dimension matrix and a K sized input vector + LinAlgMatVecMulAdd = 337, // Multiplies a MxK dimension matrix and a K sized + // input vector then adds a M sized bias vector + LinAlgMatrixAccumulate = 335, // accumulate A or B matrix into Accumulator + // matrix following LHS += RHS + LinAlgMatrixAccumulateToDescriptor = + 338, // accumulates a matrix to a RWByteAddressBuffer + LinAlgMatrixAccumulateToMemory = + 339, // accumulates a matrix to groupshared memory + LinAlgMatrixGetCoordinate = + 328, // returns a two element vector containing the column and row of the + // matrix that the thread-local index corresponds to + LinAlgMatrixGetElement = + 329, // returns the element of the matrix corresponding to the provided + // thread-local index + LinAlgMatrixLength = + 327, // returns the number of elements stored in thread-local storage on + // the active thread for the provided matrix + LinAlgMatrixLoadFromDescriptor = + 325, // fills a matrix with data from a [RW]ByteAddressBuffer + LinAlgMatrixLoadFromMemory = + 326, // fills a matrix with data from a groupshared array + LinAlgMatrixMultiply = + 334, // Returns the resulting matrix from multiplying A and B + LinAlgMatrixMultiplyAccumulate = + 322, // Returns the resulting matrix from multiplying A and B and + // accumulating into C + LinAlgMatrixOuterProduct = 340, // Outer products an M sized vector and a N + // sized vector producing an MxN matrix + LinAlgMatrixQueryAccumulatorLayout = + 333, // returns comptime 0 when accumulator matrix are A layout, 1 when B + // layout + LinAlgMatrixSetElement = 330, // sets the element of the matrix corresponding + // to the provided thread-local index + LinAlgMatrixStoreToDescriptor = + 331, // stores a matrix to a RWByteAddressBuffer + LinAlgMatrixStoreToMemory = 332, // stores a matrix to groupshared memory + LinAlgVectorAccumulateToDescriptor = + 342, // Accumulates given vector to the buffer at the given offset + // Mesh shader instructions EmitIndices = 169, // emit a primitive's vertex indices in a mesh shader GetMeshPayload = @@ -967,6 +990,10 @@ enum class OpCode : unsigned { RayTMin = 153, // float representing the parametric starting point for the ray. + // Raytracing System Values + TriangleObjectPosition = + 318, // returns triangle vertices in object space as <9 x float> + // Raytracing hit uint System Values HitKind = 143, // Returns the value passed as HitKind in ReportIntersection(). // If intersection was reported by fixed-function triangle @@ -986,7 +1013,8 @@ enum class OpCode : unsigned { PrimitiveIndex = 161, // PrimitiveIndex for raytracing shaders // Raytracing uint System Values - RayFlags = 144, // uint containing the current ray flags. + ClusterID = 314, // returns the user-defined ClusterID of the intersected CLAS + RayFlags = 144, // uint containing the current ray flags. // Resources - gather TextureGather = 73, // gathers the four texels that would be used in a @@ -1049,6 +1077,7 @@ enum class OpCode : unsigned { // Shader Execution Reordering HitObject_Attributes = 289, // Returns the attributes set for this HitObject + HitObject_ClusterID = 317, // returns the cluster ID of this committed hit HitObject_FromRayQuery = 263, // Creates a new HitObject representing a // committed hit from a RayQuery HitObject_FromRayQueryWithAttrs = @@ -1084,6 +1113,8 @@ enum class OpCode : unsigned { 286, // Returns the shader table index set for this HitObject HitObject_TraceRay = 262, // Analogous to TraceRay but without invoking CH/MS // and returns the intermediate state as a HitObject + HitObject_TriangleObjectPosition = + 321, // returns triangle vertices in object space as <9 x float> HitObject_WorldRayDirection = 276, // Returns the ray direction in world space HitObject_WorldRayOrigin = 275, // Returns the ray origin in world space HitObject_WorldToObject3x4 = 280, // Returns the world to object space @@ -1223,8 +1254,9 @@ enum class OpCode : unsigned { NumOpCodes_Dxil_1_7 = 226, NumOpCodes_Dxil_1_8 = 258, NumOpCodes_Dxil_1_9 = 312, + NumOpCodes_Dxil_1_10 = 345, - NumOpCodes = 312, // exclusive last value of enumeration + NumOpCodes = 345, // exclusive last value of enumeration Invalid = 0xFFFFFFFF, // stable invalid OpCode value // OpCodes for extended tables follow. @@ -1233,152 +1265,74 @@ enum class OpCode : unsigned { // ExperimentalOps // ExperimentalNop = 0x80000000, 2147483648U, -2147483648 EXP_OPCODE(ExperimentalOps, ExperimentalNop), // nop does nothing - // GetGroupWaveIndex = 0x80000001, 2147483649U, -2147483647 - EXP_OPCODE( - ExperimentalOps, - GetGroupWaveIndex), // returns the index of the wave in the thread group - // GetGroupWaveCount = 0x80000002, 2147483650U, -2147483646 - EXP_OPCODE( - ExperimentalOps, - GetGroupWaveCount), // returns the number of waves in the thread group - // ClusterID = 0x80000003, 2147483651U, -2147483645 - EXP_OPCODE( - ExperimentalOps, - ClusterID), // returns the user-defined ClusterID of the intersected CLAS - // RayQuery_CandidateClusterID = 0x80000004, 2147483652U, -2147483644 - EXP_OPCODE(ExperimentalOps, - RayQuery_CandidateClusterID), // returns candidate hit cluster ID - // RayQuery_CommittedClusterID = 0x80000005, 2147483653U, -2147483643 - EXP_OPCODE(ExperimentalOps, - RayQuery_CommittedClusterID), // returns committed hit cluster ID - // HitObject_ClusterID = 0x80000006, 2147483654U, -2147483642 - EXP_OPCODE( - ExperimentalOps, - HitObject_ClusterID), // returns the cluster ID of this committed hit - // TriangleObjectPosition = 0x80000007, 2147483655U, -2147483641 - EXP_OPCODE(ExperimentalOps, - TriangleObjectPosition), // returns triangle vertices in object - // space as <9 x float> - // RayQuery_CandidateTriangleObjectPosition = 0x80000008, 2147483656U, - // -2147483640 - EXP_OPCODE( - ExperimentalOps, - RayQuery_CandidateTriangleObjectPosition), // returns candidate triangle - // vertices in object space as - // <9 x float> - // RayQuery_CommittedTriangleObjectPosition = 0x80000009, 2147483657U, - // -2147483639 - EXP_OPCODE( - ExperimentalOps, - RayQuery_CommittedTriangleObjectPosition), // returns committed triangle - // vertices in object space as - // <9 x float> - // HitObject_TriangleObjectPosition = 0x8000000A, 2147483658U, -2147483638 - EXP_OPCODE(ExperimentalOps, - HitObject_TriangleObjectPosition), // returns triangle vertices in - // object space as <9 x float> - // LinAlgMatrixMultiplyAccumulate = 0x8000000B, 2147483659U, -2147483637 - EXP_OPCODE(ExperimentalOps, - LinAlgMatrixMultiplyAccumulate), // Returns the resulting matrix - // from multiplying A and B and - // accumulating into C - // LinAlgFillMatrix = 0x8000000C, 2147483660U, -2147483636 - EXP_OPCODE(ExperimentalOps, - LinAlgFillMatrix), // fills a matrix with a scalar value - // LinAlgCopyConvertMatrix = 0x8000000D, 2147483661U, -2147483635 - EXP_OPCODE( - ExperimentalOps, - LinAlgCopyConvertMatrix), // Converts and copies the element and use type - // of the source matrix to the destination - // matrix with optional transpose - // LinAlgMatrixLoadFromDescriptor = 0x8000000E, 2147483662U, -2147483634 - EXP_OPCODE(ExperimentalOps, - LinAlgMatrixLoadFromDescriptor), // fills a matrix with data from a - // [RW]ByteAddressBuffer - // LinAlgMatrixLoadFromMemory = 0x8000000F, 2147483663U, -2147483633 - EXP_OPCODE(ExperimentalOps, - LinAlgMatrixLoadFromMemory), // fills a matrix with data from a - // groupshared array - // LinAlgMatrixLength = 0x80000010, 2147483664U, -2147483632 - EXP_OPCODE(ExperimentalOps, - LinAlgMatrixLength), // returns the number of elements stored in - // thread-local storage on the active thread - // for the provided matrix - // LinAlgMatrixGetCoordinate = 0x80000011, 2147483665U, -2147483631 - EXP_OPCODE( - ExperimentalOps, - LinAlgMatrixGetCoordinate), // returns a two element vector containing the - // column and row of the matrix that the - // thread-local index corresponds to - // LinAlgMatrixGetElement = 0x80000012, 2147483666U, -2147483630 - EXP_OPCODE(ExperimentalOps, - LinAlgMatrixGetElement), // returns the element of the matrix - // corresponding to the provided - // thread-local index - // LinAlgMatrixSetElement = 0x80000013, 2147483667U, -2147483629 - EXP_OPCODE( - ExperimentalOps, - LinAlgMatrixSetElement), // sets the element of the matrix corresponding - // to the provided thread-local index - // LinAlgMatrixStoreToDescriptor = 0x80000014, 2147483668U, -2147483628 - EXP_OPCODE(ExperimentalOps, - LinAlgMatrixStoreToDescriptor), // stores a matrix to a - // RWByteAddressBuffer - // LinAlgMatrixStoreToMemory = 0x80000015, 2147483669U, -2147483627 - EXP_OPCODE( - ExperimentalOps, - LinAlgMatrixStoreToMemory), // stores a matrix to groupshared memory - // LinAlgMatrixQueryAccumulatorLayout = 0x80000016, 2147483670U, -2147483626 - EXP_OPCODE(ExperimentalOps, - LinAlgMatrixQueryAccumulatorLayout), // returns comptime 0 when - // accumulator matrix are A - // layout, 1 when B layout - // LinAlgMatrixMultiply = 0x80000017, 2147483671U, -2147483625 - EXP_OPCODE(ExperimentalOps, - LinAlgMatrixMultiply), // Returns the resulting matrix from - // multiplying A and B - // LinAlgMatrixAccumulate = 0x80000018, 2147483672U, -2147483624 - EXP_OPCODE(ExperimentalOps, - LinAlgMatrixAccumulate), // accumulate A or B matrix into - // Accumulator matrix following LHS += RHS - // LinAlgMatVecMul = 0x80000019, 2147483673U, -2147483623 - EXP_OPCODE(ExperimentalOps, - LinAlgMatVecMul), // Multiplies a MxK dimension matrix and a K - // sized input vector - // LinAlgMatVecMulAdd = 0x8000001A, 2147483674U, -2147483622 - EXP_OPCODE( - ExperimentalOps, - LinAlgMatVecMulAdd), // Multiplies a MxK dimension matrix and a K sized - // input vector then adds a M sized bias vector - // LinAlgMatrixAccumulateToDescriptor = 0x8000001B, 2147483675U, -2147483621 - EXP_OPCODE(ExperimentalOps, - LinAlgMatrixAccumulateToDescriptor), // accumulates a matrix to a - // RWByteAddressBuffer - // LinAlgMatrixAccumulateToMemory = 0x8000001C, 2147483676U, -2147483620 - EXP_OPCODE(ExperimentalOps, - LinAlgMatrixAccumulateToMemory), // accumulates a matrix to - // groupshared memory - // LinAlgMatrixOuterProduct = 0x8000001D, 2147483677U, -2147483619 - EXP_OPCODE( - ExperimentalOps, - LinAlgMatrixOuterProduct), // Outer products an M sized vector and a N - // sized vector producing an MxN matrix - // LinAlgConvert = 0x8000001E, 2147483678U, -2147483618 - EXP_OPCODE(ExperimentalOps, LinAlgConvert), // Convert vector components from - // one interpretation to another - // LinAlgVectorAccumulateToDescriptor = 0x8000001F, 2147483679U, -2147483617 - EXP_OPCODE( - ExperimentalOps, - LinAlgVectorAccumulateToDescriptor), // Accumulates given vector to the - // buffer at the given offset - // ReservedE0 = 0x80000020, 2147483680U, -2147483616 + // ReservedE0 = 0x80000001, 2147483649U, -2147483647 EXP_OPCODE(ExperimentalOps, ReservedE0), // reserved - // DebugBreak = 0x80000021, 2147483681U, -2147483615 - EXP_OPCODE(ExperimentalOps, - DebugBreak), // triggers a breakpoint if debugging is enabled - // IsDebuggingEnabled = 0x80000022, 2147483682U, -2147483614 - EXP_OPCODE(ExperimentalOps, - IsDebuggingEnabled), // returns true if debugging is enabled + // ReservedE1 = 0x80000002, 2147483650U, -2147483646 + EXP_OPCODE(ExperimentalOps, ReservedE1), // reserved + // ReservedE2 = 0x80000003, 2147483651U, -2147483645 + EXP_OPCODE(ExperimentalOps, ReservedE2), // reserved + // ReservedE3 = 0x80000004, 2147483652U, -2147483644 + EXP_OPCODE(ExperimentalOps, ReservedE3), // reserved + // ReservedE4 = 0x80000005, 2147483653U, -2147483643 + EXP_OPCODE(ExperimentalOps, ReservedE4), // reserved + // ReservedE5 = 0x80000006, 2147483654U, -2147483642 + EXP_OPCODE(ExperimentalOps, ReservedE5), // reserved + // ReservedE6 = 0x80000007, 2147483655U, -2147483641 + EXP_OPCODE(ExperimentalOps, ReservedE6), // reserved + // ReservedE7 = 0x80000008, 2147483656U, -2147483640 + EXP_OPCODE(ExperimentalOps, ReservedE7), // reserved + // ReservedE8 = 0x80000009, 2147483657U, -2147483639 + EXP_OPCODE(ExperimentalOps, ReservedE8), // reserved + // ReservedE9 = 0x8000000A, 2147483658U, -2147483638 + EXP_OPCODE(ExperimentalOps, ReservedE9), // reserved + // ReservedE10 = 0x8000000B, 2147483659U, -2147483637 + EXP_OPCODE(ExperimentalOps, ReservedE10), // reserved + // ReservedE11 = 0x8000000C, 2147483660U, -2147483636 + EXP_OPCODE(ExperimentalOps, ReservedE11), // reserved + // ReservedE12 = 0x8000000D, 2147483661U, -2147483635 + EXP_OPCODE(ExperimentalOps, ReservedE12), // reserved + // ReservedE13 = 0x8000000E, 2147483662U, -2147483634 + EXP_OPCODE(ExperimentalOps, ReservedE13), // reserved + // ReservedE14 = 0x8000000F, 2147483663U, -2147483633 + EXP_OPCODE(ExperimentalOps, ReservedE14), // reserved + // ReservedE15 = 0x80000010, 2147483664U, -2147483632 + EXP_OPCODE(ExperimentalOps, ReservedE15), // reserved + // ReservedE16 = 0x80000011, 2147483665U, -2147483631 + EXP_OPCODE(ExperimentalOps, ReservedE16), // reserved + // ReservedE17 = 0x80000012, 2147483666U, -2147483630 + EXP_OPCODE(ExperimentalOps, ReservedE17), // reserved + // ReservedE18 = 0x80000013, 2147483667U, -2147483629 + EXP_OPCODE(ExperimentalOps, ReservedE18), // reserved + // ReservedE19 = 0x80000014, 2147483668U, -2147483628 + EXP_OPCODE(ExperimentalOps, ReservedE19), // reserved + // ReservedE20 = 0x80000015, 2147483669U, -2147483627 + EXP_OPCODE(ExperimentalOps, ReservedE20), // reserved + // ReservedE21 = 0x80000016, 2147483670U, -2147483626 + EXP_OPCODE(ExperimentalOps, ReservedE21), // reserved + // ReservedE22 = 0x80000017, 2147483671U, -2147483625 + EXP_OPCODE(ExperimentalOps, ReservedE22), // reserved + // ReservedE23 = 0x80000018, 2147483672U, -2147483624 + EXP_OPCODE(ExperimentalOps, ReservedE23), // reserved + // ReservedE24 = 0x80000019, 2147483673U, -2147483623 + EXP_OPCODE(ExperimentalOps, ReservedE24), // reserved + // ReservedE25 = 0x8000001A, 2147483674U, -2147483622 + EXP_OPCODE(ExperimentalOps, ReservedE25), // reserved + // ReservedE26 = 0x8000001B, 2147483675U, -2147483621 + EXP_OPCODE(ExperimentalOps, ReservedE26), // reserved + // ReservedE27 = 0x8000001C, 2147483676U, -2147483620 + EXP_OPCODE(ExperimentalOps, ReservedE27), // reserved + // ReservedE28 = 0x8000001D, 2147483677U, -2147483619 + EXP_OPCODE(ExperimentalOps, ReservedE28), // reserved + // ReservedE29 = 0x8000001E, 2147483678U, -2147483618 + EXP_OPCODE(ExperimentalOps, ReservedE29), // reserved + // ReservedE30 = 0x8000001F, 2147483679U, -2147483617 + EXP_OPCODE(ExperimentalOps, ReservedE30), // reserved + // ReservedE31 = 0x80000020, 2147483680U, -2147483616 + EXP_OPCODE(ExperimentalOps, ReservedE31), // reserved + // ReservedE32 = 0x80000021, 2147483681U, -2147483615 + EXP_OPCODE(ExperimentalOps, ReservedE32), // reserved + // ReservedE33 = 0x80000022, 2147483682U, -2147483614 + EXP_OPCODE(ExperimentalOps, ReservedE33), // reserved }; // OPCODE-ENUM:END #undef EXP_OPCODE @@ -2366,12 +2320,15 @@ const uint64_t ShaderFeatureInfo_ExtendedCommandInfo = 0x100000000; // Experimental SM 6.9+ - Reserved, not yet supported. const uint64_t ShaderFeatureInfo_Reserved = 0x8000000; +// SM 6.10+ +const uint64_t ShaderFeatureInfo_LinearAlgebra = 0x200000000; + // Maximum count without rolling over into another 64-bit field is 40, // so the last flag we can use for a feature requirement is: 0x8000000000 // This is because of the following set of flags, considered optional // and ignored by the runtime if not recognized: // D3D11_OPTIONAL_FEATURE_FLAGS 0x7FFFFF0000000000 -const unsigned ShaderFeatureInfoCount = 33; +const unsigned ShaderFeatureInfoCount = 34; static_assert(ShaderFeatureInfoCount <= 40, "ShaderFeatureInfo flags must fit within the first 40 bits; " "after that we need to expand the FeatureInfo blob part and " diff --git a/include/dxc/DXIL/DxilInstructions.h b/include/dxc/DXIL/DxilInstructions.h index f9f27660e2..c17f4254d3 100644 --- a/include/dxc/DXIL/DxilInstructions.h +++ b/include/dxc/DXIL/DxilInstructions.h @@ -693,6 +693,18 @@ struct LlvmInst_ExtractValue { bool isAllowed() const { return true; } }; +/// This instruction inserts into aggregate +struct LlvmInst_InsertValue { + llvm::Instruction *Instr; + // Construction and identification + LlvmInst_InsertValue(llvm::Instruction *pInstr) : Instr(pInstr) {} + operator bool() const { + return Instr->getOpcode() == llvm::Instruction::InsertValue; + } + // Validation support + bool isAllowed() const { return true; } +}; + /// This instruction represents a landing pad struct LlvmInst_LandingPad { llvm::Instruction *Instr; @@ -10002,26 +10014,6 @@ struct DxilInst_FDot { void set_b(llvm::Value *val) { Instr->setOperand(2, val); } }; -/// This instruction nop does nothing -struct DxilInst_ExperimentalNop { - llvm::Instruction *Instr; - // Construction and identification - DxilInst_ExperimentalNop(llvm::Instruction *pInstr) : Instr(pInstr) {} - operator bool() const { - return hlsl::OP::IsDxilOpFuncCallInst(Instr, - hlsl::OP::OpCode::ExperimentalNop); - } - // Validation support - bool isAllowed() const { return true; } - bool isArgumentListValid() const { - if (1 != llvm::dyn_cast(Instr)->getNumArgOperands()) - return false; - return true; - } - // Metadata - bool requiresUniformInputs() const { return false; } -}; - /// This instruction returns the index of the wave in the thread group struct DxilInst_GetGroupWaveIndex { llvm::Instruction *Instr; @@ -10317,7 +10309,7 @@ struct DxilInst_LinAlgFillMatrix { // Validation support bool isAllowed() const { return true; } bool isArgumentListValid() const { - if (2 != llvm::dyn_cast(Instr)->getNumArgOperands()) + if (3 != llvm::dyn_cast(Instr)->getNumArgOperands()) return false; return true; } @@ -10325,11 +10317,14 @@ struct DxilInst_LinAlgFillMatrix { bool requiresUniformInputs() const { return false; } // Operand indexes enum OperandIdx { - arg_value = 1, + arg_isInputSigned = 1, + arg_value = 2, }; // Accessors - llvm::Value *get_value() const { return Instr->getOperand(1); } - void set_value(llvm::Value *val) { Instr->setOperand(1, val); } + llvm::Value *get_isInputSigned() const { return Instr->getOperand(1); } + void set_isInputSigned(llvm::Value *val) { Instr->setOperand(1, val); } + llvm::Value *get_value() const { return Instr->getOperand(2); } + void set_value(llvm::Value *val) { Instr->setOperand(2, val); } }; /// This instruction Converts and copies the element and use type of the source @@ -10864,7 +10859,7 @@ struct DxilInst_LinAlgMatrixAccumulateToMemory { // Validation support bool isAllowed() const { return true; } bool isArgumentListValid() const { - if (7 != llvm::dyn_cast(Instr)->getNumArgOperands()) + if (6 != llvm::dyn_cast(Instr)->getNumArgOperands()) return false; return true; } @@ -10874,24 +10869,21 @@ struct DxilInst_LinAlgMatrixAccumulateToMemory { enum OperandIdx { arg_matrix = 1, arg_memory = 2, - arg_targetType = 3, - arg_offset = 4, - arg_stride = 5, - arg_layout = 6, + arg_offset = 3, + arg_stride = 4, + arg_layout = 5, }; // Accessors llvm::Value *get_matrix() const { return Instr->getOperand(1); } void set_matrix(llvm::Value *val) { Instr->setOperand(1, val); } llvm::Value *get_memory() const { return Instr->getOperand(2); } void set_memory(llvm::Value *val) { Instr->setOperand(2, val); } - llvm::Value *get_targetType() const { return Instr->getOperand(3); } - void set_targetType(llvm::Value *val) { Instr->setOperand(3, val); } - llvm::Value *get_offset() const { return Instr->getOperand(4); } - void set_offset(llvm::Value *val) { Instr->setOperand(4, val); } - llvm::Value *get_stride() const { return Instr->getOperand(5); } - void set_stride(llvm::Value *val) { Instr->setOperand(5, val); } - llvm::Value *get_layout() const { return Instr->getOperand(6); } - void set_layout(llvm::Value *val) { Instr->setOperand(6, val); } + llvm::Value *get_offset() const { return Instr->getOperand(3); } + void set_offset(llvm::Value *val) { Instr->setOperand(3, val); } + llvm::Value *get_stride() const { return Instr->getOperand(4); } + void set_stride(llvm::Value *val) { Instr->setOperand(4, val); } + llvm::Value *get_layout() const { return Instr->getOperand(5); } + void set_layout(llvm::Value *val) { Instr->setOperand(5, val); } }; /// This instruction Outer products an M sized vector and a N sized vector @@ -10908,7 +10900,7 @@ struct DxilInst_LinAlgMatrixOuterProduct { // Validation support bool isAllowed() const { return true; } bool isArgumentListValid() const { - if (3 != llvm::dyn_cast(Instr)->getNumArgOperands()) + if (4 != llvm::dyn_cast(Instr)->getNumArgOperands()) return false; return true; } @@ -10916,14 +10908,17 @@ struct DxilInst_LinAlgMatrixOuterProduct { bool requiresUniformInputs() const { return false; } // Operand indexes enum OperandIdx { - arg_vectorA = 1, - arg_vectorB = 2, + arg_isInputSigned = 1, + arg_vectorA = 2, + arg_vectorB = 3, }; // Accessors - llvm::Value *get_vectorA() const { return Instr->getOperand(1); } - void set_vectorA(llvm::Value *val) { Instr->setOperand(1, val); } - llvm::Value *get_vectorB() const { return Instr->getOperand(2); } - void set_vectorB(llvm::Value *val) { Instr->setOperand(2, val); } + llvm::Value *get_isInputSigned() const { return Instr->getOperand(1); } + void set_isInputSigned(llvm::Value *val) { Instr->setOperand(1, val); } + llvm::Value *get_vectorA() const { return Instr->getOperand(2); } + void set_vectorA(llvm::Value *val) { Instr->setOperand(2, val); } + llvm::Value *get_vectorB() const { return Instr->getOperand(3); } + void set_vectorB(llvm::Value *val) { Instr->setOperand(3, val); } }; /// This instruction Convert vector components from one interpretation to @@ -11035,5 +11030,25 @@ struct DxilInst_IsDebuggingEnabled { // Metadata bool requiresUniformInputs() const { return false; } }; + +/// This instruction nop does nothing +struct DxilInst_ExperimentalNop { + llvm::Instruction *Instr; + // Construction and identification + DxilInst_ExperimentalNop(llvm::Instruction *pInstr) : Instr(pInstr) {} + operator bool() const { + return hlsl::OP::IsDxilOpFuncCallInst(Instr, + hlsl::OP::OpCode::ExperimentalNop); + } + // Validation support + bool isAllowed() const { return true; } + bool isArgumentListValid() const { + if (1 != llvm::dyn_cast(Instr)->getNumArgOperands()) + return false; + return true; + } + // Metadata + bool requiresUniformInputs() const { return false; } +}; // INSTR-HELPER:END } // namespace hlsl diff --git a/include/dxc/DXIL/DxilOperations.h b/include/dxc/DXIL/DxilOperations.h index 210d9c6593..a119e735cc 100644 --- a/include/dxc/DXIL/DxilOperations.h +++ b/include/dxc/DXIL/DxilOperations.h @@ -147,6 +147,7 @@ class OP { static bool IsDxilOpFuncName(llvm::StringRef name); static bool IsDxilOpFunc(const llvm::Function *F); static bool IsDxilOpLinAlgFuncName(llvm::StringRef Name); + static bool IsDxilOpLinAlgFunc(const llvm::Function *F); static bool IsDxilOpFuncCallInst(const llvm::Instruction *I); static bool IsDxilOpFuncCallInst(const llvm::Instruction *I, OpCode opcode); static bool IsDxilOpWave(OpCode C); diff --git a/include/dxc/DXIL/DxilShaderFlags.h b/include/dxc/DXIL/DxilShaderFlags.h index 7b065c63fa..0458d3280d 100644 --- a/include/dxc/DXIL/DxilShaderFlags.h +++ b/include/dxc/DXIL/DxilShaderFlags.h @@ -219,6 +219,10 @@ class ShaderFlags { void SetRequiresGroup(bool flag) { m_bRequiresGroup = flag; } bool GetRequiresGroup() const { return m_bRequiresGroup; } + // SM 6.10+ + void SetLinearAlgebra(bool flag) { m_bLinearAlgebra = flag; } + bool GetLinearAlgebra() const { return m_bLinearAlgebra; } + private: // Bit: 0 unsigned @@ -359,7 +363,12 @@ class ShaderFlags { unsigned m_bRequiresGroup : 1; // SHADER_FEATURE_OPT_REQUIRES_GROUP // (OptFeatureInfo_RequiresGroup) - uint32_t m_align1 : 23; // align to 64 bit. + // SM 6.10+ + // m_bLinearAlgebra indicates the shader uses LinearAlgebra features. + // Bit: 41 + unsigned m_bLinearAlgebra : 1; // SHADER_FEATURE_LINEAR_ALGEBRA + + uint32_t m_align1 : 22; // align to 64 bit. }; } // namespace hlsl diff --git a/include/dxc/DXIL/DxilShaderModel.h b/include/dxc/DXIL/DxilShaderModel.h index ff9ef39b99..6e5dd9225c 100644 --- a/include/dxc/DXIL/DxilShaderModel.h +++ b/include/dxc/DXIL/DxilShaderModel.h @@ -33,7 +33,7 @@ class ShaderModel { // clang-format on // VALRULE-TEXT:BEGIN static const unsigned kHighestMajor = 6; - static const unsigned kHighestMinor = 10; + static const unsigned kHighestMinor = 11; // VALRULE-TEXT:END // Major/Minor version of highest released shader model @@ -41,7 +41,7 @@ class ShaderModel { // clang-format on // VALRULE-TEXT:BEGIN static const unsigned kHighestReleasedMajor = 6; - static const unsigned kHighestReleasedMinor = 9; + static const unsigned kHighestReleasedMinor = 10; // VALRULE-TEXT:END static const unsigned kOfflineMinor = 0xF; @@ -88,6 +88,7 @@ class ShaderModel { bool IsSM68Plus() const { return IsSMAtLeast(6, 8); } bool IsSM69Plus() const { return IsSMAtLeast(6, 9); } bool IsSM610Plus() const { return IsSMAtLeast(6, 10); } + bool IsSM611Plus() const { return IsSMAtLeast(6, 11); } // VALRULE-TEXT:END const char *GetName() const { return m_pszName; } const char *GetKindName() const; @@ -139,7 +140,7 @@ class ShaderModel { bool m_bTypedUavs, unsigned m_UAVRegsLim); /* hctdb_instrhelp.get_num_shader_models()*/ // VALRULE-TEXT:BEGIN - static const unsigned kNumShaderModels = 116; + static const unsigned kNumShaderModels = 125; // VALRULE-TEXT:END static const ShaderModel ms_ShaderModels[kNumShaderModels]; diff --git a/include/dxc/DxilContainer/DxilPipelineStateValidation.h b/include/dxc/DxilContainer/DxilPipelineStateValidation.h index 87919f7df8..32174d3727 100644 --- a/include/dxc/DxilContainer/DxilPipelineStateValidation.h +++ b/include/dxc/DxilContainer/DxilPipelineStateValidation.h @@ -175,8 +175,107 @@ struct PSVRuntimeInfo3 : public PSVRuntimeInfo2 { uint32_t EntryFunctionName; }; +enum class PSVRuntimeInfo4Flag : uint32_t { + None = 0x00000000, + // Indicates use of LinAlg operations beyond the Tier 1 required set, thus + // the presence of the PSVLinAlgRuntimeInfo structure with usage details. + LinAlgRuntimeInfoPresent = 0x00000001, +}; + struct PSVRuntimeInfo4 : public PSVRuntimeInfo3 { uint32_t NumBytesGroupSharedMemory; + uint32_t Flags; // PSVRuntimeInfo4Flag +}; + +struct PSVLinAlgRuntimeInfo0 { + // Presence of each table is indicated by a non-zero count. + // Tables are serialized in this order, with each starting with the record + // stride in bytes, followed by the records. + uint32_t MatrixOperationShapeCount; + uint32_t MatrixConstructionCount; + uint32_t ThreadMatrixVectorMultiplyCount; + uint32_t WaveMatrixMultiplyCount; + uint32_t ThreadGroupMatrixMultiplyCount; + uint32_t OuterProductCount; + uint32_t AccumulateStoreCount; +}; + +struct PSVLinAlgMatrixOperationShape0 { + // For each dimension, unused == 0. + // For MatrixConstruction, the unused dimension depends on the matrix use. + uint32_t M; // Rows in matrix A / Accumulator + uint32_t N; // Columns in matrix B / Accumulator + uint32_t K; // Columns in matrix A / Rows in matrix B +}; + +struct PSVLinAlgMatrixShapeArrayReference { + uint32_t ShapesIndex; // Index into SemanticIndexTable where the array of + // LinAlgMatrixOperationShape table indexes is located. + uint32_t Count; +}; + +struct PSVLinAlgMatrixConstruction0 { + // Each shape collects only the dimensions needed for a single matrix use. + // For instance, an Accumulator only uses M and N, so K will be set to 0. + // Different matrix use types are not combined to avoid implying uses that + // aren't present. + PSVLinAlgMatrixShapeArrayReference OperationShapes; + uint8_t MatrixType; + uint8_t Reserved[3]; +}; + +enum class PSVLinAlgThreadMatrixVectorMultiplyFlag : uint8_t { + None = 0, + // If neither flag is set, the matrix is only loaded from MulOptimal layout. + // The matrix is loaded from MulOptimalTranspose layout. + MatrixTransposed = 1 << 0, + // The matrix is loaded from a non-MulOptimal layout. + MatrixNonMulOptimalLayout = 1 << 1, +}; + +struct PSVLinAlgThreadMatrixVectorMultiply0 { + uint8_t ResultType; + uint8_t MatrixType; + uint8_t VectorInputType; + uint8_t Flags; // PSVLinAlgThreadMatrixVectorMultiplyFlag +}; + +struct PSVLinAlgWaveMatrixMultiply0 { + PSVLinAlgMatrixShapeArrayReference OperationShapes; + uint8_t AccumulatorType; + uint8_t MatrixAType; + uint8_t MatrixBType; + uint8_t Reserved; +}; + +// This matches PSVLinAlgWaveMatrixMultiply0 for now, but remains a separate +// structure in case the final wave and thread-group records diverge. +struct PSVLinAlgThreadGroupMatrixMultiply0 { + PSVLinAlgMatrixShapeArrayReference OperationShapes; + uint8_t AccumulatorType; + uint8_t MatrixAType; + uint8_t MatrixBType; + uint8_t Reserved; +}; + +struct PSVLinAlgOuterProduct0 { + uint8_t ResultType; + uint8_t VectorInputType; + uint8_t Reserved[2]; +}; + +enum class PSVLinAlgAccumulateStoreFlag : uint8_t { + None = 0, + // Accumulate is to a raw buffer, for all scopes. + RawBuffer = 1 << 0, + // Accumulate is to groupshared memory, for wave/group scope only. + GroupShared = 1 << 1, +}; + +struct PSVLinAlgAccumulateStore0 { + uint8_t AccumulatorType; + uint8_t Flags; // PSVLinAlgAccumulateStoreFlag + uint8_t Reserved[2]; }; enum class PSVResourceType { @@ -494,6 +593,30 @@ struct PSVInitInfo { uint8_t SigInputVectors = 0; uint8_t SigPatchConstOrPrimVectors = 0; uint8_t SigOutputVectors[PSV_GS_MAX_STREAMS] = {0, 0, 0, 0}; + const PSVLinAlgMatrixOperationShape0 *LinAlgMatrixOperationShapes = nullptr; + uint32_t LinAlgMatrixOperationShapeCount = 0; + const PSVLinAlgMatrixConstruction0 *LinAlgMatrixConstructions = nullptr; + uint32_t LinAlgMatrixConstructionCount = 0; + const PSVLinAlgThreadMatrixVectorMultiply0 + *LinAlgThreadMatrixVectorMultiplies = nullptr; + uint32_t LinAlgThreadMatrixVectorMultiplyCount = 0; + const PSVLinAlgWaveMatrixMultiply0 *LinAlgWaveMatrixMultiplies = nullptr; + uint32_t LinAlgWaveMatrixMultiplyCount = 0; + const PSVLinAlgThreadGroupMatrixMultiply0 *LinAlgThreadGroupMatrixMultiplies = + nullptr; + uint32_t LinAlgThreadGroupMatrixMultiplyCount = 0; + const PSVLinAlgOuterProduct0 *LinAlgOuterProducts = nullptr; + uint32_t LinAlgOuterProductCount = 0; + const PSVLinAlgAccumulateStore0 *LinAlgAccumulateStores = nullptr; + uint32_t LinAlgAccumulateStoreCount = 0; + + bool HasLinAlgRuntimeInfo() const { + return LinAlgMatrixOperationShapeCount || LinAlgMatrixConstructionCount || + LinAlgThreadMatrixVectorMultiplyCount || + LinAlgWaveMatrixMultiplyCount || + LinAlgThreadGroupMatrixMultiplyCount || LinAlgOuterProductCount || + LinAlgAccumulateStoreCount; + } static_assert(MAX_PSV_VERSION == 4, "otherwise this needs updating."); uint32_t RuntimeInfoSize() const { @@ -542,6 +665,22 @@ class DxilPipelineStateValidation { nullptr, nullptr}; uint32_t *m_pInputToPCOutputTable = nullptr; uint32_t *m_pPCInputToOutputTable = nullptr; + uint32_t m_uPSVLinAlgRuntimeInfoSize = 0; + PSVLinAlgRuntimeInfo0 *m_pPSVLinAlgRuntimeInfo0 = nullptr; + uint32_t m_uPSVLinAlgMatrixOperationShapeSize = 0; + void *m_pPSVLinAlgMatrixOperationShapes = nullptr; + uint32_t m_uPSVLinAlgMatrixConstructionSize = 0; + void *m_pPSVLinAlgMatrixConstructions = nullptr; + uint32_t m_uPSVLinAlgThreadMatrixVectorMultiplySize = 0; + void *m_pPSVLinAlgThreadMatrixVectorMultiplies = nullptr; + uint32_t m_uPSVLinAlgWaveMatrixMultiplySize = 0; + void *m_pPSVLinAlgWaveMatrixMultiplies = nullptr; + uint32_t m_uPSVLinAlgThreadGroupMatrixMultiplySize = 0; + void *m_pPSVLinAlgThreadGroupMatrixMultiplies = nullptr; + uint32_t m_uPSVLinAlgOuterProductSize = 0; + void *m_pPSVLinAlgOuterProducts = nullptr; + uint32_t m_uPSVLinAlgAccumulateStoreSize = 0; + void *m_pPSVLinAlgAccumulateStores = nullptr; public: DxilPipelineStateValidation() {} @@ -643,6 +782,101 @@ class DxilPipelineStateValidation { PSVRuntimeInfo4 *GetPSVRuntimeInfo4() const { return m_pPSVRuntimeInfo4; } + PSVLinAlgRuntimeInfo0 *GetPSVLinAlgRuntimeInfo0() const { + return m_pPSVLinAlgRuntimeInfo0; + } + + uint32_t GetPSVLinAlgMatrixOperationShapeCount() const { + return m_pPSVLinAlgRuntimeInfo0 + ? m_pPSVLinAlgRuntimeInfo0->MatrixOperationShapeCount + : 0; + } + + PSVLinAlgMatrixOperationShape0 * + GetPSVLinAlgMatrixOperationShape(uint32_t index) const { + return GetRecord( + m_pPSVLinAlgMatrixOperationShapes, m_uPSVLinAlgMatrixOperationShapeSize, + GetPSVLinAlgMatrixOperationShapeCount(), index); + } + + uint32_t GetPSVLinAlgMatrixConstructionCount() const { + return m_pPSVLinAlgRuntimeInfo0 + ? m_pPSVLinAlgRuntimeInfo0->MatrixConstructionCount + : 0; + } + + PSVLinAlgMatrixConstruction0 * + GetPSVLinAlgMatrixConstruction(uint32_t index) const { + return GetRecord( + m_pPSVLinAlgMatrixConstructions, m_uPSVLinAlgMatrixConstructionSize, + GetPSVLinAlgMatrixConstructionCount(), index); + } + + uint32_t GetPSVLinAlgThreadMatrixVectorMultiplyCount() const { + return m_pPSVLinAlgRuntimeInfo0 + ? m_pPSVLinAlgRuntimeInfo0->ThreadMatrixVectorMultiplyCount + : 0; + } + + PSVLinAlgThreadMatrixVectorMultiply0 * + GetPSVLinAlgThreadMatrixVectorMultiply(uint32_t index) const { + return GetRecord( + m_pPSVLinAlgThreadMatrixVectorMultiplies, + m_uPSVLinAlgThreadMatrixVectorMultiplySize, + GetPSVLinAlgThreadMatrixVectorMultiplyCount(), index); + } + + uint32_t GetPSVLinAlgWaveMatrixMultiplyCount() const { + return m_pPSVLinAlgRuntimeInfo0 + ? m_pPSVLinAlgRuntimeInfo0->WaveMatrixMultiplyCount + : 0; + } + + PSVLinAlgWaveMatrixMultiply0 * + GetPSVLinAlgWaveMatrixMultiply(uint32_t index) const { + return GetRecord( + m_pPSVLinAlgWaveMatrixMultiplies, m_uPSVLinAlgWaveMatrixMultiplySize, + GetPSVLinAlgWaveMatrixMultiplyCount(), index); + } + + uint32_t GetPSVLinAlgThreadGroupMatrixMultiplyCount() const { + return m_pPSVLinAlgRuntimeInfo0 + ? m_pPSVLinAlgRuntimeInfo0->ThreadGroupMatrixMultiplyCount + : 0; + } + + PSVLinAlgThreadGroupMatrixMultiply0 * + GetPSVLinAlgThreadGroupMatrixMultiply(uint32_t index) const { + return GetRecord( + m_pPSVLinAlgThreadGroupMatrixMultiplies, + m_uPSVLinAlgThreadGroupMatrixMultiplySize, + GetPSVLinAlgThreadGroupMatrixMultiplyCount(), index); + } + + uint32_t GetPSVLinAlgOuterProductCount() const { + return m_pPSVLinAlgRuntimeInfo0 + ? m_pPSVLinAlgRuntimeInfo0->OuterProductCount + : 0; + } + + PSVLinAlgOuterProduct0 *GetPSVLinAlgOuterProduct(uint32_t index) const { + return GetRecord( + m_pPSVLinAlgOuterProducts, m_uPSVLinAlgOuterProductSize, + GetPSVLinAlgOuterProductCount(), index); + } + + uint32_t GetPSVLinAlgAccumulateStoreCount() const { + return m_pPSVLinAlgRuntimeInfo0 + ? m_pPSVLinAlgRuntimeInfo0->AccumulateStoreCount + : 0; + } + + PSVLinAlgAccumulateStore0 *GetPSVLinAlgAccumulateStore(uint32_t index) const { + return GetRecord( + m_pPSVLinAlgAccumulateStores, m_uPSVLinAlgAccumulateStoreSize, + GetPSVLinAlgAccumulateStoreCount(), index); + } + uint32_t GetBindCount() const { return m_uResourceCount; } template @@ -938,6 +1172,12 @@ inline void DxilPipelineStateValidation::CheckedReaderWriter::Clear() { // PSVComputeInputOutputTableDwords(SigPatchConstOrPrimVectors, // SigOutputVectors[0]) } // - Outputs affected by patch constant inputs as a table of bitmasks +// If PSVRuntimeInfo4::Flags has LinAlgRuntimeInfoPresent: +// uint32_t PSVLinAlgRuntimeInfo_size +// { PSVLinAlgRuntimeInfoN structure } +// For each non-empty LinAlg record table, in declaration order: +// uint32_t record_size +// { record } * record_count // returns true if no errors occurred. inline bool DxilPipelineStateValidation::ReadOrWrite(const void *pBits, uint32_t *pSize, @@ -963,11 +1203,22 @@ DxilPipelineStateValidation::ReadOrWrite(const void *pBits, uint32_t *pSize, // In RWMode::CalcSize, use temp runtime info to hold needed values from // initInfo - PSVRuntimeInfo1 tempRuntimeInfo = {}; + PSVRuntimeInfo4 tempRuntimeInfo = {}; if (mode == RWMode::CalcSize && initInfo.PSVVersion > 0) { m_pPSVRuntimeInfo1 = &tempRuntimeInfo; + if (initInfo.PSVVersion > 1) + m_pPSVRuntimeInfo2 = &tempRuntimeInfo; + if (initInfo.PSVVersion > 2) + m_pPSVRuntimeInfo3 = &tempRuntimeInfo; + if (initInfo.PSVVersion > 3) + m_pPSVRuntimeInfo4 = &tempRuntimeInfo; } + if (mode != RWMode::Read && m_pPSVRuntimeInfo4 && + initInfo.HasLinAlgRuntimeInfo()) + m_pPSVRuntimeInfo4->Flags |= + static_cast(PSVRuntimeInfo4Flag::LinAlgRuntimeInfoPresent); + PSV_RETB(rw.MapValue(&m_uResourceCount, initInfo.ResourceCount)); if (m_uResourceCount > 0) { @@ -1092,9 +1343,90 @@ DxilPipelineStateValidation::ReadOrWrite(const void *pBits, uint32_t *pSize, } } + bool HasLinAlgRuntimeInfo = + m_pPSVRuntimeInfo4 && + (m_pPSVRuntimeInfo4->Flags & + static_cast(PSVRuntimeInfo4Flag::LinAlgRuntimeInfoPresent)); + PSVLinAlgRuntimeInfo0 tempLinAlgRuntimeInfo = {}; + if (HasLinAlgRuntimeInfo) { + PSV_RETB(rw.MapValue(&m_uPSVLinAlgRuntimeInfoSize, + static_cast(sizeof(PSVLinAlgRuntimeInfo0)))); + PSV_RETB(sizeof(PSVLinAlgRuntimeInfo0) <= m_uPSVLinAlgRuntimeInfoSize); + PSV_RETB( + rw.MapArray(&m_pPSVLinAlgRuntimeInfo0, 1, m_uPSVLinAlgRuntimeInfoSize)); + if (mode == RWMode::CalcSize) + m_pPSVLinAlgRuntimeInfo0 = &tempLinAlgRuntimeInfo; + + if (mode != RWMode::Read) { + m_pPSVLinAlgRuntimeInfo0->MatrixOperationShapeCount = + initInfo.LinAlgMatrixOperationShapeCount; + m_pPSVLinAlgRuntimeInfo0->MatrixConstructionCount = + initInfo.LinAlgMatrixConstructionCount; + m_pPSVLinAlgRuntimeInfo0->ThreadMatrixVectorMultiplyCount = + initInfo.LinAlgThreadMatrixVectorMultiplyCount; + m_pPSVLinAlgRuntimeInfo0->WaveMatrixMultiplyCount = + initInfo.LinAlgWaveMatrixMultiplyCount; + m_pPSVLinAlgRuntimeInfo0->ThreadGroupMatrixMultiplyCount = + initInfo.LinAlgThreadGroupMatrixMultiplyCount; + m_pPSVLinAlgRuntimeInfo0->OuterProductCount = + initInfo.LinAlgOuterProductCount; + m_pPSVLinAlgRuntimeInfo0->AccumulateStoreCount = + initInfo.LinAlgAccumulateStoreCount; + } + +#define PSV_MAP_LINALG_TABLE(Record, CountField, SizeField, DataField, \ + InitData) \ + if (m_pPSVLinAlgRuntimeInfo0->CountField) { \ + PSV_RETB(rw.MapValue(&SizeField, static_cast(sizeof(Record)))); \ + PSV_RETB(sizeof(Record) <= SizeField); \ + PSV_RETB(rw.MapArray(&DataField, m_pPSVLinAlgRuntimeInfo0->CountField, \ + SizeField)); \ + if (mode == RWMode::Write) { \ + PSV_RETB(InitData != nullptr); \ + memcpy(DataField, InitData, \ + sizeof(Record) * m_pPSVLinAlgRuntimeInfo0->CountField); \ + } \ + } + + PSV_MAP_LINALG_TABLE( + PSVLinAlgMatrixOperationShape0, MatrixOperationShapeCount, + m_uPSVLinAlgMatrixOperationShapeSize, m_pPSVLinAlgMatrixOperationShapes, + initInfo.LinAlgMatrixOperationShapes); + PSV_MAP_LINALG_TABLE(PSVLinAlgMatrixConstruction0, MatrixConstructionCount, + m_uPSVLinAlgMatrixConstructionSize, + m_pPSVLinAlgMatrixConstructions, + initInfo.LinAlgMatrixConstructions); + PSV_MAP_LINALG_TABLE(PSVLinAlgThreadMatrixVectorMultiply0, + ThreadMatrixVectorMultiplyCount, + m_uPSVLinAlgThreadMatrixVectorMultiplySize, + m_pPSVLinAlgThreadMatrixVectorMultiplies, + initInfo.LinAlgThreadMatrixVectorMultiplies); + PSV_MAP_LINALG_TABLE(PSVLinAlgWaveMatrixMultiply0, WaveMatrixMultiplyCount, + m_uPSVLinAlgWaveMatrixMultiplySize, + m_pPSVLinAlgWaveMatrixMultiplies, + initInfo.LinAlgWaveMatrixMultiplies); + PSV_MAP_LINALG_TABLE(PSVLinAlgThreadGroupMatrixMultiply0, + ThreadGroupMatrixMultiplyCount, + m_uPSVLinAlgThreadGroupMatrixMultiplySize, + m_pPSVLinAlgThreadGroupMatrixMultiplies, + initInfo.LinAlgThreadGroupMatrixMultiplies); + PSV_MAP_LINALG_TABLE( + PSVLinAlgOuterProduct0, OuterProductCount, m_uPSVLinAlgOuterProductSize, + m_pPSVLinAlgOuterProducts, initInfo.LinAlgOuterProducts); + PSV_MAP_LINALG_TABLE(PSVLinAlgAccumulateStore0, AccumulateStoreCount, + m_uPSVLinAlgAccumulateStoreSize, + m_pPSVLinAlgAccumulateStores, + initInfo.LinAlgAccumulateStores); +#undef PSV_MAP_LINALG_TABLE + } + if (mode == RWMode::CalcSize) { *pSize = rw.GetSize(); - m_pPSVRuntimeInfo1 = nullptr; // clear ptr to tempRuntimeInfo + m_pPSVRuntimeInfo1 = nullptr; + m_pPSVRuntimeInfo2 = nullptr; + m_pPSVRuntimeInfo3 = nullptr; + m_pPSVRuntimeInfo4 = nullptr; + m_pPSVLinAlgRuntimeInfo0 = nullptr; } return true; } diff --git a/include/dxc/DxilContainer/RDAT_LibraryTypes.inl b/include/dxc/DxilContainer/RDAT_LibraryTypes.inl index 60f277691a..9182e765d2 100644 --- a/include/dxc/DxilContainer/RDAT_LibraryTypes.inl +++ b/include/dxc/DxilContainer/RDAT_LibraryTypes.inl @@ -83,11 +83,12 @@ RDAT_ENUM_END() // High 32-bits of ShaderFeatureInfo from DFCC_FeatureInfo RDAT_ENUM_START(DxilFeatureInfo2, uint32_t) RDAT_ENUM_VALUE(ExtendedCommandInfo, 0x1) + RDAT_ENUM_VALUE(LinearAlgebra, 0x2) // OptFeatureInfo flags RDAT_ENUM_VALUE(Opt_UsesDerivatives, 0x100) RDAT_ENUM_VALUE(Opt_RequiresGroup, 0x200) #if DEF_RDAT_ENUMS == DEF_RDAT_DUMP_IMPL - static_assert(DXIL::ShaderFeatureInfoCount == 33, + static_assert(DXIL::ShaderFeatureInfoCount == 34, "otherwise, RDAT_ENUM definition needs updating"); static_assert(DXIL::OptFeatureInfoCount == 2, "otherwise, RDAT_ENUM definition needs updating"); @@ -569,9 +570,10 @@ RDAT_DXIL_ENUM_START(hlsl::DXIL::ComponentType, uint32_t) RDAT_ENUM_VALUE_NODEF(I8) RDAT_ENUM_VALUE_NODEF(F8_E4M3FN) RDAT_ENUM_VALUE_NODEF(F8_E5M2) + RDAT_ENUM_VALUE_NODEF(BFloat16) RDAT_ENUM_VALUE_NODEF(LastEntry) #if DEF_RDAT_ENUMS == DEF_RDAT_DUMP_IMPL - static_assert((unsigned)hlsl::DXIL::ComponentType::LastEntry == 23, + static_assert((unsigned)hlsl::DXIL::ComponentType::LastEntry == 24, "otherwise, RDAT_DXIL_ENUM definition needs updating"); #endif RDAT_ENUM_END() diff --git a/include/dxc/HlslIntrinsicOp.h b/include/dxc/HlslIntrinsicOp.h index 067889e014..ecec2b377b 100644 --- a/include/dxc/HlslIntrinsicOp.h +++ b/include/dxc/HlslIntrinsicOp.h @@ -112,27 +112,6 @@ enum class IntrinsicOp { IOP_WorldToObject = 99, IOP_WorldToObject3x4 = 100, IOP_WorldToObject4x3 = 101, - IOP___builtin_LinAlg_Convert = 422, - IOP___builtin_LinAlg_CopyConvertMatrix = 401, - IOP___builtin_LinAlg_FillMatrix = 402, - IOP___builtin_LinAlg_MatrixAccumulate = 411, - IOP___builtin_LinAlg_MatrixAccumulateToDescriptor = 415, - IOP___builtin_LinAlg_MatrixAccumulateToMemory = 416, - IOP___builtin_LinAlg_MatrixGetCoordinate = 403, - IOP___builtin_LinAlg_MatrixGetElement = 404, - IOP___builtin_LinAlg_MatrixLength = 405, - IOP___builtin_LinAlg_MatrixLoadFromDescriptor = 406, - IOP___builtin_LinAlg_MatrixLoadFromMemory = 407, - IOP___builtin_LinAlg_MatrixMatrixMultiply = 412, - IOP___builtin_LinAlg_MatrixMatrixMultiplyAccumulate = 413, - IOP___builtin_LinAlg_MatrixOuterProduct = 417, - IOP___builtin_LinAlg_MatrixQueryAccumulatorLayout = 414, - IOP___builtin_LinAlg_MatrixSetElement = 408, - IOP___builtin_LinAlg_MatrixStoreToDescriptor = 409, - IOP___builtin_LinAlg_MatrixStoreToMemory = 410, - IOP___builtin_LinAlg_MatrixVectorMultiply = 418, - IOP___builtin_LinAlg_MatrixVectorMultiplyAdd = 419, - IOP___builtin_LinAlg_VectorAccumulateToDescriptor = 423, IOP_abort = 102, IOP_abs = 103, IOP_acos = 104, @@ -399,6 +378,27 @@ enum class IntrinsicOp { MOP_DxHitObject_TriangleObjectPositions = 400, IOP_DxIsDebuggingEnabled = 421, IOP_DxMaybeReorderThread = 359, + IOP_Dx__builtin_LinAlg_Convert = 422, + IOP_Dx__builtin_LinAlg_CopyConvertMatrix = 401, + IOP_Dx__builtin_LinAlg_FillMatrix = 402, + IOP_Dx__builtin_LinAlg_MatrixAccumulate = 411, + IOP_Dx__builtin_LinAlg_MatrixAccumulateToDescriptor = 415, + IOP_Dx__builtin_LinAlg_MatrixAccumulateToMemory = 416, + IOP_Dx__builtin_LinAlg_MatrixGetCoordinate = 403, + IOP_Dx__builtin_LinAlg_MatrixGetElement = 404, + IOP_Dx__builtin_LinAlg_MatrixLength = 405, + IOP_Dx__builtin_LinAlg_MatrixLoadFromDescriptor = 406, + IOP_Dx__builtin_LinAlg_MatrixLoadFromMemory = 407, + IOP_Dx__builtin_LinAlg_MatrixMatrixMultiply = 412, + IOP_Dx__builtin_LinAlg_MatrixMatrixMultiplyAccumulate = 413, + IOP_Dx__builtin_LinAlg_MatrixOuterProduct = 417, + IOP_Dx__builtin_LinAlg_MatrixQueryAccumulatorLayout = 414, + IOP_Dx__builtin_LinAlg_MatrixSetElement = 408, + IOP_Dx__builtin_LinAlg_MatrixStoreToDescriptor = 409, + IOP_Dx__builtin_LinAlg_MatrixStoreToMemory = 410, + IOP_Dx__builtin_LinAlg_MatrixVectorMultiply = 418, + IOP_Dx__builtin_LinAlg_MatrixVectorMultiplyAdd = 419, + IOP_Dx__builtin_LinAlg_VectorAccumulateToDescriptor = 423, MOP_Count = 328, MOP_FinishedCrossGroupSharing = 329, MOP_GetGroupNodeOutputRecords = 330, diff --git a/include/dxc/Support/HLSLOptions.td b/include/dxc/Support/HLSLOptions.td index f35e4809df..bfd986ad3e 100644 --- a/include/dxc/Support/HLSLOptions.td +++ b/include/dxc/Support/HLSLOptions.td @@ -462,7 +462,7 @@ def fvk_bind_counter_heap : MultiArg<["-"], "fvk-bind-counter-heap", 2>, MetaVar def target_profile : JoinedOrSeparate<["-", "/"], "T">, Flags<[CoreOption]>, Group, MetaVarName<"">, /* hctdb_instrhelp.get_target_profiles()*/ // VALRULE-TEXT:BEGIN - HelpText<"Set target profile. \n\t: ps_6_0, ps_6_1, ps_6_2, ps_6_3, ps_6_4, ps_6_5, ps_6_6, ps_6_7, ps_6_8, ps_6_9, ps_6_10, \n\t\t vs_6_0, vs_6_1, vs_6_2, vs_6_3, vs_6_4, vs_6_5, vs_6_6, vs_6_7, vs_6_8, vs_6_9, vs_6_10, \n\t\t gs_6_0, gs_6_1, gs_6_2, gs_6_3, gs_6_4, gs_6_5, gs_6_6, gs_6_7, gs_6_8, gs_6_9, gs_6_10, \n\t\t hs_6_0, hs_6_1, hs_6_2, hs_6_3, hs_6_4, hs_6_5, hs_6_6, hs_6_7, hs_6_8, hs_6_9, hs_6_10, \n\t\t ds_6_0, ds_6_1, ds_6_2, ds_6_3, ds_6_4, ds_6_5, ds_6_6, ds_6_7, ds_6_8, ds_6_9, ds_6_10, \n\t\t cs_6_0, cs_6_1, cs_6_2, cs_6_3, cs_6_4, cs_6_5, cs_6_6, cs_6_7, cs_6_8, cs_6_9, cs_6_10, \n\t\t lib_6_1, lib_6_2, lib_6_3, lib_6_4, lib_6_5, lib_6_6, lib_6_7, lib_6_8, lib_6_9, lib_6_10, \n\t\t ms_6_5, ms_6_6, ms_6_7, ms_6_8, ms_6_9, ms_6_10, \n\t\t as_6_5, as_6_6, as_6_7, as_6_8, as_6_9, as_6_10, \n\t\t ">; + HelpText<"Set target profile. \n\t: ps_6_0, ps_6_1, ps_6_2, ps_6_3, ps_6_4, ps_6_5, ps_6_6, ps_6_7, ps_6_8, ps_6_9, ps_6_10, ps_6_11, \n\t\t vs_6_0, vs_6_1, vs_6_2, vs_6_3, vs_6_4, vs_6_5, vs_6_6, vs_6_7, vs_6_8, vs_6_9, vs_6_10, vs_6_11, \n\t\t gs_6_0, gs_6_1, gs_6_2, gs_6_3, gs_6_4, gs_6_5, gs_6_6, gs_6_7, gs_6_8, gs_6_9, gs_6_10, gs_6_11, \n\t\t hs_6_0, hs_6_1, hs_6_2, hs_6_3, hs_6_4, hs_6_5, hs_6_6, hs_6_7, hs_6_8, hs_6_9, hs_6_10, hs_6_11, \n\t\t ds_6_0, ds_6_1, ds_6_2, ds_6_3, ds_6_4, ds_6_5, ds_6_6, ds_6_7, ds_6_8, ds_6_9, ds_6_10, ds_6_11, \n\t\t cs_6_0, cs_6_1, cs_6_2, cs_6_3, cs_6_4, cs_6_5, cs_6_6, cs_6_7, cs_6_8, cs_6_9, cs_6_10, cs_6_11, \n\t\t lib_6_1, lib_6_2, lib_6_3, lib_6_4, lib_6_5, lib_6_6, lib_6_7, lib_6_8, lib_6_9, lib_6_10, lib_6_11, \n\t\t ms_6_5, ms_6_6, ms_6_7, ms_6_8, ms_6_9, ms_6_10, ms_6_11, \n\t\t as_6_5, as_6_6, as_6_7, as_6_8, as_6_9, as_6_10, as_6_11, \n\t\t ">; // VALRULE-TEXT:END def entrypoint : JoinedOrSeparate<["-", "/"], "E">, Flags<[CoreOption, RewriteOption]>, Group, HelpText<"Entry point name">; diff --git a/include/dxc/dxcapi.internal.h b/include/dxc/dxcapi.internal.h index 6dbb899376..d256dafac0 100644 --- a/include/dxc/dxcapi.internal.h +++ b/include/dxc/dxcapi.internal.h @@ -47,8 +47,10 @@ enum LEGAL_INTRINSIC_TEMPLATES { 4, // Any one of scalar, vector or matrix types (but not object). LITEMPLATE_OBJECT = 5, // Object types. LITEMPLATE_ARRAY = 6, // Scalar array. + LITEMPLATE_ANY_ARRAY = + 7, // Array of scalars or of vectors of scalars (eg. float3[4]). - LITEMPLATE_COUNT = 7 + LITEMPLATE_COUNT = 8 }; // INTRIN_COMPTYPE_FROM_TYPE_ELT0 is for object method intrinsics to indicate @@ -191,6 +193,8 @@ static const UINT INTRIN_FLAG_READ_ONLY = 1U << 0; static const UINT INTRIN_FLAG_READ_NONE = 1U << 1; static const UINT INTRIN_FLAG_IS_WAVE = 1U << 2; static const UINT INTRIN_FLAG_STATIC_MEMBER = 1U << 3; +// Method mutates the object (cannot be called on a const-qualified instance). +static const UINT INTRIN_FLAG_MUTABLE_METHOD = 1U << 4; struct HLSL_INTRINSIC { UINT Op; // Intrinsic Op ID @@ -201,6 +205,8 @@ struct HLSL_INTRINSIC { // type UINT uNumArgs; // Count of arguments in pArgs. const HLSL_INTRINSIC_ARGUMENT *pArgs; // Pointer to first argument. + UINT MaxShaderModel; // Encoded maximum shader model, 0 = no maximum + // (Major << 4) + (Minor & 0xf) }; /////////////////////////////////////////////////////////////////////////////// diff --git a/include/llvm/Transforms/IPO/PassManagerBuilder.h b/include/llvm/Transforms/IPO/PassManagerBuilder.h index 2f342d9412..b5266fce7f 100644 --- a/include/llvm/Transforms/IPO/PassManagerBuilder.h +++ b/include/llvm/Transforms/IPO/PassManagerBuilder.h @@ -129,6 +129,7 @@ class PassManagerBuilder { bool HLSLHighLevel = false; // HLSL Change bool HLSLAllowPreserveValues = false; // HLSL Change bool HLSLOnlyWarnOnUnrollFail = false; // HLSL Change + bool HLSLUnrollCountIsHint = false; // HLSL Change hlsl::HLSLExtensionsCodegenHelper *HLSLExtensionsCodeGen = nullptr; // HLSL Change bool HLSLResMayAlias = false; // HLSL Change unsigned ScanLimit = 0; // HLSL Change diff --git a/include/llvm/Transforms/Scalar.h b/include/llvm/Transforms/Scalar.h index 02edcbddaf..bc7bc31cbc 100644 --- a/include/llvm/Transforms/Scalar.h +++ b/include/llvm/Transforms/Scalar.h @@ -129,7 +129,9 @@ void initializeDxilFixConstArrayInitializerPass(PassRegistry&); Pass *createDxilConditionalMem2RegPass(bool NoOpt); void initializeDxilConditionalMem2RegPass(PassRegistry&); -Pass *createDxilLoopUnrollPass(unsigned MaxIterationAttempt, bool OnlyWarnOnFail, bool StructurizeLoopExits); +Pass *createDxilLoopUnrollPass(unsigned MaxIterationAttempt, + bool OnlyWarnOnFail, bool StructurizeLoopExits, + bool UnrollCountIsHint); void initializeDxilLoopUnrollPass(PassRegistry&); Pass *createDxilEraseDeadRegionPass(); diff --git a/lib/Analysis/MemoryDependenceAnalysis.cpp b/lib/Analysis/MemoryDependenceAnalysis.cpp index 5c337fe4cf..4018878af4 100644 --- a/lib/Analysis/MemoryDependenceAnalysis.cpp +++ b/lib/Analysis/MemoryDependenceAnalysis.cpp @@ -49,7 +49,7 @@ STATISTIC(NumCacheCompleteNonLocalPtr, "Number of block queries that were completely cached"); // Limit for the number of instructions to scan in a block. -static const unsigned int BlockScanLimit = 500; +static const unsigned int BlockScanLimit = 100; // Limit on the number of memdep results to process. static const unsigned int NumResultsLimit = 100; diff --git a/lib/DXIL/DxilOperations.cpp b/lib/DXIL/DxilOperations.cpp index ffeabe766b..2896f850ce 100644 --- a/lib/DXIL/DxilOperations.cpp +++ b/lib/DXIL/DxilOperations.cpp @@ -2714,20 +2714,6 @@ static const OP::OpCodeProperty CoreOps_OpCodeProps[] = { 1, {{0x400}}, {{0x3}}}, // Overloads: getName()); } +bool OP::IsDxilOpLinAlgFuncName(StringRef Name) { + return Name.startswith(OP::m_LinAlgNamePrefix); +} + +bool OP::IsDxilOpLinAlgFunc(const llvm::Function *F) { + // Test for null to allow IsDxilOpLinAlgFunc(Call.getCalledFunc()) to be + // resilient to indirect calls + if (F == nullptr || !F->hasName()) + return false; + return IsDxilOpLinAlgFuncName(F->getName()); +} + bool OP::IsDxilOpFuncCallInst(const llvm::Instruction *I) { const CallInst *CI = dyn_cast(I); if (CI == nullptr) @@ -3375,11 +3647,10 @@ bool OP::IsDxilOpWave(OpCode C) { // WaveReadLaneFirst=118, WaveActiveOp=119, WaveActiveBit=120, // WavePrefixOp=121, QuadReadLaneAt=122, QuadOp=123, WaveAllBitCount=135, // WavePrefixBitCount=136, WaveMatch=165, WaveMultiPrefixOp=166, - // WaveMultiPrefixBitCount=167, QuadVote=222, GetGroupWaveIndex=2147483649, - // GetGroupWaveCount=2147483650 + // WaveMultiPrefixBitCount=167, QuadVote=222, GetGroupWaveIndex=312, + // GetGroupWaveCount=313 return (110 <= op && op <= 123) || (135 <= op && op <= 136) || - (165 <= op && op <= 167) || op == 222 || - (2147483649 <= op && op <= 2147483650); + (165 <= op && op <= 167) || op == 222 || (312 <= op && op <= 313); // OPCODE-WAVE:END } @@ -3959,67 +4230,63 @@ void OP::GetMinShaderModelAndMask(OpCode C, bool bWithTranslation, SFLAG(Library) | SFLAG(RayGeneration) | SFLAG(ClosestHit) | SFLAG(Miss); return; } - // Instructions: ExperimentalNop=2147483648, - // RayQuery_CandidateClusterID=2147483652, - // RayQuery_CommittedClusterID=2147483653, - // RayQuery_CandidateTriangleObjectPosition=2147483656, - // RayQuery_CommittedTriangleObjectPosition=2147483657, - // LinAlgMatrixLoadFromDescriptor=2147483662, - // LinAlgMatrixQueryAccumulatorLayout=2147483670, LinAlgMatVecMul=2147483673, - // LinAlgMatVecMulAdd=2147483674, - // LinAlgMatrixAccumulateToDescriptor=2147483675, - // LinAlgMatrixOuterProduct=2147483677, LinAlgConvert=2147483678, - // LinAlgVectorAccumulateToDescriptor=2147483679, DebugBreak=2147483681, - // IsDebuggingEnabled=2147483682 - if (op == 2147483648 || (2147483652 <= op && op <= 2147483653) || - (2147483656 <= op && op <= 2147483657) || op == 2147483662 || - op == 2147483670 || (2147483673 <= op && op <= 2147483675) || - (2147483677 <= op && op <= 2147483679) || - (2147483681 <= op && op <= 2147483682)) { + // Instructions: RayQuery_CandidateClusterID=315, + // RayQuery_CommittedClusterID=316, + // RayQuery_CandidateTriangleObjectPosition=319, + // RayQuery_CommittedTriangleObjectPosition=320, + // LinAlgMatrixLoadFromDescriptor=325, LinAlgMatrixQueryAccumulatorLayout=333, + // LinAlgMatVecMul=336, LinAlgMatVecMulAdd=337, + // LinAlgMatrixAccumulateToDescriptor=338, LinAlgMatrixOuterProduct=340, + // LinAlgConvert=341, LinAlgVectorAccumulateToDescriptor=342, DebugBreak=343, + // IsDebuggingEnabled=344 + if ((315 <= op && op <= 316) || (319 <= op && op <= 320) || op == 325 || + op == 333 || (336 <= op && op <= 338) || (340 <= op && op <= 344)) { major = 6; minor = 10; return; } - // Instructions: LinAlgMatrixMultiplyAccumulate=2147483659, - // LinAlgFillMatrix=2147483660, LinAlgCopyConvertMatrix=2147483661, - // LinAlgMatrixLoadFromMemory=2147483663, LinAlgMatrixLength=2147483664, - // LinAlgMatrixGetCoordinate=2147483665, LinAlgMatrixGetElement=2147483666, - // LinAlgMatrixSetElement=2147483667, - // LinAlgMatrixStoreToDescriptor=2147483668, - // LinAlgMatrixStoreToMemory=2147483669, LinAlgMatrixMultiply=2147483671, - // LinAlgMatrixAccumulate=2147483672, - // LinAlgMatrixAccumulateToMemory=2147483676 - if ((2147483659 <= op && op <= 2147483661) || - (2147483663 <= op && op <= 2147483669) || - (2147483671 <= op && op <= 2147483672) || op == 2147483676) { + // Instructions: LinAlgMatrixMultiplyAccumulate=322, LinAlgFillMatrix=323, + // LinAlgCopyConvertMatrix=324, LinAlgMatrixLoadFromMemory=326, + // LinAlgMatrixLength=327, LinAlgMatrixGetCoordinate=328, + // LinAlgMatrixGetElement=329, LinAlgMatrixSetElement=330, + // LinAlgMatrixStoreToDescriptor=331, LinAlgMatrixStoreToMemory=332, + // LinAlgMatrixMultiply=334, LinAlgMatrixAccumulate=335, + // LinAlgMatrixAccumulateToMemory=339 + if ((322 <= op && op <= 324) || (326 <= op && op <= 332) || + (334 <= op && op <= 335) || op == 339) { major = 6; minor = 10; mask = SFLAG(Compute); return; } - // Instructions: GetGroupWaveIndex=2147483649, GetGroupWaveCount=2147483650 - if ((2147483649 <= op && op <= 2147483650)) { + // Instructions: GetGroupWaveIndex=312, GetGroupWaveCount=313 + if ((312 <= op && op <= 313)) { major = 6; minor = 10; - mask = SFLAG(Compute) | SFLAG(Mesh) | SFLAG(Amplification) | SFLAG(Node); + mask = SFLAG(Compute) | SFLAG(Mesh) | SFLAG(Amplification); return; } - // Instructions: ClusterID=2147483651, TriangleObjectPosition=2147483655 - if (op == 2147483651 || op == 2147483655) { + // Instructions: ClusterID=314, TriangleObjectPosition=318 + if (op == 314 || op == 318) { major = 6; minor = 10; mask = SFLAG(Library) | SFLAG(AnyHit) | SFLAG(ClosestHit); return; } - // Instructions: HitObject_ClusterID=2147483654, - // HitObject_TriangleObjectPosition=2147483658 - if (op == 2147483654 || op == 2147483658) { + // Instructions: HitObject_ClusterID=317, HitObject_TriangleObjectPosition=321 + if (op == 317 || op == 321) { major = 6; minor = 10; mask = SFLAG(Library) | SFLAG(RayGeneration) | SFLAG(ClosestHit) | SFLAG(Miss); return; } + // Instructions: ExperimentalNop=2147483648 + if (op == 2147483648) { + major = 6; + minor = 11; + return; + } // OPCODE-SMMASK:END } @@ -6485,12 +6752,6 @@ Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) { A(pETy); break; - // No-op - case OpCode::ExperimentalNop: - A(pV); - A(pI32); - break; - // Group Wave Ops case OpCode::GetGroupWaveIndex: A(pI32); @@ -6562,6 +6823,7 @@ Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) { case OpCode::LinAlgFillMatrix: A(EXT(0)); A(pI32); + A(pI1); A(EXT(1)); break; case OpCode::LinAlgCopyConvertMatrix: @@ -6681,11 +6943,11 @@ Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) { A(pI32); A(pI32); A(pI32); - A(pI32); break; case OpCode::LinAlgMatrixOuterProduct: A(EXT(0)); A(pI32); + A(pI1); A(EXT(1)); A(EXT(2)); break; @@ -6705,19 +6967,157 @@ Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) { A(pETy); break; + // Debugging + case OpCode::DebugBreak: + A(pV); + A(pI32); + break; + case OpCode::IsDebuggingEnabled: + A(pI1); + A(pI32); + break; + + // No-op + case OpCode::ExperimentalNop: + A(pV); + A(pI32); + break; + // case OpCode::ReservedE0: A(pV); A(pI32); break; - - // Debugging - case OpCode::DebugBreak: + case OpCode::ReservedE1: A(pV); A(pI32); break; - case OpCode::IsDebuggingEnabled: - A(pI1); + case OpCode::ReservedE2: + A(pV); + A(pI32); + break; + case OpCode::ReservedE3: + A(pV); + A(pI32); + break; + case OpCode::ReservedE4: + A(pV); + A(pI32); + break; + case OpCode::ReservedE5: + A(pV); + A(pI32); + break; + case OpCode::ReservedE6: + A(pV); + A(pI32); + break; + case OpCode::ReservedE7: + A(pV); + A(pI32); + break; + case OpCode::ReservedE8: + A(pV); + A(pI32); + break; + case OpCode::ReservedE9: + A(pV); + A(pI32); + break; + case OpCode::ReservedE10: + A(pV); + A(pI32); + break; + case OpCode::ReservedE11: + A(pV); + A(pI32); + break; + case OpCode::ReservedE12: + A(pV); + A(pI32); + break; + case OpCode::ReservedE13: + A(pV); + A(pI32); + break; + case OpCode::ReservedE14: + A(pV); + A(pI32); + break; + case OpCode::ReservedE15: + A(pV); + A(pI32); + break; + case OpCode::ReservedE16: + A(pV); + A(pI32); + break; + case OpCode::ReservedE17: + A(pV); + A(pI32); + break; + case OpCode::ReservedE18: + A(pV); + A(pI32); + break; + case OpCode::ReservedE19: + A(pV); + A(pI32); + break; + case OpCode::ReservedE20: + A(pV); + A(pI32); + break; + case OpCode::ReservedE21: + A(pV); + A(pI32); + break; + case OpCode::ReservedE22: + A(pV); + A(pI32); + break; + case OpCode::ReservedE23: + A(pV); + A(pI32); + break; + case OpCode::ReservedE24: + A(pV); + A(pI32); + break; + case OpCode::ReservedE25: + A(pV); + A(pI32); + break; + case OpCode::ReservedE26: + A(pV); + A(pI32); + break; + case OpCode::ReservedE27: + A(pV); + A(pI32); + break; + case OpCode::ReservedE28: + A(pV); + A(pI32); + break; + case OpCode::ReservedE29: + A(pV); + A(pI32); + break; + case OpCode::ReservedE30: + A(pV); + A(pI32); + break; + case OpCode::ReservedE31: + A(pV); + A(pI32); + break; + case OpCode::ReservedE32: + A(pV); + A(pI32); + break; + case OpCode::ReservedE33: + A(pV); A(pI32); break; // OPCODE-OLOAD-FUNCS:END @@ -7021,14 +7421,47 @@ llvm::Type *OP::GetOverloadType(OpCode opCode, llvm::Function *F) { case OpCode::ReservedD1: case OpCode::ReservedD2: case OpCode::ReservedD3: - case OpCode::ExperimentalNop: case OpCode::GetGroupWaveIndex: case OpCode::GetGroupWaveCount: case OpCode::ClusterID: case OpCode::LinAlgMatrixQueryAccumulatorLayout: - case OpCode::ReservedE0: case OpCode::DebugBreak: case OpCode::IsDebuggingEnabled: + case OpCode::ExperimentalNop: + case OpCode::ReservedE0: + case OpCode::ReservedE1: + case OpCode::ReservedE2: + case OpCode::ReservedE3: + case OpCode::ReservedE4: + case OpCode::ReservedE5: + case OpCode::ReservedE6: + case OpCode::ReservedE7: + case OpCode::ReservedE8: + case OpCode::ReservedE9: + case OpCode::ReservedE10: + case OpCode::ReservedE11: + case OpCode::ReservedE12: + case OpCode::ReservedE13: + case OpCode::ReservedE14: + case OpCode::ReservedE15: + case OpCode::ReservedE16: + case OpCode::ReservedE17: + case OpCode::ReservedE18: + case OpCode::ReservedE19: + case OpCode::ReservedE20: + case OpCode::ReservedE21: + case OpCode::ReservedE22: + case OpCode::ReservedE23: + case OpCode::ReservedE24: + case OpCode::ReservedE25: + case OpCode::ReservedE26: + case OpCode::ReservedE27: + case OpCode::ReservedE28: + case OpCode::ReservedE29: + case OpCode::ReservedE30: + case OpCode::ReservedE31: + case OpCode::ReservedE32: + case OpCode::ReservedE33: return Type::getVoidTy(Ctx); case OpCode::QuadVote: return IntegerType::get(Ctx, 1); @@ -7067,6 +7500,11 @@ llvm::Type *OP::GetOverloadType(OpCode opCode, llvm::Function *F) { FT->getParamType(2), FT->getParamType(3)}); case OpCode::LinAlgFillMatrix: + if (FT->getNumParams() < 3) + return nullptr; + return llvm::StructType::get(Ctx, + {FT->getReturnType(), FT->getParamType(2)}); + case OpCode::LinAlgCopyConvertMatrix: case OpCode::LinAlgMatrixGetElement: case OpCode::LinAlgConvert: @@ -7099,7 +7537,6 @@ llvm::Type *OP::GetOverloadType(OpCode opCode, llvm::Function *F) { case OpCode::LinAlgMatrixMultiply: case OpCode::LinAlgMatrixAccumulate: - case OpCode::LinAlgMatrixOuterProduct: if (FT->getNumParams() < 3) return nullptr; return llvm::StructType::get( @@ -7112,6 +7549,12 @@ llvm::Type *OP::GetOverloadType(OpCode opCode, llvm::Function *F) { {FT->getReturnType(), FT->getParamType(1), FT->getParamType(3), FT->getParamType(5)}); + case OpCode::LinAlgMatrixOuterProduct: + if (FT->getNumParams() < 4) + return nullptr; + return llvm::StructType::get( + Ctx, {FT->getReturnType(), FT->getParamType(2), FT->getParamType(3)}); + // OPCODE-OLOAD-TYPES:END default: return Ty; diff --git a/lib/DXIL/DxilShaderFlags.cpp b/lib/DXIL/DxilShaderFlags.cpp index 90b7d033b5..b3f2e36f06 100644 --- a/lib/DXIL/DxilShaderFlags.cpp +++ b/lib/DXIL/DxilShaderFlags.cpp @@ -47,7 +47,7 @@ ShaderFlags::ShaderFlags() m_bAdvancedTextureOps(false), m_bWriteableMSAATextures(false), m_bReserved(false), m_bSampleCmpGradientOrBias(false), m_bExtendedCommandInfo(false), m_bUsesDerivatives(false), - m_bRequiresGroup(false), m_align1(0) { + m_bRequiresGroup(false), m_bLinearAlgebra(false), m_align1(0) { // Silence unused field warnings (void)m_align1; } @@ -132,6 +132,7 @@ uint64_t ShaderFlags::GetFeatureInfo() const { Flags |= m_bExtendedCommandInfo ? hlsl::DXIL::ShaderFeatureInfo_ExtendedCommandInfo : 0; + Flags |= m_bLinearAlgebra ? hlsl::DXIL::ShaderFeatureInfo_LinearAlgebra : 0; // Per-function flags Flags |= m_bUsesDerivatives ? hlsl::DXIL::OptFeatureInfo_UsesDerivatives : 0; @@ -198,6 +199,7 @@ uint64_t ShaderFlags::GetShaderFlagsRawForCollection() { Flags.SetWriteableMSAATextures(true); Flags.SetSampleCmpGradientOrBias(true); Flags.SetExtendedCommandInfo(true); + Flags.SetLinearAlgebra(true); Flags.SetUsesDerivatives(true); Flags.SetRequiresGroup(true); return Flags.GetShaderFlagsRaw(); @@ -445,6 +447,7 @@ ShaderFlags ShaderFlags::CollectShaderFlags(const Function *F, bool hasSampleCmpGradientOrBias = false; bool hasExtendedCommandInfo = false; + bool hasLinearAlgebra = false; // UsesDerivatives is used to indicate any derivative use per-function, before // flags are combined from called functions. Later, the flags are adjusted for @@ -584,6 +587,8 @@ ShaderFlags ShaderFlags::CollectShaderFlags(const Function *F, DXIL::OpCode dxilOp = hlsl::OP::getOpCode(CI); if (dxilOp == DXIL::OpCode::NumOpCodes) continue; + if (hlsl::OP::IsDxilOpLinAlgFunc(CI->getCalledFunction())) + hasLinearAlgebra = true; if (hlsl::OP::IsDxilOpWave(dxilOp)) hasWaveOps = true; if (hlsl::OP::IsDxilOpFeedback(dxilOp)) @@ -861,6 +866,7 @@ ShaderFlags ShaderFlags::CollectShaderFlags(const Function *F, !M->GetResMayAlias()); flag.SetSampleCmpGradientOrBias(hasSampleCmpGradientOrBias); flag.SetExtendedCommandInfo(hasExtendedCommandInfo); + flag.SetLinearAlgebra(hasLinearAlgebra); flag.SetUsesDerivatives(hasDerivatives); flag.SetRequiresGroup(requiresGroup); diff --git a/lib/DXIL/DxilShaderModel.cpp b/lib/DXIL/DxilShaderModel.cpp index e70a3b44c9..836c1ba71d 100644 --- a/lib/DXIL/DxilShaderModel.cpp +++ b/lib/DXIL/DxilShaderModel.cpp @@ -66,6 +66,7 @@ bool ShaderModel::IsValidForDxil() const { case 8: case 9: case 10: + case 11: // VALRULE-TEXT:END return true; case kOfflineMinor: @@ -95,107 +96,116 @@ const ShaderModel *ShaderModel::Get(Kind Kind, unsigned Major, unsigned Minor) { {1544, 12}, // ps_6_8 {1545, 13}, // ps_6_9 {1546, 14}, // ps_6_10 - {66560, 15}, // vs_4_0 - {66561, 16}, // vs_4_1 - {66816, 17}, // vs_5_0 - {66817, 18}, // vs_5_1 - {67072, 19}, // vs_6_0 - {67073, 20}, // vs_6_1 - {67074, 21}, // vs_6_2 - {67075, 22}, // vs_6_3 - {67076, 23}, // vs_6_4 - {67077, 24}, // vs_6_5 - {67078, 25}, // vs_6_6 - {67079, 26}, // vs_6_7 - {67080, 27}, // vs_6_8 - {67081, 28}, // vs_6_9 - {67082, 29}, // vs_6_10 - {132096, 30}, // gs_4_0 - {132097, 31}, // gs_4_1 - {132352, 32}, // gs_5_0 - {132353, 33}, // gs_5_1 - {132608, 34}, // gs_6_0 - {132609, 35}, // gs_6_1 - {132610, 36}, // gs_6_2 - {132611, 37}, // gs_6_3 - {132612, 38}, // gs_6_4 - {132613, 39}, // gs_6_5 - {132614, 40}, // gs_6_6 - {132615, 41}, // gs_6_7 - {132616, 42}, // gs_6_8 - {132617, 43}, // gs_6_9 - {132618, 44}, // gs_6_10 - {197632, 45}, // hs_4_0 - {197633, 46}, // hs_4_1 - {197888, 47}, // hs_5_0 - {197889, 48}, // hs_5_1 - {198144, 49}, // hs_6_0 - {198145, 50}, // hs_6_1 - {198146, 51}, // hs_6_2 - {198147, 52}, // hs_6_3 - {198148, 53}, // hs_6_4 - {198149, 54}, // hs_6_5 - {198150, 55}, // hs_6_6 - {198151, 56}, // hs_6_7 - {198152, 57}, // hs_6_8 - {198153, 58}, // hs_6_9 - {198154, 59}, // hs_6_10 - {263168, 60}, // ds_4_0 - {263169, 61}, // ds_4_1 - {263424, 62}, // ds_5_0 - {263425, 63}, // ds_5_1 - {263680, 64}, // ds_6_0 - {263681, 65}, // ds_6_1 - {263682, 66}, // ds_6_2 - {263683, 67}, // ds_6_3 - {263684, 68}, // ds_6_4 - {263685, 69}, // ds_6_5 - {263686, 70}, // ds_6_6 - {263687, 71}, // ds_6_7 - {263688, 72}, // ds_6_8 - {263689, 73}, // ds_6_9 - {263690, 74}, // ds_6_10 - {328704, 75}, // cs_4_0 - {328705, 76}, // cs_4_1 - {328960, 77}, // cs_5_0 - {328961, 78}, // cs_5_1 - {329216, 79}, // cs_6_0 - {329217, 80}, // cs_6_1 - {329218, 81}, // cs_6_2 - {329219, 82}, // cs_6_3 - {329220, 83}, // cs_6_4 - {329221, 84}, // cs_6_5 - {329222, 85}, // cs_6_6 - {329223, 86}, // cs_6_7 - {329224, 87}, // cs_6_8 - {329225, 88}, // cs_6_9 - {329226, 89}, // cs_6_10 - {394241, 90}, // lib_4_1 - {394497, 91}, // lib_5_1 - {394753, 92}, // lib_6_1 - {394754, 93}, // lib_6_2 - {394755, 94}, // lib_6_3 - {394756, 95}, // lib_6_4 - {394757, 96}, // lib_6_5 - {394758, 97}, // lib_6_6 - {394759, 98}, // lib_6_7 - {394760, 99}, // lib_6_8 - {394761, 100}, // lib_6_9 - {394762, 101}, // lib_6_10 + {1547, 15}, // ps_6_11 + {66560, 16}, // vs_4_0 + {66561, 17}, // vs_4_1 + {66816, 18}, // vs_5_0 + {66817, 19}, // vs_5_1 + {67072, 20}, // vs_6_0 + {67073, 21}, // vs_6_1 + {67074, 22}, // vs_6_2 + {67075, 23}, // vs_6_3 + {67076, 24}, // vs_6_4 + {67077, 25}, // vs_6_5 + {67078, 26}, // vs_6_6 + {67079, 27}, // vs_6_7 + {67080, 28}, // vs_6_8 + {67081, 29}, // vs_6_9 + {67082, 30}, // vs_6_10 + {67083, 31}, // vs_6_11 + {132096, 32}, // gs_4_0 + {132097, 33}, // gs_4_1 + {132352, 34}, // gs_5_0 + {132353, 35}, // gs_5_1 + {132608, 36}, // gs_6_0 + {132609, 37}, // gs_6_1 + {132610, 38}, // gs_6_2 + {132611, 39}, // gs_6_3 + {132612, 40}, // gs_6_4 + {132613, 41}, // gs_6_5 + {132614, 42}, // gs_6_6 + {132615, 43}, // gs_6_7 + {132616, 44}, // gs_6_8 + {132617, 45}, // gs_6_9 + {132618, 46}, // gs_6_10 + {132619, 47}, // gs_6_11 + {197632, 48}, // hs_4_0 + {197633, 49}, // hs_4_1 + {197888, 50}, // hs_5_0 + {197889, 51}, // hs_5_1 + {198144, 52}, // hs_6_0 + {198145, 53}, // hs_6_1 + {198146, 54}, // hs_6_2 + {198147, 55}, // hs_6_3 + {198148, 56}, // hs_6_4 + {198149, 57}, // hs_6_5 + {198150, 58}, // hs_6_6 + {198151, 59}, // hs_6_7 + {198152, 60}, // hs_6_8 + {198153, 61}, // hs_6_9 + {198154, 62}, // hs_6_10 + {198155, 63}, // hs_6_11 + {263168, 64}, // ds_4_0 + {263169, 65}, // ds_4_1 + {263424, 66}, // ds_5_0 + {263425, 67}, // ds_5_1 + {263680, 68}, // ds_6_0 + {263681, 69}, // ds_6_1 + {263682, 70}, // ds_6_2 + {263683, 71}, // ds_6_3 + {263684, 72}, // ds_6_4 + {263685, 73}, // ds_6_5 + {263686, 74}, // ds_6_6 + {263687, 75}, // ds_6_7 + {263688, 76}, // ds_6_8 + {263689, 77}, // ds_6_9 + {263690, 78}, // ds_6_10 + {263691, 79}, // ds_6_11 + {328704, 80}, // cs_4_0 + {328705, 81}, // cs_4_1 + {328960, 82}, // cs_5_0 + {328961, 83}, // cs_5_1 + {329216, 84}, // cs_6_0 + {329217, 85}, // cs_6_1 + {329218, 86}, // cs_6_2 + {329219, 87}, // cs_6_3 + {329220, 88}, // cs_6_4 + {329221, 89}, // cs_6_5 + {329222, 90}, // cs_6_6 + {329223, 91}, // cs_6_7 + {329224, 92}, // cs_6_8 + {329225, 93}, // cs_6_9 + {329226, 94}, // cs_6_10 + {329227, 95}, // cs_6_11 + {394241, 96}, // lib_4_1 + {394497, 97}, // lib_5_1 + {394753, 98}, // lib_6_1 + {394754, 99}, // lib_6_2 + {394755, 100}, // lib_6_3 + {394756, 101}, // lib_6_4 + {394757, 102}, // lib_6_5 + {394758, 103}, // lib_6_6 + {394759, 104}, // lib_6_7 + {394760, 105}, // lib_6_8 + {394761, 106}, // lib_6_9 + {394762, 107}, // lib_6_10 + {394763, 108}, // lib_6_11 // lib_6_x is for offline linking only, and relaxes restrictions - {394767, 102}, // lib_6_x - {853509, 103}, // ms_6_5 - {853510, 104}, // ms_6_6 - {853511, 105}, // ms_6_7 - {853512, 106}, // ms_6_8 - {853513, 107}, // ms_6_9 - {853514, 108}, // ms_6_10 - {919045, 109}, // as_6_5 - {919046, 110}, // as_6_6 - {919047, 111}, // as_6_7 - {919048, 112}, // as_6_8 - {919049, 113}, // as_6_9 - {919050, 114}, // as_6_10 + {394767, 109}, // lib_6_x + {853509, 110}, // ms_6_5 + {853510, 111}, // ms_6_6 + {853511, 112}, // ms_6_7 + {853512, 113}, // ms_6_8 + {853513, 114}, // ms_6_9 + {853514, 115}, // ms_6_10 + {853515, 116}, // ms_6_11 + {919045, 117}, // as_6_5 + {919046, 118}, // as_6_6 + {919047, 119}, // as_6_7 + {919048, 120}, // as_6_8 + {919049, 121}, // as_6_9 + {919050, 122}, // as_6_10 + {919051, 123}, // as_6_11 }; unsigned hash = (unsigned)Kind << 16 | Major << 8 | Minor; auto pred = [](const std::pair &elem, unsigned val) { @@ -341,6 +351,9 @@ void ShaderModel::GetDxilVersion(unsigned &DxilMajor, case 10: DxilMinor = 10; break; + case 11: + DxilMinor = 11; + break; case kOfflineMinor: // Always update this to highest dxil version DxilMinor = DXIL::kDxilMinor; break; @@ -394,6 +407,9 @@ void ShaderModel::GetMinValidatorVersion(unsigned &ValMajor, case 10: ValMinor = 10; break; + case 11: + ValMinor = 11; + break; // VALRULE-TEXT:END case kOfflineMinor: ValMajor = 0; @@ -536,6 +552,7 @@ const ShaderModel ShaderModel::ms_ShaderModels[kNumShaderModels] = { SM(Kind::Pixel, 6, 8, "ps_6_8", 32, 8, true, true, UINT_MAX), SM(Kind::Pixel, 6, 9, "ps_6_9", 32, 8, true, true, UINT_MAX), SM(Kind::Pixel, 6, 10, "ps_6_10", 32, 8, true, true, UINT_MAX), + SM(Kind::Pixel, 6, 11, "ps_6_11", 32, 8, true, true, UINT_MAX), SM(Kind::Vertex, 4, 0, "vs_4_0", 16, 16, false, false, 0), SM(Kind::Vertex, 4, 1, "vs_4_1", 32, 32, false, false, 0), SM(Kind::Vertex, 5, 0, "vs_5_0", 32, 32, true, true, 64), @@ -551,6 +568,7 @@ const ShaderModel ShaderModel::ms_ShaderModels[kNumShaderModels] = { SM(Kind::Vertex, 6, 8, "vs_6_8", 32, 32, true, true, UINT_MAX), SM(Kind::Vertex, 6, 9, "vs_6_9", 32, 32, true, true, UINT_MAX), SM(Kind::Vertex, 6, 10, "vs_6_10", 32, 32, true, true, UINT_MAX), + SM(Kind::Vertex, 6, 11, "vs_6_11", 32, 32, true, true, UINT_MAX), SM(Kind::Geometry, 4, 0, "gs_4_0", 16, 32, false, false, 0), SM(Kind::Geometry, 4, 1, "gs_4_1", 32, 32, false, false, 0), SM(Kind::Geometry, 5, 0, "gs_5_0", 32, 32, true, true, 64), @@ -566,6 +584,7 @@ const ShaderModel ShaderModel::ms_ShaderModels[kNumShaderModels] = { SM(Kind::Geometry, 6, 8, "gs_6_8", 32, 32, true, true, UINT_MAX), SM(Kind::Geometry, 6, 9, "gs_6_9", 32, 32, true, true, UINT_MAX), SM(Kind::Geometry, 6, 10, "gs_6_10", 32, 32, true, true, UINT_MAX), + SM(Kind::Geometry, 6, 11, "gs_6_11", 32, 32, true, true, UINT_MAX), SM(Kind::Hull, 4, 0, "hs_4_0", 32, 32, false, false, 0), SM(Kind::Hull, 4, 1, "hs_4_1", 32, 32, false, false, 0), SM(Kind::Hull, 5, 0, "hs_5_0", 32, 32, true, true, 64), @@ -581,6 +600,7 @@ const ShaderModel ShaderModel::ms_ShaderModels[kNumShaderModels] = { SM(Kind::Hull, 6, 8, "hs_6_8", 32, 32, true, true, UINT_MAX), SM(Kind::Hull, 6, 9, "hs_6_9", 32, 32, true, true, UINT_MAX), SM(Kind::Hull, 6, 10, "hs_6_10", 32, 32, true, true, UINT_MAX), + SM(Kind::Hull, 6, 11, "hs_6_11", 32, 32, true, true, UINT_MAX), SM(Kind::Domain, 4, 0, "ds_4_0", 32, 32, false, false, 0), SM(Kind::Domain, 4, 1, "ds_4_1", 32, 32, false, false, 0), SM(Kind::Domain, 5, 0, "ds_5_0", 32, 32, true, true, 64), @@ -596,6 +616,7 @@ const ShaderModel ShaderModel::ms_ShaderModels[kNumShaderModels] = { SM(Kind::Domain, 6, 8, "ds_6_8", 32, 32, true, true, UINT_MAX), SM(Kind::Domain, 6, 9, "ds_6_9", 32, 32, true, true, UINT_MAX), SM(Kind::Domain, 6, 10, "ds_6_10", 32, 32, true, true, UINT_MAX), + SM(Kind::Domain, 6, 11, "ds_6_11", 32, 32, true, true, UINT_MAX), SM(Kind::Compute, 4, 0, "cs_4_0", 0, 0, false, false, 0), SM(Kind::Compute, 4, 1, "cs_4_1", 0, 0, false, false, 0), SM(Kind::Compute, 5, 0, "cs_5_0", 0, 0, true, true, 64), @@ -611,6 +632,7 @@ const ShaderModel ShaderModel::ms_ShaderModels[kNumShaderModels] = { SM(Kind::Compute, 6, 8, "cs_6_8", 0, 0, true, true, UINT_MAX), SM(Kind::Compute, 6, 9, "cs_6_9", 0, 0, true, true, UINT_MAX), SM(Kind::Compute, 6, 10, "cs_6_10", 0, 0, true, true, UINT_MAX), + SM(Kind::Compute, 6, 11, "cs_6_11", 0, 0, true, true, UINT_MAX), SM(Kind::Library, 4, 1, "lib_4_1", 0, 0, false, false, 0), SM(Kind::Library, 5, 1, "lib_5_1", 0, 0, true, true, 64), SM(Kind::Library, 6, 1, "lib_6_1", 0, 0, true, true, UINT_MAX), @@ -623,6 +645,7 @@ const ShaderModel ShaderModel::ms_ShaderModels[kNumShaderModels] = { SM(Kind::Library, 6, 8, "lib_6_8", 0, 0, true, true, UINT_MAX), SM(Kind::Library, 6, 9, "lib_6_9", 0, 0, true, true, UINT_MAX), SM(Kind::Library, 6, 10, "lib_6_10", 0, 0, true, true, UINT_MAX), + SM(Kind::Library, 6, 11, "lib_6_11", 0, 0, true, true, UINT_MAX), // lib_6_x is for offline linking only, and relaxes restrictions SM(Kind::Library, 6, kOfflineMinor, "lib_6_x", 32, 32, true, true, UINT_MAX), @@ -632,12 +655,14 @@ const ShaderModel ShaderModel::ms_ShaderModels[kNumShaderModels] = { SM(Kind::Mesh, 6, 8, "ms_6_8", 0, 0, true, true, UINT_MAX), SM(Kind::Mesh, 6, 9, "ms_6_9", 0, 0, true, true, UINT_MAX), SM(Kind::Mesh, 6, 10, "ms_6_10", 0, 0, true, true, UINT_MAX), + SM(Kind::Mesh, 6, 11, "ms_6_11", 0, 0, true, true, UINT_MAX), SM(Kind::Amplification, 6, 5, "as_6_5", 0, 0, true, true, UINT_MAX), SM(Kind::Amplification, 6, 6, "as_6_6", 0, 0, true, true, UINT_MAX), SM(Kind::Amplification, 6, 7, "as_6_7", 0, 0, true, true, UINT_MAX), SM(Kind::Amplification, 6, 8, "as_6_8", 0, 0, true, true, UINT_MAX), SM(Kind::Amplification, 6, 9, "as_6_9", 0, 0, true, true, UINT_MAX), SM(Kind::Amplification, 6, 10, "as_6_10", 0, 0, true, true, UINT_MAX), + SM(Kind::Amplification, 6, 11, "as_6_11", 0, 0, true, true, UINT_MAX), // Values before Invalid must remain sorted by Kind, then Major, then Minor. SM(Kind::Invalid, 0, 0, "invalid", 0, 0, false, false, 0), // VALRULE-TEXT:END diff --git a/lib/DxilContainer/DxilContainerAssembler.cpp b/lib/DxilContainer/DxilContainerAssembler.cpp index d865971e47..6bf8247887 100644 --- a/lib/DxilContainer/DxilContainerAssembler.cpp +++ b/lib/DxilContainer/DxilContainerAssembler.cpp @@ -14,6 +14,7 @@ #include "dxc/DXIL/DxilEntryProps.h" #include "dxc/DXIL/DxilFunctionProps.h" #include "dxc/DXIL/DxilInstructions.h" +#include "dxc/DXIL/DxilMetadataHelper.h" #include "dxc/DXIL/DxilModule.h" #include "dxc/DXIL/DxilOperations.h" #include "dxc/DXIL/DxilShaderModel.h" @@ -31,6 +32,7 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/Instructions.h" @@ -42,6 +44,9 @@ #include #include // Needed for DxilPipelineStateValidation.h #include +#include +#include +#include using namespace llvm; using namespace hlsl; @@ -679,6 +684,14 @@ unsigned hlsl::LoadViewIDStateFromPSV(unsigned *pOutputData, class DxilPSVWriter : public DxilPartWriter { private: + struct LinAlgMatrixInfo { + DXIL::ComponentType Type = DXIL::ComponentType::Invalid; + uint32_t M = 0; + uint32_t N = 0; + DXIL::MatrixUse Use = DXIL::MatrixUse::A; + DXIL::MatrixScope Scope = DXIL::MatrixScope::Thread; + }; + const DxilModule &m_Module; unsigned m_ValMajor = 0, m_ValMinor = 0; PSVInitInfo m_PSVInitInfo; @@ -690,8 +703,398 @@ class DxilPSVWriter : public DxilPartWriter { std::vector m_SigInputElements; std::vector m_SigOutputElements; std::vector m_SigPatchConstOrPrimElements; + std::vector m_LinAlgShapes; + std::vector m_LinAlgConstructions; + std::vector + m_LinAlgThreadMatrixVectorMultiplies; + std::vector m_LinAlgWaveMatrixMultiplies; + std::vector + m_LinAlgThreadGroupMatrixMultiplies; + std::vector m_LinAlgOuterProducts; + std::vector m_LinAlgAccumulateStores; + std::map m_LinAlgMatrixInfos; unsigned EntryFunctionName = 0; + void LoadLinAlgMatrixInfos() { + NamedMDNode *NMD = m_Module.GetModule()->getNamedMetadata( + DxilMDHelper::kDxilTargetTypesMDName); + if (!NMD) + return; + + for (MDNode *MDN : NMD->operands()) { + MDTuple *MDT = dyn_cast(MDN); + if (!MDT || MDT->getNumOperands() != 6) + continue; + + ConstantAsMetadata *TypeMD = + dyn_cast(MDT->getOperand(0).get()); + if (!TypeMD) + continue; + + unsigned Values[5]; + bool IsValid = true; + for (unsigned I = 0; I < 5; ++I) { + ConstantAsMetadata *ValueMD = + dyn_cast(MDT->getOperand(I + 1).get()); + ConstantInt *Value = + ValueMD ? dyn_cast(ValueMD->getValue()) : nullptr; + if (!Value) { + IsValid = false; + break; + } + Values[I] = + Value->getLimitedValue(std::numeric_limits::max()); + } + if (!IsValid) + continue; + + Type *Ty = TypeMD->getValue()->getType(); + m_LinAlgMatrixInfos.emplace( + Ty, LinAlgMatrixInfo{static_cast(Values[0]), + Values[1], Values[2], + static_cast(Values[3]), + static_cast(Values[4])}); + } + } + + bool GetLinAlgMatrixInfo(Type *Ty, LinAlgMatrixInfo &Info) const { + if (!dxilutil::IsHLSLLinAlgMatrixType(Ty)) + return false; + auto It = m_LinAlgMatrixInfos.find(Ty); + if (It == m_LinAlgMatrixInfos.end()) + return false; + Info = It->second; + return true; + } + + static DXIL::ComponentType GetScalarComponentType(Type *Ty, + bool IsSigned = true) { + if (Ty->isHalfTy()) + return DXIL::ComponentType::F16; + if (Ty->isFloatTy()) + return DXIL::ComponentType::F32; + if (Ty->isDoubleTy()) + return DXIL::ComponentType::F64; + if (!Ty->isIntegerTy()) + return DXIL::ComponentType::Invalid; + switch (Ty->getIntegerBitWidth()) { + case 8: + return IsSigned ? DXIL::ComponentType::I8 : DXIL::ComponentType::U8; + case 16: + return IsSigned ? DXIL::ComponentType::I16 : DXIL::ComponentType::U16; + case 32: + return IsSigned ? DXIL::ComponentType::I32 : DXIL::ComponentType::U32; + case 64: + return IsSigned ? DXIL::ComponentType::I64 : DXIL::ComponentType::U64; + default: + return DXIL::ComponentType::Invalid; + } + } + + static DXIL::ComponentType + GetVectorOrScalarComponentType(Type *Ty, bool IsSigned = true) { + if (VectorType *VT = dyn_cast(Ty)) + return GetScalarComponentType(VT->getElementType(), IsSigned); + return GetScalarComponentType(Ty, IsSigned); + } + + uint32_t AddLinAlgShape(uint32_t M, uint32_t N, uint32_t K) { + for (uint32_t I = 0; I < m_LinAlgShapes.size(); ++I) { + const auto &Shape = m_LinAlgShapes[I]; + if (Shape.M == M && Shape.N == N && Shape.K == K) + return I; + } + m_LinAlgShapes.push_back({M, N, K}); + return static_cast(m_LinAlgShapes.size() - 1); + } + + uint32_t AddShapeIndexArray(ArrayRef ShapeIndexes) { + for (uint32_t Offset = 0; + Offset + ShapeIndexes.size() <= m_SemanticIndexBuffer.size(); + ++Offset) { + if (std::equal(ShapeIndexes.begin(), ShapeIndexes.end(), + m_SemanticIndexBuffer.begin() + Offset)) + return Offset; + } + uint32_t Offset = static_cast(m_SemanticIndexBuffer.size()); + m_SemanticIndexBuffer.append(ShapeIndexes.begin(), ShapeIndexes.end()); + return Offset; + } + + static void AddUniqueIndex(std::vector &Indexes, uint32_t Index) { + if (std::find(Indexes.begin(), Indexes.end(), Index) == Indexes.end()) + Indexes.push_back(Index); + } + + uint8_t GetMatVecLayoutFlags(Value *Matrix) const { + SmallVector Worklist(1, Matrix); + SmallPtrSet Visited; + uint8_t Flags = 0; + while (!Worklist.empty()) { + Value *V = Worklist.pop_back_val(); + if (!Visited.insert(V).second) + continue; + + if (PHINode *Phi = dyn_cast(V)) { + Worklist.append(Phi->incoming_values().begin(), + Phi->incoming_values().end()); + continue; + } + + if (SelectInst *Select = dyn_cast(V)) { + Worklist.push_back(Select->getTrueValue()); + Worklist.push_back(Select->getFalseValue()); + continue; + } + + if (CallInst *CI = dyn_cast(V)) { + DXIL::OpCode OpCode = OP::getOpCode(CI); + if (OpCode == DXIL::OpCode::LinAlgCopyConvertMatrix) { + DxilInst_LinAlgCopyConvertMatrix Op(CI); + Worklist.push_back(Op.get_srcMatrix()); + continue; + } + + if (OpCode == DXIL::OpCode::LinAlgMatrixLoadFromDescriptor) { + DxilInst_LinAlgMatrixLoadFromDescriptor Op(CI); + auto *Layout = dyn_cast(Op.get_layout()); + if (!Layout) + continue; + + DXIL::MatrixLayout LayoutValue = + static_cast(Layout->getZExtValue()); + if (LayoutValue == DXIL::MatrixLayout::MulOptimalTranspose) + Flags |= static_cast( + PSVLinAlgThreadMatrixVectorMultiplyFlag::MatrixTransposed); + else if (LayoutValue != DXIL::MatrixLayout::MulOptimal) + Flags |= + static_cast(PSVLinAlgThreadMatrixVectorMultiplyFlag:: + MatrixNonMulOptimalLayout); + } + } + } + return Flags; + } + + void CollectLinAlgRuntimeInfo() { + using ConstructionKey = std::pair; + using MultiplyKey = std::tuple; + std::map> ConstructionShapes; + std::map> MultiplyShapes; + + auto CollectConstruction = [&](Type *Ty) { + LinAlgMatrixInfo Matrix; + if (!GetLinAlgMatrixInfo(Ty, Matrix) || + Matrix.Scope == DXIL::MatrixScope::Thread) + return; + uint32_t M = Matrix.Use == DXIL::MatrixUse::B ? 0 : Matrix.M; + uint32_t N = Matrix.Use == DXIL::MatrixUse::A ? 0 : Matrix.N; + uint32_t K = + Matrix.Use == DXIL::MatrixUse::Accumulator + ? 0 + : (Matrix.Use == DXIL::MatrixUse::A ? Matrix.N : Matrix.M); + uint32_t Shape = AddLinAlgShape(M, N, K); + AddUniqueIndex(ConstructionShapes[{static_cast(Matrix.Type), + static_cast(Matrix.Use)}], + Shape); + }; + + for (const Function &F : m_Module.GetModule()->functions()) { + for (const BasicBlock &BB : F) { + for (const Instruction &I : BB) { + const CallInst *ConstCI = dyn_cast(&I); + if (!ConstCI || !OP::IsDxilOpFuncCallInst(ConstCI)) + continue; + + CallInst *CI = const_cast(ConstCI); + DXIL::OpCode OpCode = OP::getOpCode(CI); + bool IsSpecializedUse = true; + switch (OpCode) { + case DXIL::OpCode::LinAlgMatVecMul: + case DXIL::OpCode::LinAlgMatVecMulAdd: { + DxilInst_LinAlgMatVecMul Op(CI); + LinAlgMatrixInfo Matrix; + if (!GetLinAlgMatrixInfo(Op.get_matrix()->getType(), Matrix)) + break; + bool IsSigned = + cast(Op.get_isOutputSigned())->getZExtValue() != 0; + DXIL::ComponentType ResultType = + GetVectorOrScalarComponentType(CI->getType(), IsSigned); + DXIL::ComponentType InputType = static_cast( + cast(Op.get_interpretation())->getZExtValue()); + uint8_t Flags = GetMatVecLayoutFlags(Op.get_matrix()); + auto It = std::find_if( + m_LinAlgThreadMatrixVectorMultiplies.begin(), + m_LinAlgThreadMatrixVectorMultiplies.end(), + [&](const PSVLinAlgThreadMatrixVectorMultiply0 &Record) { + return Record.ResultType == + static_cast(ResultType) && + Record.MatrixType == + static_cast(Matrix.Type) && + Record.VectorInputType == + static_cast(InputType); + }); + if (It == m_LinAlgThreadMatrixVectorMultiplies.end()) + m_LinAlgThreadMatrixVectorMultiplies.push_back( + {static_cast(ResultType), + static_cast(Matrix.Type), + static_cast(InputType), Flags}); + else + It->Flags |= Flags; + break; + } + case DXIL::OpCode::LinAlgMatrixMultiply: + case DXIL::OpCode::LinAlgMatrixMultiplyAccumulate: { + DxilInst_LinAlgMatrixMultiply Op(CI); + LinAlgMatrixInfo Result, A, B; + if (!GetLinAlgMatrixInfo(CI->getType(), Result) || + !GetLinAlgMatrixInfo(Op.get_matrixA()->getType(), A) || + !GetLinAlgMatrixInfo(Op.get_matrixB()->getType(), B)) + break; + uint32_t Shape = AddLinAlgShape(A.M, B.N, A.N); + AddUniqueIndex(MultiplyShapes[{static_cast(Result.Scope), + static_cast(Result.Type), + static_cast(A.Type), + static_cast(B.Type)}], + Shape); + break; + } + case DXIL::OpCode::LinAlgMatrixOuterProduct: { + DxilInst_LinAlgMatrixOuterProduct Op(CI); + LinAlgMatrixInfo Result; + if (!GetLinAlgMatrixInfo(CI->getType(), Result)) + break; + bool IsInputSigned = + cast(Op.get_isInputSigned())->getZExtValue() != 0; + PSVLinAlgOuterProduct0 Record = { + static_cast(Result.Type), + static_cast(GetVectorOrScalarComponentType( + Op.get_vectorA()->getType(), IsInputSigned)), + {0, 0}}; + if (std::find_if( + m_LinAlgOuterProducts.begin(), m_LinAlgOuterProducts.end(), + [&](const PSVLinAlgOuterProduct0 &Existing) { + return Existing.ResultType == Record.ResultType && + Existing.VectorInputType == Record.VectorInputType; + }) == m_LinAlgOuterProducts.end()) + m_LinAlgOuterProducts.push_back(Record); + break; + } + case DXIL::OpCode::LinAlgMatrixAccumulateToDescriptor: + case DXIL::OpCode::LinAlgMatrixAccumulateToMemory: { + Value *MatrixValue; + uint8_t Flag; + if (OpCode == DXIL::OpCode::LinAlgMatrixAccumulateToDescriptor) { + DxilInst_LinAlgMatrixAccumulateToDescriptor Op(CI); + Flag = + static_cast(PSVLinAlgAccumulateStoreFlag::RawBuffer); + MatrixValue = Op.get_matrix(); + } else { + DxilInst_LinAlgMatrixAccumulateToMemory Op(CI); + Flag = static_cast( + PSVLinAlgAccumulateStoreFlag::GroupShared); + MatrixValue = Op.get_matrix(); + } + + LinAlgMatrixInfo Matrix; + if (!GetLinAlgMatrixInfo(MatrixValue->getType(), Matrix)) + break; + DXIL::ComponentType AccumulatorType = Matrix.Type; + auto It = std::find_if( + m_LinAlgAccumulateStores.begin(), + m_LinAlgAccumulateStores.end(), + [AccumulatorType](const PSVLinAlgAccumulateStore0 &Record) { + return Record.AccumulatorType == + static_cast(AccumulatorType); + }); + if (It == m_LinAlgAccumulateStores.end()) + m_LinAlgAccumulateStores.push_back( + {static_cast(AccumulatorType), Flag, {0, 0}}); + else + It->Flags |= Flag; + break; + } + case DXIL::OpCode::LinAlgVectorAccumulateToDescriptor: { + DxilInst_LinAlgVectorAccumulateToDescriptor Op(CI); + DXIL::ComponentType Type = + GetVectorOrScalarComponentType(Op.get_vector()->getType()); + auto It = std::find_if( + m_LinAlgAccumulateStores.begin(), + m_LinAlgAccumulateStores.end(), + [&](const PSVLinAlgAccumulateStore0 &Record) { + return Record.AccumulatorType == static_cast(Type); + }); + if (It == m_LinAlgAccumulateStores.end()) + m_LinAlgAccumulateStores.push_back( + {static_cast(Type), + static_cast( + PSVLinAlgAccumulateStoreFlag::RawBuffer), + {0, 0}}); + else + It->Flags |= + static_cast(PSVLinAlgAccumulateStoreFlag::RawBuffer); + break; + } + default: + IsSpecializedUse = false; + break; + } + + if (!IsSpecializedUse && + OP::IsDxilOpLinAlgFunc(CI->getCalledFunction())) { + CollectConstruction(CI->getType()); + for (unsigned ArgIndex = 0; ArgIndex < CI->getNumArgOperands(); + ++ArgIndex) + CollectConstruction(CI->getArgOperand(ArgIndex)->getType()); + } + } + } + } + + for (const auto &Entry : ConstructionShapes) { + const auto &Indexes = Entry.second; + m_LinAlgConstructions.push_back( + {{AddShapeIndexArray(Indexes), static_cast(Indexes.size())}, + Entry.first.first, + {0, 0, 0}}); + } + for (const auto &Entry : MultiplyShapes) { + const auto &Indexes = Entry.second; + PSVLinAlgMatrixShapeArrayReference Shapes = { + AddShapeIndexArray(Indexes), static_cast(Indexes.size())}; + uint8_t Scope = std::get<0>(Entry.first); + if (Scope == static_cast(DXIL::MatrixScope::Wave)) + m_LinAlgWaveMatrixMultiplies.push_back( + {Shapes, std::get<1>(Entry.first), std::get<2>(Entry.first), + std::get<3>(Entry.first), 0}); + else + m_LinAlgThreadGroupMatrixMultiplies.push_back( + {Shapes, std::get<1>(Entry.first), std::get<2>(Entry.first), + std::get<3>(Entry.first), 0}); + } + + m_PSVInitInfo.LinAlgMatrixOperationShapes = m_LinAlgShapes.data(); + m_PSVInitInfo.LinAlgMatrixOperationShapeCount = m_LinAlgShapes.size(); + m_PSVInitInfo.LinAlgMatrixConstructions = m_LinAlgConstructions.data(); + m_PSVInitInfo.LinAlgMatrixConstructionCount = m_LinAlgConstructions.size(); + m_PSVInitInfo.LinAlgThreadMatrixVectorMultiplies = + m_LinAlgThreadMatrixVectorMultiplies.data(); + m_PSVInitInfo.LinAlgThreadMatrixVectorMultiplyCount = + m_LinAlgThreadMatrixVectorMultiplies.size(); + m_PSVInitInfo.LinAlgWaveMatrixMultiplies = + m_LinAlgWaveMatrixMultiplies.data(); + m_PSVInitInfo.LinAlgWaveMatrixMultiplyCount = + m_LinAlgWaveMatrixMultiplies.size(); + m_PSVInitInfo.LinAlgThreadGroupMatrixMultiplies = + m_LinAlgThreadGroupMatrixMultiplies.data(); + m_PSVInitInfo.LinAlgThreadGroupMatrixMultiplyCount = + m_LinAlgThreadGroupMatrixMultiplies.size(); + m_PSVInitInfo.LinAlgOuterProducts = m_LinAlgOuterProducts.data(); + m_PSVInitInfo.LinAlgOuterProductCount = m_LinAlgOuterProducts.size(); + m_PSVInitInfo.LinAlgAccumulateStores = m_LinAlgAccumulateStores.data(); + m_PSVInitInfo.LinAlgAccumulateStoreCount = m_LinAlgAccumulateStores.size(); + } + void SetPSVSigElement(PSVSignatureElement0 &E, const DxilSignatureElement &SE) { memset(&E, 0, sizeof(PSVSignatureElement0)); @@ -771,6 +1174,11 @@ class DxilPSVWriter : public DxilPartWriter { Name.size()); } + if (m_PSVInitInfo.PSVVersion > 3) { + LoadLinAlgMatrixInfos(); + CollectLinAlgRuntimeInfo(); + } + // Set String and SemanticInput Tables m_PSVInitInfo.StringTable.Table = m_StringBuffer.data(); m_PSVInitInfo.StringTable.Size = m_StringBuffer.size(); diff --git a/lib/DxilContainer/DxilPipelineStateValidation.cpp b/lib/DxilContainer/DxilPipelineStateValidation.cpp index 78be73c41d..d5e480b258 100644 --- a/lib/DxilContainer/DxilPipelineStateValidation.cpp +++ b/lib/DxilContainer/DxilPipelineStateValidation.cpp @@ -911,6 +911,13 @@ void hlsl::PrintPSVRuntimeInfo(llvm::raw_ostream &OS, PSVRuntimeInfo0 *pInfo0, } if (pInfo3) OS << Comment << " EntryFunctionName: " << EntryName << "\n"; + if (pInfo4) + OS << Comment << " LinAlgRuntimeInfoPresent: " + << ((pInfo4->Flags & static_cast( + PSVRuntimeInfo4Flag::LinAlgRuntimeInfoPresent)) + ? "true" + : "false") + << "\n"; } void DxilPipelineStateValidation::PrintPSVRuntimeInfo( @@ -986,6 +993,99 @@ void DxilPipelineStateValidation::Print(raw_ostream &OS, OS << "DxilPipelineStateValidation:\n"; PrintPSVRuntimeInfo(OS, ShaderKind, ""); + if (m_pPSVLinAlgRuntimeInfo0) { + OS << "PSVLinAlgRuntimeInfo:\n"; + OS << " MatrixOperationShapeCount: " + << m_pPSVLinAlgRuntimeInfo0->MatrixOperationShapeCount << "\n"; + OS << " MatrixConstructionCount: " + << m_pPSVLinAlgRuntimeInfo0->MatrixConstructionCount << "\n"; + OS << " ThreadMatrixVectorMultiplyCount: " + << m_pPSVLinAlgRuntimeInfo0->ThreadMatrixVectorMultiplyCount << "\n"; + OS << " WaveMatrixMultiplyCount: " + << m_pPSVLinAlgRuntimeInfo0->WaveMatrixMultiplyCount << "\n"; + OS << " ThreadGroupMatrixMultiplyCount: " + << m_pPSVLinAlgRuntimeInfo0->ThreadGroupMatrixMultiplyCount << "\n"; + OS << " OuterProductCount: " << m_pPSVLinAlgRuntimeInfo0->OuterProductCount + << "\n"; + OS << " AccumulateStoreCount: " + << m_pPSVLinAlgRuntimeInfo0->AccumulateStoreCount << "\n"; + + auto PrintShapes = [&](const PSVLinAlgMatrixShapeArrayReference &ShapeRef) { + OS << "["; + if (ShapeRef.ShapesIndex > m_SemanticIndexTable.Entries || + ShapeRef.Count > + m_SemanticIndexTable.Entries - ShapeRef.ShapesIndex) { + OS << "invalid]"; + return; + } + const uint32_t *Indexes = m_SemanticIndexTable.Get(ShapeRef.ShapesIndex); + for (uint32_t I = 0; I < ShapeRef.Count; ++I) { + if (I) + OS << ", "; + PSVLinAlgMatrixOperationShape0 *Shape = + Indexes ? GetPSVLinAlgMatrixOperationShape(Indexes[I]) : nullptr; + if (Shape) + OS << "(" << Shape->M << "," << Shape->N << "," << Shape->K << ")"; + else + OS << "invalid"; + } + OS << "]"; + }; + + for (uint32_t I = 0; I < GetPSVLinAlgMatrixConstructionCount(); ++I) { + auto *Record = GetPSVLinAlgMatrixConstruction(I); + OS << " MatrixConstruction[" << I + << "]: MatrixType=" << static_cast(Record->MatrixType) + << ", Shapes="; + PrintShapes(Record->OperationShapes); + OS << "\n"; + } + for (uint32_t I = 0; I < GetPSVLinAlgThreadMatrixVectorMultiplyCount(); + ++I) { + auto *Record = GetPSVLinAlgThreadMatrixVectorMultiply(I); + OS << " ThreadMatrixVectorMultiply[" << I + << "]: ResultType=" << static_cast(Record->ResultType) + << ", MatrixType=" << static_cast(Record->MatrixType) + << ", VectorInputType=" + << static_cast(Record->VectorInputType) + << ", Flags=" << static_cast(Record->Flags) << "\n"; + } + for (uint32_t I = 0; I < GetPSVLinAlgWaveMatrixMultiplyCount(); ++I) { + auto *Record = GetPSVLinAlgWaveMatrixMultiply(I); + OS << " WaveMatrixMultiply[" << I << "]: AccumulatorType=" + << static_cast(Record->AccumulatorType) + << ", MatrixAType=" << static_cast(Record->MatrixAType) + << ", MatrixBType=" << static_cast(Record->MatrixBType) + << ", Shapes="; + PrintShapes(Record->OperationShapes); + OS << "\n"; + } + for (uint32_t I = 0; I < GetPSVLinAlgThreadGroupMatrixMultiplyCount(); + ++I) { + auto *Record = GetPSVLinAlgThreadGroupMatrixMultiply(I); + OS << " ThreadGroupMatrixMultiply[" << I << "]: AccumulatorType=" + << static_cast(Record->AccumulatorType) + << ", MatrixAType=" << static_cast(Record->MatrixAType) + << ", MatrixBType=" << static_cast(Record->MatrixBType) + << ", Shapes="; + PrintShapes(Record->OperationShapes); + OS << "\n"; + } + for (uint32_t I = 0; I < GetPSVLinAlgOuterProductCount(); ++I) { + auto *Record = GetPSVLinAlgOuterProduct(I); + OS << " OuterProduct[" << I + << "]: ResultType=" << static_cast(Record->ResultType) + << ", VectorInputType=" + << static_cast(Record->VectorInputType) << "\n"; + } + for (uint32_t I = 0; I < GetPSVLinAlgAccumulateStoreCount(); ++I) { + auto *Record = GetPSVLinAlgAccumulateStore(I); + OS << " AccumulateStore[" << I << "]: AccumulatorType=" + << static_cast(Record->AccumulatorType) + << ", Flags=" << static_cast(Record->Flags) << "\n"; + } + } + OS << "ResourceCount : " << m_uResourceCount << "\n "; if (m_uResourceCount) { if (m_uPSVResourceBindInfoSize == sizeof(PSVResourceBindInfo0)) { diff --git a/lib/DxilPIXPasses/DxilDebugBreakInstrumentation.cpp b/lib/DxilPIXPasses/DxilDebugBreakInstrumentation.cpp index 30799c4bdc..8c90074d91 100644 --- a/lib/DxilPIXPasses/DxilDebugBreakInstrumentation.cpp +++ b/lib/DxilPIXPasses/DxilDebugBreakInstrumentation.cpp @@ -120,14 +120,13 @@ bool DxilDebugBreakInstrumentation::runOnModule(Module &M) { CI->eraseFromParent(); } - // Clean up the now-unused declaration. Not strictly required for - // correctness, but keeps the module free of dead references. - if (DebugBreakFunc->use_empty()) - DebugBreakFunc->eraseFromParent(); + const bool FoundDebugBreak = !DebugBreakCalls.empty(); - const bool modified = (PixUAVResource != nullptr); + bool Modified = FoundDebugBreak; + Modified |= PIXPassHelpers::eraseIfUnused(DM, DebugBreakFunc); + Modified |= PIXPassHelpers::eraseIfUnused(DM, AtomicOpFunc); - if (modified) { + if (FoundDebugBreak) { DM.ReEmitDxilResources(); if (OSOverride != nullptr) { @@ -136,7 +135,7 @@ bool DxilDebugBreakInstrumentation::runOnModule(Module &M) { } } - return modified; + return Modified; } char DxilDebugBreakInstrumentation::ID = 0; diff --git a/lib/DxilPIXPasses/DxilDebugInstrumentation.cpp b/lib/DxilPIXPasses/DxilDebugInstrumentation.cpp index 4dd43b07cc..a40acfe860 100644 --- a/lib/DxilPIXPasses/DxilDebugInstrumentation.cpp +++ b/lib/DxilPIXPasses/DxilDebugInstrumentation.cpp @@ -1436,23 +1436,6 @@ bool DxilDebugInstrumentation::RunOnFunction(Module &M, DxilModule &DM, auto &values = m_FunctionToValues[BC.Builder.GetInsertBlock()->getParent()]; - // PIX binds two UAVs when running this instrumentation: one for raygen - // shaders and another for the hitgroups and miss shaders. Since PIX invokes - // this pass at the library level, which may contain examples of both types, - // PIX can't really specify which UAV index to use per-shader. This pass - // therefore just has to know this: - constexpr unsigned int RayGenUAVRegister = 0; - constexpr unsigned int HitGroupAndMissUAVRegister = 1; - unsigned int UAVRegisterId = RayGenUAVRegister; - switch (shaderKind) { - case DXIL::ShaderKind::ClosestHit: - case DXIL::ShaderKind::Intersection: - case DXIL::ShaderKind::AnyHit: - case DXIL::ShaderKind::Miss: - UAVRegisterId = HitGroupAndMissUAVRegister; - break; - } - values.UAVHandle = PIXPassHelpers::CreateHandleForResource( DM, Builder, uav, "PIX_DebugUAV_Handle"); diff --git a/lib/DxilPIXPasses/DxilNonUniformResourceIndexInstrumentation.cpp b/lib/DxilPIXPasses/DxilNonUniformResourceIndexInstrumentation.cpp index a442bfabed..65be5e44b5 100644 --- a/lib/DxilPIXPasses/DxilNonUniformResourceIndexInstrumentation.cpp +++ b/lib/DxilPIXPasses/DxilNonUniformResourceIndexInstrumentation.cpp @@ -59,12 +59,16 @@ bool DxilNonUniformResourceIndexInstrumentation::runOnModule(Module &M) { std::map FunctionToUAVHandle; + // Set if any dynamically indexed handle lacks the PIX instruction ordinal + // this pass needs to address its diagnostic. + bool FoundHandleWithoutInstructionNumber = false; + // This is the main pass that will iterate through all of the resources that // are dynamically indexed. If not already marked NonUniformResourceIndex, // then insert WaveActiveAllEqual to determine if the index is uniform // and finally write to a UAV resource with the result. - PIXPassHelpers::ForEachDynamicallyIndexedResource( + bool modified = PIXPassHelpers::ForEachDynamicallyIndexedResource( DM, [&](bool IsNonUniformIndex, Instruction *CreateHandle, Value *IndexOperand) { if (IsNonUniformIndex) { @@ -72,6 +76,16 @@ bool DxilNonUniformResourceIndexInstrumentation::runOnModule(Module &M) { return true; } + // Address each diagnostic by the PIX instruction ordinal. Skip a + // handle that has no ordinal instead of writing a record for + // instruction 0. + uint32_t InstructionNumber = 0; + if (!pix_dxil::PixDxilInstNum::FromInst(CreateHandle, + &InstructionNumber)) { + FoundHandleWithoutInstructionNumber = true; + return true; + } + if (!PixUAVResource) { PixUAVResource = PIXPassHelpers::CreateGlobalUAVResource(DM, 0, "PixUAVResource"); @@ -97,12 +111,6 @@ bool DxilNonUniformResourceIndexInstrumentation::runOnModule(Module &M) { IRBuilder<> Builder(CreateHandle); - uint32_t InstructionNumber = 0; - if (!pix_dxil::PixDxilInstNum::FromInst(CreateHandle, - &InstructionNumber)) { - DXASSERT_NOMSG(false); - } - // The output UAV is treated as a bit array where each bit corresponds // to an instruction number. This determines what byte offset to write // our result to based on the instruction number. @@ -147,17 +155,25 @@ bool DxilNonUniformResourceIndexInstrumentation::runOnModule(Module &M) { return true; }); - const bool modified = (PixUAVResource != nullptr); + modified |= (PixUAVResource != nullptr); + modified |= PIXPassHelpers::eraseIfUnused(DM, WaveActiveAllEqualFunc); + modified |= PIXPassHelpers::eraseIfUnused(DM, AtomicOpFunc); if (modified) { + DM.CollectShaderFlagsForModule(); DM.ReEmitDxilResources(); - if (OSOverride != nullptr) { + if (OSOverride != nullptr && PixUAVResource != nullptr) { formatted_raw_ostream FOS(*OSOverride); FOS << "\nFoundDynamicIndexingNoNuri\n"; } } + if (FoundHandleWithoutInstructionNumber && OSOverride != nullptr) { + formatted_raw_ostream FOS(*OSOverride); + FOS << "\nNuriNotInstrumentedMissingInstructionNumber\n"; + } + return modified; } diff --git a/lib/DxilPIXPasses/DxilOutputColorBecomesConstant.cpp b/lib/DxilPIXPasses/DxilOutputColorBecomesConstant.cpp index a0749fbe0f..7ecb712ea2 100644 --- a/lib/DxilPIXPasses/DxilOutputColorBecomesConstant.cpp +++ b/lib/DxilPIXPasses/DxilOutputColorBecomesConstant.cpp @@ -125,7 +125,9 @@ bool DxilOutputColorBecomesConstant::runOnModule(Module &M) { [&hasIntOutputs](CallInst *) { hasIntOutputs = true; }); if (!hasFloatOutputs && !hasIntOutputs) { - return false; + bool Modified = PIXPassHelpers::eraseIfUnused(DM, FloatOutputFunction); + Modified |= PIXPassHelpers::eraseIfUnused(DM, IntOutputFunction); + return Modified; } // Otherwise, we assume the shader outputs only one or the other (because the @@ -251,6 +253,9 @@ bool DxilOutputColorBecomesConstant::runOnModule(Module &M) { }); } + Modified |= PIXPassHelpers::eraseIfUnused(DM, FloatOutputFunction); + Modified |= PIXPassHelpers::eraseIfUnused(DM, IntOutputFunction); + return Modified; } diff --git a/lib/DxilPIXPasses/DxilPIXAddTidToAmplificationShaderPayload.cpp b/lib/DxilPIXPasses/DxilPIXAddTidToAmplificationShaderPayload.cpp index e756e98781..10122f748f 100644 --- a/lib/DxilPIXPasses/DxilPIXAddTidToAmplificationShaderPayload.cpp +++ b/lib/DxilPIXPasses/DxilPIXAddTidToAmplificationShaderPayload.cpp @@ -183,8 +183,11 @@ bool DxilPIXAddTidToAmplificationShaderPayload::runOnModule(Module &M) { {DispatchMeshOpcode, DispatchMesh.get_threadGroupCountX(), DispatchMesh.get_threadGroupCountY(), DispatchMesh.get_threadGroupCountZ(), NewStructAlloca}); + llvm::Function *OriginalDispatchMeshFn = + cast(&*I)->getCalledFunction(); I->removeFromParent(); delete &*I; + PIXPassHelpers::eraseIfUnused(DM, OriginalDispatchMeshFn); // Validation requires exactly one DispatchMesh in an AS, so we can exit // after the first one: DM.ReEmitDxilResources(); diff --git a/lib/DxilPIXPasses/DxilPIXDXRInvocationsLog.cpp b/lib/DxilPIXPasses/DxilPIXDXRInvocationsLog.cpp index c9f553a4b6..f456029085 100644 --- a/lib/DxilPIXPasses/DxilPIXDXRInvocationsLog.cpp +++ b/lib/DxilPIXPasses/DxilPIXDXRInvocationsLog.cpp @@ -18,6 +18,7 @@ #include "llvm/IR/InstIterator.h" #include "llvm/IR/PassManager.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Local.h" #include "PixPassHelpers.h" @@ -85,13 +86,18 @@ bool DxilPIXDXRInvocationsLog::runOnModule(Module &M) { Modified = true; - IRBuilder<> Builder(dxilutil::FirstNonAllocaInsertionPt(entryFunction)); + Instruction *InsertionPoint = + dxilutil::FirstNonAllocaInsertionPt(entryFunction); + IRBuilder<> Builder(InsertionPoint); - // Add the UAVs that we're going to write to + // Add the counter UAV and, when there is space, the record UAV. CallInst *HandleForCountUAV = PIXPassHelpers::CreateUAVOnceForModule( DM, Builder, /* registerID */ 0, "PIX_CountUAV_Handle"); - CallInst *HandleForUAV = PIXPassHelpers::CreateUAVOnceForModule( - DM, Builder, /* registerID */ 1, "PIX_UAV_Handle"); + CallInst *HandleForUAV = nullptr; + if (m_MaxNumEntriesInLog != 0) { + HandleForUAV = PIXPassHelpers::CreateUAVOnceForModule( + DM, Builder, /* registerID */ 1, "PIX_UAV_Handle"); + } DM.ReEmitDxilResources(); @@ -163,22 +169,9 @@ bool DxilPIXDXRInvocationsLog::runOnModule(Module &M) { Constant *AtomicAdd = HlslOP->GetU32Const((unsigned)DXIL::AtomicBinOpCode::Add); - Function *UMinOpFunc = - HlslOP->GetOpFunc(OP::OpCode::UMin, Type::getInt32Ty(Ctx)); - Constant *UMinOpCode = HlslOP->GetU32Const((unsigned)OP::OpCode::UMin); - - Function *StoreFuncFloat = - HlslOP->GetOpFunc(OP::OpCode::BufferStore, Type::getFloatTy(Ctx)); - Function *StoreFuncInt = - HlslOP->GetOpFunc(OP::OpCode::BufferStore, Type::getInt32Ty(Ctx)); - Constant *StoreOpcode = - HlslOP->GetU32Const((unsigned)OP::OpCode::BufferStore); - - Constant *WriteMask_XYZW = HlslOP->GetI8Const(15); - Constant *WriteMask_X = HlslOP->GetI8Const(1); Constant *ShaderKindAsConstant = HlslOP->GetU32Const((uint32_t)ShaderKind); - Constant *MaxEntryIndexAsConstant = - HlslOP->GetU32Const((uint32_t)m_MaxNumEntriesInLog - 1u); + Constant *MaxEntryCountAsConstant = + HlslOP->GetU32Const((uint32_t)m_MaxNumEntriesInLog); Constant *Zero32Arg = HlslOP->GetU32Const(0); Constant *One32Arg = HlslOP->GetU32Const(1); UndefValue *UndefArg = UndefValue::get(Type::getInt32Ty(Ctx)); @@ -198,24 +191,40 @@ bool DxilPIXDXRInvocationsLog::runOnModule(Module &M) { }, "EntryIndexResult"); - // Clamp the index so that we don't write off the end of the UAV. If we - // clamp, then it's up to PIX to replay the work again with a larger log - // buffer. - auto *EntryIndexClamped = Builder.CreateCall( - UMinOpFunc, {UMinOpCode, EntryIndex, MaxEntryIndexAsConstant}); + if (m_MaxNumEntriesInLog == 0) { + continue; + } + + Function *StoreFuncFloat = + HlslOP->GetOpFunc(OP::OpCode::BufferStore, Type::getFloatTy(Ctx)); + Function *StoreFuncInt = + HlslOP->GetOpFunc(OP::OpCode::BufferStore, Type::getInt32Ty(Ctx)); + Constant *StoreOpcode = + HlslOP->GetU32Const((unsigned)OP::OpCode::BufferStore); + + Constant *WriteMask_XYZW = HlslOP->GetI8Const(15); + Constant *WriteMask_X = HlslOP->GetI8Const(1); + + // The counter keeps counting past the log capacity. Skip the stores once + // the claimed slot is out of range, so the recorded entries stay intact. + Value *EntryIndexIsInRange = Builder.CreateICmpULT( + EntryIndex, MaxEntryCountAsConstant, "EntryIndexIsInRange"); + TerminatorInst *StoreEntryBlockTerminator = + SplitBlockAndInsertIfThen(EntryIndexIsInRange, InsertionPoint, + /*Unreachable*/ false); + Builder.SetInsertPoint(StoreEntryBlockTerminator); const auto numBytesPerEntry = 4 + (3 * 4) + (3 * 4) + (3 * 4) + 4 + 4 + 4; // See number of bytes we store per shader invocation below - auto EntryOffset = - Builder.CreateMul(EntryIndexClamped, - HlslOP->GetU32Const(numBytesPerEntry), "EntryOffset"); - auto EntryOffsetPlus16 = Builder.CreateAdd( + Value *EntryOffset = Builder.CreateMul( + EntryIndex, HlslOP->GetU32Const(numBytesPerEntry), "EntryOffset"); + Value *EntryOffsetPlus16 = Builder.CreateAdd( EntryOffset, HlslOP->GetU32Const(16), "EntryOffsetPlus16"); - auto EntryOffsetPlus32 = Builder.CreateAdd( + Value *EntryOffsetPlus32 = Builder.CreateAdd( EntryOffset, HlslOP->GetU32Const(32), "EntryOffsetPlus32"); - auto EntryOffsetPlus48 = Builder.CreateAdd( + Value *EntryOffsetPlus48 = Builder.CreateAdd( EntryOffset, HlslOP->GetU32Const(48), "EntryOffsetPlus48"); // Then we start storing the invocation's info into the main UAV buffer diff --git a/lib/DxilPIXPasses/DxilPIXMeshShaderOutputInstrumentation.cpp b/lib/DxilPIXPasses/DxilPIXMeshShaderOutputInstrumentation.cpp index 507a718a4c..457912f65d 100644 --- a/lib/DxilPIXPasses/DxilPIXMeshShaderOutputInstrumentation.cpp +++ b/lib/DxilPIXPasses/DxilPIXMeshShaderOutputInstrumentation.cpp @@ -310,6 +310,8 @@ bool DxilPIXMeshShaderOutputInstrumentation::runOnModule(Module &M) { } if (getMeshPayloadInstructions != nullptr) { + llvm::Function *OriginalGetMeshPayloadFunction = + cast(getMeshPayloadInstructions)->getCalledFunction(); Function *DxilFunc = HlslOP->GetOpFunc( OP::OpCode::GetMeshPayload, expanded.ExpandedPayloadStructPtrType); @@ -326,6 +328,7 @@ bool DxilPIXMeshShaderOutputInstrumentation::runOnModule(Module &M) { ReplaceAllUsesOfInstructionWithNewValueAndDeleteInstruction( getMeshPayloadInstructions, payload, expanded.ExpandedPayloadStructType); + PIXPassHelpers::eraseIfUnused(DM, OriginalGetMeshPayloadFunction); } } @@ -352,8 +355,9 @@ bool DxilPIXMeshShaderOutputInstrumentation::runOnModule(Module &M) { FirstNewStructGetMeshPayload); } - auto F = HlslOP->GetOpFunc(DXIL::OpCode::EmitIndices, Type::getVoidTy(Ctx)); - auto FunctionUses = F->uses(); + Function *EmitIndicesFunction = + HlslOP->GetOpFunc(DXIL::OpCode::EmitIndices, Type::getVoidTy(Ctx)); + auto FunctionUses = EmitIndicesFunction->uses(); for (auto FI = FunctionUses.begin(); FI != FunctionUses.end();) { auto &FunctionUse = *FI++; auto FunctionUser = FunctionUse.getUser(); @@ -378,10 +382,13 @@ bool DxilPIXMeshShaderOutputInstrumentation::runOnModule(Module &M) { {Type::getInt16Ty(Ctx), int16ValueIndicator}, {Type::getFloatTy(Ctx), floatValueIndicator}, {Type::getHalfTy(Ctx), float16ValueIndicator}}; + SmallVector StoreVertexOutputFunctions; for (auto const &Overload : StoreVertexOutputOverloads) { - F = HlslOP->GetOpFunc(DXIL::OpCode::StoreVertexOutput, Overload.type); - FunctionUses = F->uses(); + Function *StoreVertexOutputFunction = + HlslOP->GetOpFunc(DXIL::OpCode::StoreVertexOutput, Overload.type); + StoreVertexOutputFunctions.push_back(StoreVertexOutputFunction); + FunctionUses = StoreVertexOutputFunction->uses(); for (auto FI = FunctionUses.begin(); FI != FunctionUses.end();) { auto &FunctionUse = *FI++; auto FunctionUser = FunctionUse.getUser(); @@ -419,6 +426,11 @@ bool DxilPIXMeshShaderOutputInstrumentation::runOnModule(Module &M) { } } + for (Function *StoreVertexOutputFunction : StoreVertexOutputFunctions) { + PIXPassHelpers::eraseIfUnused(DM, StoreVertexOutputFunction); + } + PIXPassHelpers::eraseIfUnused(DM, EmitIndicesFunction); + DM.ReEmitDxilResources(); return true; diff --git a/lib/DxilPIXPasses/DxilRemoveDiscards.cpp b/lib/DxilPIXPasses/DxilRemoveDiscards.cpp index 5f8d9263f0..90db175e57 100644 --- a/lib/DxilPIXPasses/DxilRemoveDiscards.cpp +++ b/lib/DxilPIXPasses/DxilRemoveDiscards.cpp @@ -17,6 +17,8 @@ #include "llvm/IR/Instructions.h" #include "llvm/IR/PassManager.h" +#include "PixPassHelpers.h" + using namespace llvm; using namespace hlsl; @@ -53,6 +55,8 @@ bool DxilRemoveDiscards::runOnModule(Module &M) { Modified = true; } + Modified |= PIXPassHelpers::eraseIfUnused(DM, DiscardFunction); + return Modified; } diff --git a/lib/DxilPIXPasses/DxilShaderAccessTracking.cpp b/lib/DxilPIXPasses/DxilShaderAccessTracking.cpp index 1dddb6c0e6..ed1d1b26cc 100644 --- a/lib/DxilPIXPasses/DxilShaderAccessTracking.cpp +++ b/lib/DxilPIXPasses/DxilShaderAccessTracking.cpp @@ -808,7 +808,7 @@ bool DxilShaderAccessTracking::runOnModule(Module &M) { bool FoundDynamicIndexing = false; - PIXPassHelpers::ForEachDynamicallyIndexedResource( + Modified |= PIXPassHelpers::ForEachDynamicallyIndexedResource( DM, [&FoundDynamicIndexing](bool, Instruction *, Value *) { FoundDynamicIndexing = true; return false; diff --git a/lib/DxilPIXPasses/PixPassHelpers.cpp b/lib/DxilPIXPasses/PixPassHelpers.cpp index c7c99cf763..472cf77e79 100644 --- a/lib/DxilPIXPasses/PixPassHelpers.cpp +++ b/lib/DxilPIXPasses/PixPassHelpers.cpp @@ -26,6 +26,7 @@ #include "dxc/Support/Global.h" #include "dxc/Support/WinIncludes.h" #include "dxc/dxcapi.h" +#include #ifdef PIX_DEBUG_DUMP_HELPER #include "llvm/IR/DebugInfo.h" @@ -185,6 +186,8 @@ static std::vector SerializeRootSignatureToVector( SerializeRootSignature(rootSignature, &serializedRootSignature, &errorBlob, allowReservedRegisterSpace); std::vector ret; + if (serializedRootSignature == nullptr) + return ret; auto const *serializedData = reinterpret_cast( serializedRootSignature->GetBufferPointer()); ret.assign(serializedData, @@ -194,69 +197,83 @@ static std::vector SerializeRootSignatureToVector( } constexpr uint32_t toolsRegisterSpace = static_cast(-2); -constexpr uint32_t toolsUAVRegister = 0; +// Returns whether a parameter was appended. template -void ExtendRootSig(RootSigDesc &rootSigDesc) { - auto *existingParams = rootSigDesc.pParameters; - for (uint32_t i = 0; i < rootSigDesc.NumParameters; ++i) { - if (rootSigDesc.pParameters[i].ParameterType == +bool ExtendRootSig(RootSigDesc &RootSignatureDesc, uint32_t ToolsUAVRegister) { + auto *existingParams = RootSignatureDesc.pParameters; + for (uint32_t i = 0; i < RootSignatureDesc.NumParameters; ++i) { + if (RootSignatureDesc.pParameters[i].ParameterType == DxilRootParameterType::UAV) { - if (rootSigDesc.pParameters[i].Descriptor.RegisterSpace == + if (RootSignatureDesc.pParameters[i].Descriptor.RegisterSpace == toolsRegisterSpace && - rootSigDesc.pParameters[i].Descriptor.ShaderRegister == - toolsUAVRegister) { + RootSignatureDesc.pParameters[i].Descriptor.ShaderRegister == + ToolsUAVRegister) { // Already added - return; + return false; } } } - auto *newParams = new RootParameterDesc[rootSigDesc.NumParameters + 1]; + auto *newParams = new RootParameterDesc[RootSignatureDesc.NumParameters + 1]; if (existingParams != nullptr) { memcpy(newParams, existingParams, - rootSigDesc.NumParameters * sizeof(RootParameterDesc)); + RootSignatureDesc.NumParameters * sizeof(RootParameterDesc)); delete[] existingParams; } - rootSigDesc.pParameters = newParams; - rootSigDesc.pParameters[rootSigDesc.NumParameters].ParameterType = + RootSignatureDesc.pParameters = newParams; + RootSignatureDesc.pParameters[RootSignatureDesc.NumParameters].ParameterType = DxilRootParameterType::UAV; - rootSigDesc.pParameters[rootSigDesc.NumParameters].Descriptor.RegisterSpace = - toolsRegisterSpace; - rootSigDesc.pParameters[rootSigDesc.NumParameters].Descriptor.ShaderRegister = - toolsUAVRegister; - rootSigDesc.pParameters[rootSigDesc.NumParameters].ShaderVisibility = - DxilShaderVisibility::All; - rootSigDesc.NumParameters++; + RootSignatureDesc.pParameters[RootSignatureDesc.NumParameters] + .Descriptor.RegisterSpace = toolsRegisterSpace; + RootSignatureDesc.pParameters[RootSignatureDesc.NumParameters] + .Descriptor.ShaderRegister = ToolsUAVRegister; + RootSignatureDesc.pParameters[RootSignatureDesc.NumParameters] + .ShaderVisibility = DxilShaderVisibility::All; + RootSignatureDesc.NumParameters++; + return true; } -static std::vector AddUAVParamterToRootSignature(const void *Data, - uint32_t Size) { +static std::vector +AddUAVParameterToRootSignature(const void *Data, uint32_t Size, + uint32_t ToolsUAVRegister) { DxilVersionedRootSignature rootSignature; DeserializeRootSignature(Data, Size, rootSignature.get_address_of()); auto *rs = rootSignature.get_mutable(); switch (rootSignature->Version) { case DxilRootSignatureVersion::Version_1_0: - ExtendRootSig(rs->Desc_1_0); + ExtendRootSig(rs->Desc_1_0, + ToolsUAVRegister); break; case DxilRootSignatureVersion::Version_1_1: - ExtendRootSig(rs->Desc_1_1); - rs->Desc_1_1.pParameters[rs->Desc_1_1.NumParameters - 1].Descriptor.Flags = - hlsl::DxilRootDescriptorFlags::None; + if (ExtendRootSig( + rs->Desc_1_1, ToolsUAVRegister)) + rs->Desc_1_1.pParameters[rs->Desc_1_1.NumParameters - 1] + .Descriptor.Flags = hlsl::DxilRootDescriptorFlags::None; break; } return SerializeRootSignatureToVector(rs); } -static void AddUAVToShaderAttributeRootSignature(DxilModule &DM) { +static void AddUAVToShaderAttributeRootSignature(DxilModule &DM, + uint32_t ToolsUAVRegister) { auto rs = DM.GetSerializedRootSignature(); if (!rs.empty()) { - std::vector asVector = AddUAVParamterToRootSignature( - rs.data(), static_cast(rs.size())); - DM.ResetSerializedRootSignature(asVector); + std::vector asVector = AddUAVParameterToRootSignature( + rs.data(), static_cast(rs.size()), ToolsUAVRegister); + if (!asVector.empty()) + DM.ResetSerializedRootSignature(asVector); } } -static void AddUAVToDxilDefinedGlobalRootSignatures(DxilModule &DM) { +static void AddUAVToDxilDefinedGlobalRootSignatures(DxilModule &DM, + uint32_t ToolsUAVRegister) { + struct ReplacementRootSignature { + std::string Name; + std::vector Data; + std::optional Text; + }; + + std::vector ReplacementRootSignatures; auto *subObjects = DM.GetSubobjects(); if (subObjects != nullptr) { for (auto const &subObject : subObjects->GetSubobjects()) { @@ -264,19 +281,36 @@ static void AddUAVToDxilDefinedGlobalRootSignatures(DxilModule &DM) { DXIL::SubobjectKind::GlobalRootSignature) { const void *Data = nullptr; uint32_t Size = 0; + const char *Text = nullptr; constexpr bool notALocalRS = false; if (subObject.second->GetRootSignature(notALocalRS, Data, Size, - nullptr)) { - auto extendedRootSig = AddUAVParamterToRootSignature(Data, Size); - auto rootSignatureSubObjectName = subObject.first; - subObjects->RemoveSubobject(rootSignatureSubObjectName); - subObjects->CreateRootSignature( - rootSignatureSubObjectName, notALocalRS, extendedRootSig.data(), - static_cast(extendedRootSig.size())); - break; + &Text)) { + std::vector ExtendedRootSignature = + AddUAVParameterToRootSignature(Data, Size, ToolsUAVRegister); + if (!ExtendedRootSignature.empty()) { + std::optional OwnedText; + if (Text != nullptr) + OwnedText = Text; + ReplacementRootSignatures.push_back( + {subObject.first.str(), std::move(ExtendedRootSignature), + std::move(OwnedText)}); + } } } } + + constexpr bool NotALocalRootSignature = false; + for (const ReplacementRootSignature &Replacement : + ReplacementRootSignatures) { + subObjects->RemoveSubobject(Replacement.Name); + std::optional TextRef; + if (Replacement.Text) + TextRef.emplace(*Replacement.Text); + subObjects->CreateRootSignature( + Replacement.Name, NotALocalRootSignature, Replacement.Data.data(), + static_cast(Replacement.Data.size()), + TextRef ? &*TextRef : nullptr); + } } } @@ -286,6 +320,12 @@ hlsl::DxilResource *CreateGlobalUAVResource(hlsl::DxilModule &DM, const char *name) { LLVMContext &Ctx = DM.GetModule()->getContext(); + for (const std::unique_ptr &ExistingUAV : DM.GetUAVs()) { + if (ExistingUAV->GetSpaceID() == toolsRegisterSpace && + ExistingUAV->GetLowerBound() == hlslBindIndex) + return ExistingUAV.get(); + } + const char *PIXStructTypeName = ShaderModelHandleTypeName(DM); llvm::StructType *UAVStructTy = DM.GetModule()->getTypeByName(PIXStructTypeName); @@ -295,10 +335,8 @@ hlsl::DxilResource *CreateGlobalUAVResource(hlsl::DxilModule &DM, UAVStructTy = llvm::StructType::create(Elements, PIXStructTypeName); } - // Since this function should only be called once per module, - // we can modify the root sig at the same time: - AddUAVToDxilDefinedGlobalRootSignatures(DM); - AddUAVToShaderAttributeRootSignature(DM); + AddUAVToDxilDefinedGlobalRootSignatures(DM, hlslBindIndex); + AddUAVToShaderAttributeRootSignature(DM, hlslBindIndex); unsigned int Id = static_cast(DM.GetUAVs().size()); std::unique_ptr pUAV = llvm::make_unique(); @@ -320,8 +358,7 @@ hlsl::DxilResource *CreateGlobalUAVResource(hlsl::DxilModule &DM, } pUAV->SetGlobalName(name); pUAV->SetRW(true); // sets UAV class - pUAV->SetSpaceID( - (unsigned int)-2); // This is the reserved-for-tools register space + pUAV->SetSpaceID(toolsRegisterSpace); // reserved-for-tools register space pUAV->SetSampleCount(0); // This is what compiler generates for a raw UAV pUAV->SetGloballyCoherent(false); pUAV->SetReorderCoherent(false); @@ -351,9 +388,19 @@ hlsl::DxilResource *CreateGlobalUAVResource(hlsl::DxilModule &DM, auto *ret = pUAV.get(); DM.AddUAV(std::move(pUAV)); + DM.CollectShaderFlagsForModule(); return ret; } +bool eraseIfUnused(hlsl::DxilModule &DM, llvm::Function *OpFunction) { + if (OpFunction != nullptr && OpFunction->user_empty()) { + DM.GetOP()->RemoveFunction(OpFunction); + OpFunction->eraseFromParent(); + return true; + } + return false; +} + // Set up a UAV with structure of a single int llvm::CallInst *CreateUAVOnceForModule(hlsl::DxilModule &DM, llvm::IRBuilder<> &Builder, @@ -401,18 +448,6 @@ hlsl::DXIL::ShaderKind GetFunctionShaderKind(hlsl::DxilModule &DM, return shaderKind; } -std::vector GetAllBlocks(hlsl::DxilModule &DM) { - std::vector ret; - auto entryPoints = DM.GetExportedFunctions(); - for (auto &fn : entryPoints) { - auto &blocks = fn->getBasicBlockList(); - for (auto &block : blocks) { - ret.push_back(&block); - } - } - return ret; -} - ExpandedStruct ExpandStructType(LLVMContext &Ctx, Type *OriginalPayloadStructType) { SmallVector Elements; @@ -513,7 +548,7 @@ unsigned int FindOrAddSV_Position(hlsl::DxilModule &DM, } } -void ForEachDynamicallyIndexedResource( +bool ForEachDynamicallyIndexedResource( hlsl::DxilModule &DM, const std::function &Visitor) { OP *HlslOP = DM.GetOP(); @@ -535,7 +570,7 @@ void ForEachDynamicallyIndexedResource( if (auto *gep = dyn_cast(resOrGep)) { if (!Visitor(DxilMDHelper::IsMarkedNonUniform(gep), load, gep->getOperand(2))) { - return; + return false; } } } @@ -547,6 +582,18 @@ void ForEachDynamicallyIndexedResource( auto CreateHandleFn = HlslOP->GetOpFunc(DXIL::OpCode::CreateHandle, Type::getVoidTy(Ctx)); + llvm::Function *CreateHandleFromBindingFn = HlslOP->GetOpFunc( + DXIL::OpCode::CreateHandleFromBinding, Type::getVoidTy(Ctx)); + llvm::Function *CreateHandleFromHeapFn = HlslOP->GetOpFunc( + DXIL::OpCode::CreateHandleFromHeap, Type::getVoidTy(Ctx)); + + auto CleanupUnusedDeclarations = [&]() { + bool Modified = eraseIfUnused(DM, CreateHandleFn); + Modified |= eraseIfUnused(DM, CreateHandleFromBindingFn); + Modified |= eraseIfUnused(DM, CreateHandleFromHeapFn); + return Modified; + }; + for (auto FI = CreateHandleFn->user_begin(); FI != CreateHandleFn->user_end();) { auto *FunctionUser = *FI++; @@ -557,13 +604,11 @@ void ForEachDynamicallyIndexedResource( const DxilInst_CreateHandle createHandle(instruction); if (!Visitor(createHandle.get_nonUniformIndex_val(), instruction, index)) { - return; + return CleanupUnusedDeclarations(); } } } - auto CreateHandleFromBindingFn = HlslOP->GetOpFunc( - DXIL::OpCode::CreateHandleFromBinding, Type::getVoidTy(Ctx)); for (auto FI = CreateHandleFromBindingFn->user_begin(); FI != CreateHandleFromBindingFn->user_end();) { auto *FunctionUser = *FI++; @@ -574,13 +619,11 @@ void ForEachDynamicallyIndexedResource( const DxilInst_CreateHandleFromBinding createHandle(instruction); if (!Visitor(createHandle.get_nonUniformIndex_val(), instruction, index)) { - return; + return CleanupUnusedDeclarations(); } } } - auto CreateHandleFromHeapFn = HlslOP->GetOpFunc( - DXIL::OpCode::CreateHandleFromHeap, Type::getVoidTy(Ctx)); for (auto FI = CreateHandleFromHeapFn->user_begin(); FI != CreateHandleFromHeapFn->user_end();) { auto *FunctionUser = *FI++; @@ -591,10 +634,11 @@ void ForEachDynamicallyIndexedResource( const DxilInst_CreateHandleFromHeap createHandle(instruction); if (!Visitor(createHandle.get_nonUniformIndex_val(), instruction, index)) { - return; + return CleanupUnusedDeclarations(); } } } + return CleanupUnusedDeclarations(); } #ifdef PIX_DEBUG_DUMP_HELPER diff --git a/lib/DxilPIXPasses/PixPassHelpers.h b/lib/DxilPIXPasses/PixPassHelpers.h index d7b0b40af8..7dc13e1b7e 100644 --- a/lib/DxilPIXPasses/PixPassHelpers.h +++ b/lib/DxilPIXPasses/PixPassHelpers.h @@ -48,7 +48,7 @@ llvm::CallInst *CreateHandleForResource(hlsl::DxilModule &DM, hlsl::DxilResourceBase *resource, const char *name); llvm::Function *GetEntryFunction(hlsl::DxilModule &DM); -std::vector GetAllBlocks(hlsl::DxilModule &DM); +bool eraseIfUnused(hlsl::DxilModule &DM, llvm::Function *OpFunction); std::vector GetAllInstrumentableFunctions(hlsl::DxilModule &DM); hlsl::DXIL::ShaderKind GetFunctionShaderKind(hlsl::DxilModule &DM, @@ -83,7 +83,7 @@ void ReplaceAllUsesOfInstructionWithNewValueAndDeleteInstruction( llvm::Instruction *Instr, llvm::Value *newValue, llvm::Type *newType); unsigned int FindOrAddSV_Position(hlsl::DxilModule &DM, unsigned UpStreamSVPosRow); -void ForEachDynamicallyIndexedResource( +bool ForEachDynamicallyIndexedResource( hlsl::DxilModule &DM, const std::function &Visitor); diff --git a/lib/DxilValidation/DxilContainerValidation.cpp b/lib/DxilValidation/DxilContainerValidation.cpp index a138de6d6b..e58a3e2069 100644 --- a/lib/DxilValidation/DxilContainerValidation.cpp +++ b/lib/DxilValidation/DxilContainerValidation.cpp @@ -137,7 +137,7 @@ class SemanticIndexTableVerifier { return false; if (Offset > Table.Entries) return false; - if ((Offset + Size) > Table.Entries) + if (Size > Table.Entries - Offset) return false; for (unsigned i = Offset; i < (Offset + Size); ++i) { UseMask[i] = true; @@ -180,6 +180,7 @@ class PSVContentVerifier { PSVSignatureElement0 *, const PSVStringTable &, const PSVSemanticIndexTable &, std::string, bool); void VerifyResources(unsigned PSVVersion); + void VerifyLinAlgRuntimeInfo(unsigned PSVVersion); template void VerifyResourceTable(T &ResTab, unsigned &ResourceIndex, unsigned PSVVersion); @@ -465,6 +466,190 @@ void PSVContentVerifier::VerifyEntryProperties( } } +void PSVContentVerifier::VerifyLinAlgRuntimeInfo(unsigned PSVVersion) { + // Regenerate the expected runtime info to compare the container + // contents against + unique_ptr pWriter(NewPSVWriter(DM, PSVVersion)); + CComPtr pOutputStream; + IFT(CreateMemoryStream(DxcGetThreadMallocNoRef(), &pOutputStream)); + pOutputStream->Reserve(pWriter->size()); + pWriter->write(pOutputStream); + + DxilPipelineStateValidation ExpectedPSV; + if (!ExpectedPSV.InitFromPSV0(pOutputStream->GetPtr(), + pOutputStream->GetPtrSize())) { + ValCtx.EmitFormatError( + ValidationRule::ContainerPartMatches, + {"Pipeline State Validation generated from DxilModule"}); + return; + } + + bool HasLinAlgRuntimeInfo = PSV.GetPSVLinAlgRuntimeInfo0() != nullptr; + bool ExpectedHasLinAlgRuntimeInfo = + ExpectedPSV.GetPSVLinAlgRuntimeInfo0() != nullptr; + if (HasLinAlgRuntimeInfo != ExpectedHasLinAlgRuntimeInfo) { + EmitMismatchError("LinAlgRuntimeInfoPresent", + HasLinAlgRuntimeInfo ? "true" : "false", + ExpectedHasLinAlgRuntimeInfo ? "true" : "false"); + return; + } + + if (!HasLinAlgRuntimeInfo) + return; + + auto VerifyShapeReference = + [&](StringRef Name, const PSVLinAlgMatrixShapeArrayReference &ShapeRef, + const PSVLinAlgMatrixShapeArrayReference *ExpectedShapeRef) { + if (!IndexTableVerifier.MarkUse(ShapeRef.ShapesIndex, ShapeRef.Count)) { + EmitInvalidError("LinAlgOperationShapes"); + return; + } + const uint32_t *ShapeIndexes = + PSV.GetSemanticIndexTable().Get(ShapeRef.ShapesIndex); + for (uint32_t I = 0; I < ShapeRef.Count; ++I) { + if (!PSV.GetPSVLinAlgMatrixOperationShape(ShapeIndexes[I])) { + EmitInvalidError("LinAlgOperationShapeIndex"); + return; + } + } + + if (!ExpectedShapeRef) + return; + if (ShapeRef.Count != ExpectedShapeRef->Count) { + EmitMismatchError((Name + "Count").str(), + std::to_string(ShapeRef.Count), + std::to_string(ExpectedShapeRef->Count)); + return; + } + if (ShapeRef.Count == 0) + return; + + const PSVSemanticIndexTable &ExpectedIndexTable = + ExpectedPSV.GetSemanticIndexTable(); + if (ExpectedIndexTable.Table == nullptr || + ExpectedShapeRef->ShapesIndex > ExpectedIndexTable.Entries || + ExpectedShapeRef->Count > + ExpectedIndexTable.Entries - ExpectedShapeRef->ShapesIndex) { + EmitMismatchError( + Name, "valid shape index sequence", + "invalid shape index sequence generated from DxilModule"); + return; + } + + const uint32_t *ExpectedShapeIndexes = + ExpectedIndexTable.Get(ExpectedShapeRef->ShapesIndex); + if (!std::equal(ShapeIndexes, ShapeIndexes + ShapeRef.Count, + ExpectedShapeIndexes)) + EmitMismatchError(Name, "shape index sequence", + "shape index sequence generated from DxilModule"); + }; + + auto GetRecordName = [](StringRef Name, uint32_t I) { + return Name.str() + "[" + std::to_string(I) + "]"; + }; + + auto GetRecordBytes = [](const auto &Record) { + static constexpr char HexDigits[] = "0123456789abcdef"; + const uint8_t *Bytes = reinterpret_cast(&Record); + std::string Result; + Result.reserve(sizeof(Record) * 3 - 1); + for (size_t I = 0; I < sizeof(Record); ++I) { + if (I != 0) + Result.push_back(' '); + Result.push_back(HexDigits[Bytes[I] >> 4]); + Result.push_back(HexDigits[Bytes[I] & 0xf]); + } + return Result; + }; + + auto VerifyRecord = [&](StringRef Name, uint32_t I, const auto &Record, + const auto *ExpectedRecord) { + if (ExpectedRecord && memcmp(&Record, ExpectedRecord, sizeof(Record)) != 0) + EmitMismatchError(GetRecordName(Name, I), GetRecordBytes(Record), + GetRecordBytes(*ExpectedRecord)); + }; + + auto VerifyRecordWithShapes = [&](StringRef Name, uint32_t I, + const auto &Record, + const auto *ExpectedRecord) { + if (ExpectedRecord) { + auto ComparableRecord = Record; + auto ComparableExpectedRecord = *ExpectedRecord; + ComparableRecord.OperationShapes = {}; + ComparableExpectedRecord.OperationShapes = {}; + if (memcmp(&ComparableRecord, &ComparableExpectedRecord, + sizeof(ComparableRecord)) != 0) + EmitMismatchError(GetRecordName(Name, I), + GetRecordBytes(ComparableRecord), + GetRecordBytes(ComparableExpectedRecord)); + } + + std::string ShapeName = Name.str() + "OperationShapes"; + VerifyShapeReference(ShapeName, Record.OperationShapes, + ExpectedRecord ? &ExpectedRecord->OperationShapes + : nullptr); + }; + + auto VerifyLinAlgTable = [&](StringRef Name, auto CountMethod, auto GetMethod, + auto VerifyTableRecord) { + uint32_t Count = (PSV.*CountMethod)(); + uint32_t ExpectedCount = (ExpectedPSV.*CountMethod)(); + if (Count != ExpectedCount) + EmitMismatchError(Name.str() + "Count", std::to_string(Count), + std::to_string(ExpectedCount)); + + for (uint32_t I = 0; I < Count; ++I) { + const auto *Record = (PSV.*GetMethod)(I); + const auto *ExpectedRecord = + I < ExpectedCount ? (ExpectedPSV.*GetMethod)(I) : nullptr; + if (!Record) { + EmitMismatchError(GetRecordName(Name, I), "missing record", + ExpectedRecord ? GetRecordBytes(*ExpectedRecord) + : "record generated from DxilModule"); + continue; + } + if (I < ExpectedCount && !ExpectedRecord) + EmitMismatchError(GetRecordName(Name, I), GetRecordBytes(*Record), + "missing record generated from DxilModule"); + VerifyTableRecord(Name, I, *Record, ExpectedRecord); + } + }; + + VerifyLinAlgTable( + "LinAlgMatrixOperationShape", + &DxilPipelineStateValidation::GetPSVLinAlgMatrixOperationShapeCount, + &DxilPipelineStateValidation::GetPSVLinAlgMatrixOperationShape, + VerifyRecord); + VerifyLinAlgTable( + "LinAlgMatrixConstruction", + &DxilPipelineStateValidation::GetPSVLinAlgMatrixConstructionCount, + &DxilPipelineStateValidation::GetPSVLinAlgMatrixConstruction, + VerifyRecordWithShapes); + VerifyLinAlgTable( + "LinAlgThreadMatrixVectorMultiply", + &DxilPipelineStateValidation::GetPSVLinAlgThreadMatrixVectorMultiplyCount, + &DxilPipelineStateValidation::GetPSVLinAlgThreadMatrixVectorMultiply, + VerifyRecord); + VerifyLinAlgTable( + "LinAlgWaveMatrixMultiply", + &DxilPipelineStateValidation::GetPSVLinAlgWaveMatrixMultiplyCount, + &DxilPipelineStateValidation::GetPSVLinAlgWaveMatrixMultiply, + VerifyRecordWithShapes); + VerifyLinAlgTable( + "LinAlgThreadGroupMatrixMultiply", + &DxilPipelineStateValidation::GetPSVLinAlgThreadGroupMatrixMultiplyCount, + &DxilPipelineStateValidation::GetPSVLinAlgThreadGroupMatrixMultiply, + VerifyRecordWithShapes); + VerifyLinAlgTable("LinAlgOuterProduct", + &DxilPipelineStateValidation::GetPSVLinAlgOuterProductCount, + &DxilPipelineStateValidation::GetPSVLinAlgOuterProduct, + VerifyRecord); + VerifyLinAlgTable( + "LinAlgAccumulateStore", + &DxilPipelineStateValidation::GetPSVLinAlgAccumulateStoreCount, + &DxilPipelineStateValidation::GetPSVLinAlgAccumulateStore, VerifyRecord); +} + void PSVContentVerifier::Verify(unsigned ValMajor, unsigned ValMinor, unsigned PSVVersion) { PSVInitInfo PSVInfo(PSVVersion); @@ -521,6 +706,8 @@ void PSVContentVerifier::Verify(unsigned ValMajor, unsigned ValMinor, DM.GetEntryFunctionName()); } } + if (PSVVersion > 3) + VerifyLinAlgRuntimeInfo(PSVVersion); StrTableVerifier.Verify(ValCtx); IndexTableVerifier.Verify(ValCtx); @@ -607,6 +794,8 @@ bool VerifySignatureMatches(llvm::Module *pModule, DXIL::SignatureKind SigKind, } struct SimplePSV { + static bool IsDwordAligned(uint32_t Size) { return (Size & 3) == 0; } + uint32_t PSVRuntimeInfoSize = 0; uint32_t PSVNumResources = 0; uint32_t PSVResourceBindInfoSize = 0; @@ -616,6 +805,7 @@ struct SimplePSV { const uint32_t *SemanticIndexTable = nullptr; uint32_t PSVSignatureElementSize = 0; const PSVRuntimeInfo1 *RuntimeInfo1 = nullptr; + const PSVRuntimeInfo4 *RuntimeInfo4 = nullptr; bool IsValid = true; SimplePSV(const void *pPSVData, uint32_t PSVSize) { @@ -632,6 +822,9 @@ struct SimplePSV { if (PSVRuntimeInfoSize >= sizeof(PSVRuntimeInfo1)) RuntimeInfo1 = (const PSVRuntimeInfo1 *)(GetPtrAtOffset(pPSVData, Offset)); + if (PSVRuntimeInfoSize >= sizeof(PSVRuntimeInfo4)) + RuntimeInfo4 = + (const PSVRuntimeInfo4 *)(GetPtrAtOffset(pPSVData, Offset)); INCREMENT_POS(PSVRuntimeInfoSize); PSVNumResources = GetUint32AtOffset(pPSVData, Offset); @@ -647,7 +840,7 @@ struct SimplePSV { StringTableSize = GetUint32AtOffset(pPSVData, Offset); INCREMENT_POS(4); // Make sure StringTableSize is aligned to 4 bytes. - if ((StringTableSize & 3) != 0) { + if (!IsDwordAligned(StringTableSize)) { IsValid = false; return; } @@ -723,6 +916,60 @@ struct SimplePSV { INCREMENT_POS(TableSizeInBytes); } } + + if (RuntimeInfo4 && (RuntimeInfo4->Flags & + static_cast( + PSVRuntimeInfo4Flag::LinAlgRuntimeInfoPresent))) { + auto ReadUint32 = [&](uint32_t &Value) { + if (Offset > PSVSize || sizeof(uint32_t) > PSVSize - Offset) + return false; + memcpy(&Value, GetPtrAtOffset(pPSVData, Offset), sizeof(uint32_t)); + Offset += sizeof(uint32_t); + return true; + }; + auto ConsumeTable = [&](uint32_t Count, uint32_t MinimumRecordSize) { + if (!Count) + return true; + uint32_t RecordSize = 0; + if (!ReadUint32(RecordSize) || !IsDwordAligned(RecordSize) || + RecordSize < MinimumRecordSize) + return false; + if (Offset > PSVSize || Count > (PSVSize - Offset) / RecordSize) + return false; + Offset += Count * RecordSize; + return true; + }; + + uint32_t LinAlgRuntimeInfoSize = 0; + if (!ReadUint32(LinAlgRuntimeInfoSize) || + !IsDwordAligned(LinAlgRuntimeInfoSize) || + LinAlgRuntimeInfoSize < sizeof(PSVLinAlgRuntimeInfo0) || + Offset > PSVSize || LinAlgRuntimeInfoSize > PSVSize - Offset) { + IsValid = false; + return; + } + const PSVLinAlgRuntimeInfo0 *LinAlgRuntimeInfo = + (const PSVLinAlgRuntimeInfo0 *)GetPtrAtOffset(pPSVData, Offset); + Offset += LinAlgRuntimeInfoSize; + + if (!ConsumeTable(LinAlgRuntimeInfo->MatrixOperationShapeCount, + sizeof(PSVLinAlgMatrixOperationShape0)) || + !ConsumeTable(LinAlgRuntimeInfo->MatrixConstructionCount, + sizeof(PSVLinAlgMatrixConstruction0)) || + !ConsumeTable(LinAlgRuntimeInfo->ThreadMatrixVectorMultiplyCount, + sizeof(PSVLinAlgThreadMatrixVectorMultiply0)) || + !ConsumeTable(LinAlgRuntimeInfo->WaveMatrixMultiplyCount, + sizeof(PSVLinAlgWaveMatrixMultiply0)) || + !ConsumeTable(LinAlgRuntimeInfo->ThreadGroupMatrixMultiplyCount, + sizeof(PSVLinAlgThreadGroupMatrixMultiply0)) || + !ConsumeTable(LinAlgRuntimeInfo->OuterProductCount, + sizeof(PSVLinAlgOuterProduct0)) || + !ConsumeTable(LinAlgRuntimeInfo->AccumulateStoreCount, + sizeof(PSVLinAlgAccumulateStore0))) { + IsValid = false; + return; + } + } IsValid = PSVSize == Offset; #undef INCREMENT_POS } diff --git a/lib/DxilValidation/DxilValidation.cpp b/lib/DxilValidation/DxilValidation.cpp index 49900bef13..c8b1145733 100644 --- a/lib/DxilValidation/DxilValidation.cpp +++ b/lib/DxilValidation/DxilValidation.cpp @@ -35,6 +35,7 @@ #include "llvm/Analysis/ValueTracking.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/Dominators.h" @@ -49,7 +50,10 @@ #include "DxilValidationUtils.h" #include +#include #include +#include +#include #include using namespace llvm; @@ -974,11 +978,75 @@ static void ValidateImmOperandForMathDxilOp(CallInst *CI, DXIL::OpCode Opcode, } } +static std::optional +ValidateConstantIntGetValue(CallInst *CI, Value *V, ValidationContext &ValCtx, + StringRef ValueName, StringRef OpName) { + if (!isa(V)) { + ValCtx.EmitInstrFormatError(CI, ValidationRule::InstrOpConst, + {ValueName, OpName}); + return std::nullopt; + } + + return cast(V)->getLimitedValue(); +} + +// Determines if a ComponentType is allowed in LinAlg builtins. +// Returns true when the CT is allowed. +static bool ValidateLinAlgComponentType(CallInst *CI, DXIL::ComponentType CT, + ValidationContext &ValCtx, + StringRef SourceName) { + switch (CT) { + case DXIL::ComponentType::I8: + case DXIL::ComponentType::I16: + case DXIL::ComponentType::I32: + case DXIL::ComponentType::I64: + case DXIL::ComponentType::U8: + case DXIL::ComponentType::U16: + case DXIL::ComponentType::U32: + case DXIL::ComponentType::U64: + case DXIL::ComponentType::F8_E4M3FN: + case DXIL::ComponentType::F8_E5M2: + case DXIL::ComponentType::F16: + case DXIL::ComponentType::F32: + case DXIL::ComponentType::F64: + case DXIL::ComponentType::BFloat16: + return true; + default: + ValCtx.EmitInstrFormatError(CI, + ValidationRule::InstrLinAlgIllegalComponentType, + {ComponentTypeToString(CT), SourceName}); + return false; + } +} + +static void ValidateLinAlgKDim(CallInst *CI, LinAlgTargetType &LATT, + ValidationContext &ValCtx, + StringRef SourceName) { + // This validation can't be applied to an accumulator matrix + if (LATT.Use == DXIL::MatrixUse::Accumulator) { + return; + } + + // Validate the K dim is in bounds. Which dim is K depends on use. + unsigned MinK = DXIL::kLinAlgMatrixMinK; + unsigned K = (LATT.Use == DXIL::MatrixUse::A) ? LATT.N : LATT.M; + unsigned MaxK = DXIL::kLinAlgMatrixMaxK; + if (LATT.Scope == DXIL::MatrixScope::ThreadGroup) { + MinK = DXIL::kLinAlgThreadGroupMatrixMinK; + MaxK = DXIL::kLinAlgThreadGroupMatrixMaxK; + } + if (K < MinK || K > MaxK) + ValCtx.EmitInstrFormatError(CI, ValidationRule::InstrLinAlgIllegalKDim, + {SourceName, std::to_string(K), + std::to_string(MinK), std::to_string(MaxK)}); +} + static void ValidateLinAlgOpParameters(CallInst *CI, ValidationContext &ValCtx) { for (uint32_t Idx = 0; Idx < CI->getNumArgOperands(); ++Idx) { Value *Arg = CI->getArgOperand(Idx); Type *Ty = Arg->getType(); + std::string Name = "Arg " + std::to_string(Idx); // No parameters may be undef if (isa(Arg)) @@ -987,200 +1055,1096 @@ static void ValidateLinAlgOpParameters(CallInst *CI, // If we have a LinAlg Matrix, validate that we have correct metadata. if (!dxilutil::IsHLSLLinAlgMatrixType(Ty)) continue; - if (ValCtx.LinAlgTargetTypeMap.find(Ty) == - ValCtx.LinAlgTargetTypeMap.end()) { - ValCtx.EmitInstrError(CI, ValidationRule::MetaWellFormed); + + auto it = ValCtx.LinAlgTargetTypeMap.find(Ty); + if (it == ValCtx.LinAlgTargetTypeMap.end()) { + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMetadataMissing, {Name}); continue; } - } -} -static void ValidateLinAlgOpReturnMatrix(CallInst *CI, - ValidationContext &ValCtx) { - Type *Ty = CI->getType(); - assert(dxilutil::IsHLSLLinAlgMatrixType(Ty) && "CI must return a matrix"); + LinAlgTargetType LATT = it->second; - // Metadata is malformed if we don't have metadata - auto it = ValCtx.LinAlgTargetTypeMap.find(Ty); - if (it == ValCtx.LinAlgTargetTypeMap.end()) { - ValCtx.EmitInstrError(CI, ValidationRule::MetaWellFormed); - return; - } - - LinAlgTargetType LATT = it->second; - - // Validate the K dim is in bounds. Which dim is K depends on use. - // This validation isn't applied to an accumulator matrix - if (LATT.Use != DXIL::MatrixUse::Accumulator) { - unsigned MinK = DXIL::kLinAlgMatrixMinK; - unsigned K = (LATT.Use == DXIL::MatrixUse::A) ? LATT.N : LATT.M; - unsigned MaxK = DXIL::kLinAlgMatrixMaxK; - if (LATT.Scope == DXIL::MatrixScope::ThreadGroup) { - MinK = DXIL::kLinAlgThreadGroupMatrixMinK; - MaxK = DXIL::kLinAlgThreadGroupMatrixMaxK; - } - if (K < MinK || K > MaxK) - ValCtx.EmitInstrFormatError( - CI, ValidationRule::InstrLinAlgIllegalKDim, - {std::to_string(K), std::to_string(MinK), std::to_string(MaxK)}); + ValidateLinAlgKDim(CI, LATT, ValCtx, Name); + ValidateLinAlgComponentType(CI, LATT.Type, ValCtx, + "arg " + std::to_string(Idx) + " matrix"); } +} - // Validate the ComponentType is allowed - switch (LATT.Type) { - case DXIL::ComponentType::I8: +static unsigned ComponentTypeElementsPerScalar(DXIL::ComponentType CT) { + switch (CT) { case DXIL::ComponentType::I16: case DXIL::ComponentType::I32: case DXIL::ComponentType::I64: - case DXIL::ComponentType::U8: case DXIL::ComponentType::U16: case DXIL::ComponentType::U32: case DXIL::ComponentType::U64: + case DXIL::ComponentType::F16: + case DXIL::ComponentType::F32: + case DXIL::ComponentType::F64: + return 1; + case DXIL::ComponentType::BFloat16: + return 2; + case DXIL::ComponentType::I8: + case DXIL::ComponentType::U8: + case DXIL::ComponentType::F8_E4M3FN: + case DXIL::ComponentType::F8_E5M2: + return 4; + // All other ComponentTypes are illegal to use in LinAlg Matrix. Their usage + // is detected and reported in other parts of the validator + default: + return 4; + } +} + +static unsigned ComponentTypeByteCount(DXIL::ComponentType CT) { + switch (CT) { + case DXIL::ComponentType::I8: + case DXIL::ComponentType::U8: case DXIL::ComponentType::F8_E4M3FN: case DXIL::ComponentType::F8_E5M2: + return 1; case DXIL::ComponentType::F16: + case DXIL::ComponentType::U16: + case DXIL::ComponentType::I16: + case DXIL::ComponentType::BFloat16: + return 2; + case DXIL::ComponentType::I32: + case DXIL::ComponentType::U32: case DXIL::ComponentType::F32: + return 4; + case DXIL::ComponentType::I64: + case DXIL::ComponentType::U64: case DXIL::ComponentType::F64: - break; + return 8; + // All other ComponentTypes are illegal to use in LinAlg Matrix. Their usage + // is detected and reported in other parts of the validator default: - ValCtx.EmitInstrFormatError(CI, - ValidationRule::InstrLinAlgIllegalComponentType, - {ComponentTypeToString(LATT.Type)}); - break; + return 1; + } +} + +static std::optional +GetCheckedLATT(Type *Ty, ValidationContext &ValCtx) { + assert(dxilutil::IsHLSLLinAlgMatrixType(Ty) && + "Type must be a LinAlg Matrix"); + auto It = ValCtx.LinAlgTargetTypeMap.find(Ty); + if (It == ValCtx.LinAlgTargetTypeMap.end()) + return std::nullopt; + return It->second; +} + +static void ValidateLinAlgOpReturnMatrix(CallInst *CI, + ValidationContext &ValCtx) { + Type *Ty = CI->getType(); + assert(dxilutil::IsHLSLLinAlgMatrixType(Ty) && "CI must return a matrix"); + + // Metadata is malformed if we don't have metadata + auto it = ValCtx.LinAlgTargetTypeMap.find(Ty); + if (it == ValCtx.LinAlgTargetTypeMap.end()) { + ValCtx.EmitInstrFormatError(CI, ValidationRule::InstrLinAlgMetadataMissing, + {"Return"}); + return; } + + LinAlgTargetType LATT = it->second; + ValidateLinAlgKDim(CI, LATT, ValCtx, "Return"); + ValidateLinAlgComponentType(CI, LATT.Type, ValCtx, "return matrix"); } static void ValidateLinAlgMatrixLength(CallInst *CI, ValidationContext &ValCtx) { ValidateLinAlgOpParameters(CI, ValCtx); + DxilInst_LinAlgMatrixLength Op(CI); + std::optional Mat = + GetCheckedLATT(Op.get_matrix()->getType(), ValCtx); + if (!Mat) + return; + + if (Mat->Scope != DXIL::MatrixScope::Wave && + Mat->Scope != DXIL::MatrixScope::ThreadGroup) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeMismatch2, + {"Input", MatrixScopeToString(Mat->Scope), "Wave", "ThreadGroup"}); } static void ValidateLinAlgMatrixGetCoordinate(CallInst *CI, ValidationContext &ValCtx) { ValidateLinAlgOpParameters(CI, ValCtx); + DxilInst_LinAlgMatrixGetCoordinate Op(CI); + std::optional Mat = + GetCheckedLATT(Op.get_matrix()->getType(), ValCtx); + if (!Mat) + return; + + if (Mat->Scope != DXIL::MatrixScope::Wave && + Mat->Scope != DXIL::MatrixScope::ThreadGroup) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeMismatch2, + {"Input", MatrixScopeToString(Mat->Scope), "Wave", "ThreadGroup"}); } static void ValidateLinAlgMatrixGetElement(CallInst *CI, ValidationContext &ValCtx) { ValidateLinAlgOpParameters(CI, ValCtx); + DxilInst_LinAlgMatrixGetElement Op(CI); + std::optional Mat = + GetCheckedLATT(Op.get_matrix()->getType(), ValCtx); + if (!Mat) + return; + + if (Mat->Scope != DXIL::MatrixScope::Wave && + Mat->Scope != DXIL::MatrixScope::ThreadGroup) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeMismatch2, + {"Input", MatrixScopeToString(Mat->Scope), "Wave", "ThreadGroup"}); } static void ValidateLinAlgMatrixStoreToDescriptor(CallInst *CI, ValidationContext &ValCtx) { ValidateLinAlgOpParameters(CI, ValCtx); + DxilInst_LinAlgMatrixStoreToDescriptor Op(CI); + std::optional Mat = + GetCheckedLATT(Op.get_matrix()->getType(), ValCtx); + if (!Mat) + return; + + std::optional LayoutV = ValidateConstantIntGetValue( + CI, Op.get_layout(), ValCtx, "Layout", "LinAlgMatrixStoreToDescriptor"); + if (!LayoutV) + return; + auto Layout = static_cast(*LayoutV); + + // Layout must be Row/Col Major + if (Layout != DXIL::MatrixLayout::RowMajor && + Layout != DXIL::MatrixLayout::ColumnMajor) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixRequiresLayout2, + {"LinAlgMatrixStoreToDescriptor", "RowMajor", "ColumnMajor"}); + + // Scope must be wave/threadgroup + if (Mat->Scope != DXIL::MatrixScope::Wave && + Mat->Scope != DXIL::MatrixScope::ThreadGroup) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeMismatch2, + {"Input", MatrixScopeToString(Mat->Scope), "Wave", "ThreadGroup"}); + + // handle must be a UAV Raw buffer (RWByteAddressBuffer) + DXIL::ComponentType ResCompTy; + DXIL::ResourceClass ResClass; + DXIL::ResourceKind ResKind = + GetResourceKindAndCompTy(Op.get_handle(), ResCompTy, ResClass, ValCtx); + if (ResClass != DXIL::ResourceClass::UAV || + ResKind != DXIL::ResourceKind::RawBuffer) + ValCtx.EmitInstrFormatError(CI, + ValidationRule::InstrLinAlgMatrixRequiresRWBAB, + {"LinAlgMatrixStoreToDescriptor"}); + + // Align must be an imm constant that is a multiple of 4 greater than 0 + std::optional Align = ValidateConstantIntGetValue( + CI, Op.get_align(), ValCtx, "Align", "LinAlgMatrixStoreToDescriptor"); + if (Align) { + if (*Align == 0) + ValCtx.EmitInstrFormatError(CI, ValidationRule::InstrParamMinimumValue, + {"Align", "0", std::to_string(*Align)}); + if (*Align % 4 != 0) + ValCtx.EmitInstrFormatError(CI, ValidationRule::InstrParamMultiple, + {"Align", "4", std::to_string(*Align)}); + } } static void ValidateLinAlgMatrixStoreToMemory(CallInst *CI, ValidationContext &ValCtx) { ValidateLinAlgOpParameters(CI, ValCtx); + DxilInst_LinAlgMatrixStoreToMemory Op(CI); + std::optional Mat = + GetCheckedLATT(Op.get_matrix()->getType(), ValCtx); + if (!Mat) + return; + + // Scope must be wave/threadgroup + if (Mat->Scope != DXIL::MatrixScope::Wave && + Mat->Scope != DXIL::MatrixScope::ThreadGroup) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeMismatch2, + {"Input", MatrixScopeToString(Mat->Scope), "Wave", "ThreadGroup"}); + + GEPOperator *GSGEP = cast(Op.get_memory()); + GlobalVariable *GSMem = cast(GSGEP->getPointerOperand()); + Type *GSMemInnerTy = GSMem->getType(); + unsigned GSScalarCount = 1; + if (PointerType *GSMemPtrTy = dyn_cast(GSMemInnerTy)) + GSMemInnerTy = GSMemPtrTy->getPointerElementType(); + if (ArrayType *GSMemArrTy = dyn_cast(GSMemInnerTy)) { + GSMemInnerTy = GSMemArrTy->getArrayElementType(); + GSScalarCount *= GSMemArrTy->getNumElements(); + } + if (VectorType *GSMemVecTy = dyn_cast(GSMemInnerTy)) { + GSMemInnerTy = GSMemVecTy->getVectorElementType(); + GSScalarCount *= GSMemVecTy->getNumElements(); + } + + // if gs memory inner type != i32 then matrix elem type must match it + if (!GSMemInnerTy->isIntegerTy(32) && + !IsComponentTypeSameNativeType(Mat->Type, GSMemInnerTy)) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixGSMemTypeMustMatch, + {TypeToString(GSMemInnerTy), "input matrix", + ComponentTypeToString(Mat->Type)}); + + // gs memory must be large enough for the write + unsigned ElementsPerScalar = ComponentTypeElementsPerScalar(Mat->Type); + unsigned ExpectedScalarCount = + (Mat->N + ElementsPerScalar - 1) / ElementsPerScalar * Mat->M; + if (ExpectedScalarCount > GSScalarCount) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixGSMemMustBeLargeEnough, + {std::to_string(GSScalarCount), std::to_string(ExpectedScalarCount)}); + + // gs memory ops have the parameter in element count so it must be scaled + uint64_t ByteCount = ComponentTypeByteCount(Mat->Type); + + // if it is constant then offset must be 4-byte aligned + if (ConstantInt *OffsetV = dyn_cast(Op.get_offset())) { + unsigned Offset = OffsetV->getLimitedValue(); + uint64_t OffsetBytes = Offset * ByteCount; + if (OffsetBytes % 4 != 0) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixBytewiseMustBeMultiple, + {"Offset", "4", std::to_string(OffsetBytes), std::to_string(Offset), + std::to_string(ByteCount)}); + } + + // if it is constant then stride must be 4-byte aligned + if (ConstantInt *StrideV = dyn_cast(Op.get_stride())) { + unsigned Stride = StrideV->getLimitedValue(); + uint64_t StrideBytes = Stride * ByteCount; + if (StrideBytes % 4 != 0) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixBytewiseMustBeMultiple, + {"Stride", "4", std::to_string(StrideBytes), std::to_string(Stride), + std::to_string(ByteCount)}); + } } -static void ValidateLinAlgMatVecMul(CallInst *CI, ValidationContext &ValCtx) { +static void ValidateLinAlgIsInputSigned(CallInst *CI, Value *IsInputSignedValue, + Type *InputTy, + ValidationContext &ValCtx, + const char *OpName) { + std::optional IsInputSigned = ValidateConstantIntGetValue( + CI, IsInputSignedValue, ValCtx, "IsInputSigned", OpName); + Type *ScalarTy = InputTy->getScalarType(); + if (IsInputSigned && ScalarTy->isFloatingPointTy() && *IsInputSigned != 1) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixUnsignedFloatTypeNotAllowed, + {TypeToString(ScalarTy)}); +} + +static void ValidateLinAlgMatVecMul(CallInst *CI, ValidationContext &ValCtx, + const char *OpName = "LinAlgMatVecMul") { ValidateLinAlgOpParameters(CI, ValCtx); + DxilInst_LinAlgMatVecMul Op(CI); + VectorType *OutputVecTy = cast(CI->getType()); + VectorType *InputVecTy = cast(Op.get_inputVector()->getType()); + std::optional Mat = + GetCheckedLATT(Op.get_matrix()->getType(), ValCtx); + if (!Mat) + return; + + // Mat must be A matrix of Thread scope + if (Mat->Scope != DXIL::MatrixScope::Thread) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeMismatch, + {"Input", MatrixScopeToString(Mat->Scope), "Thread"}); + if (Mat->Use != DXIL::MatrixUse::A) + ValCtx.EmitInstrFormatError(CI, + ValidationRule::InstrLinAlgMatrixUseMismatch, + {"Input", MatrixUseToString(Mat->Use), "A"}); + + // Input Interp must be a immarg of allowed ComponentType + DXIL::ComponentType Interp = DXIL::ComponentType::Invalid; + std::optional InterpV = ValidateConstantIntGetValue( + CI, Op.get_interpretation(), ValCtx, "InputInterp", OpName); + if (InterpV) { + Interp = static_cast(*InterpV); + ValidateLinAlgComponentType(CI, Interp, ValCtx, "InputInterp"); + } + + // InputVec's length must match the K dim of input matrix after accounting + // for multiple elements packed into a single scalar. The packed elements may + // not fully saturate the final vector element but it must still be included. + // K is always the N of the matrix since its ensured to be an A Matrix. + unsigned ElementsPerScalar = ComponentTypeElementsPerScalar(Interp); + unsigned ExpectedVecK = (Mat->N + ElementsPerScalar - 1) / ElementsPerScalar; + + if (ExpectedVecK != InputVecTy->getNumElements()) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixDimKVecKMismatch, + {"Input", std::to_string(InputVecTy->getNumElements()), + std::to_string(ExpectedVecK), std::to_string(Mat->N), + ComponentTypeToString(Interp)}); + + // OutputVec length must match M dim + if (Mat->M != OutputVecTy->getNumElements()) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixDimVectorMismatch, + {"Output", std::to_string(OutputVecTy->getNumElements()), + std::to_string(Mat->M)}); + + // Sign bit must be immarg and must be true if output vec is a + // native floating point type + std::optional IsSigned = ValidateConstantIntGetValue( + CI, Op.get_isOutputSigned(), ValCtx, "IsSigned", OpName); + if (IsSigned && OutputVecTy->getElementType()->isFloatingPointTy() && + *IsSigned != 1) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixUnsignedFloatTypeNotAllowed, + {TypeToString(OutputVecTy->getElementType())}); } static void ValidateLinAlgMatVecMulAdd(CallInst *CI, ValidationContext &ValCtx) { - ValidateLinAlgOpParameters(CI, ValCtx); + // All the rules from LinAlgMatVecMul apply + ValidateLinAlgMatVecMul(CI, ValCtx, "LinAlgMatVecMulAdd"); + DxilInst_LinAlgMatVecMulAdd Op(CI); + VectorType *OutputVecTy = cast(CI->getType()); + VectorType *BiasVecTy = cast(Op.get_biasVector()->getType()); + std::optional Mat = + GetCheckedLATT(Op.get_matrix()->getType(), ValCtx); + if (!Mat) + return; + + // BiasVec length must match M dim + if (Mat->M != BiasVecTy->getNumElements()) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixDimVectorMismatch, + {"Bias", std::to_string(BiasVecTy->getNumElements()), + std::to_string(Mat->M)}); + + // Bias element type must match output element type + if (BiasVecTy->getElementType() != OutputVecTy->getElementType()) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixVecElementTypeMismatch, + {"Output", TypeToString(OutputVecTy->getElementType()), "bias", + TypeToString(BiasVecTy->getElementType())}); } static void ValidateLinAlgMatrixAccumulateToDescriptor(CallInst *CI, ValidationContext &ValCtx) { ValidateLinAlgOpParameters(CI, ValCtx); + DxilInst_LinAlgMatrixAccumulateToDescriptor Op(CI); + std::optional Mat = + GetCheckedLATT(Op.get_matrix()->getType(), ValCtx); + if (!Mat) + return; + + std::optional LayoutV = + ValidateConstantIntGetValue(CI, Op.get_layout(), ValCtx, "Layout", + "LinAlgMatrixAccumulateToDescriptor"); + if (!LayoutV) + return; + auto Layout = static_cast(*LayoutV); + bool LayoutIsRowColMajor = (Layout == DXIL::MatrixLayout::RowMajor || + Layout == DXIL::MatrixLayout::ColumnMajor); + + // Thread Matrix must have layout OuterProductOptimal* + if (Mat->Scope == DXIL::MatrixScope::Thread && + (Layout != DXIL::MatrixLayout::OuterProductOptimal && + Layout != DXIL::MatrixLayout::OuterProductOptimalTranspose)) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeReqLayout2, + {"Input", MatrixScopeToString(Mat->Scope), "OuterProductOptimal", + "OuterProductOptimalTranspose", "LinAlgMatrixAccumulateToDescriptor"}); + + // Wave/ThreadGroup matrix must have layout RowMajor/ColMajor + if ((Mat->Scope == DXIL::MatrixScope::Wave || + Mat->Scope == DXIL::MatrixScope::ThreadGroup) && + !LayoutIsRowColMajor) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeReqLayout2, + {"Input", MatrixScopeToString(Mat->Scope), "RowMajor", "ColumnMajor", + "LinAlgMatrixAccumulateToDescriptor"}); + + // Stride must be an imm 0 if layout is not Row/Col Major + if (!LayoutIsRowColMajor) { + std::optional Stride = + ValidateConstantIntGetValue(CI, Op.get_stride(), ValCtx, "Stride", + "LinAlgMatrixAccumulateToDescriptor"); + if (Stride && *Stride != 0) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixLayoutReqStride, + {"LinAlgMatrixAccumulateToDescriptor", MatrixLayoutToString(Layout)}); + } + + // Matrix must have Accumulator use + if (Mat->Use != DXIL::MatrixUse::Accumulator) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixUseMismatch, + {"Input", MatrixUseToString(Mat->Use), "Accumulator"}); + + // handle must be a UAV Raw buffer (RWByteAddressBuffer) + DXIL::ComponentType ResCompTy; + DXIL::ResourceClass ResClass; + DXIL::ResourceKind ResKind = + GetResourceKindAndCompTy(Op.get_handle(), ResCompTy, ResClass, ValCtx); + if (ResClass != DXIL::ResourceClass::UAV || + ResKind != DXIL::ResourceKind::RawBuffer) + ValCtx.EmitInstrFormatError(CI, + ValidationRule::InstrLinAlgMatrixRequiresRWBAB, + {"LinAlgMatrixAccumulateToDescriptor"}); + + uint64_t RequiredAlignment = + Mat->Scope == DXIL::MatrixScope::Thread ? 128 : 4; + // Align must be an imm constant with the scope's required alignment + std::optional Align = + ValidateConstantIntGetValue(CI, Op.get_align(), ValCtx, "Align", + "LinAlgMatrixAccumulateToDescriptor"); + if (Align) { + if (*Align == 0) + ValCtx.EmitInstrFormatError(CI, ValidationRule::InstrParamMinimumValue, + {"Align", "0", std::to_string(*Align)}); + if (*Align % RequiredAlignment != 0) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrParamMultiple, + {"Align", std::to_string(RequiredAlignment), std::to_string(*Align)}); + } } static void ValidateLinAlgMatrixAccumulateToMemory(CallInst *CI, ValidationContext &ValCtx) { ValidateLinAlgOpParameters(CI, ValCtx); + DxilInst_LinAlgMatrixAccumulateToMemory Op(CI); + std::optional Mat = + GetCheckedLATT(Op.get_matrix()->getType(), ValCtx); + if (!Mat) + return; + + // Scope must be wave/threadgroup + if (Mat->Scope != DXIL::MatrixScope::Wave && + Mat->Scope != DXIL::MatrixScope::ThreadGroup) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeMismatch2, + {"Input", MatrixScopeToString(Mat->Scope), "Wave", "ThreadGroup"}); + + // Matrix must have Accumulator use + if (Mat->Use != DXIL::MatrixUse::Accumulator) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixUseMismatch, + {"Input", MatrixUseToString(Mat->Use), "Accumulator"}); + + GEPOperator *GSGEP = cast(Op.get_memory()); + GlobalVariable *GSMem = cast(GSGEP->getPointerOperand()); + Type *GSMemInnerTy = GSMem->getType(); + unsigned GSScalarCount = 1; + if (PointerType *GSMemPtrTy = dyn_cast(GSMemInnerTy)) + GSMemInnerTy = GSMemPtrTy->getPointerElementType(); + if (ArrayType *GSMemArrTy = dyn_cast(GSMemInnerTy)) { + GSMemInnerTy = GSMemArrTy->getArrayElementType(); + GSScalarCount *= GSMemArrTy->getNumElements(); + } + if (VectorType *GSMemVecTy = dyn_cast(GSMemInnerTy)) { + GSMemInnerTy = GSMemVecTy->getVectorElementType(); + GSScalarCount *= GSMemVecTy->getNumElements(); + } + + // if gs memory inner type != i32 then matrix elem type must match it + if (!GSMemInnerTy->isIntegerTy(32) && + !IsComponentTypeSameNativeType(Mat->Type, GSMemInnerTy)) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixGSMemTypeMustMatch, + {TypeToString(GSMemInnerTy), "input matrix", + ComponentTypeToString(Mat->Type)}); + + // gs memory must be large enough for the write + unsigned ElementsPerScalar = ComponentTypeElementsPerScalar(Mat->Type); + unsigned ExpectedScalarCount = + (Mat->N + ElementsPerScalar - 1) / ElementsPerScalar * Mat->M; + if (ExpectedScalarCount > GSScalarCount) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixGSMemMustBeLargeEnough, + {std::to_string(GSScalarCount), std::to_string(ExpectedScalarCount)}); + + // gs memory ops have the parameter in element count so it must be scaled + uint64_t ByteCount = ComponentTypeByteCount(Mat->Type); + + // if it is constant then offset must be 4-byte aligned + if (ConstantInt *OffsetV = dyn_cast(Op.get_offset())) { + unsigned Offset = OffsetV->getLimitedValue(); + uint64_t OffsetBytes = Offset * ByteCount; + if (OffsetBytes % 4 != 0) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixBytewiseMustBeMultiple, + {"Offset", "4", std::to_string(OffsetBytes), std::to_string(Offset), + std::to_string(ByteCount)}); + } + + // if it is constant then stride must be 4-byte aligned + if (ConstantInt *StrideV = dyn_cast(Op.get_stride())) { + unsigned Stride = StrideV->getLimitedValue(); + uint64_t StrideBytes = Stride * ByteCount; + if (StrideBytes % 4 != 0) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixBytewiseMustBeMultiple, + {"Stride", "4", std::to_string(StrideBytes), std::to_string(Stride), + std::to_string(ByteCount)}); + } } static void ValidateLinAlgConvert(CallInst *CI, ValidationContext &ValCtx) { ValidateLinAlgOpParameters(CI, ValCtx); + DxilInst_LinAlgConvert Op(CI); + + VectorType *RetVecTy = cast(CI->getType()); + VectorType *InVecTy = cast(Op.get_inputVector()->getType()); + bool IsComponentTypeValid = true; + + // Input interp must be a immarg of allowed ComponentType + std::optional InputInterpV = + ValidateConstantIntGetValue(CI, Op.get_inputInterpretation(), ValCtx, + "InputInterpretation", "LinAlgConvert"); + if (!InputInterpV) + return; + DXIL::ComponentType InputInterp = + static_cast(*InputInterpV); + IsComponentTypeValid &= ValidateLinAlgComponentType(CI, InputInterp, ValCtx, + "InputInterpretation"); + + // Output interp must be a immarg of allowed ComponentType + std::optional OutputInterpV = + ValidateConstantIntGetValue(CI, Op.get_outputInterpretation(), ValCtx, + "OutputInterpretation", "LinAlgConvert"); + if (!OutputInterpV) + return; + DXIL::ComponentType OutputInterp = + static_cast(*OutputInterpV); + IsComponentTypeValid &= ValidateLinAlgComponentType(CI, OutputInterp, ValCtx, + "OutputInterpretation"); + + // The remaining validations only give reasonable errors when assuming valid + // ComponentTypes. Stop early to minimize noise/avoid being unhelpful + if (!IsComponentTypeValid) + return; + + bool IsNativeInputInterp = IsComponentTypeNative(InputInterp); + bool IsNativeOutputInterp = IsComponentTypeNative(OutputInterp); + + // If input interp is native then input vector element type must match that + // type + if (IsNativeInputInterp && + !IsComponentTypeSameNativeType(InputInterp, InVecTy->getElementType())) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixVectorTypeMustMatch, + {"Input", TypeToString(InVecTy->getElementType()), + "InputInterpretation", ComponentTypeToString(InputInterp)}); + + // If input interp is non-native then input vector element type must be i32 + if (!IsNativeInputInterp && !InVecTy->getElementType()->isIntegerTy(32)) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixVectorTypeMustMatchPacked, + {"Input", TypeToString(InVecTy->getElementType()), + "InputInterpretation", ComponentTypeToString(InputInterp)}); + + // If output interp is native then output vector element type must match that + // type + if (IsNativeOutputInterp && + !IsComponentTypeSameNativeType(OutputInterp, RetVecTy->getElementType())) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixVectorTypeMustMatch, + {"Output", TypeToString(RetVecTy->getElementType()), + "OutputInterpretation", ComponentTypeToString(OutputInterp)}); + + // If output interp is non-native then output vector element type must be i32 + if (!IsNativeOutputInterp && !RetVecTy->getElementType()->isIntegerTy(32)) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixVectorTypeMustMatchPacked, + {"Output", TypeToString(RetVecTy->getElementType()), + "OutputInterpretation", ComponentTypeToString(OutputInterp)}); + + // output vector length must be properly converted from input length + unsigned InputElemCount = + InVecTy->getNumElements() * ComponentTypeElementsPerScalar(InputInterp); + unsigned OutputElemPerScalar = ComponentTypeElementsPerScalar(OutputInterp); + unsigned ExpectedOutVecSize = + (InputElemCount + OutputElemPerScalar - 1) / OutputElemPerScalar; + if (RetVecTy->getNumElements() != ExpectedOutVecSize) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixVecElemCountMismatch, + {std::to_string(RetVecTy->getNumElements()), + std::to_string(ExpectedOutVecSize)}); } static void ValidateLinAlgVectorAccumulateToDescriptor(CallInst *CI, ValidationContext &ValCtx) { ValidateLinAlgOpParameters(CI, ValCtx); + DxilInst_LinAlgVectorAccumulateToDescriptor Op(CI); + + // handle must be a UAV Raw buffer (RWByteAddressBuffer) + DXIL::ComponentType ResCompTy; + DXIL::ResourceClass ResClass; + DXIL::ResourceKind ResKind = + GetResourceKindAndCompTy(Op.get_handle(), ResCompTy, ResClass, ValCtx); + if (ResClass != DXIL::ResourceClass::UAV || + ResKind != DXIL::ResourceKind::RawBuffer) + ValCtx.EmitInstrFormatError(CI, + ValidationRule::InstrLinAlgMatrixRequiresRWBAB, + {"LinAlgVectorAccumulateToDescriptor"}); + + // Align must be an imm constant that is a multiple of 64 greater than 0 + std::optional Align = + ValidateConstantIntGetValue(CI, Op.get_align(), ValCtx, "Align", + "LinAlgVectorAccumulateToDescriptor"); + if (Align) { + if (*Align == 0) + ValCtx.EmitInstrFormatError(CI, ValidationRule::InstrParamMinimumValue, + {"Align", "0", std::to_string(*Align)}); + if (*Align % 64 != 0) + ValCtx.EmitInstrFormatError(CI, ValidationRule::InstrParamMultiple, + {"Align", "64", std::to_string(*Align)}); + } } static void ValidateLinAlgFillMatrix(CallInst *CI, ValidationContext &ValCtx) { ValidateLinAlgOpReturnMatrix(CI, ValCtx); ValidateLinAlgOpParameters(CI, ValCtx); + DxilInst_LinAlgFillMatrix Op(CI); + ValidateLinAlgIsInputSigned(CI, Op.get_isInputSigned(), + Op.get_value()->getType(), ValCtx, + "LinAlgFillMatrix"); + std::optional RetMat = + GetCheckedLATT(CI->getType(), ValCtx); + if (!RetMat) + return; + + if (RetMat->Scope != DXIL::MatrixScope::Wave && + RetMat->Scope != DXIL::MatrixScope::ThreadGroup) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeMismatch2, + {"Return", MatrixScopeToString(RetMat->Scope), "Wave", "ThreadGroup"}); } static void ValidateLinAlgMatrixLoadFromMemory(CallInst *CI, ValidationContext &ValCtx) { ValidateLinAlgOpReturnMatrix(CI, ValCtx); ValidateLinAlgOpParameters(CI, ValCtx); + DxilInst_LinAlgMatrixLoadFromMemory Op(CI); + + std::optional RetMat = + GetCheckedLATT(CI->getType(), ValCtx); + if (!RetMat) + return; + + // Scope must be wave/threadgroup + if (RetMat->Scope != DXIL::MatrixScope::Wave && + RetMat->Scope != DXIL::MatrixScope::ThreadGroup) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeMismatch2, + {"Return", MatrixScopeToString(RetMat->Scope), "Wave", "ThreadGroup"}); + + GEPOperator *GSGEP = cast(Op.get_memory()); + GlobalVariable *GSMem = cast(GSGEP->getPointerOperand()); + Type *GSMemInnerTy = GSMem->getType(); + unsigned GSScalarCount = 1; + if (PointerType *GSMemPtrTy = dyn_cast(GSMemInnerTy)) + GSMemInnerTy = GSMemPtrTy->getPointerElementType(); + if (ArrayType *GSMemArrTy = dyn_cast(GSMemInnerTy)) { + GSMemInnerTy = GSMemArrTy->getArrayElementType(); + GSScalarCount *= GSMemArrTy->getNumElements(); + } + if (VectorType *GSMemVecTy = dyn_cast(GSMemInnerTy)) { + GSMemInnerTy = GSMemVecTy->getVectorElementType(); + GSScalarCount *= GSMemVecTy->getNumElements(); + } + + // if gs memory inner type != i32 then matrix elem type must match it + if (!GSMemInnerTy->isIntegerTy(32) && + !IsComponentTypeSameNativeType(RetMat->Type, GSMemInnerTy)) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixGSMemTypeMustMatch, + {TypeToString(GSMemInnerTy), "return matrix", + ComponentTypeToString(RetMat->Type)}); + + // gs memory must be large enough for the read + unsigned ElementsPerScalar = ComponentTypeElementsPerScalar(RetMat->Type); + unsigned ExpectedScalarCount = + (RetMat->N + ElementsPerScalar - 1) / ElementsPerScalar * RetMat->M; + if (ExpectedScalarCount > GSScalarCount) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixGSMemMustBeLargeEnough, + {std::to_string(GSScalarCount), std::to_string(ExpectedScalarCount)}); + + // gs memory ops have the parameter in element count so it must be scaled + uint64_t ByteCount = ComponentTypeByteCount(RetMat->Type); + + // if it is constant then offset must be 4-byte aligned + if (ConstantInt *OffsetV = dyn_cast(Op.get_offset())) { + unsigned Offset = OffsetV->getLimitedValue(); + uint64_t OffsetBytes = Offset * ByteCount; + if (OffsetBytes % 4 != 0) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixBytewiseMustBeMultiple, + {"Offset", "4", std::to_string(OffsetBytes), std::to_string(Offset), + std::to_string(ByteCount)}); + } + + // if it is constant then stride must be 4-byte aligned + if (ConstantInt *StrideV = dyn_cast(Op.get_stride())) { + unsigned Stride = StrideV->getLimitedValue(); + uint64_t StrideBytes = Stride * ByteCount; + if (StrideBytes % 4 != 0) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixBytewiseMustBeMultiple, + {"Stride", "4", std::to_string(StrideBytes), std::to_string(Stride), + std::to_string(ByteCount)}); + } } static void ValidateLinAlgMatrixSetElement(CallInst *CI, ValidationContext &ValCtx) { ValidateLinAlgOpReturnMatrix(CI, ValCtx); ValidateLinAlgOpParameters(CI, ValCtx); + DxilInst_LinAlgMatrixSetElement Op(CI); + std::optional RetMat = + GetCheckedLATT(CI->getType(), ValCtx); + if (!RetMat) + return; + std::optional InMat = + GetCheckedLATT(Op.get_matrix()->getType(), ValCtx); + if (!InMat) + return; + + if (InMat->Scope != DXIL::MatrixScope::Wave && + InMat->Scope != DXIL::MatrixScope::ThreadGroup) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeMismatch2, + {"Input", MatrixScopeToString(InMat->Scope), "Wave", "ThreadGroup"}); + + if (RetMat->Scope != DXIL::MatrixScope::Wave && + RetMat->Scope != DXIL::MatrixScope::ThreadGroup) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeMismatch2, + {"Return", MatrixScopeToString(RetMat->Scope), "Wave", "ThreadGroup"}); } static void ValidateLinAlgMatrixMultiply(CallInst *CI, ValidationContext &ValCtx) { ValidateLinAlgOpReturnMatrix(CI, ValCtx); ValidateLinAlgOpParameters(CI, ValCtx); + DxilInst_LinAlgMatrixMultiply Op(CI); + std::optional RetMat = + GetCheckedLATT(CI->getType(), ValCtx); + if (!RetMat) + return; + std::optional AMat = + GetCheckedLATT(Op.get_matrixA()->getType(), ValCtx); + if (!AMat) + return; + std::optional BMat = + GetCheckedLATT(Op.get_matrixB()->getType(), ValCtx); + if (!BMat) + return; + + // A is an A matrix + if (AMat->Use != DXIL::MatrixUse::A) + ValCtx.EmitInstrFormatError(CI, + ValidationRule::InstrLinAlgMatrixUseMismatch, + {"A", MatrixUseToString(AMat->Use), "A"}); + + // B is a B matrix + if (BMat->Use != DXIL::MatrixUse::B) + ValCtx.EmitInstrFormatError(CI, + ValidationRule::InstrLinAlgMatrixUseMismatch, + {"B", MatrixUseToString(BMat->Use), "B"}); + + // Ret is an Accumulator matrix + if (RetMat->Use != DXIL::MatrixUse::Accumulator) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixUseMismatch, + {"Return", MatrixUseToString(RetMat->Use), "Accumulator"}); + + // A scope must be Wave or ThreadGroup + if (AMat->Scope != DXIL::MatrixScope::Wave && + AMat->Scope != DXIL::MatrixScope::ThreadGroup) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeMismatch2, + {"A", MatrixScopeToString(AMat->Scope), "Wave", "ThreadGroup"}); + + // B scope must be Wave or ThreadGroup + if (BMat->Scope != DXIL::MatrixScope::Wave && + BMat->Scope != DXIL::MatrixScope::ThreadGroup) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeMismatch2, + {"B", MatrixScopeToString(BMat->Scope), "Wave", "ThreadGroup"}); + + // Ret scope must be Wave or ThreadGroup + if (RetMat->Scope != DXIL::MatrixScope::Wave && + RetMat->Scope != DXIL::MatrixScope::ThreadGroup) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeMismatch2, + {"Return", MatrixScopeToString(RetMat->Scope), "Wave", "ThreadGroup"}); + + // A, B, Ret scope must all be the same + if (AMat->Scope != BMat->Scope || BMat->Scope != RetMat->Scope) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeMustMatch3, + {"A", MatrixScopeToString(AMat->Scope), "B", + MatrixScopeToString(BMat->Scope), "Return", + MatrixScopeToString(RetMat->Scope)}); + + unsigned M = AMat->M; + unsigned AK = AMat->N; + unsigned BK = BMat->M; + unsigned N = BMat->N; + + // K dim must match between A and B + if (AK != BK) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixMatrixKDimMustMatch, + {std::to_string(M) + "x" + std::to_string(AK), + std::to_string(BK) + "x" + std::to_string(N), std::to_string(AK), + std::to_string(BK)}); + + // Return dim must match A.M x B.N + if (RetMat->M != M || RetMat->N != N) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixMatrixResDimMustMatch, + {"Return", std::to_string(RetMat->M) + "x" + std::to_string(RetMat->N), + std::to_string(M) + "x" + std::to_string(N)}); } static void ValidateLinAlgMatrixMultiplyAccumulate(CallInst *CI, ValidationContext &ValCtx) { ValidateLinAlgOpReturnMatrix(CI, ValCtx); ValidateLinAlgOpParameters(CI, ValCtx); + DxilInst_LinAlgMatrixMultiplyAccumulate Op(CI); + std::optional RetMat = + GetCheckedLATT(CI->getType(), ValCtx); + if (!RetMat) + return; + std::optional AMat = + GetCheckedLATT(Op.get_matrixA()->getType(), ValCtx); + if (!AMat) + return; + std::optional BMat = + GetCheckedLATT(Op.get_matrixB()->getType(), ValCtx); + if (!BMat) + return; + std::optional CMat = + GetCheckedLATT(Op.get_matrixC()->getType(), ValCtx); + if (!CMat) + return; + + // A is an A matrix + if (AMat->Use != DXIL::MatrixUse::A) + ValCtx.EmitInstrFormatError(CI, + ValidationRule::InstrLinAlgMatrixUseMismatch, + {"A", MatrixUseToString(AMat->Use), "A"}); + + // B is a B matrix + if (BMat->Use != DXIL::MatrixUse::B) + ValCtx.EmitInstrFormatError(CI, + ValidationRule::InstrLinAlgMatrixUseMismatch, + {"B", MatrixUseToString(BMat->Use), "B"}); + + // C is an Accumulator matrix + if (CMat->Use != DXIL::MatrixUse::Accumulator) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixUseMismatch, + {"C", MatrixUseToString(CMat->Use), "Accumulator"}); + + // Ret is an Accumulator matrix + if (RetMat->Use != DXIL::MatrixUse::Accumulator) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixUseMismatch, + {"Return", MatrixUseToString(RetMat->Use), "Accumulator"}); + + // A scope must be Wave or ThreadGroup + if (AMat->Scope != DXIL::MatrixScope::Wave && + AMat->Scope != DXIL::MatrixScope::ThreadGroup) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeMismatch2, + {"A", MatrixScopeToString(AMat->Scope), "Wave", "ThreadGroup"}); + + // B scope must be Wave or ThreadGroup + if (BMat->Scope != DXIL::MatrixScope::Wave && + BMat->Scope != DXIL::MatrixScope::ThreadGroup) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeMismatch2, + {"B", MatrixScopeToString(BMat->Scope), "Wave", "ThreadGroup"}); + + // C scope must be Wave or ThreadGroup + if (CMat->Scope != DXIL::MatrixScope::Wave && + CMat->Scope != DXIL::MatrixScope::ThreadGroup) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeMismatch2, + {"C", MatrixScopeToString(CMat->Scope), "Wave", "ThreadGroup"}); + + // Ret scope must be Wave or ThreadGroup + if (RetMat->Scope != DXIL::MatrixScope::Wave && + RetMat->Scope != DXIL::MatrixScope::ThreadGroup) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeMismatch2, + {"Return", MatrixScopeToString(RetMat->Scope), "Wave", "ThreadGroup"}); + + // A, B, C, Ret scope must all be the same + if (AMat->Scope != BMat->Scope || BMat->Scope != CMat->Scope || + CMat->Scope != RetMat->Scope) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeMustMatch4, + {"A", MatrixScopeToString(AMat->Scope), "B", + MatrixScopeToString(BMat->Scope), "C", + MatrixScopeToString(CMat->Scope), "Return", + MatrixScopeToString(RetMat->Scope)}); + + unsigned M = AMat->M; + unsigned AK = AMat->N; + unsigned BK = BMat->M; + unsigned N = BMat->N; + + // K dim must match between A and B + if (AK != BK) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixMatrixKDimMustMatch, + {std::to_string(M) + "x" + std::to_string(AK), + std::to_string(BK) + "x" + std::to_string(N), std::to_string(AK), + std::to_string(BK)}); + + // C dim must match A.M x B.N + if (CMat->M != M || CMat->N != N) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixMatrixResDimMustMatch, + {"C", std::to_string(CMat->M) + "x" + std::to_string(CMat->N), + std::to_string(M) + "x" + std::to_string(N)}); + + // Return dim must match A.M x B.N + if (RetMat->M != M || RetMat->N != N) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixMatrixResDimMustMatch, + {"Return", std::to_string(RetMat->M) + "x" + std::to_string(RetMat->N), + std::to_string(M) + "x" + std::to_string(N)}); } static void ValidateLinAlgMatrixOuterProduct(CallInst *CI, ValidationContext &ValCtx) { ValidateLinAlgOpReturnMatrix(CI, ValCtx); ValidateLinAlgOpParameters(CI, ValCtx); + DxilInst_LinAlgMatrixOuterProduct Op(CI); + VectorType *AVecTy = cast(Op.get_vectorA()->getType()); + VectorType *BVecTy = cast(Op.get_vectorB()->getType()); + ValidateLinAlgIsInputSigned(CI, Op.get_isInputSigned(), AVecTy, ValCtx, + "LinAlgMatrixOuterProduct"); + std::optional RetMat = + GetCheckedLATT(CI->getType(), ValCtx); + if (!RetMat) + return; + + // Matrix must be thread scope + if (RetMat->Scope != DXIL::MatrixScope::Thread) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeMismatch, + {"Return", MatrixScopeToString(RetMat->Scope), "Thread"}); + + // Matrix must be accumulator use + if (RetMat->Use != DXIL::MatrixUse::Accumulator) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixUseMismatch, + {"Return", MatrixUseToString(RetMat->Use), "Accumulator"}); + + // M dim must be length of vecA + unsigned M = AVecTy->getNumElements(); + + // N dim must be length of vecB + unsigned N = BVecTy->getNumElements(); + + // Matrix must be M*N dim + if (RetMat->M != M || RetMat->N != N) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrix2PartsMustMatch, + {"Return", "dimension", + std::to_string(RetMat->M) + "x" + std::to_string(RetMat->N), "derived", + "dimension", std::to_string(M) + "x" + std::to_string(N)}); + + // element type of vecA and vecB must be the same + if (AVecTy->getElementType() != BVecTy->getElementType()) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixVecElementTypeMismatch, + {"A", TypeToString(AVecTy->getElementType()), "B", + TypeToString(BVecTy->getElementType())}); } static void ValidateLinAlgMatrixLoadFromDescriptor(CallInst *CI, ValidationContext &ValCtx) { ValidateLinAlgOpReturnMatrix(CI, ValCtx); ValidateLinAlgOpParameters(CI, ValCtx); - - Type *RetMatTy = CI->getType(); - assert(dxilutil::IsHLSLLinAlgMatrixType(RetMatTy) && "Must be LinAlg type"); - auto RetIt = ValCtx.LinAlgTargetTypeMap.find(RetMatTy); - if (RetIt == ValCtx.LinAlgTargetTypeMap.end()) + DxilInst_LinAlgMatrixLoadFromDescriptor Op(CI); + std::optional RetMat = + GetCheckedLATT(CI->getType(), ValCtx); + if (!RetMat) return; - LinAlgTargetType RetLATT = RetIt->second; - Value *StrideOp = CI->getArgOperand(3); - Value *LayoutOp = CI->getArgOperand(4); - ConstantInt *LayoutCI = dyn_cast(LayoutOp); - if (!LayoutCI) { - ValCtx.EmitInstrFormatError(CI, ValidationRule::InstrOpConst, - {"Layout", "LinAlgMatrixLoadFromDescriptor"}); - return; + std::optional LayoutV; + // Layout must be an immarg for Thread matrix otherwise it can be non-immarg + if (RetMat->Scope == DXIL::MatrixScope::Thread) { + LayoutV = ValidateConstantIntGetValue(CI, Op.get_layout(), ValCtx, "Layout", + "LinAlgMatrixLoadFromDescriptor"); + if (!LayoutV) + return; + } else if (ConstantInt *Layout = dyn_cast(Op.get_layout())) { + LayoutV = Layout->getZExtValue(); } - auto Layout = static_cast(LayoutCI->getLimitedValue()); - bool LayoutIsRowColMajor = (Layout == DXIL::MatrixLayout::RowMajor || - Layout == DXIL::MatrixLayout::ColumnMajor); - - // Layout must be Row/Col Major if Scope is Wave/ThreadGroup - if (RetLATT.Scope != DXIL::MatrixScope::Thread && !LayoutIsRowColMajor) - ValCtx.EmitInstrFormatError( - CI, ValidationRule::InstrLinAlgMatrixScopeReqLayout2, - {MatrixScopeToString(RetLATT.Scope), "RowMajor", "ColumnMajor"}); + if (LayoutV) { + DXIL::MatrixLayout Layout = static_cast(*LayoutV); + bool LayoutIsRowColMajor = (Layout == DXIL::MatrixLayout::RowMajor || + Layout == DXIL::MatrixLayout::ColumnMajor); - // Stride must be an imm 0 if Layout is not Row/Col Major - if (!LayoutIsRowColMajor) { - ConstantInt *StrideCI = dyn_cast(StrideOp); - if (StrideCI) { - if (!StrideCI->isZero()) + // Layout must be Row/Col Major if Scope is Wave/ThreadGroup + if ((RetMat->Scope == DXIL::MatrixScope::Wave || + RetMat->Scope == DXIL::MatrixScope::ThreadGroup) && + !LayoutIsRowColMajor) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeReqLayout2, + {"Return", MatrixScopeToString(RetMat->Scope), "RowMajor", + "ColumnMajor", "LinAlgMatrixLoadFromDescriptor"}); + + // Stride must be an imm 0 if Layout is not Row/Col Major + if (!LayoutIsRowColMajor) { + std::optional Stride = + ValidateConstantIntGetValue(CI, Op.get_stride(), ValCtx, "Stride", + "LinAlgMatrixLoadFromDescriptor"); + if (Stride && *Stride != 0) ValCtx.EmitInstrFormatError( CI, ValidationRule::InstrLinAlgMatrixLayoutReqStride, - {MatrixLayoutToString(Layout)}); - } else - ValCtx.EmitInstrFormatError(CI, ValidationRule::InstrOpConst, - {"Stride", "LinAlgMatrixLoadFromDescriptor"}); + {"LinAlgMatrixLoadFromDescriptor", MatrixLayoutToString(Layout)}); + } + } + + uint64_t RequiredAlignment = + RetMat->Scope == DXIL::MatrixScope::Thread ? 128 : 4; + // Align must be an imm constant with the scope's required alignment + std::optional Align = ValidateConstantIntGetValue( + CI, Op.get_align(), ValCtx, "Align", "LinAlgMatrixLoadFromDescriptor"); + if (Align) { + if (*Align == 0) + ValCtx.EmitInstrFormatError(CI, ValidationRule::InstrParamMinimumValue, + {"Align", "0", std::to_string(*Align)}); + if (*Align % RequiredAlignment != 0) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrParamMultiple, + {"Align", std::to_string(RequiredAlignment), std::to_string(*Align)}); + } + + // Thread matrix may only load from SRV ByteAddressBuffer + if (RetMat->Scope == DXIL::MatrixScope::Thread) { + DXIL::ComponentType ResCompTy; + DXIL::ResourceClass ResClass; + DXIL::ResourceKind ResKind = + GetResourceKindAndCompTy(Op.get_handle(), ResCompTy, ResClass, ValCtx); + if (ResClass != DXIL::ResourceClass::SRV || + ResKind != DXIL::ResourceKind::RawBuffer) + ValCtx.EmitInstrError( + CI, ValidationRule::InstrLinAlgMatrixLoadThreadRequiresBAB); } } @@ -1188,115 +2152,119 @@ static void ValidateLinAlgMatrixAccumulate(CallInst *CI, ValidationContext &ValCtx) { ValidateLinAlgOpReturnMatrix(CI, ValCtx); ValidateLinAlgOpParameters(CI, ValCtx); - + DxilInst_LinAlgMatrixAccumulate Op(CI); Type *RetMatTy = CI->getType(); - Type *LHSMatTy = CI->getArgOperand(1)->getType(); - Type *RHSMatTy = CI->getArgOperand(2)->getType(); - assert(dxilutil::IsHLSLLinAlgMatrixType(RetMatTy) && - dxilutil::IsHLSLLinAlgMatrixType(LHSMatTy) && - dxilutil::IsHLSLLinAlgMatrixType(RHSMatTy) && "Must be LinAlg types"); + Type *LHSMatTy = Op.get_matrixLHS()->getType(); + Type *RHSMatTy = Op.get_matrixRHS()->getType(); // Ret and LHS must have the exact same type if (RetMatTy != LHSMatTy) { StructType *RetST = cast(RetMatTy); StructType *LHSST = cast(LHSMatTy); - ValCtx.EmitInstrFormatError(CI, - ValidationRule::InstrLinAlgMatrixNotExactMatch, - {RetST->getName(), LHSST->getName()}); + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixNotExactMatch, + {"Return", RetST->getName(), "arg 1", LHSST->getName()}); } - auto RetIt = ValCtx.LinAlgTargetTypeMap.find(RetMatTy); - auto RHSIt = ValCtx.LinAlgTargetTypeMap.find(RHSMatTy); - if (RetIt == ValCtx.LinAlgTargetTypeMap.end()) + + std::optional RetMat = GetCheckedLATT(RetMatTy, ValCtx); + if (!RetMat) return; - if (RHSIt == ValCtx.LinAlgTargetTypeMap.end()) + std::optional LHSMat = GetCheckedLATT(LHSMatTy, ValCtx); + if (!LHSMat) + return; + std::optional RHSMat = GetCheckedLATT(RHSMatTy, ValCtx); + if (!RHSMat) return; - LinAlgTargetType RetLATT = RetIt->second; - LinAlgTargetType RHSLATT = RHSIt->second; - if (RetLATT.Use != DXIL::MatrixUse::Accumulator) + if (RetMat->Use != DXIL::MatrixUse::Accumulator) ValCtx.EmitInstrFormatError( CI, ValidationRule::InstrLinAlgMatrixUseMismatch, - {MatrixUseToString(RetLATT.Use), "Accumulator"}); + {"Return", MatrixUseToString(RetMat->Use), "Accumulator"}); - if (RHSLATT.Use == DXIL::MatrixUse::Accumulator) - ValCtx.EmitInstrFormatError(CI, - ValidationRule::InstrLinAlgMatrixUseMismatch2, - {MatrixUseToString(RHSLATT.Use), "A", "B"}); + if (RHSMat->Use != DXIL::MatrixUse::A && RHSMat->Use != DXIL::MatrixUse::B) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixUseMismatch2, + {"Arg 2", MatrixUseToString(RHSMat->Use), "A", "B"}); - if (RetLATT.Scope != RHSLATT.Scope) - ValCtx.EmitInstrFormatError(CI, - ValidationRule::InstrLinAlgMatrixScopeMismatch, - {MatrixScopeToString(RHSLATT.Scope), - MatrixScopeToString(RetLATT.Scope)}); + if (RetMat->Scope != RHSMat->Scope) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrix2PartsMustMatch, + {"Return", "scope", MatrixScopeToString(RetMat->Scope), "Arg 2", + "scope", MatrixScopeToString(RHSMat->Scope)}); - if (RetLATT.Scope == DXIL::MatrixScope::Thread) + if (RHSMat->Scope != DXIL::MatrixScope::Wave && + RHSMat->Scope != DXIL::MatrixScope::ThreadGroup) ValCtx.EmitInstrFormatError( - CI, ValidationRule::InstrLinAlgMatrixScopeNotAllowed, - {"Thread", "LinAlgMatrixAccumulate"}); + CI, ValidationRule::InstrLinAlgMatrixScopeMismatch2, + {"Arg 2", MatrixScopeToString(RHSMat->Scope), "Wave", "ThreadGroup"}); - if (RetLATT.M != RHSLATT.M || RetLATT.N != RHSLATT.N) + if (RetMat->Scope != DXIL::MatrixScope::Wave && + RetMat->Scope != DXIL::MatrixScope::ThreadGroup) ValCtx.EmitInstrFormatError( - CI, ValidationRule::InstrLinAlgMatrixDimMismatch, - {std::to_string(RHSLATT.M), std::to_string(RHSLATT.N), - std::to_string(RetLATT.M), std::to_string(RetLATT.N)}); + CI, ValidationRule::InstrLinAlgMatrixScopeMismatch2, + {"Return", MatrixScopeToString(RetMat->Scope), "Wave", "ThreadGroup"}); + + if (RetMat->M != RHSMat->M || RetMat->N != RHSMat->N) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrix2PartsMustMatch, + {"Arg 2", "dimension", + std::to_string(RHSMat->M) + "x" + std::to_string(RHSMat->N), "return", + "dimension", + std::to_string(RetMat->M) + "x" + std::to_string(RetMat->N)}); } static void ValidateLinAlgCopyConvertMatrix(CallInst *CI, ValidationContext &ValCtx) { ValidateLinAlgOpReturnMatrix(CI, ValCtx); ValidateLinAlgOpParameters(CI, ValCtx); + DxilInst_LinAlgCopyConvertMatrix Op(CI); - Type *DstMatTy = CI->getType(); - Type *SrcMatTy = CI->getArgOperand(1)->getType(); - assert(dxilutil::IsHLSLLinAlgMatrixType(DstMatTy) && - dxilutil::IsHLSLLinAlgMatrixType(SrcMatTy) && "Must be LinAlg types"); - - Value *TransposeOp = CI->getArgOperand(2); - ConstantInt *TransposeCI = dyn_cast(TransposeOp); - bool Transpose = false; - - if (TransposeCI) - Transpose = TransposeCI->isOne(); - else - ValCtx.EmitInstrFormatError(CI, ValidationRule::InstrOpConst, - {"Transpose", "LinAlgCopyConvertMatrix"}); - - auto DstIt = ValCtx.LinAlgTargetTypeMap.find(DstMatTy); - auto SrcIt = ValCtx.LinAlgTargetTypeMap.find(SrcMatTy); - if (DstIt == ValCtx.LinAlgTargetTypeMap.end()) + std::optional DstMat = + GetCheckedLATT(CI->getType(), ValCtx); + if (!DstMat) return; - if (SrcIt == ValCtx.LinAlgTargetTypeMap.end()) + std::optional SrcMat = + GetCheckedLATT(Op.get_srcMatrix()->getType(), ValCtx); + if (!SrcMat) return; - LinAlgTargetType DstLATT = DstIt->second; - LinAlgTargetType SrcLATT = SrcIt->second; + std::optional Transpose = ValidateConstantIntGetValue( + CI, Op.get_transpose(), ValCtx, "Transpose", "LinAlgCopyConvertMatrix"); - if (DstLATT.Scope == DXIL::MatrixScope::Thread || - SrcLATT.Scope == DXIL::MatrixScope::Thread) + if (DstMat->Scope != DXIL::MatrixScope::Wave && + DstMat->Scope != DXIL::MatrixScope::ThreadGroup) ValCtx.EmitInstrFormatError( - CI, ValidationRule::InstrLinAlgMatrixScopeNotAllowed, - {"Thread", "LinAlgCopyConvertMatrix"}); + CI, ValidationRule::InstrLinAlgMatrixScopeMismatch2, + {"Destination", MatrixScopeToString(DstMat->Scope), "Wave", + "ThreadGroup"}); - if (DstLATT.Scope != SrcLATT.Scope) - ValCtx.EmitInstrFormatError(CI, - ValidationRule::InstrLinAlgMatrixScopeMismatch, - {MatrixScopeToString(DstLATT.Scope), - MatrixScopeToString(SrcLATT.Scope)}); + if (SrcMat->Scope != DXIL::MatrixScope::Wave && + SrcMat->Scope != DXIL::MatrixScope::ThreadGroup) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrixScopeMismatch2, + {"Source", MatrixScopeToString(SrcMat->Scope), "Wave", "ThreadGroup"}); + + if (DstMat->Scope != SrcMat->Scope) + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrix2PartsMustMatch, + {"Destination", "scope", MatrixScopeToString(DstMat->Scope), "source", + "scope", MatrixScopeToString(SrcMat->Scope)}); - unsigned DstM = DstLATT.M; - unsigned DstN = DstLATT.N; - unsigned SrcM = SrcLATT.M; - unsigned SrcN = SrcLATT.N; - if (Transpose) { - SrcM = SrcLATT.N; - SrcN = SrcLATT.M; + unsigned DstM = DstMat->M; + unsigned DstN = DstMat->N; + unsigned SrcM = SrcMat->M; + unsigned SrcN = SrcMat->N; + if (Transpose && *Transpose == 1) { + SrcM = SrcMat->N; + SrcN = SrcMat->M; } if (DstM != SrcM || DstN != SrcN) - ValCtx.EmitInstrFormatError(CI, - ValidationRule::InstrLinAlgMatrixDimMismatch, - {std::to_string(DstM), std::to_string(DstN), - std::to_string(SrcM), std::to_string(SrcN)}); + ValCtx.EmitInstrFormatError( + CI, ValidationRule::InstrLinAlgMatrix2PartsMustMatch, + {"Destination", "dimension", + std::to_string(DstM) + "x" + std::to_string(DstN), "source", + "dimension", std::to_string(SrcM) + "x" + std::to_string(SrcN)}); } // Validate the type-defined mask compared to the store value mask which @@ -3317,20 +4285,20 @@ static bool IsLLVMInstructionAllowedForLib(Instruction &I, } // Shader model specific checks for valid LLVM instructions. -// Currently only checks for pre 6.9 usage of vector operations. -// Returns false if shader model is pre 6.9 and I represents a vector -// operation. Returns true otherwise. static bool IsLLVMInstructionAllowedForShaderModel(Instruction &I, ValidationContext &ValCtx) { - if (ValCtx.DxilMod.GetShaderModel()->IsSM69Plus()) + switch (I.getOpcode()) { + // Instructions added in SM 6.9. + case Instruction::InsertElement: + case Instruction::ExtractElement: + case Instruction::ShuffleVector: + return ValCtx.DxilMod.GetShaderModel()->IsSM69Plus(); + // Instructions added in SM 6.10. + case Instruction::InsertValue: + return ValCtx.DxilMod.GetShaderModel()->IsSM610Plus(); + default: return true; - unsigned Opcode = I.getOpcode(); - if (Opcode == Instruction::InsertElement || - Opcode == Instruction::ExtractElement || - Opcode == Instruction::ShuffleVector) - return false; - - return true; + } } static void ValidateFunctionBody(Function *F, ValidationContext &ValCtx) { @@ -3472,15 +4440,21 @@ static void ValidateFunctionBody(Function *F, ValidationContext &ValCtx) { for (Value *op : I.operands()) { if (isa(op)) { - bool LegalUndef = isa(&I); - if (isa(&I)) { + bool LegalUndef = false; + switch (I.getOpcode()) { + case Instruction::PHI: + LegalUndef = true; + break; + case Instruction::InsertElement: + case Instruction::InsertValue: + case Instruction::Store: LegalUndef = op == I.getOperand(0); - } - if (isa(&I)) { + break; + case Instruction::ShuffleVector: LegalUndef = op == I.getOperand(1); - } - if (isa(&I)) { - LegalUndef = op == I.getOperand(0); + break; + default: + break; } if (!LegalUndef) @@ -6053,6 +7027,12 @@ static void ValidateEntryProps(ValidationContext &ValCtx, ValidateWaveSize(ValCtx, EntryProps, F); + const ShaderModel *SM = ValCtx.DxilMod.GetShaderModel(); + if (Props.IsNode() && SM->IsSM610Plus()) + ValCtx.EmitFnFormatError( + F, ValidationRule::SmShaderStage, + {ShaderModel::GetKindName(ShaderType), SM->GetName()}); + if (ShaderType == DXIL::ShaderKind::Compute || Props.IsNode()) { unsigned X = Props.numThreads[0]; unsigned Y = Props.numThreads[1]; diff --git a/lib/DxilValidation/DxilValidationUtils.cpp b/lib/DxilValidation/DxilValidationUtils.cpp index 324853778d..d6fdf44937 100644 --- a/lib/DxilValidation/DxilValidationUtils.cpp +++ b/lib/DxilValidation/DxilValidationUtils.cpp @@ -665,6 +665,8 @@ llvm::StringRef ComponentTypeToString(DXIL::ComponentType CT) { return "F8_E4M3FN"; case DXIL::ComponentType::F8_E5M2: return "F8_E5M2"; + case DXIL::ComponentType::BFloat16: + return "BFloat16"; default: return "Unknown ComponentType"; } @@ -715,4 +717,51 @@ llvm::StringRef MatrixLayoutToString(DXIL::MatrixLayout ML) { } } +std::string TypeToString(llvm::Type *Ty) { + std::string S; + llvm::raw_string_ostream OS(S); + Ty->print(OS); + return OS.str(); +} + +bool IsComponentTypeSameNativeType(DXIL::ComponentType CT, llvm::Type *Ty) { + switch (CT) { + case DXIL::ComponentType::I16: + case DXIL::ComponentType::U16: + return Ty->isIntegerTy(16); + case DXIL::ComponentType::I32: + case DXIL::ComponentType::U32: + return Ty->isIntegerTy(32); + case DXIL::ComponentType::I64: + case DXIL::ComponentType::U64: + return Ty->isIntegerTy(64); + case DXIL::ComponentType::F16: + return Ty->isHalfTy(); + case DXIL::ComponentType::F32: + return Ty->isFloatTy(); + case DXIL::ComponentType::F64: + return Ty->isDoubleTy(); + // All other CTs cannot be represented in a native type + default: + return false; + } +} + +bool IsComponentTypeNative(DXIL::ComponentType CT) { + switch (CT) { + case DXIL::ComponentType::I16: + case DXIL::ComponentType::U16: + case DXIL::ComponentType::I32: + case DXIL::ComponentType::U32: + case DXIL::ComponentType::I64: + case DXIL::ComponentType::U64: + case DXIL::ComponentType::F16: + case DXIL::ComponentType::F32: + case DXIL::ComponentType::F64: + return true; + default: + return false; + } +} + } // namespace hlsl diff --git a/lib/DxilValidation/DxilValidationUtils.h b/lib/DxilValidation/DxilValidationUtils.h index 1e924182c1..e854ad97c5 100644 --- a/lib/DxilValidation/DxilValidationUtils.h +++ b/lib/DxilValidation/DxilValidationUtils.h @@ -163,4 +163,10 @@ llvm::StringRef MatrixScopeToString(DXIL::MatrixScope MS); llvm::StringRef MatrixUseToString(DXIL::MatrixUse MU); llvm::StringRef MatrixLayoutToString(DXIL::MatrixLayout ML); + +std::string TypeToString(llvm::Type *Ty); + +bool IsComponentTypeSameNativeType(DXIL::ComponentType CT, llvm::Type *Ty); + +bool IsComponentTypeNative(DXIL::ComponentType CT); } // namespace hlsl diff --git a/lib/HLSL/DxilPreparePasses.cpp b/lib/HLSL/DxilPreparePasses.cpp index 81b9dff4ca..eb7d5b7124 100644 --- a/lib/HLSL/DxilPreparePasses.cpp +++ b/lib/HLSL/DxilPreparePasses.cpp @@ -1717,7 +1717,7 @@ class DxilTrimTargetTypes : public ModulePass { continue; // Currently only LinAlgMatrix ops use target types. - if (!OP::IsDxilOpLinAlgFuncName(F.getName())) + if (!OP::IsDxilOpLinAlgFunc(&F)) continue; llvm::Type *RetTy = F.getReturnType(); diff --git a/lib/HLSL/HLOperationLower.cpp b/lib/HLSL/HLOperationLower.cpp index 30c27f5391..20a2c24e50 100644 --- a/lib/HLSL/HLOperationLower.cpp +++ b/lib/HLSL/HLOperationLower.cpp @@ -6783,13 +6783,14 @@ Value *TranslateLinAlgFillMatrix(CallInst *CI, IntrinsicOp IOP, Value *MatrixPtr = CI->getArgOperand(1); DXASSERT_NOMSG(isa(MatrixPtr->getType())); Type *MatrixType = MatrixPtr->getType()->getPointerElementType(); - Value *Scalar = CI->getArgOperand(2); + Value *IsInputSigned = CI->getArgOperand(2); + Value *Scalar = CI->getArgOperand(3); Constant *OpArg = HlslOp->GetU32Const((unsigned)OpCode); Function *DxilFunc = HlslOp->GetOpFunc(OpCode, {MatrixType, Scalar->getType()}); - Value *Matrix = Builder.CreateCall(DxilFunc, {OpArg, Scalar}); + Value *Matrix = Builder.CreateCall(DxilFunc, {OpArg, IsInputSigned, Scalar}); Builder.CreateStore(Matrix, MatrixPtr); return nullptr; @@ -6913,14 +6914,16 @@ Value *TranslateLinAlgMatrixOuterProduct( Value *MatrixPtr = CI->getArgOperand(1); DXASSERT_NOMSG(isa(MatrixPtr->getType())); Type *MatrixType = MatrixPtr->getType()->getPointerElementType(); - Value *VecA = CI->getArgOperand(2); - Value *VecB = CI->getArgOperand(3); + Value *IsInputSigned = CI->getArgOperand(2); + Value *VecA = CI->getArgOperand(3); + Value *VecB = CI->getArgOperand(4); Constant *OpArg = HlslOp->GetU32Const((unsigned)OpCode); Function *DxilFunc = HlslOp->GetOpFunc(OpCode, {MatrixType, VecA->getType(), VecB->getType()}); - Value *Matrix = Builder.CreateCall(DxilFunc, {OpArg, VecA, VecB}); + Value *Matrix = + Builder.CreateCall(DxilFunc, {OpArg, IsInputSigned, VecA, VecB}); Builder.CreateStore(Matrix, MatrixPtr); return nullptr; @@ -7157,10 +7160,9 @@ Value *TranslateLinAlgMatrixAccumToMemory( Value *Matrix = CI->getArgOperand(1); Value *Arr = CI->getArgOperand(2); - Value *TargetType = CI->getArgOperand(3); - Value *Offset = CI->getArgOperand(4); - Value *Stride = CI->getArgOperand(5); - Value *Layout = CI->getArgOperand(6); + Value *Offset = CI->getArgOperand(3); + Value *Stride = CI->getArgOperand(4); + Value *Layout = CI->getArgOperand(5); Value *Zero = Builder.getInt32(0); Value *ArrPtr = Builder.CreateGEP(Arr, {Zero, Zero}); @@ -7169,8 +7171,8 @@ Value *TranslateLinAlgMatrixAccumToMemory( Constant *OpArg = HlslOp->GetU32Const((unsigned)OpCode); Function *DxilFunc = HlslOp->GetOpFunc(OpCode, {Matrix->getType(), ArrEltTy}); - return Builder.CreateCall( - DxilFunc, {OpArg, Matrix, ArrPtr, TargetType, Offset, Stride, Layout}); + return Builder.CreateCall(DxilFunc, + {OpArg, Matrix, ArrPtr, Offset, Stride, Layout}); } Value *TranslateLinAlgConvert(CallInst *CI, IntrinsicOp IOP, OP::OpCode OpCode, @@ -7959,51 +7961,51 @@ constexpr IntrinsicLower gLowerTable[] = { TranslateHitObjectTriangleObjectPositions, DXIL::OpCode::HitObject_TriangleObjectPosition}, - {IntrinsicOp::IOP___builtin_LinAlg_CopyConvertMatrix, + {IntrinsicOp::IOP_Dx__builtin_LinAlg_CopyConvertMatrix, TranslateLinAlgCopyConvertMatrix, DXIL::OpCode::LinAlgCopyConvertMatrix}, - {IntrinsicOp::IOP___builtin_LinAlg_FillMatrix, TranslateLinAlgFillMatrix, + {IntrinsicOp::IOP_Dx__builtin_LinAlg_FillMatrix, TranslateLinAlgFillMatrix, DXIL::OpCode::LinAlgFillMatrix}, - {IntrinsicOp::IOP___builtin_LinAlg_MatrixGetCoordinate, + {IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixGetCoordinate, TranslateLinAlgMatrixGetCoordinate, DXIL::OpCode::LinAlgMatrixGetCoordinate}, - {IntrinsicOp::IOP___builtin_LinAlg_MatrixGetElement, + {IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixGetElement, TranslateLinAlgMatrixGetElement, DXIL::OpCode::LinAlgMatrixGetElement}, - {IntrinsicOp::IOP___builtin_LinAlg_MatrixLength, TrivialUnaryOperation, + {IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixLength, TrivialUnaryOperation, DXIL::OpCode::LinAlgMatrixLength}, - {IntrinsicOp::IOP___builtin_LinAlg_MatrixLoadFromDescriptor, + {IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixLoadFromDescriptor, TranslateLinAlgMatrixLoadFromDescriptor, DXIL::OpCode::LinAlgMatrixLoadFromDescriptor}, - {IntrinsicOp::IOP___builtin_LinAlg_MatrixLoadFromMemory, + {IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixLoadFromMemory, TranslateLinAlgMatrixLoadFromMemory, DXIL::OpCode::LinAlgMatrixLoadFromMemory}, - {IntrinsicOp::IOP___builtin_LinAlg_MatrixSetElement, + {IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixSetElement, TranslateLinAlgMatrixSetElement, DXIL::OpCode::LinAlgMatrixSetElement}, - {IntrinsicOp::IOP___builtin_LinAlg_MatrixStoreToDescriptor, + {IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixStoreToDescriptor, TranslateLinAlgMatrixAccumStoreToDescriptor, DXIL::OpCode::LinAlgMatrixStoreToDescriptor}, - {IntrinsicOp::IOP___builtin_LinAlg_MatrixStoreToMemory, + {IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixStoreToMemory, TranslateLinAlgMatrixStoreToMemory, DXIL::OpCode::LinAlgMatrixStoreToMemory}, - {IntrinsicOp::IOP___builtin_LinAlg_MatrixAccumulate, + {IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixAccumulate, TranslateLinAlgMatrixAccumulate, DXIL::OpCode::LinAlgMatrixAccumulate}, - {IntrinsicOp::IOP___builtin_LinAlg_MatrixMatrixMultiply, + {IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixMatrixMultiply, TranslateLinAlgMatrixMatrixMultiply, DXIL::OpCode::LinAlgMatrixMultiply}, - {IntrinsicOp::IOP___builtin_LinAlg_MatrixMatrixMultiplyAccumulate, + {IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixMatrixMultiplyAccumulate, TranslateLinAlgMatrixMatrixMultiplyAccumulate, DXIL::OpCode::LinAlgMatrixMultiplyAccumulate}, - {IntrinsicOp::IOP___builtin_LinAlg_MatrixQueryAccumulatorLayout, + {IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixQueryAccumulatorLayout, TrivialNoArgOperation, DXIL::OpCode::LinAlgMatrixQueryAccumulatorLayout}, - {IntrinsicOp::IOP___builtin_LinAlg_MatrixAccumulateToDescriptor, + {IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixAccumulateToDescriptor, TranslateLinAlgMatrixAccumStoreToDescriptor, DXIL::OpCode::LinAlgMatrixAccumulateToDescriptor}, - {IntrinsicOp::IOP___builtin_LinAlg_MatrixAccumulateToMemory, + {IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixAccumulateToMemory, TranslateLinAlgMatrixAccumToMemory, DXIL::OpCode::LinAlgMatrixAccumulateToMemory}, - {IntrinsicOp::IOP___builtin_LinAlg_MatrixOuterProduct, + {IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixOuterProduct, TranslateLinAlgMatrixOuterProduct, DXIL::OpCode::LinAlgMatrixOuterProduct}, - {IntrinsicOp::IOP___builtin_LinAlg_MatrixVectorMultiply, + {IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixVectorMultiply, TranslateLinAlgMatVecMul, DXIL::OpCode::LinAlgMatVecMul}, - {IntrinsicOp::IOP___builtin_LinAlg_MatrixVectorMultiplyAdd, + {IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixVectorMultiplyAdd, TranslateLinAlgMatVecMulAdd, DXIL::OpCode::LinAlgMatVecMulAdd}, {IntrinsicOp::IOP_DebugBreak, TrivialNoArgOperation, @@ -8011,9 +8013,9 @@ constexpr IntrinsicLower gLowerTable[] = { {IntrinsicOp::IOP_DxIsDebuggingEnabled, TranslateWaveToVal, DXIL::OpCode::IsDebuggingEnabled}, - {IntrinsicOp::IOP___builtin_LinAlg_Convert, TranslateLinAlgConvert, + {IntrinsicOp::IOP_Dx__builtin_LinAlg_Convert, TranslateLinAlgConvert, DXIL::OpCode::LinAlgConvert}, - {IntrinsicOp::IOP___builtin_LinAlg_VectorAccumulateToDescriptor, + {IntrinsicOp::IOP_Dx__builtin_LinAlg_VectorAccumulateToDescriptor, TranslateLinAlgVectorAccumulateToDescriptor, DXIL::OpCode::LinAlgVectorAccumulateToDescriptor}, }; diff --git a/lib/HLSL/WaveSensitivityAnalysis.cpp b/lib/HLSL/WaveSensitivityAnalysis.cpp index c87230dbf5..3bf034d17f 100644 --- a/lib/HLSL/WaveSensitivityAnalysis.cpp +++ b/lib/HLSL/WaveSensitivityAnalysis.cpp @@ -75,7 +75,10 @@ void WaveSensitivityAnalyzer::Analyze(Function *F) { // If any phis with explored preds remain unknown // it has to be in a loop that don't include wave sensitivity // Update each as such and redo Analyze to mark the descendents - while (!UnknownPhis.empty() || !InstWorkList.empty() || !BBWorkList.empty()) { + while (!UnknownPhis.empty()) { + assert(InstWorkList.empty() && BBWorkList.empty()); + std::vector DeferredPhis; + bool ResolvedPhi = false; while (!UnknownPhis.empty()) { PHINode *Phi = UnknownPhis.back(); UnknownPhis.pop_back(); @@ -100,10 +103,32 @@ void WaveSensitivityAnalyzer::Analyze(Function *F) { } } #endif - if (allPredsVisited) + if (allPredsVisited) { UpdateInst(Phi, KnownNotSensitive); + ResolvedPhi = true; + } else { + // This phi is still unknown. Try again later. + DeferredPhis.push_back(Phi); + } } } + UnknownPhis = std::move(DeferredPhis); + + // If we did not resolve any phis, then we have reached a steady state, and + // we can stop. + if (!ResolvedPhi) + break; + Analyze(); + } + + if (!UnknownPhis.empty()) { + // There are cycles of instructions that are still unknown. They must all + // contain a phi. Mark those phis as not sensitive, and do one more analysis + // to mark the whole cycle as not sensitive. + for (PHINode *Phi : UnknownPhis) { + if (Unknown == GetInstState(Phi)) + UpdateInst(Phi, KnownNotSensitive); + } Analyze(); } #ifndef NDEBUG diff --git a/lib/Transforms/IPO/PassManagerBuilder.cpp b/lib/Transforms/IPO/PassManagerBuilder.cpp index 46dc5508b9..38d7adb309 100644 --- a/lib/Transforms/IPO/PassManagerBuilder.cpp +++ b/lib/Transforms/IPO/PassManagerBuilder.cpp @@ -308,10 +308,12 @@ void PassManagerBuilder::addHLSLPasses(legacy::PassManagerBase &MPM) { // struct members. // Needs to happen before resources are lowered and before HL // module is gone. - MPM.add(createDxilLoopUnrollPass(1024, HLSLOnlyWarnOnUnrollFail, StructurizeLoopExitsForUnroll)); + MPM.add(createDxilLoopUnrollPass(1024, HLSLOnlyWarnOnUnrollFail, + StructurizeLoopExitsForUnroll, + HLSLUnrollCountIsHint)); - // Default unroll pass. This is purely for optimizing loops without - // attributes. + // Default unroll pass. In HLSL 202x, this consumes [unroll(N)] as a + // partial-unroll hint; it otherwise optimizes loops without attributes. if (OptLevel > 2) { MPM.add(createLoopUnrollPass(-1, -1, -1, -1, StructurizeLoopExitsForUnroll)); } diff --git a/lib/Transforms/Scalar/DxilLoopUnroll.cpp b/lib/Transforms/Scalar/DxilLoopUnroll.cpp index a48896f4a7..c59e827456 100644 --- a/lib/Transforms/Scalar/DxilLoopUnroll.cpp +++ b/lib/Transforms/Scalar/DxilLoopUnroll.cpp @@ -109,12 +109,15 @@ class DxilLoopUnroll : public LoopPass { unsigned MaxIterationAttempt = 0; bool OnlyWarnOnFail = false; bool StructurizeLoopExits = false; + bool UnrollCountIsHint = false; DxilLoopUnroll(unsigned MaxIterationAttempt = 1024, - bool OnlyWarnOnFail = false, bool StructurizeLoopExits = false) + bool OnlyWarnOnFail = false, bool StructurizeLoopExits = false, + bool UnrollCountIsHint = false) : LoopPass(ID), MaxIterationAttempt(MaxIterationAttempt), OnlyWarnOnFail(OnlyWarnOnFail), - StructurizeLoopExits(StructurizeLoopExits) { + StructurizeLoopExits(StructurizeLoopExits), + UnrollCountIsHint(UnrollCountIsHint) { initializeDxilLoopUnrollPass(*PassRegistry::getPassRegistry()); } StringRef getPassName() const override { return "Dxil Loop Unroll"; } @@ -138,12 +141,14 @@ class DxilLoopUnroll : public LoopPass { false); GetPassOptionBool(O, "OnlyWarnOnFail", &OnlyWarnOnFail, false); GetPassOptionBool(O, "StructurizeLoopExits", &StructurizeLoopExits, false); + GetPassOptionBool(O, "UnrollCountIsHint", &UnrollCountIsHint, false); } void dumpConfig(raw_ostream &OS) override { LoopPass::dumpConfig(OS); OS << ",MaxIterationAttempt=" << MaxIterationAttempt; OS << ",OnlyWarnOnFail=" << OnlyWarnOnFail; OS << ",StructurizeLoopExits=" << StructurizeLoopExits; + OS << ",UnrollCountIsHint=" << UnrollCountIsHint; } void RecursivelyRemoveLoopOnSuccess(LPPassManager &LPM, Loop *L); void RecursivelyRecreateSubLoopForIteration(LPPassManager &LPM, LoopInfo *LI, @@ -790,6 +795,8 @@ bool DxilLoopUnroll::runOnLoop(Loop *L, LPPassManager &LPM) { return false; } ExplicitUnrollCount = (unsigned)ExplicitUnrollCountSigned; + if (UnrollCountIsHint) + return false; } if (!IsLoopSafeToClone(L)) @@ -1256,9 +1263,10 @@ bool DxilLoopUnroll::doFinalization() { Pass *llvm::createDxilLoopUnrollPass(unsigned MaxIterationAttempt, bool OnlyWarnOnFail, - bool StructurizeLoopExits) { + bool StructurizeLoopExits, + bool UnrollCountIsHint) { return new DxilLoopUnroll(MaxIterationAttempt, OnlyWarnOnFail, - StructurizeLoopExits); + StructurizeLoopExits, UnrollCountIsHint); } INITIALIZE_PASS_BEGIN(DxilLoopUnroll, "dxil-loop-unroll", "Dxil Unroll loops", diff --git a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp index d80a678651..11421f5067 100644 --- a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp +++ b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp @@ -1323,6 +1323,10 @@ void MarkUnsafe(AllocaInfo &I, Instruction *User) { DEBUG(dbgs() << " Transformation preventing inst: " << *User << '\n'); } +static bool isValidVectorIndex(const ConstantInt *Index, unsigned NumElements) { + return !Index->isNegative() && Index->getValue().ult(NumElements); +} + /// isSafeGEP - Check if a GEP instruction can be handled for scalar /// replacement. It is safe when all the indices are constant, in-bounds /// references, and when the resulting offset corresponds to an element within @@ -1363,6 +1367,8 @@ void isSafeGEP(GetElementPtrInst *GEPI, uint64_t &Offset, AllocaInfo &Info) { } // Allow dynamic indexing ConstantInt *IdxVal = dyn_cast(GEPIt.getOperand()); + if (GEPIt->isVectorTy() && IdxVal && !isValidVectorIndex(IdxVal, arraySize)) + return MarkUnsafe(Info, GEPI); if (!IdxVal) { // for dynamic index, use array size - 1 to check the offset *indicesIt = Constant::getIntegerValue( @@ -1386,6 +1392,8 @@ void isSafeGEP(GetElementPtrInst *GEPI, uint64_t &Offset, AllocaInfo &Info) { } // Allow dynamic indexing ConstantInt *IdxVal = dyn_cast(GEPIt.getOperand()); + if (GEPIt->isVectorTy() && IdxVal && !isValidVectorIndex(IdxVal, arraySize)) + return MarkUnsafe(Info, GEPI); if (!IdxVal) { // for dynamic index, use array size - 1 to check the offset *indicesIt = Constant::getIntegerValue( @@ -1690,7 +1698,10 @@ bool hasDynamicVectorIndexing(Value *V) { for (; GEPIt != E; ++GEPIt) { if (isa(*GEPIt)) { Value *VecIdx = GEPIt.getOperand(); - if (!isa(VecIdx)) + ConstantInt *ConstantVecIdx = dyn_cast(VecIdx); + if (!ConstantVecIdx || + !isValidVectorIndex(ConstantVecIdx, + GEPIt->getVectorNumElements())) return true; } } diff --git a/tools/clang/include/clang/AST/HlslTypes.h b/tools/clang/include/clang/AST/HlslTypes.h index cc72c51048..547eed0ae1 100644 --- a/tools/clang/include/clang/AST/HlslTypes.h +++ b/tools/clang/include/clang/AST/HlslTypes.h @@ -545,6 +545,7 @@ bool DoesTypeDefineOverloadedOperator(clang::QualType typeWithOperator, clang::OverloadedOperatorKind opc, clang::QualType paramType); bool IsPatchConstantFunctionDecl(const clang::FunctionDecl *FD); +bool IsTypeDeducibleWithAuto(clang::QualType type); #ifdef ENABLE_SPIRV_CODEGEN bool IsVKBufferPointerType(clang::QualType type); diff --git a/tools/clang/include/clang/Basic/Attr.td b/tools/clang/include/clang/Basic/Attr.td index 21b57c8934..2d298fb056 100644 --- a/tools/clang/include/clang/Basic/Attr.td +++ b/tools/clang/include/clang/Basic/Attr.td @@ -1189,8 +1189,7 @@ def HLSLSubObject : InheritableAttr { } // Marks builtin record types that have no deducible value form, so 'auto' must -// not infer them: the inner indexer objects behind .mips / .sample, and the -// subobject types used to configure DXR state objects. +// not infer them. def HLSLNonAutoDeducible : InheritableAttr { let Spellings = []; // No spellings! let Subjects = SubjectList<[CXXRecord]>; diff --git a/tools/clang/include/clang/Basic/DiagnosticCommonKinds.td b/tools/clang/include/clang/Basic/DiagnosticCommonKinds.td index f457cd8c1c..0d70e261c0 100644 --- a/tools/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/tools/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -68,6 +68,15 @@ def err_invalid_storage_class_in_func_decl : Error< def err_expected_namespace_name : Error<"expected namespace name">; // HLSL Change Starts def err_hlsl_variadic_templates : Error<"variadic templates are not supported in HLSL">; +def warn_hlsl_2026_effects + : Warning<"%select{possible |}1effect %select{annotation|sampler_state " + "assignment|state block|technique|object}0 ignored - " + "effect syntax is deprecated and will be removed in HLSL 2026">, + InGroup; +def warn_hlsl_2026_removed_keyword + : Warning<"'%0' is ignored and will be removed in HLSL 2026">, + InGroup, + DefaultIgnore; // HLSL Change Ends def ext_variadic_templates : ExtWarn< "variadic templates are a C++11 extension">, InGroup; diff --git a/tools/clang/include/clang/Basic/DiagnosticGroups.td b/tools/clang/include/clang/Basic/DiagnosticGroups.td index f0d75709f1..196577d5a1 100644 --- a/tools/clang/include/clang/Basic/DiagnosticGroups.td +++ b/tools/clang/include/clang/Basic/DiagnosticGroups.td @@ -806,7 +806,21 @@ def HLSLParameterUsage : DiagGroup<"parameter-usage">; def HLSLAvailability: DiagGroup<"hlsl-availability">; def HLSLAvailabilityConstant: DiagGroup<"hlsl-availability-constant">; def HLSLBarrier : DiagGroup<"hlsl-barrier">; +def HLSLBufferInitializer : DiagGroup<"hlsl-buffer-initializer">; +def HLSLGroupSharedInitializer : + DiagGroup<"hlsl-groupshared-initializer">; + +// HLSL 2026 compatibility warnings: these warn on code in older language modes +// that changes meaning or becomes illegal in HLSL 2026. def HLSLLegacyLiterals : DiagGroup<"hlsl-legacy-literal">; +def HLSL2026RemovedKeywords : DiagGroup<"hlsl-2026-removed-keywords">; +def HLSL2026Compat + : DiagGroup<"hlsl-2026-compat", [HLSLLegacyLiterals, HLSLEffectsSyntax, + HLSL2026RemovedKeywords]>; + def HLSLGroupshared202x : DiagGroup<"hlsl-groupshared-202x">; -def HLSL202xExtensions : DiagGroup<"hlsl-202x-extensions", [HLSLGroupshared202x]>; +def HLSLFoldExpressions : DiagGroup<"hlsl-fold-expressions">; +def HLSL202xExtensions + : DiagGroup<"hlsl-202x-extensions", [HLSLFoldExpressions, + HLSLGroupshared202x]>; // HLSL Change Ends diff --git a/tools/clang/include/clang/Basic/DiagnosticParseKinds.td b/tools/clang/include/clang/Basic/DiagnosticParseKinds.td index ac4bad2cc2..ef6c15e62a 100644 --- a/tools/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/tools/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -279,6 +279,10 @@ def warn_cxx98_compat_generalized_initializer_lists : Warning< InGroup, DefaultIgnore; def err_hlsl_compat_generalized_initializer_lists : Error< "generalized initializer lists are incompatible with HLSL">; +def warn_hlsl_fold_expression + : Warning<"fold expressions are a C++17 extension and are not part of " + "standard HLSL">, + InGroup; def err_init_list_bin_op : Error<"initializer list cannot be used on the " "%select{left|right}0 hand side of operator '%1'">; def warn_cxx98_compat_trailing_return_type : Warning< @@ -1009,18 +1013,8 @@ def err_hlsl_nested_namespace_definition : Error< "nested namespace definition must define each namespace separately">; def warn_hlsl_minprecision_promotion : Warning < "%0 is promoted to %1">; -def warn_hlsl_effect_annotation : Warning < - "possible effect annotation ignored - effect syntax is deprecated">, - InGroup< HLSLEffectsSyntax >; -def warn_hlsl_effect_sampler_state : Warning < - "effect sampler_state assignment ignored - effect syntax is deprecated">, - InGroup< HLSLEffectsSyntax >; -def warn_hlsl_effect_state_block : Warning < - "effect state block ignored - effect syntax is deprecated. To use braces as an initializer use them with equal signs.">, - InGroup< HLSLEffectsSyntax >; -def warn_hlsl_effect_technique : Warning < - "effect technique ignored - effect syntax is deprecated">, - InGroup< HLSLEffectsSyntax >; +def note_hlsl_effects_use_equal + : Note<"To use braces as an initializer use them with equal signs">; def warn_hlsl_semantic_identifier_collision : Warning < "'%0' interpreted as semantic; previous definition(s) ignored">, InGroup< HLSLSemanticIdentifierCollision >; @@ -1028,6 +1022,9 @@ def err_hlsl_expected_hlsl_attribute : Error < "Unexpected '(' in semantic annotation. Did you mean 'packoffset()' or 'register()'?">; def err_hlsl_enum : Error< "enum is unsupported in HLSL before 2017">; +def err_hlsl_const_member_function_202x + : Error<"const-qualified member functions are unsupported in HLSL before " + "202x">; def warn_hlsl_new_feature : Warning < "%0 is a HLSL %1 feature, and is available in older versions as a non-portable extension.">; diff --git a/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td b/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td index dba557e509..7d798010d9 100644 --- a/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7575,6 +7575,14 @@ def err_hlsl_packoffset_requires_cbuffer : Error< "packoffset is only allowed in a constant buffer">; def warn_hlsl_packoffset_mix : Warning< "cannot mix packoffset elements with nonpackoffset elements in a cbuffer">; +def warn_hlsl_buffer_initializer : Warning< + "initializer for a variable in a %select{tbuffer|cbuffer}0 will be ignored">, + InGroup; +def err_hlsl_buffer_initializer : Error< + "variable in a %select{tbuffer|cbuffer}0 cannot have an initializer">; +def warn_hlsl_groupshared_initializer : Warning< + "initializer of 'groupshared' variable will be ignored">, + InGroup; def err_hlsl_packoffset_overlap : Error<"packoffset overlap between %0, %1">; def err_hlsl_register_semantics_conflicting : Error< "conflicting register semantics">; @@ -7682,6 +7690,29 @@ def warn_hlsl_builtin_constant_unavailable: Warning< def warn_hlsl_builtin_type_unavailable: Warning< "potential misuse of built-in type %0 in shader model %1; introduced" " in shader model %2">, DefaultError, InGroup; +def warn_hlsl_builtin_constant_removed + : Warning<"built-in constant %0 is unavailable in shader model %1; it was " + "removed" + " in shader model %2">, + InGroup; +def warn_hlsl_builtin_type_removed + : Warning< + "built-in type %0 is unavailable in shader model %1; it was removed" + " in shader model %2">, + DefaultError, + InGroup; +def warn_hlsl_intrinsic_removed + : Warning< + "intrinsic %0 potentially used by '%1' is unavailable; it was removed" + " in shader model %2">, + DefaultError, + InGroup; +def warn_hlsl_node_shader_removed + : Warning< + "node shaders and other Work Graphs functionality are not supported" + " when targeting shader model %0">, + DefaultError, + InGroup; def err_hlsl_unsupported_char_literal : Error< "unsupported style of char literal - use a single-character char-based literal">; def err_hlsl_unsupported_clipplane_argument_expression : Error< @@ -7825,11 +7856,8 @@ def warn_hlsl_unsupported_statement_for_switch_attribute : Warning< def warn_hlsl_unsupported_statement_for_loop_attribute : Warning< "attribute %0 can only be applied to 'for', 'while' and 'do' loop statements">, InGroup; -def err_hlsl_matrix_layout_wrong_type : Error< - "%0 can only be used with a matrix type">; -def warn_hlsl_effect_object : Warning < - "effect object ignored - effect syntax is deprecated">, - InGroup< HLSLEffectsSyntax >; +def err_hlsl_matrix_layout_wrong_type + : Error<"%0 can only be used with a matrix type">; def warn_hlsl_unused_call : Warning< "ignoring return value of function that only reads data">, InGroup; @@ -7906,6 +7934,9 @@ def err_hlsl_unsupported_object_context "entry function parameters|entry function return type|" "patch constant function parameters|patch constant function return type|" "payload parameters|attributes|builtin template parameters|structured buffers|global variables|groupshared variables}1">; +def err_hlsl_unsupported_declaration_in_buffer + : Error<"unsupported declaration %0 in %select{tbuffer|cbuffer}1 " + "declaration">; def err_hlsl_logical_binop_scalar : Error< "operands for short-circuiting logical binary operator must be scalar, for non-scalar types use '%select{and|or}0'">; def err_hlsl_ternary_scalar : Error< @@ -8059,6 +8090,9 @@ def err_hlsl_linalg_matrix_attribute_on_invalid_type : Error<"matrix attributes can only be applied to %0">; def err_hlsl_linalg_attributed_matrix_required : Error<"argument must be linear algebra matrix type">; +def err_hlsl_linalg_matrix_global_not_static + : Error<"global variable %0 containing a linear algebra matrix must be " + "declared 'static'">; def err_hlsl_linalg_unsupported_stage : Error< "builtin unavailable in shader stage '%0' (requires 'compute', 'mesh' or 'amplification')">; diff --git a/tools/clang/include/clang/Basic/LangOptions.h b/tools/clang/include/clang/Basic/LangOptions.h index 433b767c8d..e2495048a4 100644 --- a/tools/clang/include/clang/Basic/LangOptions.h +++ b/tools/clang/include/clang/Basic/LangOptions.h @@ -188,6 +188,13 @@ class LangOptions : public LangOptionsBase { return MSCompatibilityVersion >= MajorVersion * 10000000U; } + // HLSL Change Starts + /// Whether the active HLSL version rejects variadic templates. + bool HLSLDisallowsVariadicTemplates() const { + return HLSL && HLSLVersion < hlsl::LangStd::v202x; + } + // HLSL Change Ends + /// \brief Reset all of the options that are not considered when building a /// module. void resetNonModularOptions(); diff --git a/tools/clang/include/clang/Basic/TokenKinds.def b/tools/clang/include/clang/Basic/TokenKinds.def index 6933c965cf..565f74310d 100644 --- a/tools/clang/include/clang/Basic/TokenKinds.def +++ b/tools/clang/include/clang/Basic/TokenKinds.def @@ -349,7 +349,7 @@ CXX11_KEYWORD(constexpr , 0) CXX11_KEYWORD(decltype , 0) CXX11_KEYWORD(noexcept , 0) CXX11_KEYWORD(nullptr , 0) -CXX11_KEYWORD(static_assert , 0) +CXX11_KEYWORD(static_assert , KEYHLSL2026) // HLSL Change - 2026 adds static_assert CXX11_KEYWORD(thread_local , 0) // C++ concepts TS keywords @@ -494,10 +494,10 @@ KEYWORD(row_major , KEYHLSL) KEYWORD(in , KEYHLSL) KEYWORD(out , KEYHLSL) KEYWORD(inout , KEYHLSL) -KEYWORD(uniform , KEYHLSL) +KEYWORD(uniform , KEYHLSL | KEYHLSL2026_REMOVED) KEYWORD(precise , KEYHLSL) KEYWORD(center , KEYHLSL) -KEYWORD(shared , KEYHLSL) +KEYWORD(shared , KEYHLSL | KEYHLSL2026_REMOVED) KEYWORD(groupshared , KEYHLSL) KEYWORD(discard , KEYHLSL) KEYWORD(snorm , KEYHLSL) @@ -510,15 +510,15 @@ KEYWORD(triangleadj , KEYHLSL) KEYWORD(globallycoherent , KEYHLSL) KEYWORD(reordercoherent , KEYHLSL) KEYWORD(interface , KEYHLSL) -KEYWORD(sampler_state , KEYHLSL) -KEYWORD(technique , KEYHLSL) +KEYWORD(sampler_state , KEYHLSL | KEYHLSL2026_REMOVED) +KEYWORD(technique , KEYHLSL | KEYHLSL2026_REMOVED) KEYWORD(indices , KEYHLSL) KEYWORD(vertices , KEYHLSL) KEYWORD(primitives , KEYHLSL) KEYWORD(payload , KEYHLSL) -ALIAS("Technique", technique , KEYHLSL) -ALIAS("technique10", technique , KEYHLSL) -ALIAS("technique11", technique , KEYHLSL) +ALIAS("Technique", technique , KEYHLSL | KEYHLSL2026_REMOVED) +ALIAS("technique10", technique , KEYHLSL | KEYHLSL2026_REMOVED) +ALIAS("technique11", technique , KEYHLSL | KEYHLSL2026_REMOVED) // OpenCL address space qualifiers KEYWORD(__global , KEYOPENCL) diff --git a/tools/clang/include/clang/Lex/PreprocessorOptions.h b/tools/clang/include/clang/Lex/PreprocessorOptions.h index 454b7ac005..d9499ea834 100644 --- a/tools/clang/include/clang/Lex/PreprocessorOptions.h +++ b/tools/clang/include/clang/Lex/PreprocessorOptions.h @@ -147,15 +147,15 @@ class PreprocessorOptions : public RefCountedBase { IntrusiveRefCntPtr FailedModules; public: - PreprocessorOptions() : UsePredefines(true), DetailedRecord(false), - IgnoreLineDirectives(false), // HLSL Change - ignore line directives. - DisablePCHValidation(false), - AllowPCHWithCompilerErrors(false), - DumpDeserializedPCHDecls(false), - PrecompiledPreambleBytes(0, true), - RemappedFilesKeepOriginalName(true), - RetainRemappedFileBuffers(false), - ObjCXXARCStandardLibrary(ARCXX_nolib) { } + PreprocessorOptions() + : UsePredefines(true), DetailedRecord(false), + // HLSL Change Begin - ignore line directives. + IgnoreLineDirectives(false), ExpandTokPastingArg(false), + // HLSL Change End + DisablePCHValidation(false), AllowPCHWithCompilerErrors(false), + DumpDeserializedPCHDecls(false), PrecompiledPreambleBytes(0, true), + RemappedFilesKeepOriginalName(true), RetainRemappedFileBuffers(false), + ObjCXXARCStandardLibrary(ARCXX_nolib) {} void addMacroDef(StringRef Name) { Macros.emplace_back(Name, false); } void addMacroUndef(StringRef Name) { Macros.emplace_back(Name, true); } diff --git a/tools/clang/include/clang/Sema/SemaHLSL.h b/tools/clang/include/clang/Sema/SemaHLSL.h index be17274521..1917a9277a 100644 --- a/tools/clang/include/clang/Sema/SemaHLSL.h +++ b/tools/clang/include/clang/Sema/SemaHLSL.h @@ -93,10 +93,6 @@ bool DiagnoseTypeElements(clang::Sema &S, clang::SourceLocation Loc, TypeDiagContext LongVecDiagContext, const clang::FieldDecl *FD = nullptr); -// Returns true if 'auto' is allowed to deduce the given type. Container types -// are deducible only when the type they wrap is deducible. -bool IsTypeDeducibleWithAuto(clang::Sema &S, clang::QualType Ty); - void DiagnoseControlFlowConditionForHLSL(clang::Sema *self, clang::Expr *condExpr, llvm::StringRef StmtName); diff --git a/tools/clang/lib/AST/ASTContext.cpp b/tools/clang/lib/AST/ASTContext.cpp index dd6ec2784d..19511b0f41 100644 --- a/tools/clang/lib/AST/ASTContext.cpp +++ b/tools/clang/lib/AST/ASTContext.cpp @@ -3078,6 +3078,8 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef ArgArray, const FunctionProtoType::ExtProtoInfo &EPI, ArrayRef ParamMods) const { // HLSL Change - param mods size_t NumArgs = ArgArray.size(); + assert((ParamMods.empty() || ParamMods.size() == NumArgs) && + "parameter modifier count does not match parameter count"); // Unique functions, to guarantee there is only one function of a particular // structure. diff --git a/tools/clang/lib/AST/ASTContextHLSL.cpp b/tools/clang/lib/AST/ASTContextHLSL.cpp index 517be3c8c3..c63e494fc4 100644 --- a/tools/clang/lib/AST/ASTContextHLSL.cpp +++ b/tools/clang/lib/AST/ASTContextHLSL.cpp @@ -472,6 +472,25 @@ static void AddRecordSubscriptAccess(clang::ASTContext &Ctx, AddRecordAccessMethod(Ctx, RD, ReturnTy, false, true, true); } +static AvailabilityAttr * +ConstructAvailabilityAttribute(clang::ASTContext &context, + VersionTuple Introduced, + VersionTuple Deprecated = VersionTuple(), + VersionTuple Obsoleted = VersionTuple()) { + AvailabilityAttr *AAttr = AvailabilityAttr::CreateImplicit( + context, &context.Idents.get(""), Introduced, Deprecated, Obsoleted, + false, ""); + return AAttr; +} + +// Work graph node record objects: available SM6.8, deprecated SM6.9, +// obsoleted SM6.10. +static AvailabilityAttr * +ConstructNodeRecordAvailabilityAttribute(clang::ASTContext &context) { + return ConstructAvailabilityAttribute( + context, VersionTuple(6, 8), VersionTuple(6, 9), VersionTuple(6, 10)); +} + /// Adds up-front support for HLSL *NodeOutputRecords template /// types. void hlsl::AddHLSLNodeOutputRecordTemplate( @@ -496,6 +515,8 @@ void hlsl::AddHLSLNodeOutputRecordTemplate( typeDeclBuilder.getRecordDecl()->addAttr( HLSLNodeObjectAttr::CreateImplicit(context, Type)); + typeDeclBuilder.getRecordDecl()->addAttr( + ConstructNodeRecordAvailabilityAttribute(context)); QualType elementType = context.getTemplateTypeParmType( 0, 0, ParameterPackFalse, outputTemplateParamDecl); @@ -546,14 +567,6 @@ hlsl::DeclareRecordTypeWithHandle(ASTContext &context, StringRef name, return typeDeclBuilder.getRecordDecl(); } -AvailabilityAttr *ConstructAvailabilityAttribute(clang::ASTContext &context, - VersionTuple Introduced) { - AvailabilityAttr *AAttr = AvailabilityAttr::CreateImplicit( - context, &context.Idents.get(""), clang::VersionTuple(6, 9), - clang::VersionTuple(), clang::VersionTuple(), false, ""); - return AAttr; -} - // creates a global static constant unsigned integer with value. // equivalent to: static const uint name = val; static void AddConstUInt(clang::ASTContext &context, DeclContext *DC, @@ -1321,6 +1334,7 @@ CXXRecordDecl *hlsl::DeclareResourceType(ASTContext &context, bool bSampler) { CXXRecordDecl *recordDecl = typeDeclBuilder.getRecordDecl(); recordDecl->addAttr( HLSLDynamicResourceAttr::CreateImplicit(context, bSampler)); + recordDecl->addAttr(HLSLNonAutoDeducibleAttr::CreateImplicit(context)); QualType indexType = context.UnsignedIntTy; QualType resultType = context.getRecordType(recordDecl); @@ -1355,6 +1369,8 @@ CXXRecordDecl *hlsl::DeclareNodeOrRecordType( Builder.getRecordDecl()->addAttr( HLSLNodeObjectAttr::CreateImplicit(Ctx, Type)); + Builder.getRecordDecl()->addAttr( + ConstructNodeRecordAvailabilityAttribute(Ctx)); if (IsRecordTypeTemplate) { QualType ParamTy = QualType(TyParamDecl->getTypeForDecl(), 0); @@ -1488,6 +1504,8 @@ CXXRecordDecl *hlsl::DeclareNodeOutputArray(clang::ASTContext &Ctx, Builder.getRecordDecl()->addAttr( HLSLNodeObjectAttr::CreateImplicit(Ctx, Type)); + Builder.getRecordDecl()->addAttr( + ConstructNodeRecordAvailabilityAttribute(Ctx)); QualType ResultType; if (IsRecordTypeTemplate) { diff --git a/tools/clang/lib/AST/Decl.cpp b/tools/clang/lib/AST/Decl.cpp index 4c8c0ae268..134a86de82 100644 --- a/tools/clang/lib/AST/Decl.cpp +++ b/tools/clang/lib/AST/Decl.cpp @@ -1958,7 +1958,6 @@ VarDecl::isThisDeclarationADefinition(ASTContext &C) const { getTemplateSpecializationKind() != TSK_ExplicitSpecialization) return DeclarationOnly; - if (!getASTContext().getLangOpts().HLSL) // HLSL Change - take extern as define to match fxc. if (hasExternalStorage()) return DeclarationOnly; @@ -2370,15 +2369,23 @@ unsigned ParmVarDecl::getParameterIndexLarge() const { // HLSL Change Begins void ParmVarDecl::updateOutParamToRefType(ASTContext &C) { + QualType ParamType = getType(); + const PackExpansionType *Expansion = dyn_cast(ParamType); + if (Expansion) + ParamType = Expansion->getPattern(); + // Aggregate type will be indirect param convert to pointer type. // So don't update to ReferenceType. - if ((!getType()->isArrayType() && !getType()->isRecordType()) || - hlsl::IsHLSLVecMatType(getType())) - setType(C.getLValueReferenceType(getType(), false)); + if ((!ParamType->isArrayType() && !ParamType->isRecordType()) || + hlsl::IsHLSLVecMatType(ParamType)) + ParamType = C.getLValueReferenceType(ParamType, false); // Add restrict to out param. - QualType QT = getType(); - QT.addRestrict(); - setType(QT); + ParamType.addRestrict(); + + if (Expansion) + ParamType = + C.getPackExpansionType(ParamType, Expansion->getNumExpansions()); + setType(ParamType); } // HLSL Change Ends diff --git a/tools/clang/lib/AST/HlslTypes.cpp b/tools/clang/lib/AST/HlslTypes.cpp index 6edbb3b862..4e82490918 100644 --- a/tools/clang/lib/AST/HlslTypes.cpp +++ b/tools/clang/lib/AST/HlslTypes.cpp @@ -97,9 +97,11 @@ bool IsHLSLNumericOrAggregateOfNumericType(clang::QualType type) { } // Chars can only appear as part of strings, which we don't consider numeric. + // LinAlg matrix handles are opaque objects, not numeric data. const BuiltinType *BuiltinTy = dyn_cast(Ty); return BuiltinTy != nullptr && - BuiltinTy->getKind() != BuiltinType::Kind::Char_S; + BuiltinTy->getKind() != BuiltinType::Kind::Char_S && + BuiltinTy->getKind() != BuiltinType::Kind::LinAlgMatrix; } // In some cases we need record types that are annotatable and trivially @@ -753,17 +755,7 @@ clang::RecordDecl *GetRecordDeclFromNodeObjectType(clang::QualType ObjectTy) { } bool IsHLSLRayQueryType(clang::QualType type) { - type = type.getCanonicalType(); - if (const RecordType *RT = dyn_cast(type)) { - if (const ClassTemplateSpecializationDecl *templateDecl = - dyn_cast( - RT->getAsCXXRecordDecl())) { - StringRef name = templateDecl->getName(); - if (name == "RayQuery") - return true; - } - } - return false; + return nullptr != getAttr(type); } #ifdef ENABLE_SPIRV_CODEGEN @@ -991,4 +983,24 @@ HLSLScalarType MakeUnsigned(HLSLScalarType T) { return T; } +bool IsTypeDeducibleWithAuto(QualType type) { + if (type.isNull()) + return false; + + if (hlsl::IsStringType(type) || hlsl::IsStringLiteralType(type)) + return false; + + if (const CXXRecordDecl *recordDecl = + GetStructuralForm(type)->getAsCXXRecordDecl()) { + if (!recordDecl->hasAttr()) + if (const CXXRecordDecl *pattern = + recordDecl->getTemplateInstantiationPattern()) + recordDecl = pattern; + if (recordDecl->hasAttr()) + return false; + } + + return true; +} + } // namespace hlsl diff --git a/tools/clang/lib/Analysis/UninitializedValues.cpp b/tools/clang/lib/Analysis/UninitializedValues.cpp index dfd689bdf3..0bcccc7e6b 100644 --- a/tools/clang/lib/Analysis/UninitializedValues.cpp +++ b/tools/clang/lib/Analysis/UninitializedValues.cpp @@ -171,6 +171,12 @@ class CFGBlockValues { return declToIndex.getHLSLOutParams(); } // HLSL Change End - Treat `out` parameters as uninitialized values. + + // HLSL Change Begin - check the variable is in the declToIndex map + bool hasValueIndex(const VarDecl *vd) { + return declToIndex.getValueIndex(vd).hasValue(); + } + // HLSL Change End - check the variable is in the declToIndex map }; } // end anonymous namespace @@ -781,10 +787,23 @@ void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) { case ClassifyRefs::Ignore: break; case ClassifyRefs::Use: - reportUse(dr, cast(dr->getDecl())); + // HLSL Change Begin - check the variable is in the declToIndex map + // before calling reportUse(). HLSL out parameters or local variables from + // template instantiations may not be mapped in the current DeclContext. + if (const VarDecl *VD = cast(dr->getDecl())) { + if (vals.hasValueIndex(VD)) + reportUse(dr, VD); + } + // HLSL Change End - check the variable is in the declToIndex map break; case ClassifyRefs::Init: - vals[cast(dr->getDecl())] = Initialized; + // HLSL Change Begin - check the variable is in the declToIndex map + // before marking it Initialized. + if (const VarDecl *VD = cast(dr->getDecl())) { + if (vals.hasValueIndex(VD)) + vals[VD] = Initialized; + } + // HLSL Change End - check the variable is in the declToIndex map break; case ClassifyRefs::SelfInit: handler.handleSelfInit(cast(dr->getDecl())); @@ -795,8 +814,12 @@ void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) { void TransferFunctions::VisitBinaryOperator(BinaryOperator *BO) { if (BO->getOpcode() == BO_Assign) { FindVarResult Var = findVar(BO->getLHS()); + // HLSL Change Begin - check the variable is in the declToIndex map + // before marking it Initialized. if (const VarDecl *VD = Var.getDecl()) - vals[VD] = Initialized; + if (vals.hasValueIndex(VD)) + vals[VD] = Initialized; + // HLSL Change End - check the variable is in the declToIndex map } } diff --git a/tools/clang/lib/Basic/IdentifierTable.cpp b/tools/clang/lib/Basic/IdentifierTable.cpp index feb7f35e21..15fb287ba6 100644 --- a/tools/clang/lib/Basic/IdentifierTable.cpp +++ b/tools/clang/lib/Basic/IdentifierTable.cpp @@ -91,38 +91,40 @@ IdentifierTable::IdentifierTable(const LangOptions &LangOpts, // Constants for TokenKinds.def namespace { - enum { - KEYC99 = 0x1, - KEYCXX = 0x2, - KEYCXX11 = 0x4, - KEYGNU = 0x8, - KEYMS = 0x10, - BOOLSUPPORT = 0x20, - KEYALTIVEC = 0x40, - KEYNOCXX = 0x80, - KEYBORLAND = 0x100, - KEYOPENCL = 0x200, - KEYC11 = 0x400, - KEYARC = 0x800, - KEYNOMS18 = 0x01000, - KEYNOOPENCL = 0x02000, - WCHARSUPPORT = 0x04000, - HALFSUPPORT = 0x08000, - KEYCONCEPTS = 0x10000, - KEYOBJC2 = 0x20000, - KEYZVECTOR = 0x40000, - KEYHLSL = 0x80000, // MS Change: Flag for hlsl keywords - KEYALL = (0x7ffff & ~KEYNOMS18 & - ~KEYNOOPENCL) // KEYNOMS18 and KEYNOOPENCL are used to exclude. - }; +enum { + KEYC99 = 0x1, + KEYCXX = 0x2, + KEYCXX11 = 0x4, + KEYGNU = 0x8, + KEYMS = 0x10, + BOOLSUPPORT = 0x20, + KEYALTIVEC = 0x40, + KEYNOCXX = 0x80, + KEYBORLAND = 0x100, + KEYOPENCL = 0x200, + KEYC11 = 0x400, + KEYARC = 0x800, + KEYNOMS18 = 0x01000, + KEYNOOPENCL = 0x02000, + WCHARSUPPORT = 0x04000, + HALFSUPPORT = 0x08000, + KEYCONCEPTS = 0x10000, + KEYOBJC2 = 0x20000, + KEYZVECTOR = 0x40000, + KEYHLSL = 0x80000, // MS Change: Flag for hlsl keywords + KEYHLSL2026_REMOVED = 0x100000, + KEYHLSL2026 = 0x200000, + KEYALL = (0x7ffff & ~KEYNOMS18 & + ~KEYNOOPENCL) // KEYNOMS18 and KEYNOOPENCL are used to exclude. +}; - /// \brief How a keyword is treated in the selected standard. - enum KeywordStatus { - KS_Disabled, // Disabled - KS_Extension, // Is an extension - KS_Enabled, // Enabled - KS_Future // Is a keyword in future standard - }; +/// \brief How a keyword is treated in the selected standard. +enum KeywordStatus { + KS_Disabled, // Disabled + KS_Extension, // Is an extension + KS_Enabled, // Enabled + KS_Future // Is a keyword in future standard +}; } /// \brief Translates flags as specified in TokenKinds.def into keyword status @@ -142,7 +144,16 @@ static KeywordStatus getKeywordStatus(const LangOptions &LangOpts, if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) return KS_Enabled; if (LangOpts.OpenCL && (Flags & KEYOPENCL)) return KS_Enabled; if (!LangOpts.CPlusPlus && (Flags & KEYNOCXX)) return KS_Enabled; - if (LangOpts.HLSL && (Flags & KEYHLSL)) return KS_Enabled; // HLSL Change: Support for HLSL Keywords + // HLSL Change Begin - Support for HLSL Keywords. + if (LangOpts.HLSL && LangOpts.HLSLVersion >= hlsl::LangStd::v202x && + (Flags & KEYHLSL2026_REMOVED)) + return KS_Disabled; + if (LangOpts.HLSL && LangOpts.HLSLVersion >= hlsl::LangStd::v202x && + (Flags & KEYHLSL2026)) + return KS_Enabled; + if (LangOpts.HLSL && (Flags & KEYHLSL)) + return KS_Enabled; + // HLSL Change - End if (LangOpts.C11 && (Flags & KEYC11)) return KS_Enabled; // We treat bridge casts as objective-C keywords so we can warn on them // in non-arc mode. diff --git a/tools/clang/lib/CodeGen/BackendUtil.cpp b/tools/clang/lib/CodeGen/BackendUtil.cpp index 52d77bf115..88e0f4639e 100644 --- a/tools/clang/lib/CodeGen/BackendUtil.cpp +++ b/tools/clang/lib/CodeGen/BackendUtil.cpp @@ -342,6 +342,8 @@ void EmitAssemblyHelper::CreatePasses() { PMBuilder.HLSLHighLevel = CodeGenOpts.HLSLHighLevel; PMBuilder.HLSLAllowPreserveValues = CodeGenOpts.HLSLAllowPreserveValues; PMBuilder.HLSLOnlyWarnOnUnrollFail = CodeGenOpts.HLSLOnlyWarnOnUnrollFail; + PMBuilder.HLSLUnrollCountIsHint = + LangOpts.HLSLVersion >= hlsl::LangStd::v202x; PMBuilder.HLSLExtensionsCodeGen = CodeGenOpts.HLSLExtensionsCodegen.get(); PMBuilder.HLSLResMayAlias = CodeGenOpts.HLSLResMayAlias; PMBuilder.ScanLimit = CodeGenOpts.ScanLimit; diff --git a/tools/clang/lib/CodeGen/CGHLSLMSFinishCodeGen.cpp b/tools/clang/lib/CodeGen/CGHLSLMSFinishCodeGen.cpp index 13edadf9df..7aa5eb4ad4 100644 --- a/tools/clang/lib/CodeGen/CGHLSLMSFinishCodeGen.cpp +++ b/tools/clang/lib/CodeGen/CGHLSLMSFinishCodeGen.cpp @@ -12,6 +12,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Analysis/DxilValueCache.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/CFG.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" @@ -330,6 +331,13 @@ void LowerGetResourceFromHeap( for (auto uit = resPtr->user_begin(); uit != resPtr->user_end();) { User *U = *(uit++); BitCastInst *BCI = cast(U); + // Ignore uses of the resource which are just bitcasts to i8* for lifetime + // markers. These will get cleaned up in later legalization. + if (BCI->getType()->getPointerElementType()->isIntegerTy(8)) { + DXASSERT(onlyUsedByLifetimeMarkers(BCI), + "otherwise, unexpected use of i8* cast of resource ptr"); + continue; + } DXASSERT( dxilutil::IsHLSLResourceType( BCI->getType()->getPointerElementType()) || @@ -348,7 +356,10 @@ void LowerGetResourceFromHeap( } BCI->eraseFromParent(); } - resPtr->eraseFromParent(); + // Only erase the resource if it has no remaining uses. The correct fix here + // is to just not generate these resources, but that is a larger change. + if (resPtr->use_empty()) + resPtr->eraseFromParent(); } } diff --git a/tools/clang/lib/CodeGen/CodeGenModule.cpp b/tools/clang/lib/CodeGen/CodeGenModule.cpp index b274ea9d64..8ac5730a67 100644 --- a/tools/clang/lib/CodeGen/CodeGenModule.cpp +++ b/tools/clang/lib/CodeGen/CodeGenModule.cpp @@ -2109,12 +2109,6 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { NeedsGlobalCtor = true; // HLSL Change Begins. if (getLangOpts().HLSL && D->isExternallyVisible()) { - // For global constant with init, the init will be ignored. - // Warning here. - unsigned DiagID = Diags.getCustomDiagID( - DiagnosticsEngine::Warning, - "Initializer of external global will be ignored"); - Diags.Report(D->getLocation(), DiagID); // Don't create global ctor for it. NeedsGlobalCtor = false; } @@ -2130,13 +2124,9 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { if (getLangOpts().CPlusPlus && !NeedsGlobalDtor) DelayedCXXInitPosition.erase(D); // HLSL Change Begins. - if (getLangOpts().HLSL && D->isExternallyVisible() && !D->isStaticDataMember()) { - // For global constant with init, the init will be ignored. + if (getLangOpts().HLSL && D->isExternallyVisible() && + !D->isStaticDataMember()) { Init = EmitNullConstant(D->getType()); - unsigned DiagID = Diags.getCustomDiagID( - DiagnosticsEngine::Warning, - "Initializer of external global will be ignored"); - Diags.Report(D->getLocation(), DiagID); } // HLSL Change Ends. } diff --git a/tools/clang/lib/Frontend/InitPreprocessor.cpp b/tools/clang/lib/Frontend/InitPreprocessor.cpp index b0a53650b5..621f5da94b 100644 --- a/tools/clang/lib/Frontend/InitPreprocessor.cpp +++ b/tools/clang/lib/Frontend/InitPreprocessor.cpp @@ -376,6 +376,8 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, // HLSL Version Builder.defineMacro("__HLSL_VERSION", Twine((unsigned int)LangOpts.HLSLVersion)); + if (!LangOpts.HLSLDisallowsVariadicTemplates()) + Builder.defineMacro("__cpp_variadic_templates", "200704"); // This define is enabled in Clang and allows conditionally compiling code // based on whether or not native 16-bit types are supported. if (!LangOpts.UseMinPrecision) diff --git a/tools/clang/lib/Headers/hlsl/dx/linalg.h b/tools/clang/lib/Headers/hlsl/dx/linalg.h index 2bd81986b6..ff5e119fa3 100644 --- a/tools/clang/lib/Headers/hlsl/dx/linalg.h +++ b/tools/clang/lib/Headers/hlsl/dx/linalg.h @@ -43,13 +43,17 @@ enum class ComponentType : uint32_t { PackedS8x32 = 17, PackedU8x32 = 18, - // BEGIN NEW FOR SM 6.10 + // BEGIN NEW FOR SM 6.9 I8 = 19, U8 = 20, F8_E4M3FN = 21, F8_E5M2 = 22, // END + // BEGIN NEW FOR SM 6.10 + BFloat16 = 23, + // END + LastEntry }; @@ -83,6 +87,7 @@ struct ComponentType { __COMPONENT_TYPE(F16), __COMPONENT_TYPE(F32), __COMPONENT_TYPE(F64), + __COMPONENT_TYPE(BFloat16), }; }; @@ -121,17 +126,49 @@ struct MatrixLayout { using MatrixLayoutEnum = MatrixLayout::MatrixLayoutEnum; namespace __detail { -template struct ComponentTypeTraits { +template struct ComponentTypeTraits { using Type = uint; static const bool IsNativeScalar = false; static const uint ElementsPerScalar = 4; }; -template struct TypeTraits { +template struct TypeTraits { static const ComponentEnum CompType = (ComponentEnum)dxil::ComponentType::Invalid; }; +template struct IsComponentTypeAvailable { + static const bool value = true; +}; + +#if !__HLSL_ENABLE_16_BIT +template <> struct IsComponentTypeAvailable { + static const bool value = false; +}; +template <> struct IsComponentTypeAvailable { + static const bool value = false; +}; +template <> struct IsComponentTypeAvailable { + static const bool value = false; +}; +#endif + +template struct IsCompatibleVectorElement { + static const bool IsPackedCarrier = + hlsl::is_same::value || + hlsl::is_same::value; + static const bool value = + IsComponentTypeAvailable::value && + (hlsl::is_same::Type>::value || + (!ComponentTypeTraits::IsNativeScalar && IsPackedCarrier)); +}; + +template <> struct ComponentTypeTraits { + using Type = uint; + static const bool IsNativeScalar = false; + static const uint ElementsPerScalar = 2; +}; + #define __MATRIX_SCALAR_COMPONENT_MAPPING(enum_val, type) \ template <> struct ComponentTypeTraits { \ using Type = type; \ @@ -155,13 +192,13 @@ __MATRIX_SCALAR_COMPONENT_MAPPING(ComponentType::I64, int64_t) __MATRIX_SCALAR_COMPONENT_MAPPING(ComponentType::U64, uint64_t) __MATRIX_SCALAR_COMPONENT_MAPPING(ComponentType::F64, double) -template struct DstN { +template struct DstN { // Make sure to round up in case SrcN isn't an even multiple of the number of // elements per scalar static const int Value = - (SrcN * ComponentTypeTraits::ElementsPerScalar + - ComponentTypeTraits::ElementsPerScalar - 1) / - ComponentTypeTraits::ElementsPerScalar; + (SrcN * ComponentTypeTraits::ElementsPerScalar + + ComponentTypeTraits::ElementsPerScalar - 1) / + ComponentTypeTraits::ElementsPerScalar; }; template struct DimMN { @@ -174,245 +211,256 @@ template struct DimMN { static const SIZE_TYPE N = MVal; }; -template +template struct ScalarCountFromPackedComponents { static const SIZE_TYPE ElementsPerScalar = - ComponentTypeTraits::ElementsPerScalar; + ComponentTypeTraits::ElementsPerScalar; static const SIZE_TYPE Value = (PackedComponentCount + ElementsPerScalar - 1) / ElementsPerScalar; }; +template struct DefaultAlign { + enum { + MinDim = M < N ? M : N, + ScalarCount = ScalarCountFromPackedComponents::Value, + ByteAlign = ScalarCount * 4, + MinByteAlign = ByteAlign < 4 ? 4 : ByteAlign, + Value = MinByteAlign < 16 ? MinByteAlign : 16 + }; +}; + } // namespace __detail -template struct VectorRef { +template struct VectorRef { ByteAddressBuffer Buf; uint Offset; }; -template struct InterpretedVector { - vector Data; - static const ComponentEnum Interpretation = DT; +template struct InterpretedVector { + vector Data; + static const ComponentEnum Interpretation = CT; static const SIZE_TYPE Size = - __detail::ComponentTypeTraits
::ElementsPerScalar * N; + __detail::ComponentTypeTraits::ElementsPerScalar * N; }; -template -InterpretedVector MakeInterpretedVector(vector Vec) { - InterpretedVector IV = {Vec}; +template +typename hlsl::enable_if< __detail::IsCompatibleVectorElement::value, + InterpretedVector >::type +MakeInterpretedVector(vector Vec) { + InterpretedVector IV = {Vec}; return IV; } -template +template typename hlsl::enable_if< - DestTy != OriginTy, - InterpretedVector::Type, - __detail::DstN::Value, - DestTy> >::type -Convert(vector Vec) { - vector::Type, - __detail::DstN::Value> + DestCT != OriginCT && __detail::IsComponentTypeAvailable::value && + __detail::IsCompatibleVectorElement::value, + InterpretedVector::Type, + __detail::DstN::Value, + DestCT> >::type +Convert(vector Vec) { + vector::Type, + __detail::DstN::Value> Result; - __builtin_LinAlg_Convert(Result, Vec, OriginTy, DestTy); - return MakeInterpretedVector(Result); + dx::__builtin_LinAlg_Convert(Result, Vec, OriginCT, DestCT); + return MakeInterpretedVector(Result); } -template -typename hlsl::enable_if >::type -Convert(vector Vec) { - return MakeInterpretedVector(Vec); +template +typename hlsl::enable_if< + DestCT == OriginCT && + __detail::IsCompatibleVectorElement::value, + InterpretedVector >::type +Convert(vector Vec) { + return MakeInterpretedVector(Vec); } -template +template class Matrix { - using ElementType = typename __detail::ComponentTypeTraits::Type; - // If this isn't a native scalar, we have an 8-bit type, so we have 4 elements - // packed in each scalar value. + using ElementType = typename __detail::ComponentTypeTraits::Type; + // If this isn't a native scalar, we have a type that may pack more than 1 + // element in each scalar value. (Ex. 8bit => 4elems, 16bit => 2elems) static const uint ElementsPerScalar = - __detail::ComponentTypeTraits::ElementsPerScalar; + __detail::ComponentTypeTraits::ElementsPerScalar; static const bool IsNativeScalar = - __detail::ComponentTypeTraits::IsNativeScalar; + __detail::ComponentTypeTraits::IsNativeScalar; using HandleT = __builtin_LinAlgMatrix - [[__LinAlgMatrix_Attributes(ComponentTy, M, N, Use, Scope)]]; + [[__LinAlgMatrix_Attributes(CT, M, N, Use, Scope)]]; HandleT __handle; - template - [[nodiscard]] Matrix::M, + [[nodiscard]] Matrix::M, __detail::DimMN::N, NewUse, Scope> Cast() { - Matrix::M, + Matrix::M, __detail::DimMN::N, NewUse, Scope> Result; - __builtin_LinAlg_CopyConvertMatrix(Result.__handle, __handle, Transpose); + dx::__builtin_LinAlg_CopyConvertMatrix(Result.__handle, __handle, + Transpose); return Result; } - template + template [[nodiscard]] static - typename hlsl::enable_if::value, Matrix>::type - Splat(T Val) { + typename hlsl::enable_if::value, Matrix>::type + Splat(Ty Val) { Matrix Result; - __builtin_LinAlg_FillMatrix(Result.__handle, Val); + dx::__builtin_LinAlg_FillMatrix(Result.__handle, hlsl::is_signed::value, + Val); return Result; } - template + template ::Value> [[nodiscard]] static Matrix Load(ByteAddressBuffer Res, uint StartOffset, uint Stride, MatrixLayoutEnum Layout) { Matrix Result; - __builtin_LinAlg_MatrixLoadFromDescriptor(Result.__handle, Res, StartOffset, - Stride, Layout, Align); + dx::__builtin_LinAlg_MatrixLoadFromDescriptor( + Result.__handle, Res, StartOffset, Stride, Layout, Align); return Result; } - template + template ::Value> [[nodiscard]] static Matrix Load(RWByteAddressBuffer Res, uint StartOffset, uint Stride, MatrixLayoutEnum Layout) { Matrix Result; - __builtin_LinAlg_MatrixLoadFromDescriptor(Result.__handle, Res, StartOffset, - Stride, Layout, Align); + dx::__builtin_LinAlg_MatrixLoadFromDescriptor( + Result.__handle, Res, StartOffset, Stride, Layout, Align); return Result; } - template + template [[nodiscard]] static typename hlsl::enable_if< - (hlsl::is_same::type, + (hlsl::is_same::type, ElementType>::value || - hlsl::is_same::type, + hlsl::is_same::type, uint8_t4_packed>::value), Matrix>::type - Load(groupshared T Arr[Size], uint StartIdx, uint Stride, + Load(groupshared Ty Arr[Size], uint StartIdx, uint Stride, MatrixLayoutEnum Layout) { Matrix Result; - __builtin_LinAlg_MatrixLoadFromMemory(Result.__handle, Arr, StartIdx, - Stride, Layout); + dx::__builtin_LinAlg_MatrixLoadFromMemory(Result.__handle, Arr, StartIdx, + Stride, Layout); return Result; } - template - typename hlsl::enable_if::type + template + typename hlsl::enable_if::type Length() { - return __builtin_LinAlg_MatrixLength(__handle); + return dx::__builtin_LinAlg_MatrixLength(__handle); } - template - typename hlsl::enable_if::type + template + typename hlsl::enable_if::type GetCoordinate(uint Index) { - return __builtin_LinAlg_MatrixGetCoordinate(__handle, Index); + return dx::__builtin_LinAlg_MatrixGetCoordinate(__handle, Index); } - template - typename hlsl::enable_if::type + template + typename hlsl::enable_if::type Get(uint Index) { ElementType Result; - __builtin_LinAlg_MatrixGetElement(Result, __handle, Index); + dx::__builtin_LinAlg_MatrixGetElement(Result, __handle, Index); return Result; } - template - typename hlsl::enable_if::type + template + typename hlsl::enable_if::type Set(uint Index, ElementType Value) { - __builtin_LinAlg_MatrixSetElement(__handle, __handle, Index, Value); + dx::__builtin_LinAlg_MatrixSetElement(__handle, __handle, Index, Value); } - template + template ::Value> void Store(RWByteAddressBuffer Res, uint StartOffset, uint Stride, MatrixLayoutEnum Layout) { - __builtin_LinAlg_MatrixStoreToDescriptor(__handle, Res, StartOffset, Stride, - Layout, Align); + dx::__builtin_LinAlg_MatrixStoreToDescriptor(__handle, Res, StartOffset, + Stride, Layout, Align); } - template + template typename hlsl::enable_if< - (hlsl::is_same::type, + (hlsl::is_same::type, ElementType>::value || - hlsl::is_same::type, + hlsl::is_same::type, uint8_t4_packed>::value), void>::type - Store(groupshared T Arr[Size], uint StartIdx, uint Stride, + Store(groupshared Ty Arr[Size], uint StartIdx, uint Stride, MatrixLayoutEnum Layout) { - __builtin_LinAlg_MatrixStoreToMemory(__handle, Arr, StartIdx, Stride, - Layout); + dx::__builtin_LinAlg_MatrixStoreToMemory(__handle, Arr, StartIdx, Stride, + Layout); } // Accumulate methods - template + template ::Value, + MatrixUseEnum UseLocal = Use> typename hlsl::enable_if::type InterlockedAccumulate(RWByteAddressBuffer Res, uint StartOffset, uint Stride, MatrixLayoutEnum Layout) { - __builtin_LinAlg_MatrixAccumulateToDescriptor(__handle, Res, StartOffset, - Stride, Layout, Align); + dx::__builtin_LinAlg_MatrixAccumulateToDescriptor( + __handle, Res, StartOffset, Stride, Layout, Align); } - template + template typename hlsl::enable_if< - hlsl::is_arithmetic_vector::value && Use == MatrixUse::Accumulator && - UseLocal == Use && Scope == MatrixScope::Wave && ScopeLocal == Scope, + hlsl::is_same::type, + ElementType>::value && + hlsl::is_arithmetic_vector::value && + Use == MatrixUse::Accumulator && UseLocal == Use, void>::type - InterlockedAccumulate(groupshared T Arr[Size], uint StartIdx, uint Stride, + InterlockedAccumulate(groupshared Ty Arr[Size], uint StartIdx, uint Stride, MatrixLayoutEnum Layout) { - __builtin_LinAlg_MatrixAccumulateToMemory(__handle, Arr, ComponentTy, - StartIdx, Stride, Layout); + dx::__builtin_LinAlg_MatrixAccumulateToMemory(__handle, Arr, StartIdx, + Stride, Layout); } - template + template typename hlsl::enable_if< - hlsl::is_same::type, + hlsl::is_same::type, uint8_t4_packed>::value && - Use == MatrixUse::Accumulator && UseLocal == Use && - Scope == MatrixScope::Wave && ScopeLocal == Scope, + Use == MatrixUse::Accumulator && UseLocal == Use, void>::type - InterlockedAccumulate(groupshared T Arr[Size], uint StartIdx, uint Stride, + InterlockedAccumulate(groupshared Ty Arr[Size], uint StartIdx, uint Stride, MatrixLayoutEnum Layout) { - __builtin_LinAlg_MatrixAccumulateToMemory(__handle, Arr, TargetCompTy, - StartIdx, Stride, Layout); + dx::__builtin_LinAlg_MatrixAccumulateToMemory(__handle, Arr, StartIdx, + Stride, Layout); } - template + template typename hlsl::enable_if::type - Accumulate(const Matrix MatrixA) { - __builtin_LinAlg_MatrixAccumulate(__handle, __handle, MatrixA.__handle); + Accumulate(const Matrix MatrixA) { + dx::__builtin_LinAlg_MatrixAccumulate(__handle, __handle, MatrixA.__handle); } - template + template typename hlsl::enable_if::type - Accumulate(const Matrix MatrixB) { - __builtin_LinAlg_MatrixAccumulate(__handle, __handle, MatrixB.__handle); + Accumulate(const Matrix MatrixB) { + dx::__builtin_LinAlg_MatrixAccumulate(__handle, __handle, MatrixB.__handle); } - template typename hlsl::enable_if::type - MultiplyAccumulate(const Matrix MatrixA, - const Matrix MatrixB) { - __builtin_LinAlg_MatrixMatrixMultiplyAccumulate(__handle, MatrixA.__handle, - MatrixB.__handle, __handle); + MultiplyAccumulate(const Matrix MatrixA, + const Matrix MatrixB) { + dx::__builtin_LinAlg_MatrixMatrixMultiplyAccumulate( + __handle, MatrixA.__handle, MatrixB.__handle, __handle); } }; // Thread-scope Matrices are read-only. Using a template partial // specialization for this simplifies the SFINAE-foo above. -template -class Matrix { - using ElementType = typename __detail::ComponentTypeTraits::Type; +template +class Matrix { + using ElementType = typename __detail::ComponentTypeTraits::Type; - using HandleT = __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes( - ComponentTy, M, N, Use, MatrixScope::Thread)]]; + using HandleT = __builtin_LinAlgMatrix + [[__LinAlgMatrix_Attributes(CT, M, N, Use, MatrixScope::Thread)]]; HandleT __handle; template { Matrix>::type Load(ByteAddressBuffer Res, uint StartOffset, uint Stride) { Matrix Result; - __builtin_LinAlg_MatrixLoadFromDescriptor(Result.__handle, Res, StartOffset, - Stride, Layout, Align); + dx::__builtin_LinAlg_MatrixLoadFromDescriptor( + Result.__handle, Res, StartOffset, Stride, Layout, Align); return Result; } - template + template typename hlsl::enable_if::type InterlockedAccumulate(RWByteAddressBuffer Res, uint StartOffset) { - __builtin_LinAlg_MatrixAccumulateToDescriptor( - __handle, Res, StartOffset, 0, MatrixLayout::OuterProductOptimal, 0); + dx::__builtin_LinAlg_MatrixAccumulateToDescriptor( + __handle, Res, StartOffset, 0, MatrixLayout::OuterProductOptimal, + Align); } }; MatrixUseEnum AccumulatorLayout() { - return (MatrixUseEnum)(__builtin_LinAlg_MatrixQueryAccumulatorLayout()); + return (MatrixUseEnum)(dx::__builtin_LinAlg_MatrixQueryAccumulatorLayout()); } -template -[[nodiscard]] Matrix -Multiply(const Matrix MatrixA, - const Matrix MatrixB) { - Matrix Result; - __builtin_LinAlg_MatrixMatrixMultiply(Result.__handle, MatrixA.__handle, - MatrixB.__handle); +[[nodiscard]] Matrix +Multiply(const Matrix MatrixA, + const Matrix MatrixB) { + Matrix Result; + dx::__builtin_LinAlg_MatrixMatrixMultiply(Result.__handle, MatrixA.__handle, + MatrixB.__handle); return Result; } -template -[[nodiscard]] Matrix -Multiply(const Matrix MatrixA, - const Matrix MatrixB) { - Matrix Result; - __builtin_LinAlg_MatrixMatrixMultiply(Result.__handle, MatrixA.__handle, - MatrixB.__handle); +template +[[nodiscard]] Matrix +Multiply(const Matrix MatrixA, + const Matrix MatrixB) { + Matrix Result; + dx::__builtin_LinAlg_MatrixMatrixMultiply(Result.__handle, MatrixA.__handle, + MatrixB.__handle); return Result; } -template -[[nodiscard]] Matrix Multiply( - const Matrix MatrixA, - const Matrix MatrixB) { - Matrix Result; - __builtin_LinAlg_MatrixMatrixMultiply(Result.__handle, MatrixA.__handle, - MatrixB.__handle); + const Matrix MatrixA, + const Matrix MatrixB) { + Matrix Result; + dx::__builtin_LinAlg_MatrixMatrixMultiply(Result.__handle, MatrixA.__handle, + MatrixB.__handle); return Result; } -template -[[nodiscard]] Matrix +template +[[nodiscard]] Matrix Multiply( - const Matrix MatrixA, - const Matrix - MatrixB) { - Matrix Result; - __builtin_LinAlg_MatrixMatrixMultiply(Result.__handle, MatrixA.__handle, - MatrixB.__handle); + const Matrix MatrixA, + const Matrix MatrixB) { + Matrix Result; + dx::__builtin_LinAlg_MatrixMatrixMultiply(Result.__handle, MatrixA.__handle, + MatrixB.__handle); return Result; } @@ -491,176 +538,179 @@ Multiply( // Cooperative Vector operates on per-thread vectors multiplying against B // matrices with thread scope. -template -typename hlsl::enable_if::value, - vector >::type -Multiply(Matrix MatrixA, - vector Vec) { - vector Result; - __builtin_LinAlg_MatrixVectorMultiply(Result, MatrixA.__handle, - hlsl::is_signed::value, Vec, - MatrixDT); +template +typename hlsl::enable_if::value, + vector >::type +Multiply(Matrix MatrixA, + vector Vec) { + vector Result; + dx::__builtin_LinAlg_MatrixVectorMultiply( + Result, MatrixA.__handle, hlsl::is_signed::value, Vec, + __detail::TypeTraits::CompType); return Result; } -template +template typename hlsl::enable_if< - InterpretedVector::Size == K, - vector >::type -Multiply(Matrix MatrixA, - InterpretedVector InterpVec) { - vector Result; - __builtin_LinAlg_MatrixVectorMultiply( - Result, MatrixA.__handle, hlsl::is_signed::value, + InterpretedVector::Size == K && + __detail::IsCompatibleVectorElement::value, + vector >::type +Multiply(Matrix MatrixA, + InterpretedVector InterpVec) { + vector Result; + dx::__builtin_LinAlg_MatrixVectorMultiply( + Result, MatrixA.__handle, hlsl::is_signed::value, InterpVec.Data, InterpVec.Interpretation); return Result; } -template -typename hlsl::enable_if::value && - hlsl::is_arithmetic::value, - vector >::type -MultiplyAdd(Matrix MatrixA, - vector Vec, vector Bias) { - - InterpretedVector::CompType> - BiasConvInterp = Convert<__detail::TypeTraits::CompType, - __detail::TypeTraits::CompType>(Bias); - - vector Result; - __builtin_LinAlg_MatrixVectorMultiplyAdd( - Result, MatrixA.__handle, hlsl::is_signed::value, Vec, - __detail::TypeTraits::CompType, BiasConvInterp.Data); +template +typename hlsl::enable_if::value && + hlsl::is_arithmetic::value, + vector >::type +MultiplyAdd(Matrix MatrixA, + vector Vec, vector Bias) { + + InterpretedVector::CompType> + BiasConvInterp = Convert<__detail::TypeTraits::CompType, + __detail::TypeTraits::CompType>(Bias); + + vector Result; + dx::__builtin_LinAlg_MatrixVectorMultiplyAdd( + Result, MatrixA.__handle, hlsl::is_signed::value, Vec, + __detail::TypeTraits::CompType, BiasConvInterp.Data); return Result; } -template +template typename hlsl::enable_if< - VecK == __detail::ScalarCountFromPackedComponents::Value && - hlsl::is_arithmetic::value, - vector >::type -MultiplyAdd(Matrix MatrixA, - InterpretedVector InterpVec, - vector Bias) { - - InterpretedVector::CompType> - BiasConvInterp = Convert<__detail::TypeTraits::CompType, - __detail::TypeTraits::CompType>(Bias); - - vector Result; - __builtin_LinAlg_MatrixVectorMultiplyAdd( - Result, MatrixA.__handle, hlsl::is_signed::value, + VecK == __detail::ScalarCountFromPackedComponents::Value && + __detail::IsCompatibleVectorElement::value && + hlsl::is_arithmetic::value, + vector >::type +MultiplyAdd(Matrix MatrixA, + InterpretedVector InterpVec, + vector Bias) { + + InterpretedVector::CompType> + BiasConvInterp = Convert<__detail::TypeTraits::CompType, + __detail::TypeTraits::CompType>(Bias); + + vector Result; + dx::__builtin_LinAlg_MatrixVectorMultiplyAdd( + Result, MatrixA.__handle, hlsl::is_signed::value, InterpVec.Data, InterpVec.Interpretation, BiasConvInterp.Data); return Result; } -template -typename hlsl::enable_if::value, - vector >::type -MultiplyAdd(Matrix MatrixA, - vector Vec, VectorRef BiasRef) { +template +typename hlsl::enable_if::value, + vector >::type +MultiplyAdd(Matrix MatrixA, + vector Vec, VectorRef BiasRef) { using BiasVecTy = - vector::Type, - __detail::ScalarCountFromPackedComponents::Value>; + vector::Type, + __detail::ScalarCountFromPackedComponents::Value>; BiasVecTy Bias = BiasRef.Buf.template Load(BiasRef.Offset); - // FIXME: Convert currently does not support packed type vector sizes that + // Convert currently does not support packed type vector sizes that // are not a multiple of the number of elements per scalar, so we // need to do an extra conversion here to get it into the right shape. - // For example if BiasRef is F8_E4M3FN and M is 7, it gets loaded to into - // vector, and if OutputElTy is half, Convert will return + // For example, if BiasRef is F8_E4M3FN and M is 7, it gets loaded into + // vector, and if OutputTy is half, Convert will return // vector instead of vector. // https://github.com/microsoft/DirectXShaderCompiler/issues/8418 - - // Convert to OutputElTy vector with padding + // + // Convert to OutputTy vector with padding using BiasConvInterpPaddedTy = InterpretedVector< - OutputElTy, - __detail::DstN<__detail::TypeTraits::CompType, BiasElTy, - __detail::ScalarCountFromPackedComponents< - BiasElTy, M>::Value>::Value, - __detail::TypeTraits::CompType>; + OutputTy, + __detail::DstN< + __detail::TypeTraits::CompType, BiasCT, + __detail::ScalarCountFromPackedComponents< BiasCT, M>::Value>::Value, + __detail::TypeTraits::CompType>; BiasConvInterpPaddedTy BiasConvInterpPadded = - Convert<__detail::TypeTraits::CompType, BiasElTy>(Bias); + Convert<__detail::TypeTraits::CompType, BiasCT>(Bias); // Truncate the vector to the correct size M - vector BiasConv = - (vector)BiasConvInterpPadded.Data; + vector BiasConv = (vector)BiasConvInterpPadded.Data; - vector Result; - __builtin_LinAlg_MatrixVectorMultiplyAdd( - Result, MatrixA.__handle, hlsl::is_signed::value, Vec, - __detail::TypeTraits::CompType, BiasConv); + vector Result; + dx::__builtin_LinAlg_MatrixVectorMultiplyAdd( + Result, MatrixA.__handle, hlsl::is_signed::value, Vec, + __detail::TypeTraits::CompType, BiasConv); return Result; } -template +template typename hlsl::enable_if< - VecK == __detail::ScalarCountFromPackedComponents::Value, - vector >::type -MultiplyAdd(Matrix MatrixA, - InterpretedVector InterpVec, - VectorRef BiasRef) { + VecK == __detail::ScalarCountFromPackedComponents::Value && + __detail::IsCompatibleVectorElement::value, + vector >::type +MultiplyAdd(Matrix MatrixA, + InterpretedVector InterpVec, + VectorRef BiasRef) { using BiasVecTy = - vector::Type, - __detail::ScalarCountFromPackedComponents::Value>; + vector::Type, + __detail::ScalarCountFromPackedComponents::Value>; BiasVecTy Bias = BiasRef.Buf.template Load(BiasRef.Offset); - // FIXME: Convert currently does not support packed type vector sizes that + // Convert currently does not support packed type vector sizes that // are not a multiple of the number of elements per scalar, so we // need to do an extra conversion here to get it into the right shape. - // For example if BiasRef is F8_E4M3FN and M is 7, it gets loaded to into - // vector, and if OutputElTy is half, Convert will return + // For example, if BiasRef is F8_E4M3FN and M is 7, it gets loaded into + // vector, and if OutputTy is half, Convert will return // vector instead of vector. // https://github.com/microsoft/DirectXShaderCompiler/issues/8418 - - // Convert to OutputElTy vector with padding + // + // Convert to OutputTy vector with padding using BiasConvInterpPaddedTy = InterpretedVector< - OutputElTy, - __detail::DstN<__detail::TypeTraits::CompType, BiasElTy, - __detail::ScalarCountFromPackedComponents< - BiasElTy, M>::Value>::Value, - __detail::TypeTraits::CompType>; + OutputTy, + __detail::DstN< + __detail::TypeTraits::CompType, BiasCT, + __detail::ScalarCountFromPackedComponents< BiasCT, M>::Value>::Value, + __detail::TypeTraits::CompType>; BiasConvInterpPaddedTy BiasConvInterpPadded = - Convert<__detail::TypeTraits::CompType, BiasElTy>(Bias); + Convert<__detail::TypeTraits::CompType, BiasCT>(Bias); // Truncate the vector to the correct size M - vector BiasConv = - (vector)BiasConvInterpPadded.Data; + vector BiasConv = (vector)BiasConvInterpPadded.Data; - vector Result; - __builtin_LinAlg_MatrixVectorMultiplyAdd( - Result, MatrixA.__handle, hlsl::is_signed::value, + vector Result; + dx::__builtin_LinAlg_MatrixVectorMultiplyAdd( + Result, MatrixA.__handle, hlsl::is_signed::value, InterpVec.Data, InterpVec.Interpretation, BiasConv); return Result; } // Outer product functions -template +template [[nodiscard]] typename hlsl::enable_if< - hlsl::is_arithmetic::value, - Matrix >::type -OuterProduct(vector VecA, vector VecB) { - Matrix Result; - __builtin_LinAlg_MatrixOuterProduct(Result.__handle, VecA, VecB); + hlsl::is_arithmetic::value, + Matrix >::type +OuterProduct(vector VecA, vector VecB) { + Matrix Result; + dx::__builtin_LinAlg_MatrixOuterProduct( + Result.__handle, hlsl::is_signed::value, VecA, VecB); return Result; } -template -typename hlsl::enable_if::value, void>::type +template +typename hlsl::enable_if::value, void>::type InterlockedAccumulate(RWByteAddressBuffer Res, uint StartOffset, - vector Vec) { - __builtin_LinAlg_VectorAccumulateToDescriptor(Res, StartOffset, Align, Vec); + vector Vec) { + dx::__builtin_LinAlg_VectorAccumulateToDescriptor(Res, StartOffset, Align, + Vec); } } // namespace linalg diff --git a/tools/clang/lib/Lex/PPMacroExpansion.cpp b/tools/clang/lib/Lex/PPMacroExpansion.cpp index 16040d69c7..edaed47a9a 100644 --- a/tools/clang/lib/Lex/PPMacroExpansion.cpp +++ b/tools/clang/lib/Lex/PPMacroExpansion.cpp @@ -1156,7 +1156,11 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("cxx_unicode_literals", LangOpts.CPlusPlus11) .Case("cxx_unrestricted_unions", LangOpts.CPlusPlus11) .Case("cxx_user_literals", LangOpts.CPlusPlus11) - .Case("cxx_variadic_templates", LangOpts.CPlusPlus11) + // HLSL Change Begin - Enable variadic templates. + .Case("cxx_variadic_templates", + LangOpts.CPlusPlus11 || + (LangOpts.HLSL && !LangOpts.HLSLDisallowsVariadicTemplates())) + // HLSL Change End. // C++1y features .Case("cxx_aggregate_nsdmi", LangOpts.CPlusPlus14) .Case("cxx_binary_literals", LangOpts.CPlusPlus14) @@ -1231,30 +1235,31 @@ static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) { // Because we inherit the feature list from HasFeature, this string switch // must be less restrictive than HasFeature's. return llvm::StringSwitch(Extension) - // C11 features supported by other languages as extensions. - .Case("c_alignas", true) - .Case("c_alignof", true) - .Case("c_atomic", true) - .Case("c_generic_selections", true) - .Case("c_static_assert", true) - .Case("c_thread_local", PP.getTargetInfo().isTLSSupported()) - // C++11 features supported by other languages as extensions. - .Case("cxx_atomic", LangOpts.CPlusPlus) - .Case("cxx_deleted_functions", LangOpts.CPlusPlus) - .Case("cxx_explicit_conversions", LangOpts.CPlusPlus) - .Case("cxx_inline_namespaces", LangOpts.CPlusPlus) - .Case("cxx_local_type_template_args", LangOpts.CPlusPlus) - .Case("cxx_nonstatic_member_init", LangOpts.CPlusPlus) - .Case("cxx_override_control", LangOpts.CPlusPlus) - .Case("cxx_range_for", LangOpts.CPlusPlus) - .Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus) - .Case("cxx_rvalue_references", LangOpts.CPlusPlus) - .Case("cxx_variadic_templates", LangOpts.CPlusPlus) - // C++1y features supported by other languages as extensions. - .Case("cxx_binary_literals", true) - .Case("cxx_init_captures", LangOpts.CPlusPlus11) - .Case("cxx_variable_templates", LangOpts.CPlusPlus) - .Default(false); + // C11 features supported by other languages as extensions. + .Case("c_alignas", true) + .Case("c_alignof", true) + .Case("c_atomic", true) + .Case("c_generic_selections", true) + .Case("c_static_assert", true) + .Case("c_thread_local", PP.getTargetInfo().isTLSSupported()) + // C++11 features supported by other languages as extensions. + .Case("cxx_atomic", LangOpts.CPlusPlus) + .Case("cxx_deleted_functions", LangOpts.CPlusPlus) + .Case("cxx_explicit_conversions", LangOpts.CPlusPlus) + .Case("cxx_inline_namespaces", LangOpts.CPlusPlus) + .Case("cxx_local_type_template_args", LangOpts.CPlusPlus) + .Case("cxx_nonstatic_member_init", LangOpts.CPlusPlus) + .Case("cxx_override_control", LangOpts.CPlusPlus) + .Case("cxx_range_for", LangOpts.CPlusPlus) + .Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus) + .Case("cxx_rvalue_references", LangOpts.CPlusPlus) + .Case("cxx_variadic_templates", + LangOpts.CPlusPlus && !LangOpts.HLSLDisallowsVariadicTemplates()) + // C++1y features supported by other languages as extensions. + .Case("cxx_binary_literals", true) + .Case("cxx_init_captures", LangOpts.CPlusPlus11) + .Case("cxx_variable_templates", LangOpts.CPlusPlus) + .Default(false); } /// EvaluateHasIncludeCommon - Process a '__has_include("path")' diff --git a/tools/clang/lib/Parse/ParseDecl.cpp b/tools/clang/lib/Parse/ParseDecl.cpp index 85404a1673..eea8e58d89 100644 --- a/tools/clang/lib/Parse/ParseDecl.cpp +++ b/tools/clang/lib/Parse/ParseDecl.cpp @@ -2667,78 +2667,79 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( if (isTokenEqualOrEqualTypo()) { SourceLocation EqualLoc = ConsumeToken(); - // HLSL Change Starts - skip legacy effects sampler_state { ... } assignment and warn - if (Tok.is(tok::kw_sampler_state)) { - Diag(Tok.getLocation(), diag::warn_hlsl_effect_sampler_state); + // HLSL Change Starts - skip legacy effects sampler_state assignment + if (getLangOpts().HLSLVersion < hlsl::LangStd::v202x && + Tok.is(tok::kw_sampler_state)) { + Diag(Tok.getLocation(), diag::warn_hlsl_2026_effects) + << /*sampler_state assignment*/ 1 << /*known not possible*/ 1; SkipUntil(tok::l_brace); // skip until '{' SkipUntil(tok::r_brace); // skip until '}' } else - // HLSL Change Ends - if (Tok.is(tok::kw_delete)) { - if (D.isFunctionDeclarator()) - Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) - << 1 /* delete */; - else - Diag(ConsumeToken(), diag::err_deleted_non_function); - } else if (Tok.is(tok::kw_default)) { - if (D.isFunctionDeclarator()) - Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) - << 0 /* default */; - else - Diag(ConsumeToken(), diag::err_default_special_members); - } else { - if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { - EnterScope(0); - Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl); - } + // HLSL Change Ends + if (Tok.is(tok::kw_delete)) { + if (D.isFunctionDeclarator()) + Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) + << 1 /* delete */; + else + Diag(ConsumeToken(), diag::err_deleted_non_function); + } else if (Tok.is(tok::kw_default)) { + if (D.isFunctionDeclarator()) + Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) + << 0 /* default */; + else + Diag(ConsumeToken(), diag::err_default_special_members); + } else { + if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { + EnterScope(0); + Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl); + } - if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteInitializer(getCurScope(), ThisDecl); - Actions.FinalizeDeclaration(ThisDecl); - cutOffParsing(); - return nullptr; - } + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteInitializer(getCurScope(), ThisDecl); + Actions.FinalizeDeclaration(ThisDecl); + cutOffParsing(); + return nullptr; + } + // HLSL Change Begin. + // Skip the initializer of effect object. + if (D.isInvalidType()) { + SkipUntil(tok::semi, StopBeforeMatch); // skip until ';' + Actions.ActOnUninitializedDecl(ThisDecl, TypeContainsAuto); + return nullptr; + } + // HLSL Change End. + + ExprResult Init(ParseInitializer()); + + // If this is the only decl in (possibly) range based for statement, + // our best guess is that the user meant ':' instead of '='. + if (Tok.is(tok::r_paren) && FRI && D.isFirstDeclarator()) { + Diag(EqualLoc, diag::err_single_decl_assign_in_for_range) + << FixItHint::CreateReplacement(EqualLoc, ":"); + // We are trying to stop parser from looking for ';' in this for + // statement, therefore preventing spurious errors to be issued. + FRI->ColonLoc = EqualLoc; + Init = ExprError(); + FRI->RangeExpr = Init; + } - // HLSL Change Begin. - // Skip the initializer of effect object. - if (D.isInvalidType()) { - SkipUntil(tok::semi, StopBeforeMatch); // skip until ';' - Actions.ActOnUninitializedDecl(ThisDecl, TypeContainsAuto); - return nullptr; - } - // HLSL Change End. - - ExprResult Init(ParseInitializer()); - - // If this is the only decl in (possibly) range based for statement, - // our best guess is that the user meant ':' instead of '='. - if (Tok.is(tok::r_paren) && FRI && D.isFirstDeclarator()) { - Diag(EqualLoc, diag::err_single_decl_assign_in_for_range) - << FixItHint::CreateReplacement(EqualLoc, ":"); - // We are trying to stop parser from looking for ';' in this for - // statement, therefore preventing spurious errors to be issued. - FRI->ColonLoc = EqualLoc; - Init = ExprError(); - FRI->RangeExpr = Init; - } + if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { + Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); + ExitScope(); + } - if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { - Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); - ExitScope(); + if (Init.isInvalid()) { + SmallVector StopTokens; + StopTokens.push_back(tok::comma); + if (D.getContext() == Declarator::ForContext) + StopTokens.push_back(tok::r_paren); + SkipUntil(StopTokens, StopAtSemi | StopBeforeMatch); + Actions.ActOnInitializerError(ThisDecl); + } else + Actions.AddInitializerToDecl(ThisDecl, Init.get(), + /*DirectInit=*/false, TypeContainsAuto); } - - if (Init.isInvalid()) { - SmallVector StopTokens; - StopTokens.push_back(tok::comma); - if (D.getContext() == Declarator::ForContext) - StopTokens.push_back(tok::r_paren); - SkipUntil(StopTokens, StopAtSemi | StopBeforeMatch); - Actions.ActOnInitializerError(ThisDecl); - } else - Actions.AddInitializerToDecl(ThisDecl, Init.get(), - /*DirectInit=*/false, TypeContainsAuto); - } } else if (Tok.is(tok::l_paren)) { // Parse C++ direct initializer: '(' expression-list ')' BalancedDelimiterTracker T(*this, tok::l_paren); @@ -2806,12 +2807,15 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( /*DirectInit=*/true, TypeContainsAuto); // HLSL Change Starts - } else if (getLangOpts().HLSL && Tok.is(tok::l_brace) && - !D.isFunctionDeclarator()) { + } else if (getLangOpts().HLSL && + getLangOpts().HLSLVersion < hlsl::LangStd::v202x && + Tok.is(tok::l_brace) && !D.isFunctionDeclarator()) { // HLSL allows for a block definition here that it silently ignores. // This is to allow for effects state block definitions. Detect a // block here, warn about effect deprecation, and ignore the block. - Diag(Tok.getLocation(), diag::warn_hlsl_effect_state_block); + Diag(Tok.getLocation(), diag::warn_hlsl_2026_effects) + << /*state block */ 2 << /*known not possible*/ 1; + Diag(Tok.getLocation(), diag::note_hlsl_effects_use_equal); ConsumeBrace(); SkipUntil(tok::r_brace); // skip until '}' // Braces could have been used to initialize an array. @@ -3865,6 +3869,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, break; // HLSL Change Starts case tok::kw_shared: + Diag(Tok.getLocation(), diag::warn_hlsl_2026_removed_keyword) << "shared"; + [[fallthrough]]; case tok::kw_groupshared: case tok::kw_uniform: case tok::kw_in: @@ -6103,12 +6109,11 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // been expanded or contains auto; otherwise, it is parsed as part of the // parameter-declaration-clause. if (Tok.is(tok::ellipsis) && D.getCXXScopeSpec().isEmpty() && - !getLangOpts().HLSL && // HLSL Change: do not support ellipsis + !getLangOpts().HLSLDisallowsVariadicTemplates() && // HLSL Change !((D.getContext() == Declarator::PrototypeContext || D.getContext() == Declarator::LambdaExprParameterContext || D.getContext() == Declarator::BlockLiteralContext) && - NextToken().is(tok::r_paren) && - !D.hasGroupingParens() && + NextToken().is(tok::r_paren) && !D.hasGroupingParens() && !Actions.containsUnexpandedParameterPacks(D) && D.getDeclSpec().getTypeSpecType() != TST_auto)) { SourceLocation EllipsisLoc = ConsumeToken(); @@ -6330,9 +6335,10 @@ void Parser::ParseDirectDeclarator(Declarator &D) { if (getLangOpts().HLSL) { if (MaybeParseHLSLAttributes(D)) D.setInvalidType(); - if (Tok.is(tok::less)) { + if (getLangOpts().HLSLVersion < hlsl::LangStd::v202x && Tok.is(tok::less)) { // Consume effects annotations - Diag(Tok.getLocation(), diag::warn_hlsl_effect_annotation); + Diag(Tok.getLocation(), diag::warn_hlsl_2026_effects) + << /*annotation*/ 0 << /*possible*/ 0; ConsumeToken(); while (!Tok.is(tok::greater) && !Tok.is(tok::eof)) { SkipUntil(tok::semi); // skip through ; @@ -6545,14 +6551,28 @@ void Parser::ParseFunctionDeclarator(Declarator &D, // with the pure-specifier in the same way. // Parse cv-qualifier-seq[opt]. + // HLSL Change Starts + // HLSL only supports `const` here (HLSL 202x). Parse it directly because + // the HLSL path of ParseTypeQualifierListOpt is shared with other + // declarator contexts (e.g. array bounds) that must still reject it. + if (getLangOpts().HLSL) { + while (Tok.is(tok::kw_const)) { + const char *PrevSpec = nullptr; + unsigned DiagID = 0; + SourceLocation Loc = Tok.getLocation(); + if (DS.SetTypeQual(DeclSpec::TQ_const, Loc, PrevSpec, DiagID, + getLangOpts())) + Diag(Loc, DiagID) << PrevSpec; + DS.SetRangeEnd(ConsumeToken()); + } + if (DS.getConstSpecLoc().isValid() && + getLangOpts().HLSLVersion < hlsl::LangStd::v202x) + Diag(DS.getConstSpecLoc(), diag::err_hlsl_const_member_function_202x); + } + // HLSL Change Ends ParseTypeQualifierListOpt(DS, AR_NoAttributesParsed, /*AtomicAllowed*/ false); if (!DS.getSourceRange().getEnd().isInvalid()) { - // HLSL Change Starts - if (getLangOpts().HLSL) { - Diag(DS.getSourceRange().getEnd(), diag::err_hlsl_unsupported_construct) << "qualifiers"; - } - // HLSL Change Ends EndLoc = DS.getSourceRange().getEnd(); ConstQualifierLoc = DS.getConstSpecLoc(); VolatileQualifierLoc = DS.getVolatileSpecLoc(); diff --git a/tools/clang/lib/Parse/ParseDeclCXX.cpp b/tools/clang/lib/Parse/ParseDeclCXX.cpp index 8412987a39..0861cf2de5 100644 --- a/tools/clang/lib/Parse/ParseDeclCXX.cpp +++ b/tools/clang/lib/Parse/ParseDeclCXX.cpp @@ -736,12 +736,18 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ ExprResult AssertMessage; if (Tok.is(tok::r_paren)) { - Diag(Tok, getLangOpts().CPlusPlus1z - ? diag::warn_cxx14_compat_static_assert_no_message - : diag::ext_static_assert_no_message) - << (getLangOpts().CPlusPlus1z - ? FixItHint() - : FixItHint::CreateInsertion(Tok.getLocation(), ", \"\"")); + // HLSL Change Starts - In HLSL 202x, allow omitting the message just like + // C++17 does, without emitting an extension warning. + bool AllowNoMessage = getLangOpts().CPlusPlus1z || + (getLangOpts().HLSL && + getLangOpts().HLSLVersion >= hlsl::LangStd::v202x); + if (!AllowNoMessage) + Diag(Tok, diag::ext_static_assert_no_message) + << FixItHint::CreateInsertion(Tok.getLocation(), ", \"\""); + else if (getLangOpts().CPlusPlus1z) + Diag(Tok, diag::warn_cxx14_compat_static_assert_no_message) + << FixItHint(); + // HLSL Change Ends } else { if (ExpectAndConsume(tok::comma)) { SkipUntil(tok::semi); diff --git a/tools/clang/lib/Parse/ParseExpr.cpp b/tools/clang/lib/Parse/ParseExpr.cpp index 9af3dbe610..76117ceb9b 100644 --- a/tools/clang/lib/Parse/ParseExpr.cpp +++ b/tools/clang/lib/Parse/ParseExpr.cpp @@ -1946,7 +1946,8 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { ConsumeToken(); // [C++11] 'sizeof' '...' '(' identifier ')' - if (Tok.is(tok::ellipsis) && OpTok.is(tok::kw_sizeof) && !getLangOpts().HLSL) { // HLSL Change + if (Tok.is(tok::ellipsis) && OpTok.is(tok::kw_sizeof) && + !getLangOpts().HLSLDisallowsVariadicTemplates()) { // HLSL Change SourceLocation EllipsisLoc = ConsumeToken(); SourceLocation LParenLoc, RParenLoc; IdentifierInfo *Name = nullptr; @@ -2747,9 +2748,12 @@ ExprResult Parser::ParseFoldExpression(ExprResult LHS, } } - Diag(EllipsisLoc, getLangOpts().CPlusPlus1z - ? diag::warn_cxx14_compat_fold_expression - : diag::ext_fold_expression); + if (getLangOpts().HLSL && !getLangOpts().HLSLDisallowsVariadicTemplates()) + Diag(EllipsisLoc, diag::warn_hlsl_fold_expression); + else + Diag(EllipsisLoc, getLangOpts().CPlusPlus1z + ? diag::warn_cxx14_compat_fold_expression + : diag::ext_fold_expression); T.consumeClose(); return Actions.ActOnCXXFoldExpr(T.getOpenLocation(), LHS.get(), Kind, @@ -2801,7 +2805,7 @@ bool Parser::ParseExpressionList(SmallVectorImpl &Exprs, if (Tok.is(tok::ellipsis)) { // HLSL Change Starts - if (getLangOpts().HLSL) { + if (getLangOpts().HLSLDisallowsVariadicTemplates()) { Diag(Tok, diag::err_hlsl_variadic_templates); SkipUntil(tok::r_paren, StopBeforeMatch); Actions.CorrectDelayedTyposInExpr(Expr); diff --git a/tools/clang/lib/Parse/ParseInit.cpp b/tools/clang/lib/Parse/ParseInit.cpp index 1dcb20645d..1ef318f52e 100644 --- a/tools/clang/lib/Parse/ParseInit.cpp +++ b/tools/clang/lib/Parse/ParseInit.cpp @@ -438,7 +438,7 @@ ExprResult Parser::ParseBraceInitializer() { if (Tok.is(tok::ellipsis)) { // HLSL Change Starts - if (getLangOpts().HLSL) { + if (getLangOpts().HLSLDisallowsVariadicTemplates()) { Diag(Tok, diag::err_hlsl_unsupported_construct) << "expansion"; InitExprsOk = false; SkipUntil(tok::r_brace, StopBeforeMatch); diff --git a/tools/clang/lib/Parse/ParseTemplate.cpp b/tools/clang/lib/Parse/ParseTemplate.cpp index fbedf41caa..960dc6fa30 100644 --- a/tools/clang/lib/Parse/ParseTemplate.cpp +++ b/tools/clang/lib/Parse/ParseTemplate.cpp @@ -516,15 +516,15 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { SourceLocation EllipsisLoc; if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) { // HLSL Change Starts - if (getLangOpts().HLSL) { + if (getLangOpts().HLSLDisallowsVariadicTemplates()) { Diag(EllipsisLoc, diag::err_hlsl_variadic_templates); return nullptr; } // HLSL Change Ends - Diag(EllipsisLoc, - getLangOpts().CPlusPlus11 - ? diag::warn_cxx98_compat_variadic_templates - : diag::ext_variadic_templates); + if (!getLangOpts().HLSL) // HLSL Change: HLSL has no C++98-compat warnings + Diag(EllipsisLoc, getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_variadic_templates + : diag::ext_variadic_templates); } // Grab the template parameter name (if given) @@ -620,9 +620,9 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { SourceLocation EllipsisLoc; if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) { // HLSL Change Starts - if (getLangOpts().HLSL) + if (getLangOpts().HLSLDisallowsVariadicTemplates()) Diag(EllipsisLoc, diag::err_hlsl_variadic_templates); - else + else if (!getLangOpts().HLSL) // HLSL has no C++98-compat warnings // HLSL Change Ends Diag(EllipsisLoc, getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_variadic_templates @@ -1296,7 +1296,7 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { SourceLocation EllipsisLoc; if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) { // HLSL Change Starts - if (getLangOpts().HLSL) { + if (getLangOpts().HLSLDisallowsVariadicTemplates()) { Diag(EllipsisLoc, diag::err_hlsl_unsupported_construct) << "ellipsis"; SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch); return true; diff --git a/tools/clang/lib/Parse/Parser.cpp b/tools/clang/lib/Parse/Parser.cpp index 01371b8242..bf7f486963 100644 --- a/tools/clang/lib/Parse/Parser.cpp +++ b/tools/clang/lib/Parse/Parser.cpp @@ -587,12 +587,13 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { // HLSL Change Starts - skip legacy effects technique syntax case tok::kw_technique: - Diag(Tok.getLocation(), diag::warn_hlsl_effect_technique); - SkipUntil(tok::l_brace); // skip through { - SkipUntil(tok::r_brace); // skip through matching } + Diag(Tok.getLocation(), diag::warn_hlsl_2026_effects) + << /*technique*/ 3 << /*known not possible*/ 1; + SkipUntil(tok::l_brace); // skip through { + SkipUntil(tok::r_brace); // skip through matching } Result = DeclGroupPtrTy(); return false; - // HLSL Change Ends + // HLSL Change Ends default: break; @@ -760,8 +761,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, return DeclGroupPtrTy(); // HLSL Change Starts: Ignore shared keyword for now case tok::kw_shared: - ConsumeToken(); - return ParseExternalDeclaration(attrs); + Diag(Tok.getLocation(), diag::warn_hlsl_2026_removed_keyword) << "shared"; + ConsumeToken(); + return ParseExternalDeclaration(attrs); // HLSL Change Ends // HLSL Change Starts: Start parsing declaration of cbuffer and tbuffers case tok::kw_cbuffer: diff --git a/tools/clang/lib/SPIRV/AstTypeProbe.cpp b/tools/clang/lib/SPIRV/AstTypeProbe.cpp index c933a82c16..a871bd3577 100644 --- a/tools/clang/lib/SPIRV/AstTypeProbe.cpp +++ b/tools/clang/lib/SPIRV/AstTypeProbe.cpp @@ -1141,12 +1141,13 @@ bool isOpaqueType(QualType type) { if (name == "RaytracingAccelerationStructure") return true; - if (name == "RayQuery") - return true; - if (name == "SubpassInput") return true; } + + if (hlsl::IsHLSLRayQueryType(type)) + return true; + return false; } diff --git a/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp b/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp index 3a88334ffc..9aaa36c97b 100644 --- a/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp +++ b/tools/clang/lib/SPIRV/DeclResultIdMapper.cpp @@ -299,6 +299,14 @@ LocationAndComponent getLocationAndComponentCount(const ASTContext &astContext, return {0, 0, false}; } +/// Returns true if the given decl is a static variable declared inside +/// a cbuffer/tbuffer/struct. These are not actually part of the +/// cbuffer/tbuffer/struct, and should not consume a member index. +bool isStaticBufferDecl(const Decl *decl) { + const auto *varDecl = dyn_cast(decl); + return varDecl && varDecl->getStorageClass() == StorageClass::SC_Static; +} + bool shouldSkipInStructLayout(const Decl *decl) { // Ignore implicit generated struct declarations/constructors/destructors if (decl->isImplicit()) @@ -1455,7 +1463,7 @@ SpirvVariable *DeclResultIdMapper::createStructOrStructArrayVarOfExplicitLayout( // Static variables are not part of the struct from a layout perspective. // Thus, they should not be listed in the struct fields. - if (fieldVar->getStorageClass() == StorageClass::SC_Static) { + if (isStaticBufferDecl(fieldVar)) { continue; } @@ -1558,8 +1566,11 @@ void DeclResultIdMapper::createCTBuffer(const HLSLBufferDecl *decl) { if (shouldSkipInStructLayout(subDecl)) continue; - // If the subDecl is a resource, it is lowered as a standalone variable. const auto *varDecl = cast(subDecl); + + if (isStaticBufferDecl(varDecl)) + continue; + if (isResourceType(varDecl->getType())) { createExternVar(varDecl); continue; @@ -1737,6 +1748,9 @@ DeclResultIdMapper::createShaderRecordBuffer(const HLSLBufferDecl *decl, if (isResourceType(varDecl->getType())) continue; + if (isStaticBufferDecl(varDecl)) + continue; + registerVariableForDecl(varDecl, createDeclSpirvInfo(bufferVar, index++)); } return bufferVar; @@ -1766,13 +1780,6 @@ void DeclResultIdMapper::createGlobalsCBuffer(const VarDecl *var) { uint32_t index = 0; for (const auto *decl : collectDeclsInDeclContext(context)) { if (const auto *varDecl = dyn_cast(decl)) { - if (!spirvOptions.noWarnIgnoredFeatures) { - if (const auto *init = varDecl->getInit()) - emitWarning( - "variable '%0' will be placed in $Globals so initializer ignored", - init->getExprLoc()) - << var->getName() << init->getSourceRange(); - } if (const auto *attr = varDecl->getAttr()) { emitError("variable '%0' will be placed in $Globals so cannot have " "vk::binding attribute", diff --git a/tools/clang/lib/SPIRV/LowerTypeVisitor.cpp b/tools/clang/lib/SPIRV/LowerTypeVisitor.cpp index 4c06cd4113..b330d40d85 100644 --- a/tools/clang/lib/SPIRV/LowerTypeVisitor.cpp +++ b/tools/clang/lib/SPIRV/LowerTypeVisitor.cpp @@ -965,7 +965,7 @@ LowerTypeVisitor::lowerResourceType(QualType type, SpirvLayoutRule rule, return spvContext.getAccelerationStructureTypeNV(); } - if (name == "RayQuery") + if (hlsl::IsHLSLRayQueryType(type)) return spvContext.getRayQueryTypeKHR(); if (name == "StructuredBuffer" || name == "RWStructuredBuffer" || diff --git a/tools/clang/lib/SPIRV/SpirvBuilder.cpp b/tools/clang/lib/SPIRV/SpirvBuilder.cpp index d8eceaccc6..216025c984 100644 --- a/tools/clang/lib/SPIRV/SpirvBuilder.cpp +++ b/tools/clang/lib/SPIRV/SpirvBuilder.cpp @@ -305,6 +305,7 @@ SpirvStore *SpirvBuilder::createStore(SpirvInstruction *address, } SpirvInstruction *source = value; + SpirvLoad *bitfieldLoad = nullptr; const auto &bitfieldInfo = address->getBitfieldInfo(); if (bitfieldInfo.hasValue()) { // Generate SPIR-V type for value. This is required to know the final @@ -313,11 +314,12 @@ SpirvStore *SpirvBuilder::createStore(SpirvInstruction *address, lowerTypeVisitor.visitInstruction(value); context.addToInstructionsWithLoweredType(value); - auto *base = createLoad(value->getResultType(), address, loc, range); - source = createBitFieldInsert(/*QualType*/ {}, base, value, + bitfieldLoad = createLoad(value->getResultType(), address, loc, range); + source = createBitFieldInsert(/*QualType*/ {}, bitfieldLoad, value, bitfieldInfo->offsetInBits, bitfieldInfo->sizeInBits, loc, range); source->setResultType(value->getResultType()); + source->setAstResultType(value->getAstResultType()); } auto *instruction = @@ -337,6 +339,8 @@ SpirvStore *SpirvBuilder::createStore(SpirvInstruction *address, std::tie(align, size) = alignmentCalc.getAlignmentAndSize( source->getAstResultType(), address->getLayoutRule(), llvm::None, &stride); + if (bitfieldLoad) + bitfieldLoad->setAlignment(align); instruction->setAlignment(align); } diff --git a/tools/clang/lib/SPIRV/SpirvEmitter.cpp b/tools/clang/lib/SPIRV/SpirvEmitter.cpp index f05c0d9553..13abbdbe90 100644 --- a/tools/clang/lib/SPIRV/SpirvEmitter.cpp +++ b/tools/clang/lib/SPIRV/SpirvEmitter.cpp @@ -1051,7 +1051,7 @@ void SpirvEmitter::HandleTranslationUnit(ASTContext &context) { void SpirvEmitter::doDecl(const Decl *decl) { if (isa(decl) || isa(decl) || - isa(decl)) + isa(decl) || isa(decl)) return; // Implicit decls are lazily created when needed. @@ -1937,17 +1937,10 @@ void SpirvEmitter::registerCapabilitiesAndExtensionsForVarDecl( void SpirvEmitter::doHLSLBufferDecl(const HLSLBufferDecl *bufferDecl) { // This is a cbuffer/tbuffer decl. - // Check and emit warnings for member intializers which are not - // supported in Vulkan for (const auto *member : bufferDecl->decls()) { if (const auto *varMember = dyn_cast(member)) { - if (!spirvOptions.noWarnIgnoredFeatures) { - if (const auto *init = varMember->getInit()) - emitWarning("%select{tbuffer|cbuffer}0 member initializer " - "ignored since no Vulkan equivalent", - init->getExprLoc()) - << bufferDecl->isCBuffer() << init->getSourceRange(); - } + if (varMember->getStorageClass() == StorageClass::SC_Static) + continue; // We cannot handle external initialization of column-major matrices now. if (isOrContainsNonFpColMajorMatrix(astContext, spirvOptions, @@ -1970,6 +1963,12 @@ void SpirvEmitter::doHLSLBufferDecl(const HLSLBufferDecl *bufferDecl) { } else { declIdMapper.createCTBuffer(bufferDecl); } + + for (const auto *member : bufferDecl->decls()) { + const auto *varMember = dyn_cast(member); + if (varMember && varMember->getStorageClass() == StorageClass::SC_Static) + doVarDecl(varMember); + } } void SpirvEmitter::doClassTemplateDecl( @@ -2165,9 +2164,11 @@ void SpirvEmitter::doVarDecl(const VarDecl *decl) { // ConstantBuffers and TextureBuffers are not HLSLBufferDecls. if (const auto *bufferDecl = dyn_cast(decl->getDeclContext())) { - // This is a VarDecl of cbuffer/tbuffer type. - doHLSLBufferDecl(bufferDecl); - return; + if (decl->getStorageClass() != StorageClass::SC_Static) { + // This is a VarDecl of cbuffer/tbuffer type. + doHLSLBufferDecl(bufferDecl); + return; + } } if (decl->getAttr()) { @@ -2188,10 +2189,6 @@ void SpirvEmitter::doVarDecl(const VarDecl *decl) { // variables) belongs to the Function storage class. if (isExternalVar(decl)) { var = declIdMapper.createExternVar(decl); - if (decl->hasInit()) { - emitWarning("Initializer of external global will be ignored", - decl->getLocation()); - } } else { // We already know the variable is not externally visible here. If it does // not have local storage, it should be file scope variable. @@ -16224,9 +16221,22 @@ SpirvInstruction *SpirvEmitter::processRawBufferLoad(const CallExpr *callExpr) { return nullptr; } - uint32_t alignment = callExpr->getNumArgs() == 1 - ? 4 - : getRawBufferAlignment(callExpr->getArg(1)); + uint32_t alignment = 0; + if (callExpr->getNumArgs() == 1) { + // Compute the required scalar alignment from the loaded type. + // Per the Vulkan spec, PhysicalStorageBuffer alignment must be at least the + // largest scalar alignment within the type, this matches scalar layout + // rules. See: + // https://docs.vulkan.org/guide/latest/buffer_device_address_alignment.html + AlignmentSizeCalculator alignmentCalc(astContext, spirvOptions); + uint32_t stride = 0; + QualType bufferType = callExpr->getCallReturnType(astContext); + std::tie(alignment, std::ignore) = + alignmentCalc.getAlignmentAndSize(bufferType, SpirvLayoutRule::Scalar, + /*isRowMajor*/ llvm::None, &stride); + } else { + alignment = getRawBufferAlignment(callExpr->getArg(1)); + } if (alignment == 0) return nullptr; @@ -16327,9 +16337,22 @@ SpirvEmitter::processRawBufferStore(const CallExpr *callExpr) { return nullptr; } - uint32_t alignment = callExpr->getNumArgs() == 2 - ? 4 - : getRawBufferAlignment(callExpr->getArg(2)); + uint32_t alignment = 0; + if (callExpr->getNumArgs() == 2) { + // Compute the required scalar alignment from the stored type. + // Per the Vulkan spec, PhysicalStorageBuffer alignment must be at least the + // largest scalar alignment within the type, this matches scalar layout + // rules. See: + // https://docs.vulkan.org/guide/latest/buffer_device_address_alignment.html + QualType bufferType = callExpr->getArg(1)->getType(); + AlignmentSizeCalculator alignmentCalc(astContext, spirvOptions); + uint32_t stride = 0; + std::tie(alignment, std::ignore) = + alignmentCalc.getAlignmentAndSize(bufferType, SpirvLayoutRule::Scalar, + /*isRowMajor*/ llvm::None, &stride); + } else { + alignment = getRawBufferAlignment(callExpr->getArg(2)); + } if (alignment == 0) return nullptr; diff --git a/tools/clang/lib/Sema/SemaDecl.cpp b/tools/clang/lib/Sema/SemaDecl.cpp index 52c870d994..1b1b6e1305 100644 --- a/tools/clang/lib/Sema/SemaDecl.cpp +++ b/tools/clang/lib/Sema/SemaDecl.cpp @@ -25,6 +25,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/HlslTypes.h" // HLSL Change #include "clang/AST/StmtCXX.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/PartialDiagnostic.h" @@ -65,6 +66,28 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType) { namespace { +// HLSL Change Begin +// Returns true if VD is a shader constant: a variable stored in an explicit +// cbuffer/tbuffer declaration, or in the implicit $Globals constant buffer. +// On success IsConstantBuffer is false only for tbuffer members. +bool IsHLSLShaderConstant(const VarDecl *VD, bool &IsConstantBuffer) { + if (const auto *Buffer = dyn_cast(VD->getDeclContext())) { + IsConstantBuffer = Buffer->isCBuffer(); + return VD->getStorageClass() != SC_Static; + } + + IsConstantBuffer = true; + const DeclContext *DC = VD->getDeclContext(); + return (DC->isTranslationUnit() || DC->isNamespace()) && + VD->hasExternalFormalLinkage() && + !VD->hasAttr() && + !VD->hasAttr() && + !VD->hasAttr() && + !VD->hasAttr() && + hlsl::IsHLSLNumericOrAggregateOfNumericType(VD->getType()); +} +// HLSL Change End + class TypeNameValidatorCCC : public CorrectionCandidateCallback { public: TypeNameValidatorCCC(bool AllowInvalid, bool WantClass=false, @@ -3442,6 +3465,14 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous, ShadowMergeState& if (New->isInvalidDecl()) return; + // HLSL does not permit multiple declarations of a global variable. + if (getLangOpts().HLSL && New->isFileVarDecl() && Old->isFileVarDecl() && + !New->isStaticDataMember() && !Old->isStaticDataMember()) { + Diag(New->getLocation(), diag::err_redefinition) << New->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_definition); + return New->setInvalidDecl(); + } + diag::kind PrevDiag; SourceLocation OldLocation; std::tie(PrevDiag, OldLocation) = @@ -7484,7 +7515,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_auto_fn_virtual); } - if (getLangOpts().CPlusPlus14 && + if ((getLangOpts().CPlusPlus14 || getLangOpts().HLSL) && // HLSL Change (NewFD->isDependentContext() || (isFriend && CurContext->isDependentContext())) && NewFD->getReturnType()->isUndeducedType()) { @@ -9055,7 +9086,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // A dependent deduced type cannot be classified yet; defer the check to // instantiation, when 'auto' is re-deduced to a concrete type. if (!DeducedType->isDependentType() && - !hlsl::IsTypeDeducibleWithAuto(*this, DeducedType)) { + !hlsl::IsTypeDeducibleWithAuto(DeducedType)) { Diag(VDecl->getLocation(), diag::err_hlsl_auto_undeducible_type) << DeducedType; VDecl->setInvalidDecl(); @@ -9325,6 +9356,28 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // Attach the initializer to the decl. VDecl->setInit(Init); + // HLSL Change Begin + if (getLangOpts().HLSL) { + if (VDecl->hasAttr() && + (getLangOpts().SPIRV || VDecl->isExternallyVisible())) { + Diag(Init->getExprLoc(), diag::warn_hlsl_groupshared_initializer) + << Init->getSourceRange(); + } else { + // Variables in a cbuffer/tbuffer declaration, or in the implicit + // $Globals constant buffer, are initialized by the pipeline, so any + // initializer is ignored. This is an error starting with HLSL 202x. + bool IsConstantBuffer = false; + if (IsHLSLShaderConstant(VDecl, IsConstantBuffer)) { + Diag(Init->getExprLoc(), + getLangOpts().HLSLVersion >= hlsl::LangStd::v202x + ? diag::err_hlsl_buffer_initializer + : diag::warn_hlsl_buffer_initializer) + << IsConstantBuffer << Init->getSourceRange(); + } + } + } + // HLSL Change End + if (VDecl->isLocalVarDecl()) { // C99 6.7.8p4: All the expressions in an initializer for an object that has // static storage duration shall be constant expressions or string literals. @@ -10907,8 +10960,11 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, if (FD) { FD->setBody(Body); - if (getLangOpts().CPlusPlus14 && !FD->isInvalidDecl() && Body && - !FD->isDependentContext() && FD->getReturnType()->isUndeducedType()) { + // HLSL Change Begin - HLSL supports C++14-style deduced return types. + if ((getLangOpts().CPlusPlus14 || getLangOpts().HLSL) && + !FD->isInvalidDecl() && Body && !FD->isDependentContext() && + FD->getReturnType()->isUndeducedType()) { + // HLSL Change End // If the function has a deduced result type but contains no 'return' // statements, the result type as written must be exactly 'auto', and // the deduced result type is 'void'. diff --git a/tools/clang/lib/Sema/SemaExpr.cpp b/tools/clang/lib/Sema/SemaExpr.cpp index 1c6c699bde..725e517ad5 100644 --- a/tools/clang/lib/Sema/SemaExpr.cpp +++ b/tools/clang/lib/Sema/SemaExpr.cpp @@ -63,7 +63,9 @@ bool Sema::CanUseDecl(NamedDecl *D) { // If the function has a deduced return type, and we can't deduce it, // then we can't use it either. - if (getLangOpts().CPlusPlus14 && FD->getReturnType()->isUndeducedType() && + // HLSL Change - HLSL supports C++14-style deduced return types. + if ((getLangOpts().CPlusPlus14 || getLangOpts().HLSL) && + FD->getReturnType()->isUndeducedType() && DeduceReturnType(FD, SourceLocation(), /*Diagnose*/ false)) return false; } @@ -366,8 +368,9 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, // If the function has a deduced return type, and we can't deduce it, // then we can't use it either. - if (getLangOpts().CPlusPlus14 && FD->getReturnType()->isUndeducedType() && - DeduceReturnType(FD, Loc)) + // HLSL Change - HLSL supports C++14-style deduced return types. + if ((getLangOpts().CPlusPlus14 || getLangOpts().HLSL) && + FD->getReturnType()->isUndeducedType() && DeduceReturnType(FD, Loc)) return true; } DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass, @@ -3537,7 +3540,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { if (Val < std::numeric_limits::max()) Width = 32; uint64_t MSB = 1ull << (Width - 1); - if ((Val & MSB) != 0) + if (!Literal.isUnsigned && (Val & MSB) != 0) Diag(Tok.getLocation(), diag::warn_hlsl_legacy_integer_literal_signedness); } @@ -3699,7 +3702,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { // HLSL Change Begin - 202x integer warnings. if (Literal.getRadix() != 10) { uint64_t Val = ResultVal.getLimitedValue(); - if ((Val & MSB) != 0) + if (!Literal.isUnsigned && (Val & MSB) != 0) Diag(Tok.getLocation(), diag::warn_hlsl_legacy_integer_literal_signedness); } diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index 66e673d015..5d480a99ee 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -47,11 +47,11 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include -#include #include #include @@ -1042,7 +1042,7 @@ static const ArTypeObjectKind g_ArrayTT[] = {AR_TOBJ_ARRAY, AR_TOBJ_UNKNOWN}; const ArTypeObjectKind *g_LegalIntrinsicTemplates[] = { g_NullTT, g_ScalarTT, g_VectorTT, g_MatrixTT, - g_AnyTT, g_ObjectTT, g_ArrayTT, + g_AnyTT, g_ObjectTT, g_ArrayTT, g_ArrayTT, }; C_ASSERT(ARRAYSIZE(g_LegalIntrinsicTemplates) == LITEMPLATE_COUNT); @@ -2002,6 +2002,15 @@ static bool IsStaticMember(const HLSL_INTRINSIC *fn) { return fn->Flags & INTRIN_FLAG_STATIC_MEMBER; } +// Returns true if the intrinsic is a non-static method that does not mutate +// instance state. Writing through a resource handle does not mutate the handle. +static bool IsConstMemberIntrinsic(const HLSL_INTRINSIC *fn) { + if (IsStaticMember(fn)) + return false; + // A method is const unless it explicitly mutates the object. + return !(fn->Flags & INTRIN_FLAG_MUTABLE_METHOD); +} + static bool IsVariadicIntrinsicFunction(const HLSL_INTRINSIC *fn) { return fn->pArgs[fn->uNumArgs - 1].uTemplateId == INTRIN_TEMPLATE_VARARGS; } @@ -2021,7 +2030,6 @@ ParamModsFromIntrinsicArg(const HLSL_INTRINSIC_ARGUMENT *pArg) { } if (pArg->qwUsage == AR_QUAL_REF) return hlsl::ParameterModifier(hlsl::ParameterModifier::Kind::Ref); - // TODO: https://github.com/microsoft/DirectXShaderCompiler/issues/8270 if (pArg->qwUsage == AR_QUAL_GROUPSHARED) return hlsl::ParameterModifier(hlsl::ParameterModifier::Kind::In); DXASSERT(qwUsage & AR_QUAL_IN, "else usage is incorrect"); @@ -2090,12 +2098,31 @@ static void AddHLSLIntrinsicAttr(FunctionDecl *FD, ASTContext &context, FD->addAttr(PureAttr::CreateImplicit(context)); if (pIntrinsic->Flags & INTRIN_FLAG_IS_WAVE) FD->addAttr(HLSLWaveSensitiveAttr::CreateImplicit(context)); - if (pIntrinsic->MinShaderModel) { - unsigned Major = pIntrinsic->MinShaderModel >> 4; - unsigned Minor = pIntrinsic->MinShaderModel & 0xF; + if (pIntrinsic->MinShaderModel || pIntrinsic->MaxShaderModel) { + clang::VersionTuple Introduced; + if (pIntrinsic->MinShaderModel) { + unsigned Major = pIntrinsic->MinShaderModel >> 4; + unsigned Minor = pIntrinsic->MinShaderModel & 0xF; + Introduced = clang::VersionTuple(Major, Minor); + } + // The maximum shader model is the last one that still supports the + // intrinsic: it is deprecated there, and obsoleted in the next minor + // shader model version. We could give longer deprecation periods in the + // future if there is a need for that. + clang::VersionTuple Deprecated; + clang::VersionTuple Obsoleted; + if (pIntrinsic->MaxShaderModel) { + unsigned Major = pIntrinsic->MaxShaderModel >> 4; + unsigned Minor = pIntrinsic->MaxShaderModel & 0xF; + Deprecated = clang::VersionTuple(Major, Minor); + DXASSERT( + Minor <= 14, + "I don't know how we should handle this, so let's assert for now."); + Obsoleted = clang::VersionTuple(Major, Minor + 1); + } FD->addAttr(AvailabilityAttr::CreateImplicit( - context, &context.Idents.get(""), clang::VersionTuple(Major, Minor), - clang::VersionTuple(), clang::VersionTuple(), false, "")); + context, &context.Idents.get(""), Introduced, Deprecated, Obsoleted, + false, "")); } } @@ -3250,9 +3277,9 @@ class HLSLExternalSource : public ExternalSemaSource { CXXRecordDecl *m_objectTypeDecls[_countof(g_ArBasicKindsAsTypes)]; // Map from object decl to the object index. using ObjectTypeDeclMapType = - std::array, - _countof(g_ArBasicKindsAsTypes) + - _countof(g_DeprecatedEffectObjectNames)>; + SmallVector, + _countof(g_ArBasicKindsAsTypes) + + _countof(g_DeprecatedEffectObjectNames)>; ObjectTypeDeclMapType m_objectTypeDeclsMap; UsedIntrinsicStore m_usedIntrinsics; @@ -3431,11 +3458,12 @@ class HLSLExternalSource : public ExternalSemaSource { DeclarationName declarationName = DeclarationName(ii); StorageClass SC = IsStaticMember(intrinsic) ? SC_Static : SC_None; + bool IsConst = IsConstMemberIntrinsic(intrinsic); CXXMethodDecl *functionDecl = CreateObjectFunctionDeclarationWithParams( *m_context, recordDecl, functionResultQT, ArrayRef(argsQTs, numParams), - ArrayRef(argNames, numParams), declarationName, true, SC, + ArrayRef(argNames, numParams), declarationName, IsConst, SC, templateParamNamedDeclsCount > 0); functionDecl->setImplicit(true); @@ -3864,6 +3892,10 @@ class HLSLExternalSource : public ExternalSemaSource { auto &context = m_sema->getASTContext(); for (uint32_t i = 0; i < tableSize; ++i) { const HLSL_INTRINSIC *intrinsic = &table[i]; + // Builtins can contain call-site-dependent types and are declared lazily. + if (StringRef(intrinsic->pArgs->pName).startswith("__builtin_")) + continue; + const IdentifierInfo &fnII = context.Idents.get( intrinsic->pArgs->pName, tok::TokenKind::identifier); DeclarationName functionName(&fnII); @@ -4241,7 +4273,7 @@ class HLSLExternalSource : public ExternalSemaSource { *m_context, typeName, templateArgCount, typeDefault, Attr); } m_objectTypeDecls[i] = recordDecl; - m_objectTypeDeclsMap[i] = std::make_pair(recordDecl, i); + m_objectTypeDeclsMap.push_back(std::make_pair(recordDecl, i)); } // Create an alias for SamplerState. 'sampler' is very commonly used. @@ -4258,10 +4290,14 @@ class HLSLExternalSource : public ExternalSemaSource { samplerDecl->setImplicit(true); // Create decls for each deprecated effect object type: - unsigned effectObjBase = _countof(g_ArBasicKindsAsTypes); - // TypeSourceInfo* effectObjTypeSource = - // m_context->getTrivialTypeSourceInfo(GetBasicKindType(AR_OBJECT_LEGACY_EFFECT)); + // The legacy effects syntax is removed in HLSL 202x, so these type names + // are not registered in 202x and later. Using them then produces a + // natural "unknown type name" diagnostic. + bool RegisterEffectObjects = + m_sema->getLangOpts().HLSLVersion < hlsl::LangStd::v202x; for (unsigned i = 0; i < _countof(g_DeprecatedEffectObjectNames); i++) { + if (!RegisterEffectObjects) + continue; IdentifierInfo &idInfo = m_context->Idents.get(StringRef(g_DeprecatedEffectObjectNames[i]), tok::TokenKind::identifier); @@ -4272,8 +4308,8 @@ class HLSLExternalSource : public ExternalSemaSource { currentDeclContext, NoLoc, NoLoc, &idInfo); currentDeclContext->addDecl(effectObjDecl); effectObjDecl->setImplicit(true); - m_objectTypeDeclsMap[i + effectObjBase] = - std::make_pair(effectObjDecl, effectKindIndex); + m_objectTypeDeclsMap.push_back( + std::make_pair(effectObjDecl, effectKindIndex)); } } @@ -4781,26 +4817,6 @@ class HLSLExternalSource : public ExternalSemaSource { return type; } - bool IsTypeDeducibleWithAuto(QualType type) { - if (type.isNull()) - return false; - - if (hlsl::IsStringType(type) || hlsl::IsStringLiteralType(type)) - return false; - - if (const CXXRecordDecl *recordDecl = - GetStructuralForm(type)->getAsCXXRecordDecl()) { - if (!recordDecl->hasAttr()) - if (const CXXRecordDecl *pattern = - recordDecl->getTemplateInstantiationPattern()) - recordDecl = pattern; - if (recordDecl->hasAttr()) - return false; - } - - return true; - } - /// Given a Clang type, return the ArBasicKind classification for its /// contents. ArBasicKind GetTypeElementKind(QualType type) { @@ -5665,6 +5681,8 @@ class HLSLExternalSource : public ExternalSemaSource { /// numeric elements exclusively. bool IsTypeNumeric(QualType type, UINT *count); + bool ContainsLinAlgMatrixType(QualType type); + /// Checks whether the specified type is a scalar type. bool IsScalarType(const QualType &type) { DXASSERT(!type.isNull(), "caller should validate its type is initialized"); @@ -6076,7 +6094,7 @@ class HLSLExternalSource : public ExternalSemaSource { if (isMatrix || isVector) { Expr *expr = arg.getAsExpr(); llvm::APSInt constantResult; - if (expr != nullptr && + if (expr != nullptr && !expr->isValueDependent() && expr->isIntegerConstantExpr(constantResult, *m_context)) { if (CheckRangedTemplateArgument(argSrcLoc, constantResult, isVector)) @@ -6378,11 +6396,14 @@ class HLSLExternalSource : public ExternalSemaSource { MultiLevelTemplateArgumentList mlTemplateArgumentList(templateArgumentList); TemplateDeclInstantiator declInstantiator(*this->m_sema, owner, mlTemplateArgumentList); - FunctionProtoType::ExtProtoInfo EmptyEPI; + FunctionProtoType::ExtProtoInfo EPI; + // Preserve the method's const qualification on the resolved specialization. + if (IsConstMemberIntrinsic(intrinsic)) + EPI.TypeQuals = Qualifiers::Const; QualType functionType = m_context->getFunctionType( parameterTypes[0], - ArrayRef(parameterTypes + 1, parameterTypeCount - 1), - EmptyEPI, paramMods); + ArrayRef(parameterTypes + 1, parameterTypeCount - 1), EPI, + paramMods); TypeSourceInfo *TInfo = m_context->CreateTypeSourceInfo(functionType, 0); FunctionProtoTypeLoc Proto = TInfo->getTypeLoc().getAs(); @@ -7164,7 +7185,23 @@ bool HLSLExternalSource::MatchArguments( case AR_TOBJ_BASIC: case AR_TOBJ_OBJECT: case AR_TOBJ_STRING: + break; case AR_TOBJ_ARRAY: + // Arrays of vectors are only allowed for LITEMPLATE_ANY_ARRAY + // parameters, where the vector size is matched the same way it would be + // for a plain vector parameter. + if (pIntrinsicArg->uLegalTemplates == LITEMPLATE_ANY_ARRAY) { + QualType EltType = QualType(pType->getBaseElementTypeUnsafe(), 0); + switch (GetTypeObjectKind(EltType)) { + case AR_TOBJ_VECTOR: + TypeInfoCols = GetHLSLVecSize(EltType); + break; + case AR_TOBJ_BASIC: + break; + default: + badArgIdx = std::min(badArgIdx, iArg); + } + } break; default: badArgIdx = std::min(badArgIdx, iArg); // no struct, arrays or void @@ -7614,12 +7651,26 @@ bool HLSLExternalSource::MatchArguments( pArgument->qwUsage & (AR_QUAL_ROWMAJOR | AR_QUAL_COLMAJOR | AR_QUAL_GROUPSHARED); - if ((0 == i) || !(pArgument->qwUsage & AR_QUAL_OUT)) + if ((0 == i) || + !(pArgument->qwUsage & (AR_QUAL_OUT | AR_QUAL_GROUPSHARED))) qwQual |= AR_QUAL_CONST; DXASSERT_VALIDBASICKIND(pEltType); - pNewType = NewSimpleAggregateType(Template[pArgument->uTemplateId], - pEltType, qwQual, uRows, uCols); + + // Array parameters build the array element type here, which is later + // wrapped in the argument's array dimensions. For arrays of vectors the + // element has to be built as a vector, even when it holds a single + // component. + ArTypeObjectKind AggregateKind = Template[pArgument->uTemplateId]; + if (i > 0 && AggregateKind == AR_TOBJ_ARRAY && + pArgument->uLegalTemplates == LITEMPLATE_ANY_ARRAY && + GetTypeObjectKind(QualType( + Args[i - 1]->getType()->getBaseElementTypeUnsafe(), 0)) == + AR_TOBJ_VECTOR) + AggregateKind = AR_TOBJ_VECTOR; + + pNewType = + NewSimpleAggregateType(AggregateKind, pEltType, qwQual, uRows, uCols); // If array type, wrap in the argument's array type. if (i > 0 && Template[pArgument->uTemplateId] == AR_TOBJ_ARRAY) { @@ -8659,8 +8710,9 @@ UINT64 HLSLExternalSource::ScoreFunction(OverloadCandidateSet::iterator &Cand) { // in/out considerations have been taken care of by viability. - // 'this' considerations don't matter without inheritance, other - // than lookup and viability. + // The implicit object argument (`this`) affects lookup and viability. + // In HLSL 202x, its const qualification also breaks ties between viable + // overloads: a non-const object prefers a non-const method. UINT64 result = 0; for (unsigned convIdx = 0; convIdx < Cand->NumConversions; ++convIdx) { @@ -8678,6 +8730,23 @@ UINT64 HLSLExternalSource::ScoreFunction(OverloadCandidateSet::iterator &Cand) { } result += score; } + + // HLSL 202x: when both const and non-const overloads of a method are + // viable for a non-const object, prefer the non-const overload. Add a + // small tie-breaking penalty when the implicit object argument requires + // adding `const` to call a const-qualified method. This uses the low score + // bits reserved by SCORE_MIN_SHIFT. + CXXMethodDecl *Method = dyn_cast_or_null(Cand->Function); + if (m_sema->getLangOpts().HLSLVersion >= hlsl::LangStd::v202x && Method && + !Cand->IgnoreObjectArgument && + (Method->getTypeQualifiers() & Qualifiers::Const)) { + const ImplicitConversionSequence &ICS = Cand->Conversions[0]; + if (ICS.isStandard()) { + QualType FromType = ICS.Standard.getFromType(); + if (!FromType.isNull() && !FromType.isConstQualified()) + result += 1; + } + } return result; } @@ -8989,10 +9058,40 @@ bool HLSLExternalSource::IsTypeNumeric(QualType type, UINT *count) { case AR_TOBJ_OBJECT: case AR_TOBJ_DEPENDENT: case AR_TOBJ_STRING: + case AR_TOBJ_LINALG_MATRIX: return false; } } +bool HLSLExternalSource::ContainsLinAlgMatrixType(QualType Type) { + DXASSERT_NOMSG(!Type.isNull()); + + Type = GetStructuralForm(Type); + // Covers both attributed matrices and the unattributed builtin handle. + if (Type->isAttributedLinAlgMatrixType() || Type->isLinAlgMatrixType()) + return true; + + if (const ArrayType *AT = m_context->getAsArrayType(Type)) + return ContainsLinAlgMatrixType(AT->getElementType()); + + if (GetTypeObjectKind(Type) != AR_TOBJ_COMPOUND) + return false; + + const CXXRecordDecl *RD = Type->getAsCXXRecordDecl(); + if (!RD || !RD->hasDefinition()) + return false; + + for (const CXXBaseSpecifier &Base : RD->bases()) + if (ContainsLinAlgMatrixType(Base.getType())) + return true; + + for (const FieldDecl *Field : RD->fields()) + if (ContainsLinAlgMatrixType(Field->getType())) + return true; + + return false; +} + enum MatrixMemberAccessError { MatrixMemberAccessError_None, // No errors found. MatrixMemberAccessError_BadFormat, // Formatting error (non-digit). @@ -12701,19 +12800,19 @@ void Sema::DiagnoseReachableHLSLCall(CallExpr *CE, const hlsl::ShaderModel *SM, case hlsl::IntrinsicOp::IOP_DxMaybeReorderThread: DiagnoseReachableSERCall(*this, CE, EntrySK, EntryDecl, true); break; - case hlsl::IntrinsicOp::IOP___builtin_LinAlg_FillMatrix: - case hlsl::IntrinsicOp::IOP___builtin_LinAlg_CopyConvertMatrix: - case hlsl::IntrinsicOp::IOP___builtin_LinAlg_MatrixLength: - case hlsl::IntrinsicOp::IOP___builtin_LinAlg_MatrixGetCoordinate: - case hlsl::IntrinsicOp::IOP___builtin_LinAlg_MatrixGetElement: - case hlsl::IntrinsicOp::IOP___builtin_LinAlg_MatrixSetElement: - case hlsl::IntrinsicOp::IOP___builtin_LinAlg_MatrixStoreToDescriptor: - case hlsl::IntrinsicOp::IOP___builtin_LinAlg_MatrixLoadFromMemory: - case hlsl::IntrinsicOp::IOP___builtin_LinAlg_MatrixStoreToMemory: - case hlsl::IntrinsicOp::IOP___builtin_LinAlg_MatrixAccumulateToMemory: - case hlsl::IntrinsicOp::IOP___builtin_LinAlg_MatrixMatrixMultiply: - case hlsl::IntrinsicOp::IOP___builtin_LinAlg_MatrixMatrixMultiplyAccumulate: - case hlsl::IntrinsicOp::IOP___builtin_LinAlg_MatrixAccumulate: + case hlsl::IntrinsicOp::IOP_Dx__builtin_LinAlg_FillMatrix: + case hlsl::IntrinsicOp::IOP_Dx__builtin_LinAlg_CopyConvertMatrix: + case hlsl::IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixLength: + case hlsl::IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixGetCoordinate: + case hlsl::IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixGetElement: + case hlsl::IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixSetElement: + case hlsl::IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixStoreToDescriptor: + case hlsl::IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixLoadFromMemory: + case hlsl::IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixStoreToMemory: + case hlsl::IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixAccumulateToMemory: + case hlsl::IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixMatrixMultiply: + case hlsl::IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixMatrixMultiplyAccumulate: + case hlsl::IntrinsicOp::IOP_Dx__builtin_LinAlg_MatrixAccumulate: DiagnoseReachableLimitedLinAlgCall(*this, CE, EntrySK, EntryDecl); break; default: @@ -12738,6 +12837,17 @@ static bool AllowObjectInContext(QualType Ty, TypeDiagContext DiagContext) { return true; } +// LinAlg matrices (attributed or the raw builtin handle) are opaque, thread +// local values. They are only valid as static global state, locals, and +// non-entry function parameters and return types, never in resources, +// groupshared memory, or shader interfaces. +static bool AllowLinAlgMatrixInContext(TypeDiagContext DiagContext) { + // Non-static globals are rejected separately with a diagnostic that asks for + // an explicit 'static'. + return DiagContext == TypeDiagContext::GlobalVariables || + DiagContext == TypeDiagContext::CBuffersOrTBuffers; +} + // Determine if `Ty` is valid in this `DiagContext` and/or an empty type. If // invalid returns false and Sema `S`, location `Loc`, error index // `DiagContext`, and FieldDecl `FD` are used to emit diagnostics. If @@ -12768,6 +12878,21 @@ DiagnoseElementTypes(Sema &S, SourceLocation Loc, QualType Ty, bool &Empty, static_cast(TypeDiagContext::LongVecDiagMaxSelectIndex))); HLSLExternalSource *Source = HLSLExternalSource::FromSema(&S); + + const Type *CanonTy = Ty.getCanonicalType().getTypePtr(); + if (CanonTy->isAttributedLinAlgMatrixType() || + CanonTy->isLinAlgMatrixType()) { + Empty = false; + if (!CheckObjects || AllowLinAlgMatrixInContext(ObjDiagContext)) + return false; + S.Diag(Loc, diag::err_hlsl_unsupported_object_context) + << Ty << ObjDiagContextIdx; + if (FD) + S.Diag(FD->getLocation(), diag::note_field_declared_here) + << FD->getType() << FD->getSourceRange(); + return true; + } + ArTypeObjectKind ShapeKind = Source->GetTypeObjectKind(Ty); switch (ShapeKind) { case AR_TOBJ_VECTOR: @@ -12838,10 +12963,6 @@ bool hlsl::DiagnoseTypeElements(Sema &S, SourceLocation Loc, QualType Ty, LongVecDiagContext, CheckedDecls, FD); } -bool hlsl::IsTypeDeducibleWithAuto(Sema &S, QualType Ty) { - return HLSLExternalSource::FromSema(&S)->IsTypeDeducibleWithAuto(Ty); -} - bool hlsl::DiagnoseNodeStructArgument(Sema *self, TemplateArgumentLoc ArgLoc, QualType ArgTy, bool &Empty, const FieldDecl *FD) { @@ -15335,6 +15456,20 @@ void Sema::ActOnFinishHLSLBuffer(Decl *Dcl, SourceLocation RBrace) { bool HasPackOffset = false; bool HasNonPackOffset = false; for (auto *Field : BufDecl->decls()) { + // HLSL 202x 0005 Cbuffer Contexts proposal restricts the contents of a + // cbuffer to declarations allowed at block scope, plus templates, functions + // and empty declarations (see: + // https://hlsl-tc57.github.io/tc57/proposal/0005/). + if (getLangOpts().HLSLVersion >= hlsl::LangStd::v202x && + (isa(Field) || isa(Field))) { + NamedDecl *ND = cast(Field); + Diag(Field->getLocation(), + diag::err_hlsl_unsupported_declaration_in_buffer) + << ND << BufDecl->isCBuffer(); + Diag(Dcl->getLocation(), diag::note_declared_at); + Dcl->setInvalidDecl(); + } + VarDecl *Var = dyn_cast(Field); if (!Var) continue; @@ -15418,6 +15553,9 @@ HLSLBufferDecl::Create(ASTContext &C, DeclContext *lexicalParent, bool cbuffer, std::vector &BufferAttributes, SourceLocation LBrace) { DeclContext *DC = C.getTranslationUnitDecl(); + // In HLSL 202x, buffers and their members belong to the enclosing namespace. + if (C.getLangOpts().HLSLVersion >= hlsl::LangStd::v202x) + DC = lexicalParent; HLSLBufferDecl *result = ::new (C) HLSLBufferDecl( DC, cbuffer, constantbuffer, KwLoc, Id, IdLoc, BufferAttributes, LBrace); if (DC != lexicalParent) { @@ -15631,7 +15769,8 @@ bool Sema::DiagnoseHLSLDecl(Declarator &D, DeclContext *DC, Expr *BitWidth, if (hlsl::IsObjectType(this, qt, &bDeprecatedEffectObject)) { bIsObject = true; if (bDeprecatedEffectObject) { - Diag(D.getLocStart(), diag::warn_hlsl_effect_object); + Diag(D.getLocStart(), diag::warn_hlsl_2026_effects) + << /*object*/ 4 << /*known not possible*/ 1; D.setInvalidType(); return false; } @@ -15767,6 +15906,9 @@ bool Sema::DiagnoseHLSLDecl(Declarator &D, DeclContext *DC, Expr *BitWidth, << pAttr->getRange(); result = false; } + if ((isGlobal || isParameter) && !isStatic) + Diag(pAttr->getLoc(), diag::warn_hlsl_2026_removed_keyword) + << "uniform"; pUniform = pAttr; break; @@ -16050,6 +16192,15 @@ bool Sema::DiagnoseHLSLDecl(Declarator &D, DeclContext *DC, Expr *BitWidth, if (DiagnoseTypeElements(*this, D.getLocStart(), qt, ObjDiagContext, LongVecDiagContext)) result = false; + + // LinAlg matrices are mutable state that cannot live in the implicit + // global constant buffer. Groupshared is rejected above. + if (!isStatic && !isGroupShared && !D.isInvalidType() && + !qt->isDependentType() && hlslSource->ContainsLinAlgMatrixType(qt)) { + Diag(D.getLocStart(), diag::err_hlsl_linalg_matrix_global_not_static) + << D.getIdentifier(); + result = false; + } } // SPIRV change starts @@ -17896,6 +18047,8 @@ ConvertLinAlgMatrixComponentTypeToString(hlsl::DXIL::ComponentType CompType) { return "ComponentType::F8_E4M3FN"; case DXIL::ComponentType::F8_E5M2: return "ComponentType::F8_E5M2"; + case DXIL::ComponentType::BFloat16: + return "ComponentType::BFloat16"; default: llvm_unreachable("Unknown ComponentType"); } diff --git a/tools/clang/lib/Sema/SemaHLSLDiagnoseTU.cpp b/tools/clang/lib/Sema/SemaHLSLDiagnoseTU.cpp index ec723f374d..32cb4e565c 100644 --- a/tools/clang/lib/Sema/SemaHLSLDiagnoseTU.cpp +++ b/tools/clang/lib/Sema/SemaHLSLDiagnoseTU.cpp @@ -489,31 +489,57 @@ class HLSLReachableDiagnoseVisitor return SMVT >= AAttrVT; } + bool CheckObsoleted(VersionTuple ObsoletedVT) { + if (ObsoletedVT.empty() || IsTargetProfileLib6x(*sema)) + return true; + VersionTuple SMVT = VersionTuple(SM->GetMajor(), SM->GetMinor()); + return SMVT < ObsoletedVT; + } + void DiagnoseAvailability(AvailabilityAttr *AAttr, QualType Ty, SourceLocation Loc) { VersionTuple AAttrVT = AAttr->getIntroduced(); - if (CheckSMVersion(AAttrVT)) + if (!CheckSMVersion(AAttrVT)) { + sema->Diag(Loc, diag::warn_hlsl_builtin_type_unavailable) + << Ty << SM->GetName() << AAttrVT.getAsString(); return; + } - sema->Diag(Loc, diag::warn_hlsl_builtin_type_unavailable) - << Ty << SM->GetName() << AAttrVT.getAsString(); + VersionTuple ObsoletedVT = AAttr->getObsoleted(); + if (!CheckObsoleted(ObsoletedVT)) + sema->Diag(Loc, diag::warn_hlsl_builtin_type_removed) + << Ty << SM->GetName() << ObsoletedVT.getAsString(); } void DiagnoseAvailability(AvailabilityAttr *AAttr, NamedDecl *ND, SourceLocation Loc) { VersionTuple AAttrVT = AAttr->getIntroduced(); - if (CheckSMVersion(AAttrVT)) + if (!CheckSMVersion(AAttrVT)) { + if (isa(ND)) { + sema->Diag(Loc, diag::warn_hlsl_intrinsic_in_wrong_shader_model) + << ND->getQualifiedNameAsString() << EntryDecl + << AAttrVT.getAsString(); + return; + } + + sema->Diag(Loc, diag::warn_hlsl_builtin_constant_unavailable) + << ND << SM->GetName() << AAttrVT.getAsString(); + return; + } + + VersionTuple ObsoletedVT = AAttr->getObsoleted(); + if (CheckObsoleted(ObsoletedVT)) return; if (isa(ND)) { - sema->Diag(Loc, diag::warn_hlsl_intrinsic_in_wrong_shader_model) + sema->Diag(Loc, diag::warn_hlsl_intrinsic_removed) << ND->getQualifiedNameAsString() << EntryDecl - << AAttrVT.getAsString(); + << ObsoletedVT.getAsString(); return; } - sema->Diag(Loc, diag::warn_hlsl_builtin_constant_unavailable) - << ND << SM->GetName() << AAttrVT.getAsString(); + sema->Diag(Loc, diag::warn_hlsl_builtin_constant_removed) + << ND << SM->GetName() << ObsoletedVT.getAsString(); } clang::Sema *getSema() { return sema; } @@ -768,6 +794,15 @@ void hlsl::DiagnoseTranslationUnit(clang::Sema *self) { if (EntrySK == DXIL::ShaderKind::Library && IsTargetProfileLib6x(*self)) continue; + // Work Graphs (node shaders) were obsoleted in shader model 6.10. + // Declaring a node shader when targeting 6.10 or above is an error, + // regardless of whether any node record types are actually used. + if (EntrySK == DXIL::ShaderKind::Node && shaderModel->IsSMAtLeast(6, 10) && + !IsTargetProfileLib6x(*self)) { + self->Diag(FDecl->getLocation(), diag::warn_hlsl_node_shader_removed) + << shaderModel->GetName(); + } + // Visit all visited functions in call graph to collect illegal intrinsic // calls. HLSLReachableDiagnoseVisitor Visitor( diff --git a/tools/clang/lib/Sema/SemaOverload.cpp b/tools/clang/lib/Sema/SemaOverload.cpp index 6198282ff0..b21da0c7e1 100644 --- a/tools/clang/lib/Sema/SemaOverload.cpp +++ b/tools/clang/lib/Sema/SemaOverload.cpp @@ -4870,13 +4870,26 @@ TryObjectArgumentInitialization(Sema &S, QualType FromType, // First check the qualifiers. QualType FromTypeCanon = S.Context.getCanonicalType(FromType); // HLSL Change Starts - // HLSL Note: For calls that aren't compiler-generated C++ overloads, we - // disregard const qualifiers so that member functions can be called on - // `const` objects from constant buffer types. This should change in the - // future if we support const instance methods. + // HLSL Note: Prior to HLSL 202x, for calls that aren't compiler-generated + // C++ overloads, we disregard const qualifiers so that member functions can + // be called on `const` objects from constant buffer types. + // + // HLSL 202x supports `const` instance methods. When the method is const- + // qualified, or when the object is const-qualified, we enforce + // const-correctness so that: + // - a const object cannot call a non-const method + // - a non-const object calling a const method incurs a qualification + // adjustment (which the HLSL overload scorer can use to prefer the + // non-const overload). FromTypeCanon.removeLocalRestrict(); // HLSL Change - disregard restrict. + bool EnforceHLSLConst = S.getLangOpts().HLSL && + S.getLangOpts().HLSLVersion >= hlsl::LangStd::v202x && + !isa(Method) && + ((Method->getTypeQualifiers() & Qualifiers::Const) || + FromTypeCanon.isConstQualified()); if (!S.getLangOpts().HLSL || - (Method != nullptr && Method->hasAttr())) { + (Method != nullptr && Method->hasAttr()) || + EnforceHLSLConst) { // HLSL Change Ends if (ImplicitParamType.getCVRQualifiers() != FromTypeCanon.getLocalCVRQualifiers() && diff --git a/tools/clang/lib/Sema/SemaStmt.cpp b/tools/clang/lib/Sema/SemaStmt.cpp index baa9559dbb..856748e207 100644 --- a/tools/clang/lib/Sema/SemaStmt.cpp +++ b/tools/clang/lib/Sema/SemaStmt.cpp @@ -3071,6 +3071,17 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, if (DAR != DAR_Succeeded) return true; + // HLSL Change Begin - Diagnose deduced return types that 'auto' cannot + // represent. A dependent deduced type cannot be classified yet; defer the + // check to instantiation, when 'auto' is re-deduced to a concrete type. + if (getLangOpts().HLSL && !Deduced->isDependentType() && + !hlsl::IsTypeDeducibleWithAuto(Deduced)) { + Diag(RetExpr->getExprLoc(), diag::err_hlsl_auto_undeducible_type) + << Deduced; + return true; + } + // HLSL Change End + // If a local type is part of the returned type, mark its fields as // referenced. LocalTypedefNameReferencer Referencer(*this); @@ -3177,7 +3188,9 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // FIXME: Add a flag to the ScopeInfo to indicate whether we're performing // deduction. - if (getLangOpts().CPlusPlus14) { + // HLSL Change Begin - HLSL supports C++14-style deduced return types. + if (getLangOpts().CPlusPlus14 || getLangOpts().HLSL) { + // HLSL Change End if (AutoType *AT = FnRetType->getContainedAutoType()) { FunctionDecl *FD = cast(CurContext); if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) { diff --git a/tools/clang/lib/Sema/SemaTemplateDeduction.cpp b/tools/clang/lib/Sema/SemaTemplateDeduction.cpp index e2e510d0c1..819de72767 100644 --- a/tools/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/tools/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -2555,19 +2555,23 @@ Sema::SubstituteExplicitTemplateArguments( // Isolate our substituted parameters from our caller. LocalInstantiationScope InstScope(*this, /*MergeWithOuterScope*/true); + // HLSL Change Begin - HLSL needs the parameter decls to instantiate parameter + // modifiers correctly. + SmallVector ParamDecls; // Instantiate the types of each of the function parameters given the // explicitly-specified template arguments. If the function has a trailing // return type, substitute it after the arguments to ensure we substitute // in lexical order. if (Proto->hasTrailingReturn()) { - if (SubstParmTypes(Function->getLocation(), - Function->param_begin(), Function->getNumParams(), + if (SubstParmTypes(Function->getLocation(), Function->param_begin(), + Function->getNumParams(), MultiLevelTemplateArgumentList(*ExplicitArgumentList), - ParamTypes)) + ParamTypes, &ParamDecls)) return TDK_SubstitutionFailure; } - + // HLSL Change End + // Instantiate the return type. QualType ResultType; { @@ -2594,22 +2598,30 @@ Sema::SubstituteExplicitTemplateArguments( if (ResultType.isNull() || Trap.hasErrorOccurred()) return TDK_SubstitutionFailure; } - + // Instantiate the types of each of the function parameters given the // explicitly-specified template arguments if we didn't do so earlier. + // HLSL Change Begin - Pass ParamDecls to SubstParmTypes to correctly + // instantiate parameter modifiers. if (!Proto->hasTrailingReturn() && - SubstParmTypes(Function->getLocation(), - Function->param_begin(), Function->getNumParams(), + SubstParmTypes(Function->getLocation(), Function->param_begin(), + Function->getNumParams(), MultiLevelTemplateArgumentList(*ExplicitArgumentList), - ParamTypes)) + ParamTypes, &ParamDecls)) return TDK_SubstitutionFailure; + // HLSL Change - End if (FunctionType) { - // HLSL Change - FIX - We should move param mods to parameter QualTypes + // HLSL Change Begin - Pass ParamDecls to SubstParmTypes to correctly + // instantiate parameter modifiers. + SmallVector ParamMods; + ParamMods.reserve(ParamDecls.size()); + for (ParmVarDecl *Param : ParamDecls) + ParamMods.push_back(Param ? Param->getParamModifiers() + : hlsl::ParameterModifier()); *FunctionType = BuildFunctionType( ResultType, ParamTypes, Function->getLocation(), - Function->getDeclName(), Proto->getExtProtoInfo(), - cast(Function->getType())->getParamMods()); + Function->getDeclName(), Proto->getExtProtoInfo(), ParamMods); // HLSL Change - End if (FunctionType->isNull() || Trap.hasErrorOccurred()) return TDK_SubstitutionFailure; diff --git a/tools/clang/lib/Sema/SemaTemplateVariadic.cpp b/tools/clang/lib/Sema/SemaTemplateVariadic.cpp index b575bfaf4d..8658b7d514 100644 --- a/tools/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/tools/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -545,10 +545,12 @@ bool Sema::CheckParameterPacksForExpansion( std::pair FirstPack; bool HaveFirstPack = false; - if (getLangOpts().HLSL) { + // HLSL Change Begin - Disallow variadic templates in HLSL 2021. + if (getLangOpts().HLSLDisallowsVariadicTemplates()) { Diag(EllipsisLoc, diag::err_hlsl_variadic_templates); return true; } + // HLSL Change End for (ArrayRef::iterator i = Unexpanded.begin(), end = Unexpanded.end(); diff --git a/tools/clang/lib/Sema/SemaType.cpp b/tools/clang/lib/Sema/SemaType.cpp index 7465cc2cec..454fb00dc8 100644 --- a/tools/clang/lib/Sema/SemaType.cpp +++ b/tools/clang/lib/Sema/SemaType.cpp @@ -2658,8 +2658,12 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, // type (this is checked later) and we can skip this. In other languages // using auto, we need to check regardless. // C++14 In generic lambdas allow 'auto' in their parameters. + // HLSL Change Begin - HLSL supports 'auto' as a function declarator return + // type with C++14-style deduction; skip this check for functions. if (ContainsPlaceholderType && - (!SemaRef.getLangOpts().CPlusPlus11 || !D.isFunctionDeclarator())) { + (!(SemaRef.getLangOpts().CPlusPlus11 || SemaRef.getLangOpts().HLSL) || + !D.isFunctionDeclarator())) { + // HLSL Change End int Error = -1; switch (D.getContext()) { @@ -3748,9 +3752,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, if (!D.isInvalidType()) { // trailing-return-type is only required if we're declaring a function, // and not, for instance, a pointer to a function. + // HLSL Change Begin - HLSL supports C++14-style deduced return types. if (D.getDeclSpec().containsPlaceholderType() && !FTI.hasTrailingReturnType() && chunkIndex == 0 && - !S.getLangOpts().CPlusPlus14) { + !(S.getLangOpts().CPlusPlus14 || S.getLangOpts().HLSL)) { + // HLSL Change End S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto ? diag::err_auto_missing_trailing_return @@ -4280,14 +4286,14 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // parameter packs in the type of the non-type template parameter, then // it expands those parameter packs. // HLSL Change Starts - if (LangOpts.HLSL) { + if (LangOpts.HLSLDisallowsVariadicTemplates()) { S.Diag(D.getEllipsisLoc(), diag::err_hlsl_variadic_templates); break; } // HLSL Change Ends if (T->containsUnexpandedParameterPack()) T = Context.getPackExpansionType(T, None); - else + else if (!LangOpts.HLSL) // HLSL Change: HLSL has no C++98-compat warnings S.Diag(D.getEllipsisLoc(), LangOpts.CPlusPlus11 ? diag::warn_cxx98_compat_variadic_templates diff --git a/tools/clang/lib/Sema/TreeTransform.h b/tools/clang/lib/Sema/TreeTransform.h index ef3a83c988..0d1c4fb2e0 100644 --- a/tools/clang/lib/Sema/TreeTransform.h +++ b/tools/clang/lib/Sema/TreeTransform.h @@ -4753,8 +4753,17 @@ QualType TreeTransform::TransformFunctionProtoType( !std::equal(T->param_type_begin(), T->param_type_end(), ParamTypes.begin()) || EPIChanged) { // HLSL Change - FIX - We should move param mods to parameter QualTypes + SmallVector ExpandedParamMods; + ArrayRef ParamMods = T->getParamMods(); + if (ParamMods.size() != ParamTypes.size()) { + ExpandedParamMods.reserve(ParamDecls.size()); + for (ParmVarDecl *Param : ParamDecls) + ExpandedParamMods.push_back(Param ? Param->getParamModifiers() + : hlsl::ParameterModifier()); + ParamMods = ExpandedParamMods; + } Result = getDerived().RebuildFunctionProtoType(ResultType, ParamTypes, - T->getParamMods(), EPI); + ParamMods, EPI); // HLSL Change - End if (Result.isNull()) return QualType(); @@ -10721,9 +10730,19 @@ TreeTransform::TransformBlockExpr(BlockExpr *E) { QualType exprResultType = getDerived().TransformType(exprFunctionType->getReturnType()); - // HLSL Change - FIX - We should move param mods to parameter QualTypes + // HLSL Change - Fix up the parameter modifiers for the block's parameters. + SmallVector ExpandedParamMods; + ArrayRef ParamMods = + exprFunctionType->getParamMods(); + if (ParamMods.size() != paramTypes.size()) { + ExpandedParamMods.reserve(params.size()); + for (ParmVarDecl *Param : params) + ExpandedParamMods.push_back(Param ? Param->getParamModifiers() + : hlsl::ParameterModifier()); + ParamMods = ExpandedParamMods; + } QualType functionType = getDerived().RebuildFunctionProtoType( - exprResultType, paramTypes, exprFunctionType->getParamMods(), + exprResultType, paramTypes, ParamMods, exprFunctionType->getExtProtoInfo()); // HLSL Change - End blockScope->FunctionType = functionType; @@ -10965,7 +10984,7 @@ TreeTransform::RebuildDependentSizedExtVectorType(QualType ElementType, return SemaRef.BuildExtVectorType(ElementType, SizeExpr, AttributeLoc); } -// HLSL Change - FIX - We should move param mods to parameter QualTypes +// HLSL Change - Fix up the parameter modifiers for the function prototype. template QualType TreeTransform::RebuildFunctionProtoType( QualType T, diff --git a/tools/clang/test/CMakeLists.txt b/tools/clang/test/CMakeLists.txt index 2c8eb6f609..9c84f893a1 100644 --- a/tools/clang/test/CMakeLists.txt +++ b/tools/clang/test/CMakeLists.txt @@ -137,20 +137,20 @@ function(add_released_dxc name version) ) endfunction() -# Iterate over releases -list(LENGTH DXC_RELEASES DXC_RELEASES_LENGTH) -math(EXPR num_pairs "${DXC_RELEASES_LENGTH} / 2") -math(EXPR loop_end "${num_pairs} - 1") -foreach(i RANGE 0 ${loop_end}) - math(EXPR idx_name "${i}*2") - math(EXPR idx_version "${i}*2 + 1") +if(WIN32) + # Iterate over releases + list(LENGTH DXC_RELEASES DXC_RELEASES_LENGTH) + math(EXPR num_pairs "${DXC_RELEASES_LENGTH} / 2") + math(EXPR loop_end "${num_pairs} - 1") + foreach(i RANGE 0 ${loop_end}) + math(EXPR idx_name "${i}*2") + math(EXPR idx_version "${i}*2 + 1") - list(GET DXC_RELEASES ${idx_name} name) - list(GET DXC_RELEASES ${idx_version} version) + list(GET DXC_RELEASES ${idx_name} name) + list(GET DXC_RELEASES ${idx_version} version) - add_released_dxc(${name} ${version}) + add_released_dxc(${name} ${version}) - if(WIN32) # Determine target architecture for DXC binaries if(CMAKE_GENERATOR MATCHES "Visual Studio") # Multi-config generators (VS/Xcode) @@ -197,8 +197,8 @@ foreach(i RANGE 0 ${loop_end}) DEPENDS ${CLANG_TEST_DEPS} ${name} ARGS ${CLANG_TEST_EXTRA_ARGS} ) - endif() -endforeach() + endforeach() +endif() # ------------------------------------------------------------------------- set(CLANG_TEST_PARAMS diff --git a/tools/clang/test/CodeGenDXIL/cbuffer.namespace.hlsl b/tools/clang/test/CodeGenDXIL/cbuffer.namespace.hlsl new file mode 100644 index 0000000000..ec436c2d69 --- /dev/null +++ b/tools/clang/test/CodeGenDXIL/cbuffer.namespace.hlsl @@ -0,0 +1,23 @@ +// RUN: %dxc -T ps_6_0 -E main -HV 202x %s | FileCheck %s + +// CHECK: ; cbuffer SceneConstants +// CHECK: ; cbuffer SceneConstants +// CHECK: ; Resource Bindings: +// CHECK-DAG: ; SceneConstants{{ +}}cbuffer{{ +}}NA{{ +}}NA{{ +}}CB0{{ +}}cb3{{ +}}1 +// CHECK-DAG: ; SceneConstants{{ +}}cbuffer{{ +}}NA{{ +}}NA{{ +}}CB1{{ +}}cb4{{ +}}1 + +namespace First { +cbuffer SceneConstants : register(b3) { + float Value; +} +} + +namespace Second { +cbuffer SceneConstants : register(b4) { + float Value; +} +} + +float4 main() : SV_Target { + return First::Value + Second::Value; +} diff --git a/tools/clang/test/CodeGenDXIL/discarded_dynamic_res.hlsl b/tools/clang/test/CodeGenDXIL/discarded_dynamic_res.hlsl new file mode 100644 index 0000000000..b632762130 --- /dev/null +++ b/tools/clang/test/CodeGenDXIL/discarded_dynamic_res.hlsl @@ -0,0 +1,48 @@ +// RUN: %dxc -T cs_6_6 -fcgl %s | FileCheck %s +// RUN: %dxc -T cs_6_6 -Od -fcgl %s | FileCheck --check-prefix=NO_LIFETIMES %s + +// Regression test: indexing into a resource heap (or sampler heap) as a +// discarded-value expression (i.e. its result is never read) used to crash +// the compiler. Clang still emits an alloca plus lifetime markers for the +// implicit temporary in that case, and CGHLSLMSHelper::LowerGetResourceFromHeap +// only expected the resource pointer to be used through a resource-typed +// bitcast that is loaded from; it did not expect the i8* bitcast used by +// llvm.lifetime.start/llvm.lifetime.end, which triggered an invalid cast<> +// (see FinishIntrinsics -> LowerGetResourceFromHeap). + +// When `-Od` is passed lifetime markers are implicitly disabled, so the +// remainder of the IR changes are irrelevant. +// NO_LIFETIMES: define void @main + +// CHECK: [[ResourceX:%.*]] = alloca %struct..Resource +// CHECK: [[SamplerX:%.*]] = alloca %struct..Sampler +// CHECK: [[ResourceY:%.*]] = alloca %struct..Resource +// CHECK: [[SamplerY:%.*]] = alloca %struct..Sampler + +[numthreads(1, 1, 1)] +void main(uint3 tid : SV_DispatchThreadID) { + // CHECK: [[Start:%.*]] = bitcast %struct..Resource* [[ResourceX]] to i8* + // CHECK-NEXT: call void @llvm.lifetime.start(i64 4, i8* [[Start]]) + // CHECK: [[End:%.*]] = bitcast %struct..Resource* [[ResourceX]] to i8* + // CHECK-NEXT: call void @llvm.lifetime.end(i64 4, i8* [[End]]) + ResourceDescriptorHeap[tid.x]; + + // CHECK: [[Start:%.*]] = bitcast %struct..Sampler* [[SamplerX]] to i8* + // CHECK-NEXT: call void @llvm.lifetime.start(i64 4, i8* [[Start]]) + // CHECK: [[End:%.*]] = bitcast %struct..Sampler* [[SamplerX]] to i8* + // CHECK-NEXT: call void @llvm.lifetime.end(i64 4, i8* [[End]]) + SamplerDescriptorHeap[tid.x]; + + + // CHECK: [[Start:%.*]] = bitcast %struct..Resource* [[ResourceY]] to i8* + // CHECK-NEXT: call void @llvm.lifetime.start(i64 4, i8* [[Start]]) + // CHECK: [[End:%.*]] = bitcast %struct..Resource* [[ResourceY]] to i8* + // CHECK-NEXT: call void @llvm.lifetime.end(i64 4, i8* [[End]]) + (void)ResourceDescriptorHeap[tid.y]; + + // CHECK: [[Start:%.*]] = bitcast %struct..Sampler* [[SamplerY]] to i8* + // CHECK-NEXT: call void @llvm.lifetime.start(i64 4, i8* [[Start]]) + // CHECK: [[End:%.*]] = bitcast %struct..Sampler* [[SamplerY]] to i8* + // CHECK-NEXT: call void @llvm.lifetime.end(i64 4, i8* [[End]]) + (void)SamplerDescriptorHeap[tid.y]; +} diff --git a/tools/clang/test/CodeGenDXIL/hlsl/builtin_triangle_positions.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/builtin_triangle_positions.hlsl index 4e343bb3a9..000ff80361 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/builtin_triangle_positions.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/builtin_triangle_positions.hlsl @@ -7,7 +7,7 @@ struct [raypayload] Payload { // Global TriangleObjectPositions - closesthit // CHECK-LABEL: define void {{.*}}ClosestHit -// CHECK: %[[TP:[^ ]+]] = call <9 x float> @dx.op.triangleObjectPosition.f32(i32 -2147483641) ; TriangleObjectPosition() +// CHECK: %[[TP:[^ ]+]] = call <9 x float> @dx.op.triangleObjectPosition.f32(i32 318) ; TriangleObjectPosition() // CHECK: %[[E0:[^ ]+]] = extractelement <9 x float> %[[TP]], i32 0 // CHECK: %{{[^ ]+}} = fmul fast float %[[E0]], 2.000000e+00 // CHECK: %[[E1:[^ ]+]] = extractelement <9 x float> %[[TP]], i32 1 diff --git a/tools/clang/test/CodeGenDXIL/hlsl/intrinsics/buffer-agg-load-stores.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/intrinsics/buffer-agg-load-stores.hlsl index 572734d679..451ea43106 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/intrinsics/buffer-agg-load-stores.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/intrinsics/buffer-agg-load-stores.hlsl @@ -1,53 +1,51 @@ -// RUN: %dxc -T vs_6_6 -DETY=float -DCOLS=3 %s | FileCheck %s --check-prefixes=CHECK,MULTI -// RUN: %dxc -T vs_6_6 -DETY=bool -DCOLS=3 %s | FileCheck %s --check-prefixes=CHECK,MULTI -// RUN: %dxc -T vs_6_6 -DETY=uint64_t -DCOLS=3 %s | FileCheck %s --check-prefixes=CHECK,MULTI -// RUN: %dxc -T vs_6_6 -DETY=double -DCOLS=3 %s | FileCheck %s --check-prefixes=CHECK,MULTI - -// RUN: %dxc -T vs_6_6 -DETY=float1 -DCOLS=3 %s | FileCheck %s --check-prefixes=CHECK,MULTI -// RUN: %dxc -T vs_6_6 -DETY=bool1 -DCOLS=3 %s | FileCheck %s --check-prefixes=CHECK,MULTI -// RUN: %dxc -T vs_6_6 -DETY=uint64_t1 -DCOLS=3 %s | FileCheck %s --check-prefixes=CHECK,MULTI -// RUN: %dxc -T vs_6_6 -DETY=double1 -DCOLS=3 %s | FileCheck %s --check-prefixes=CHECK,MULTI - -// RUN: %dxc -T vs_6_6 -DETY=float4 -DCOLS=3 %s | FileCheck %s --check-prefixes=CHECK,MULTI -// RUN: %dxc -T vs_6_6 -DETY=bool4 -DCOLS=3 %s | FileCheck %s --check-prefixes=CHECK,MULTI -// RUN: %dxc -T vs_6_6 -DETY=uint64_t4 -DCOLS=3 %s | FileCheck %s --check-prefixes=CHECK,MULTI -// RUN: %dxc -T vs_6_6 -DETY=double4 -DCOLS=3 %s | FileCheck %s --check-prefixes=CHECK,MULTI - -// RUN: %dxc -T vs_6_6 -DATY=matrix -DETY=float -DCOLS=2 -DROWS=2 %s | FileCheck %s -// RUN: %dxc -T vs_6_6 -DATY=matrix -DETY=bool -DCOLS=2 -DROWS=2 %s | FileCheck %s -// RUN: %dxc -T vs_6_6 -DATY=matrix -DETY=uint64_t -DCOLS=2 -DROWS=2 %s | FileCheck %s -// RUN: %dxc -T vs_6_6 -DATY=matrix -DETY=double -DCOLS=2 -DROWS=2 %s | FileCheck %s - -// RUN: %dxc -T vs_6_6 -DATY=matrix -DETY=float -DCOLS=3 -DROWS=3 %s | FileCheck %s --check-prefixes=CHECK,MULTI -// RUN: %dxc -T vs_6_6 -DATY=matrix -DETY=bool -DCOLS=3 -DROWS=3 %s | FileCheck %s --check-prefixes=CHECK,MULTI -// RUN: %dxc -T vs_6_6 -DATY=matrix -DETY=uint64_t -DCOLS=3 -DROWS=3 %s | FileCheck %s --check-prefixes=CHECK,MULTI -// RUN: %dxc -T vs_6_6 -DATY=matrix -DETY=double -DCOLS=3 -DROWS=3 %s | FileCheck %s --check-prefixes=CHECK,MULTI - -// RUN: %dxc -T vs_6_6 -DATY=Matrix -DETY=float -DCOLS=2 -DROWS=2 %s | FileCheck %s -// RUN: %dxc -T vs_6_6 -DATY=Matrix -DETY=uint64_t -DCOLS=2 -DROWS=2 %s | FileCheck %s -// RUN: %dxc -T vs_6_6 -DATY=Matrix -DETY=double -DCOLS=2 -DROWS=2 %s | FileCheck %s -// RUN: %dxc -T vs_6_6 -DATY=Matrix -DETY=float -DCOLS=3 -DROWS=3 %s | FileCheck %s --check-prefixes=CHECK,MULTI -// RUN: %dxc -T vs_6_6 -DATY=Matrix -DETY=bool -DCOLS=3 -DROWS=3 %s | FileCheck %s --check-prefixes=CHECK,MULTI -// RUN: %dxc -T vs_6_6 -DATY=Matrix -DETY=uint64_t -DCOLS=3 -DROWS=3 %s | FileCheck %s --check-prefixes=CHECK,MULTI -// RUN: %dxc -T vs_6_6 -DATY=Matrix -DETY=double -DCOLS=3 -DROWS=3 %s | FileCheck %s --check-prefixes=CHECK,MULTI - -// RUN: %dxc -T vs_6_6 -DATY=Vector -DETY=float -DCOLS=4 %s | FileCheck %s -// RUN: %dxc -T vs_6_6 -DATY=Vector -DETY=bool -DCOLS=4 %s | FileCheck %s -// RUN: %dxc -T vs_6_6 -DATY=Vector -DETY=uint64_t -DCOLS=2 %s | FileCheck %s -// RUN: %dxc -T vs_6_6 -DATY=Vector -DETY=double -DCOLS=2 %s | FileCheck %s - -// RUN: %dxc -T vs_6_6 -DATY=OffVector -DETY=float -DCOLS=4 %s | FileCheck %s --check-prefixes=CHECK,OFF -// RUN: %dxc -T vs_6_6 -DATY=OffVector -DETY=bool -DCOLS=4 %s | FileCheck %s --check-prefixes=CHECK,OFF -// RUN: %dxc -T vs_6_6 -DATY=OffVector -DETY=uint64_t -DCOLS=2 %s | FileCheck %s --check-prefixes=CHECK,OFF -// RUN: %dxc -T vs_6_6 -DATY=OffVector -DETY=double -DCOLS=2 %s | FileCheck %s --check-prefixes=CHECK,OFF +// RUN: %dxc -fcgl -T vs_6_6 -DETY=float -DCOLS=3 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DETY=bool -DCOLS=3 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DETY=uint64_t -DCOLS=3 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DETY=double -DCOLS=3 %s | FileCheck %s + +// RUN: %dxc -fcgl -T vs_6_6 -DETY=float1 -DCOLS=3 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DETY=bool1 -DCOLS=3 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DETY=uint64_t1 -DCOLS=3 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DETY=double1 -DCOLS=3 %s | FileCheck %s + +// RUN: %dxc -fcgl -T vs_6_6 -DETY=float4 -DCOLS=3 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DETY=bool4 -DCOLS=3 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DETY=uint64_t4 -DCOLS=3 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DETY=double4 -DCOLS=3 %s | FileCheck %s + +// RUN: %dxc -fcgl -T vs_6_6 -DATY=matrix -DETY=float -DCOLS=2 -DROWS=2 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DATY=matrix -DETY=bool -DCOLS=2 -DROWS=2 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DATY=matrix -DETY=uint64_t -DCOLS=2 -DROWS=2 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DATY=matrix -DETY=double -DCOLS=2 -DROWS=2 %s | FileCheck %s + +// RUN: %dxc -fcgl -T vs_6_6 -DATY=matrix -DETY=float -DCOLS=3 -DROWS=3 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DATY=matrix -DETY=bool -DCOLS=3 -DROWS=3 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DATY=matrix -DETY=uint64_t -DCOLS=3 -DROWS=3 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DATY=matrix -DETY=double -DCOLS=3 -DROWS=3 %s | FileCheck %s + +// RUN: %dxc -fcgl -T vs_6_6 -DATY=Matrix -DETY=float -DCOLS=2 -DROWS=2 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DATY=Matrix -DETY=uint64_t -DCOLS=2 -DROWS=2 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DATY=Matrix -DETY=double -DCOLS=2 -DROWS=2 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DATY=Matrix -DETY=float -DCOLS=3 -DROWS=3 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DATY=Matrix -DETY=bool -DCOLS=3 -DROWS=3 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DATY=Matrix -DETY=uint64_t -DCOLS=3 -DROWS=3 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DATY=Matrix -DETY=double -DCOLS=3 -DROWS=3 %s | FileCheck %s + +// RUN: %dxc -fcgl -T vs_6_6 -DATY=Vector -DETY=float -DCOLS=4 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DATY=Vector -DETY=bool -DCOLS=4 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DATY=Vector -DETY=uint64_t -DCOLS=2 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DATY=Vector -DETY=double -DCOLS=2 %s | FileCheck %s + +// RUN: %dxc -fcgl -T vs_6_6 -DATY=OffVector -DETY=float -DCOLS=4 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DATY=OffVector -DETY=bool -DCOLS=4 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DATY=OffVector -DETY=uint64_t -DCOLS=2 %s | FileCheck %s +// RUN: %dxc -fcgl -T vs_6_6 -DATY=OffVector -DETY=double -DCOLS=2 %s | FileCheck %s /////////////////////////////////////////////////////////////////////// // Test codegen for various load and store operations and conversions // for different aggregate buffer types and indices. /////////////////////////////////////////////////////////////////////// -// CHECK: %dx.types.ResRet.[[TY:[a-z][0-9][0-9]]] = type { [[TYPE:[a-z0-9]*]], - #if !defined(ATY) // Arrays have no aggregate typename #define TYPE ETY @@ -125,17 +123,11 @@ TYPE Add(TYPE f1[COLS], TYPE f2[COLS], TYPE f3[COLS], TYPE f4[COLS], TYPE f5[COL template T Add(T v1, T v2, T v3, T v4, T v5, T v6) { return v1 + v2 + v3 + v4 + v5 + v6; } +// CHECK-LABEL: define void @main void main(uint ix[3] : IX) { // ByteAddressBuffer Tests - - // CHECK-DAG: [[HDLROBY:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 1, i32 1, i32 0, i8 0 }, i32 1, i1 false) - // CHECK-DAG: [[HDLRWBY:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 1, i32 1, i32 0, i8 1 }, i32 1, i1 false) - - // CHECK-DAG: [[HDLROST:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 2, i32 2, i32 0, i8 0 }, i32 2, i1 false) - // CHECK-DAG: [[HDLRWST:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 2, i32 2, i32 0, i8 1 }, i32 2, i1 false) - - // CHECK-DAG: [[HDLCON:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 4, i32 4, i32 0, i8 1 }, i32 4, i1 false) - // CHECK-DAG: [[HDLAPP:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 5, i32 5, i32 0, i8 1 }, i32 5, i1 false) + // CHECK-COUNT-4: call {{.*}}@"dx.hl.op{{.*}}"(i32 231, + // CHECK-COUNT-2: call void @"dx.hl.op{{.*}}"(i32 277, // These -DAGs must match the same line. That is the only reason for the -DAG. // The first match will assign [[IX0]] to the actual index value. @@ -144,177 +136,49 @@ void main(uint ix[3] : IX) { // for lack offset support and a separate variable is needed for this index + offset value. // For these cases, the OFF : lines below will match the updated index value with the new offsets. // These lines will always match the same line since this shader can only produce one loadInput call. - // CHECK-DAG: [[IX0:%.*]] = call i32 @dx.op.loadInput.i32(i32 4, i32 {{[0-9]*}}, i32 [[BOFF:0]] - // CHECK-DAG: [[RIX0:%.*]] = call i32 @dx.op.loadInput.i32(i32 4, i32 {{[0-9]*}}, i32 [[BOFF]] - - // CHECK: [[ANHDLRWBY:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLRWBY]] - // OFF: [[RIX0:%.*]] = add i32 [[IX0]], [[BOFF:[0-9]+]] - // CHECK: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLRWBY]], i32 [[RIX0]] - // MULTI: [[IX0p4:%.*]] = add i32 [[RIX0]], [[p4:[0-9]+]] - // MULTI: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLRWBY]], i32 [[IX0p4]] - // MULTI: [[IX0p8:%.*]] = add i32 [[RIX0]], [[p8:[0-9]+]] - // MULTI: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLRWBY]], i32 [[IX0p8]] - // I1: icmp ne i32 - // I1: icmp ne i32 - // I1: icmp ne i32 - // I1: icmp ne i32 TYPE babElt1 SS = RwByBuf.Load< TYPE SS >(ix[0]); - // CHECK-DAG: [[IX1:%.*]] = call i32 @dx.op.loadInput.i32(i32 4, i32 {{[0-9]*}}, i32 1 - // CHECK-DAG: [[RIX1:%.*]] = call i32 @dx.op.loadInput.i32(i32 4, i32 {{[0-9]*}}, i32 1 - // OFF: [[RIX1:%.*]] = add i32 [[IX1]], [[BOFF]] - // CHECK: [[RESRET:%.*]] = call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLRWBY]], i32 [[RIX1]] - // MULTI: [[IX1p4:%.*]] = add i32 [[RIX1]], [[p4]] - // MULTI: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLRWBY]], i32 [[IX1p4]] - // MULTI: [[IX1p8:%.*]] = add i32 [[RIX1]], [[p8]] - // MULTI: [[RESRET:%.*]] = call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLRWBY]], i32 [[IX1p8]] - // CHECK: [[STATUS:%.*]] = extractvalue %dx.types.ResRet.[[TY]] [[RESRET]], 4 - // CHECK: [[CHK1:%.*]] = call i1 @dx.op.checkAccessFullyMapped.i32(i32 71, i32 [[STATUS]]) - // I1: icmp ne i32 - // I1: icmp ne i32 - // I1: icmp ne i32 - // I1: icmp ne i32 uint status1; TYPE babElt3 SS = RwByBuf.Load< TYPE SS >(ix[1], status1); - // CHECK: [[ANHDLROBY:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLROBY]] - // CHECK: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLROBY]], i32 [[RIX0]] - // MULTI: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLROBY]], i32 [[IX0p4]] - // MULTI: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLROBY]], i32 [[IX0p8]] - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 TYPE babElt2 SS = RoByBuf.Load< TYPE SS >(ix[0]); - // CHECK: [[RESRET:%.*]] = call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLROBY]], i32 [[RIX1]] - // MULTI: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLROBY]], i32 [[IX1p4]] - // MULTI: [[RESRET:%.*]] = call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLROBY]], i32 [[IX1p8]] - // CHECK: [[STATUS:%.*]] = extractvalue %dx.types.ResRet.[[TY]] [[RESRET]], 4 - // CHECK: [[CHK2:%.*]] = call i1 @dx.op.checkAccessFullyMapped.i32(i32 71, i32 [[STATUS]]) - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 uint status2; TYPE babElt4 SS = RoByBuf.Load< TYPE SS >(ix[1], status2); - // I1: zext i1 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // OFF: call void @dx.op.rawBufferStore.f32(i32 140, %dx.types.Handle [[ANHDLRWBY]], i32 {{%.*}}, i32 undef, float 0.0 - // OFF: call void @dx.op.rawBufferStore.f64(i32 140, %dx.types.Handle [[ANHDLRWBY]], i32 {{%.*}}, i32 undef, double 0.0 - // CHECK: call void @dx.op.rawBufferStore.[[TY]](i32 140, %dx.types.Handle [[ANHDLRWBY]], i32 [[RIX0]] - // MULTI: call void @dx.op.rawBufferStore.[[TY]](i32 140, %dx.types.Handle [[ANHDLRWBY]], i32 [[IX0p4]] - // MULTI: call void @dx.op.rawBufferStore.[[TY]](i32 140, %dx.types.Handle [[ANHDLRWBY]], i32 [[IX0p8]] - // CHECK: and i1 [[CHK1]], [[CHK2]] - // CHECK: [[ANHDLRWBY:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLRWBY]] - // CHECK: call void @dx.op.rawBufferStore.i32(i32 140, %dx.types.Handle [[ANHDLRWBY]], i32 100 RwByBuf.Store< TYPE SS >(ix[0], Add(babElt1, babElt2, babElt3, babElt4)); RwByBuf.Store< uint > (100, status1 && status2); // StructuredBuffer Tests - // CHECK: [[ANHDLRWST:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLRWST]] - // CHECK: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLRWST]], i32 [[IX0]], i32 [[BOFF]] - // MULTI: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLRWST]], i32 [[IX0]], i32 [[p4]] - // MULTI: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLRWST]], i32 [[IX0]], i32 [[p8]] - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 + // StructuredBuffer loads, subscripts, and stores. + + // CHECK: call {{.*}}@"dx.hl.op{{.*}}"(i32 231, TYPE stbElt1 SS = RwStBuf.Load(ix[0]); - // CHECK: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLRWST]], i32 [[IX1]], i32 [[BOFF]] - // MULTI: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLRWST]], i32 [[IX1]], i32 [[p4]] - // MULTI: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLRWST]], i32 [[IX1]], i32 [[p8]] - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 + // CHECK: call {{.*}}@"dx.hl.subscript.{{.*}}"(i32 0, TYPE stbElt2 SS = RwStBuf[ix[1]]; - // CHECK: [[IX2:%.*]] = call i32 @dx.op.loadInput.i32(i32 4, i32 {{[0-9]*}}, i32 2 - // CHECK: [[RESRET:%.*]] = call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLRWST]], i32 [[IX2]], i32 [[BOFF]] - // MULTI: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLRWST]], i32 [[IX2]], i32 [[p4]] - // MULTI: [[RESRET:%.*]] = call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLRWST]], i32 [[IX2]], i32 [[p8]] - // CHECK: [[STATUS:%.*]] = extractvalue %dx.types.ResRet.[[TY]] [[RESRET]], 4 - // CHECK: [[CHK1:%.*]] = call i1 @dx.op.checkAccessFullyMapped.i32(i32 71, i32 [[STATUS]]) - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 + // CHECK: call {{.*}}@"dx.hl.op{{.*}}"(i32 231, TYPE stbElt5 SS = RwStBuf.Load(ix[2], status1); - // CHECK: [[ANHDLROST:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLROST]] - // CHECK: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLROST]], i32 [[IX0]], i32 [[BOFF]] - // MULTI: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLROST]], i32 [[IX0]], i32 [[p4]] - // MULTI: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLROST]], i32 [[IX0]], i32 [[p8]] - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 + // CHECK: call {{.*}}@"dx.hl.op{{.*}}"(i32 231, TYPE stbElt3 SS = RoStBuf.Load(ix[0]); - // CHECK: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLROST]], i32 [[IX1]], i32 [[BOFF]] - // MULTI: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLROST]], i32 [[IX1]], i32 [[p4]] - // MULTI: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLROST]], i32 [[IX1]], i32 [[p8]] - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 + // CHECK: call {{.*}}@"dx.hl.subscript.{{.*}}"(i32 0, TYPE stbElt4 SS = RoStBuf[ix[1]]; - // CHECK: [[RESRET:%.*]] = call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLROST]], i32 [[IX2]], i32 [[BOFF]] - // MULTI: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLROST]], i32 [[IX2]], i32 [[p4]] - // MULTI: [[RESRET:%.*]] = call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLROST]], i32 [[IX2]], i32 [[p8]] - // CHECK: [[STATUS:%.*]] = extractvalue %dx.types.ResRet.[[TY]] [[RESRET]], 4 - // CHECK: [[CHK2:%.*]] = call i1 @dx.op.checkAccessFullyMapped.i32(i32 71, i32 [[STATUS]]) - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 + // CHECK: call {{.*}}@"dx.hl.op{{.*}}"(i32 231, TYPE stbElt6 SS = RoStBuf.Load(ix[2], status2); - // I1: zext i1 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // OFF: call void @dx.op.rawBufferStore.f32(i32 140, %dx.types.Handle [[ANHDLRWST]], i32 [[IX0]], i32 0, float 0.0 - // OFF: call void @dx.op.rawBufferStore.f64(i32 140, %dx.types.Handle [[ANHDLRWST]], i32 [[IX0]], i32 16, double 0.0 - // CHECK: call void @dx.op.rawBufferStore.[[TY]](i32 140, %dx.types.Handle [[ANHDLRWST]], i32 [[IX0]], i32 [[BOFF]] - // MULTI: call void @dx.op.rawBufferStore.[[TY]](i32 140, %dx.types.Handle [[ANHDLRWST]], i32 [[IX0]], i32 [[p4]] - // MULTI: call void @dx.op.rawBufferStore.[[TY]](i32 140, %dx.types.Handle [[ANHDLRWST]], i32 [[IX0]], i32 [[p8]] - // CHECK: and i1 [[CHK1]], [[CHK2]] - // CHECK: [[ANHDLRWBY:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLRWBY]] - // CHECK: call void @dx.op.rawBufferStore.i32(i32 140, %dx.types.Handle [[ANHDLRWBY]], i32 200 + // CHECK: call {{.*}}@"dx.hl.subscript.{{.*}}"(i32 0, + // CHECK: call void @"dx.hl.op{{.*}}"(i32 277, RwStBuf[ix[0]] = Add(stbElt1, stbElt2, stbElt3, stbElt4, stbElt5, stbElt6); RwByBuf.Store< uint > (200, status1 && status2); // {Append/Consume}StructuredBuffer Tests - // CHECK: [[ANHDLCON:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLCON]] - // CHECK: [[CONIX:%.*]] = call i32 @dx.op.bufferUpdateCounter(i32 70, %dx.types.Handle [[ANHDLCON]], i8 -1) - // OFF: call %dx.types.ResRet.f32 @dx.op.rawBufferLoad.f32(i32 139, %dx.types.Handle [[ANHDLCON]], i32 [[CONIX]], i32 - // OFF: call %dx.types.ResRet.f64 @dx.op.rawBufferLoad.f64(i32 139, %dx.types.Handle [[ANHDLCON]], i32 [[CONIX]], i32 16 - // CHECK: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLCON]], i32 [[CONIX]], i32 [[BOFF]] - // MULTI: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLCON]], i32 [[CONIX]], i32 [[p4]] - // MULTI: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLCON]], i32 [[CONIX]], i32 [[p8]] - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 + // CHECK: call {{.*}}@"dx.hl.op..consume{{.*}}"(i32 283, TYPE cnElt SS = CnStBuf.Consume(); - // CHECK: [[ANHDLAPP:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLAPP]] - // CHECK: [[APPIX:%.*]] = call i32 @dx.op.bufferUpdateCounter(i32 70, %dx.types.Handle [[ANHDLAPP]], i8 1) - // I1: zext i1 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // OFF: call void @dx.op.rawBufferStore.f32(i32 140, %dx.types.Handle [[ANHDLAPP]], i32 [[APPIX]], i32 0 - // OFF: call void @dx.op.rawBufferStore.f64(i32 140, %dx.types.Handle [[ANHDLAPP]], i32 [[APPIX]], i32 16 - // CHECK: call void @dx.op.rawBufferStore.[[TY]](i32 140, %dx.types.Handle [[ANHDLAPP]], i32 [[APPIX]], i32 [[BOFF]] - // MULTI: call void @dx.op.rawBufferStore.[[TY]](i32 140, %dx.types.Handle [[ANHDLAPP]], i32 [[APPIX]], i32 [[p4]] - // MULTI: call void @dx.op.rawBufferStore.[[TY]](i32 140, %dx.types.Handle [[ANHDLAPP]], i32 [[APPIX]], i32 [[p8]] + // CHECK: call void @"dx.hl.op..appendvoid{{.*}}"(i32 226, ApStBuf.Append(cnElt); } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/intrinsics/buffer-load-stores.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/intrinsics/buffer-load-stores.hlsl index 896f442c2c..c6834f929d 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/intrinsics/buffer-load-stores.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/intrinsics/buffer-load-stores.hlsl @@ -1,14 +1,13 @@ -// RUN: %dxc -DTYPE=float4 -T vs_6_6 %s | FileCheck %s -// RUN: %dxc -DTYPE=bool4 -T vs_6_6 %s | FileCheck %s --check-prefixes=CHECK,I1 -// RUN: %dxc -DTYPE=uint64_t2 -T vs_6_6 %s | FileCheck %s --check-prefixes=CHECK,I64 -// RUN: %dxc -DTYPE=double2 -T vs_6_6 %s | FileCheck %s --check-prefixes=CHECK,F64 +// RUN: %dxc -fcgl -DTYPE=float4 -T vs_6_6 %s | FileCheck %s --check-prefixes=CHECK,FLOAT +// RUN: %dxc -fcgl -DTYPE=bool4 -T vs_6_6 %s | FileCheck %s --check-prefixes=CHECK,BOOL +// RUN: %dxc -fcgl -DTYPE=uint64_t2 -T vs_6_6 %s | FileCheck %s --check-prefixes=CHECK,UINT64 +// RUN: %dxc -fcgl -DTYPE=double2 -T vs_6_6 %s | FileCheck %s --check-prefixes=CHECK,DOUBLE /////////////////////////////////////////////////////////////////////// // Test codegen for various load and store operations and conversions // for different scalar/vector buffer types and indices. /////////////////////////////////////////////////////////////////////// - // These -DAGs must match the same line. That is the only reason for the -DAG. // The first match will assign [[TY]] to the native type // For most runs, the second match will assign [[TY32]] to the same thing. @@ -16,10 +15,6 @@ // For these cases, there is another line that will always match i32. // This line will also force the previous -DAGs to match the same line since the most // This shader can produce is two ResRet types. -// CHECK-DAG: %dx.types.ResRet.[[TY:[a-z][0-9][0-9]]] = type { [[TYPE:[a-z0-9]*]], -// CHECK-DAG: %dx.types.ResRet.[[TY32:[a-z][0-9][0-9]]] = type { [[TYPE]], -// I64: %dx.types.ResRet.[[TY32:i32]] -// F64: %dx.types.ResRet.[[TY32:i32]] ByteAddressBuffer RoByBuf : register(t1); RWByteAddressBuffer RwByBuf : register(u1); @@ -40,412 +35,89 @@ RWTexture2D< TYPE > RwTex2d : register(u7); Texture3D< TYPE > RoTex3d : register(t8); RWTexture3D< TYPE > RwTex3d : register(u8); +// CHECK-LABEL: define void @main void main(uint ix0 : IX0, uint ix1 : IX1, uint2 ix2 : IX2, uint3 ix3 : IX3) { // ByteAddressBuffer Tests - // CHECK-DAG: [[HDLROBY:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 1, i32 1, i32 0, i8 0 }, i32 1, i1 false) - // CHECK-DAG: [[HDLRWBY:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 1, i32 1, i32 0, i8 1 }, i32 1, i1 false) - - // CHECK-DAG: [[HDLROST:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 2, i32 2, i32 0, i8 0 }, i32 2, i1 false) - // CHECK-DAG: [[HDLRWST:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 2, i32 2, i32 0, i8 1 }, i32 2, i1 false) - - // CHECK-DAG: [[HDLCON:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 3, i32 3, i32 0, i8 1 }, i32 3, i1 false) - // CHECK-DAG: [[HDLAPP:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 4, i32 4, i32 0, i8 1 }, i32 4, i1 false) - - // CHECK-DAG: [[HDLROTY:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 5, i32 5, i32 0, i8 0 }, i32 5, i1 false) - // CHECK-DAG: [[HDLRWTY:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 5, i32 5, i32 0, i8 1 }, i32 5, i1 false) - - // CHECK-DAG: [[HDLROTX1:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 6, i32 6, i32 0, i8 0 }, i32 6, i1 false) - // CHECK-DAG: [[HDLRWTX1:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 6, i32 6, i32 0, i8 1 }, i32 6, i1 false) - // CHECK-DAG: [[HDLROTX2:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 7, i32 7, i32 0, i8 0 }, i32 7, i1 false) - // CHECK-DAG: [[HDLRWTX2:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 7, i32 7, i32 0, i8 1 }, i32 7, i1 false) - // CHECK-DAG: [[HDLROTX3:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 8, i32 8, i32 0, i8 0 }, i32 8, i1 false) - // CHECK-DAG: [[HDLRWTX3:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 8, i32 8, i32 0, i8 1 }, i32 8, i1 false) - - - // CHECK-DAG: [[IX0:%.*]] = call i32 @dx.op.loadInput.i32(i32 4, i32 0, i32 0, i8 0 - // CHECK-DAG: [[IX1:%.*]] = call i32 @dx.op.loadInput.i32(i32 4, i32 1, i32 0, i8 0 - // CHECK-DAG: [[IX20:%.*]] = call i32 @dx.op.loadInput.i32(i32 4, i32 2, i32 0, i8 0 - // CHECK-DAG: [[IX21:%.*]] = call i32 @dx.op.loadInput.i32(i32 4, i32 2, i32 0, i8 1 - // CHECK-DAG: [[IX30:%.*]] = call i32 @dx.op.loadInput.i32(i32 4, i32 3, i32 0, i8 0 - // CHECK-DAG: [[IX31:%.*]] = call i32 @dx.op.loadInput.i32(i32 4, i32 3, i32 0, i8 1 - // CHECK-DAG: [[IX32:%.*]] = call i32 @dx.op.loadInput.i32(i32 4, i32 3, i32 0, i8 2 - - // CHECK: [[ANHDLRWBY:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLRWBY]] - // CHECK: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLRWBY]], i32 [[IX0]] - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 + // FLOAT: call <4 x float> @"dx.hl.op.ro.<4 x float> (i32, %dx.types.Handle, i32)"(i32 231, + // BOOL: call <4 x i1> @"dx.hl.op.ro.<4 x i1> (i32, %dx.types.Handle, i32)"(i32 231, + // UINT64: call <2 x i64> @"dx.hl.op.ro.<2 x i64> (i32, %dx.types.Handle, i32)"(i32 231, + // DOUBLE: call <2 x double> @"dx.hl.op.ro.<2 x double> (i32, %dx.types.Handle, i32)"(i32 231, TYPE babElt1 = RwByBuf.Load< TYPE >(ix0); - - // CHECK: [[ANHDLROBY:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLROBY]] - // CHECK: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLROBY]], i32 [[IX0]] - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 + + // CHECK: call {{.*}}@"dx.hl.op{{.*}}"(i32 231, TYPE babElt2 = RoByBuf.Load< TYPE >(ix0); - // CHECK: [[RESRET:%.*]] = call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLRWBY]], i32 [[IX1]] - // CHECK: [[STATUS:%.*]] = extractvalue %dx.types.ResRet.[[TY]] [[RESRET]], 4 - // CHECK: [[CHK1:%.*]] = call i1 @dx.op.checkAccessFullyMapped.i32(i32 71, i32 [[STATUS]]) - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 + // CHECK: call {{.*}}@"dx.hl.op{{.*}}"(i32 231, uint status1 = 0; TYPE babElt3 = RwByBuf.Load< TYPE >(ix1, status1); - // CHECK: [[RESRET:%.*]] = call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLROBY]], i32 [[IX1]] - // CHECK: [[STATUS:%.*]] = extractvalue %dx.types.ResRet.[[TY]] [[RESRET]], 4 - // CHECK: [[CHK2:%.*]] = call i1 @dx.op.checkAccessFullyMapped.i32(i32 71, i32 [[STATUS]]) - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 + // CHECK: call {{.*}}@"dx.hl.op{{.*}}"(i32 231, uint status2 = 0; TYPE babElt4 = RoByBuf.Load< TYPE >(ix1, status2); - // I1: zext i1 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // CHECK: all void @dx.op.rawBufferStore.[[TY]](i32 140, %dx.types.Handle [[ANHDLRWBY]], i32 [[IX0]] - // CHECK: and i1 [[CHK1]], [[CHK2]] - // CHECK: [[ANHDLRWBY:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLRWBY]] - // CHECK: call void @dx.op.rawBufferStore.i32(i32 140, %dx.types.Handle [[ANHDLRWBY]], i32 100 + // CHECK-COUNT-2: call void @"dx.hl.op{{.*}}"(i32 277, RwByBuf.Store< TYPE >(ix0, babElt1 + babElt2 + babElt3 + babElt4); RwByBuf.Store< uint > (100, status1 && status2); // StructuredBuffer Tests - // CHECK: [[ANHDLRWST:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLRWST]] - // CHECK: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLRWST]], i32 [[IX0]] - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 + // CHECK: call {{.*}}@"dx.hl.op{{.*}}"(i32 231, TYPE stbElt1 = RwStBuf.Load(ix0); - // CHECK: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLRWST]], i32 [[IX1]] - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 + // CHECK: call {{.*}}@"dx.hl.subscript.{{.*}}"(i32 0, TYPE stbElt2 = RwStBuf[ix1]; - // CHECK: [[ANHDLROST:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLROST]] - // CHECK: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLROST]], i32 [[IX0]] - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 + // CHECK: call {{.*}}@"dx.hl.op{{.*}}"(i32 231, TYPE stbElt3 = RoStBuf.Load(ix0); - // CHECK: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLROST]], i32 [[IX1]] - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 + // CHECK: call {{.*}}@"dx.hl.subscript.{{.*}}"(i32 0, TYPE stbElt4 = RoStBuf[ix1]; - // CHECK: [[RESRET:%.*]] = call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLRWST]], i32 [[IX20]] - // CHECK: [[STATUS:%.*]] = extractvalue %dx.types.ResRet.[[TY]] [[RESRET]], 4 - // CHECK: [[CHK1:%.*]] = call i1 @dx.op.checkAccessFullyMapped.i32(i32 71, i32 [[STATUS]]) - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 + // CHECK-COUNT-2: call {{.*}}@"dx.hl.op{{.*}}"(i32 231, TYPE stbElt5 = RwStBuf.Load(ix2[0], status1); - - // CHECK: [[RESRET:%.*]] = call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLROST]], i32 [[IX20]] - // CHECK: [[STATUS:%.*]] = extractvalue %dx.types.ResRet.[[TY]] [[RESRET]], 4 - // CHECK: [[CHK2:%.*]] = call i1 @dx.op.checkAccessFullyMapped.i32(i32 71, i32 [[STATUS]]) - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 TYPE stbElt6 = RoStBuf.Load(ix2[0], status2); - // I1: zext i1 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // CHECK: all void @dx.op.rawBufferStore.[[TY]](i32 140, %dx.types.Handle [[ANHDLRWST]], i32 [[IX0]] - // CHECK: and i1 [[CHK1]], [[CHK2]] - // CHECK: [[ANHDLRWBY:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLRWBY]] - // CHECK: call void @dx.op.rawBufferStore.i32(i32 140, %dx.types.Handle [[ANHDLRWBY]], i32 200 + // CHECK: call {{.*}}@"dx.hl.subscript.{{.*}}"(i32 0, + // CHECK: call void @"dx.hl.op{{.*}}"(i32 277, RwStBuf[ix0] = stbElt1 + stbElt2 + stbElt3 + stbElt4 + stbElt5 + stbElt6; RwByBuf.Store< uint > (200, status1 && status2); // {Append/Consume}StructuredBuffer Tests - // CHECK: [[ANHDLCON:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLCON]] - // CHECK: [[CONIX:%.*]] = call i32 @dx.op.bufferUpdateCounter(i32 70, %dx.types.Handle [[ANHDLCON]], i8 -1) - // CHECK: call %dx.types.ResRet.[[TY]] @dx.op.rawBufferLoad.[[TY]](i32 139, %dx.types.Handle [[ANHDLCON]], i32 [[CONIX]] - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 + // CHECK: call {{.*}}@"dx.hl.op..consume{{.*}}"(i32 283, TYPE cnElt = CnStBuf.Consume(); - - // CHECK: [[ANHDLAPP:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLAPP]] - // CHECK: [[APPIX:%.*]] = call i32 @dx.op.bufferUpdateCounter(i32 70, %dx.types.Handle [[ANHDLAPP]], i8 1) - // I1: zext i1 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // CHECK: all void @dx.op.rawBufferStore.[[TY]](i32 140, %dx.types.Handle [[ANHDLAPP]], i32 [[APPIX]] + + // CHECK: call void @"dx.hl.op..appendvoid{{.*}}"(i32 226, ApStBuf.Append(cnElt); // TypedBuffer Tests - // CHECK: [[ANHDLRWTY:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLRWTY]] - // CHECK: call %dx.types.ResRet.[[TY32]] @dx.op.bufferLoad.[[TY32]](i32 68, %dx.types.Handle [[ANHDLRWTY]], i32 [[IX0]] - // F64: call double @dx.op.makeDouble.f64(i32 101 - // F64: call double @dx.op.makeDouble.f64(i32 101 - // I64: zext i32 %{{.*}} to i64 - // I64: zext i32 %{{.*}} to i64 - // I64: shl nuw i64 - // I64: or i64 - // I64: zext i32 %{{.*}} to i64 - // I64: zext i32 %{{.*}} to i64 - // I64: shl nuw i64 - // I64: or i64 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 + // CHECK: call {{.*}}@"dx.hl.op{{.*}}"(i32 231, TYPE typElt1 = RwTyBuf.Load(ix0); - // CHECK: call %dx.types.ResRet.[[TY32]] @dx.op.bufferLoad.[[TY32]](i32 68, %dx.types.Handle [[ANHDLRWTY]], i32 [[IX1]] - // F64: call double @dx.op.makeDouble.f64(i32 101 - // F64: call double @dx.op.makeDouble.f64(i32 101 - // I64: zext i32 %{{.*}} to i64 - // I64: zext i32 %{{.*}} to i64 - // I64: shl nuw i64 - // I64: or i64 - // I64: zext i32 %{{.*}} to i64 - // I64: zext i32 %{{.*}} to i64 - // I64: shl nuw i64 - // I64: or i64 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 + // CHECK: call {{.*}}@"dx.hl.subscript.{{.*}}"(i32 0, TYPE typElt2 = RwTyBuf[ix1]; - // CHECK: [[ANHDLROTY:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLROTY]] - // CHECK: call %dx.types.ResRet.[[TY32]] @dx.op.bufferLoad.[[TY32]](i32 68, %dx.types.Handle [[ANHDLROTY]], i32 [[IX0]] - // F64: call double @dx.op.makeDouble.f64(i32 101 - // F64: call double @dx.op.makeDouble.f64(i32 101 - // I64: zext i32 %{{.*}} to i64 - // I64: zext i32 %{{.*}} to i64 - // I64: shl nuw i64 - // I64: or i64 - // I64: zext i32 %{{.*}} to i64 - // I64: zext i32 %{{.*}} to i64 - // I64: shl nuw i64 - // I64: or i64 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 + // CHECK: call {{.*}}@"dx.hl.op{{.*}}"(i32 231, TYPE typElt3 = RoTyBuf.Load(ix0); - // CHECK: call %dx.types.ResRet.[[TY32]] @dx.op.bufferLoad.[[TY32]](i32 68, %dx.types.Handle [[ANHDLROTY]], i32 [[IX1]] - // F64: call double @dx.op.makeDouble.f64(i32 101 - // F64: call double @dx.op.makeDouble.f64(i32 101 - // I64: zext i32 %{{.*}} to i64 - // I64: zext i32 %{{.*}} to i64 - // I64: shl nuw i64 - // I64: or i64 - // I64: zext i32 %{{.*}} to i64 - // I64: zext i32 %{{.*}} to i64 - // I64: shl nuw i64 - // I64: or i64 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 + // CHECK: call {{.*}}@"dx.hl.subscript.{{.*}}"(i32 0, TYPE typElt4 = RoTyBuf[ix1]; - // CHECK: [[RESRET:%.*]] = call %dx.types.ResRet.[[TY32]] @dx.op.bufferLoad.[[TY32]](i32 68, %dx.types.Handle [[ANHDLRWTY]], i32 [[IX20]] - // CHECK: [[STATUS:%.*]] = extractvalue %dx.types.ResRet.[[TY32]] [[RESRET]], 4 - // CHECK: [[CHK1:%.*]] = call i1 @dx.op.checkAccessFullyMapped.i32(i32 71, i32 [[STATUS]]) - // F64: call double @dx.op.makeDouble.f64(i32 101 - // F64: call double @dx.op.makeDouble.f64(i32 101 - // I64: zext i32 %{{.*}} to i64 - // I64: zext i32 %{{.*}} to i64 - // I64: shl nuw i64 - // I64: or i64 - // I64: zext i32 %{{.*}} to i64 - // I64: zext i32 %{{.*}} to i64 - // I64: shl nuw i64 - // I64: or i64 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 + // CHECK-COUNT-2: call {{.*}}@"dx.hl.op{{.*}}"(i32 231, TYPE typElt5 = RwTyBuf.Load(ix2[0], status1); - - // CHECK: [[RESRET:%.*]] = call %dx.types.ResRet.[[TY32]] @dx.op.bufferLoad.[[TY32]](i32 68, %dx.types.Handle [[ANHDLROTY]], i32 [[IX20]] - // CHECK: [[STATUS:%.*]] = extractvalue %dx.types.ResRet.[[TY32]] [[RESRET]], 4 - // CHECK: [[CHK2:%.*]] = call i1 @dx.op.checkAccessFullyMapped.i32(i32 71, i32 [[STATUS]]) - // F64: call double @dx.op.makeDouble.f64(i32 101 - // F64: call double @dx.op.makeDouble.f64(i32 101 - // I64: zext i32 %{{.*}} to i64 - // I64: zext i32 %{{.*}} to i64 - // I64: shl nuw i64 - // I64: or i64 - // I64: zext i32 %{{.*}} to i64 - // I64: zext i32 %{{.*}} to i64 - // I64: shl nuw i64 - // I64: or i64 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 TYPE typElt6 = RoTyBuf.Load(ix2[0], status2); - // F64: call %dx.types.splitdouble @dx.op.splitDouble.f64(i32 102 - // F64: call %dx.types.splitdouble @dx.op.splitDouble.f64(i32 102 - // I64: trunc i64 %{{.*}} to i32 - // lshr i64 %{{.*}}, 32 - // I64: trunc i64 %{{.*}} to i32 - // I64: trunc i64 %{{.*}} to i32 - // lshr i64 %{{.*}}, 32 - // I64: trunc i64 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // CHECK: call void @dx.op.bufferStore.[[TY32]](i32 69, %dx.types.Handle [[ANHDLRWTY]], i32 [[IX0]] - // CHECK: and i1 [[CHK1]], [[CHK2]] - // CHECK: [[ANHDLRWBY:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLRWBY]] - // CHECK: call void @dx.op.rawBufferStore.i32(i32 140, %dx.types.Handle [[ANHDLRWBY]], i32 300 + // CHECK: call {{.*}}@"dx.hl.subscript.{{.*}}"(i32 0, + // CHECK: call void @"dx.hl.op{{.*}}"(i32 277, RwTyBuf[ix0] = typElt1 + typElt2 + typElt3 + typElt4 + typElt5 + typElt6; RwByBuf.Store< uint > (300, status1 && status2); // Texture Tests - // CHECK: [[ANHDLROTX1:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLROTX1]] - // CHECK: call %dx.types.ResRet.[[TY32]] @dx.op.textureLoad.[[TY32]](i32 66, %dx.types.Handle [[ANHDLROTX1]], i32 0, i32 [[IX0]], i32 undef, i32 undef - // F64: call double @dx.op.makeDouble.f64(i32 101 - // F64: call double @dx.op.makeDouble.f64(i32 101 - // I64: zext i32 %{{.*}} to i64 - // I64: zext i32 %{{.*}} to i64 - // I64: shl nuw i64 - // I64: or i64 - // I64: zext i32 %{{.*}} to i64 - // I64: zext i32 %{{.*}} to i64 - // I64: shl nuw i64 - // I64: or i64 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 + // CHECK-COUNT-7: call {{.*}}@"dx.hl.subscript.{{.*}}"(i32 0, TYPE texElt1 = RoTex1d[ix0]; - - // CHECK: [[ANHDLRWTX1:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLRWTX1]] - // CHECK: call %dx.types.ResRet.[[TY32]] @dx.op.textureLoad.[[TY32]](i32 66, %dx.types.Handle [[ANHDLRWTX1]], i32 undef, i32 [[IX0]], i32 undef, i32 undef - // F64: call double @dx.op.makeDouble.f64(i32 101 - // F64: call double @dx.op.makeDouble.f64(i32 101 - // I64: zext i32 %{{.*}} to i64 - // I64: zext i32 %{{.*}} to i64 - // I64: shl nuw i64 - // I64: or i64 - // I64: zext i32 %{{.*}} to i64 - // I64: zext i32 %{{.*}} to i64 - // I64: shl nuw i64 - // I64: or i64 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 TYPE texElt2 = RwTex1d[ix0]; - - // CHECK: [[ANHDLROTX2:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLROTX2]] - // CHECK: call %dx.types.ResRet.[[TY32]] @dx.op.textureLoad.[[TY32]](i32 66, %dx.types.Handle [[ANHDLROTX2]], i32 0, i32 [[IX20]], i32 [[IX21]], i32 undef - // F64: call double @dx.op.makeDouble.f64(i32 101 - // F64: call double @dx.op.makeDouble.f64(i32 101 - // I64: zext i32 %{{.*}} to i64 - // I64: zext i32 %{{.*}} to i64 - // I64: shl nuw i64 - // I64: or i64 - // I64: zext i32 %{{.*}} to i64 - // I64: zext i32 %{{.*}} to i64 - // I64: shl nuw i64 - // I64: or i64 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 TYPE texElt3 = RoTex2d[ix2]; - - // CHECK: [[ANHDLRWTX2:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLRWTX2]] - // CHECK: call %dx.types.ResRet.[[TY32]] @dx.op.textureLoad.[[TY32]](i32 66, %dx.types.Handle [[ANHDLRWTX2]], i32 undef, i32 [[IX20]], i32 [[IX21]], i32 undef - // F64: call double @dx.op.makeDouble.f64(i32 101 - // F64: call double @dx.op.makeDouble.f64(i32 101 - // I64: zext i32 %{{.*}} to i64 - // I64: zext i32 %{{.*}} to i64 - // I64: shl nuw i64 - // I64: or i64 - // I64: zext i32 %{{.*}} to i64 - // I64: zext i32 %{{.*}} to i64 - // I64: shl nuw i64 - // I64: or i64 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 TYPE texElt4 = RwTex2d[ix2]; - - // CHECK: [[ANHDLROTX3:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLROTX3]] - // CHECK: call %dx.types.ResRet.[[TY32]] @dx.op.textureLoad.[[TY32]](i32 66, %dx.types.Handle [[ANHDLROTX3]], i32 0, i32 [[IX30]], i32 [[IX31]], i32 [[IX32]] - // F64: call double @dx.op.makeDouble.f64(i32 101 - // F64: call double @dx.op.makeDouble.f64(i32 101 - // I64: zext i32 %{{.*}} to i64 - // I64: zext i32 %{{.*}} to i64 - // I64: shl nuw i64 - // I64: or i64 - // I64: zext i32 %{{.*}} to i64 - // I64: zext i32 %{{.*}} to i64 - // I64: shl nuw i64 - // I64: or i64 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 TYPE texElt5 = RoTex3d[ix3]; - - // CHECK: [[ANHDLRWTX3:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HDLRWTX3]] - // CHECK: call %dx.types.ResRet.[[TY32]] @dx.op.textureLoad.[[TY32]](i32 66, %dx.types.Handle [[ANHDLRWTX3]], i32 undef, i32 [[IX30]], i32 [[IX31]], i32 [[IX32]] - // F64: call double @dx.op.makeDouble.f64(i32 101 - // F64: call double @dx.op.makeDouble.f64(i32 101 - // I64: zext i32 %{{.*}} to i64 - // I64: zext i32 %{{.*}} to i64 - // I64: shl nuw i64 - // I64: or i64 - // I64: zext i32 %{{.*}} to i64 - // I64: zext i32 %{{.*}} to i64 - // I64: shl nuw i64 - // I64: or i64 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 - // I1: icmp ne i32 %{{.*}}, 0 TYPE texElt6 = RwTex3d[ix3]; - - // F64: call %dx.types.splitdouble @dx.op.splitDouble.f64(i32 102 - // F64: call %dx.types.splitdouble @dx.op.splitDouble.f64(i32 102 - // I64: trunc i64 %{{.*}} to i32 - // lshr i64 %{{.*}}, 32 - // I64: trunc i64 %{{.*}} to i32 - // I64: trunc i64 %{{.*}} to i32 - // lshr i64 %{{.*}}, 32 - // I64: trunc i64 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // I1: zext i1 %{{.*}} to i32 - // CHECK: call void @dx.op.textureStore.[[TY32]](i32 67, %dx.types.Handle [[ANHDLRWTX3]], i32 [[IX30]], i32 [[IX31]], i32 [[IX32]] RwTex3d[ix3] = texElt1 + texElt2 + texElt3 + texElt4 + texElt5 + texElt6; } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/intrinsics/clusterid.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/intrinsics/clusterid.hlsl index d95b5ed143..11b16a8c7e 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/intrinsics/clusterid.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/intrinsics/clusterid.hlsl @@ -5,19 +5,19 @@ // Test ClusterID intrinsics for SM 6.10 -// AST: `-CXXMethodDecl {{.*}} used GetClusterID 'unsigned int ()' extern +// AST: `-CXXMethodDecl {{.*}} used GetClusterID 'unsigned int () const' extern // AST-NEXT: {{.*}}|-TemplateArgument type 'unsigned int' // AST-NEXT: {{.*}}|-HLSLIntrinsicAttr {{.*}} Implicit "op" "" 396 // AST-NEXT: {{.*}}|-ConstAttr {{.*}} Implicit // AST-NEXT: {{.*}}`-AvailabilityAttr {{.*}} Implicit 6.10 0 0 "" -// AST: `-CXXMethodDecl {{.*}} used CandidateClusterID 'unsigned int ()' extern +// AST: `-CXXMethodDecl {{.*}} used CandidateClusterID 'unsigned int () const' extern // AST-NEXT: {{.*}}|-TemplateArgument type 'unsigned int' // AST-NEXT: {{.*}}|-HLSLIntrinsicAttr {{.*}} Implicit "op" "" 394 // AST-NEXT: {{.*}}|-PureAttr {{.*}} Implicit // AST-NEXT: {{.*}}`-AvailabilityAttr {{.*}} Implicit 6.10 0 0 "" -// AST: `-CXXMethodDecl {{.*}} used CommittedClusterID 'unsigned int ()' extern +// AST: `-CXXMethodDecl {{.*}} used CommittedClusterID 'unsigned int () const' extern // AST-NEXT: {{.*}}|-TemplateArgument type 'unsigned int' // AST-NEXT: {{.*}}|-HLSLIntrinsicAttr {{.*}} Implicit "op" "" 395 // AST-NEXT: {{.*}}|-PureAttr {{.*}} Implicit @@ -37,7 +37,7 @@ struct [raypayload] Payload { // Global ClusterID intrinsic // CHECK-LABEL: define void @{{.*}}test_cluster_id{{.*}}( -// CHECK: call i32 @dx.op.clusterID(i32 -2147483645) +// CHECK: call i32 @dx.op.clusterID(i32 314) // CHECK: call void @dx.op.rawBufferStore.i32 // FCGL-LABEL: define void @{{.*}}test_cluster_id{{.*}}( @@ -50,7 +50,7 @@ void test_cluster_id(inout Payload payload, in BuiltInTriangleIntersectionAttrib // RayQuery CandidateClusterID // CHECK-LABEL: define void @{{.*}}test_rayquery_candidate_cluster_id{{.*}}( -// CHECK: call i32 @dx.op.rayQuery_StateScalar.i32(i32 -2147483644 +// CHECK: call i32 @dx.op.rayQuery_StateScalar.i32(i32 315 // CHECK: call void @dx.op.rawBufferStore.i32 // FCGL-LABEL: define void @{{.*}}test_rayquery_candidate_cluster_id{{.*}}( @@ -73,7 +73,7 @@ void test_rayquery_candidate_cluster_id() { // RayQuery CommittedClusterID // CHECK-LABEL: define void @{{.*}}test_rayquery_committed_cluster_id{{.*}}( -// CHECK: call i32 @dx.op.rayQuery_StateScalar.i32(i32 -2147483643 +// CHECK: call i32 @dx.op.rayQuery_StateScalar.i32(i32 316 // CHECK: call void @dx.op.rawBufferStore.i32 // FCGL-LABEL: define void @{{.*}}test_rayquery_committed_cluster_id{{.*}}( @@ -95,7 +95,7 @@ void test_rayquery_committed_cluster_id() { // HitObject GetClusterID // CHECK-LABEL: define void @{{.*}}test_hitobject_cluster_id{{.*}}( -// CHECK: call i32 @dx.op.hitObject_StateScalar.i32(i32 -2147483642 +// CHECK: call i32 @dx.op.hitObject_StateScalar.i32(i32 317 // CHECK: call void @dx.op.rawBufferStore.i32 // FCGL-LABEL: define void @{{.*}}test_hitobject_cluster_id{{.*}}( diff --git a/tools/clang/test/CodeGenDXIL/hlsl/intrinsics/clusterid_invalid_constant.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/intrinsics/clusterid_invalid_constant.hlsl index 60b5e18cbf..2a3b0eab62 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/intrinsics/clusterid_invalid_constant.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/intrinsics/clusterid_invalid_constant.hlsl @@ -10,7 +10,7 @@ struct [raypayload] Payload { }; // CHECK-LABEL: define void @{{.*}}test_cluster_id_invalid{{.*}}( -// CHECK: %[[CID:[0-9]+]] = call i32 @dx.op.clusterID(i32 -2147483645) +// CHECK: %[[CID:[0-9]+]] = call i32 @dx.op.clusterID(i32 314) // CHECK: %[[CMP:[0-9]+]] = icmp eq i32 %[[CID]], -1 // CHECK: br i1 %[[CMP]] // CHECK: call void @dx.op.rawBufferStore.i32(i32 140, %dx.types.Handle %{{[0-9]+}}, i32 0, i32 undef, i32 -1, i32 undef, i32 undef, i32 undef, i8 1, i32 4) diff --git a/tools/clang/test/CodeGenDXIL/hlsl/intrinsics/triangle_positions.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/intrinsics/triangle_positions.hlsl index 431080f956..15a2df6825 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/intrinsics/triangle_positions.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/intrinsics/triangle_positions.hlsl @@ -3,19 +3,19 @@ // RUN: %dxc -T lib_6_10 %s -ast-dump-implicit | FileCheck %s --check-prefix AST // RUN: %dxc -T lib_6_10 %s -fcgl | FileCheck %s --check-prefix FCGL -// AST: `-CXXMethodDecl {{.*}} <> used TriangleObjectPositions 'BuiltInTrianglePositions &()' extern +// AST: `-CXXMethodDecl {{.*}} <> used TriangleObjectPositions 'BuiltInTrianglePositions &() const' extern // AST-NEXT: |-TemplateArgument type 'BuiltInTrianglePositions' // AST-NEXT: |-HLSLIntrinsicAttr {{.*}} <> Implicit "op" "" 400 // AST-NEXT: |-ConstAttr {{.*}} <> Implicit // AST-NEXT: `-AvailabilityAttr {{.*}} <> Implicit 6.10 0 0 "" -// AST: `-CXXMethodDecl {{.*}} <> used CandidateTriangleObjectPositions 'BuiltInTrianglePositions &()' extern +// AST: `-CXXMethodDecl {{.*}} <> used CandidateTriangleObjectPositions 'BuiltInTrianglePositions &() const' extern // AST: |-TemplateArgument type 'BuiltInTrianglePositions' // AST: |-HLSLIntrinsicAttr {{.*}} <> Implicit "op" "" 398 // AST: |-PureAttr {{.*}} <> Implicit // AST: `-AvailabilityAttr {{.*}} <> Implicit 6.10 0 0 "" -// AST `-CXXMethodDecl {{.*}} <> used CommittedTriangleObjectPositions 'BuiltInTrianglePositions &()' extern +// AST `-CXXMethodDecl {{.*}} <> used CommittedTriangleObjectPositions 'BuiltInTrianglePositions &() const' extern // AST |-TemplateArgument type 'BuiltInTrianglePositions' // AST |-HLSLIntrinsicAttr {{.*}} <> Implicit "op" "" 399 // AST |-PureAttr {{.*}} <> Implicit @@ -39,7 +39,7 @@ struct [raypayload] Payload { // Global TriangleObjectPositions - closesthit // CHECK-LABEL: define void {{.*}}ClosestHit -// CHECK: %{{.*}} = call <9 x float> @dx.op.triangleObjectPosition.f32(i32 -2147483641) ; TriangleObjectPosition() +// CHECK: %{{.*}} = call <9 x float> @dx.op.triangleObjectPosition.f32(i32 318) ; TriangleObjectPosition() // FCGL-LABEL: define void {{.*}}ClosestHit // FCGL: call void @"dx.hl.op..void (i32, %struct.BuiltInTrianglePositions*)"(i32 397, %struct.BuiltInTrianglePositions* %{{.*}}) @@ -51,7 +51,7 @@ void ClosestHit(inout Payload payload, in BuiltInTriangleIntersectionAttributes // Global TriangleObjectPositions - anyhit // CHECK-LABEL: define void {{.*}}AnyHit -// CHECK: %{{.*}} = call <9 x float> @dx.op.triangleObjectPosition.f32(i32 -2147483641) ; TriangleObjectPosition() +// CHECK: %{{.*}} = call <9 x float> @dx.op.triangleObjectPosition.f32(i32 318) ; TriangleObjectPosition() // FCGL-LABEL: define void {{.*}}AnyHit // FCGL: call void @"dx.hl.op..void (i32, %struct.BuiltInTrianglePositions*)"(i32 397, %struct.BuiltInTrianglePositions* %{{.*}}) @@ -64,8 +64,8 @@ void AnyHit(inout Payload payload, in BuiltInTriangleIntersectionAttributes attr // RayQuery CandidateTriangleObjectPositions and CommittedTriangleObjectPositions // CHECK-LABEL: define void {{.*}}RayQueryTest -// CHECK: %{{.*}} = call <9 x float> @dx.op.rayQuery_CandidateTriangleObjectPosition.f32(i32 -2147483640, i32 %{{.*}}) ; RayQuery_CandidateTriangleObjectPosition(rayQueryHandle) -// CHECK: %{{.*}} = call <9 x float> @dx.op.rayQuery_CommittedTriangleObjectPosition.f32(i32 -2147483639, i32 %{{.*}}) ; RayQuery_CommittedTriangleObjectPosition(rayQueryHandle) +// CHECK: %{{.*}} = call <9 x float> @dx.op.rayQuery_CandidateTriangleObjectPosition.f32(i32 319, i32 %{{.*}}) ; RayQuery_CandidateTriangleObjectPosition(rayQueryHandle) +// CHECK: %{{.*}} = call <9 x float> @dx.op.rayQuery_CommittedTriangleObjectPosition.f32(i32 320, i32 %{{.*}}) ; RayQuery_CommittedTriangleObjectPosition(rayQueryHandle) // FCGL-LABEL: define void {{.*}}RayQueryTest // FCGL: %{{.*}} = call %struct.BuiltInTrianglePositions* @"dx.hl.op.ro.%struct.BuiltInTrianglePositions* (i32, %{{.*}}"(i32 398, @@ -98,7 +98,7 @@ void RayQueryTest() { // HitObject TriangleObjectPositions // CHECK-LABEL: define void {{.*}}HitObjectTest -// CHECK: %{{.*}} = call <9 x float> @dx.op.hitObject_TriangleObjectPosition.f32(i32 -2147483638, %dx.types.HitObject %{{.*}}) ; HitObject_TriangleObjectPosition(hitObject) +// CHECK: %{{.*}} = call <9 x float> @dx.op.hitObject_TriangleObjectPosition.f32(i32 321, %dx.types.HitObject %{{.*}}) ; HitObject_TriangleObjectPosition(hitObject) // FCGL-LABEL: define void {{.*}}HitObjectTest // FCGL: %{{.*}} = call %struct.BuiltInTrianglePositions* @"dx.hl.op.rn.%struct.BuiltInTrianglePositions* (i32, %dx.types.HitObject*)"(i32 400, %dx.types.HitObject* %{{.*}}) diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/api/matrix-class.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/api/matrix-class.hlsl index dddaff35d9..1920ee84d9 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/api/matrix-class.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/api/matrix-class.hlsl @@ -7,6 +7,7 @@ using namespace dx::linalg; using MatrixATy = Matrix; using MatrixBTy = Matrix; using MatrixAccumTy = Matrix; +using TGMatrixAccumTy = Matrix; using TSMatrixATy = Matrix; using TSMatrixAccumTy = Matrix; @@ -29,43 +30,43 @@ void main(uint ID : SV_GroupID) // Matrix::Splat // // CHECK: %[[MATA1:.*]] = call %dx.types.LinAlgMatrixC9M4N4U0S1 @dx.op.linAlgFillMatrix.mC9M4N4U0S1.f32( -// CHECK-SAME: i32 -2147483636, float 1.000000e+00) +// CHECK-SAME: i32 323, i1 true, float 1.000000e+00) MatrixATy MatA1 = MatrixATy::Splat(1.0f); // CHECK: %[[MATB1:.*]] = call %dx.types.LinAlgMatrixC9M4N4U1S1 @dx.op.linAlgFillMatrix.mC9M4N4U1S1.f32( -// CHECK-SAME: i32 -2147483636, float 2.000000e+00) +// CHECK-SAME: i32 323, i1 true, float 2.000000e+00) MatrixBTy MatB1; MatB1 = MatrixBTy::Splat(2.0f); // Matrix::Cast // // CHECK: %[[MAT48F:.*]] = call %dx.types.LinAlgMatrixC9M4N8U0S1 @dx.op.linAlgFillMatrix.mC9M4N8U0S1.f32( -// CHECK-SAME: i32 -2147483636, float 3.000000e+00) ; LinAlgFillMatrix(value) +// CHECK-SAME: i32 323, i1 true, float 3.000000e+00) ; LinAlgFillMatrix(isInputSigned,value) // CHECK: call %dx.types.LinAlgMatrixC4M4N8U0S1 @dx.op.linAlgCopyConvertMatrix.mC4M4N8U0S1.mC9M4N8U0S1( -// CHECK-SAME: i32 -2147483635, %dx.types.LinAlgMatrixC9M4N8U0S1 %[[MAT48F]], i1 false) +// CHECK-SAME: i32 324, %dx.types.LinAlgMatrixC9M4N8U0S1 %[[MAT48F]], i1 false) // CHECK-SAME: ; LinAlgCopyConvertMatrix(srcMatrix,transpose) Matrix48TyFloat Mat48F = Matrix48TyFloat::Splat(3.0f); Matrix48TyInt Mat48I = Mat48F.Cast(); // CHECK: call %dx.types.LinAlgMatrixC4M8N4U0S1 @dx.op.linAlgCopyConvertMatrix.mC4M8N4U0S1.mC9M4N8U0S1( -// CHECK-SAME: i32 -2147483635, %dx.types.LinAlgMatrixC9M4N8U0S1 %[[MAT48F]], i1 true) +// CHECK-SAME: i32 324, %dx.types.LinAlgMatrixC9M4N8U0S1 %[[MAT48F]], i1 true) // CHECK-SAME: ; LinAlgCopyConvertMatrix(srcMatrix,transpose) Matrix84TyInt Mat84I = Mat48F.Cast(); // Matrix::Load from ByteAddressBuffer // // CHECK: %[[MATA2:.*]] = call %dx.types.LinAlgMatrixC9M4N4U0S1 -// CHECK-SAME: @dx.op.linAlgMatrixLoadFromDescriptor.mC9M4N4U0S1(i32 -2147483634, -// CHECK-SAME: %dx.types.Handle %{{[0-9]+}}, i32 0, i32 16, i32 1, i32 128) +// CHECK-SAME: @dx.op.linAlgMatrixLoadFromDescriptor.mC9M4N4U0S1(i32 325, +// CHECK-SAME: %dx.types.Handle %{{[0-9]+}}, i32 0, i32 16, i32 1, i32 16) // CHECK-SAME: ; LinAlgMatrixLoadFromDescriptor(handle,offset,stride,layout,align) MatrixATy MatA2 = MatrixATy::Load(BAB, 0, 16, MatrixLayoutEnum::ColMajor); // Matrix::Load from RWByteAddressBuffer // // CHECK: %[[MATB2:.*]] = call %dx.types.LinAlgMatrixC9M4N4U1S1 -// CHECK-SAME: @dx.op.linAlgMatrixLoadFromDescriptor.mC9M4N4U1S1(i32 -2147483634, -// CHECK-SAME: %dx.types.Handle %{{[0-9]+}}, i32 256, i32 16, i32 1, i32 128) +// CHECK-SAME: @dx.op.linAlgMatrixLoadFromDescriptor.mC9M4N4U1S1(i32 325, +// CHECK-SAME: %dx.types.Handle %{{[0-9]+}}, i32 256, i32 16, i32 1, i32 16) // CHECK-SAME: ; LinAlgMatrixLoadFromDescriptor(handle,offset,stride,layout,align) MatrixBTy MatB2; MatB2 = MatrixBTy::Load(RWBAB, 256, 16, MatrixLayoutEnum::ColMajor); @@ -73,7 +74,7 @@ void main(uint ID : SV_GroupID) // Matrix::Load from groupshared memory // // CHECK: %[[MATB3:.*]] = call %dx.types.LinAlgMatrixC9M4N4U1S1 -// CHECK-SAME: @dx.op.linAlgMatrixLoadFromMemory.mC9M4N4U1S1.f32(i32 -2147483633, +// CHECK-SAME: @dx.op.linAlgMatrixLoadFromMemory.mC9M4N4U1S1.f32(i32 326, // CHECK-SAME: float addrspace(3)* getelementptr inbounds ([256 x float], // CHECK-SAME: [256 x float] addrspace(3)* @"\01?SharedArr@@3PAMA", i32 0, i32 0), // CHECK-SAME: i32 0, i32 16, i32 1) ; LinAlgMatrixLoadFromMemory(memory,offset,stride,layout) @@ -82,7 +83,7 @@ void main(uint ID : SV_GroupID) // Matrix::Load from packed groupshared memory // // CHECK: %[[MATB4:.*]] = call %dx.types.LinAlgMatrixC9M4N4U1S1 -// CHECK-SAME: @dx.op.linAlgMatrixLoadFromMemory.mC9M4N4U1S1.i32(i32 -2147483633, +// CHECK-SAME: @dx.op.linAlgMatrixLoadFromMemory.mC9M4N4U1S1.i32(i32 326, // CHECK-SAME: i32 addrspace(3)* getelementptr inbounds ([256 x i32], // CHECK-SAME: [256 x i32] addrspace(3)* @"\01?PackedArr@@3PA$ui8_4pk@A", i32 0, i32 0), // CHECK-SAME: i32 0, i32 16, i32 1) ; LinAlgMatrixLoadFromMemory(memory,offset,stride,layout) @@ -90,20 +91,20 @@ void main(uint ID : SV_GroupID) // Matrix::Length // -// CHECK: call i32 @dx.op.linAlgMatrixLength.mC9M4N4U0S1(i32 -2147483632, +// CHECK: call i32 @dx.op.linAlgMatrixLength.mC9M4N4U0S1(i32 327, // CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U0S1 %[[MATA1]]) ; LinAlgMatrixLength uint len = MatA1.Length(); // Matrix::GetCoordinate // -// CHECK: call <2 x i32> @dx.op.linAlgMatrixGetCoordinate.mC9M4N4U1S1(i32 -2147483631, +// CHECK: call <2 x i32> @dx.op.linAlgMatrixGetCoordinate.mC9M4N4U1S1(i32 328, // CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U1S1 %[[MATB1]], i32 %[[GROUP_ID]]) // CHECK-SAME:; LinAlgMatrixGetCoordinate(matrix,threadLocalIndex) uint2 coord = MatB1.GetCoordinate(ID); // Matrix::Get // -// CHECK: %[[VAL:.*]] = call float @dx.op.linAlgMatrixGetElement.f32.mC9M4N4U0S1(i32 -2147483630, +// CHECK: %[[VAL:.*]] = call float @dx.op.linAlgMatrixGetElement.f32.mC9M4N4U0S1(i32 329, // CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U0S1 %[[MATA1]], i32 %[[GROUP_ID]]) // CHECK-SAME:; LinAlgMatrixGetElement(matrix,threadLocalIndex) float val = MatA1.Get(ID); @@ -112,21 +113,21 @@ void main(uint ID : SV_GroupID) // // CHECK: %[[MATB1_2:.*]] = call %dx.types.LinAlgMatrixC9M4N4U1S1 // CHECK-SAME: @dx.op.linAlgMatrixSetElement.mC9M4N4U1S1.mC9M4N4U1S1.f32( -// CHECK-SAME: i32 -2147483629, %dx.types.LinAlgMatrixC9M4N4U1S1 %[[MATB1]], +// CHECK-SAME: i32 330, %dx.types.LinAlgMatrixC9M4N4U1S1 %[[MATB1]], // CHECK-SAME: i32 %[[GROUP_ID]], float %[[VAL]]) ; LinAlgMatrixSetElement(matrix,threadLocalIndex,value) MatB1.Set(ID, val); // Matrix::Store to resource descriptor // -// CHECK: call void @dx.op.linAlgMatrixStoreToDescriptor.mC9M4N4U1S1(i32 -2147483628, +// CHECK: call void @dx.op.linAlgMatrixStoreToDescriptor.mC9M4N4U1S1(i32 331, // CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U1S1 %[[MATB1_2]], %dx.types.Handle %{{[0-9]+}}, -// CHECK-SAME: i32 256, i32 16, i32 1, i32 128) ; +// CHECK-SAME: i32 256, i32 16, i32 1, i32 16) ; // CHECK-SAME: LinAlgMatrixStoreToDescriptor(matrix,handle,offset,stride,layout,align) MatB1.Store(RWBAB, 256, 16, MatrixLayoutEnum::ColMajor); // Matrix::Store to groupshared memory // -// CHECK: call void @dx.op.linAlgMatrixStoreToMemory.mC9M4N4U1S1.f32(i32 -2147483627, +// CHECK: call void @dx.op.linAlgMatrixStoreToMemory.mC9M4N4U1S1.f32(i32 332, // CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U1S1 %[[MATB2]], float addrspace(3)* getelementptr inbounds // CHECK-SAME: ([256 x float], [256 x float] addrspace(3)* @"\01?SharedArr@@3PAMA", i32 0, i32 0), // CHECK-SAME: i32 0, i32 16, i32 1) ; LinAlgMatrixStoreToMemory(matrix,memory,offset,stride,layout) @@ -134,61 +135,67 @@ void main(uint ID : SV_GroupID) // Matrix::Store to packed groupshared memory // -// CHECK: call void @dx.op.linAlgMatrixStoreToMemory.mC9M4N4U1S1.i32(i32 -2147483627, +// CHECK: call void @dx.op.linAlgMatrixStoreToMemory.mC9M4N4U1S1.i32(i32 332, // CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U1S1 %[[MATB4]], i32 addrspace(3)* getelementptr inbounds // CHECK-SAME: ([256 x i32], [256 x i32] addrspace(3)* @"\01?PackedArr@@3PA$ui8_4pk@A", i32 0, i32 0), // CHECK-SAME: i32 0, i32 16, i32 1) ; LinAlgMatrixStoreToMemory(matrix,memory,offset,stride,layout) MatB4.Store(PackedArr, 0, 16, MatrixLayoutEnum::ColMajor); // CHECK: %[[ACCUM0:.*]] = call %dx.types.LinAlgMatrixC9M4N4U2S1 @dx.op.linAlgFillMatrix.mC9M4N4U2S1.f32( -// CHECK-SAME: i32 -2147483636, float 1.400000e+01) ; LinAlgFillMatrix(value) +// CHECK-SAME: i32 323, i1 true, float 1.400000e+01) ; LinAlgFillMatrix(isInputSigned,value) MatrixAccumTy AccMat1 = MatrixAccumTy::Splat(14.0f); // Matrix::InterlockedAccumulate to resource descriptor // -// CHECK: call void @dx.op.linAlgMatrixAccumulateToDescriptor.mC9M4N4U2S1(i32 -2147483621, -// CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U2S1 %[[ACCUM0]], %dx.types.Handle %{{[0-9]+}}, i32 0, i32 16, i32 1, i32 128) +// CHECK: call void @dx.op.linAlgMatrixAccumulateToDescriptor.mC9M4N4U2S1(i32 338, +// CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U2S1 %[[ACCUM0]], %dx.types.Handle %{{[0-9]+}}, i32 0, i32 16, i32 1, i32 16) // CHECK-SAME: ; LinAlgMatrixAccumulateToDescriptor(matrix,handle,offset,stride,layout,align) AccMat1.InterlockedAccumulate(RWBAB, 0, 16, MatrixLayoutEnum::ColMajor); // Matrix::InterlockedAccumulate to groupshared memory // -// CHECK: call void @dx.op.linAlgMatrixAccumulateToMemory.mC9M4N4U2S1.f32(i32 -2147483620, +// CHECK: call void @dx.op.linAlgMatrixAccumulateToMemory.mC9M4N4U2S1.f32(i32 339, // CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U2S1 %[[ACCUM0]], // CHECK-SAME: float addrspace(3)* getelementptr inbounds ([256 x float], -// CHECK-SAME: [256 x float] addrspace(3)* @"\01?SharedArr@@3PAMA", i32 0, i32 0), i32 9, i32 0, i32 16, i32 1) -// CHECK-SAME: ; LinAlgMatrixAccumulateToMemory(matrix,memory,targetType,offset,stride,layout) +// CHECK-SAME: [256 x float] addrspace(3)* @"\01?SharedArr@@3PAMA", i32 0, i32 0), i32 0, i32 16, i32 1) +// CHECK-SAME: ; LinAlgMatrixAccumulateToMemory(matrix,memory,offset,stride,layout) AccMat1.InterlockedAccumulate(SharedArr, 0, 16, MatrixLayoutEnum::ColMajor); // Matrix::InterlockedAccumulate to packed groupshared memory // -// CHECK: call void @dx.op.linAlgMatrixAccumulateToMemory.mC9M4N4U2S1.i32(i32 -2147483620, +// CHECK: call void @dx.op.linAlgMatrixAccumulateToMemory.mC9M4N4U2S1.i32(i32 339, // CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U2S1 %[[ACCUM0]], // CHECK-SAME: i32 addrspace(3)* getelementptr inbounds ([256 x i32], -// CHECK-SAME: [256 x i32] addrspace(3)* @"\01?PackedArr@@3PA$ui8_4pk@A", i32 0, i32 0), i32 9, i32 0, i32 16, i32 1) -// CHECK-SAME: ; LinAlgMatrixAccumulateToMemory(matrix,memory,targetType,offset,stride,layout) +// CHECK-SAME: [256 x i32] addrspace(3)* @"\01?PackedArr@@3PA$ui8_4pk@A", i32 0, i32 0), i32 0, i32 16, i32 1) +// CHECK-SAME: ; LinAlgMatrixAccumulateToMemory(matrix,memory,offset,stride,layout) AccMat1.InterlockedAccumulate(PackedArr, 0, 16, MatrixLayoutEnum::ColMajor); -// CHECK: call void @dx.op.linAlgMatrixAccumulateToMemory.mC9M4N4U2S1.i32(i32 -2147483620, -// CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U2S1 %[[ACCUM0]], -// CHECK-SAME: i32 addrspace(3)* getelementptr inbounds ([256 x i32], -// CHECK-SAME: [256 x i32] addrspace(3)* @"\01?PackedArr@@3PA$ui8_4pk@A", i32 0, i32 0), i32 4, i32 0, i32 16, i32 1) -// CHECK-SAME: ; LinAlgMatrixAccumulateToMemory(matrix,memory,targetType,offset,stride,layout) - AccMat1.InterlockedAccumulate(PackedArr, 0, 16, MatrixLayoutEnum::ColMajor); + +// Matrix::InterlockedAccumulate supports thread-group scope +// +// CHECK: %[[TGACCUM:.*]] = call %dx.types.LinAlgMatrixC9M4N4U2S2 @dx.op.linAlgFillMatrix.mC9M4N4U2S2.f32( +// CHECK-SAME: i32 323, i1 true, float 1.500000e+01) + TGMatrixAccumTy TGAccMat = TGMatrixAccumTy::Splat(15.0f); +// CHECK: call void @dx.op.linAlgMatrixAccumulateToMemory.mC9M4N4U2S2.f32(i32 339, +// CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U2S2 %[[TGACCUM]], +// CHECK-SAME: float addrspace(3)* getelementptr inbounds ([256 x float], +// CHECK-SAME: [256 x float] addrspace(3)* @"\01?SharedArr@@3PAMA", i32 0, i32 0), i32 0, i32 16, i32 1) +// CHECK-SAME: ; LinAlgMatrixAccumulateToMemory(matrix,memory,offset,stride,layout) + TGAccMat.InterlockedAccumulate(SharedArr, 0, 16, MatrixLayoutEnum::ColMajor); // Matrix::Accumulate // // CHECK: %[[ACCUM1:.*]] = call %dx.types.LinAlgMatrixC9M4N4U2S1 @dx.op.linAlgFillMatrix.mC9M4N4U2S1.f32( -// CHECK-SAME: i32 -2147483636, float 0.000000e+00) ; LinAlgFillMatrix(value) +// CHECK-SAME: i32 323, i1 true, float 0.000000e+00) ; LinAlgFillMatrix(isInputSigned,value) MatrixAccumTy AccMat2 = MatrixAccumTy::Splat(0.0f); // CHECK: %[[ACCUM2:.*]] = call %dx.types.LinAlgMatrixC9M4N4U2S1 -// CHECK-SAME: @dx.op.linAlgMatrixAccumulate.mC9M4N4U2S1.mC9M4N4U2S1.mC9M4N4U0S1(i32 -2147483624, +// CHECK-SAME: @dx.op.linAlgMatrixAccumulate.mC9M4N4U2S1.mC9M4N4U2S1.mC9M4N4U0S1(i32 335, // CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U2S1 %[[ACCUM1]], // CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U0S1 %[[MATA2]]) ; LinAlgMatrixAccumulate(matrixLHS,matrixRHS) AccMat2.Accumulate(MatA2); // CHECK: %[[ACCUM3:.*]] = call %dx.types.LinAlgMatrixC9M4N4U2S1 -// CHECK-SAME: @dx.op.linAlgMatrixAccumulate.mC9M4N4U2S1.mC9M4N4U2S1.mC9M4N4U1S1(i32 -2147483624, +// CHECK-SAME: @dx.op.linAlgMatrixAccumulate.mC9M4N4U2S1.mC9M4N4U2S1.mC9M4N4U1S1(i32 335, // CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U2S1 %[[ACCUM2]], // CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U1S1 %[[MATB2]]) // CHECK-SAME: ; LinAlgMatrixAccumulate(matrixLHS,matrixRHS) @@ -197,7 +204,7 @@ void main(uint ID : SV_GroupID) // Matrix::MultiplyAccumulate // // CHECK: %[[ACCUM4:.*]] = call %dx.types.LinAlgMatrixC9M4N4U2S1 -// CHECK-SAME: @dx.op.linAlgMatrixMultiplyAccumulate.mC9M4N4U2S1.mC9M4N4U0S1.mC9M4N4U1S1.mC9M4N4U2S1(i32 -2147483637, +// CHECK-SAME: @dx.op.linAlgMatrixMultiplyAccumulate.mC9M4N4U2S1.mC9M4N4U0S1.mC9M4N4U1S1.mC9M4N4U2S1(i32 322, // CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U0S1 %[[MATA1]], // CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U1S1 %[[MATB1_2]], // CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U2S1 %[[ACCUM3]]) @@ -207,21 +214,21 @@ void main(uint ID : SV_GroupID) // Matrix::Load for thread-scope matrix // // CHECK: %[[TSMATA:.*]] = call %dx.types.LinAlgMatrixC9M4N4U0S0 @dx.op.linAlgMatrixLoadFromDescriptor.mC9M4N4U0S0( -// CHECK-SAME: i32 -2147483634, %dx.types.Handle %{{[0-9]+}}, i32 0, i32 16, i32 1, i32 128) +// CHECK-SAME: i32 325, %dx.types.Handle %{{[0-9]+}}, i32 0, i32 16, i32 1, i32 128) // CHECK-SAME: ; LinAlgMatrixLoadFromDescriptor(handle,offset,stride,layout,align) TSMatrixATy TSMatA = TSMatrixATy::Load(BAB, 0, 16); // Matrix::InterlockedAccumulate for thread-scope matrix // // CHECK: %[[TSACCUM:.*]] = call %dx.types.LinAlgMatrixC9M4N4U2S0 @dx.op.linAlgMatrixOuterProduct.mC9M4N4U2S0.v4f32.v4f32 -// CHECK: call void @dx.op.linAlgMatrixAccumulateToDescriptor.mC9M4N4U2S0(i32 -2147483621, -// CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U2S0 %[[TSACCUM]], %dx.types.Handle %{{[0-9]+}}, i32 0, i32 0, i32 4, i32 0) +// CHECK: call void @dx.op.linAlgMatrixAccumulateToDescriptor.mC9M4N4U2S0(i32 338, +// CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U2S0 %[[TSACCUM]], %dx.types.Handle %{{[0-9]+}}, i32 0, i32 0, i32 4, i32 128) // CHECK-SAME: ; LinAlgMatrixAccumulateToDescriptor(matrix,handle,offset,stride,layout,align) vector vec1 = 1.0f; vector vec2 = 2.0f; TSMatrixAccumTy TSMatAccum = OuterProduct(vec1, vec2); TSMatAccum.InterlockedAccumulate(RWBAB, 0); -// CHECK: call i32 @dx.op.linAlgMatrixQueryAccumulatorLayout(i32 -2147483626) ; LinAlgMatrixQueryAccumulatorLayout() +// CHECK: call i32 @dx.op.linAlgMatrixQueryAccumulatorLayout(i32 333) ; LinAlgMatrixQueryAccumulatorLayout() MatrixUseEnum layout = AccumulatorLayout(); } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/api/matrix-groupshared-vector-array.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/api/matrix-groupshared-vector-array.hlsl new file mode 100644 index 0000000000..131c895be3 --- /dev/null +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/api/matrix-groupshared-vector-array.hlsl @@ -0,0 +1,80 @@ +// REQUIRES: dxil-1-10 +// RUN: %dxc -T cs_6_10 %s | FileCheck %s + +// dx::linalg::Matrix's groupshared memory methods accept arrays of vectors of +// the matrix component type, in addition to arrays of scalars. The DXIL +// operations are overloaded on the array element type, so the memory operand +// is a pointer to a vector. + +#include +using namespace dx::linalg; + +using MatrixBTy = Matrix; +using MatrixAccumTy = Matrix; + +// CHECK: @"\01?SharedVecArr@@3PAV?$vector@M$03@@A" = external addrspace(3) global [64 x <4 x float>] +groupshared float4 SharedVecArr[64]; +// CHECK: @"\01?PackedVecArr@@3PAV?$vector@$ui8_4pk@$01@@A" = external addrspace(3) global [64 x <2 x i32>] +groupshared vector PackedVecArr[64]; + +[numthreads(4, 4, 4)] +void main() { + +// Matrix::Load from an array of vectors +// +// CHECK: %[[MATB:.*]] = call %dx.types.LinAlgMatrixC9M4N4U1S1 +// CHECK-SAME: @dx.op.linAlgMatrixLoadFromMemory.mC9M4N4U1S1.v4f32(i32 326, +// CHECK-SAME: <4 x float> addrspace(3)* getelementptr inbounds ([64 x <4 x float>], +// CHECK-SAME: [64 x <4 x float>] addrspace(3)* @"\01?SharedVecArr@@3PAV?$vector@M$03@@A", i32 0, i32 0), +// CHECK-SAME: i32 0, i32 16, i32 1) ; LinAlgMatrixLoadFromMemory(memory,offset,stride,layout) + MatrixBTy MatB = MatrixBTy::Load(SharedVecArr, 0, 16, MatrixLayoutEnum::ColMajor); + +// Matrix::Store to an array of vectors +// +// CHECK: call void @dx.op.linAlgMatrixStoreToMemory.mC9M4N4U1S1.v4f32(i32 332, +// CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U1S1 %[[MATB]], +// CHECK-SAME: <4 x float> addrspace(3)* getelementptr inbounds ([64 x <4 x float>], +// CHECK-SAME: [64 x <4 x float>] addrspace(3)* @"\01?SharedVecArr@@3PAV?$vector@M$03@@A", i32 0, i32 0), +// CHECK-SAME: i32 0, i32 16, i32 1) ; LinAlgMatrixStoreToMemory(matrix,memory,offset,stride,layout) + MatB.Store(SharedVecArr, 0, 16, MatrixLayoutEnum::ColMajor); + +// Matrix::Load from an array of packed vectors +// +// CHECK: %[[MATP:.*]] = call %dx.types.LinAlgMatrixC9M4N4U1S1 +// CHECK-SAME: @dx.op.linAlgMatrixLoadFromMemory.mC9M4N4U1S1.v2i32(i32 326, +// CHECK-SAME: <2 x i32> addrspace(3)* getelementptr inbounds ([64 x <2 x i32>], +// CHECK-SAME: [64 x <2 x i32>] addrspace(3)* @"\01?PackedVecArr@@3PAV?$vector@$ui8_4pk@$01@@A", i32 0, i32 0), +// CHECK-SAME: i32 0, i32 16, i32 1) ; LinAlgMatrixLoadFromMemory(memory,offset,stride,layout) + MatrixBTy MatP = MatrixBTy::Load(PackedVecArr, 0, 16, MatrixLayoutEnum::ColMajor); + +// Matrix::Store to an array of packed vectors +// +// CHECK: call void @dx.op.linAlgMatrixStoreToMemory.mC9M4N4U1S1.v2i32(i32 332, +// CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U1S1 %[[MATP]], +// CHECK-SAME: <2 x i32> addrspace(3)* getelementptr inbounds ([64 x <2 x i32>], +// CHECK-SAME: [64 x <2 x i32>] addrspace(3)* @"\01?PackedVecArr@@3PAV?$vector@$ui8_4pk@$01@@A", i32 0, i32 0), +// CHECK-SAME: i32 0, i32 16, i32 1) ; LinAlgMatrixStoreToMemory(matrix,memory,offset,stride,layout) + MatP.Store(PackedVecArr, 0, 16, MatrixLayoutEnum::ColMajor); + + MatrixAccumTy Acc = MatrixAccumTy::Splat(0); + +// Matrix::InterlockedAccumulate to an array of vectors +// +// CHECK: call void @dx.op.linAlgMatrixAccumulateToMemory.mC9M4N4U2S1.v4f32(i32 339, +// CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U2S1 %[[ACC:[0-9]+]], +// CHECK-SAME: <4 x float> addrspace(3)* getelementptr inbounds ([64 x <4 x float>], +// CHECK-SAME: [64 x <4 x float>] addrspace(3)* @"\01?SharedVecArr@@3PAV?$vector@M$03@@A", i32 0, i32 0), +// CHECK-SAME: i32 0, i32 16, i32 1) +// CHECK-SAME: ; LinAlgMatrixAccumulateToMemory(matrix,memory,offset,stride,layout) + Acc.InterlockedAccumulate(SharedVecArr, 0, 16, MatrixLayoutEnum::ColMajor); + +// Matrix::InterlockedAccumulate to an array of packed vectors +// +// CHECK: call void @dx.op.linAlgMatrixAccumulateToMemory.mC9M4N4U2S1.v2i32(i32 339, +// CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U2S1 %[[ACC]], +// CHECK-SAME: <2 x i32> addrspace(3)* getelementptr inbounds ([64 x <2 x i32>], +// CHECK-SAME: [64 x <2 x i32>] addrspace(3)* @"\01?PackedVecArr@@3PAV?$vector@$ui8_4pk@$01@@A", i32 0, i32 0), +// CHECK-SAME: i32 0, i32 16, i32 1) +// CHECK-SAME: ; LinAlgMatrixAccumulateToMemory(matrix,memory,offset,stride,layout) + Acc.InterlockedAccumulate(PackedVecArr, 0, 16, MatrixLayoutEnum::ColMajor); +} diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/api/matrix-multiply.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/api/matrix-multiply.hlsl index ab2da55138..d989f2cd29 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/api/matrix-multiply.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/api/matrix-multiply.hlsl @@ -11,31 +11,36 @@ void main() // using MatrixAF16WTy = Matrix; using MatrixAI32WTy = Matrix; + using MatrixAU32WTy = Matrix; using MatrixBI32WTy = Matrix; using MatrixAccF32WTy = Matrix; using MatrixAccI32WTy = Matrix; // CHECK: %[[MATA1:.*]] = call %dx.types.LinAlgMatrixC8M3N4U0S1 @dx.op.linAlgFillMatrix.mC8M3N4U0S1.f32( -// CHECK-SAME: i32 -2147483636, float 1.500000e+00) ; LinAlgFillMatrix(value) +// CHECK-SAME: i32 323, i1 true, float 1.500000e+00) ; LinAlgFillMatrix(isInputSigned,value) MatrixAF16WTy MatA1 = MatrixAF16WTy::Splat(1.5f); // CHECK: %[[MATA2:.*]] = call %dx.types.LinAlgMatrixC4M3N4U0S1 @dx.op.linAlgFillMatrix.mC4M3N4U0S1.i32( -// CHECK-SAME: i32 -2147483636, i32 45) ; LinAlgFillMatrix(value) +// CHECK-SAME: i32 323, i1 true, i32 45) ; LinAlgFillMatrix(isInputSigned,value) MatrixAI32WTy MatA2 = MatrixAI32WTy::Splat(45); +// CHECK: call %dx.types.LinAlgMatrixC5M3N4U0S1 @dx.op.linAlgFillMatrix.mC5M3N4U0S1.i32( +// CHECK-SAME: i32 323, i1 false, i32 45) ; LinAlgFillMatrix(isInputSigned,value) + MatrixAU32WTy MatAU32 = MatrixAU32WTy::Splat(45u); + // CHECK: %[[MATB1:.*]] = call %dx.types.LinAlgMatrixC4M4N5U1S1 @dx.op.linAlgFillMatrix.mC4M4N5U1S1.i32( -// CHECK-SAME: i32 -2147483636, i32 13) ; LinAlgFillMatrix(value) +// CHECK-SAME: i32 323, i1 true, i32 13) ; LinAlgFillMatrix(isInputSigned,value) MatrixBI32WTy MatB1 = MatrixBI32WTy::Splat(13); // CHECK: %[[MATC1:.*]] = call %dx.types.LinAlgMatrixC9M3N5U2S1 -// CHECK-SAME: @dx.op.linAlgMatrixMultiply.mC9M3N5U2S1.mC8M3N4U0S1.mC4M4N5U1S1(i32 -2147483625, +// CHECK-SAME: @dx.op.linAlgMatrixMultiply.mC9M3N5U2S1.mC8M3N4U0S1.mC4M4N5U1S1(i32 334, // CHECK-SAME: %dx.types.LinAlgMatrixC8M3N4U0S1 %[[MATA1]], %dx.types.LinAlgMatrixC4M4N5U1S1 %[[MATB1]]) // CHECK-SAME: ; LinAlgMatrixMultiply(matrixA,matrixB) MatrixAccF32WTy MatCFlt1 = Multiply(MatA1, MatB1); // CHECK: %[[MATC2:.*]] = call %dx.types.LinAlgMatrixC4M3N5U2S1 -// CHECK-SAME: @dx.op.linAlgMatrixMultiply.mC4M3N5U2S1.mC4M3N4U0S1.mC4M4N5U1S1(i32 -2147483625, -// CHECK-SAME: %dx.types.LinAlgMatrixC4M3N4U0S1 %2, %dx.types.LinAlgMatrixC4M4N5U1S1 %3) +// CHECK-SAME: @dx.op.linAlgMatrixMultiply.mC4M3N5U2S1.mC4M3N4U0S1.mC4M4N5U1S1(i32 334, +// CHECK-SAME: %dx.types.LinAlgMatrixC4M3N4U0S1 %[[MATA2]], %dx.types.LinAlgMatrixC4M4N5U1S1 %[[MATB1]]) // CHECK-SAME: ; LinAlgMatrixMultiply(matrixA,matrixB) MatrixAccI32WTy MatCInt1 = Multiply(MatA2, MatB1); @@ -48,25 +53,25 @@ void main() using MatrixAccI32TGTy = Matrix; // CHECK: %[[MATA3:.*]] = call %dx.types.LinAlgMatrixC8M3N4U0S2 @dx.op.linAlgFillMatrix.mC8M3N4U0S2.f32( -// CHECK-SAME: i32 -2147483636, float 2.500000e+00) ; LinAlgFillMatrix(value) +// CHECK-SAME: i32 323, i1 true, float 2.500000e+00) ; LinAlgFillMatrix(isInputSigned,value) MatrixAF16TGTy MatA3 = MatrixAF16TGTy::Splat(2.5f); // CHECK: %[[MATA4:.*]] = call %dx.types.LinAlgMatrixC4M3N4U0S2 @dx.op.linAlgFillMatrix.mC4M3N4U0S2.i32( -// CHECK-SAME: i32 -2147483636, i32 23) ; LinAlgFillMatrix(value) +// CHECK-SAME: i32 323, i1 true, i32 23) ; LinAlgFillMatrix(isInputSigned,value) MatrixAI32TGTy MatA4 = MatrixAI32TGTy::Splat(23); // CHECK: %[[MATB3:.*]] = call %dx.types.LinAlgMatrixC4M4N5U1S2 @dx.op.linAlgFillMatrix.mC4M4N5U1S2.i32( -// CHECK-SAME: i32 -2147483636, i32 7) ; LinAlgFillMatrix(value) +// CHECK-SAME: i32 323, i1 true, i32 7) ; LinAlgFillMatrix(isInputSigned,value) MatrixBI32TGTy MatB3 = MatrixBI32TGTy::Splat(7); // CHECK: %[[MATC3:.*]] = call %dx.types.LinAlgMatrixC9M3N5U2S2 -// CHECK-SAME: @dx.op.linAlgMatrixMultiply.mC9M3N5U2S2.mC8M3N4U0S2.mC4M4N5U1S2(i32 -2147483625, +// CHECK-SAME: @dx.op.linAlgMatrixMultiply.mC9M3N5U2S2.mC8M3N4U0S2.mC4M4N5U1S2(i32 334, // CHECK-SAME: %dx.types.LinAlgMatrixC8M3N4U0S2 %[[MATA3]], %dx.types.LinAlgMatrixC4M4N5U1S2 %[[MATB3]]) // CHECK-SAME: ; LinAlgMatrixMultiply(matrixA,matrixB) MatrixAccF32TGTy MatCFlt2 = Multiply(MatA3, MatB3); // CHECK: %[[MATC4:.*]] = call %dx.types.LinAlgMatrixC4M3N5U2S2 -// CHECK-SAME: @dx.op.linAlgMatrixMultiply.mC4M3N5U2S2.mC4M3N4U0S2.mC4M4N5U1S2(i32 -2147483625, +// CHECK-SAME: @dx.op.linAlgMatrixMultiply.mC4M3N5U2S2.mC4M3N4U0S2.mC4M4N5U1S2(i32 334, // CHECK-SAME: %dx.types.LinAlgMatrixC4M3N4U0S2 %[[MATA4]], %dx.types.LinAlgMatrixC4M4N5U1S2 %[[MATB3]]) // CHECK-SAME: ; LinAlgMatrixMultiply(matrixA,matrixB) MatrixAccI32TGTy MatCInt2 = Multiply(MatA4, MatB3); diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/api/matrix-vector-multiply-input-type.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/api/matrix-vector-multiply-input-type.hlsl new file mode 100644 index 0000000000..6d2890d358 --- /dev/null +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/api/matrix-vector-multiply-input-type.hlsl @@ -0,0 +1,24 @@ +// REQUIRES: dxil-1-10 +// RUN: %dxc -enable-16bit-types -T cs_6_10 %s | FileCheck %s + +#include +using namespace dx::linalg; + +using MatrixATy = + Matrix; + +ByteAddressBuffer Input : register(t0); +RWStructuredBuffer > Output : register(u0); + +[numthreads(1, 1, 1)] +void main(uint Index : SV_GroupIndex) { + MatrixATy Mat = + MatrixATy::Load(Input, 0, 8); + vector Vec = 10.3h; + + // CHECK: call <4 x half> @dx.op.linAlgMatVecMul.v4f16.mC21M4N8U0S0.v8f16( + // CHECK-SAME: i1 true, <8 x half> + // CHECK-SAME: i32 8) + Output[Index] = Multiply(Mat, Vec); +} diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/api/vectors.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/api/vectors.hlsl index 86f109d651..ea17809106 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/api/vectors.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/api/vectors.hlsl @@ -7,8 +7,10 @@ using namespace dx::linalg; using MatrixATy = Matrix; using MatrixAccum_8_8_Ty = Matrix; using MatrixAccum_8_4_Ty = Matrix; +using MatrixAccum_U32_4_4_Ty = Matrix; using Matrix_7_15_ATy = Matrix; using MatrixPacked_7_15_ATy = Matrix; +using MatrixA_BFloat = Matrix; RWByteAddressBuffer RWBAB : register(u0); ByteAddressBuffer BAB : register(t0); @@ -17,13 +19,13 @@ ByteAddressBuffer BAB : register(t0); void main(uint ID : SV_GroupID) { // CHECK: %[[MAT1:.*]] = call %dx.types.LinAlgMatrixC8M8N4U0S0 @dx.op.linAlgMatrixLoadFromDescriptor.mC8M8N4U0S0( - // CHECK-SAME: i32 -2147483634, %dx.types.Handle %{{[0-9]+}}, i32 0, i32 8, i32 1, i32 128) + // CHECK-SAME: i32 325, %dx.types.Handle %{{[0-9]+}}, i32 0, i32 8, i32 1, i32 128) // CHECK-SAME: ; LinAlgMatrixLoadFromDescriptor(handle,offset,stride,layout,align) MatrixATy Mat1 = MatrixATy::Load(BAB, 0, 8); vector vec1 = 10.3f; - // CHECK: %[[VEC2:.*]] = call <8 x half> @dx.op.linAlgMatVecMul.v8f16.mC8M8N4U0S0.v4f16(i32 -2147483623, + // CHECK: %[[VEC2:.*]] = call <8 x half> @dx.op.linAlgMatVecMul.v8f16.mC8M8N4U0S0.v4f16(i32 336, // CHECK-SAME: %dx.types.LinAlgMatrixC8M8N4U0S0 %[[MAT1]], i1 true, <4 x half> , i32 8) ; LinAlgMatVecMul(matrix,isOutputSigned,inputVector,interpretation) vector vec2 = Multiply(Mat1, vec1); @@ -31,19 +33,19 @@ void main(uint ID : SV_GroupID) { // CHECK: %[[VEC20:.*]] = shufflevector vector vec20 = (vector)vec2; - // CHECK: %[[VEC29:.*]] = call <8 x half> @dx.op.linAlgMatVecMul.v8f16.mC8M8N4U0S0.v4f16(i32 -2147483623, + // CHECK: %[[VEC29:.*]] = call <8 x half> @dx.op.linAlgMatVecMul.v8f16.mC8M8N4U0S0.v4f16(i32 336, // CHECK-SAME: %dx.types.LinAlgMatrixC8M8N4U0S0 %[[MAT1]], i1 true, <4 x half> %[[VEC20]], i32 8) // CHECK-SAME: ; LinAlgMatVecMul(matrix,isOutputSigned,inputVector,interpretation) InterpretedVector interpVec0 = MakeInterpretedVector(vec20); vector vec29 = Multiply(Mat1, interpVec0); - // CHECK: %[[VEC3:.*]] = call <8 x half> @dx.op.linAlgMatVecMulAdd.v8f16.mC8M8N4U0S0.v4f16.v8f16(i32 -2147483622, + // CHECK: %[[VEC3:.*]] = call <8 x half> @dx.op.linAlgMatVecMulAdd.v8f16.mC8M8N4U0S0.v4f16.v8f16(i32 337, // CHECK-SAME: %dx.types.LinAlgMatrixC8M8N4U0S0 %[[MAT1]], i1 true, <4 x half> , i32 8, <8 x half> %[[VEC29]]) // CHECK-SAME: ; LinAlgMatVecMulAdd(matrix,isOutputSigned,inputVector,inputInterpretation,biasVector) vector vec3 = MultiplyAdd(Mat1, vec1, vec29); - // CHECK: %[[VEC4:.*]] = call <8 x half> @dx.op.linAlgMatVecMulAdd.v8f16.mC8M8N4U0S0.v4f16.v8f16(i32 -2147483622, + // CHECK: %[[VEC4:.*]] = call <8 x half> @dx.op.linAlgMatVecMulAdd.v8f16.mC8M8N4U0S0.v4f16.v8f16(i32 337, // CHECK-SAME: %dx.types.LinAlgMatrixC8M8N4U0S0 %[[MAT1]], i1 true, <4 x half> %[[VEC20]], i32 8, <8 x half> %[[VEC3]]) // CHECK-SAME: ; LinAlgMatVecMulAdd(matrix,isOutputSigned,inputVector,inputInterpretation,biasVector) InterpretedVector interpVec2 = MakeInterpretedVector(vec20); @@ -54,9 +56,9 @@ void main(uint ID : SV_GroupID) { // CHECK: %[[VEC_BIAS:.*]] = extractvalue %dx.types.ResRet.v8i16 %[[RAWLOAD]], 0 - // CHECK: %[[BIAS_CONV:.*]] = call <8 x half> @dx.op.linAlgConvert.v8f16.v8i16(i32 -2147483618, <8 x i16> %[[VEC_BIAS]], i32 2, i32 8) + // CHECK: %[[BIAS_CONV:.*]] = call <8 x half> @dx.op.linAlgConvert.v8f16.v8i16(i32 341, <8 x i16> %[[VEC_BIAS]], i32 2, i32 8) // CHECK-SAME: ; LinAlgConvert(inputVector,inputInterpretation,outputInterpretation) - // CHECK: %[[VEC5:.*]] = call <8 x half> @dx.op.linAlgMatVecMulAdd.v8f16.mC8M8N4U0S0.v4f16.v8f16(i32 -2147483622, + // CHECK: %[[VEC5:.*]] = call <8 x half> @dx.op.linAlgMatVecMulAdd.v8f16.mC8M8N4U0S0.v4f16.v8f16(i32 337, // CHECK-SAME: %dx.types.LinAlgMatrixC8M8N4U0S0 %[[MAT1]], i1 true, <4 x half> %[[VEC20]], i32 8, <8 x half> %[[BIAS_CONV]]) // CHECK-SAME:; LinAlgMatVecMulAdd(matrix,isOutputSigned,inputVector,inputInterpretation,biasVector) VectorRef memBias = {BAB, 4096}; @@ -68,34 +70,41 @@ void main(uint ID : SV_GroupID) { // CHECK: %[[VEC_BIAS:.*]] = extractvalue %dx.types.ResRet.v8i16 %[[RAWLOAD]], 0 - // CHECK: %[[BIAS_CONV:.*]] = call <8 x half> @dx.op.linAlgConvert.v8f16.v8i16(i32 -2147483618, <8 x i16> %[[VEC_BIAS]], i32 2, i32 8) + // CHECK: %[[BIAS_CONV:.*]] = call <8 x half> @dx.op.linAlgConvert.v8f16.v8i16(i32 341, <8 x i16> %[[VEC_BIAS]], i32 2, i32 8) // CHECK-SAME: ; LinAlgConvert(inputVector,inputInterpretation,outputInterpretation) - // CHECK: %[[VEC6:.*]] = call <8 x half> @dx.op.linAlgMatVecMulAdd.v8f16.mC8M8N4U0S0.v4f16.v8f16(i32 -2147483622, + // CHECK: %[[VEC6:.*]] = call <8 x half> @dx.op.linAlgMatVecMulAdd.v8f16.mC8M8N4U0S0.v4f16.v8f16(i32 337, // CHECK-SAME: %dx.types.LinAlgMatrixC8M8N4U0S0 %[[MAT1]], i1 true, <4 x half> %[[VEC20]], i32 8, <8 x half> %[[BIAS_CONV]]) // CHECK-SAME: ; LinAlgMatVecMulAdd(matrix,isOutputSigned,inputVector,inputInterpretation,biasVector) vector vec6 = MultiplyAdd(Mat1, interpVec2, memBias); // CHECK: %[[ACCUM1:.*]] = call %dx.types.LinAlgMatrixC8M8N8U2S0 - // CHECK-SAME: @dx.op.linAlgMatrixOuterProduct.mC8M8N8U2S0.v8f16.v8f16(i32 -2147483619, - // CHECK-SAME: <8 x half> %[[VEC5]], <8 x half> %[[VEC6]]) ; LinAlgMatrixOuterProduct(vectorA,vectorB) + // CHECK-SAME: @dx.op.linAlgMatrixOuterProduct.mC8M8N8U2S0.v8f16.v8f16(i32 340, + // CHECK-SAME: i1 true, <8 x half> %[[VEC5]], <8 x half> %[[VEC6]]) ; LinAlgMatrixOuterProduct(isInputSigned,vectorA,vectorB) MatrixAccum_8_8_Ty AccumMatrix1 = OuterProduct(vec5, vec6); // CHECK: %[[ACCUM2:.*]] = call %dx.types.LinAlgMatrixC8M8N4U2S0 @dx.op.linAlgMatrixOuterProduct.mC8M8N4U2S0.v8f16.v4f16( - // CHECK-SAME: i32 -2147483619, <8 x half> %[[VEC5]], <4 x half> %[[VEC20]]) ; LinAlgMatrixOuterProduct(vectorA,vectorB) + // CHECK-SAME: i32 340, i1 true, <8 x half> %[[VEC5]], <4 x half> %[[VEC20]]) ; LinAlgMatrixOuterProduct(isInputSigned,vectorA,vectorB) MatrixAccum_8_4_Ty AccumMatrix2 = OuterProduct(vec5, vec20); - // CHECK: %[[CONV_VEC:.*]] = call <8 x float> @dx.op.linAlgConvert.v8f32.v8f16(i32 -2147483618, + uint4 unsignedVec = {1, 2, 3, 4}; + // CHECK: call %dx.types.LinAlgMatrixC5M4N4U2S0 @dx.op.linAlgMatrixOuterProduct.mC5M4N4U2S0.v4i32.v4i32( + // CHECK-SAME: i32 340, i1 false, <4 x i32> , <4 x i32> ) + // CHECK-SAME: ; LinAlgMatrixOuterProduct(isInputSigned,vectorA,vectorB) + MatrixAccum_U32_4_4_Ty UnsignedAccum = + OuterProduct(unsignedVec, unsignedVec); + + // CHECK: %[[CONV_VEC:.*]] = call <8 x float> @dx.op.linAlgConvert.v8f32.v8f16(i32 341, // CHECK-SAME: <8 x half> %[[VEC6]], i32 8, i32 9) ; LinAlgConvert(inputVector,inputInterpretation,outputInterpretation) InterpretedVector convertedVec; convertedVec = Convert(vec6); - // CHECK: call <4 x i32> @dx.op.linAlgConvert.v4i32.v16f16(i32 -2147483618, <16 x half> %{{[0-9]+}}, i32 8, i32 21) + // CHECK: call <4 x i32> @dx.op.linAlgConvert.v4i32.v16f16(i32 341, <16 x half> %{{[0-9]+}}, i32 8, i32 21) // CHECK: ; LinAlgConvert(inputVector,inputInterpretation,outputInterpretation) typedef vector half16; half16 srcF16 = BAB.Load(128); InterpretedVector convertedPacked = Convert(srcF16); - // CHECK: call <1 x i32> @dx.op.linAlgConvert.v1i32.v3f16(i32 -2147483618, <3 x half> %{{[0-9]+}}, i32 8, i32 21) + // CHECK: call <1 x i32> @dx.op.linAlgConvert.v1i32.v3f16(i32 341, <3 x half> %{{[0-9]+}}, i32 8, i32 21) // CHECK-SAME: ; LinAlgConvert(inputVector,inputInterpretation,outputInterpretation) half3 ThreeF16 = BAB.Load(256); InterpretedVector convertedPacked2 = @@ -107,16 +116,20 @@ void main(uint ID : SV_GroupID) { InterpretedVector interpVecH15 = MakeInterpretedVector(vecH15); - // CHECK: %[[MAT_7_15:.*]] = call %dx.types.LinAlgMatrixC8M7N15U0S0 @dx.op.linAlgMatrixLoadFromDescriptor.mC8M7N15U0S0(i32 -2147483634, + // CHECK: %[[MAT_7_15:.*]] = call %dx.types.LinAlgMatrixC8M7N15U0S0 @dx.op.linAlgMatrixLoadFromDescriptor.mC8M7N15U0S0(i32 325, // CHECK-SAME: %dx.types.Handle %{{[0-9]+}}, i32 0, i32 16, i32 1, i32 128) ; LinAlgMatrixLoadFromDescriptor(handle,offset,stride,layout,align) Matrix_7_15_ATy Mat_7_15 = Matrix_7_15_ATy::Load(BAB, 0, 16); - // CHECK: call <7 x half> @dx.op.linAlgMatVecMulAdd.v7f16.mC8M7N15U0S0.v15f16.v7f16(i32 -2147483622, + // CHECK: %[[MATBF:.*]] = call %dx.types.LinAlgMatrixC23M8N4U0S0 @dx.op.linAlgMatrixLoadFromDescriptor.mC23M8N4U0S0(i32 325, + // CHECK-SAME: %dx.types.Handle %{{[0-9]+}}, i32 0, i32 16, i32 1, i32 128) ; LinAlgMatrixLoadFromDescriptor(handle,offset,stride,layout,align) + MatrixA_BFloat MatBF = MatrixA_BFloat::Load(BAB, 0, 16); + + // CHECK: call <7 x half> @dx.op.linAlgMatVecMulAdd.v7f16.mC8M7N15U0S0.v15f16.v7f16(i32 337, // CHECK-SAME: %dx.types.LinAlgMatrixC8M7N15U0S0 %[[MAT_7_15]], i1 true, <15 x half> %{{[0-9]+}}, i32 8, <7 x half> %{{[0-9]+}}) // CHECK-SAME: ; LinAlgMatVecMulAdd(matrix,isOutputSigned,inputVector,inputInterpretation,biasVector) vector vec7 = MultiplyAdd(Mat_7_15, vecH15, vecH7); - // CHECK: call <7 x half> @dx.op.linAlgMatVecMulAdd.v7f16.mC8M7N15U0S0.v15f16.v7f16(i32 -2147483622, %dx.types.LinAlgMatrixC8M7N15U0S0 %[[MAT_7_15]], + // CHECK: call <7 x half> @dx.op.linAlgMatVecMulAdd.v7f16.mC8M7N15U0S0.v15f16.v7f16(i32 337, %dx.types.LinAlgMatrixC8M7N15U0S0 %[[MAT_7_15]], // CHECK-SAME; i1 true, <15 x half> %{{[0-9]+}}, i32 8, <7 x half> %{{[0-9]+}}) // CHECK-SAME: ; LinAlgMatVecMulAdd(matrix,isOutputSigned,inputVector,inputInterpretation,biasVector) vector vec8 = MultiplyAdd(Mat_7_15, interpVecH15, vecH7); @@ -124,7 +137,7 @@ void main(uint ID : SV_GroupID) { // CHECK: %[[LOAD1:.*]] = call %dx.types.ResRet.v7f16 @dx.op.rawBufferVectorLoad.v7f16(i32 303, %dx.types.Handle %{{[0-9]+}}, i32 512, i32 undef, i32 2) // CHECK-SAME: ; RawBufferVectorLoad(buf,index,elementOffset,alignment) // CHECK-NEXT: %[[MEM_BIAS1:.*]] = extractvalue %dx.types.ResRet.v7f16 %[[LOAD1]], 0 - // CHECK-NEXT: call <7 x half> @dx.op.linAlgMatVecMulAdd.v7f16.mC8M7N15U0S0.v15f16.v7f16(i32 -2147483622, + // CHECK-NEXT: call <7 x half> @dx.op.linAlgMatVecMulAdd.v7f16.mC8M7N15U0S0.v15f16.v7f16(i32 337, // CHECK-SAME: %dx.types.LinAlgMatrixC8M7N15U0S0 %[[MAT_7_15]], i1 true, <15 x half> %{{[0-9]+}}, i32 8, <7 x half> %{{[0-9]+}}) // CHECK-SAME: ; LinAlgMatVecMulAdd(matrix,isOutputSigned,inputVector,inputInterpretation,biasVector) VectorRef memBias7 = {BAB, 512}; @@ -139,11 +152,11 @@ void main(uint ID : SV_GroupID) { // Test MultiplyAdd with packed input vector // - // CHECK: %[[INTERP_VEC_H15_PACKED:.*]] = call <4 x i32> @dx.op.linAlgConvert.v4i32.v15f16(i32 -2147483618, + // CHECK: %[[INTERP_VEC_H15_PACKED:.*]] = call <4 x i32> @dx.op.linAlgConvert.v4i32.v15f16(i32 341, // CHECK-SAME: <15 x half> %{{[0-9]+}}, i32 8, i32 21) ; LinAlgConvert(inputVector,inputInterpretation,outputInterpretation) InterpretedVector interpVecH15Packed = Convert(vecH15); - // CHECK: call <7 x half> @dx.op.linAlgMatVecMulAdd.v7f16.mC8M7N15U0S0.v4i32.v7f16(i32 -2147483622, + // CHECK: call <7 x half> @dx.op.linAlgMatVecMulAdd.v7f16.mC8M7N15U0S0.v4i32.v7f16(i32 337, // CHECK-SAME: %dx.types.LinAlgMatrixC8M7N15U0S0 %[[MAT_7_15]], i1 true, <4 x i32> %{{[0-9]+}}, i32 21, <7 x half> %{{[0-9]+}}) // CHECK-SAME: ; LinAlgMatVecMulAdd(matrix,isOutputSigned,inputVector,inputInterpretation,biasVector) vector vec11 = MultiplyAdd(Mat_7_15, interpVecH15Packed, vecH7); @@ -151,24 +164,31 @@ void main(uint ID : SV_GroupID) { // CHECK: %[[LOAD3:.+]] = call %dx.types.ResRet.v7f16 @dx.op.rawBufferVectorLoad.v7f16(i32 303, %dx.types.Handle %{{[0-9]+}}, i32 512, i32 undef, i32 2) // CHECK-SAME: ; RawBufferVectorLoad(buf,index,elementOffset,alignment) // CHECK-NEXT: %[[MEM_BIAS3:.*]] = extractvalue %dx.types.ResRet.v7f16 %{{[0-9]+}}, 0 - // CHECK-NEXT: call <7 x half> @dx.op.linAlgMatVecMulAdd.v7f16.mC8M7N15U0S0.v4i32.v7f16(i32 -2147483622, + // CHECK-NEXT: call <7 x half> @dx.op.linAlgMatVecMulAdd.v7f16.mC8M7N15U0S0.v4i32.v7f16(i32 337, // CHECK-SAME: %dx.types.LinAlgMatrixC8M7N15U0S0 %[[MAT_7_15]], i1 true, <4 x i32> %[[INTERP_VEC_H15_PACKED]], i32 21, <7 x half> %[[MEM_BIAS3]]) // CHECK-SAME: ; LinAlgMatVecMulAdd(matrix,isOutputSigned,inputVector,inputInterpretation,biasVector) - vector vec12 = MultiplyAdd(Mat_7_15, interpVecH15Packed, memBias7); + vector vec12 = MultiplyAdd(Mat_7_15, interpVecH15Packed, memBias7); + + // CHECK: call <8 x half> @dx.op.linAlgMatVecMul.v8f16.mC23M8N4U0S0.v2i32(i32 336, + // CHECK-SAME: %dx.types.LinAlgMatrixC23M8N4U0S0 %[[MATBF]], i1 true, <2 x i32> , i32 23) + // CHECK-SAME: ; LinAlgMatVecMul(matrix,isOutputSigned,inputVector,interpretation) + vector vecBfloatBin = 12345; + InterpretedVector vecBfloat = MakeInterpretedVector(vecBfloatBin); + vector vecBFMul = Multiply(MatBF, vecBfloat); // Test Convert and MultiplyAdd with odd sizes and packed types - // CHECK: %[[MAT_7_15_PACKED:.*]] = call %dx.types.LinAlgMatrixC21M7N15U0S0 @dx.op.linAlgMatrixLoadFromDescriptor.mC21M7N15U0S0(i32 -2147483634, + // CHECK: %[[MAT_7_15_PACKED:.*]] = call %dx.types.LinAlgMatrixC21M7N15U0S0 @dx.op.linAlgMatrixLoadFromDescriptor.mC21M7N15U0S0(i32 325, // CHECK-SAME: %dx.types.Handle %{{[0-9]+}}, i32 0, i32 16, i32 1, i32 128) ; LinAlgMatrixLoadFromDescriptor(handle,offset,stride,layout,align) MatrixPacked_7_15_ATy Mat_7_15_Packed = MatrixPacked_7_15_ATy::Load(BAB, 0, 16); - // CHECK: call <7 x half> @dx.op.linAlgMatVecMulAdd.v7f16.mC21M7N15U0S0.v15f16.v7f16(i32 -2147483622, + // CHECK: call <7 x half> @dx.op.linAlgMatVecMulAdd.v7f16.mC21M7N15U0S0.v15f16.v7f16(i32 337, // CHECK-SAME: %dx.types.LinAlgMatrixC21M7N15U0S0 %[[MAT_7_15_PACKED]], i1 true, <15 x half> %{{[0-9]+}}, i32 8, <7 x half> %{{[0-9]+}}) // CHECK-SAME: ; LinAlgMatVecMulAdd(matrix,isOutputSigned,inputVector,inputInterpretation,biasVector) vector vec21 = MultiplyAdd(Mat_7_15_Packed, vecH15, vecH7); - // CHECK: call <7 x half> @dx.op.linAlgMatVecMulAdd.v7f16.mC21M7N15U0S0.v4i32.v7f16(i32 -2147483622, %dx.types.LinAlgMatrixC21M7N15U0S0 %[[MAT_7_15_PACKED]], + // CHECK: call <7 x half> @dx.op.linAlgMatVecMulAdd.v7f16.mC21M7N15U0S0.v4i32.v7f16(i32 337, %dx.types.LinAlgMatrixC21M7N15U0S0 %[[MAT_7_15_PACKED]], // CHECK-SAME: i1 true, <4 x i32> %[[INTERP_VEC_H15_PACKED]], i32 21, <7 x half> %{{[0-9]+}}) // CHECK-SAME: ; LinAlgMatVecMulAdd(matrix,isOutputSigned,inputVector,inputInterpretation,biasVector) vector vec22 = MultiplyAdd(Mat_7_15_Packed, interpVecH15Packed, vecH7); @@ -176,10 +196,10 @@ void main(uint ID : SV_GroupID) { // CHECK: %[[LOAD4:.*]] = call %dx.types.ResRet.v2i32 @dx.op.rawBufferVectorLoad.v2i32(i32 303, %dx.types.Handle %{{[0-9]+}}, i32 512, i32 undef, i32 4) // CHECK-SAME: ; RawBufferVectorLoad(buf,index,elementOffset,alignment) // CHECK-NEXT: %[[MEM_BIAS_PACKED1:.*]] = extractvalue %dx.types.ResRet.v2i32 %[[LOAD4]], 0 - // CHECK-NEXT: %[[MEM_BIAS_CONV_PADDED:.*]] = call <8 x half> @dx.op.linAlgConvert.v8f16.v2i32(i32 -2147483618, + // CHECK-NEXT: %[[MEM_BIAS_CONV_PADDED:.*]] = call <8 x half> @dx.op.linAlgConvert.v8f16.v2i32(i32 341, // CHECK-SAME: <2 x i32> %[[MEM_BIAS_PACKED1]], i32 21, i32 8) ; LinAlgConvert(inputVector,inputInterpretation,outputInterpretation) // CHECK-NEXT: %[[MEM_BIAS_CONV1:.*]] = shufflevector <8 x half> %[[MEM_BIAS_CONV_PADDED]], <8 x half> undef, <7 x i32> - // CHECK-NEXT: call <7 x half> @dx.op.linAlgMatVecMulAdd.v7f16.mC21M7N15U0S0.v15f16.v7f16(i32 -2147483622, + // CHECK-NEXT: call <7 x half> @dx.op.linAlgMatVecMulAdd.v7f16.mC21M7N15U0S0.v15f16.v7f16(i32 337, // CHECK-SAME: %dx.types.LinAlgMatrixC21M7N15U0S0 %[[MAT_7_15_PACKED]], i1 true, <15 x half> %{{[0-9]+}}, i32 8, <7 x half> %[[MEM_BIAS_CONV1]]) // CHECK-SAME: ; LinAlgMatVecMulAdd(matrix,isOutputSigned,inputVector,inputInterpretation,biasVector) VectorRef memBias7Packed = {BAB, 512}; @@ -188,20 +208,20 @@ void main(uint ID : SV_GroupID) { // CHECK: %[[LOAD5:.*]] = call %dx.types.ResRet.v2i32 @dx.op.rawBufferVectorLoad.v2i32(i32 303, %dx.types.Handle %{{[0-9]+}}, i32 512, i32 undef, i32 4) // CHECK-SAME: ; RawBufferVectorLoad(buf,index,elementOffset,alignment) // CHECK-NEXT: %[[MEM_BIAS_PACKED2:.*]] = extractvalue %dx.types.ResRet.v2i32 %[[LOAD5]], 0 - // CHECK-NEXT: %[[MEM_BIAS_CONV_PADDED2:.*]] = call <8 x half> @dx.op.linAlgConvert.v8f16.v2i32(i32 -2147483618, + // CHECK-NEXT: %[[MEM_BIAS_CONV_PADDED2:.*]] = call <8 x half> @dx.op.linAlgConvert.v8f16.v2i32(i32 341, // CHECK-SAME: <2 x i32> %[[MEM_BIAS_PACKED2]], i32 21, i32 8) ; LinAlgConvert(inputVector,inputInterpretation,outputInterpretation) // CHECK-NEXT: %[[MEM_BIAS_CONV2:.*]] = shufflevector <8 x half> %[[MEM_BIAS_CONV_PADDED2]], <8 x half> undef, <7 x i32> - // CHECK-NEXT: call <7 x half> @dx.op.linAlgMatVecMulAdd.v7f16.mC21M7N15U0S0.v4i32.v7f16(i32 -2147483622, + // CHECK-NEXT: call <7 x half> @dx.op.linAlgMatVecMulAdd.v7f16.mC21M7N15U0S0.v4i32.v7f16(i32 337, // CHECK-SAME: %dx.types.LinAlgMatrixC21M7N15U0S0 %[[MAT_7_15_PACKED]], i1 true, <4 x i32> %[[INTERP_VEC_H15_PACKED]], i32 21, <7 x half> %[[MEM_BIAS_CONV2]]) // CHECK-SAME: ; LinAlgMatVecMulAdd(matrix,isOutputSigned,inputVector,inputInterpretation,biasVector) vector vec24 = MultiplyAdd(Mat_7_15_Packed, interpVecH15Packed, memBias7Packed); - // CHECK: call void @dx.op.linAlgVectorAccumulateToDescriptor.v4f16(i32 -2147483617, %dx.types.Handle %{{[0-9]+}}, + // CHECK: call void @dx.op.linAlgVectorAccumulateToDescriptor.v4f16(i32 342, %dx.types.Handle %{{[0-9]+}}, // CHECK-SAME: i32 0, i32 64, <4 x half> ) // CHECK-SAME: ; LinAlgVectorAccumulateToDescriptor(handle,offset,align,vector) InterlockedAccumulate(RWBAB, 0, vec1); - // CHECK: call void @dx.op.linAlgVectorAccumulateToDescriptor.v8f16(i32 -2147483617, %dx.types.Handle %{{[0-9]+}}, + // CHECK: call void @dx.op.linAlgVectorAccumulateToDescriptor.v8f16(i32 342, %dx.types.Handle %{{[0-9]+}}, // CHECK-SAME: i32 8, i32 64, <8 x half> %{{[0-9]+}}) ; LinAlgVectorAccumulateToDescriptor(handle,offset,align,vector) InterlockedAccumulate(RWBAB, 8, vec2); } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/convert/nominal.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/convert/nominal.hlsl index d0270cb12f..3a336e1021 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/convert/nominal.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/convert/nominal.hlsl @@ -7,22 +7,32 @@ void main() { // CHECK-LABEL: define void @main() // CHECK: %{{.*}} = call <4 x i32> @dx.op.linAlgConvert.v4i32.v4f32 - // CHECK-SAME: (i32 -2147483618, <4 x float> , i32 1, i32 2) + // CHECK-SAME: (i32 341, <4 x float> , i32 9, i32 4) // CHECK-SAME: ; LinAlgConvert(inputVector,inputInterpretation,outputInterpretation) // CHECK2: call void @"dx.hl.op..void (i32, <4 x i32>*, <4 x float>, i32, i32)" - // CHECK2-SAME: (i32 422, <4 x i32>* %result1, <4 x float> %{{.*}}, i32 1, i32 2) + // CHECK2-SAME: (i32 422, <4 x i32>* %result1, <4 x float> %{{.*}}, i32 9, i32 4) float4 vec1 = {9.0, 8.0, 7.0, 6.0}; int4 result1; - __builtin_LinAlg_Convert(result1, vec1, 1, 2); + dx::__builtin_LinAlg_Convert(result1, vec1, 9, 4); // CHECK: %{{.*}} = call <4 x i64> @dx.op.linAlgConvert.v4i64.v4f64 - // CHECK-SAME: (i32 -2147483618, <4 x double> , i32 1, i32 2) + // CHECK-SAME: (i32 341, <4 x double> , i32 10, i32 6) // CHECK-SAME: ; LinAlgConvert(inputVector,inputInterpretation,outputInterpretation) // CHECK2: call void @"dx.hl.op..void (i32, <4 x i64>*, <4 x double>, i32, i32)" - // CHECK2-SAME: (i32 422, <4 x i64>* %result2, <4 x double> %{{.*}}, i32 1, i32 2) + // CHECK2-SAME: (i32 422, <4 x i64>* %result2, <4 x double> %{{.*}}, i32 10, i32 6) double4 vec2 = {9.0, 8.0, 7.0, 6.0}; vector result2; - __builtin_LinAlg_Convert(result2, vec2, 1, 2); + dx::__builtin_LinAlg_Convert(result2, vec2, 10, 6); + + // CHECK: %{{.*}} = call <4 x i64> @dx.op.linAlgConvert.v4i64.v4f64 + // CHECK-SAME: (i32 341, <4 x double> , i32 10, i32 7) + // CHECK-SAME: ; LinAlgConvert(inputVector,inputInterpretation,outputInterpretation) + + // CHECK2: call void @"dx.hl.op..void (i32, <4 x i64>*, <4 x double>, i32, i32)" + // CHECK2-SAME: (i32 422, <4 x i64>* %result3, <4 x double> %{{.*}}, i32 10, i32 7) + double4 vec3 = {9.0, 8.0, 7.0, 6.0}; + vector result3; + dx::__builtin_LinAlg_Convert(result3, vec3, 10, 7); } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/copyconvertmatrix/nominal.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/copyconvertmatrix/nominal.hlsl index 6780c0cc83..89a9c1f35f 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/copyconvertmatrix/nominal.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/copyconvertmatrix/nominal.hlsl @@ -7,7 +7,7 @@ void main() { // CHECK-LABEL: define void @main() // CHECK: call %dx.types.LinAlgMatrixC4M5N4U1S2 @dx.op.linAlgCopyConvertMatrix.mC4M5N4U1S2.mC2M5N4U1S2 - // CHECK-SAME: (i32 -2147483635, %dx.types.LinAlgMatrixC2M5N4U1S2 %{{.*}}, i1 false) + // CHECK-SAME: (i32 324, %dx.types.LinAlgMatrixC2M5N4U1S2 %{{.*}}, i1 false) // CHECK-SAME: ; LinAlgCopyConvertMatrix(srcMatrix,transpose) // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC4M5N4U1S2*, %dx.types.LinAlgMatrixC2M5N4U1S2, i1)" @@ -15,7 +15,7 @@ void main() { __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(2, 5, 4, 1, 2)]] mat1; __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 5, 4, 1, 2)]] mat2; - __builtin_LinAlg_FillMatrix(mat1, 1); + dx::__builtin_LinAlg_FillMatrix(mat1, true, 1); - __builtin_LinAlg_CopyConvertMatrix(mat2, mat1, false); + dx::__builtin_LinAlg_CopyConvertMatrix(mat2, mat1, false); } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/fillmatrix/nominal.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/fillmatrix/nominal.hlsl index 0c9d693c3a..978a911180 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/fillmatrix/nominal.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/fillmatrix/nominal.hlsl @@ -7,38 +7,42 @@ void main() { // CHECK-LABEL: define void @main() // CHECK: %{{.*}} = call %dx.types.LinAlgMatrixC4M5N4U1S2 @dx.op.linAlgFillMatrix.mC4M5N4U1S2.i32 - // CHECK-SAME: (i32 -2147483636, i32 {{.*}}) ; LinAlgFillMatrix(value) + // CHECK-SAME: (i32 323, i1 true, i32 {{.*}}) ; LinAlgFillMatrix(isInputSigned,value) - // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC4M5N4U1S2*, i32)" - // CHECK2-SAME: (i32 402, %dx.types.LinAlgMatrixC4M5N4U1S2* {{.*}}, i32 5), + // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC4M5N4U1S2*, i1, i32)" + // CHECK2-SAME: (i32 402, %dx.types.LinAlgMatrixC4M5N4U1S2* {{.*}}, i1 true, i32 5), + // Matrix __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 5, 4, 1, 2)]] mat1; - __builtin_LinAlg_FillMatrix(mat1, 5); + dx::__builtin_LinAlg_FillMatrix(mat1, true, 5); - // CHECK: %{{.*}} = call %dx.types.LinAlgMatrixC5M3N4U0S0 @dx.op.linAlgFillMatrix.mC5M3N4U0S0.f32 - // CHECK-SAME: (i32 -2147483636, float {{.*}}) ; LinAlgFillMatrix(value) + // CHECK: %{{.*}} = call %dx.types.LinAlgMatrixC5M8N4U0S1 @dx.op.linAlgFillMatrix.mC5M8N4U0S1.f32 + // CHECK-SAME: (i32 323, i1 true, float {{.*}}) ; LinAlgFillMatrix(isInputSigned,value) - // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC5M3N4U0S0*, float)" - // CHECK2-SAME: (i32 402, %dx.types.LinAlgMatrixC5M3N4U0S0* {{.*}}, float 0x40091EB860000000) - __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(5, 3, 4, 0, 0)]] mat2; - __builtin_LinAlg_FillMatrix(mat2, 3.14); + // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC5M8N4U0S1*, i1, float)" + // CHECK2-SAME: (i32 402, %dx.types.LinAlgMatrixC5M8N4U0S1* {{.*}}, i1 true, float 0x40091EB860000000) + // Matrix + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(5, 8, 4, 0, 1)]] mat2; + dx::__builtin_LinAlg_FillMatrix(mat2, true, 3.14); - // CHECK: %{{.*}} = call %dx.types.LinAlgMatrixC5M3N4U0S0 @dx.op.linAlgFillMatrix.mC5M3N4U0S0.f64 - // CHECK-SAME: (i32 -2147483636, double {{.*}}) ; LinAlgFillMatrix(value) + // CHECK: %{{.*}} = call %dx.types.LinAlgMatrixC5M8N4U0S2 @dx.op.linAlgFillMatrix.mC5M8N4U0S2.f64 + // CHECK-SAME: (i32 323, i1 true, double {{.*}}) ; LinAlgFillMatrix(isInputSigned,value) - // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC5M3N4U0S0*, double)" - // CHECK2-SAME: (i32 402, %dx.types.LinAlgMatrixC5M3N4U0S0* {{.*}}, double %{{.+}}) + // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC5M8N4U0S2*, i1, double)" + // CHECK2-SAME: (i32 402, %dx.types.LinAlgMatrixC5M8N4U0S2* {{.*}}, i1 true, double %{{.+}}) + // Matrix double dVal = 9.87; - __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(5, 3, 4, 0, 0)]] mat3; - __builtin_LinAlg_FillMatrix(mat2, dVal); + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(5, 8, 4, 0, 2)]] mat3; + dx::__builtin_LinAlg_FillMatrix(mat3, true, dVal); - // CHECK: %{{.*}} = call %dx.types.LinAlgMatrixC5M3N4U0S0 @dx.op.linAlgFillMatrix.mC5M3N4U0S0.i64 - // CHECK-SAME: (i32 -2147483636, i64 {{.*}}) ; LinAlgFillMatrix(value) + // CHECK: %{{.*}} = call %dx.types.LinAlgMatrixC5M4N4U1S1 @dx.op.linAlgFillMatrix.mC5M4N4U1S1.i64 + // CHECK-SAME: (i32 323, i1 true, i64 {{.*}}) ; LinAlgFillMatrix(isInputSigned,value) - // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC5M3N4U0S0*, i64)" - // CHECK2-SAME: (i32 402, %dx.types.LinAlgMatrixC5M3N4U0S0* {{.*}}, i64 %{{.+}}) + // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC5M4N4U1S1*, i1, i64)" + // CHECK2-SAME: (i32 402, %dx.types.LinAlgMatrixC5M4N4U1S1* {{.*}}, i1 true, i64 %{{.+}}) + // Matrix int64_t i64Val = 12345; - __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(5, 3, 4, 0, 0)]] mat4; - __builtin_LinAlg_FillMatrix(mat2, i64Val); + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(5, 4, 4, 1, 1)]] mat4; + dx::__builtin_LinAlg_FillMatrix(mat4, true, i64Val); } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixaccumulate/nominal.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixaccumulate/nominal.hlsl index 8d20733f8f..6c365683cd 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixaccumulate/nominal.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixaccumulate/nominal.hlsl @@ -10,14 +10,14 @@ void main() { __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(5, 4, 4, 2, 1)]] mat2; __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(5, 4, 4, 2, 1)]] mat3; - __builtin_LinAlg_FillMatrix(mat1, 1); - __builtin_LinAlg_FillMatrix(mat2, 2); + dx::__builtin_LinAlg_FillMatrix(mat1, true, 1); + dx::__builtin_LinAlg_FillMatrix(mat2, true, 2); // CHECK: call %dx.types.LinAlgMatrixC5M4N4U2S1 @dx.op.linAlgMatrixAccumulate.mC5M4N4U2S1.mC5M4N4U2S1.mC5M4N4U0S1 - // CHECK-SAME: (i32 -2147483624, %dx.types.LinAlgMatrixC5M4N4U2S1 %{{.*}}, %dx.types.LinAlgMatrixC5M4N4U0S1 %{{.*}}) ; LinAlgMatrixAccumulate(matrixLHS,matrixRHS) + // CHECK-SAME: (i32 335, %dx.types.LinAlgMatrixC5M4N4U2S1 %{{.*}}, %dx.types.LinAlgMatrixC5M4N4U0S1 %{{.*}}) ; LinAlgMatrixAccumulate(matrixLHS,matrixRHS) // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC5M4N4U2S1*, %dx.types.LinAlgMatrixC5M4N4U2S1, // CHECK2-SAME: %dx.types.LinAlgMatrixC5M4N4U0S1)"(i32 411, %dx.types.LinAlgMatrixC5M4N4U2S1* %mat3, // CHECK2-SAME: %dx.types.LinAlgMatrixC5M4N4U2S1 %{{[0-9]+}}, %dx.types.LinAlgMatrixC5M4N4U0S1 %{{[0-9]+}}) - __builtin_LinAlg_MatrixAccumulate(mat3, mat2, mat1); + dx::__builtin_LinAlg_MatrixAccumulate(mat3, mat2, mat1); } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixaccumulatetodescriptor/nominal.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixaccumulatetodescriptor/nominal.hlsl index 591eebf5e7..64491f6943 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixaccumulatetodescriptor/nominal.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixaccumulatetodescriptor/nominal.hlsl @@ -8,13 +8,15 @@ RWByteAddressBuffer outbuf; void main() { // CHECK-LABEL: define void @main() - // CHECK: call void @dx.op.linAlgMatrixAccumulateToDescriptor.mC4M5N4U1S2(i32 -2147483621, - // CHECK-SAME: %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, %dx.types.Handle %{{.*}}, i32 5, i32 5, i32 5, i32 4) + // CHECK: call void @dx.op.linAlgMatrixAccumulateToDescriptor.mC9M4N4U2S1(i32 338, + // CHECK-SAME: %dx.types.LinAlgMatrixC9M4N4U2S1 %{{.*}}, %dx.types.Handle %{{.*}}, i32 0, i32 0, i32 0, i32 128) // CHECK-SAME: ; LinAlgMatrixAccumulateToDescriptor(matrix,handle,offset,stride,layout,align) - // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC4M5N4U1S2, %dx.types.Handle, i32, i32, i32, i32)" - // CHECK2-SAME: (i32 415, %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, %dx.types.Handle {{.*}}, i32 5, i32 5, i32 5, i32 4) - __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 5, 4, 1, 2)]] mat; - __builtin_LinAlg_FillMatrix(mat, 1); - __builtin_LinAlg_MatrixAccumulateToDescriptor(mat, outbuf, 5, 5, 5, 4); + // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC9M4N4U2S1, %dx.types.Handle, i32, i32, i32, i32)" + // CHECK2-SAME: (i32 415, %dx.types.LinAlgMatrixC9M4N4U2S1 %{{.*}}, %dx.types.Handle {{.*}}, i32 0, i32 0, i32 0, i32 128) + + // Matrix + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(9, 4, 4, 2, 1)]] mat; + dx::__builtin_LinAlg_FillMatrix(mat, true, 1); + dx::__builtin_LinAlg_MatrixAccumulateToDescriptor(mat, outbuf, 0, 0, 0, 128); } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixaccumulatetomemory/nominal.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixaccumulatetomemory/nominal.hlsl index 824503cd9f..62e9402c97 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixaccumulatetomemory/nominal.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixaccumulatetomemory/nominal.hlsl @@ -9,16 +9,16 @@ groupshared float SharedArr[64]; void main() { // CHECK-LABEL: define void @main() - // CHECK: call void @dx.op.linAlgMatrixAccumulateToMemory.mC4M5N4U1S2.f32(i32 -2147483620, - // CHECK-SAME: %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, float addrspace(3)* getelementptr inbounds ([64 x float], - // CHECK-SAME: [64 x float] addrspace(3)* @"\01?SharedArr@@3PAMA", i32 0, i32 0), i32 9, i32 1, i32 2, i32 3) - // CHECK-SAME: ; LinAlgMatrixAccumulateToMemory(matrix,memory,targetType,offset,stride,layout) + // CHECK: call void @dx.op.linAlgMatrixAccumulateToMemory.mC9M5N4U2S2.f32(i32 339, + // CHECK-SAME: %dx.types.LinAlgMatrixC9M5N4U2S2 %{{.*}}, float addrspace(3)* getelementptr inbounds ([64 x float], + // CHECK-SAME: [64 x float] addrspace(3)* @"\01?SharedArr@@3PAMA", i32 0, i32 0), i32 128, i32 16, i32 3) + // CHECK-SAME: ; LinAlgMatrixAccumulateToMemory(matrix,memory,offset,stride,layout) - // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC4M5N4U1S2, - // CHECK2-SAME: [64 x float] addrspace(3)*, i32, i32, i32, i32)"(i32 416, - // CHECK2-SAME: %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, [64 x float] addrspace(3)* @"\01?SharedArr@@3PAMA", - // CHECK2-SAME: i32 9, i32 1, i32 2, i32 3) - __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 5, 4, 1, 2)]] mat; - __builtin_LinAlg_FillMatrix(mat, 1); - __builtin_LinAlg_MatrixAccumulateToMemory(mat, SharedArr, 9, 1, 2, 3); + // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC9M5N4U2S2, + // CHECK2-SAME: [64 x float] addrspace(3)*, i32, i32, i32)"(i32 416, + // CHECK2-SAME: %dx.types.LinAlgMatrixC9M5N4U2S2 %{{.*}}, [64 x float] addrspace(3)* @"\01?SharedArr@@3PAMA", + // CHECK2-SAME: i32 128, i32 16, i32 3) + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(9, 5, 4, 2, 2)]] mat; + dx::__builtin_LinAlg_FillMatrix(mat, true, 1); + dx::__builtin_LinAlg_MatrixAccumulateToMemory(mat, SharedArr, 128, 16, 3); } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixaccumulatetomemory/vector-array.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixaccumulatetomemory/vector-array.hlsl new file mode 100644 index 0000000000..4e03f34cf7 --- /dev/null +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixaccumulatetomemory/vector-array.hlsl @@ -0,0 +1,29 @@ +// REQUIRES: dxil-1-10 +// RUN: %dxc -T cs_6_10 -HV 202x -E main %s | FileCheck %s +// RUN: %dxc -T cs_6_10 -HV 202x -E main -fcgl %s | FileCheck %s --check-prefix=CHECK2 + +// The groupshared array may hold vectors of the matrix component type. The +// DXIL operation is overloaded on the array's element type, so the memory +// operand is a pointer to a vector. + +// CHECK: @"\01?SharedArr@@3PAV?$vector@M$01@@A" = external addrspace(3) global [64 x <2 x float>], align 4 +groupshared float2 SharedArr[64]; + +[numthreads(4,1,1)] +void main() { + // CHECK-LABEL: define void @main() + + // CHECK: call void @dx.op.linAlgMatrixAccumulateToMemory.mC9M5N4U2S2.v2f32(i32 339, + // CHECK-SAME: %dx.types.LinAlgMatrixC9M5N4U2S2 %{{.*}}, <2 x float> addrspace(3)* getelementptr inbounds ([64 x <2 x float>], + // CHECK-SAME: [64 x <2 x float>] addrspace(3)* @"\01?SharedArr@@3PAV?$vector@M$01@@A", i32 0, i32 0), + // CHECK-SAME: i32 128, i32 16, i32 3) + // CHECK-SAME: ; LinAlgMatrixAccumulateToMemory(matrix,memory,offset,stride,layout) + + // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC9M5N4U2S2, + // CHECK2-SAME: [64 x <2 x float>] addrspace(3)*, i32, i32, i32)"(i32 416, + // CHECK2-SAME: %dx.types.LinAlgMatrixC9M5N4U2S2 %{{.*}}, [64 x <2 x float>] addrspace(3)* + // CHECK2-SAME: @"\01?SharedArr@@3PAV?$vector@M$01@@A", i32 128, i32 16, i32 3) + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(9, 5, 4, 2, 2)]] mat; + dx::__builtin_LinAlg_FillMatrix(mat, true, 1); + dx::__builtin_LinAlg_MatrixAccumulateToMemory(mat, SharedArr, 128, 16, 3); +} diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixgetcoordinate/nominal.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixgetcoordinate/nominal.hlsl index 9732790d20..49d45aefc5 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixgetcoordinate/nominal.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixgetcoordinate/nominal.hlsl @@ -6,13 +6,13 @@ void main() { // CHECK-LABEL: define void @main() - // CHECK: call <2 x i32> @dx.op.linAlgMatrixGetCoordinate.mC4M5N4U1S2(i32 -2147483631, + // CHECK: call <2 x i32> @dx.op.linAlgMatrixGetCoordinate.mC4M5N4U1S2(i32 328, // CHECK-SAME: %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, i32 1) // CHECK-SAME: ; LinAlgMatrixGetCoordinate(matrix,threadLocalIndex) // CHECK2: call <2 x i32> @"dx.hl.op..<2 x i32> (i32, %dx.types.LinAlgMatrixC4M5N4U1S2, i32)" // CHECK2-SAME: (i32 403, %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, i32 1) __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 5, 4, 1, 2)]] mat; - __builtin_LinAlg_FillMatrix(mat, 1); - uint2 coord = __builtin_LinAlg_MatrixGetCoordinate(mat, 1); + dx::__builtin_LinAlg_FillMatrix(mat, true, 1); + uint2 coord = dx::__builtin_LinAlg_MatrixGetCoordinate(mat, 1); } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixgetelement/nominal.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixgetelement/nominal.hlsl index 0f16ff9d90..32e6311615 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixgetelement/nominal.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixgetelement/nominal.hlsl @@ -8,41 +8,41 @@ void main() { __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 5, 4, 1, 2)]] mat; - // CHECK: call i32 @dx.op.linAlgMatrixGetElement.i32.mC4M5N4U1S2(i32 -2147483630, + // CHECK: call i32 @dx.op.linAlgMatrixGetElement.i32.mC4M5N4U1S2(i32 329, // CHECK-SAME: %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, i32 0) // CHECK-SAME: ; LinAlgMatrixGetElement(matrix,threadLocalIndex) // CHECK2: call void @"dx.hl.op..void (i32, i32*, %dx.types.LinAlgMatrixC4M5N4U1S2, i32)" // CHECK2-SAME: (i32 404, i32* %elem1, %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, i32 0) uint elem1; - __builtin_LinAlg_FillMatrix(mat, 1); - __builtin_LinAlg_MatrixGetElement(elem1, mat, 0); + dx::__builtin_LinAlg_FillMatrix(mat, true, 1); + dx::__builtin_LinAlg_MatrixGetElement(elem1, mat, 0); - // CHECK: call float @dx.op.linAlgMatrixGetElement.f32.mC4M5N4U1S2(i32 -2147483630, + // CHECK: call float @dx.op.linAlgMatrixGetElement.f32.mC4M5N4U1S2(i32 329, // CHECK-SAME: %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, i32 1) // CHECK-SAME: ; LinAlgMatrixGetElement(matrix,threadLocalIndex) // CHECK2: call void @"dx.hl.op..void (i32, float*, %dx.types.LinAlgMatrixC4M5N4U1S2, i32)" // CHECK2-SAME: (i32 404, float* %elem2, %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, i32 1) float elem2; - __builtin_LinAlg_MatrixGetElement(elem2, mat, 1); + dx::__builtin_LinAlg_MatrixGetElement(elem2, mat, 1); - // CHECK: call double @dx.op.linAlgMatrixGetElement.f64.mC4M5N4U1S2(i32 -2147483630, + // CHECK: call double @dx.op.linAlgMatrixGetElement.f64.mC4M5N4U1S2(i32 329, // CHECK-SAME: %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, i32 1) // CHECK-SAME: ; LinAlgMatrixGetElement(matrix,threadLocalIndex) // CHECK2: call void @"dx.hl.op..void (i32, double*, %dx.types.LinAlgMatrixC4M5N4U1S2, i32)" // CHECK2-SAME: (i32 404, double* %elem3, %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, i32 1) double elem3; - __builtin_LinAlg_MatrixGetElement(elem3, mat, 1); + dx::__builtin_LinAlg_MatrixGetElement(elem3, mat, 1); - // CHECK: call i64 @dx.op.linAlgMatrixGetElement.i64.mC4M5N4U1S2(i32 -2147483630, + // CHECK: call i64 @dx.op.linAlgMatrixGetElement.i64.mC4M5N4U1S2(i32 329, // CHECK-SAME: %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, i32 1) // CHECK-SAME: ; LinAlgMatrixGetElement(matrix,threadLocalIndex) // CHECK2: call void @"dx.hl.op..void (i32, i64*, %dx.types.LinAlgMatrixC4M5N4U1S2, i32)" // CHECK2-SAME: (i32 404, i64* %elem4, %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, i32 1) int64_t elem4; - __builtin_LinAlg_MatrixGetElement(elem4, mat, 1); + dx::__builtin_LinAlg_MatrixGetElement(elem4, mat, 1); } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixlength/nominal.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixlength/nominal.hlsl index a21539d412..ed35e63467 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixlength/nominal.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixlength/nominal.hlsl @@ -6,12 +6,12 @@ void main() { // CHECK-LABEL: define void @main() - // CHECK: call i32 @dx.op.linAlgMatrixLength.mC4M5N4U1S2(i32 -2147483632, + // CHECK: call i32 @dx.op.linAlgMatrixLength.mC4M5N4U1S2(i32 327, // CHECK-SAME: %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}) ; LinAlgMatrixLength(matrix) // CHECK2: call i32 @"dx.hl.op..i32 (i32, %dx.types.LinAlgMatrixC4M5N4U1S2)" // CHECK2-SAME: (i32 405, %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}) __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 5, 4, 1, 2)]] mat; - __builtin_LinAlg_FillMatrix(mat, 1); - uint len = __builtin_LinAlg_MatrixLength(mat); + dx::__builtin_LinAlg_FillMatrix(mat, true, 1); + uint len = dx::__builtin_LinAlg_MatrixLength(mat); } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixloadfromdescriptor/nominal.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixloadfromdescriptor/nominal.hlsl index b584fdeb81..8b165b5690 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixloadfromdescriptor/nominal.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixloadfromdescriptor/nominal.hlsl @@ -9,11 +9,11 @@ void main() { // CHECK-LABEL: define void @main() // CHECK: %{{.*}} = call %dx.types.LinAlgMatrixC2M4N4U0S0 @dx.op.linAlgMatrixLoadFromDescriptor.mC2M4N4U0S0 - // CHECK-SAME: (i32 -2147483634, %dx.types.Handle %{{.*}}, i32 0, i32 0, i32 0, i32 4) + // CHECK-SAME: (i32 325, %dx.types.Handle %{{.*}}, i32 0, i32 0, i32 0, i32 256) // CHECK-SAME: ; LinAlgMatrixLoadFromDescriptor(handle,offset,stride,layout,align) // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC2M4N4U0S0*, %dx.types.Handle, i32, i32, i32, i32) - // CHECK2-SAME: "(i32 406, %dx.types.LinAlgMatrixC2M4N4U0S0* %mat, %dx.types.Handle {{.*}}, i32 0, i32 0, i32 0, i32 4) + // CHECK2-SAME: "(i32 406, %dx.types.LinAlgMatrixC2M4N4U0S0* %mat, %dx.types.Handle {{.*}}, i32 0, i32 0, i32 0, i32 256) __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(2, 4, 4, 0, 0)]] mat; - __builtin_LinAlg_MatrixLoadFromDescriptor(mat, inbuf, 0, 0, 0, 4); + dx::__builtin_LinAlg_MatrixLoadFromDescriptor(mat, inbuf, 0, 0, 0, 256); } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixloadfrommemory/nominal.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixloadfrommemory/nominal.hlsl index f3ef819052..2ce23b4277 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixloadfrommemory/nominal.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixloadfrommemory/nominal.hlsl @@ -9,14 +9,14 @@ groupshared float SharedArr[64]; void main() { // CHECK-LABEL: define void @main() - // CHECK: call %dx.types.LinAlgMatrixC4M5N4U1S2 @dx.op.linAlgMatrixLoadFromMemory.mC4M5N4U1S2.f32 - // CHECK-SAME; (i32 -2147483633, float addrspace(3)* getelementptr inbounds ([64 x float], - // CHECK-SAME: [64 x float] addrspace(3)* @"\01?SharedArr@@3PAMA", i32 0, i32 0), i32 1, i32 2, i32 3) + // CHECK: call %dx.types.LinAlgMatrixC9M5N4U1S2 @dx.op.linAlgMatrixLoadFromMemory.mC9M5N4U1S2.f32 + // CHECK-SAME; (i32 326, float addrspace(3)* getelementptr inbounds ([64 x float], + // CHECK-SAME: [64 x float] addrspace(3)* @"\01?SharedArr@@3PAMA", i32 0, i32 0), i32 128, i32 16, i32 3) // CHECK-SAME: ; LinAlgMatrixLoadFromMemory(memory,offset,stride,layout) - // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC4M5N4U1S2*, [64 x float] addrspace(3)*, - // CHECK2-SAME: i32, i32, i32)"(i32 407, %dx.types.LinAlgMatrixC4M5N4U1S2* %mat, [64 x float] addrspace(3)* - // CHECK2-SAME: @"\01?SharedArr@@3PAMA", i32 1, i32 2, i32 3) - __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 5, 4, 1, 2)]] mat; - __builtin_LinAlg_MatrixLoadFromMemory(mat, SharedArr, 1, 2, 3); + // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC9M5N4U1S2*, [64 x float] addrspace(3)*, + // CHECK2-SAME: i32, i32, i32)"(i32 407, %dx.types.LinAlgMatrixC9M5N4U1S2* %mat, [64 x float] addrspace(3)* + // CHECK2-SAME: @"\01?SharedArr@@3PAMA", i32 128, i32 16, i32 3) + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(9, 5, 4, 1, 2)]] mat; + dx::__builtin_LinAlg_MatrixLoadFromMemory(mat, SharedArr, 128, 16, 3); } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixloadfrommemory/vector-array.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixloadfrommemory/vector-array.hlsl new file mode 100644 index 0000000000..cc3de47de5 --- /dev/null +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixloadfrommemory/vector-array.hlsl @@ -0,0 +1,40 @@ +// REQUIRES: dxil-1-10 +// RUN: %dxc -T cs_6_10 -HV 202x -E main %s | FileCheck %s +// RUN: %dxc -T cs_6_10 -HV 202x -E main -fcgl %s | FileCheck %s --check-prefix=CHECK2 + +// The groupshared array may hold vectors of the matrix component type. The +// DXIL operation is overloaded on the array's element type, so the memory +// operand is a pointer to a vector. + +// CHECK: @"\01?SharedArr@@3PAV?$vector@M$03@@A" = external addrspace(3) global [64 x <4 x float>], align 4 +groupshared float4 SharedArr[64]; + +// The array may also reach the builtin through a function parameter. +void LoadIndirect(groupshared float4 Arr[64]) { + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(9, 5, 4, 1, 2)]] mat; + dx::__builtin_LinAlg_MatrixLoadFromMemory(mat, Arr, 128, 16, 3); +} + +[numthreads(4,1,1)] +void main() { + // CHECK-LABEL: define void @main() + + // CHECK: call %dx.types.LinAlgMatrixC9M5N4U1S2 @dx.op.linAlgMatrixLoadFromMemory.mC9M5N4U1S2.v4f32 + // CHECK-SAME: (i32 326, <4 x float> addrspace(3)* getelementptr inbounds ([64 x <4 x float>], + // CHECK-SAME: [64 x <4 x float>] addrspace(3)* @"\01?SharedArr@@3PAV?$vector@M$03@@A", i32 0, i32 0), + // CHECK-SAME: i32 128, i32 16, i32 3) + // CHECK-SAME: ; LinAlgMatrixLoadFromMemory(memory,offset,stride,layout) + + // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC9M5N4U1S2*, [64 x <4 x float>] addrspace(3)*, + // CHECK2-SAME: i32, i32, i32)"(i32 407, %dx.types.LinAlgMatrixC9M5N4U1S2* %mat, [64 x <4 x float>] addrspace(3)* + // CHECK2-SAME: @"\01?SharedArr@@3PAV?$vector@M$03@@A", i32 128, i32 16, i32 3) + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(9, 5, 4, 1, 2)]] mat; + dx::__builtin_LinAlg_MatrixLoadFromMemory(mat, SharedArr, 128, 16, 3); + + // CHECK: call %dx.types.LinAlgMatrixC9M5N4U1S2 @dx.op.linAlgMatrixLoadFromMemory.mC9M5N4U1S2.v4f32 + // CHECK-SAME: (i32 326, <4 x float> addrspace(3)* getelementptr inbounds ([64 x <4 x float>], + // CHECK-SAME: [64 x <4 x float>] addrspace(3)* @"\01?SharedArr@@3PAV?$vector@M$03@@A", i32 0, i32 0), + // CHECK-SAME: i32 128, i32 16, i32 3) + // CHECK-SAME: ; LinAlgMatrixLoadFromMemory(memory,offset,stride,layout) + LoadIndirect(SharedArr); +} diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixmatrixmultiply/nominal.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixmatrixmultiply/nominal.hlsl index 817a4acefe..6d782a782f 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixmatrixmultiply/nominal.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixmatrixmultiply/nominal.hlsl @@ -6,14 +6,22 @@ void main() { // CHECK-LABEL: define void @main() - // CHECK: call %dx.types.LinAlgMatrixC4M5N4U1S2 @dx.op.linAlgMatrixMultiply.mC4M5N4U1S2.mC4M5N4U1S2.mC4M5N4U1S2(i32 -2147483625, - // CHECK-SAME: %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}) ; LinAlgMatrixMultiply(matrixA,matrixB) + // Matrix + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 8, 4, 0, 2)]] matA; + // Matrix + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 4, 8, 1, 2)]] matB; + // Matrix + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 8, 8, 2, 2)]] matC; - // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC4M5N4U1S2*, %dx.types.LinAlgMatrixC4M5N4U1S2, - // CHECK2-SAME: %dx.types.LinAlgMatrixC4M5N4U1S2)"(i32 412, %dx.types.LinAlgMatrixC4M5N4U1S2* %mat2, - // CHECK2-SAME: %dx.types.LinAlgMatrixC4M5N4U1S2 %{{[0-9]+}}, %dx.types.LinAlgMatrixC4M5N4U1S2 %{{[0-9]+}}) - __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 5, 4, 1, 2)]] mat1; - __builtin_LinAlg_FillMatrix(mat1, 1); - __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 5, 4, 1, 2)]] mat2; - __builtin_LinAlg_MatrixMatrixMultiply(mat2, mat1, mat1); + dx::__builtin_LinAlg_FillMatrix(matA, true, 1); + dx::__builtin_LinAlg_FillMatrix(matB, true, 2); + + // CHECK: call %dx.types.LinAlgMatrixC4M8N8U2S2 @dx.op.linAlgMatrixMultiply.mC4M8N8U2S2.mC4M8N4U0S2.mC4M4N8U1S2(i32 334, + // CHECK-SAME: %dx.types.LinAlgMatrixC4M8N4U0S2 %{{.*}}, %dx.types.LinAlgMatrixC4M4N8U1S2 %{{.*}}) ; LinAlgMatrixMultiply(matrixA,matrixB) + + // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC4M8N8U2S2*, %dx.types.LinAlgMatrixC4M8N4U0S2, + // CHECK2-SAME: %dx.types.LinAlgMatrixC4M4N8U1S2)"(i32 412, %dx.types.LinAlgMatrixC4M8N8U2S2* %matC, + // CHECK2-SAME: %dx.types.LinAlgMatrixC4M8N4U0S2 %{{[0-9]+}}, %dx.types.LinAlgMatrixC4M4N8U1S2 %{{[0-9]+}}) + + dx::__builtin_LinAlg_MatrixMatrixMultiply(matC, matA, matB); } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixmatrixmultiplyaccumulate/nominal.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixmatrixmultiplyaccumulate/nominal.hlsl index 458f08c6a4..4664117493 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixmatrixmultiplyaccumulate/nominal.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixmatrixmultiplyaccumulate/nominal.hlsl @@ -8,24 +8,32 @@ void main() { // The FillMatrix calls are similar enough that they start matching // the CHECK-SAME lines so we consume them first. - // CHECK: ; LinAlgFillMatrix(value) - // CHECK: ; LinAlgFillMatrix(value) - // CHECK: ; LinAlgFillMatrix(value) + // CHECK: ; LinAlgFillMatrix(isInputSigned,value) + // CHECK: ; LinAlgFillMatrix(isInputSigned,value) + // CHECK: ; LinAlgFillMatrix(isInputSigned,value) - // CHECK: call %dx.types.LinAlgMatrixC4M5N3U1S2 - // CHECK-SAME: @dx.op.linAlgMatrixMultiplyAccumulate.mC4M5N3U1S2.mC4M5N4U1S2.mC4M4N3U1S2.mC4M5N3U1S2 - // CHECK-SAME: (i32 -2147483637, %dx.types.LinAlgMatrixC4M5N4U1S2 %{{[0-9]+}}, %dx.types.LinAlgMatrixC4M4N3U1S2 %{{[0-9]+}}, - // CHECK-SAME: %dx.types.LinAlgMatrixC4M5N3U1S2 %{{[0-9]+}}) ; LinAlgMatrixMultiplyAccumulate(matrixA,matrixB,matrixC) + // Matrix + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 8, 4, 0, 2)]] matA; + // Matrix + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 4, 8, 1, 2)]] matB; + // Matrix + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 8, 8, 2, 2)]] matC; + // Matrix + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 8, 8, 2, 2)]] matR; - // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC4M5N3U1S2*, %dx.types.LinAlgMatrixC4M5N4U1S2, - // CHECK2-SAME: %dx.types.LinAlgMatrixC4M4N3U1S2, %dx.types.LinAlgMatrixC4M5N3U1S2)"(i32 413, - // CHECK2-SAME: %dx.types.LinAlgMatrixC4M5N3U1S2* %{{.*}}, %dx.types.LinAlgMatrixC4M5N4U1S2 %{{[0-9]+}}, - // CHECK2-SAME: %dx.types.LinAlgMatrixC4M4N3U1S2 %{{[0-9]+}}, %dx.types.LinAlgMatrixC4M5N3U1S2 %{{[0-9]+}}) - __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 5, 4, 1, 2)]] mat1; - __builtin_LinAlg_FillMatrix(mat1, 1); - __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 4, 3, 1, 2)]] mat2; - __builtin_LinAlg_FillMatrix(mat2, 2); - __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 5, 3, 1, 2)]] mat3; - __builtin_LinAlg_FillMatrix(mat3, 3); - __builtin_LinAlg_MatrixMatrixMultiplyAccumulate(mat3, mat1, mat2, mat3); + dx::__builtin_LinAlg_FillMatrix(matA, true, 1); + dx::__builtin_LinAlg_FillMatrix(matB, true, 2); + dx::__builtin_LinAlg_FillMatrix(matC, true, 3); + + // CHECK: call %dx.types.LinAlgMatrixC4M8N8U2S2 + // CHECK-SAME: @dx.op.linAlgMatrixMultiplyAccumulate.mC4M8N8U2S2.mC4M8N4U0S2.mC4M4N8U1S2.mC4M8N8U2S2 + // CHECK-SAME: (i32 322, %dx.types.LinAlgMatrixC4M8N4U0S2 %{{[0-9]+}}, %dx.types.LinAlgMatrixC4M4N8U1S2 %{{[0-9]+}}, + // CHECK-SAME: %dx.types.LinAlgMatrixC4M8N8U2S2 %{{[0-9]+}}) ; LinAlgMatrixMultiplyAccumulate(matrixA,matrixB,matrixC) + + // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC4M8N8U2S2*, %dx.types.LinAlgMatrixC4M8N4U0S2, + // CHECK2-SAME: %dx.types.LinAlgMatrixC4M4N8U1S2, %dx.types.LinAlgMatrixC4M8N8U2S2)"(i32 413, + // CHECK2-SAME: %dx.types.LinAlgMatrixC4M8N8U2S2* %{{.*}}, %dx.types.LinAlgMatrixC4M8N4U0S2 %{{[0-9]+}}, + // CHECK2-SAME: %dx.types.LinAlgMatrixC4M4N8U1S2 %{{[0-9]+}}, %dx.types.LinAlgMatrixC4M8N8U2S2 %{{[0-9]+}}) + + dx::__builtin_LinAlg_MatrixMatrixMultiplyAccumulate(matR, matA, matB, matC); } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixouterproduct/nominal.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixouterproduct/nominal.hlsl index 8b478f2980..d38ecaf19e 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixouterproduct/nominal.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixouterproduct/nominal.hlsl @@ -9,33 +9,36 @@ void main() { float4 lhs1 = {1,2,3,4}; float4 rhs1 = {4,3,2,1}; - // CHECK: call %dx.types.LinAlgMatrixC2M2N2U2S2 @dx.op.linAlgMatrixOuterProduct.mC2M2N2U2S2.v4f32.v4f32 - // CHECK-SAME: (i32 -2147483619, <4 x float> {{.*}}, <4 x float> {{.*}}) ; LinAlgMatrixOuterProduct(vectorA,vectorB) + // CHECK: call %dx.types.LinAlgMatrixC9M4N4U2S0 @dx.op.linAlgMatrixOuterProduct.mC9M4N4U2S0.v4f32.v4f32 + // CHECK-SAME: (i32 340, i1 true, <4 x float> {{.*}}, <4 x float> {{.*}}) ; LinAlgMatrixOuterProduct(isInputSigned,vectorA,vectorB) - // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC2M2N2U2S2*, <4 x float>, <4 x float>)" - // CHECK2: (i32 417, %dx.types.LinAlgMatrixC2M2N2U2S2* {{.*}}, <4 x float> {{.*}}, <4 x float> {{.*}}) - __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(2, 2, 2, 2, 2)]] mat1; - __builtin_LinAlg_MatrixOuterProduct(mat1, lhs1, rhs1); + // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC9M4N4U2S0*, i1, <4 x float>, <4 x float>)" + // CHECK2: (i32 417, %dx.types.LinAlgMatrixC9M4N4U2S0* {{.*}}, i1 true, <4 x float> {{.*}}, <4 x float> {{.*}}) + // Matrix + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(9, 4, 4, 2, 0)]] mat1; + dx::__builtin_LinAlg_MatrixOuterProduct(mat1, true, lhs1, rhs1); double4 lhs2 = {1,2,3,4}; double4 rhs2 = {4,3,2,1}; - // CHECK: call %dx.types.LinAlgMatrixC2M2N2U2S2 @dx.op.linAlgMatrixOuterProduct.mC2M2N2U2S2.v4f64.v4f64 - // CHECK-SAME: (i32 -2147483619, <4 x double> {{.*}}, <4 x double> {{.*}}) ; LinAlgMatrixOuterProduct(vectorA,vectorB) + // CHECK: call %dx.types.LinAlgMatrixC10M4N4U2S0 @dx.op.linAlgMatrixOuterProduct.mC10M4N4U2S0.v4f64.v4f64 + // CHECK-SAME: (i32 340, i1 true, <4 x double> {{.*}}, <4 x double> {{.*}}) ; LinAlgMatrixOuterProduct(isInputSigned,vectorA,vectorB) - // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC2M2N2U2S2*, <4 x double>, <4 x double>)" - // CHECK2: (i32 417, %dx.types.LinAlgMatrixC2M2N2U2S2* {{.*}}, <4 x double> {{.*}}, <4 x double> {{.*}}) - __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(2, 2, 2, 2, 2)]] mat2; - __builtin_LinAlg_MatrixOuterProduct(mat2, lhs2, rhs2); + // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC10M4N4U2S0*, i1, <4 x double>, <4 x double>)" + // CHECK2: (i32 417, %dx.types.LinAlgMatrixC10M4N4U2S0* {{.*}}, i1 true, <4 x double> {{.*}}, <4 x double> {{.*}}) + // Matrix + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(10, 4, 4, 2, 0)]] mat2; + dx::__builtin_LinAlg_MatrixOuterProduct(mat2, true, lhs2, rhs2); vector lhs3 = {1,2,3,4}; vector rhs3 = {4,3,2,1}; - // CHECK: call %dx.types.LinAlgMatrixC2M2N2U2S2 @dx.op.linAlgMatrixOuterProduct.mC2M2N2U2S2.v4i64.v4i64 - // CHECK-SAME: (i32 -2147483619, <4 x i64> {{.*}}, <4 x i64> {{.*}}) ; LinAlgMatrixOuterProduct(vectorA,vectorB) + // CHECK: call %dx.types.LinAlgMatrixC6M4N4U2S0 @dx.op.linAlgMatrixOuterProduct.mC6M4N4U2S0.v4i64.v4i64 + // CHECK-SAME: (i32 340, i1 true, <4 x i64> {{.*}}, <4 x i64> {{.*}}) ; LinAlgMatrixOuterProduct(isInputSigned,vectorA,vectorB) - // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC2M2N2U2S2*, <4 x i64>, <4 x i64>)" - // CHECK2: (i32 417, %dx.types.LinAlgMatrixC2M2N2U2S2* {{.*}}, <4 x i64> {{.*}}, <4 x i64> {{.*}}) - __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(2, 2, 2, 2, 2)]] mat3; - __builtin_LinAlg_MatrixOuterProduct(mat3, lhs3, rhs3); + // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC6M4N4U2S0*, i1, <4 x i64>, <4 x i64>)" + // CHECK2: (i32 417, %dx.types.LinAlgMatrixC6M4N4U2S0* {{.*}}, i1 true, <4 x i64> {{.*}}, <4 x i64> {{.*}}) + // Matrix + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(6, 4, 4, 2, 0)]] mat3; + dx::__builtin_LinAlg_MatrixOuterProduct(mat3, true, lhs3, rhs3); } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixqueryaccumulatorlayout/nominal.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixqueryaccumulatorlayout/nominal.hlsl index 86ca447ff8..520bc0ee4a 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixqueryaccumulatorlayout/nominal.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixqueryaccumulatorlayout/nominal.hlsl @@ -6,8 +6,8 @@ void main() { // CHECK-LABEL: define void @main() - // CHECK: call i32 @dx.op.linAlgMatrixQueryAccumulatorLayout(i32 -2147483626) ; LinAlgMatrixQueryAccumulatorLayout() + // CHECK: call i32 @dx.op.linAlgMatrixQueryAccumulatorLayout(i32 333) ; LinAlgMatrixQueryAccumulatorLayout() // CHECK2: call i32 @"dx.hl.op..i32 (i32)"(i32 414) - uint layout = __builtin_LinAlg_MatrixQueryAccumulatorLayout(); + uint layout = dx::__builtin_LinAlg_MatrixQueryAccumulatorLayout(); } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixsetelement/nominal.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixsetelement/nominal.hlsl index 952096af29..6c544b306b 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixsetelement/nominal.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixsetelement/nominal.hlsl @@ -10,15 +10,15 @@ void main() { // CHECK-LABEL: define void @main() // CHECK: call %dx.types.LinAlgMatrixC4M5N4U1S2 @dx.op.linAlgMatrixSetElement.mC4M5N4U1S2.mC4M5N4U1S2.i32 - // CHECK-SAME: (i32 -2147483629, %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, i32 1, i32 5) + // CHECK-SAME: (i32 330, %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, i32 1, i32 5) // CHECK-SAME: ; LinAlgMatrixSetElement(matrix,threadLocalIndex,value) // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC4M5N4U1S2*, %dx.types.LinAlgMatrixC4M5N4U1S2, i32, i32) // CHECK2-SAME: "(i32 408, %dx.types.LinAlgMatrixC4M5N4U1S2* %{{.*}}, %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, i32 1, i32 5) __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 5, 4, 1, 2)]] mat1; - __builtin_LinAlg_FillMatrix(mat1, 1); + dx::__builtin_LinAlg_FillMatrix(mat1, true, 1); __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 5, 4, 1, 2)]] mat2; - __builtin_LinAlg_MatrixSetElement(mat2, mat1, 1, 5); + dx::__builtin_LinAlg_MatrixSetElement(mat2, mat1, 1, 5); } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixstoretodescriptor/nominal.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixstoretodescriptor/nominal.hlsl index dcbee120f5..dcd27e8c70 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixstoretodescriptor/nominal.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixstoretodescriptor/nominal.hlsl @@ -8,13 +8,13 @@ RWByteAddressBuffer outbuf; void main() { // CHECK-LABEL: define void @main() - // CHECK: call void @dx.op.linAlgMatrixStoreToDescriptor.mC4M5N4U1S2(i32 -2147483628, - // CHECK-SAME: %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, %dx.types.Handle %{{.*}}, i32 1, i32 1, i32 0, i32 4) + // CHECK: call void @dx.op.linAlgMatrixStoreToDescriptor.mC4M5N4U1S2(i32 331, + // CHECK-SAME: %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, %dx.types.Handle %{{.*}}, i32 1, i32 1, i32 0, i32 256) // CHECK-SAME: ; LinAlgMatrixStoreToDescriptor(matrix,handle,offset,stride,layout,align) // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC4M5N4U1S2, %dx.types.Handle, i32, i32, i32, i32) - // CHECK2-SAME: "(i32 409, %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, %dx.types.Handle {{.*}}, i32 1, i32 1, i32 0, i32 4) + // CHECK2-SAME: "(i32 409, %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, %dx.types.Handle {{.*}}, i32 1, i32 1, i32 0, i32 256) __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 5, 4, 1, 2)]] mat; - __builtin_LinAlg_FillMatrix(mat, 1); - __builtin_LinAlg_MatrixStoreToDescriptor(mat, outbuf, 1, 1, 0, 4); + dx::__builtin_LinAlg_FillMatrix(mat, true, 1); + dx::__builtin_LinAlg_MatrixStoreToDescriptor(mat, outbuf, 1, 1, 0, 256); } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixstoretomemory/nominal.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixstoretomemory/nominal.hlsl index 51b30ec0c2..2e21d6c9b9 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixstoretomemory/nominal.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixstoretomemory/nominal.hlsl @@ -9,15 +9,15 @@ groupshared float SharedArr[64]; void main() { // CHECK-LABEL: define void @main() - // CHECK: call void @dx.op.linAlgMatrixStoreToMemory.mC4M5N4U1S2.f32(i32 -2147483627, - // CHECK-SAME: %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, float addrspace(3)* getelementptr + // CHECK: call void @dx.op.linAlgMatrixStoreToMemory.mC9M5N4U1S2.f32(i32 332, + // CHECK-SAME: %dx.types.LinAlgMatrixC9M5N4U1S2 %{{.*}}, float addrspace(3)* getelementptr // CHECK-SAME: inbounds ([64 x float], [64 x float] addrspace(3)* @"\01?SharedArr@@3PAMA", - // CHECK-SAME: i32 0, i32 0), i32 1, i32 2, i32 3) ; LinAlgMatrixStoreToMemory(matrix,memory,offset,stride,layout) + // CHECK-SAME: i32 0, i32 0), i32 896, i32 48, i32 3) ; LinAlgMatrixStoreToMemory(matrix,memory,offset,stride,layout) - // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC4M5N4U1S2, [64 x float] addrspace(3)*, i32, i32, i32)" - // CHECK2-SAME: (i32 410, %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, [64 x float] addrspace(3)* @"\01?SharedArr@@3PAMA", - // CHECK2-SAME: i32 1, i32 2, i32 3) - __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 5, 4, 1, 2)]] mat; - __builtin_LinAlg_FillMatrix(mat, 1); - __builtin_LinAlg_MatrixStoreToMemory(mat, SharedArr, 1, 2, 3); + // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC9M5N4U1S2, [64 x float] addrspace(3)*, i32, i32, i32)" + // CHECK2-SAME: (i32 410, %dx.types.LinAlgMatrixC9M5N4U1S2 %{{.*}}, [64 x float] addrspace(3)* @"\01?SharedArr@@3PAMA", + // CHECK2-SAME: i32 896, i32 48, i32 3) + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(9, 5, 4, 1, 2)]] mat; + dx::__builtin_LinAlg_FillMatrix(mat, true, 1); + dx::__builtin_LinAlg_MatrixStoreToMemory(mat, SharedArr, 128 * 7, 16 * 3, 3); } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixstoretomemory/vector-array.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixstoretomemory/vector-array.hlsl new file mode 100644 index 0000000000..98ab7b2f0f --- /dev/null +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixstoretomemory/vector-array.hlsl @@ -0,0 +1,28 @@ +// REQUIRES: dxil-1-10 +// RUN: %dxc -T cs_6_10 -HV 202x -E main %s | FileCheck %s +// RUN: %dxc -T cs_6_10 -HV 202x -E main -fcgl %s | FileCheck %s --check-prefix=CHECK2 + +// The groupshared array may hold vectors of the matrix component type. The +// DXIL operation is overloaded on the array's element type, so the memory +// operand is a pointer to a vector. + +// CHECK: @"\01?SharedArr@@3PAV?$vector@M$03@@A" = external addrspace(3) global [64 x <4 x float>] +groupshared float4 SharedArr[64]; + +[numthreads(4,1,1)] +void main() { + // CHECK-LABEL: define void @main() + + // CHECK: call void @dx.op.linAlgMatrixStoreToMemory.mC9M5N4U1S2.v4f32(i32 332, + // CHECK-SAME: %dx.types.LinAlgMatrixC9M5N4U1S2 %{{.*}}, <4 x float> addrspace(3)* getelementptr + // CHECK-SAME: inbounds ([64 x <4 x float>], [64 x <4 x float>] addrspace(3)* + // CHECK-SAME: @"\01?SharedArr@@3PAV?$vector@M$03@@A", i32 0, i32 0), i32 128, i32 16, i32 3) + // CHECK-SAME: ; LinAlgMatrixStoreToMemory(matrix,memory,offset,stride,layout) + + // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.LinAlgMatrixC9M5N4U1S2, [64 x <4 x float>] addrspace(3)*, + // CHECK2-SAME: i32, i32, i32)"(i32 410, %dx.types.LinAlgMatrixC9M5N4U1S2 %{{.*}}, [64 x <4 x float>] addrspace(3)* + // CHECK2-SAME: @"\01?SharedArr@@3PAV?$vector@M$03@@A", i32 128, i32 16, i32 3) + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(9, 5, 4, 1, 2)]] mat; + dx::__builtin_LinAlg_FillMatrix(mat, true, 1); + dx::__builtin_LinAlg_MatrixStoreToMemory(mat, SharedArr, 128, 16, 3); +} diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixvectormultiply/nominal.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixvectormultiply/nominal.hlsl index fc9fd3ee00..25b42a4f16 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixvectormultiply/nominal.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixvectormultiply/nominal.hlsl @@ -2,20 +2,23 @@ // RUN: %dxc -T cs_6_10 -E main %s | FileCheck %s // RUN: %dxc -T cs_6_10 -E main -fcgl %s | FileCheck %s --check-prefix=CHECK2 +ByteAddressBuffer inbuf; + [numthreads(1,1,1)] void main() { // CHECK-LABEL: define void @main() - __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 5, 4, 1, 2)]] mat; - __builtin_LinAlg_FillMatrix(mat, 1); + // Matrix + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 4, 4, 0, 0)]] mat; + dx::__builtin_LinAlg_MatrixLoadFromDescriptor(mat, inbuf, 0, 0, 0, 128); float4 vec = {1,2,3,4}; float4 result; - // CHECK: call <4 x float> @dx.op.linAlgMatVecMul.v4f32.mC4M5N4U1S2.v4f32(i32 -2147483623, - // CHECK-SAME: %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, i1 true, <4 x float> , i32 1) ; LinAlgMatVecMul(matrix,isOutputSigned,inputVector,interpretation) + // CHECK: call <4 x float> @dx.op.linAlgMatVecMul.v4f32.mC4M4N4U0S0.v4f32(i32 336, + // CHECK-SAME: %dx.types.LinAlgMatrixC4M4N4U0S0 %{{.*}}, i1 true, <4 x float> , i32 9) ; LinAlgMatVecMul(matrix,isOutputSigned,inputVector,interpretation) - // CHECK2: call void @"dx.hl.op..void (i32, <4 x float>*, %dx.types.LinAlgMatrixC4M5N4U1S2, i1, <4 x float>, i32) - // CHECK2-SAME: "(i32 418, <4 x float>* %result, %dx.types.LinAlgMatrixC4M5N4U1S2 %{{.*}}, i1 true, <4 x float> %{{.*}}, i32 1) - __builtin_LinAlg_MatrixVectorMultiply(result, mat, true, vec, 1); + // CHECK2: call void @"dx.hl.op..void (i32, <4 x float>*, %dx.types.LinAlgMatrixC4M4N4U0S0, i1, <4 x float>, i32) + // CHECK2-SAME: "(i32 418, <4 x float>* %result, %dx.types.LinAlgMatrixC4M4N4U0S0 %{{.*}}, i1 true, <4 x float> %{{.*}}, i32 9) + dx::__builtin_LinAlg_MatrixVectorMultiply(result, mat, true, vec, 9); } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixvectormultiplyadd/nominal.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixvectormultiplyadd/nominal.hlsl index 8c745dbb71..2650adbdc6 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixvectormultiplyadd/nominal.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/matrixvectormultiplyadd/nominal.hlsl @@ -2,70 +2,71 @@ // RUN: %dxc -T cs_6_10 -E main %s | FileCheck %s // RUN: %dxc -T cs_6_10 -E main -fcgl %s | FileCheck %s --check-prefix=CHECK2 +ByteAddressBuffer inbuf; + [numthreads(1,1,1)] void main() { // CHECK-LABEL: define void @main() - __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(5, 3, 4, 0, 0)]] mat1; - __builtin_LinAlg_FillMatrix(mat1, 1); + + // Matrix + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(5, 4, 4, 0, 0)]] mat1; + dx::__builtin_LinAlg_MatrixLoadFromDescriptor(mat1, inbuf, 0, 0, 0, 128); float4 vec = {1,2,3,4}; float4 result = 0; - // CHECK: call <4 x float> @dx.op.linAlgMatVecMulAdd.v4f32.mC5M3N4U0S0.v4f32.v4f32(i32 -2147483622, - // CHECK-SAME: %dx.types.LinAlgMatrixC5M3N4U0S0 %{{.*}}, i1 true, <4 x float> , i32 1, <4 x float> zeroinitializer) + // CHECK: call <4 x float> @dx.op.linAlgMatVecMulAdd.v4f32.mC5M4N4U0S0.v4f32.v4f32(i32 337, + // CHECK-SAME: %dx.types.LinAlgMatrixC5M4N4U0S0 %{{.*}}, i1 true, <4 x float> , i32 9, <4 x float> zeroinitializer) // CHECK-SAME: ; LinAlgMatVecMulAdd(matrix,isOutputSigned,inputVector,inputInterpretation,biasVector) - // CHECK2: call void @"dx.hl.op..void (i32, <4 x float>*, %dx.types.LinAlgMatrixC5M3N4U0S0, i1, <4 x float>, - // CHECK2-SAME: i32, <4 x float>)"(i32 419, <4 x float>* %result, %dx.types.LinAlgMatrixC5M3N4U0S0 %{{[0-9]+}}, - // CHECK2-SAME: i1 true, <4 x float> %{{[0-9]+}}, i32 1, <4 x float> %{{[0-9]+}}) + // CHECK2: call void @"dx.hl.op..void (i32, <4 x float>*, %dx.types.LinAlgMatrixC5M4N4U0S0, i1, <4 x float>, + // CHECK2-SAME: i32, <4 x float>)"(i32 419, <4 x float>* %result, %dx.types.LinAlgMatrixC5M4N4U0S0 %{{[0-9]+}}, + // CHECK2-SAME: i1 true, <4 x float> %{{[0-9]+}}, i32 9, <4 x float> %{{[0-9]+}}) - __builtin_LinAlg_MatrixVectorMultiplyAdd(result, mat1, true, vec, 1, result); + dx::__builtin_LinAlg_MatrixVectorMultiplyAdd(result, mat1, true, vec, 9, result); - __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(5, 3, 4, 0, 0)]] mat2; - __builtin_LinAlg_FillMatrix(mat2, 2); double4 vec2 = {1,2,3,4}; double4 result2 = 0; - // CHECK: call <4 x double> @dx.op.linAlgMatVecMulAdd.v4f64.mC5M3N4U0S0.v4f64.v4f64(i32 -2147483622, - // CHECK-SAME: %dx.types.LinAlgMatrixC5M3N4U0S0 %{{.*}}, i1 true, <4 x double> , i32 1, <4 x double> zeroinitializer) + // CHECK: call <4 x double> @dx.op.linAlgMatVecMulAdd.v4f64.mC5M4N4U0S0.v4f64.v4f64(i32 337, + // CHECK-SAME: %dx.types.LinAlgMatrixC5M4N4U0S0 %{{.*}}, i1 true, <4 x double> , i32 10, <4 x double> zeroinitializer) // CHECK-SAME: ; LinAlgMatVecMulAdd(matrix,isOutputSigned,inputVector,inputInterpretation,biasVector) - // CHECK2: call void @"dx.hl.op..void (i32, <4 x double>*, %dx.types.LinAlgMatrixC5M3N4U0S0, i1, <4 x double>, - // CHECK2-SAME: i32, <4 x double>)"(i32 419, <4 x double>* %result2, %dx.types.LinAlgMatrixC5M3N4U0S0 %{{[0-9]+}}, - // CHECK2-SAME: i1 true, <4 x double> %{{[0-9]+}}, i32 1, <4 x double> %{{[0-9]+}}) + // CHECK2: call void @"dx.hl.op..void (i32, <4 x double>*, %dx.types.LinAlgMatrixC5M4N4U0S0, i1, <4 x double>, + // CHECK2-SAME: i32, <4 x double>)"(i32 419, <4 x double>* %result2, %dx.types.LinAlgMatrixC5M4N4U0S0 %{{[0-9]+}}, + // CHECK2-SAME: i1 true, <4 x double> %{{[0-9]+}}, i32 10, <4 x double> %{{[0-9]+}}) - __builtin_LinAlg_MatrixVectorMultiplyAdd(result2, mat2, true, vec2, 1, result2); + dx::__builtin_LinAlg_MatrixVectorMultiplyAdd(result2, mat1, true, vec2, 10, result2); - __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(5, 3, 4, 0, 0)]] mat3; - __builtin_LinAlg_FillMatrix(mat3, 3); vector vec3 = {1,2,3,4}; vector result3 = 0; - // CHECK: call <4 x i64> @dx.op.linAlgMatVecMulAdd.v4i64.mC5M3N4U0S0.v4i64.v4i64(i32 -2147483622, - // CHECK-SAME: %dx.types.LinAlgMatrixC5M3N4U0S0 %{{.*}}, i1 true, <4 x i64> , i32 1, <4 x i64> zeroinitializer) + // CHECK: call <4 x i64> @dx.op.linAlgMatVecMulAdd.v4i64.mC5M4N4U0S0.v4i64.v4i64(i32 337, + // CHECK-SAME: %dx.types.LinAlgMatrixC5M4N4U0S0 %{{.*}}, i1 true, <4 x i64> , i32 6, <4 x i64> zeroinitializer) // CHECK-SAME: ; LinAlgMatVecMulAdd(matrix,isOutputSigned,inputVector,inputInterpretation,biasVector) - // CHECK2: call void @"dx.hl.op..void (i32, <4 x i64>*, %dx.types.LinAlgMatrixC5M3N4U0S0, i1, <4 x i64>, - // CHECK2-SAME: i32, <4 x i64>)"(i32 419, <4 x i64>* %result3, %dx.types.LinAlgMatrixC5M3N4U0S0 %{{[0-9]+}}, - // CHECK2-SAME: i1 true, <4 x i64> %{{[0-9]+}}, i32 1, <4 x i64> %{{[0-9]+}}) + // CHECK2: call void @"dx.hl.op..void (i32, <4 x i64>*, %dx.types.LinAlgMatrixC5M4N4U0S0, i1, <4 x i64>, + // CHECK2-SAME: i32, <4 x i64>)"(i32 419, <4 x i64>* %result3, %dx.types.LinAlgMatrixC5M4N4U0S0 %{{[0-9]+}}, + // CHECK2-SAME: i1 true, <4 x i64> %{{[0-9]+}}, i32 6, <4 x i64> %{{[0-9]+}}) - __builtin_LinAlg_MatrixVectorMultiplyAdd(result3, mat3, true, vec3, 1, result3); + dx::__builtin_LinAlg_MatrixVectorMultiplyAdd(result3, mat1, true, vec3, 6, result3); + // Matrix __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 8, 8, 0, 0)]] mat4; - __builtin_LinAlg_FillMatrix(mat4, 4); + dx::__builtin_LinAlg_MatrixLoadFromDescriptor(mat4, inbuf, 0, 0, 0, 128); vector vec4 = 0; vector result4 = 0; - // CHECK: call <8 x i32> @dx.op.linAlgMatVecMulAdd.v8i32.mC4M8N8U0S0.v8i32.v8i32(i32 -2147483622, + // CHECK: call <8 x i32> @dx.op.linAlgMatVecMulAdd.v8i32.mC4M8N8U0S0.v8i32.v8i32(i32 337, // CHECK-SAME: %dx.types.LinAlgMatrixC4M8N8U0S0 %{{.*}}, i1 true, <8 x i32> zeroinitializer, - // CHECK-SAME: i32 1, <8 x i32> zeroinitializer) + // CHECK-SAME: i32 4, <8 x i32> zeroinitializer) // CHECK-SAME: ; LinAlgMatVecMulAdd(matrix,isOutputSigned,inputVector,inputInterpretation,biasVector) // CHECK2: call void @"dx.hl.op..void (i32, <8 x i32>*, %dx.types.LinAlgMatrixC4M8N8U0S0, i1, <8 x i32>, // CHECK2-SAME: i32, <8 x i32>)"(i32 419, <8 x i32>* %result4, %dx.types.LinAlgMatrixC4M8N8U0S0 %{{[0-9]+}}, - // CHECK2-SAME: i1 true, <8 x i32> %{{[0-9]+}}, i32 1, <8 x i32> %{{[0-9]+}}) + // CHECK2-SAME: i1 true, <8 x i32> %{{[0-9]+}}, i32 4, <8 x i32> %{{[0-9]+}}) - __builtin_LinAlg_MatrixVectorMultiplyAdd(result4, mat4, true, vec4, 1, result4); + dx::__builtin_LinAlg_MatrixVectorMultiplyAdd(result4, mat4, true, vec4, 4, result4); } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/vectoraccumulatetodescriptor/nominal.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/vectoraccumulatetodescriptor/nominal.hlsl index 787cd6adae..d99ae9d502 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/vectoraccumulatetodescriptor/nominal.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/builtins/vectoraccumulatetodescriptor/nominal.hlsl @@ -8,12 +8,12 @@ RWByteAddressBuffer outbuf; void main() { // CHECK-LABEL: define void @main() - // CHECK: call void @dx.op.linAlgVectorAccumulateToDescriptor.v4f32(i32 -2147483617, %dx.types.Handle %{{.*}}, i32 16, + // CHECK: call void @dx.op.linAlgVectorAccumulateToDescriptor.v4f32(i32 342, %dx.types.Handle %{{.*}}, i32 16, // CHECK-SAME: i32 64, <4 x float> ) // CHECK-SAME: ; LinAlgVectorAccumulateToDescriptor(handle,offset,align,vector) // CHECK2: call void @"dx.hl.op..void (i32, %dx.types.Handle, i32, i32, <4 x float>)" // CHECK2-SAME: (i32 423, %dx.types.Handle %{{.*}}, i32 16, i32 64, <4 x float> %{{.*}}) float4 vec = {9.0, 8.0, 7.0, 6.0}; - __builtin_LinAlg_VectorAccumulateToDescriptor(outbuf, 16, 64, vec); + dx::__builtin_LinAlg_VectorAccumulateToDescriptor(outbuf, 16, 64, vec); } diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/linalg-matrix-global.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/linalg-matrix-global.hlsl new file mode 100644 index 0000000000..31b29a9cbe --- /dev/null +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/linalg-matrix-global.hlsl @@ -0,0 +1,39 @@ +// REQUIRES: dxil-1-10 +// RUN: %dxc -T cs_6_10 -E main -fcgl %s | FileCheck %s +// RUN: %dxc -T cs_6_10 -E main %s | FileCheck %s --check-prefix=DXIL + +// Explicitly static LinAlg matrix globals are mutable module state, not +// constant buffer data. + +#include +using namespace dx::linalg; + +using MatrixTy = + Matrix; + +struct MatrixState { + MatrixTy Matrix; +}; + +static MatrixTy GlobalMatrix; +static MatrixTy GlobalMatrixArray[2]; +static MatrixState GlobalMatrixState; +RWByteAddressBuffer Output; + +[numthreads(1, 1, 1)] +void main() { + GlobalMatrix = MatrixTy::Splat(1.0f); + Output.Store(0, GlobalMatrix.Get(0)); +} + +// CHECK-NOT: dx.hl.subscript.cb +// CHECK: @GlobalMatrix = internal global +// CHECK-NOT: dx.hl.subscript.cb +// CHECK: bitcast {{.*}} @GlobalMatrix +// CHECK: call float {{.*}} @GlobalMatrix +// CHECK-NOT: dx.hl.subscript.cb + +// DXIL: call %dx.types.LinAlgMatrixC9M4N4U2S1 @dx.op.linAlgFillMatrix +// DXIL: call float @dx.op.linAlgMatrixGetElement +// DXIL-NOT: @dx.op.cbufferLoad diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/matrix-target-type-in-struct.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/matrix-target-type-in-struct.hlsl index a48c56f013..8b8c2b6418 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/matrix-target-type-in-struct.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/matrix-target-type-in-struct.hlsl @@ -8,7 +8,7 @@ class MyMatrix { static MyMatrix Splat(float Val) { MyMatrix Result; - __builtin_LinAlg_FillMatrix(Result.handle, Val); + dx::__builtin_LinAlg_FillMatrix(Result.handle, true, Val); return Result; } }; @@ -18,5 +18,5 @@ void main() { MyMatrix MatA = MyMatrix::Splat(1.0f); } -// CHECK: call %dx.types.LinAlgMatrixC9M4N4U0S1 @dx.op.linAlgFillMatrix.mC9M4N4U0S1.f32(i32 -2147483636, float 1.000000e+00) ; LinAlgFillMatrix(value) +// CHECK: call %dx.types.LinAlgMatrixC9M4N4U0S1 @dx.op.linAlgFillMatrix.mC9M4N4U0S1.f32(i32 323, i1 true, float 1.000000e+00) ; LinAlgFillMatrix(isInputSigned,value) // CHECK-NOT: @llvm.trap() diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/trim-target-types-metadata-compute.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/trim-target-types-metadata-compute.hlsl index 347c5daa18..c176299ab9 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/trim-target-types-metadata-compute.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/trim-target-types-metadata-compute.hlsl @@ -8,26 +8,26 @@ // return values and arguments of LinAlgMatrix operations. uint useMatrix1() { - // Matrix m; - __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 4, 5, 0, 0)]] mat1; + // Matrix m; + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 4, 5, 0, 2)]] mat1; // mat1 = Matrix::Splat(5); - __builtin_LinAlg_FillMatrix(mat1, 5); + dx::__builtin_LinAlg_FillMatrix(mat1, true, 5); - // Matrix m; - __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(5, 8, 8, 0, 0)]] mat2; + // Matrix m; + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(5, 8, 8, 0, 2)]] mat2; // mat2 = Matrix::Splat(1); - __builtin_LinAlg_FillMatrix(mat2, 1); + dx::__builtin_LinAlg_FillMatrix(mat2, true, 1); // return mat2.Length(); - return __builtin_LinAlg_MatrixLength(mat2); + return dx::__builtin_LinAlg_MatrixLength(mat2); } uint useMatrix2() { // Matrix m; __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(10, 2, 2, 1, 1)]] mat3; // mat3 = Matrix::Splat(5); - __builtin_LinAlg_FillMatrix(mat3, 5); + dx::__builtin_LinAlg_FillMatrix(mat3, true, 5); // return mat3.Length(); - return __builtin_LinAlg_MatrixLength(mat3); + return dx::__builtin_LinAlg_MatrixLength(mat3); } RWBuffer Out; @@ -38,6 +38,6 @@ void main() { } // CHECK: !dx.targetTypes = !{!{{[0-9]+}}, !{{[0-9]+}}} -// CHECK: !{{[0-9]+}} = !{%dx.types.LinAlgMatrixC4M4N5U0S0 undef, i32 4, i32 4, i32 5, i32 0, i32 0} -// CHECK: !{{[0-9]+}} = !{%dx.types.LinAlgMatrixC5M8N8U0S0 undef, i32 5, i32 8, i32 8, i32 0, i32 0} +// CHECK: !{{[0-9]+}} = !{%dx.types.LinAlgMatrixC4M4N5U0S2 undef, i32 4, i32 4, i32 5, i32 0, i32 2} +// CHECK: !{{[0-9]+}} = !{%dx.types.LinAlgMatrixC5M8N8U0S2 undef, i32 5, i32 8, i32 8, i32 0, i32 2} // CHECK-NOT: !{%dx.types.LinAlgMatrixC10M2N2U1S1 undef, i32 10, i32 2, i32 2, i32 1, i32 1} diff --git a/tools/clang/test/CodeGenDXIL/hlsl/linalg/trim-target-types-metadata-lib.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/linalg/trim-target-types-metadata-lib.hlsl index 35aa78380c..8f0cbc6658 100644 --- a/tools/clang/test/CodeGenDXIL/hlsl/linalg/trim-target-types-metadata-lib.hlsl +++ b/tools/clang/test/CodeGenDXIL/hlsl/linalg/trim-target-types-metadata-lib.hlsl @@ -21,21 +21,21 @@ void useMatrix3(); #ifdef LIB1 uint useMatrix1() { - // Matrix m; - __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 4, 5, 0, 0)]] mat1; + // Matrix m; + __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(4, 4, 5, 0, 2)]] mat1; // mat1 = Matrix::Splat(5); - __builtin_LinAlg_FillMatrix(mat1, 5); + dx::__builtin_LinAlg_FillMatrix(mat1, true, 5); // return mat1.Length(); - return __builtin_LinAlg_MatrixLength(mat1); + return dx::__builtin_LinAlg_MatrixLength(mat1); } uint useMatrix2() { // Matrix m; __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(10, 4, 4, 1, 1)]] mat2; // Matrix::Splat(1) - __builtin_LinAlg_FillMatrix(mat2, 1); + dx::__builtin_LinAlg_FillMatrix(mat2, true, 1); // return mat2.Length(); - return __builtin_LinAlg_MatrixLength(mat2); + return dx::__builtin_LinAlg_MatrixLength(mat2); } #endif @@ -47,7 +47,7 @@ void useMatrix3() { //Matrix m; __builtin_LinAlgMatrix [[__LinAlgMatrix_Attributes(5, 6, 6, 2, 2)]] mat3; // mat3 = Matrix::Splat(5); - __builtin_LinAlg_FillMatrix(mat3, 5); + dx::__builtin_LinAlg_FillMatrix(mat3, true, 5); } RWBuffer Out; @@ -75,7 +75,7 @@ void CSMain3() { // Target types in lib1 // LIB1: !dx.targetTypes = !{![[TT1:.*]], ![[TT2:.*]]} -// LIB1: ![[TT1]] = !{%dx.types.LinAlgMatrixC4M4N5U0S0 undef, i32 4, i32 4, i32 5, i32 0, i32 0} +// LIB1: ![[TT1]] = !{%dx.types.LinAlgMatrixC4M4N5U0S2 undef, i32 4, i32 4, i32 5, i32 0, i32 2} // LIB1: ![[TT2]] = !{%dx.types.LinAlgMatrixC10M4N4U1S1 undef, i32 10, i32 4, i32 4, i32 1, i32 1} // Target types in lib2 @@ -89,7 +89,7 @@ void CSMain3() { // CSMain2 uses one type of matrix // CSMAIN2: !dx.targetTypes = !{!{{[0-9]+}}} -// CSMAIN2: !{{[0-9]+}} = !{%dx.types.LinAlgMatrixC4M4N5U0S0 undef, i32 4, i32 4, i32 5, i32 0, i32 0} +// CSMAIN2: !{{[0-9]+}} = !{%dx.types.LinAlgMatrixC4M4N5U0S2 undef, i32 4, i32 4, i32 5, i32 0, i32 2} // CSMain3 uses two types of matrices // CSMAIN3: !dx.targetTypes = !{!{{[0-9]+}}, !{{[0-9]+}}} diff --git a/tools/clang/test/CodeGenDXIL/reflection/experimental_rdat.hlsl b/tools/clang/test/CodeGenDXIL/reflection/experimental_rdat.hlsl index a3f4c18813..44977d5e7e 100644 --- a/tools/clang/test/CodeGenDXIL/reflection/experimental_rdat.hlsl +++ b/tools/clang/test/CodeGenDXIL/reflection/experimental_rdat.hlsl @@ -1,17 +1,17 @@ // Note: Base this on highest the experimental version, or released+1. -// REQUIRES: dxil-1-10 -// RUN: %dxc %s -Tlib_6_10 -Vd -validator-version 0.0 -Fo %t +// REQUIRES: dxil-1-11 +// RUN: %dxc %s -Tlib_6_11 -Vd -validator-version 0.0 -Fo %t // RUN: %dxa %t -dumprdat | FileCheck %s -check-prefixes=CHECK,EXP -// RUN: %dxc %s -Tlib_6_10 -Fo %t +// RUN: %dxc %s -Tlib_6_11 -Fo %t // RUN: %dxa %t -dumprdat | FileCheck %s -check-prefixes=CHECK,EXP -// RUN: %dxc %s -Tlib_6_10 -validator-version 1.10 -Fo %t +// RUN: %dxc %s -Tlib_6_11 -validator-version 1.11 -Fo %t // RUN: %dxa %t -dumprdat | FileCheck %s -check-prefixes=CHECK,EXP // No experimental RDAT for released shader models even with default or latest // validator versions. -// RUN: %dxc %s -Tlib_6_9 -Fo %t +// RUN: %dxc %s -Tlib_6_10 -Fo %t // RUN: %dxa %t -dumprdat | FileCheck %s -check-prefixes=CHECK,NOEXP -// RUN: %dxc %s -Tlib_6_9 -validator-version 1.10 -Fo %t +// RUN: %dxc %s -Tlib_6_10 -validator-version 1.11 -Fo %t // RUN: %dxa %t -dumprdat | FileCheck %s -check-prefixes=CHECK,NOEXP // Make sure experimental RDAT is not emitted for released shader models, diff --git a/tools/clang/test/CodeGenDXIL/reflection/experimental_rdat_rel_sm.hlsl b/tools/clang/test/CodeGenDXIL/reflection/experimental_rdat_rel_sm.hlsl index bc582dca05..0d1508a16f 100644 --- a/tools/clang/test/CodeGenDXIL/reflection/experimental_rdat_rel_sm.hlsl +++ b/tools/clang/test/CodeGenDXIL/reflection/experimental_rdat_rel_sm.hlsl @@ -1,13 +1,19 @@ // Note: Add RUN lines for newer released shader models to this test when available. -// REQUIRES: dxil-1-9 +// REQUIRES: dxil-1-11 // RUN: %dxc %s -Tlib_6_x -Fo %t // RUN: %dxa %t -dumprdat | FileCheck %s -check-prefixes=CHECK,EXP -// RUN: %dxc %s -Tlib_6_9 -Vd -validator-version 0.0 -Fo %t +// RUN: %dxc %s -Tlib_6_10 -Vd -validator-version 0.0 -Fo %t // RUN: %dxa %t -dumprdat | FileCheck %s -check-prefixes=CHECK,EXP -// RUN: %dxc %s -Tlib_6_9 -Fo %t +// RUN: %dxc %s -Tlib_6_10 -Fo %t // RUN: %dxa %t -dumprdat | FileCheck %s -check-prefixes=CHECK,NOEXP -// RUN: %dxc %s -Tlib_6_9 -validator-version 1.9 -Fo %t +// RUN: %dxc %s -Tlib_6_10 -validator-version 1.10 -Fo %t // RUN: %dxa %t -dumprdat | FileCheck %s -check-prefixes=CHECK,NOEXP +// RUN: %dxc %s -Tlib_6_11 -Vd -validator-version 0.0 -Fo %t +// RUN: %dxa %t -dumprdat | FileCheck %s -check-prefixes=CHECK,EXP +// RUN: %dxc %s -Tlib_6_11 -Fo %t +// RUN: %dxa %t -dumprdat | FileCheck %s -check-prefixes=CHECK,EXP +// RUN: %dxc %s -Tlib_6_11 -validator-version 1.11 -Fo %t +// RUN: %dxa %t -dumprdat | FileCheck %s -check-prefixes=CHECK,EXP // Make sure experimental RDAT is not emitted for released shader models, // unless the validator version is 0.0 (no validation supported). Validator diff --git a/tools/clang/test/CodeGenSPIRV/cbuffer.namespace.hlsl b/tools/clang/test/CodeGenSPIRV/cbuffer.namespace.hlsl new file mode 100644 index 0000000000..8e755a2779 --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/cbuffer.namespace.hlsl @@ -0,0 +1,22 @@ +// RUN: %dxc -T ps_6_0 -E main -HV 202x -spirv -fcgl %s | FileCheck %s + +// CHECK-DAG: OpDecorate [[FIRST:%[^ ]+]] Binding 3 +// CHECK-DAG: OpDecorate [[SECOND:%[^ ]+]] Binding 4 +// CHECK-DAG: [[FIRST]] = OpVariable {{%[^ ]+}} Uniform +// CHECK-DAG: [[SECOND]] = OpVariable {{%[^ ]+}} Uniform + +namespace First { +cbuffer SceneConstants : register(b3) { + float Value; +} +} + +namespace Second { +cbuffer SceneConstants : register(b4) { + float Value; +} +} + +float4 main() : SV_Target { + return First::Value + Second::Value; +} diff --git a/tools/clang/test/CodeGenSPIRV/cbuffer.static.member.hlsl b/tools/clang/test/CodeGenSPIRV/cbuffer.static.member.hlsl new file mode 100644 index 0000000000..3f5884e905 --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/cbuffer.static.member.hlsl @@ -0,0 +1,34 @@ +// RUN: %dxc -T vs_6_0 -E main -fcgl %s -spirv | FileCheck %s + +// A `static` variable declared inside a cbuffer is an ordinary global variable, +// not a member of the buffer. It must be left out of the buffer's struct (it is +// not part of the layout) *and* it must not consume a member index, otherwise +// the access chains for the members declared after it are shifted, and the last +// one ends up out of bounds. + +// CHECK: OpMemberName %type_MyCBuffer 0 "a" +// CHECK: OpMemberName %type_MyCBuffer 1 "b" +// CHECK: OpMemberName %type_MyCBuffer 2 "c" +// CHECK-NOT: OpMemberName %type_MyCBuffer 3 + +// CHECK-DAG: %uint_10 = OpConstant %uint 10 +// CHECK-DAG: %uint_11 = OpConstant %uint 11 +// CHECK-DAG: %uint_12 = OpConstant %uint 12 + +// CHECK: %type_MyCBuffer = OpTypeStruct %uint %uint %uint + +cbuffer MyCBuffer { + uint a; + static const uint a_mode = 10; + uint b; + static const uint b_mode = 11; + uint c; + static const uint c_mode = 12; +}; + +float4 main() : SV_Position { +// CHECK: OpAccessChain %_ptr_Uniform_uint %MyCBuffer %int_0 +// CHECK: OpAccessChain %_ptr_Uniform_uint %MyCBuffer %int_1 +// CHECK: OpAccessChain %_ptr_Uniform_uint %MyCBuffer %int_2 + return float4(a + b + c, a_mode, b_mode, c_mode); +} diff --git a/tools/clang/test/CodeGenSPIRV/fn.auto.return.hlsl b/tools/clang/test/CodeGenSPIRV/fn.auto.return.hlsl new file mode 100644 index 0000000000..b66b267d61 --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/fn.auto.return.hlsl @@ -0,0 +1,45 @@ +// RUN: %dxc -T cs_6_0 -E main -HV 202x -fcgl %s -spirv | FileCheck %s + +// Test that the 'auto' keyword can be used as a function return type and +// that the deduced type is used correctly when targeting SPIR-V. + +// CHECK-DAG: [[INT:%[a-zA-Z0-9_]+]] = OpTypeInt 32 1 +// CHECK-DAG: [[FLOAT:%[a-zA-Z0-9_]+]] = OpTypeFloat 32 +// CHECK-DAG: [[V4FLOAT:%[a-zA-Z0-9_]+]] = OpTypeVector [[FLOAT]] 4 + +// Function 'SquareInt' must return int. +// CHECK-DAG: %SquareInt = OpFunction [[INT]] None +// CHECK-DAG: %SquareFloat = OpFunction [[FLOAT]] None +// CHECK-DAG: %Scale = OpFunction [[V4FLOAT]] None +// CHECK-DAG: %WriteOutput = OpFunction %void None +// CHECK-DAG: %Sum = OpFunction [[FLOAT]] None + +RWBuffer output : register(u0); + +auto SquareInt(int x) { + return x * x; +} + +auto SquareFloat(float x) { + return x * x; +} + +auto Scale(float4 v, float s) { + return v * s; +} + +template +auto Sum(T L, T R) { + return L + R; +} + +auto WriteOutput(uint i, float v) { + output[i] = v; +} + +[numthreads(1,1,1)] +void main() { + float4 v = float4(1, 2, 3, 4); + float4 s = Scale(v, 0.5f); + WriteOutput(0, (float)SquareInt(3) + Sum(SquareFloat(2.5f), s.x)); +} diff --git a/tools/clang/test/CodeGenSPIRV/groupshared.init.warning.hlsl b/tools/clang/test/CodeGenSPIRV/groupshared.init.warning.hlsl index c49534948b..5a48eade22 100644 --- a/tools/clang/test/CodeGenSPIRV/groupshared.init.warning.hlsl +++ b/tools/clang/test/CodeGenSPIRV/groupshared.init.warning.hlsl @@ -1,11 +1,15 @@ -// RUN: %dxc -T cs_6_0 -E main -spirv %s 2>&1 | FileCheck %s +// RUN: %dxc -T cs_6_0 -E main -spirv -verify %s groupshared uint testing = 0; +// expected-warning@-1 {{initializer of 'groupshared' variable will be ignored}} + +static groupshared uint staticTesting = 1; +// expected-warning@-1 {{initializer of 'groupshared' variable will be ignored}} [numthreads(64, 1, 1)] void main(uint local_thread_id_flat : SV_GroupIndex) { - InterlockedAdd(testing, 1); + InterlockedAdd(testing, staticTesting); GroupMemoryBarrierWithGroupSync(); if (local_thread_id_flat == 0) { @@ -14,6 +18,3 @@ void main(uint local_thread_id_flat : SV_GroupIndex) { } } } - -// CHECK: warning: Initializer of external global will be ignored -// CHECK-NEXT: groupshared uint testing = 0; \ No newline at end of file diff --git a/tools/clang/test/CodeGenSPIRV/implicit.global.ubo.hlsl b/tools/clang/test/CodeGenSPIRV/implicit.global.ubo.hlsl index e19376b895..a011be6d7d 100644 --- a/tools/clang/test/CodeGenSPIRV/implicit.global.ubo.hlsl +++ b/tools/clang/test/CodeGenSPIRV/implicit.global.ubo.hlsl @@ -1,4 +1,5 @@ -// RUN: %dxc -T ps_6_0 -E main %s -spirv | FileCheck %s +// RUN: %dxc -T ps_6_0 -E main -Werror %s -spirv | FileCheck %s +// RUN: %dxc -T ps_6_0 -E main -HV 202x %s -spirv | FileCheck %s // This test checks that the specialization constant and push constants are not // included in the implicit global ubo. diff --git a/tools/clang/test/CodeGenSPIRV/intrinsics.vkrawbufferload.64bit-align.hlsl b/tools/clang/test/CodeGenSPIRV/intrinsics.vkrawbufferload.64bit-align.hlsl new file mode 100644 index 0000000000..ea200ad153 --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/intrinsics.vkrawbufferload.64bit-align.hlsl @@ -0,0 +1,154 @@ +// RUN: %dxc -T cs_6_2 -E main -enable-16bit-types -fcgl %s -spirv | FileCheck %s + +// Test that vk::RawBufferLoad/Store with 64-bit types uses alignment 8 +// when no explicit alignment is specified. + +struct StructWith64BitMember { + uint64_t member; +}; + +struct StructWithDoubleMember { + double member; +}; + +// Mixes of 16-bit, 32-bit and 64-bit scalar members. The required alignment is +// the largest scalar alignment within the structure. +struct StructWithMixedScalars { + uint16_t a; + uint b; + uint64_t c; +}; + +// A 16-bit/32-bit mix without any 64-bit member: the largest scalar alignment +// is 4, so alignment 4 is used. +struct StructWith16And32BitScalars { + uint16_t a; + float b; +}; + +// A structure with only 16-bit members. The largest scalar alignment is 2, so +// alignment 2 is used: nothing in the Vulkan spec requires a larger minimum. +struct StructWithOnly16BitScalars { + uint16_t a; + half b; +}; + +// A structure containing vectors of 16-bit, 32-bit and 64-bit elements. The +// 64-bit vector forces alignment 8. +struct StructWithMixedVectors { + half2 a; + float3 b; + double2 c; +}; + +// A structure containing matrices. The 64-bit matrix forces alignment 8. +struct StructWithMixedMatrices { + float2x2 a; + double2x2 b; +}; + +uint64_t Address; + +[numthreads(1, 1, 1)] +void main() { + // CHECK: [[addr:%[0-9]+]] = OpLoad %ulong + // CHECK: [[buf:%[0-9]+]] = OpBitcast %_ptr_PhysicalStorageBuffer_ulong + // CHECK-NEXT: [[load:%[0-9]+]] = OpLoad %ulong [[buf]] Aligned 8 + uint64_t scalar = vk::RawBufferLoad(Address); + + // CHECK: [[buf_1:%[0-9]+]] = OpBitcast %_ptr_PhysicalStorageBuffer_double + // CHECK-NEXT: [[load_1:%[0-9]+]] = OpLoad %double [[buf_1]] Aligned 8 + double dbl = vk::RawBufferLoad(Address); + + // CHECK: [[buf_2:%[0-9]+]] = OpBitcast %_ptr_PhysicalStorageBuffer_StructWith64BitMember + // CHECK-NEXT: [[load_2:%[0-9]+]] = OpLoad %StructWith64BitMember{{[^ ]*}} [[buf_2]] Aligned 8 + StructWith64BitMember s1 = vk::RawBufferLoad(Address); + + // CHECK: [[buf_3:%[0-9]+]] = OpBitcast %_ptr_PhysicalStorageBuffer_StructWithDoubleMember + // CHECK-NEXT: [[load_3:%[0-9]+]] = OpLoad %StructWithDoubleMember{{[^ ]*}} [[buf_3]] Aligned 8 + StructWithDoubleMember s2 = vk::RawBufferLoad(Address); + + // Stores should also use alignment 8 for 64-bit types. + // CHECK: [[buf_4:%[0-9]+]] = OpBitcast %_ptr_PhysicalStorageBuffer_ulong + // CHECK-NEXT: OpStore [[buf_4]] {{%[0-9]+}} Aligned 8 + vk::RawBufferStore(Address, scalar); + + // CHECK: [[buf_5:%[0-9]+]] = OpBitcast %_ptr_PhysicalStorageBuffer_double + // CHECK-NEXT: OpStore [[buf_5]] {{%[0-9]+}} Aligned 8 + vk::RawBufferStore(Address, dbl); + + // CHECK: [[buf_6:%[0-9]+]] = OpBitcast %_ptr_PhysicalStorageBuffer_StructWith64BitMember + // CHECK: OpStore [[buf_6]] {{%[0-9]+}} Aligned 8 + vk::RawBufferStore(Address, s1); + + // CHECK: [[buf_7:%[0-9]+]] = OpBitcast %_ptr_PhysicalStorageBuffer_StructWithDoubleMember + // CHECK: OpStore [[buf_7]] {{%[0-9]+}} Aligned 8 + vk::RawBufferStore(Address, s2); + + // A structure mixing 16-bit, 32-bit and 64-bit scalars uses alignment 8 + // because of its 64-bit member. + // CHECK: [[buf_8:%[0-9]+]] = OpBitcast %_ptr_PhysicalStorageBuffer_StructWithMixedScalars + // CHECK-NEXT: [[load_8:%[0-9]+]] = OpLoad %StructWithMixedScalars{{[^ ]*}} [[buf_8]] Aligned 8 + StructWithMixedScalars s3 = vk::RawBufferLoad(Address); + + // A structure mixing only 16-bit and 32-bit scalars uses alignment 4. + // CHECK: [[buf_9:%[0-9]+]] = OpBitcast %_ptr_PhysicalStorageBuffer_StructWith16And32BitScalars + // CHECK-NEXT: [[load_9:%[0-9]+]] = OpLoad %StructWith16And32BitScalars{{[^ ]*}} [[buf_9]] Aligned 4 + StructWith16And32BitScalars s4 = vk::RawBufferLoad(Address); + + // A structure with only 16-bit scalars has scalar alignment 2, which is the + // minimum required by the Vulkan spec for such an access. + // CHECK: [[buf_10:%[0-9]+]] = OpBitcast %_ptr_PhysicalStorageBuffer_StructWithOnly16BitScalars + // CHECK-NEXT: [[load_10:%[0-9]+]] = OpLoad %StructWithOnly16BitScalars{{[^ ]*}} [[buf_10]] Aligned 2 + StructWithOnly16BitScalars s5 = vk::RawBufferLoad(Address); + + // A structure containing 16-bit, 32-bit and 64-bit vectors uses alignment 8 + // because of its 64-bit vector member. + // CHECK: [[buf_11:%[0-9]+]] = OpBitcast %_ptr_PhysicalStorageBuffer_StructWithMixedVectors + // CHECK-NEXT: [[load_11:%[0-9]+]] = OpLoad %StructWithMixedVectors{{[^ ]*}} [[buf_11]] Aligned 8 + StructWithMixedVectors s6 = vk::RawBufferLoad(Address); + + // A structure containing 32-bit and 64-bit matrices uses alignment 8 because + // of its 64-bit matrix member. + // CHECK: [[buf_12:%[0-9]+]] = OpBitcast %_ptr_PhysicalStorageBuffer_StructWithMixedMatrices + // CHECK-NEXT: [[load_12:%[0-9]+]] = OpLoad %StructWithMixedMatrices{{[^ ]*}} [[buf_12]] Aligned 8 + StructWithMixedMatrices s7 = vk::RawBufferLoad(Address); + + // Stores use the same computed alignments as loads. + // CHECK: [[buf_13:%[0-9]+]] = OpBitcast %_ptr_PhysicalStorageBuffer_StructWithMixedScalars + // CHECK: OpStore [[buf_13]] {{%[0-9]+}} Aligned 8 + vk::RawBufferStore(Address, s3); + + // CHECK: [[buf_14:%[0-9]+]] = OpBitcast %_ptr_PhysicalStorageBuffer_StructWith16And32BitScalars + // CHECK: OpStore [[buf_14]] {{%[0-9]+}} Aligned 4 + vk::RawBufferStore(Address, s4); + + // CHECK: [[buf_15:%[0-9]+]] = OpBitcast %_ptr_PhysicalStorageBuffer_StructWithOnly16BitScalars + // CHECK: OpStore [[buf_15]] {{%[0-9]+}} Aligned 2 + vk::RawBufferStore(Address, s5); + + // CHECK: [[buf_16:%[0-9]+]] = OpBitcast %_ptr_PhysicalStorageBuffer_StructWithMixedVectors + // CHECK: OpStore [[buf_16]] {{%[0-9]+}} Aligned 8 + vk::RawBufferStore(Address, s6); + + // CHECK: [[buf_17:%[0-9]+]] = OpBitcast %_ptr_PhysicalStorageBuffer_StructWithMixedMatrices + // CHECK: OpStore [[buf_17]] {{%[0-9]+}} Aligned 8 + vk::RawBufferStore(Address, s7); + + // A 16-bit scalar requires only 2-byte alignment. + // CHECK: [[buf_18:%[0-9]+]] = OpBitcast %_ptr_PhysicalStorageBuffer_ushort + // CHECK-NEXT: [[load_18:%[0-9]+]] = OpLoad %ushort [[buf_18]] Aligned 2 + uint16_t u16 = vk::RawBufferLoad(Address); + + // CHECK: [[buf_19:%[0-9]+]] = OpBitcast %_ptr_PhysicalStorageBuffer_half + // CHECK-NEXT: [[load_19:%[0-9]+]] = OpLoad %half [[buf_19]] Aligned 2 + half h = vk::RawBufferLoad(Address); + + // CHECK: [[buf_20:%[0-9]+]] = OpBitcast %_ptr_PhysicalStorageBuffer_ushort + // CHECK: OpStore [[buf_20]] {{%[0-9]+}} Aligned 2 + vk::RawBufferStore(Address, u16); + + // CHECK: [[buf_21:%[0-9]+]] = OpBitcast %_ptr_PhysicalStorageBuffer_half + // CHECK: OpStore [[buf_21]] {{%[0-9]+}} Aligned 2 + vk::RawBufferStore(Address, h); +} diff --git a/tools/clang/test/CodeGenSPIRV/intrinsics.vkrawbufferload.hlsl b/tools/clang/test/CodeGenSPIRV/intrinsics.vkrawbufferload.hlsl index c2892cfc29..9057c66cbe 100644 --- a/tools/clang/test/CodeGenSPIRV/intrinsics.vkrawbufferload.hlsl +++ b/tools/clang/test/CodeGenSPIRV/intrinsics.vkrawbufferload.hlsl @@ -14,7 +14,7 @@ struct BufferData { using MyInt = vk::SpirvType< /*spv::OpTypeInt*/21, - 1,1, // size and alignment + 2,2, // size and alignment (a 16-bit int is 2 bytes) vk::Literal >, // bits vk::Literal > // signed >; @@ -60,7 +60,7 @@ float4 main() : SV_Target0 { d = vk::RawBufferLoad(0); // CHECK: [[buf:%[0-9]+]] = OpBitcast %_ptr_PhysicalStorageBuffer_spirvIntrinsicType %ulong_0 - // CHECK-NEXT: [[load:%[0-9]+]] = OpLoad %spirvIntrinsicType [[buf]] Aligned 4 + // CHECK-NEXT: [[load:%[0-9]+]] = OpLoad %spirvIntrinsicType [[buf]] Aligned 2 // CHECK-NEXT: OpStore %mi [[load]] MyInt mi = vk::RawBufferLoad(0); diff --git a/tools/clang/test/CodeGenSPIRV/linalg.builtins.error.hlsl b/tools/clang/test/CodeGenSPIRV/linalg.builtins.error.hlsl new file mode 100644 index 0000000000..4bbc7fee70 --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/linalg.builtins.error.hlsl @@ -0,0 +1,8 @@ +// RUN: not %dxc -T cs_6_10 -spirv %s 2>&1 | FileCheck %s + +// CHECK: error: __builtin_LinAlg_MatrixQueryAccumulatorLayout intrinsic function unimplemented + +[numthreads(1, 1, 1)] +void main() { + uint layout = dx::__builtin_LinAlg_MatrixQueryAccumulatorLayout(); +} diff --git a/tools/clang/test/CodeGenSPIRV/resource-heap-ext-texture.hlsl b/tools/clang/test/CodeGenSPIRV/resource-heap-ext-texture.hlsl index 1641d1f038..a6d6f29ea2 100644 --- a/tools/clang/test/CodeGenSPIRV/resource-heap-ext-texture.hlsl +++ b/tools/clang/test/CodeGenSPIRV/resource-heap-ext-texture.hlsl @@ -1,5 +1,10 @@ // RUN: %dxc -T cs_6_6 -E main -fspv-use-descriptor-heap -spirv %s | FileCheck %s +// The validator now requires explicit layout for UniformConstant when +// SPV_EXT_descriptor_heap is used (KhronosGroup/SPIRV-Tools#6792). DXC's +// descriptor heap support does not yet emit ArrayStride. +// XFAIL: * + // CHECK: OpCapability DescriptorHeapEXT // CHECK: OpExtension "SPV_EXT_descriptor_heap" diff --git a/tools/clang/test/CodeGenSPIRV/static.assert.hlsl b/tools/clang/test/CodeGenSPIRV/static.assert.hlsl new file mode 100644 index 0000000000..5b4196bbf2 --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/static.assert.hlsl @@ -0,0 +1,21 @@ +// RUN: %dxc -T ps_6_0 -E main -HV 202x -spirv %s | FileCheck %s + +static_assert(1 == 1, "translation unit"); +static_assert(sizeof(float) == 4); + +namespace N { +static_assert(2 + 2 == 4, "namespace"); +} + +struct S { + static_assert(sizeof(float) == 4, "record"); + float Value; +}; + +float main() : SV_Target { + static_assert(sizeof(S) == 4, "function"); + static_assert(1 < 2); + return 0; +} + +// CHECK: OpEntryPoint Fragment %main "main" diff --git a/tools/clang/test/CodeGenSPIRV/type.rayquery.user-defined-shadow.hlsl b/tools/clang/test/CodeGenSPIRV/type.rayquery.user-defined-shadow.hlsl new file mode 100644 index 0000000000..95530d3b85 --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/type.rayquery.user-defined-shadow.hlsl @@ -0,0 +1,36 @@ +// RUN: %dxc -T cs_6_6 -E MainRayGenShader -fcgl -spirv %s | FileCheck %s --implicit-check-not=OpTypeRayQueryKHR + +// A user-defined struct named "RayQuery" that shadows the reserved intrinsic +// name must be lowered as an ordinary struct, not as the opaque ray query +// type. Previously this crashed the SPIR-V backend. +// See https://github.com/microsoft/DirectXShaderCompiler/issues/8601 + +namespace UnifiedRT { +struct RayQuery { + float4 foo; +}; +} // namespace UnifiedRT + +// The shadowing struct is lowered to an ordinary struct with a float4 field, +// and the local variable uses that struct type in the Function storage class. +// CHECK: %RayQuery = OpTypeStruct %v4float +// CHECK: %_ptr_Function_RayQuery = OpTypePointer Function %RayQuery +// CHECK: %rayQuery = OpVariable %_ptr_Function_RayQuery Function + +// It must not be lowered to the opaque ray query type. The absence of +// OpTypeRayQueryKHR anywhere in the module is checked by the +// --implicit-check-not on the FileCheck invocation above. + +StructuredBuffer _UnifiedRT_DispatchDims; + +[numthreads(128, 1, 1)] +void MainRayGenShader(in uint3 gidx : SV_DispatchThreadID, + in uint lidx : SV_GroupIndex) { + if (gidx.x >= _UnifiedRT_DispatchDims[0] || + gidx.y >= _UnifiedRT_DispatchDims[1] || + gidx.z >= _UnifiedRT_DispatchDims[2]) + return; + + UnifiedRT::RayQuery rayQuery; + rayQuery.foo = float4(1.0, 1.0, 1.0, 1.0); +} diff --git a/tools/clang/test/CodeGenSPIRV/type.rayquery.user-defined-shadow.template.hlsl b/tools/clang/test/CodeGenSPIRV/type.rayquery.user-defined-shadow.template.hlsl new file mode 100644 index 0000000000..d1023e856c --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/type.rayquery.user-defined-shadow.template.hlsl @@ -0,0 +1,34 @@ +// RUN: %dxc -T cs_6_6 -E MainRayGenShader -HV 2021 -fcgl -spirv %s | FileCheck %s --implicit-check-not=OpTypeRayQueryKHR + +// A user-defined class template named "RayQuery" that shadows the reserved +// intrinsic name must be lowered as an ordinary struct, not as the opaque ray +// query type. The intrinsic is itself a class template, so detecting it by +// name and specialization kind alone also misclassifies this case. +// See https://github.com/microsoft/DirectXShaderCompiler/issues/8601 + +namespace UnifiedRT { +template struct RayQuery { + T foo; +}; +} // namespace UnifiedRT + +// The shadowing template instance is lowered to an ordinary struct with a +// float4 field, and the local variable uses that struct type in the Function +// storage class. +// CHECK: %RayQuery = OpTypeStruct %v4float +// CHECK: %_ptr_Function_RayQuery = OpTypePointer Function %RayQuery +// CHECK: %rayQuery = OpVariable %_ptr_Function_RayQuery Function + +StructuredBuffer _UnifiedRT_DispatchDims; + +[numthreads(128, 1, 1)] +void MainRayGenShader(in uint3 gidx : SV_DispatchThreadID, + in uint lidx : SV_GroupIndex) { + if (gidx.x >= _UnifiedRT_DispatchDims[0] || + gidx.y >= _UnifiedRT_DispatchDims[1] || + gidx.z >= _UnifiedRT_DispatchDims[2]) + return; + + UnifiedRT::RayQuery rayQuery; + rayQuery.foo = float4(1.0, 1.0, 1.0, 1.0); +} diff --git a/tools/clang/test/CodeGenSPIRV/var.globals.error.hlsl b/tools/clang/test/CodeGenSPIRV/var.globals.error.hlsl index 0f7adb1206..526898f15c 100644 --- a/tools/clang/test/CodeGenSPIRV/var.globals.error.hlsl +++ b/tools/clang/test/CodeGenSPIRV/var.globals.error.hlsl @@ -1,8 +1,9 @@ // RUN: not %dxc -T vs_6_0 -E main -fcgl %s -spirv 2>&1 | FileCheck %s - +// Note: this test uses FileCheck instead of -verify because the error +// diagnostic comes from the code generation layer instead of sema. [[vk::binding(10, 2)]] float4 gVec = 1.0; float4 main() : A { return gVec; } -// CHECK: :3:38: warning: variable 'gVec' will be placed in $Globals so initializer ignored -// CHECK: :3:3: error: variable 'gVec' will be placed in $Globals so cannot have vk::binding attribute +// CHECK: :4:38: warning: initializer for a variable in a cbuffer will be ignored +// CHECK: :4:3: error: variable 'gVec' will be placed in $Globals so cannot have vk::binding attribute diff --git a/tools/clang/test/CodeGenSPIRV/var.init.cbuffer.hlsl b/tools/clang/test/CodeGenSPIRV/var.init.cbuffer.hlsl index 1f18dcaef6..3f2cdf50f9 100644 --- a/tools/clang/test/CodeGenSPIRV/var.init.cbuffer.hlsl +++ b/tools/clang/test/CodeGenSPIRV/var.init.cbuffer.hlsl @@ -1,13 +1,10 @@ -// RUN: %dxc -T vs_6_0 -E main -fcgl %s -spirv 2>&1 | FileCheck %s +// RUN: %dxc -T vs_6_0 -E main -verify %s -spirv cbuffer MyCBuffer { - float a = 1.0; - float4 b = 2.0; + float a = 1.0; // expected-warning{{initializer for a variable in a cbuffer will be ignored}} + float4 b = 2.0; // expected-warning{{initializer for a variable in a cbuffer will be ignored}} }; float main() : A { return 1.0; } - -// CHECK: :4:15: warning: cbuffer member initializer ignored since no Vulkan equivalent -// CHECK: :5:16: warning: cbuffer member initializer ignored since no Vulkan equivalent diff --git a/tools/clang/test/CodeGenSPIRV/var.init.tbuffer.hlsl b/tools/clang/test/CodeGenSPIRV/var.init.tbuffer.hlsl index c727c7d148..b41b98a6ee 100644 --- a/tools/clang/test/CodeGenSPIRV/var.init.tbuffer.hlsl +++ b/tools/clang/test/CodeGenSPIRV/var.init.tbuffer.hlsl @@ -1,13 +1,10 @@ -// RUN: %dxc -T vs_6_0 -E main -fcgl %s -spirv 2>&1 | FileCheck %s +// RUN: %dxc -T vs_6_0 -E main -verify %s -spirv tbuffer MyTBuffer { - float a = 1.0; - float4 b = 2.0; + float a = 1.0; //expected-warning{{initializer for a variable in a tbuffer will be ignored}} + float4 b = 2.0; //expected-warning{{initializer for a variable in a tbuffer will be ignored}} }; float main() : A { return 1.0; } - -// CHECK: :4:15: warning: tbuffer member initializer ignored since no Vulkan equivalent -// CHECK: :5:16: warning: tbuffer member initializer ignored since no Vulkan equivalent diff --git a/tools/clang/test/CodeGenSPIRV/var.init.warning.ignored.hlsl b/tools/clang/test/CodeGenSPIRV/var.init.warning.ignored.hlsl index 5ba946587c..308cc7e7f2 100644 --- a/tools/clang/test/CodeGenSPIRV/var.init.warning.ignored.hlsl +++ b/tools/clang/test/CodeGenSPIRV/var.init.warning.ignored.hlsl @@ -1,4 +1,4 @@ -// RUN: %dxc -T vs_6_0 -E main -Wno-vk-ignored-features -fcgl %s -spirv 2>&1 | FileCheck %s +// RUN: %dxc -T vs_6_0 -E main -Wno-vk-ignored-features -Wno-hlsl-buffer-initializer -fcgl %s -spirv 2>&1 | FileCheck %s cbuffer MyCBuffer { float a = 1.0; diff --git a/tools/clang/test/CodeGenSPIRV/variadic.templates.basic.hlsl b/tools/clang/test/CodeGenSPIRV/variadic.templates.basic.hlsl new file mode 100644 index 0000000000..764c50b94b --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/variadic.templates.basic.hlsl @@ -0,0 +1,41 @@ +// RUN: %dxc -E main -T ps_6_0 -HV 202x -fcgl %s -spirv | FileCheck %s + +// Verify SPIR-V code generation for function parameter packs, pack expansions, +// and sizeof...(). + +template +T Sum(T First) { + return First; +} + +template +T Sum(T First, U Second, Rest... Others) { + return First + Sum(Second, Others...); +} + +template +uint CountArgs(Args... args) { + return sizeof...(Args); +} + +// CHECK-LABEL: %src_main = OpFunction %float None +// CHECK: OpFunctionCall %float %Sum +// CHECK: OpFunctionCall %uint %CountArgs +// CHECK-LABEL: %Sum = OpFunction %float None +// CHECK: OpFunctionCall %float %Sum_0 +// CHECK-LABEL: %CountArgs = OpFunction %uint None +// CHECK-NEXT: %args = OpFunctionParameter +// CHECK-NEXT: %args_0 = OpFunctionParameter +// CHECK-NEXT: %args_1 = OpFunctionParameter +// CHECK: OpReturnValue %uint_3 +// CHECK-LABEL: %Sum_0 = OpFunction %float None +// CHECK: OpFunctionCall %float %Sum_1 +// CHECK-LABEL: %Sum_1 = OpFunction %float None +// CHECK: OpFunctionCall %float %Sum_2 +// CHECK-LABEL: %Sum_2 = OpFunction %float None +float main() : SV_Target { + float total = Sum(1.0, 2.0, 3.0, 4.0); + // Keep CountArgs in the unoptimized SPIR-V without changing the result. + total += 0 * (float)CountArgs(1, 2, 3); + return total; +} diff --git a/tools/clang/test/CodeGenSPIRV/variadic.templates.builtin.hlsl b/tools/clang/test/CodeGenSPIRV/variadic.templates.builtin.hlsl new file mode 100644 index 0000000000..b6aa079025 --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/variadic.templates.builtin.hlsl @@ -0,0 +1,31 @@ +// RUN: %dxc -E main -T ps_6_0 -HV 202x -fcgl %s -spirv | FileCheck %s + +// Verify pack expansion into HLSL vector and matrix templates. + +template +vector MakeVector(T First, Rest... Others) { + return vector(First, Others...); +} + +template +struct MatrixWrapper { + matrix M; +}; + +// CHECK: OpName %MatrixWrapper "MatrixWrapper" +// CHECK: OpMemberName %MatrixWrapper 0 "M" +// CHECK: OpName %MakeVector "MakeVector" + +// CHECK-LABEL: %src_main = OpFunction %v4float +float4 main(float4 a : A) : SV_Target { + // CHECK: OpFunctionCall %v4float %MakeVector + vector v = MakeVector(a.x, a.y, a.z, a.w); + + MatrixWrapper mw; + // CHECK: OpCompositeConstruct %mat2v2float + mw.M = matrix(v.x, v.y, v.z, v.w); + + return float4(mw.M._11, mw.M._22, v.z, v.w); +} + +// CHECK-LABEL: %MakeVector = OpFunction %v4float diff --git a/tools/clang/test/CodeGenSPIRV/variadic.templates.initlist-scalarize.hlsl b/tools/clang/test/CodeGenSPIRV/variadic.templates.initlist-scalarize.hlsl new file mode 100644 index 0000000000..d65bec15a7 --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/variadic.templates.initlist-scalarize.hlsl @@ -0,0 +1,88 @@ +// RUN: %dxc -E main -T ps_6_0 -HV 202x -fcgl %s -spirv | FileCheck %s + +// Verify that pack expansions and equivalent explicit initializers produce +// the expected SPIR-V composite structure. + +struct PairOf2 { + float2 lo; + float2 hi; +}; + +template +float4 PackVectorMixed(Ts... vals) { + float4 v = { vals... }; + return v; +} +float4 ManualVectorMixed(float2 a, float2 b) { + float4 v = { a, b }; + return v; +} + +template +float2 PackArrayOverflow(Ts... vals) { + float2 arr[2] = { vals... }; + return arr[0] + arr[1]; +} +float2 ManualArrayOverflow(float a, float b, float c, float d) { + float2 arr[2] = { a, b, c, d }; + return arr[0] + arr[1]; +} + +template +PairOf2 PackStruct(Ts... vals) { + PairOf2 s = { vals... }; + return s; +} +PairOf2 ManualStruct(float2 a, float2 b) { + PairOf2 s = { a, b }; + return s; +} + +// CHECK-LABEL: %PackVectorMixed = OpFunction %v4float +// CHECK: [[PACK_V0:%[0-9]+]] = OpCompositeExtract %float {{%[0-9]+}} 0 +// CHECK: [[PACK_V1:%[0-9]+]] = OpCompositeExtract %float {{%[0-9]+}} 1 +// CHECK: [[PACK_V2:%[0-9]+]] = OpCompositeExtract %float {{%[0-9]+}} 0 +// CHECK: [[PACK_V3:%[0-9]+]] = OpCompositeExtract %float {{%[0-9]+}} 1 +// CHECK: OpCompositeConstruct %v4float [[PACK_V0]] [[PACK_V1]] +// CHECK-SAME: [[PACK_V2]] [[PACK_V3]] +// CHECK-LABEL: %ManualVectorMixed = OpFunction %v4float +// CHECK: [[MANUAL_V0:%[0-9]+]] = OpCompositeExtract %float {{%[0-9]+}} 0 +// CHECK: [[MANUAL_V1:%[0-9]+]] = OpCompositeExtract %float {{%[0-9]+}} 1 +// CHECK: [[MANUAL_V2:%[0-9]+]] = OpCompositeExtract %float {{%[0-9]+}} 0 +// CHECK: [[MANUAL_V3:%[0-9]+]] = OpCompositeExtract %float {{%[0-9]+}} 1 +// CHECK: OpCompositeConstruct %v4float [[MANUAL_V0]] [[MANUAL_V1]] +// CHECK-SAME: [[MANUAL_V2]] [[MANUAL_V3]] + +// CHECK-LABEL: %PackArrayOverflow = OpFunction %v2float +// CHECK: [[PACK_A0:%[0-9]+]] = OpCompositeConstruct %v2float +// CHECK: [[PACK_A1:%[0-9]+]] = OpCompositeConstruct %v2float +// CHECK: OpCompositeConstruct %_arr_v2float_uint_2 [[PACK_A0]] [[PACK_A1]] +// CHECK-LABEL: %ManualArrayOverflow = OpFunction %v2float +// CHECK: [[MANUAL_A0:%[0-9]+]] = OpCompositeConstruct %v2float +// CHECK: [[MANUAL_A1:%[0-9]+]] = OpCompositeConstruct %v2float +// CHECK: OpCompositeConstruct %_arr_v2float_uint_2 [[MANUAL_A0]] [[MANUAL_A1]] + +// CHECK-LABEL: %PackStruct = OpFunction %PairOf2 +// CHECK: [[PACK_S0:%[0-9]+]] = OpLoad %v2float +// CHECK: [[PACK_S1:%[0-9]+]] = OpLoad %v2float +// CHECK: OpCompositeConstruct %PairOf2 [[PACK_S0]] [[PACK_S1]] +// CHECK-LABEL: %ManualStruct = OpFunction %PairOf2 +// CHECK: [[MANUAL_S0:%[0-9]+]] = OpLoad %v2float +// CHECK: [[MANUAL_S1:%[0-9]+]] = OpLoad %v2float +// CHECK: OpCompositeConstruct %PairOf2 [[MANUAL_S0]] [[MANUAL_S1]] +float4 main(float4 inp : A) : SV_Target { + float2 lo = inp.xy; + float2 hi = inp.zw; + + float4 vp = PackVectorMixed(lo, hi); + float4 vm = ManualVectorMixed(lo, hi); + + float2 op = PackArrayOverflow(inp.x, inp.y, inp.z, inp.w); + float2 om = ManualArrayOverflow(inp.x, inp.y, inp.z, inp.w); + + PairOf2 sp = PackStruct(lo, hi); + PairOf2 sm = ManualStruct(lo, hi); + + return vp + vm + float4(op + om, 0, 0) + + float4(sp.lo + sm.lo, sp.hi + sm.hi); +} diff --git a/tools/clang/test/CodeGenSPIRV/vk.buffer-pointer.bitfield.hlsl b/tools/clang/test/CodeGenSPIRV/vk.buffer-pointer.bitfield.hlsl new file mode 100644 index 0000000000..b2b4c813be --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/vk.buffer-pointer.bitfield.hlsl @@ -0,0 +1,20 @@ +// RUN: %dxc -spirv -E main -T cs_6_7 %s | FileCheck %s + +struct Foo { + uint a : 16; + uint b : 16; +}; + +[[vk::push_constant]] struct Pc { + vk::BufferPointer ptr; +} pc; + +[numthreads(1, 1, 1)] +void main() { + pc.ptr.Get().a = 123; +} + +// CHECK: [[FIELD:%[0-9]+]] = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%[0-9]+}} %int_0 +// CHECK: [[OLD:%[0-9]+]] = OpLoad %uint [[FIELD]] Aligned 4 +// CHECK: [[NEW:%[0-9]+]] = OpBitFieldInsert %uint [[OLD]] %uint_123 %uint_0 %uint_16 +// CHECK: OpStore [[FIELD]] [[NEW]] Aligned 4 diff --git a/tools/clang/test/CodeGenSPIRV/vk.shader-record-ext.static.member.hlsl b/tools/clang/test/CodeGenSPIRV/vk.shader-record-ext.static.member.hlsl new file mode 100644 index 0000000000..44e9a05798 --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/vk.shader-record-ext.static.member.hlsl @@ -0,0 +1,41 @@ +// RUN: %dxc -T lib_6_3 -fspv-target-env=vulkan1.2 -fcgl %s -spirv | FileCheck %s + +// Same as cbuffer.static.member.hlsl, but for a shader record buffer, which +// goes through createShaderRecordBuffer() instead of createCTBuffer(). A +// `static` variable declared inside the buffer is an ordinary global variable, +// not a member of the buffer. It must be left out of the buffer's struct (it is +// not part of the layout) *and* it must not consume a member index, otherwise +// the access chains for the members declared after it are shifted, and the last +// one ends up out of bounds. + +// CHECK: OpMemberName %type_ShaderRecordBufferKHR_block 0 "a" +// CHECK: OpMemberName %type_ShaderRecordBufferKHR_block 1 "b" +// CHECK: OpMemberName %type_ShaderRecordBufferKHR_block 2 "c" +// CHECK-NOT: OpMemberName %type_ShaderRecordBufferKHR_block 3 + +// CHECK-DAG: %uint_10 = OpConstant %uint 10 +// CHECK-DAG: %uint_11 = OpConstant %uint 11 +// CHECK-DAG: %uint_12 = OpConstant %uint 12 + +// CHECK: %type_ShaderRecordBufferKHR_block = OpTypeStruct %uint %uint %uint + +[[vk::shader_record_ext]] +cbuffer block { + uint a; + static const uint a_mode = 10; + uint b; + static const uint b_mode = 11; + uint c; + static const uint c_mode = 12; +} + +struct Payload { float p; }; +struct Attr { float a; }; + +[shader("closesthit")] +void main(inout Payload P, in Attr A) { +// CHECK: OpAccessChain %_ptr_ShaderRecordBufferKHR_uint %block %int_0 +// CHECK: OpAccessChain %_ptr_ShaderRecordBufferKHR_uint %block %int_1 +// CHECK: OpAccessChain %_ptr_ShaderRecordBufferKHR_uint %block %int_2 + P.p = a + b + c + a_mode + b_mode + c_mode; +} diff --git a/tools/clang/test/DXC/Passes/DxilGen/clusterid_dxilgen.ll b/tools/clang/test/DXC/Passes/DxilGen/clusterid_dxilgen.ll index 0f82fc5d71..7fc7f7663c 100644 --- a/tools/clang/test/DXC/Passes/DxilGen/clusterid_dxilgen.ll +++ b/tools/clang/test/DXC/Passes/DxilGen/clusterid_dxilgen.ll @@ -2,16 +2,16 @@ ; REQUIRES: dxil-1-10 ; CHECK-LABEL: define void @"\01?test_cluster_id -; CHECK: call i32 @dx.op.clusterID(i32 -2147483645) +; CHECK: call i32 @dx.op.clusterID(i32 314) ; CHECK-LABEL: define void @"\01?test_rayquery_candidate_cluster_id -; CHECK: call i32 @dx.op.rayQuery_StateScalar.i32(i32 -2147483644, i32 %{{.*}}) +; CHECK: call i32 @dx.op.rayQuery_StateScalar.i32(i32 315, i32 %{{.*}}) ; CHECK-LABEL: define void @"\01?test_rayquery_committed_cluster_id -; CHECK: call i32 @dx.op.rayQuery_StateScalar.i32(i32 -2147483643, i32 %{{.*}}) +; CHECK: call i32 @dx.op.rayQuery_StateScalar.i32(i32 316, i32 %{{.*}}) ; CHECK-LABEL: define void @"\01?test_hitobject_cluster_id -; CHECK: call i32 @dx.op.hitObject_StateScalar.i32(i32 -2147483642, %dx.types.HitObject +; CHECK: call i32 @dx.op.hitObject_StateScalar.i32(i32 317, %dx.types.HitObject ; CHECK-DAG: declare i32 @dx.op.clusterID(i32) ; CHECK-DAG: declare i32 @dx.op.rayQuery_StateScalar.i32(i32, i32) diff --git a/tools/clang/test/DXC/Passes/DxilGen/debugbreak.ll b/tools/clang/test/DXC/Passes/DxilGen/debugbreak.ll index 5101528d01..2f25f4b7a4 100644 --- a/tools/clang/test/DXC/Passes/DxilGen/debugbreak.ll +++ b/tools/clang/test/DXC/Passes/DxilGen/debugbreak.ll @@ -1,7 +1,7 @@ ; REQUIRES: dxil-1-10 ; RUN: %dxopt %s -hlsl-passes-resume -dxilgen -S | FileCheck %s -; CHECK: call void @dx.op.debugBreak(i32 -2147483615) +; CHECK: call void @dx.op.debugBreak(i32 343) ; Generated from: ; dxc -T cs_6_10 -fcgl tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/debugbreak.hlsl diff --git a/tools/clang/test/DXC/Passes/DxilGen/group-wave-index.ll b/tools/clang/test/DXC/Passes/DxilGen/group-wave-index.ll index 78774e1653..358e068566 100644 --- a/tools/clang/test/DXC/Passes/DxilGen/group-wave-index.ll +++ b/tools/clang/test/DXC/Passes/DxilGen/group-wave-index.ll @@ -1,8 +1,8 @@ ; REQUIRES: dxil-1-10 ; RUN: %dxopt %s -hlsl-passes-resume -dxilgen -S | FileCheck %s -; CHECK: call i32 @dx.op.getGroupWaveIndex(i32 -2147483647) -; CHECK: call i32 @dx.op.getGroupWaveCount(i32 -2147483646) +; CHECK: call i32 @dx.op.getGroupWaveIndex(i32 312) +; CHECK: call i32 @dx.op.getGroupWaveCount(i32 313) ; Generated from: ; utils/hct/ExtractIRForPassTest.py -p dxilgen -o tools/clang/test/DXC/Passes/DxilGen/group-wave-index.ll tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/wave/group-wave-index.hlsl -- -T cs_6_10 -E main diff --git a/tools/clang/test/DXC/Passes/DxilGen/isdebuggingenabled.ll b/tools/clang/test/DXC/Passes/DxilGen/isdebuggingenabled.ll index 6de7448801..168b884fcf 100644 --- a/tools/clang/test/DXC/Passes/DxilGen/isdebuggingenabled.ll +++ b/tools/clang/test/DXC/Passes/DxilGen/isdebuggingenabled.ll @@ -1,7 +1,7 @@ ; REQUIRES: dxil-1-10 ; RUN: %dxopt %s -hlsl-passes-resume -dxilgen -S | FileCheck %s -; CHECK: call i1 @dx.op.isDebuggingEnabled(i32 -2147483614) +; CHECK: call i1 @dx.op.isDebuggingEnabled(i32 344) ; CHECK: declare i1 @dx.op.isDebuggingEnabled(i32) #[[QUERY_ATTR:[0-9]+]] ; CHECK: attributes #[[QUERY_ATTR]] = { nounwind } diff --git a/tools/clang/test/DXC/Passes/DxilGen/triangle_positions_dxilgen.ll b/tools/clang/test/DXC/Passes/DxilGen/triangle_positions_dxilgen.ll index 218c4882cf..0172cb794c 100644 --- a/tools/clang/test/DXC/Passes/DxilGen/triangle_positions_dxilgen.ll +++ b/tools/clang/test/DXC/Passes/DxilGen/triangle_positions_dxilgen.ll @@ -2,17 +2,17 @@ ; REQUIRES: dxil-1-10 ; CHECK-LABEL: define void {{.*}}ClosestHit -; CHECK: %{{.*}} = call <9 x float> @dx.op.triangleObjectPosition.f32(i32 -2147483641) +; CHECK: %{{.*}} = call <9 x float> @dx.op.triangleObjectPosition.f32(i32 318) ; CHECK-LABEL: define void {{.*}}AnyHit -; CHECK: %{{.*}} = call <9 x float> @dx.op.triangleObjectPosition.f32(i32 -2147483641) +; CHECK: %{{.*}} = call <9 x float> @dx.op.triangleObjectPosition.f32(i32 318) ; CHECK-LABEL: define void {{.*}}RayQueryTest -; CHECK: %{{.*}} = call <9 x float> @dx.op.rayQuery_CandidateTriangleObjectPosition.f32(i32 -2147483640, i32 %{{.*}}) -; CHECK: %{{.*}} = call <9 x float> @dx.op.rayQuery_CommittedTriangleObjectPosition.f32(i32 -2147483639, i32 %{{.*}}) +; CHECK: %{{.*}} = call <9 x float> @dx.op.rayQuery_CandidateTriangleObjectPosition.f32(i32 319, i32 %{{.*}}) +; CHECK: %{{.*}} = call <9 x float> @dx.op.rayQuery_CommittedTriangleObjectPosition.f32(i32 320, i32 %{{.*}}) ; CHECK-LABEL: define void {{.*}}HitObjectTest -; CHECK: %{{.*}} = call <9 x float> @dx.op.hitObject_TriangleObjectPosition.f32(i32 -2147483638, %dx.types.HitObject %{{.*}}) +; CHECK: %{{.*}} = call <9 x float> @dx.op.hitObject_TriangleObjectPosition.f32(i32 321, %dx.types.HitObject %{{.*}}) ; CHECK-DAG: declare <9 x float> @dx.op.triangleObjectPosition.f32(i32) ; CHECK-DAG: declare <9 x float> @dx.op.rayQuery_CommittedTriangleObjectPosition.f32(i32, i32) diff --git a/tools/clang/test/DXC/Passes/DxilValidateWaveSensitivity/nested-loops.ll b/tools/clang/test/DXC/Passes/DxilValidateWaveSensitivity/nested-loops.ll new file mode 100644 index 0000000000..f51e629d88 --- /dev/null +++ b/tools/clang/test/DXC/Passes/DxilValidateWaveSensitivity/nested-loops.ll @@ -0,0 +1,80 @@ +; RUN: opt -hlsl-dxilload -hlsl-validate-wave-sensitivity -S %s -o /dev/null 2>&1 | FileCheck %s + +; Uses opt rather than dxopt because dxopt does not print the pass's warnings. + +; The outer latch is only reached through the inner loop, so the outer loop +; header phis can only be resolved after the inner loop phis. Check that the +; analysis still resolves them, and warns only in @nested_sensitive. + +; CHECK-NOT: Gradient +; CHECK: Function: nested_sensitive: warning: Gradient operations are not affected by wave-sensitive data or control flow. +; CHECK-NOT: Gradient + +target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64" +target triple = "dxil-ms-dx" + +; The gradient operand is not wave sensitive. The pass only runs because +; @nested_sensitive contains a wave op. +define void @nested(float %p, i32 %n) { +entry: + br label %outer + +outer: + %i = phi i32 [ 0, %entry ], [ %i.next, %outer.latch ] + br label %inner + +inner: + %j = phi i32 [ 0, %outer ], [ %j.next, %inner ] + %f = uitofp i32 %j to float + %d = call float @dx.op.unary.f32(i32 83, float %f) + %j.next = add i32 %j, 1 + %j.done = icmp eq i32 %j.next, %n + br i1 %j.done, label %outer.latch, label %inner + +outer.latch: + %i.next = add i32 %i, 1 + %i.done = icmp eq i32 %i.next, %n + br i1 %i.done, label %exit, label %outer + +exit: + ret void +} + +; The wave op in the outer latch feeds the gradient operand on the next outer +; iteration, so the gradient operand is wave sensitive. +define void @nested_sensitive(float %p, i32 %n) { +entry: + br label %outer + +outer: + %i = phi i32 [ 0, %entry ], [ %i.next, %outer.latch ] + %q = phi float [ %p, %entry ], [ %w, %outer.latch ] + br label %inner + +inner: + %j = phi i32 [ 0, %outer ], [ %j.next, %inner ] + %d = call float @dx.op.unary.f32(i32 83, float %q) + %j.next = add i32 %j, 1 + %j.done = icmp eq i32 %j.next, %n + br i1 %j.done, label %outer.latch, label %inner + +outer.latch: + %w = call float @dx.op.waveActiveOp.f32(i32 119, float %q, i8 0, i8 0) + %i.next = add i32 %i, 1 + %i.done = icmp eq i32 %i.next, %n + br i1 %i.done, label %exit, label %outer + +exit: + ret void +} + +declare float @dx.op.unary.f32(i32, float) +declare float @dx.op.waveActiveOp.f32(i32, float, i8, i8) + +!dx.version = !{!0} +!dx.shaderModel = !{!1} +!dx.entryPoints = !{!2} + +!0 = !{i32 1, i32 3} +!1 = !{!"lib", i32 6, i32 3} +!2 = !{null, !"", null, null, null} diff --git a/tools/clang/test/DXC/Passes/GVN/memdep-scan-limit.ll b/tools/clang/test/DXC/Passes/GVN/memdep-scan-limit.ll new file mode 100644 index 0000000000..24565f7d38 --- /dev/null +++ b/tools/clang/test/DXC/Passes/GVN/memdep-scan-limit.ll @@ -0,0 +1,248 @@ +; RUN: %dxopt %s -hlsl-passes-resume -gvn -S | FileCheck %s --check-prefix=GVN +; RUN: %dxopt %s -hlsl-passes-resume -basicaa -dse -S | FileCheck %s --check-prefix=DSE + +; MemoryDependenceAnalysis scans at most 100 instructions, including the +; dependency itself. Keep coverage for passes used by DXC that rely on this +; limit. MemCpyOpt also uses MemDep in LLVM, but DXC disables that pass because +; HLSL does not allow memcpy. The live add chains ensure that the filler +; survives GVN and DSE. + +target datalayout = "e-m:e-p:32:32-i64:64-n8:16:32:64" +target triple = "dxil-ms-dx" + +; With 98 intervening instructions, MemDep reaches the defining access. +; +; GVN-LABEL: define i32 @within_limit( +; GVN-COUNT-1: load i32, i32* %load.ptr +; +; DSE-LABEL: define i32 @within_limit( +; DSE-NOT: store i32 1, i32* %store.ptr +; DSE: store i32 2, i32* %store.ptr +define i32 @within_limit(i32* noalias %load.ptr, i32* noalias %store.ptr, + i32 %seed) { +entry: + %load.first = load i32, i32* %load.ptr + store i32 1, i32* %store.ptr + %add.pre = add i32 %seed, 1 + %add.0 = add i32 %add.pre, 1 + %add.1 = add i32 %add.0, 1 + %add.2 = add i32 %add.1, 1 + %add.3 = add i32 %add.2, 1 + %add.4 = add i32 %add.3, 1 + %add.5 = add i32 %add.4, 1 + %add.6 = add i32 %add.5, 1 + %add.7 = add i32 %add.6, 1 + %add.8 = add i32 %add.7, 1 + %add.9 = add i32 %add.8, 1 + %add.10 = add i32 %add.9, 1 + %add.11 = add i32 %add.10, 1 + %add.12 = add i32 %add.11, 1 + %add.13 = add i32 %add.12, 1 + %add.14 = add i32 %add.13, 1 + %add.15 = add i32 %add.14, 1 + %add.16 = add i32 %add.15, 1 + %add.17 = add i32 %add.16, 1 + %add.18 = add i32 %add.17, 1 + %add.19 = add i32 %add.18, 1 + %add.20 = add i32 %add.19, 1 + %add.21 = add i32 %add.20, 1 + %add.22 = add i32 %add.21, 1 + %add.23 = add i32 %add.22, 1 + %add.24 = add i32 %add.23, 1 + %add.25 = add i32 %add.24, 1 + %add.26 = add i32 %add.25, 1 + %add.27 = add i32 %add.26, 1 + %add.28 = add i32 %add.27, 1 + %add.29 = add i32 %add.28, 1 + %add.30 = add i32 %add.29, 1 + %add.31 = add i32 %add.30, 1 + %add.32 = add i32 %add.31, 1 + %add.33 = add i32 %add.32, 1 + %add.34 = add i32 %add.33, 1 + %add.35 = add i32 %add.34, 1 + %add.36 = add i32 %add.35, 1 + %add.37 = add i32 %add.36, 1 + %add.38 = add i32 %add.37, 1 + %add.39 = add i32 %add.38, 1 + %add.40 = add i32 %add.39, 1 + %add.41 = add i32 %add.40, 1 + %add.42 = add i32 %add.41, 1 + %add.43 = add i32 %add.42, 1 + %add.44 = add i32 %add.43, 1 + %add.45 = add i32 %add.44, 1 + %add.46 = add i32 %add.45, 1 + %add.47 = add i32 %add.46, 1 + %add.48 = add i32 %add.47, 1 + %add.49 = add i32 %add.48, 1 + %add.50 = add i32 %add.49, 1 + %add.51 = add i32 %add.50, 1 + %add.52 = add i32 %add.51, 1 + %add.53 = add i32 %add.52, 1 + %add.54 = add i32 %add.53, 1 + %add.55 = add i32 %add.54, 1 + %add.56 = add i32 %add.55, 1 + %add.57 = add i32 %add.56, 1 + %add.58 = add i32 %add.57, 1 + %add.59 = add i32 %add.58, 1 + %add.60 = add i32 %add.59, 1 + %add.61 = add i32 %add.60, 1 + %add.62 = add i32 %add.61, 1 + %add.63 = add i32 %add.62, 1 + %add.64 = add i32 %add.63, 1 + %add.65 = add i32 %add.64, 1 + %add.66 = add i32 %add.65, 1 + %add.67 = add i32 %add.66, 1 + %add.68 = add i32 %add.67, 1 + %add.69 = add i32 %add.68, 1 + %add.70 = add i32 %add.69, 1 + %add.71 = add i32 %add.70, 1 + %add.72 = add i32 %add.71, 1 + %add.73 = add i32 %add.72, 1 + %add.74 = add i32 %add.73, 1 + %add.75 = add i32 %add.74, 1 + %add.76 = add i32 %add.75, 1 + %add.77 = add i32 %add.76, 1 + %add.78 = add i32 %add.77, 1 + %add.79 = add i32 %add.78, 1 + %add.80 = add i32 %add.79, 1 + %add.81 = add i32 %add.80, 1 + %add.82 = add i32 %add.81, 1 + %add.83 = add i32 %add.82, 1 + %add.84 = add i32 %add.83, 1 + %add.85 = add i32 %add.84, 1 + %add.86 = add i32 %add.85, 1 + %add.87 = add i32 %add.86, 1 + %add.88 = add i32 %add.87, 1 + %add.89 = add i32 %add.88, 1 + %add.90 = add i32 %add.89, 1 + %add.91 = add i32 %add.90, 1 + %add.92 = add i32 %add.91, 1 + %add.93 = add i32 %add.92, 1 + %add.94 = add i32 %add.93, 1 + %add.95 = add i32 %add.94, 1 + %load.second = load i32, i32* %load.ptr + store i32 2, i32* %store.ptr + %loads = add i32 %load.first, %load.second + %result = add i32 %loads, %add.95 + ret i32 %result +} + +; With 99 intervening instructions, MemDep stops before the defining access. +; +; GVN-LABEL: define i32 @outside_limit( +; GVN: [[LOAD_FIRST:%.*]] = load i32, i32* %load.ptr +; GVN: [[LOAD_SECOND:%.*]] = load i32, i32* %load.ptr +; GVN: add i32 [[LOAD_FIRST]], [[LOAD_SECOND]] +; +; DSE-LABEL: define i32 @outside_limit( +; DSE: store i32 1, i32* %store.ptr +; DSE: store i32 2, i32* %store.ptr +define i32 @outside_limit(i32* noalias %load.ptr, i32* noalias %store.ptr, + i32 %seed) { +entry: + %load.first = load i32, i32* %load.ptr + store i32 1, i32* %store.ptr + %add.pre = add i32 %seed, 1 + %add.0 = add i32 %add.pre, 1 + %add.1 = add i32 %add.0, 1 + %add.2 = add i32 %add.1, 1 + %add.3 = add i32 %add.2, 1 + %add.4 = add i32 %add.3, 1 + %add.5 = add i32 %add.4, 1 + %add.6 = add i32 %add.5, 1 + %add.7 = add i32 %add.6, 1 + %add.8 = add i32 %add.7, 1 + %add.9 = add i32 %add.8, 1 + %add.10 = add i32 %add.9, 1 + %add.11 = add i32 %add.10, 1 + %add.12 = add i32 %add.11, 1 + %add.13 = add i32 %add.12, 1 + %add.14 = add i32 %add.13, 1 + %add.15 = add i32 %add.14, 1 + %add.16 = add i32 %add.15, 1 + %add.17 = add i32 %add.16, 1 + %add.18 = add i32 %add.17, 1 + %add.19 = add i32 %add.18, 1 + %add.20 = add i32 %add.19, 1 + %add.21 = add i32 %add.20, 1 + %add.22 = add i32 %add.21, 1 + %add.23 = add i32 %add.22, 1 + %add.24 = add i32 %add.23, 1 + %add.25 = add i32 %add.24, 1 + %add.26 = add i32 %add.25, 1 + %add.27 = add i32 %add.26, 1 + %add.28 = add i32 %add.27, 1 + %add.29 = add i32 %add.28, 1 + %add.30 = add i32 %add.29, 1 + %add.31 = add i32 %add.30, 1 + %add.32 = add i32 %add.31, 1 + %add.33 = add i32 %add.32, 1 + %add.34 = add i32 %add.33, 1 + %add.35 = add i32 %add.34, 1 + %add.36 = add i32 %add.35, 1 + %add.37 = add i32 %add.36, 1 + %add.38 = add i32 %add.37, 1 + %add.39 = add i32 %add.38, 1 + %add.40 = add i32 %add.39, 1 + %add.41 = add i32 %add.40, 1 + %add.42 = add i32 %add.41, 1 + %add.43 = add i32 %add.42, 1 + %add.44 = add i32 %add.43, 1 + %add.45 = add i32 %add.44, 1 + %add.46 = add i32 %add.45, 1 + %add.47 = add i32 %add.46, 1 + %add.48 = add i32 %add.47, 1 + %add.49 = add i32 %add.48, 1 + %add.50 = add i32 %add.49, 1 + %add.51 = add i32 %add.50, 1 + %add.52 = add i32 %add.51, 1 + %add.53 = add i32 %add.52, 1 + %add.54 = add i32 %add.53, 1 + %add.55 = add i32 %add.54, 1 + %add.56 = add i32 %add.55, 1 + %add.57 = add i32 %add.56, 1 + %add.58 = add i32 %add.57, 1 + %add.59 = add i32 %add.58, 1 + %add.60 = add i32 %add.59, 1 + %add.61 = add i32 %add.60, 1 + %add.62 = add i32 %add.61, 1 + %add.63 = add i32 %add.62, 1 + %add.64 = add i32 %add.63, 1 + %add.65 = add i32 %add.64, 1 + %add.66 = add i32 %add.65, 1 + %add.67 = add i32 %add.66, 1 + %add.68 = add i32 %add.67, 1 + %add.69 = add i32 %add.68, 1 + %add.70 = add i32 %add.69, 1 + %add.71 = add i32 %add.70, 1 + %add.72 = add i32 %add.71, 1 + %add.73 = add i32 %add.72, 1 + %add.74 = add i32 %add.73, 1 + %add.75 = add i32 %add.74, 1 + %add.76 = add i32 %add.75, 1 + %add.77 = add i32 %add.76, 1 + %add.78 = add i32 %add.77, 1 + %add.79 = add i32 %add.78, 1 + %add.80 = add i32 %add.79, 1 + %add.81 = add i32 %add.80, 1 + %add.82 = add i32 %add.81, 1 + %add.83 = add i32 %add.82, 1 + %add.84 = add i32 %add.83, 1 + %add.85 = add i32 %add.84, 1 + %add.86 = add i32 %add.85, 1 + %add.87 = add i32 %add.86, 1 + %add.88 = add i32 %add.87, 1 + %add.89 = add i32 %add.88, 1 + %add.90 = add i32 %add.89, 1 + %add.91 = add i32 %add.90, 1 + %add.92 = add i32 %add.91, 1 + %add.93 = add i32 %add.92, 1 + %add.94 = add i32 %add.93, 1 + %add.95 = add i32 %add.94, 1 + %add.96 = add i32 %add.95, 1 + %load.second = load i32, i32* %load.ptr + store i32 2, i32* %store.ptr + %loads = add i32 %load.first, %load.second + %result = add i32 %loads, %add.96 + ret i32 %result +} diff --git a/tools/clang/test/DXC/Passes/ScalarReplHLSL/vector-index-bounds.ll b/tools/clang/test/DXC/Passes/ScalarReplHLSL/vector-index-bounds.ll new file mode 100644 index 0000000000..82fcea760a --- /dev/null +++ b/tools/clang/test/DXC/Passes/ScalarReplHLSL/vector-index-bounds.ll @@ -0,0 +1,77 @@ +; RUN: %dxopt %s -hlsl-passes-resume -scalarrepl-param-hlsl -S | FileCheck %s + +; Scalar replacement splits an array of vectors into one scalar array per +; vector lane. Verify that invalid local lane indices are not scalarized. +; Constant global GEPs are first canonicalized across the entire aggregate, +; turning lane 7 into array index 1, lane 3, which can be scalarized safely. + +; CHECK-DAG: %valid.3 = alloca [2 x float] +; CHECK-DAG: %nested = alloca [2 x %struct.S] +; CHECK-DAG: %out_of_bounds = alloca [2 x <4 x float>] +; CHECK-DAG: %negative = alloca [2 x <4 x float>] +; CHECK-DAG: @global_out_of_bounds.3 = internal global [2 x float] zeroinitializer +; CHECK: getelementptr inbounds [2 x <4 x float>], [2 x <4 x float>]* %out_of_bounds, i32 0, i32 0, i32 7 +; CHECK: getelementptr inbounds [2 x <4 x float>], [2 x <4 x float>]* %negative, i32 0, i32 0, i32 -1 +; CHECK: getelementptr inbounds [2 x float], [2 x float]* %valid.3, i32 0, i32 0 +; CHECK: getelementptr [2 x %struct.S], [2 x %struct.S]* %nested, i32 0, i32 0, i32 0, i32 7 +; CHECK: getelementptr inbounds ([2 x float], [2 x float]* @global_out_of_bounds.3, i32 0, i64 1) + +target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64" +target triple = "dxil-ms-dx" + +%ConstantBuffer = type opaque +%struct.S = type { <4 x float> } + +@"$Globals" = external constant %ConstantBuffer +@global_out_of_bounds = internal global [2 x <4 x float>] zeroinitializer + +define <4 x float> @main() { +entry: + %out_of_bounds = alloca [2 x <4 x float>] + %out_of_bounds.vector = getelementptr [2 x <4 x float>], [2 x <4 x float>]* %out_of_bounds, i32 0, i32 0 + %out_of_bounds.element = getelementptr <4 x float>, <4 x float>* %out_of_bounds.vector, i32 0, i32 7 + store float 9.000000e+00, float* %out_of_bounds.element + + %negative = alloca [2 x <4 x float>] + %negative.vector = getelementptr [2 x <4 x float>], [2 x <4 x float>]* %negative, i32 0, i32 0 + %negative.element = getelementptr <4 x float>, <4 x float>* %negative.vector, i32 0, i32 -1 + store float 9.000000e+00, float* %negative.element + + %valid = alloca [2 x <4 x float>] + %valid.vector = getelementptr [2 x <4 x float>], [2 x <4 x float>]* %valid, i32 0, i32 0 + %valid.element = getelementptr <4 x float>, <4 x float>* %valid.vector, i32 0, i32 3 + store float 9.000000e+00, float* %valid.element + + %nested = alloca [2 x %struct.S] + %nested.element = getelementptr [2 x %struct.S], [2 x %struct.S]* %nested, i32 0, i32 0, i32 0, i32 7 + store float 9.000000e+00, float* %nested.element + + store float 9.000000e+00, float* getelementptr inbounds ([2 x <4 x float>], [2 x <4 x float>]* @global_out_of_bounds, i32 0, i32 0, i32 7) + + ret <4 x float> zeroinitializer +} + +!pauseresume = !{!0} +!dx.version = !{!1} +!dx.valver = !{!2} +!dx.shaderModel = !{!3} +!dx.typeAnnotations = !{!4} +!dx.entryPoints = !{!8} +!dx.fnprops = !{!12} +!dx.options = !{!13, !14} + +!0 = !{!"hlsl-hlemit", !"hlsl-hlensure"} +!1 = !{i32 1, i32 6} +!2 = !{i32 1, i32 10} +!3 = !{!"ps", i32 6, i32 6} +!4 = !{i32 1, <4 x float> ()* @main, !5} +!5 = !{!6} +!6 = !{i32 1, !7, !7} +!7 = !{} +!8 = !{<4 x float> ()* @main, !"main", null, !9, null} +!9 = !{null, null, !10, null} +!10 = !{!11} +!11 = !{i32 0, %ConstantBuffer* @"$Globals", !"$Globals", i32 0, i32 -1, i32 1, i32 0, null} +!12 = !{<4 x float> ()* @main, i32 0, i1 false} +!13 = !{i32 64} +!14 = !{i32 -1} diff --git a/tools/clang/test/DXC/dumpPSV_AS.hlsl b/tools/clang/test/DXC/dumpPSV_AS.hlsl index eac57cc957..6de38b9e96 100644 --- a/tools/clang/test/DXC/dumpPSV_AS.hlsl +++ b/tools/clang/test/DXC/dumpPSV_AS.hlsl @@ -19,6 +19,7 @@ // CHECK-NEXT: SigOutputVectors[2]: 0 // CHECK-NEXT: SigOutputVectors[3]: 0 // CHECK-NEXT: EntryFunctionName: main +// CHECK-NEXT: LinAlgRuntimeInfoPresent: false // CHECK-NEXT: ResourceCount : 0 #define NUM_THREADS 32 diff --git a/tools/clang/test/DXC/dumpPSV_CS.hlsl b/tools/clang/test/DXC/dumpPSV_CS.hlsl index a70b5595ab..a0b81154d1 100644 --- a/tools/clang/test/DXC/dumpPSV_CS.hlsl +++ b/tools/clang/test/DXC/dumpPSV_CS.hlsl @@ -19,6 +19,7 @@ // CHECK-NEXT: SigOutputVectors[2]: 0 // CHECK-NEXT: SigOutputVectors[3]: 0 // CHECK-NEXT: EntryFunctionName: main +// CHECK-NEXT: LinAlgRuntimeInfoPresent: false // CHECK-NEXT: ResourceCount : 3 // CHECK-NEXT: PSVResourceBindInfo: // CHECK-NEXT: Space: 0 diff --git a/tools/clang/test/DXC/dumpPSV_DS.hlsl b/tools/clang/test/DXC/dumpPSV_DS.hlsl index 2d4a611a2b..fb6bc2a0cc 100644 --- a/tools/clang/test/DXC/dumpPSV_DS.hlsl +++ b/tools/clang/test/DXC/dumpPSV_DS.hlsl @@ -1,4 +1,4 @@ -// REQUIRES: dxil-1-8 +// REQUIRES: dxil-1-10 // RUN: %dxc -E main -T ds_6_8 %s -Fo %t // RUN: %dxa %t -dumppsv | FileCheck %s @@ -18,6 +18,7 @@ // CHECK-NEXT: SigOutputVectors[2]: 0 // CHECK-NEXT: SigOutputVectors[3]: 0 // CHECK-NEXT: EntryFunctionName: main +// CHECK-NEXT: LinAlgRuntimeInfoPresent: false // CHECK-NEXT: ResourceCount : 0 // CHECK-NEXT: PSVSignatureElement: // CHECK-NEXT: SemanticName: diff --git a/tools/clang/test/DXC/dumpPSV_GS.hlsl b/tools/clang/test/DXC/dumpPSV_GS.hlsl index 77ff2806ff..cb8b421b16 100644 --- a/tools/clang/test/DXC/dumpPSV_GS.hlsl +++ b/tools/clang/test/DXC/dumpPSV_GS.hlsl @@ -1,4 +1,4 @@ -// REQUIRES: dxil-1-8 +// REQUIRES: dxil-1-10 // RUN: %dxc -E main -T gs_6_8 %s -Fo %t // RUN: %dxa %t -dumppsv | FileCheck %s @@ -21,6 +21,7 @@ // CHECK-NEXT: SigOutputVectors[2]: 0 // CHECK-NEXT: SigOutputVectors[3]: 0 // CHECK-NEXT: EntryFunctionName: main +// CHECK-NEXT: LinAlgRuntimeInfoPresent: false // CHECK-NEXT: ResourceCount : 1 // CHECK-NEXT: PSVResourceBindInfo: // CHECK-NEXT: Space: 0 diff --git a/tools/clang/test/DXC/dumpPSV_HS.hlsl b/tools/clang/test/DXC/dumpPSV_HS.hlsl index 6a4e2957aa..f54374a420 100644 --- a/tools/clang/test/DXC/dumpPSV_HS.hlsl +++ b/tools/clang/test/DXC/dumpPSV_HS.hlsl @@ -1,4 +1,4 @@ -// REQUIRES: dxil-1-8 +// REQUIRES: dxil-1-10 // RUN: %dxc -E main -T hs_6_8 %s -Fo %t // RUN: %dxa %t -dumppsv | FileCheck %s @@ -21,6 +21,7 @@ // CHECK-NEXT: SigOutputVectors[2]: 0 // CHECK-NEXT: SigOutputVectors[3]: 0 // CHECK-NEXT: EntryFunctionName: main +// CHECK-NEXT: LinAlgRuntimeInfoPresent: false // CHECK-NEXT: ResourceCount : 0 // CHECK-NEXT: PSVSignatureElement: // CHECK-NEXT: SemanticName: diff --git a/tools/clang/test/DXC/dumpPSV_LinAlg.hlsl b/tools/clang/test/DXC/dumpPSV_LinAlg.hlsl new file mode 100644 index 0000000000..cc89fa5f65 --- /dev/null +++ b/tools/clang/test/DXC/dumpPSV_LinAlg.hlsl @@ -0,0 +1,58 @@ +// REQUIRES: dxil-1-10 +// RUN: %dxc -enable-16bit-types -E main -T cs_6_10 %s -Fo %t +// RUN: %dxa %t -dumppsv | FileCheck %s + +#include +using namespace dx::linalg; + +ByteAddressBuffer Input : register(t0); +RWByteAddressBuffer Output : register(u0); +RWStructuredBuffer > VectorOutput : register(u1); +groupshared uint8_t4_packed SharedOutput[64]; + +using ThreadA = + Matrix; +using WaveA = + Matrix; +using WaveB = + Matrix; +using WaveAccumulator = + Matrix; +using ThreadAccumulator = Matrix; + +[numthreads(4, 4, 1)] +void main(uint Index : SV_GroupIndex) { + ThreadA TA = + ThreadA::Load(Input, 0, 0); + VectorOutput[Index] = Multiply(TA, (vector)1.0h); + + WaveA A = WaveA::Splat(1.0h); + WaveB B = WaveB::Splat(2); + WaveAccumulator C = Multiply(A, B); + C.Store(Output, 0, 20, MatrixLayout::RowMajor); + C.InterlockedAccumulate(SharedOutput, 0, 16, MatrixLayout::RowMajor); + + ThreadAccumulator Outer = + OuterProduct((float4)1.0f, (float4)2.0f); + Outer.InterlockedAccumulate(Output, 256); + InterlockedAccumulate(Output, 512, (int4)Index); +} + +// CHECK: LinAlgRuntimeInfoPresent: true +// CHECK: PSVLinAlgRuntimeInfo: +// CHECK-NEXT: MatrixOperationShapeCount: 4 +// CHECK-NEXT: MatrixConstructionCount: 3 +// CHECK-NEXT: ThreadMatrixVectorMultiplyCount: 1 +// CHECK-NEXT: WaveMatrixMultiplyCount: 1 +// CHECK-NEXT: ThreadGroupMatrixMultiplyCount: 0 +// CHECK-NEXT: OuterProductCount: 1 +// CHECK-NEXT: AccumulateStoreCount: 2 +// CHECK-NEXT: MatrixConstruction[0]: MatrixType=4, Shapes=[(0,5,4)] +// CHECK-NEXT: MatrixConstruction[1]: MatrixType=8, Shapes=[(3,0,4)] +// CHECK-NEXT: MatrixConstruction[2]: MatrixType=9, Shapes=[(3,5,0)] +// CHECK-NEXT: ThreadMatrixVectorMultiply[0]: ResultType=8, MatrixType=8, VectorInputType=8, Flags=1 +// CHECK-NEXT: WaveMatrixMultiply[0]: AccumulatorType=9, MatrixAType=8, MatrixBType=4, Shapes=[(3,5,4)] +// CHECK-NEXT: OuterProduct[0]: ResultType=9, VectorInputType=9 +// CHECK-NEXT: AccumulateStore[0]: AccumulatorType=9, Flags=3 +// CHECK-NEXT: AccumulateStore[1]: AccumulatorType=4, Flags=1 diff --git a/tools/clang/test/DXC/dumpPSV_LinAlgAccumulate.hlsl b/tools/clang/test/DXC/dumpPSV_LinAlgAccumulate.hlsl new file mode 100644 index 0000000000..f5a37a9a35 --- /dev/null +++ b/tools/clang/test/DXC/dumpPSV_LinAlgAccumulate.hlsl @@ -0,0 +1,78 @@ +// REQUIRES: dxil-1-10 +// RUN: %dxc -enable-16bit-types -E main -T cs_6_10 %s -Fo %t +// RUN: %dxa %t -dumppsv | FileCheck %s + +#include +using namespace dx::linalg; + +RWByteAddressBuffer Output : register(u0); +groupshared half SharedHalf[64]; +groupshared float SharedFloat[64]; + +using ThreadHalfAccumulator = Matrix; +using ThreadFloatAccumulator = Matrix; +using ThreadIntAccumulator = Matrix; +using ThreadUIntAccumulator = Matrix; +using WaveHalfAccumulator = Matrix; +using WaveFloatAccumulator = Matrix; + +[numthreads(4, 4, 1)] +void main(uint Index : SV_GroupIndex) { + ThreadHalfAccumulator HalfOuter = + OuterProduct((vector)1.0h, + (vector)2.0h); + HalfOuter.InterlockedAccumulate(Output, 0); + + ThreadFloatAccumulator FloatOuter = + OuterProduct((vector)3.0h, + (vector)4.0h); + FloatOuter.InterlockedAccumulate(Output, 64); + + ThreadIntAccumulator IntOuter = + OuterProduct((int4)5, (int4)6); + IntOuter.InterlockedAccumulate(Output, 128); + + ThreadUIntAccumulator UIntOuter = + OuterProduct((uint4)7, (uint4)8); + UIntOuter.InterlockedAccumulate(Output, 192); + + WaveHalfAccumulator WaveHalf = WaveHalfAccumulator::Splat(7.0h); + WaveHalf.InterlockedAccumulate(Output, 256, 4, MatrixLayout::RowMajor); + WaveHalf.InterlockedAccumulate(SharedHalf, 0, 8, MatrixLayout::RowMajor); + + WaveFloatAccumulator WaveFloat = WaveFloatAccumulator::Splat(8.0f); + WaveFloat.InterlockedAccumulate(SharedFloat, 0, 4, MatrixLayout::RowMajor); + + InterlockedAccumulate(Output, 320, (vector)Index); +} + +// CHECK: LinAlgRuntimeInfoPresent: true +// CHECK: PSVLinAlgRuntimeInfo: +// CHECK-NEXT: MatrixOperationShapeCount: 1 +// CHECK-NEXT: MatrixConstructionCount: 2 +// CHECK-NEXT: ThreadMatrixVectorMultiplyCount: 0 +// CHECK-NEXT: WaveMatrixMultiplyCount: 0 +// CHECK-NEXT: ThreadGroupMatrixMultiplyCount: 0 +// CHECK-NEXT: OuterProductCount: 4 +// CHECK-NEXT: AccumulateStoreCount: 5 +// CHECK-NEXT: MatrixConstruction[0]: MatrixType=8, Shapes=[(2,2,0)] +// CHECK-NEXT: MatrixConstruction[1]: MatrixType=9, Shapes=[(2,2,0)] +// CHECK-NEXT: OuterProduct[0]: ResultType=8, VectorInputType=8 +// CHECK-NEXT: OuterProduct[1]: ResultType=9, VectorInputType=8 +// CHECK-NEXT: OuterProduct[2]: ResultType=4, VectorInputType=4 +// CHECK-NEXT: OuterProduct[3]: ResultType=5, VectorInputType=5 +// CHECK-NEXT: AccumulateStore[0]: AccumulatorType=8, Flags=3 +// CHECK-NEXT: AccumulateStore[1]: AccumulatorType=9, Flags=3 +// CHECK-NEXT: AccumulateStore[2]: AccumulatorType=4, Flags=1 +// CHECK-NEXT: AccumulateStore[3]: AccumulatorType=5, Flags=1 +// CHECK-NEXT: AccumulateStore[4]: AccumulatorType=6, Flags=1 diff --git a/tools/clang/test/DXC/dumpPSV_LinAlgConstructions.hlsl b/tools/clang/test/DXC/dumpPSV_LinAlgConstructions.hlsl new file mode 100644 index 0000000000..4b86ae86de --- /dev/null +++ b/tools/clang/test/DXC/dumpPSV_LinAlgConstructions.hlsl @@ -0,0 +1,47 @@ +// REQUIRES: dxil-1-10 +// RUN: %dxc -E main -T cs_6_10 %s -Fo %t +// RUN: %dxa %t -dumppsv | FileCheck %s + +#include +using namespace dx::linalg; + +RWByteAddressBuffer Output : register(u0); + +using WaveA0 = + Matrix; +using GroupA1 = + Matrix; +using WaveB0 = + Matrix; +using GroupB1 = + Matrix; +using WaveAccumulator0 = Matrix; +using GroupAccumulator1 = + Matrix; + +[numthreads(4, 4, 1)] +void main() { + WaveA0::Splat(1.0f).Store(Output, 0, 16, MatrixLayout::RowMajor); + GroupA1::Splat(2.0f).Store(Output, 64, 20, MatrixLayout::RowMajor); + WaveB0::Splat(3.0f).Store(Output, 128, 16, MatrixLayout::RowMajor); + GroupB1::Splat(4.0f).Store(Output, 192, 24, MatrixLayout::RowMajor); + WaveAccumulator0::Splat(5.0f).Store(Output, 256, 16, + MatrixLayout::RowMajor); + GroupAccumulator1::Splat(6.0f).Store(Output, 320, 24, + MatrixLayout::RowMajor); +} + +// CHECK: LinAlgRuntimeInfoPresent: true +// CHECK: PSVLinAlgRuntimeInfo: +// CHECK-NEXT: MatrixOperationShapeCount: 6 +// CHECK-NEXT: MatrixConstructionCount: 3 +// CHECK-NEXT: ThreadMatrixVectorMultiplyCount: 0 +// CHECK-NEXT: WaveMatrixMultiplyCount: 0 +// CHECK-NEXT: ThreadGroupMatrixMultiplyCount: 0 +// CHECK-NEXT: OuterProductCount: 0 +// CHECK-NEXT: AccumulateStoreCount: 0 +// CHECK-NEXT: MatrixConstruction[0]: MatrixType=9, Shapes=[(2,0,4), (4,0,5)] +// CHECK-NEXT: MatrixConstruction[1]: MatrixType=9, Shapes=[(0,4,4), (0,6,5)] +// CHECK-NEXT: MatrixConstruction[2]: MatrixType=9, Shapes=[(2,4,0), (4,6,0)] diff --git a/tools/clang/test/DXC/dumpPSV_LinAlgMatVec.hlsl b/tools/clang/test/DXC/dumpPSV_LinAlgMatVec.hlsl new file mode 100644 index 0000000000..2b8515bee6 --- /dev/null +++ b/tools/clang/test/DXC/dumpPSV_LinAlgMatVec.hlsl @@ -0,0 +1,60 @@ +// REQUIRES: dxil-1-10 +// RUN: %dxc -enable-16bit-types -E main -T cs_6_10 %s -Fo %t +// RUN: %dxa %t -dumppsv | FileCheck %s + +#include +using namespace dx::linalg; + +ByteAddressBuffer Input : register(t0); +RWStructuredBuffer > HalfOutput : register(u0); +RWStructuredBuffer FloatOutput : register(u1); +RWStructuredBuffer IntOutput : register(u2); +RWStructuredBuffer UintOutput : register(u3); + +using HalfA = + Matrix; +using FloatA = + Matrix; +using IntA = + Matrix; + +[numthreads(4, 4, 1)] +void main(uint Index : SV_GroupIndex) { + HalfA MulOptimal = + HalfA::Load(Input, 0, 0); + HalfOutput[Index] = Multiply(MulOptimal, (vector)1.0h); + + FloatA Transposed = + FloatA::Load(Input, 64, 0); + FloatOutput[Index] = + MultiplyAdd(Transposed, (float4)2.0f, (float4)3.0f); + + IntA RowMajor = + IntA::Load(Input, 128, 16); + IntOutput[Index] = Multiply(RowMajor, (int4)4); + + IntA MaybeTransposed = + IntA::Load(Input, 192, 0); + IntA MaybeRowMajor = + IntA::Load(Input, 256, 16); + IntA Selected = MaybeTransposed; + if (Index) + Selected = MaybeRowMajor; + InterpretedVector UnsignedInput = + MakeInterpretedVector((uint4)5); + UintOutput[Index] = Multiply(Selected, UnsignedInput); +} + +// CHECK: LinAlgRuntimeInfoPresent: true +// CHECK: PSVLinAlgRuntimeInfo: +// CHECK-NEXT: MatrixOperationShapeCount: 0 +// CHECK-NEXT: MatrixConstructionCount: 0 +// CHECK-NEXT: ThreadMatrixVectorMultiplyCount: 4 +// CHECK-NEXT: WaveMatrixMultiplyCount: 0 +// CHECK-NEXT: ThreadGroupMatrixMultiplyCount: 0 +// CHECK-NEXT: OuterProductCount: 0 +// CHECK-NEXT: AccumulateStoreCount: 0 +// CHECK-NEXT: ThreadMatrixVectorMultiply[0]: ResultType=8, MatrixType=8, VectorInputType=8, Flags=0 +// CHECK-NEXT: ThreadMatrixVectorMultiply[1]: ResultType=9, MatrixType=9, VectorInputType=9, Flags=1 +// CHECK-NEXT: ThreadMatrixVectorMultiply[2]: ResultType=4, MatrixType=4, VectorInputType=4, Flags=2 +// CHECK-NEXT: ThreadMatrixVectorMultiply[3]: ResultType=5, MatrixType=4, VectorInputType=5, Flags=3 diff --git a/tools/clang/test/DXC/dumpPSV_LinAlgMatrixMultiply.hlsl b/tools/clang/test/DXC/dumpPSV_LinAlgMatrixMultiply.hlsl new file mode 100644 index 0000000000..39d622c36d --- /dev/null +++ b/tools/clang/test/DXC/dumpPSV_LinAlgMatrixMultiply.hlsl @@ -0,0 +1,66 @@ +// REQUIRES: dxil-1-10 +// RUN: %dxc -enable-16bit-types -E main -T cs_6_10 %s -Fo %t +// RUN: %dxa %t -dumppsv | FileCheck %s + +#include +using namespace dx::linalg; + +RWByteAddressBuffer Output : register(u0); + +using WaveA0 = + Matrix; +using WaveB0 = + Matrix; +using WaveAccumulator0 = Matrix; +using WaveA1 = + Matrix; +using WaveB1 = + Matrix; +using WaveAccumulator1 = Matrix; + +using GroupA = + Matrix; +using GroupB = + Matrix; +using GroupAccumulator = + Matrix; + +[numthreads(4, 4, 1)] +void main() { + WaveA0 A0 = WaveA0::Splat(1.0h); + WaveB0 B0 = WaveB0::Splat(2); + WaveAccumulator0 C0 = Multiply(A0, B0); + C0.Store(Output, 0, 16, MatrixLayout::RowMajor); + + WaveA1 A1 = WaveA1::Splat(3.0h); + WaveB1 B1 = WaveB1::Splat(4); + WaveAccumulator1 C1 = WaveAccumulator1::Splat(5.0f); + C1.MultiplyAccumulate(A1, B1); + C1.Store(Output, 128, 24, MatrixLayout::RowMajor); + + GroupA GA = GroupA::Splat(6); + GroupB GB = GroupB::Splat(7u); + GroupAccumulator GC = Multiply(GA, GB); + GC.Store(Output, 256, 20, MatrixLayout::RowMajor); +} + +// CHECK: LinAlgRuntimeInfoPresent: true +// CHECK: PSVLinAlgRuntimeInfo: +// CHECK-NEXT: MatrixOperationShapeCount: 12 +// CHECK-NEXT: MatrixConstructionCount: 6 +// CHECK-NEXT: ThreadMatrixVectorMultiplyCount: 0 +// CHECK-NEXT: WaveMatrixMultiplyCount: 1 +// CHECK-NEXT: ThreadGroupMatrixMultiplyCount: 1 +// CHECK-NEXT: OuterProductCount: 0 +// CHECK-NEXT: AccumulateStoreCount: 0 +// CHECK-NEXT: MatrixConstruction[0]: MatrixType=4, Shapes=[(3,0,4)] +// CHECK-NEXT: MatrixConstruction[1]: MatrixType=4, Shapes=[(0,4,4), (0,6,7)] +// CHECK-NEXT: MatrixConstruction[2]: MatrixType=4, Shapes=[(3,5,0)] +// CHECK-NEXT: MatrixConstruction[3]: MatrixType=5, Shapes=[(0,5,4)] +// CHECK-NEXT: MatrixConstruction[4]: MatrixType=8, Shapes=[(2,0,4), (5,0,7)] +// CHECK-NEXT: MatrixConstruction[5]: MatrixType=9, Shapes=[(2,4,0), (5,6,0)] +// CHECK-NEXT: WaveMatrixMultiply[0]: AccumulatorType=9, MatrixAType=8, MatrixBType=4, Shapes=[(2,4,4), (5,6,7)] +// CHECK-NEXT: ThreadGroupMatrixMultiply[0]: AccumulatorType=4, MatrixAType=4, MatrixBType=5, Shapes=[(3,5,4)] diff --git a/tools/clang/test/DXC/dumpPSV_MS.hlsl b/tools/clang/test/DXC/dumpPSV_MS.hlsl index e34c5c46ab..dad2afaf8a 100644 --- a/tools/clang/test/DXC/dumpPSV_MS.hlsl +++ b/tools/clang/test/DXC/dumpPSV_MS.hlsl @@ -20,6 +20,7 @@ // CHECK-NEXT: SigOutputVectors[2]: 0 // CHECK-NEXT: SigOutputVectors[3]: 0 // CHECK-NEXT: EntryFunctionName: main +// CHECK-NEXT: LinAlgRuntimeInfoPresent: false // CHECK-NEXT: ResourceCount : 0 // CHECK-NEXT: PSVSignatureElement: // CHECK-NEXT: SemanticName: diff --git a/tools/clang/test/DXC/dumpPSV_PS.hlsl b/tools/clang/test/DXC/dumpPSV_PS.hlsl index ce640799ef..941ac335ae 100644 --- a/tools/clang/test/DXC/dumpPSV_PS.hlsl +++ b/tools/clang/test/DXC/dumpPSV_PS.hlsl @@ -1,4 +1,4 @@ -// REQUIRES: dxil-1-8 +// REQUIRES: dxil-1-10 // RUN: %dxc -E main -T ps_6_8 %s -Fo %t // RUN: %dxa %t -dumppsv | FileCheck %s @@ -19,6 +19,7 @@ // CHECK-NEXT: SigOutputVectors[2]: 0 // CHECK-NEXT: SigOutputVectors[3]: 0 // CHECK-NEXT: EntryFunctionName: main +// CHECK-NEXT: LinAlgRuntimeInfoPresent: false // CHECK-NEXT: ResourceCount : 3 // CHECK-NEXT: PSVResourceBindInfo: // CHECK-NEXT: Space: 0 diff --git a/tools/clang/test/DXC/dumpPSV_VS.hlsl b/tools/clang/test/DXC/dumpPSV_VS.hlsl index 20b4266998..a8de545ae3 100644 --- a/tools/clang/test/DXC/dumpPSV_VS.hlsl +++ b/tools/clang/test/DXC/dumpPSV_VS.hlsl @@ -1,4 +1,4 @@ -// REQUIRES: dxil-1-8 +// REQUIRES: dxil-1-10 // RUN: %dxc -E main -T vs_6_8 %s -Fo %t // RUN: %dxa %t -dumppsv | FileCheck %s @@ -18,6 +18,7 @@ // CHECK-NEXT: SigOutputVectors[2]: 0 // CHECK-NEXT: SigOutputVectors[3]: 0 // CHECK-NEXT: EntryFunctionName: main +// CHECK-NEXT: LinAlgRuntimeInfoPresent: false // CHECK-NEXT: ResourceCount : 1 // CHECK-NEXT: PSVResourceBindInfo: // CHECK-NEXT: Space: 0 diff --git a/tools/clang/test/DXC/experimental-dxil-6-10-op.ll b/tools/clang/test/DXC/experimental-dxil-6-11-op.ll similarity index 94% rename from tools/clang/test/DXC/experimental-dxil-6-10-op.ll rename to tools/clang/test/DXC/experimental-dxil-6-11-op.ll index 2e94fdc6a2..f1beeedae0 100644 --- a/tools/clang/test/DXC/experimental-dxil-6-10-op.ll +++ b/tools/clang/test/DXC/experimental-dxil-6-11-op.ll @@ -1,4 +1,4 @@ -; REQUIRES: dxil-1-10 +; REQUIRES: dxil-1-11 ; RUN: %dxa %s -o %t.dxil | FileCheck %s -check-prefix=DXA ; RUN: %dxc -dumpbin %t.dxil | FileCheck %s -check-prefix=DXIL ; RUN: %dxv %t.dxil -o %t.hash.dxil 2>&1 | FileCheck %s -check-prefix=VAL @@ -36,8 +36,8 @@ attributes #0 = { nounwind readnone } !dx.entryPoints = !{!4} !0 = !{!"custom IR"} -!1 = !{i32 1, i32 10} -!2 = !{!"cs", i32 6, i32 10} +!1 = !{i32 1, i32 11} +!2 = !{!"cs", i32 6, i32 11} !3 = !{null, null, null, null} !4 = !{void ()* @main, !"main", null, !3, !5} !5 = !{i32 0, i64 0, i32 4, !6} diff --git a/tools/clang/test/DXC/template_uninitialized_values.hlsl b/tools/clang/test/DXC/template_uninitialized_values.hlsl new file mode 100644 index 0000000000..300309cf75 --- /dev/null +++ b/tools/clang/test/DXC/template_uninitialized_values.hlsl @@ -0,0 +1,81 @@ +// RUN: %dxc -E main -T cs_6_6 -HV 2021 -Wno-unused-value %s | FileCheck %s + +// Asserts in UninitializedValues.cpp were triggered by the following code +// examples. The cause was that HLSL out parameters or local variables from +// template instantiations may not be present in the declToIndex map when the +// variable's DeclContext differs from the analysis context (common in +// template instantiations). +// The fix was to add defensive checks so that if the variable isn't tracked +// it is silently ignored. + +// CHECK: define void @main() + +template +void test(R x, out uint result) { + uint repro = 0; + result = 10; +} + +[numthreads(32, 32, 1)] void main(uint2 threadId: SV_DispatchThreadID) { + uint x; + test(10, x); +} + +template +void func2(out uint var1) +{ + uint var3; + uint var4; + uint var5; + uint var6; + uint var7; + uint var8; + uint var9; + uint var10; + uint var11; + uint var12; + uint var13; + uint var14; + uint var15; + uint var16; + uint var17; + uint var18; + uint var19; + uint var20; + uint var21; + uint var22; + uint var23; + uint var24; + uint var25; + uint var26; + uint var27; + uint var28; + uint var29; + uint var30; + uint var31; + var1; +} + +// Exercise the defensive ClassifyRefs::Init path when an unmapped out +// parameter is forwarded to another out parameter through a template call. +template +void func3(out uint var1, out uint var2) +{ + var2 = var1; +} + +template +void func4(out uint var1) +{ + uint var2; + func3(var1, var2); +} + +void func1() +{ + uint var33; + func2(var33); + + uint var34; + func4(var34); +} diff --git a/tools/clang/test/HLSL/cpp-errors-hv2015.hlsl b/tools/clang/test/HLSL/cpp-errors-hv2015.hlsl index 57c512741c..56715770cd 100644 --- a/tools/clang/test/HLSL/cpp-errors-hv2015.hlsl +++ b/tools/clang/test/HLSL/cpp-errors-hv2015.hlsl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -HV 2015 -fsyntax-only -Wno-unused-value -ffreestanding -verify %s +// RUN: %clang_cc1 -Wno-hlsl-buffer-initializer -HV 2015 -fsyntax-only -Wno-unused-value -ffreestanding -verify %s float f_arr_empty_init[] = { 1, 2, 3 }; float f_arr_empty_pack[] = { 1, 2 ... }; // expected-error {{expansion is unsupported in HLSL}} @@ -59,7 +59,7 @@ struct s_with_friend { friend void some_fn(); // expected-error {{'friend' is a reserved keyword in HLSL}} }; -typedef int (*fn_int_const)(int) const; // expected-error {{expected ';' after top level declarator}} expected-error {{pointers are unsupported in HLSL}} expected-warning {{declaration does not declare anything}} +typedef int (*fn_int_const)(int) const; // expected-error {{const-qualified member functions are unsupported in HLSL before 202x}} expected-error {{pointers are unsupported in HLSL}} typedef int (*fn_int_volatile)(int) volatile; // expected-error {{'volatile' is a reserved keyword in HLSL}} expected-error {{expected ';' after top level declarator}} expected-error {{pointers are unsupported in HLSL}} expected-warning {{declaration does not declare anything}} void fn_throw() throw() { } // expected-error {{exception specification is unsupported in HLSL}} diff --git a/tools/clang/test/HLSL/cpp-errors.hlsl b/tools/clang/test/HLSL/cpp-errors.hlsl index 1ecf4a57e1..8a20c3b2fc 100644 --- a/tools/clang/test/HLSL/cpp-errors.hlsl +++ b/tools/clang/test/HLSL/cpp-errors.hlsl @@ -1,18 +1,18 @@ // RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -ffreestanding -HV 2018 -verify %s -float f_arr_empty_init[] = { 1, 2, 3 }; +float f_arr_empty_init[] = { 1, 2, 3 }; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ float f_arr_empty_pack[] = { 1, 2 ... }; // expected-error {{expansion is unsupported in HLSL}} struct s_arr_i_f { int i; float f; }; -s_arr_i_f arr_struct_none[] = { }; // TODO: this should fail - see comments in HLSLExternalSource::InitializeInitSequenceForHLSL -s_arr_i_f arr_struct_one[] = { 1, 2 }; +s_arr_i_f arr_struct_none[] = { }; // TODO: this should fail - see comments in HLSLExternalSource::InitializeInitSequenceForHLSL /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ +s_arr_i_f arr_struct_one[] = { 1, 2 }; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ s_arr_i_f arr_struct_incomplete[] = { 1, 2, 3 }; // expected-error {{too few elements in vector initialization (expected 4 elements, have 3)}} -s_arr_i_f arr_struct_two[] = { 1, 2, 3, 4 }; +s_arr_i_f arr_struct_two[] = { 1, 2, 3, 4 }; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ int g_int; typeof(g_int) g_typeof_int; // expected-error {{HLSL requires a type specifier for all declarations}} expected-error {{expected ';' after top level declarator}} expected-error {{unknown type name 'typeof'; did you mean 'typedef'?}} typedef int (*fn_int)(int); // expected-error {{pointers are unsupported in HLSL}} -auto g_auto = 3; // auto is now supported in HLSL via type deduction; no error expected +auto g_auto = 3; // auto is now supported in HLSL via type deduction; no error expected /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ __is_signed g_is_signed; // expected-error {{'__is_signed' is a reserved keyword in HLSL}} expected-error {{HLSL requires a type specifier for all declarations}} register int g_register; // expected-error {{'register' is a reserved keyword in HLSL}} __thread int g_thread; // expected-error {{'__thread' is a reserved keyword in HLSL}} @@ -56,7 +56,7 @@ struct s_with_friend { friend void some_fn(); // expected-error {{'friend' is a reserved keyword in HLSL}} }; -typedef int (*fn_int_const)(int) const; // expected-error {{expected ';' after top level declarator}} expected-error {{pointers are unsupported in HLSL}} expected-warning {{declaration does not declare anything}} +typedef int (*fn_int_const)(int) const; // expected-error {{const-qualified member functions are unsupported in HLSL before 202x}} expected-error {{pointers are unsupported in HLSL}} typedef int (*fn_int_volatile)(int) volatile; // expected-error {{'volatile' is a reserved keyword in HLSL}} expected-error {{expected ';' after top level declarator}} expected-error {{pointers are unsupported in HLSL}} expected-warning {{declaration does not declare anything}} void fn_throw() throw() { } // expected-error {{exception specification is unsupported in HLSL}} @@ -321,7 +321,7 @@ struct forward_struct; // this fails in fxc, but we allow it now struct my_struct_type_decl { int a; } my_struct_var_decl; struct my_struct_type_decl_parens { int a; } (my_struct_var_decl_parens); // expected-error {{HLSL requires a type specifier for all declarations}} expected-error {{expected ';' after struct}} struct my_struct_type_const { int a; } const my_struct_type_var; // // expected-error {{HLSL requires a type specifier for all declarations}} expected-error {{expected ';' after struct}} -struct my_struct_type_init { int a; } my_struct_type_init_one = { 1 }, my_struct_type_init_two = { 2 }; +struct my_struct_type_init { int a; } my_struct_type_init_one = { 1 }, my_struct_type_init_two = { 2 }; /* expected-warning 2 {{initializer for a variable in a cbuffer will be ignored}} */ struct my_struct_type_static { int a; } static my_struct_type_static; // expected-error {{expected ';' after struct}} expected-warning {{declaration does not declare anything}} struct { int my_anon_struct_field; } my_anon_struct_type; diff --git a/tools/clang/test/HLSL/rewriter/cpp-errors_noerr.hlsl b/tools/clang/test/HLSL/rewriter/cpp-errors_noerr.hlsl index 44c3f33538..3719729439 100644 --- a/tools/clang/test/HLSL/rewriter/cpp-errors_noerr.hlsl +++ b/tools/clang/test/HLSL/rewriter/cpp-errors_noerr.hlsl @@ -1,13 +1,13 @@ // RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -ffreestanding -verify %s -float f_arr_empty_init[] = { 1, 2, 3 }; +float f_arr_empty_init[] = { 1, 2, 3 }; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ //float f_arr_empty_pack[] = { 1, 2 ... }; // expected-error {{expansion is unsupported in HLSL}} struct s_arr_i_f { int i; float f; }; -s_arr_i_f arr_struct_none[] = { }; // TODO: this should fail - see comments in HLSLExternalSource::InitializeInitSequenceForHLSL -s_arr_i_f arr_struct_one[] = { 1, 2 }; +s_arr_i_f arr_struct_none[] = { }; // TODO: this should fail - see comments in HLSLExternalSource::InitializeInitSequenceForHLSL /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ +s_arr_i_f arr_struct_one[] = { 1, 2 }; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ //s_arr_i_f arr_struct_incomplete[] = { 1, 2, 3 }; // expected-error {{too few elements in vector initialization (expected 4 elements, have 3)}} -s_arr_i_f arr_struct_two[] = { 1, 2, 3, 4 }; +s_arr_i_f arr_struct_two[] = { 1, 2, 3, 4 }; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ int g_int; //typeof(g_int) g_typeof_int; // expected-error {{unknown type name 'typeof'; did you mean 'typedef'?}} expected-error {{HLSL requires a type specifier for all declarations}} expected-error {{expected ';' after top level declarator}} @@ -332,7 +332,7 @@ struct my_struct_5 : my_class, my_interface { }; struct my_struct_type_decl { int a; } my_struct_var_decl; //struct my_struct_type_decl_parens { int a; } (my_struct_var_decl_parens); // expected-error {{expected ';' after struct}} expected-error {{HLSL requires a type specifier for all declarations}} //struct my_struct_type_const { int a; } const my_struct_type_var; // // expected-error {{expected ';' after struct}} expected-error {{HLSL requires a type specifier for all declarations}} -struct my_struct_type_init { int a; } my_struct_type_init_one = { 1 }, my_struct_type_init_two = { 2 }; +struct my_struct_type_init { int a; } my_struct_type_init_one = { 1 }, my_struct_type_init_two = { 2 }; /* expected-warning 2 {{initializer for a variable in a cbuffer will be ignored}} */ //struct my_struct_type_static { int a; } static my_struct_type_static; // expected-error {{expected ';' after struct}} expected-warning {{declaration does not declare anything}} struct { int my_anon_struct_field; } my_anon_struct_type; diff --git a/tools/clang/test/HLSL/rewriter/typemods-syntax_noerr.hlsl b/tools/clang/test/HLSL/rewriter/typemods-syntax_noerr.hlsl index 0616f75cdd..6c76f9af91 100644 --- a/tools/clang/test/HLSL/rewriter/typemods-syntax_noerr.hlsl +++ b/tools/clang/test/HLSL/rewriter/typemods-syntax_noerr.hlsl @@ -263,14 +263,14 @@ cbuffer CBInit { // modify(lines, gen_code('%(mods)s float2x3 g_%(id)s_init = sc_%(id)s_init_scalar;')) // GENERATED_CODE:BEGIN - row_major float2x3 g_row_init = sc_row_init_scalar; - row_major snorm float2x3 g_row_sno_init = sc_row_sno_init_scalar; - row_major unorm float2x3 g_row_uno_init = sc_row_uno_init_scalar; - column_major float2x3 g_col_init = sc_col_init_scalar; - column_major snorm float2x3 g_col_sno_init = sc_col_sno_init_scalar; - column_major unorm float2x3 g_col_uno_init = sc_col_uno_init_scalar; - snorm float2x3 g_sno_init = sc_sno_init_scalar; - unorm float2x3 g_uno_init = sc_uno_init_scalar; + row_major float2x3 g_row_init = sc_row_init_scalar; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ + row_major snorm float2x3 g_row_sno_init = sc_row_sno_init_scalar; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ + row_major unorm float2x3 g_row_uno_init = sc_row_uno_init_scalar; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ + column_major float2x3 g_col_init = sc_col_init_scalar; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ + column_major snorm float2x3 g_col_sno_init = sc_col_sno_init_scalar; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ + column_major unorm float2x3 g_col_uno_init = sc_col_uno_init_scalar; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ + snorm float2x3 g_sno_init = sc_sno_init_scalar; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ + unorm float2x3 g_uno_init = sc_uno_init_scalar; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ //row_major column_major float2x3 g_row_col_init = sc_row_col_init_scalar; /* expected-error {{'row_major' and 'column_major' attributes are not compatible}} fxc-error {{X3048: matrix types cannot be both column_major and row_major}} */ //row_major column_major snorm float2x3 g_row_col_sno_init = sc_row_col_sno_init_scalar; /* expected-error {{'row_major' and 'column_major' attributes are not compatible}} fxc-error {{X3048: matrix types cannot be both column_major and row_major}} */ //row_major column_major snorm unorm float2x3 g_row_col_sno_uno_init = sc_row_col_sno_uno_init_scalar; /* expected-error {{'row_major' and 'column_major' attributes are not compatible}} expected-error {{'unorm' and 'snorm' attributes are not compatible}} fxc-error {{X3000: syntax error: unexpected token 'unorm'}} */ @@ -282,14 +282,14 @@ cbuffer CBInit // modify(lines, gen_code('%(mods)s float2x3 g_%(id)s_init_scalar = 1.0f;')) // GENERATED_CODE:BEGIN - row_major float2x3 g_row_init_scalar = 1.0f; - row_major snorm float2x3 g_row_sno_init_scalar = 1.0f; - row_major unorm float2x3 g_row_uno_init_scalar = 1.0f; - column_major float2x3 g_col_init_scalar = 1.0f; - column_major snorm float2x3 g_col_sno_init_scalar = 1.0f; - column_major unorm float2x3 g_col_uno_init_scalar = 1.0f; - snorm float2x3 g_sno_init_scalar = 1.0f; - unorm float2x3 g_uno_init_scalar = 1.0f; + row_major float2x3 g_row_init_scalar = 1.0f; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ + row_major snorm float2x3 g_row_sno_init_scalar = 1.0f; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ + row_major unorm float2x3 g_row_uno_init_scalar = 1.0f; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ + column_major float2x3 g_col_init_scalar = 1.0f; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ + column_major snorm float2x3 g_col_sno_init_scalar = 1.0f; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ + column_major unorm float2x3 g_col_uno_init_scalar = 1.0f; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ + snorm float2x3 g_sno_init_scalar = 1.0f; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ + unorm float2x3 g_uno_init_scalar = 1.0f; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ //row_major column_major float2x3 g_row_col_init_scalar = 1.0f; /* expected-error {{'row_major' and 'column_major' attributes are not compatible}} fxc-error {{X3048: matrix types cannot be both column_major and row_major}} */ //row_major column_major snorm float2x3 g_row_col_sno_init_scalar = 1.0f; /* expected-error {{'row_major' and 'column_major' attributes are not compatible}} fxc-error {{X3048: matrix types cannot be both column_major and row_major}} */ //row_major column_major snorm unorm float2x3 g_row_col_sno_uno_init_scalar = 1.0f; /* expected-error {{'row_major' and 'column_major' attributes are not compatible}} expected-error {{'unorm' and 'snorm' attributes are not compatible}} fxc-error {{X3000: syntax error: unexpected token 'unorm'}} */ @@ -683,4 +683,4 @@ class C // return (float3x4) 1.0; //} -}; \ No newline at end of file +}; diff --git a/tools/clang/test/HLSL/rewriter/varmods-syntax_noerr.hlsl b/tools/clang/test/HLSL/rewriter/varmods-syntax_noerr.hlsl index b0e205a869..9f009571da 100644 --- a/tools/clang/test/HLSL/rewriter/varmods-syntax_noerr.hlsl +++ b/tools/clang/test/HLSL/rewriter/varmods-syntax_noerr.hlsl @@ -174,12 +174,12 @@ groupshared const float g_gro_con_init = 1.0f; //extern volatile float g_ext_vol_init = 1.0f; /* expected-error {{'volatile' is not a valid modifier for a global variable}} fxc-error {{X3008: 'g_ext_vol_init': global variables cannot be declared 'volatile'}} */ //extern volatile const float g_ext_vol_con_init = 1.0f; /* expected-error {{'volatile' is not a valid modifier for a global variable}} fxc-error {{X3008: 'g_ext_vol_con_init': global variables cannot be declared 'volatile'}} */ //extern const float g_ext_con_init = 1.0f; /* expected-warning {{'extern' variable has an initializer}} fxc-warning {{X3207: Initializer used on a global 'const' variable. This requires setting an external constant. If a literal is desired, use 'static const' instead.}} */ -precise float g_pre_init = 1.0f; +precise float g_pre_init = 1.0f; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ precise static float g_pre_sta_init = 1.0f; //precise static volatile float g_pre_sta_vol_init = 1.0f; /* expected-error {{'volatile' is not a valid modifier for a global variable}} fxc-error {{X3008: 'g_pre_sta_vol_init': global variables cannot be declared 'volatile'}} */ //precise static volatile const float g_pre_sta_vol_con_init = 1.0f; /* expected-error {{'volatile' is not a valid modifier for a global variable}} fxc-error {{X3008: 'g_pre_sta_vol_con_init': global variables cannot be declared 'volatile'}} */ precise static const float g_pre_sta_con_init = 1.0f; -precise uniform float g_pre_uni_init = 1.0f; +precise uniform float g_pre_uni_init = 1.0f; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ //precise uniform volatile float g_pre_uni_vol_init = 1.0f; /* expected-error {{'volatile' is not a valid modifier for a global variable}} fxc-error {{X3008: 'g_pre_uni_vol_init': global variables cannot be declared 'volatile'}} */ //precise uniform volatile const float g_pre_uni_vol_con_init = 1.0f; /* expected-error {{'volatile' is not a valid modifier for a global variable}} fxc-error {{X3008: 'g_pre_uni_vol_con_init': global variables cannot be declared 'volatile'}} */ //precise uniform const float g_pre_uni_con_init = 1.0f; /* fxc-warning {{X3207: Initializer used on a global 'const' variable. This requires setting an external constant. If a literal is desired, use 'static const' instead.}} */ @@ -190,7 +190,7 @@ static float g_sta_init = 1.0f; //static volatile float g_sta_vol_init = 1.0f; /* expected-error {{'volatile' is not a valid modifier for a global variable}} fxc-error {{X3008: 'g_sta_vol_init': global variables cannot be declared 'volatile'}} */ //static volatile const float g_sta_vol_con_init = 1.0f; /* expected-error {{'volatile' is not a valid modifier for a global variable}} fxc-error {{X3008: 'g_sta_vol_con_init': global variables cannot be declared 'volatile'}} */ static const float g_sta_con_init = 1.0f; -uniform float g_uni_init = 1.0f; +uniform float g_uni_init = 1.0f; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */ //uniform volatile float g_uni_vol_init = 1.0f; /* expected-error {{'volatile' is not a valid modifier for a global variable}} fxc-error {{X3008: 'g_uni_vol_init': global variables cannot be declared 'volatile'}} */ //uniform volatile const float g_uni_vol_con_init = 1.0f; /* expected-error {{'volatile' is not a valid modifier for a global variable}} fxc-error {{X3008: 'g_uni_vol_con_init': global variables cannot be declared 'volatile'}} */ //uniform const float g_uni_con_init = 1.0f; /* fxc-warning {{X3207: Initializer used on a global 'const' variable. This requires setting an external constant. If a literal is desired, use 'static const' instead.}} */ diff --git a/tools/clang/test/HLSLFileCheck/hlsl/classes/const_method_202x_codegen.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/classes/const_method_202x_codegen.hlsl new file mode 100644 index 0000000000..4394df7a01 --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/hlsl/classes/const_method_202x_codegen.hlsl @@ -0,0 +1,28 @@ +// RUN: %dxc -T ps_6_0 -E main -HV 202x %s | FileCheck %s + +// Verify that const-instance methods generate valid DXIL: a const method +// called on a non-const local lvalue should be inlined as a normal read of +// the object's fields, and a const method called on a cbuffer member should +// lower to cbufferLoadLegacy. + +struct S { + int x; + int y; + int sum() const { return x + y; } +}; + +cbuffer CB { S cs; }; + +int main(int idx : A) : SV_Target { + S ls = {3, 4}; + return ls.sum() + cs.sum(); +} + +// CHECK: define void @main() +// CHECK: call %dx.types.Handle @dx.op.createHandle( +// CHECK: call %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32( +// The 3+4 from the local 'ls' is constant-folded to 7 and added to the +// two i32 lanes loaded from the cbuffer. +// CHECK: add i32 {{.*}}, 7 +// CHECK: call void @dx.op.storeOutput.i32( +// CHECK: ret void diff --git a/tools/clang/test/HLSLFileCheck/hlsl/classes/const_resource_local.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/classes/const_resource_local.hlsl new file mode 100644 index 0000000000..24e0c0a76b --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/hlsl/classes/const_resource_local.hlsl @@ -0,0 +1,41 @@ +// RUN: %dxc -T ps_6_6 -E main -HV 202x %s | FileCheck %s + +// Verify that const local resource objects can still be used through their +// instance methods (which are now properly marked const). A const handle only +// prevents reassigning the handle, so writing through a const RW resource is +// still allowed. + +Texture2D tex : register(t0); +SamplerState samp : register(s0); +RWBuffer buf : register(u0); +ByteAddressBuffer bab : register(t1); +StructuredBuffer sb : register(t2); + +// CHECK: define void @main() +float4 main(float2 uv : TEXCOORD) : SV_Target { + const Texture2D ltex = tex; + const SamplerState lsamp = samp; + const RWBuffer lbuf = buf; + const ByteAddressBuffer lbab = bab; + const StructuredBuffer lsb = sb; + + // CHECK: call %dx.types.ResRet.f32 @dx.op.sample.f32(i32 60, + float4 sampled = ltex.Sample(lsamp, uv); + // CHECK: call %dx.types.ResRet.f32 @dx.op.textureLoad.f32(i32 66, + float4 loaded = ltex.Load(int3(0, 0, 0)); + // CHECK: call %dx.types.ResRet.f32 @dx.op.bufferLoad.f32(i32 68, + float4 fromBuf = lbuf.Load(0); + // CHECK: call %dx.types.ResRet.i32 @dx.op.rawBufferLoad.i32(i32 139, {{.*}}, i32 0, i32 undef, + uint raw = lbab.Load(0); + // CHECK: call %dx.types.ResRet.i32 @dx.op.rawBufferLoad.i32(i32 139, {{.*}}, i32 0, i32 0, + int si = lsb.Load(0); + + // CHECK: call %dx.types.Dimensions @dx.op.getDimensions(i32 72, + uint w, h, l; + ltex.GetDimensions(0, w, h, l); + + // CHECK: call void @dx.op.bufferStore.f32(i32 69, + lbuf[1] = sampled; + + return sampled + loaded + fromBuf + float4(raw, si, w, h); +} diff --git a/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/count_cbuff.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/count_cbuff.hlsl index 8bb0b0fc3a..42aeba751d 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/count_cbuff.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/count_cbuff.hlsl @@ -1,4 +1,4 @@ -// RUN: %dxc -E main -T ps_6_0 %s | FileCheck %s +// RUN: %dxc -E main -T ps_6_0 -HV 2021 %s | FileCheck %s // CHECK: call float @dx.op.dot3 // CHECK: call float @dx.op.dot3 diff --git a/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/count_greater_than_i.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/count_greater_than_i.hlsl index d86da03dca..b0d6c787cb 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/count_greater_than_i.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/count_greater_than_i.hlsl @@ -1,4 +1,4 @@ -// RUN: %dxc -E main -T ps_6_0 %s | FileCheck %s +// RUN: %dxc -E main -T ps_6_0 -HV 2021 %s | FileCheck %s // CHECK: call float @dx.op.dot3 // CHECK: call float @dx.op.dot3 diff --git a/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/count_hint_202x.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/count_hint_202x.hlsl new file mode 100644 index 0000000000..8fec049021 --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/count_hint_202x.hlsl @@ -0,0 +1,24 @@ +// RUN: %dxc -E main -T ps_6_0 -HV 202x -O2 %s | FileCheck %s -check-prefix=O2 +// RUN: %dxc -E main -T ps_6_0 -HV 202x -O3 %s | FileCheck %s -check-prefix=O3 + +// O2: call float @dx.op.dot3 +// O2-NOT: call float @dx.op.dot3 +// O2: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop +// O2: !{!"llvm.loop.unroll.count", i32 3} + +// O3: call float @dx.op.dot3 +// O3: call float @dx.op.dot3 +// O3: call float @dx.op.dot3 +// O3: call float @dx.op.dot3 +// O3-NOT: call float @dx.op.dot3 +// O3: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop +// O3: !{!"llvm.loop.unroll.disable"} + +float main(float3 a : A, float3 b : B) : SV_Target { + float result = 0; + [unroll(3)] + for (int i = 0; i < 10; i++) { + result += dot(a * i, b); + } + return result; +} diff --git a/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/count_less_than_i.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/count_less_than_i.hlsl index a2fc63157d..e85291a644 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/count_less_than_i.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/count_less_than_i.hlsl @@ -1,4 +1,4 @@ -// RUN: %dxc -E main -T ps_6_0 %s | FileCheck %s +// RUN: %dxc -E main -T ps_6_0 -HV 2021 %s | FileCheck %s // CHECK: call float @dx.op.dot3 // CHECK: call float @dx.op.dot3 diff --git a/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/count_runtime_hint_202x.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/count_runtime_hint_202x.hlsl new file mode 100644 index 0000000000..943d6e8a9f --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/count_runtime_hint_202x.hlsl @@ -0,0 +1,46 @@ +// RUN: %dxc -E main -T ps_6_0 -HV 202x -O2 %s | FileCheck %s -check-prefixes=COMMON,O2 +// RUN: %dxc -E main -T ps_6_0 -HV 202x -O3 %s | FileCheck %s -check-prefixes=COMMON,O3 +// RUN: %dxc -E mainPowerOfTwo -T ps_6_0 -HV 202x -O2 %s | FileCheck %s -check-prefixes=COMMON,POWER-O2 +// RUN: %dxc -E mainPowerOfTwo -T ps_6_0 -HV 202x -O3 %s | FileCheck %s -check-prefix=POWER-O3 + +// O2 Doesn't unroll and O3 Runtime unrolling only supports +// power-of-two factors, so the count hint is +// consumed without cloning the loop body. +// COMMON: call float @dx.op.dot3 +// COMMON-NOT: call float @dx.op.dot3 +// COMMON: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop +// O2: !{!"llvm.loop.unroll.count", i32 3} +// O3: !{!"llvm.loop.unroll.disable"} +// POWER-O2: !{!"llvm.loop.unroll.count", i32 4} + +// The O3 output has one remainder-loop body and four unrolled main-loop bodies. +// POWER-O3: and i32 {{.*}}, 3 +// POWER-O3: call float @dx.op.dot3 +// POWER-O3: call float @dx.op.dot3 +// POWER-O3: call float @dx.op.dot3 +// POWER-O3: call float @dx.op.dot3 +// POWER-O3: call float @dx.op.dot3 +// POWER-O3-NOT: call float @dx.op.dot3 +// POWER-O3: add i32 {{.*}}, 4 +// POWER-O3: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop +// POWER-O3: !{!"llvm.loop.unroll.disable"} + +float main(float3 a : A, float3 b : B, + uint iterationCount : COUNT) : SV_Target { + float result = 0; + [unroll(3)] + for (uint i = 0; i < iterationCount; i++) { + result += dot(a * i, b); + } + return result; +} + +float mainPowerOfTwo(float3 a : A, float3 b : B, + uint iterationCount : COUNT) : SV_Target { + float result = 0; + [unroll(4)] + for (uint i = 0; i < iterationCount; i++) { + result += dot(a * i, b); + } + return result; +} diff --git a/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/full_hint_202x.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/full_hint_202x.hlsl new file mode 100644 index 0000000000..38be4d8135 --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/hlsl/control_flow/attributes/unroll/full_hint_202x.hlsl @@ -0,0 +1,25 @@ +// RUN: %dxc -E main -T ps_6_0 -HV 202x -O2 %s | FileCheck %s -check-prefix=CHECK +// RUN: %dxc -E main -T ps_6_0 -HV 202x -O3 %s | FileCheck %s -check-prefix=CHECK + +// CHECK: call float @dx.op.dot3 +// CHECK: call float @dx.op.dot3 +// CHECK: call float @dx.op.dot3 +// CHECK: call float @dx.op.dot3 +// CHECK: call float @dx.op.dot3 +// CHECK: call float @dx.op.dot3 +// CHECK: call float @dx.op.dot3 +// CHECK: call float @dx.op.dot3 +// CHECK: call float @dx.op.dot3 +// CHECK: call float @dx.op.dot3 +// CHECK-NOT: call float @dx.op.dot3 +// CHECK-NOT: br i1 +// CHECK-NOT: !llvm.loop + +float main(float3 a : A, float3 b : B) : SV_Target { + float result = 0; + [unroll] + for (int i = 0; i < 10; i++) { + result += dot(a * i, b); + } + return result; +} diff --git a/tools/clang/test/HLSLFileCheck/hlsl/template/InstantiateObjectMethods.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/template/InstantiateObjectMethods.hlsl index 21f404bf48..f9471a83a4 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/template/InstantiateObjectMethods.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/template/InstantiateObjectMethods.hlsl @@ -18,6 +18,7 @@ float4 main() : SV_Target { // CHECK: CXXMemberCallExpr 0x{{[0-9a-fA-F]+}} 'vector' // CHECK-NEXT: MemberExpr 0x{{[0-9a-fA-F]+}} '' .Load +// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} 'const Texture2D >' // CHECK-NEXT: CXXMemberCallExpr 0x{{[0-9a-fA-F]+}} 'Texture2D >':'Texture2D >' // CHECK-NEXT: MemberExpr 0x{{[0-9a-fA-F]+}} '' .Get // CHECK-NEXT: CXXThisExpr 0x{{[0-9a-fA-F]+}} 'MyTex2D diff --git a/tools/clang/test/HLSLFileCheck/hlsl/workgraph/ast-nodeinput.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/workgraph/ast-nodeinput.hlsl index 7f5de6606b..d7a39c2c74 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/workgraph/ast-nodeinput.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/workgraph/ast-nodeinput.hlsl @@ -18,6 +18,7 @@ void node01(DispatchNodeInputRecord input) {} //CHECK-NEXT: CXXRecordDecl {{0x[0-9a-fA-F]+}} <> implicit struct DispatchNodeInputRecord definition //CHECK-NEXT: FinalAttr {{0x[0-9a-fA-F]+}} <> Implicit final //CHECK-NEXT: HLSLNodeObjectAttr {{0x[0-9a-fA-F]+}} <> Implicit DispatchNodeInputRecord +//CHECK-NEXT: AvailabilityAttr {{0x[0-9a-fA-F]+}} <> Implicit 6.8 6.9 6.10 "" //CHECK-NEXT: FieldDecl {{0x[0-9a-fA-F]+}} <> implicit h 'int' //CHECK-NEXT: CXXMethodDecl {{0x[0-9a-fA-F]+}} <> Get 'const recordtype &() const' //CHECK-NEXT: HLSLIntrinsicAttr {{0x[0-9a-fA-F]+}} <> Implicit "subscript" "" 0 @@ -34,6 +35,7 @@ void node02(GroupNodeInputRecords input) {} //CHECK-NEXT: CXXRecordDecl {{0x[0-9a-fA-F]+}} <> implicit struct GroupNodeInputRecords definition //CHECK-NEXT: FinalAttr {{0x[0-9a-fA-F]+}} <> Implicit final //CHECK-NEXT: HLSLNodeObjectAttr {{0x[0-9a-fA-F]+}} <> Implicit GroupNodeInputRecords +//CHECK-NEXT: AvailabilityAttr {{0x[0-9a-fA-F]+}} <> Implicit 6.8 6.9 6.10 "" //CHECK-NEXT: FieldDecl {{0x[0-9a-fA-F]+}} <> implicit h 'int' //CHECK-NEXT: CXXMethodDecl {{0x[0-9a-fA-F]+}} <> Get 'const recordtype &(unsigned int) const' //CHECK-NEXT: ParmVarDecl {{0x[0-9a-fA-F]+}} <> Index 'unsigned int' cinit @@ -63,6 +65,7 @@ void node03(ThreadNodeInputRecord input) {} //CHECK-NEXT: CXXRecordDecl {{0x[0-9a-fA-F]+}} <> implicit struct ThreadNodeInputRecord definition //CHECK-NEXT: FinalAttr {{0x[0-9a-fA-F]+}} <> Implicit final //CHECK-NEXT: HLSLNodeObjectAttr {{0x[0-9a-fA-F]+}} <> Implicit ThreadNodeInputRecord +//CHECK-NEXT: AvailabilityAttr {{0x[0-9a-fA-F]+}} <> Implicit 6.8 6.9 6.10 "" //CHECK-NEXT: FieldDecl {{0x[0-9a-fA-F]+}} <> implicit h 'int' //CHECK-NEXT: CXXMethodDecl {{0x[0-9a-fA-F]+}} <> Get 'const recordtype &() const' //CHECK-NEXT: HLSLIntrinsicAttr {{0x[0-9a-fA-F]+}} <> Implicit "subscript" "" 0 diff --git a/tools/clang/test/HLSLFileCheck/hlsl/workgraph/ast-nodeoutput.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/workgraph/ast-nodeoutput.hlsl index 423db5292f..89e17e5d47 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/workgraph/ast-nodeoutput.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/workgraph/ast-nodeoutput.hlsl @@ -23,6 +23,7 @@ void node01(NodeOutput output) //CHECK-NEXT: CXXRecordDecl {{0x[0-9a-fA-F]+}} <> implicit struct GroupNodeOutputRecords definition //CHECK-NEXT: FinalAttr {{0x[0-9a-fA-F]+}} <> Implicit final //CHECK-NEXT: HLSLNodeObjectAttr {{0x[0-9a-fA-F]+}} <> Implicit GroupNodeOutputRecords +//CHECK-NEXT: AvailabilityAttr {{0x[0-9a-fA-F]+}} <> Implicit 6.8 6.9 6.10 "" //CHECK-NEXT: FieldDecl {{0x[0-9a-fA-F]+}} <> implicit h 'int' //CHECK-NEXT: CXXMethodDecl {{0x[0-9a-fA-F]+}} <> operator[] 'recordType &(unsigned int)' //CHECK-NEXT: ParmVarDecl {{0x[0-9a-fA-F]+}} <> Index 'unsigned int' @@ -54,6 +55,7 @@ void node01(NodeOutput output) //CHECK-NEXT: TemplateArgument type 'RECORD' //CHECK-NEXT: FinalAttr {{0x[0-9a-fA-F]+}} <> Implicit final //CHECK-NEXT: HLSLNodeObjectAttr {{0x[0-9a-fA-F]+}} <> Implicit GroupNodeOutputRecords +//CHECK-NEXT: AvailabilityAttr {{0x[0-9a-fA-F]+}} <> Implicit 6.8 6.9 6.10 "" //CHECK-NEXT: FieldDecl {{0x[0-9a-fA-F]+}} <> implicit h 'int' //CHECK-NEXT: CXXMethodDecl {{0x[0-9a-fA-F]+}} <> operator[] 'RECORD &(unsigned int)' //CHECK-NEXT: ParmVarDecl {{0x[0-9a-fA-F]+}} <> Index 'unsigned int' @@ -95,6 +97,7 @@ void node02(NodeOutput output) //CHECK-NEXT: CXXRecordDecl {{0x[0-9a-fA-F]+}} <> implicit struct ThreadNodeOutputRecords definition //CHECK-NEXT: FinalAttr {{0x[0-9a-fA-F]+}} <> Implicit final //CHECK-NEXT: HLSLNodeObjectAttr {{0x[0-9a-fA-F]+}} <> Implicit ThreadNodeOutputRecords +//CHECK-NEXT: AvailabilityAttr {{0x[0-9a-fA-F]+}} <> Implicit 6.8 6.9 6.10 "" //CHECK-NEXT: FieldDecl {{0x[0-9a-fA-F]+}} <> implicit h 'int' //CHECK-NEXT: CXXMethodDecl {{0x[0-9a-fA-F]+}} <> operator[] 'recordType &(unsigned int)' //CHECK-NEXT: ParmVarDecl {{0x[0-9a-fA-F]+}} <> Index 'unsigned int' @@ -126,6 +129,7 @@ void node02(NodeOutput output) //CHECK-NEXT: TemplateArgument type 'RECORD' //CHECK-NEXT: FinalAttr {{0x[0-9a-fA-F]+}} <> Implicit final //CHECK-NEXT: HLSLNodeObjectAttr {{0x[0-9a-fA-F]+}} <> Implicit ThreadNodeOutputRecords +//CHECK-NEXT: AvailabilityAttr {{0x[0-9a-fA-F]+}} <> Implicit 6.8 6.9 6.10 "" //CHECK-NEXT: FieldDecl {{0x[0-9a-fA-F]+}} <> implicit h 'int' //CHECK-NEXT: CXXMethodDecl {{0x[0-9a-fA-F]+}} <> operator[] 'RECORD &(unsigned int)' //CHECK-NEXT: ParmVarDecl {{0x[0-9a-fA-F]+}} <> Index 'unsigned int' diff --git a/tools/clang/test/HLSLFileCheck/hlsl/workgraph/ast-rwnodeinput.hlsl b/tools/clang/test/HLSLFileCheck/hlsl/workgraph/ast-rwnodeinput.hlsl index fb34e2094a..1593226f9c 100644 --- a/tools/clang/test/HLSLFileCheck/hlsl/workgraph/ast-rwnodeinput.hlsl +++ b/tools/clang/test/HLSLFileCheck/hlsl/workgraph/ast-rwnodeinput.hlsl @@ -18,6 +18,7 @@ void node01(RWDispatchNodeInputRecord input) {} //CHECK-NEXT: CXXRecordDecl {{0x[0-9a-fA-F]+}} <> implicit struct RWDispatchNodeInputRecord definition //CHECK-NEXT: FinalAttr {{0x[0-9a-fA-F]+}} <> Implicit final //CHECK-NEXT: HLSLNodeObjectAttr {{0x[0-9a-fA-F]+}} <> Implicit RWDispatchNodeInputRecord +//CHECK-NEXT: AvailabilityAttr {{0x[0-9a-fA-F]+}} <> Implicit 6.8 6.9 6.10 "" //CHECK-NEXT: FieldDecl {{0x[0-9a-fA-F]+}} <> implicit h 'int' //CHECK-NEXT: CXXMethodDecl {{0x[0-9a-fA-F]+}} <> Get 'recordtype &()' //CHECK-NEXT: HLSLIntrinsicAttr {{0x[0-9a-fA-F]+}} <> Implicit "subscript" "" 0 @@ -40,6 +41,7 @@ void node02(RWGroupNodeInputRecords input) {} //CHECK-NEXT: CXXRecordDecl {{0x[0-9a-fA-F]+}} <> implicit struct RWGroupNodeInputRecords definition //CHECK-NEXT: FinalAttr {{0x[0-9a-fA-F]+}} <> Implicit final //CHECK-NEXT: HLSLNodeObjectAttr {{0x[0-9a-fA-F]+}} <> Implicit RWGroupNodeInputRecords +//CHECK-NEXT: AvailabilityAttr {{0x[0-9a-fA-F]+}} <> Implicit 6.8 6.9 6.10 "" //CHECK-NEXT: FieldDecl {{0x[0-9a-fA-F]+}} <> implicit h 'int' //CHECK-NEXT: CXXMethodDecl {{0x[0-9a-fA-F]+}} <> Get 'recordtype &(unsigned int)' //CHECK-NEXT: ParmVarDecl {{0x[0-9a-fA-F]+}} <> Index 'unsigned int' cinit @@ -78,6 +80,7 @@ void node03(RWThreadNodeInputRecord input) {} //CHECK-NEXT: CXXRecordDecl {{0x[0-9a-fA-F]+}} <> implicit struct RWThreadNodeInputRecord definition //CHECK-NEXT: FinalAttr {{0x[0-9a-fA-F]+}} <> Implicit final //CHECK-NEXT: HLSLNodeObjectAttr {{0x[0-9a-fA-F]+}} <> Implicit RWThreadNodeInputRecord +//CHECK-NEXT: AvailabilityAttr {{0x[0-9a-fA-F]+}} <> Implicit 6.8 6.9 6.10 "" //CHECK-NEXT: FieldDecl {{0x[0-9a-fA-F]+}} <> implicit h 'int' //CHECK-NEXT: CXXMethodDecl {{0x[0-9a-fA-F]+}} <> Get 'recordtype &()' //CHECK-NEXT: HLSLIntrinsicAttr {{0x[0-9a-fA-F]+}} <> Implicit "subscript" "" 0 diff --git a/tools/clang/test/HLSLFileCheck/pix/InvocationsLog_ClosestHit.hlsl b/tools/clang/test/HLSLFileCheck/pix/InvocationsLog_ClosestHit.hlsl index a17b94b153..34c932dd36 100644 --- a/tools/clang/test/HLSLFileCheck/pix/InvocationsLog_ClosestHit.hlsl +++ b/tools/clang/test/HLSLFileCheck/pix/InvocationsLog_ClosestHit.hlsl @@ -14,7 +14,7 @@ // Now check that at least three functions were modified (the hit group shaders): // -------- one ---------- -// Check for out-of-bounds clamp: +// Check for the per-entry offset calculation: // CHECK: mul i32 // CHECK: 52 @@ -28,7 +28,7 @@ // CHECK: i32 1 // -------- two ---------- -// Check for out-of-bounds clamp: +// Check for the per-entry offset calculation: // CHECK: mul i32 // CHECK: 52 @@ -43,7 +43,7 @@ // CHECK: dx.op.atomicBinOp.i32 // CHECK: i32 1 -// Check for out-of-bounds clamp: +// Check for the per-entry offset calculation: // CHECK: mul i32 // CHECK: 52 diff --git a/tools/clang/test/HLSLFileCheck/pix/InvocationsLog_OverflowIsNotClamped.hlsl b/tools/clang/test/HLSLFileCheck/pix/InvocationsLog_OverflowIsNotClamped.hlsl new file mode 100644 index 0000000000..8f61c7683e --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/pix/InvocationsLog_OverflowIsNotClamped.hlsl @@ -0,0 +1,57 @@ +// RUN: %dxc -Tlib_6_6 %s | %opt -S -hlsl-dxil-pix-dxr-invocations-log,maxNumEntriesInLog=100 | %FileCheck %s + +// Each invocation claims one log slot. +// The counter keeps counting past the log capacity. +// The stores execute only when the claimed slot is in range. + +// CHECK: [[ENTRYINDEX:%EntryIndexResult[0-9]*]] = call i32 @dx.op.atomicBinOp.i32(i32 78, +// CHECK: [[INRANGE:%EntryIndexIsInRange[0-9]*]] = icmp ult i32 [[ENTRYINDEX]], 100 +// CHECK: br i1 [[INRANGE]] +// CHECK: mul i32 [[ENTRYINDEX]], 52 +// CHECK: call void @dx.op.bufferStore.i32 +// CHECK: call void @dx.op.bufferStore.f32 +// CHECK: call void @dx.op.bufferStore.f32 +// CHECK: call void @dx.op.bufferStore.i32 + +// UMin is not part of this shader. +// CHECK-NOT: @dx.op.binary.i32(i32 40 +// CHECK-NOT: declare i32 @dx.op.binary.i32 + +struct Payload +{ + float4 color; +}; + +struct Attribs +{ + float2 barycentrics; +}; + +RaytracingAccelerationStructure scene : register(t0); +RWTexture2D output : register(u0); + +[shader("raygeneration")] +void RayGen() +{ + RayDesc ray; + ray.Origin = float3(0, 0, 0); + ray.Direction = float3(0, 0, 1); + ray.TMin = 0.001f; + ray.TMax = 1000.f; + Payload payload; + payload.color = float4(0, 0, 0, 0); + TraceRay(scene, RAY_FLAG_NONE, ~0, 0, 1, 0, ray, payload); + output[DispatchRaysIndex().xy] = payload.color; +} + +[shader("closesthit")] +void ClosestHit(inout Payload payload, in Attribs attribs) +{ + payload.color = float4(attribs.barycentrics, 0, 1); +} + +[shader("miss")] +void Miss(inout Payload payload) +{ + payload.color = float4(1, 0, 0, 1); +} diff --git a/tools/clang/test/HLSLFileCheck/pix/NonUniformResourceIndexInstructionNumber.hlsl b/tools/clang/test/HLSLFileCheck/pix/NonUniformResourceIndexInstructionNumber.hlsl new file mode 100644 index 0000000000..ab79b41af4 --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/pix/NonUniformResourceIndexInstructionNumber.hlsl @@ -0,0 +1,26 @@ +// RUN: %dxc -Emain -Tps_6_0 %s | %opt -S -dxil-annotate-with-virtual-regs -hlsl-dxil-non-uniform-resource-index-instrumentation | %FileCheck %s + +// With the annotation prepass in place, the diagnostic is addressed to +// the ordinal of the createHandle that performed the unmarked dynamic +// indexing. The pass encodes the ordinal as a shift within a 32-bit word +// (InstructionNumber % 32), with InstructionNumber / 32 selecting the +// word. A zero shift addresses bit 0 in that word; ordinals 32, 64, etc. +// also have a zero shift in later words. +// +// Match any non-zero shift rather than a literal ordinal. A createHandle +// whose index comes from an interpolated input is never the first +// numbered instruction. + +// CHECK-NOT: NuriNotInstrumentedMissingInstructionNumber +// CHECK: FoundDynamicIndexingNoNuri +// CHECK: @dx.op.waveActiveAllEqual +// CHECK: shl i32 %{{[0-9]+}}, {{[1-9][0-9]*}} +// CHECK: @dx.op.atomicBinOp.i32(i32 78 + +Texture2D tex[8] : register(t0); + +float4 main(float2 uv : TEXCOORD0) : SV_TARGET +{ + uint index = uv.x * uv.y; + return tex[index].Load(int3(0, 0, 0)); +} diff --git a/tools/clang/test/HLSLFileCheck/pix/NonUniformResourceIndexLibraryHelper.hlsl b/tools/clang/test/HLSLFileCheck/pix/NonUniformResourceIndexLibraryHelper.hlsl new file mode 100644 index 0000000000..cf0a16883b --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/pix/NonUniformResourceIndexLibraryHelper.hlsl @@ -0,0 +1,27 @@ +// RUN: %dxc -T lib_6_6 -Od %s | %opt -S -dxil-annotate-with-virtual-regs -hlsl-dxil-non-uniform-resource-index-instrumentation | %FileCheck %s + +// Coverage for an unmarked dynamic index that stays in a library helper. +// The helper remains a separate function. The diagnostic is addressed to +// a non-zero instruction ordinal. + +// CHECK-NOT: NuriNotInstrumentedMissingInstructionNumber +// CHECK: FoundDynamicIndexingNoNuri +// CHECK: define void {{.*}}IndexInHelper +// CHECK: @dx.op.waveActiveAllEqual +// CHECK: shl i32 %{{[0-9]+}}, {{[1-9][0-9]*}} +// CHECK: @dx.op.atomicBinOp.i32(i32 78 + +RWTexture2D RT[] : register(u0); + +[noinline] +export void IndexInHelper(uint index) +{ + float2 rayIndex = DispatchRaysIndex().xy; + RT[index][rayIndex] = 1; +} + +[shader("raygeneration")] +void RayGen() +{ + IndexInHelper(DispatchRaysIndex().x); +} diff --git a/tools/clang/test/HLSLFileCheck/pix/NonUniformResourceIndexNoInstructionNumbers.hlsl b/tools/clang/test/HLSLFileCheck/pix/NonUniformResourceIndexNoInstructionNumbers.hlsl new file mode 100644 index 0000000000..7053fbdefc --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/pix/NonUniformResourceIndexNoInstructionNumbers.hlsl @@ -0,0 +1,23 @@ +// RUN: %dxc -Emain -Tps_6_0 %s | %opt -S -hlsl-dxil-non-uniform-resource-index-instrumentation | %FileCheck %s + +// This pass addresses each diagnostic by the PIX instruction ordinal. +// This RUN line omits the annotation prepass, so no createHandle carries +// an ordinal. The pass leaves the handle uninstrumented and reports the +// missing precondition. +// +// The pass writes its messages to the same stream as the -S module print, +// and writes them before the module, so the message checks come first. + +// CHECK-NOT: FoundDynamicIndexingNoNuri +// CHECK: NuriNotInstrumentedMissingInstructionNumber +// CHECK-NOT: !"PixUAVResource" +// CHECK-NOT: @dx.op.waveActiveAllEqual +// CHECK-NOT: @dx.op.atomicBinOp + +Texture2D tex[8] : register(t0); + +float4 main(float2 uv : TEXCOORD0) : SV_TARGET +{ + uint index = uv.x * uv.y; + return tex[index].Load(int3(0, 0, 0)); +} diff --git a/tools/clang/test/HLSLFileCheck/pix/pixelCounterEarlyZ.hlsl b/tools/clang/test/HLSLFileCheck/pix/pixelCounterEarlyZ.hlsl index 86d6d498b8..63968a3375 100644 --- a/tools/clang/test/HLSLFileCheck/pix/pixelCounterEarlyZ.hlsl +++ b/tools/clang/test/HLSLFileCheck/pix/pixelCounterEarlyZ.hlsl @@ -3,9 +3,11 @@ // Check the write to the UAV was emitted: // CHECK: %UAVIncResult = call i32 @dx.op.atomicBinOp.i32(i32 78, %dx.types.Handle %PIX_CountUAV_Handle, i32 0, i32 %ByteIndex, i32 undef, i32 undef, i32 1) -// Early z flag value is 8. The flags are stored in an entry in the entry function description record. See: +// The flags are stored in an entry in the entry function description record. See: // https://github.com/Microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#shader-properties-and-capabilities -// CHECK: !{i32 0, i64 8} +// 8 is force-early-z. 16 is EnableRawAndStructuredBuffers, set for the +// RWByteAddressBuffer counter this pass adds. 8 | 16 = 24. +// CHECK: !{i32 0, i64 24} float4 main(float4 pos : SV_Position) : SV_Target { return pos; diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-reference.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-reference.hlsl index 499c26aec7..39b05f7dde 100644 --- a/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-reference.hlsl +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-reference.hlsl @@ -3,7 +3,7 @@ // Test that 'auto' cannot be used to declare reference types in HLSL. // References are unsupported in HLSL. -int gVal = 42; +static int gVal = 42; [numthreads(1,1,1)] void main() { diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-return-errors.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-return-errors.hlsl new file mode 100644 index 0000000000..d8cb621d7b --- /dev/null +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-return-errors.hlsl @@ -0,0 +1,31 @@ +// RUN: %dxc -T cs_6_0 -HV 202x -verify %s + +// Test diagnostics for incorrect uses of 'auto' as a function return type. + +// Inconsistent deduced types between return statements is an error. +auto BadDeduction(int x) { + if (x > 0) + return 1; // deduced as int + return 2.0f; // expected-error {{'auto' in return type deduced as 'float' here but deduced as 'int' in earlier return statement}} +} + +// A function declared with 'auto' must be defined before it is used; a +// forward declaration alone is not sufficient for the call site. +auto ForwardOnly(int x); +void useForward() { + ForwardOnly(1); // expected-error {{function 'ForwardOnly' with deduced return type cannot be used before it is defined}} +} +// expected-note@-4 {{'ForwardOnly' declared here}} + +// A recursive call to a function with deduced return type must occur after +// a return statement that allows the type to be deduced. +auto BadRecurse(int x) { + return BadRecurse(x - 1) + 1; // expected-error {{cannot be used before it is defined}} +} +// expected-note@-3 {{'BadRecurse' declared here}} + +[numthreads(1,1,1)] +void main() { + BadDeduction(1); + BadRecurse(2); +} diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-return-extension-warning.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-return-extension-warning.hlsl new file mode 100644 index 0000000000..886a84bd27 --- /dev/null +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-return-extension-warning.hlsl @@ -0,0 +1,19 @@ +// RUN: %dxc -T cs_6_0 -E main -HV 2016 -verify %s +// RUN: %dxc -T cs_6_0 -E main -HV 2017 -verify %s +// RUN: %dxc -T cs_6_0 -E main -HV 2018 -verify %s +// RUN: %dxc -T cs_6_0 -E main -HV 2021 -verify %s + +// 'auto' is allowed as a function return type from HLSL 2016 onward, but +// using it before language mode 202x produces an extension warning. + +RWBuffer output : register(u0); + +// expected-warning@+1 {{'auto' type specifier is a HLSL 202x extension}} +auto Square(int x) { + return x * x; +} + +[numthreads(1,1,1)] +void main() { + output[0] = (float)Square(3); +} diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-return-type.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-return-type.hlsl new file mode 100644 index 0000000000..7e1648e259 --- /dev/null +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-return-type.hlsl @@ -0,0 +1,74 @@ +// RUN: %dxc -T cs_6_0 -E main - %s -verify +// RUN: %dxc -T cs_6_0 -E main -HV 202x -fcgl %s | FileCheck %s + +// Test that the 'auto' keyword can be used as a function return type and +// that the deduced type matches C++14 [dcl.spec.auto] rules. + +// CHECK-LABEL: define void @main() + +// CHECK-LABEL: define internal <4 x float> @"\01?Scale +// CHECK: ret <4 x float> + +// CHECK-LABEL: define internal void @"\01?WriteOutput +// CHECK: ret void + +// CHECK-LABEL: define internal i32 @"\01?SquareInt +// CHECK: ret i32 + +// CHECK-LABEL: define internal float @"\01?SquareFloat +// CHECK: ret float + +// CHECK-LABEL: define internal float @"\01??$Sum +// CHECK: ret float + +// CHECK-LABEL: define internal float @"\01?Clamp01 +// CHECK: ret float + +RWBuffer output : register(u0); + +// Deduces int from a single return statement. +// expected-warning@+1 {{'auto' type specifier is a HLSL 202x extension}} +auto SquareInt(int x) { + return x * x; +} + +// Deduces float from a single return statement. +// expected-warning@+1 {{'auto' type specifier is a HLSL 202x extension}} +auto SquareFloat(float x) { + return x * x; +} + +// Deduces float4 from a single return statement. +// expected-warning@+1 {{'auto' type specifier is a HLSL 202x extension}} +auto Scale(float4 v, float s) { + return v * s; +} + +// Deduces void when no return statement is present. +// expected-warning@+1 {{'auto' type specifier is a HLSL 202x extension}} +auto WriteOutput(uint i, float v) { + output[i] = v; +} + +// Multiple return statements with the same deduced type are allowed. +// expected-warning@+1 {{'auto' type specifier is a HLSL 202x extension}} +auto Clamp01(float v) { + if (v < 0.0f) + return 0.0f; + if (v > 1.0f) + return 1.0f; + return v; +} + +// expected-warning@+2 {{'auto' type specifier is a HLSL 202x extension}} +template +auto Sum(T L, T R) { + return L + R; +} + +[numthreads(1,1,1)] +void main() { + float4 v = float4(1, 2, 3, 4); + float4 s = Scale(v, 0.5f); + WriteOutput(0, (float)SquareInt(3) + SquareFloat(2.5f) + Sum(s.x, Clamp01(1.5f))); +} diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-return-undeducible-types.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-return-undeducible-types.hlsl new file mode 100644 index 0000000000..17c74b7f0c --- /dev/null +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-return-undeducible-types.hlsl @@ -0,0 +1,74 @@ +// RUN: %dxc -T lib_6_6 -HV 202x -verify %s + +// Test that deducing a return type that 'auto' cannot represent produces a +// diagnostic, mirroring the checks already performed for 'auto' variables +// (see auto-undeducible-types.hlsl and auto-no-subobject.hlsl). + +Texture2D tex : register(t0); +Texture2DMS texMS : register(t1); + +GlobalRootSignature grs = {"CBV(b0)"}; + +// String literals cannot be deduced by 'auto'. +auto GetString() { + // expected-error@+1 {{'auto' cannot deduce type 'literal string'}} + return "abc"; +} + +// The proxy types used for '.mips'/'.sample' subscript operators cannot be +// deduced by 'auto'. +auto GetMips() { + // expected-error@+1 {{'auto' cannot deduce type}} + return tex.mips; +} + +auto GetMipsElement() { + // expected-error@+1 {{'auto' cannot deduce type}} + return tex.mips[0]; +} + +auto GetSample() { + // expected-error@+1 {{'auto' cannot deduce type}} + return texMS.sample; +} + +auto GetSampleElement() { + // expected-error@+1 {{'auto' cannot deduce type}} + return texMS.sample[0]; +} + +// Subobjects cannot be deduced by 'auto'. +auto GetSubobject() { + // expected-error@+1 {{'auto' cannot deduce type 'GlobalRootSignature'}} + return grs; +} + +// Fully subscripted mips/sample accesses deduce a normal, deducible type. +auto GetMipsValue() { + return tex.mips[0][int2(1, 2)]; +} + +auto GetSampleValue() { + return texMS.sample[0][int2(1, 2)]; +} + +auto GetDynamicResource() { + // expected-error@+1 {{'auto' cannot deduce type '.Resource'}} + return ResourceDescriptorHeap[0]; +} + +auto GetDynamicSampler() { + // expected-error@+1 {{'auto' cannot deduce type '.Sampler'}} + return SamplerDescriptorHeap[0]; +} + +auto GetDynamicResource2() { + return ((RWBuffer)ResourceDescriptorHeap[0]); +} + +auto GetDynamicResource(bool IsRW) { + if (IsRW) + return ((RWBuffer)ResourceDescriptorHeap[0]); + // expected-error@+1 {{'auto' in return type deduced as 'Buffer' here but deduced as 'RWBuffer' in earlier return statement}} + return ((Buffer)ResourceDescriptorHeap[0]); +} diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/entry/attributes/GroupSharedLimitNode.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/entry/attributes/GroupSharedLimitNode.hlsl deleted file mode 100644 index dbbb99fd9d..0000000000 --- a/tools/clang/test/HLSLFileCheckLit/hlsl/entry/attributes/GroupSharedLimitNode.hlsl +++ /dev/null @@ -1,61 +0,0 @@ -// REQUIRES: dxil-1-10 - -// PASS: usage <= default (no limit) -// RUN: %dxc -T lib_6_10 -DGSM_DWORDS=8192 %s | FileCheck %s - -// PASS: default < usage <= limit -// RUN: %dxc -T lib_6_10 -DGSM_DWORDS=9216 -DUSE_GROUP_SHARED_LIMIT -DLIMIT_BYTES=36864 %s | FileCheck %s - -// PASS: no usage, limit=0 (edge case) -// RUN: %dxc -T lib_6_10 -DNO_GSM -DUSE_GROUP_SHARED_LIMIT -DLIMIT_BYTES=0 %s | FileCheck %s - -// PASS: limit == usage < default -// RUN: %dxc -T lib_6_10 -DGSM_DWORDS=4096 -DUSE_GROUP_SHARED_LIMIT -DLIMIT_BYTES=16384 %s | FileCheck %s - -// CHECK: define void @NodeMain() - -#define NUM_THREADS 1024 - -#ifndef NO_GSM -#ifndef GSM_DWORDS -#define GSM_DWORDS 8192 -#endif -groupshared uint g_testBuffer[GSM_DWORDS]; -#endif - -RWStructuredBuffer g_output : register(u0); - -struct MY_INPUT_RECORD { - uint data; -}; - -[Shader("node")] -[NodeLaunch("broadcasting")] -[NodeDispatchGrid(2, 1, 1)] -[NumThreads(NUM_THREADS, 1, 1)] -#ifdef USE_GROUP_SHARED_LIMIT -[GroupSharedLimit(LIMIT_BYTES)] -#endif -void NodeMain(DispatchNodeInputRecord myInput) -{ - uint tid = myInput.Get().data; - -#ifndef NO_GSM - uint iterations = GSM_DWORDS / NUM_THREADS; - - for (uint i = 0; i < iterations; i++) - { - uint index = tid + i * NUM_THREADS; - g_testBuffer[index] = index; - } - - GroupMemoryBarrierWithGroupSync(); - - // Write the shared data to the output buffer - for (uint j = 0; j < iterations; j++) - { - uint index = tid + j * NUM_THREADS; - g_output[index] = g_testBuffer[index]; - } -#endif -} diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/entry/attributes/GroupSharedLimitNodeError.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/entry/attributes/GroupSharedLimitNodeError.hlsl deleted file mode 100644 index 49c28b74a2..0000000000 --- a/tools/clang/test/HLSLFileCheckLit/hlsl/entry/attributes/GroupSharedLimitNodeError.hlsl +++ /dev/null @@ -1,58 +0,0 @@ -// REQUIRES: dxil-1-10 - -// FAIL: default < limit < usage (36864 < 40960) -// RUN: not %dxc -T lib_6_10 -DGSM_DWORDS=10240 -DUSE_GROUP_SHARED_LIMIT -DLIMIT_BYTES=36864 %s 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL1 -// CHECK-FAIL1: Total Thread Group Shared Memory used by 'NodeMain' is 40960, exceeding explicit limit: 36864. - -// FAIL: default < usage (no limit) (32768 < 36864) -// RUN: not %dxc -T lib_6_10 -DGSM_DWORDS=9216 %s 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL2 -// CHECK-FAIL2: Total Thread Group Shared Memory used by 'NodeMain' is 36864, exceeding maximum: 32768 - -// FAIL: limit < usage < default (8192 < 16384 < 32768) -// RUN: not %dxc -T lib_6_10 -DGSM_DWORDS=4096 -DUSE_GROUP_SHARED_LIMIT -DLIMIT_BYTES=8192 %s 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL3 -// CHECK-FAIL3: Total Thread Group Shared Memory used by 'NodeMain' is 16384, exceeding explicit limit: 8192. - -// FAIL: limit=0 < usage < default (0 < 16384 < 32768) (edge case) -// RUN: not %dxc -T lib_6_10 -DGSM_DWORDS=4096 -DUSE_GROUP_SHARED_LIMIT -DLIMIT_BYTES=0 %s 2>&1 | FileCheck %s --check-prefix=CHECK-FAIL4 -// CHECK-FAIL4: Total Thread Group Shared Memory used by 'NodeMain' is 16384, exceeding explicit limit: 0. - -#define NUM_THREADS 1024 - -#ifndef GSM_DWORDS -#define GSM_DWORDS 8192 -#endif -groupshared uint g_testBuffer[GSM_DWORDS]; - -RWStructuredBuffer g_output : register(u0); - -struct MY_INPUT_RECORD { - uint data; -}; - -[Shader("node")] -[NodeLaunch("broadcasting")] -[NodeDispatchGrid(2, 1, 1)] -[NumThreads(NUM_THREADS, 1, 1)] -#ifdef USE_GROUP_SHARED_LIMIT -[GroupSharedLimit(LIMIT_BYTES)] -#endif -void NodeMain(DispatchNodeInputRecord myInput) -{ - uint tid = myInput.Get().data; - uint iterations = GSM_DWORDS / NUM_THREADS; - - for (uint i = 0; i < iterations; i++) - { - uint index = tid + i * NUM_THREADS; - g_testBuffer[index] = index; - } - - GroupMemoryBarrierWithGroupSync(); - - // Write the shared data to the output buffer - for (uint j = 0; j < iterations; j++) - { - uint index = tid + j * NUM_THREADS; - g_output[index] = g_testBuffer[index]; - } -} diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/entry/groupshared-initializer.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/entry/groupshared-initializer.hlsl new file mode 100644 index 0000000000..e2e11a3ba3 --- /dev/null +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/entry/groupshared-initializer.hlsl @@ -0,0 +1,17 @@ +// RUN: %dxc -T cs_6_0 -E main -fcgl -verify %s + +uint getValue() { return 2; } + +groupshared uint Constant = 1; +// expected-warning@-1 {{initializer of 'groupshared' variable will be ignored}} + +groupshared uint Dynamic = getValue(); +// expected-warning@-1 {{initializer of 'groupshared' variable will be ignored}} + +// DXIL retains initializers on static groupshared variables. +static groupshared uint Static = 3; + +[numthreads(1, 1, 1)] +void main() { + Constant += Dynamic + Static; +} diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/debugbreak.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/debugbreak.hlsl index 282384ea3d..5b6acf900d 100644 --- a/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/debugbreak.hlsl +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/debugbreak.hlsl @@ -4,7 +4,7 @@ // RUN: %dxc -T cs_6_10 -fcgl %s | FileCheck %s --check-prefix=FCGL // RUN: %dxc -T cs_6_10 -ast-dump %s | FileCheck %s --check-prefix=AST -// CHECK: call void @dx.op.debugBreak(i32 -2147483615) ; DebugBreak() +// CHECK: call void @dx.op.debugBreak(i32 343) ; DebugBreak() // FCGL: call void @"dx.hl.op..void (i32)"(i32 420) // AST: CallExpr {{.*}} 'void' diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/isdebuggingenabled.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/isdebuggingenabled.hlsl index 784aa327da..d10b542667 100644 --- a/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/isdebuggingenabled.hlsl +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/basic/isdebuggingenabled.hlsl @@ -4,8 +4,8 @@ // RUN: %dxc -T cs_6_10 -fcgl %s | FileCheck %s --check-prefix=FCGL // RUN: %dxc -T cs_6_10 -ast-dump %s | FileCheck %s --check-prefix=AST -// CHECK: call i1 @dx.op.isDebuggingEnabled(i32 -2147483614) ; IsDebuggingEnabled() -// CHECK: call i1 @dx.op.isDebuggingEnabled(i32 -2147483614) ; IsDebuggingEnabled() +// CHECK: call i1 @dx.op.isDebuggingEnabled(i32 344) ; IsDebuggingEnabled() +// CHECK: call i1 @dx.op.isDebuggingEnabled(i32 344) ; IsDebuggingEnabled() // FCGL: call i1 @"dx.hl.op..i1 (i32)"(i32 421) // FCGL: call i1 @"dx.hl.op..i1 (i32)"(i32 421) diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/wave/group-wave-index.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/wave/group-wave-index.hlsl index 3469dc24a8..cb34e3f212 100644 --- a/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/wave/group-wave-index.hlsl +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/wave/group-wave-index.hlsl @@ -6,8 +6,8 @@ // FCGL: call i32 @"dx.hl.op.rn.i32 (i32)"(i32 392) // FCGL: call i32 @"dx.hl.op.rn.i32 (i32)"(i32 391) -// CHECK: %[[Index:[^ ]+]] = call i32 @dx.op.getGroupWaveIndex(i32 -2147483647) ; GetGroupWaveIndex() -// CHECK: %[[Count:[^ ]+]] = call i32 @dx.op.getGroupWaveCount(i32 -2147483646) ; GetGroupWaveCount() +// CHECK: %[[Index:[^ ]+]] = call i32 @dx.op.getGroupWaveIndex(i32 312) ; GetGroupWaveIndex() +// CHECK: %[[Count:[^ ]+]] = call i32 @dx.op.getGroupWaveCount(i32 313) ; GetGroupWaveCount() // CHECK: call void @dx.op.rawBufferStore.i32(i32 140, %dx.types.Handle %{{[^,]+}}, i32 0, i32 0, i32 %[[Index]], i32 undef, i32 undef, i32 undef, i8 1, i32 4) // CHECK: call void @dx.op.rawBufferStore.i32(i32 140, %dx.types.Handle %{{[^,]+}}, i32 16, i32 0, i32 %[[Count]], i32 undef, i32 undef, i32 undef, i8 1, i32 4) diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/wave/group-wave-invalid-nodes.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/wave/group-wave-invalid-nodes.hlsl deleted file mode 100644 index ea85b59ef2..0000000000 --- a/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/wave/group-wave-invalid-nodes.hlsl +++ /dev/null @@ -1,28 +0,0 @@ -// REQUIRES: dxil-1-10 - -// RUN: not %dxc -T lib_6_10 %s 2>&1 | FileCheck %s - -// CHECK-DAG: error: Function requires a visible group, but is called from a shader without one. - -struct InputRecord { - uint value; -}; - -struct OutputRecord { - uint value; -}; - -RWStructuredBuffer output : register(u0); - -// Thread launch - no thread group, should FAIL -[Shader("node")] -[NodeLaunch("thread")] -void ThreadNode( - RWThreadNodeInputRecord inputData, - [MaxRecords(1)] NodeOutput outputData) { - uint waveIdx = GetGroupWaveIndex(); - uint waveCount = GetGroupWaveCount(); - ThreadNodeOutputRecords outRec = outputData.GetThreadNodeOutputRecords(1); - outRec.Get().value = waveIdx + waveCount; - outRec.OutputComplete(); -} diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/wave/group-wave-nodes.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/wave/group-wave-nodes.hlsl deleted file mode 100644 index b88c8c23d2..0000000000 --- a/tools/clang/test/HLSLFileCheckLit/hlsl/intrinsics/wave/group-wave-nodes.hlsl +++ /dev/null @@ -1,41 +0,0 @@ -// REQUIRES: dxil-1-10 - -// RUN: %dxc -T lib_6_10 %s 2>&1 | FileCheck %s - -// CHECK-DAG: define void @BroadcastingNode -// CHECK-DAG: define void @CoalescingNode - -struct InputRecord { - uint value; -}; - -struct OutputRecord { - uint value; -}; - -RWStructuredBuffer output : register(u0); - -// Broadcasting launch - has thread group, should work -[Shader("node")] -[NodeLaunch("broadcasting")] -[NodeDispatchGrid(1,1,1)] -[NumThreads(8,1,1)] -void BroadcastingNode(DispatchNodeInputRecord inputData) { - uint waveIdx = GetGroupWaveIndex(); - uint waveCount = GetGroupWaveCount(); - output[0] = waveIdx + waveCount + inputData.Get().value; -} - -// Coalescing launch - has thread group, should work -[Shader("node")] -[NodeLaunch("coalescing")] -[NumThreads(8,1,1)] -void CoalescingNode( - [MaxRecords(8)] GroupNodeInputRecords inputData, - [MaxRecords(8)] NodeOutput outputData) { - uint waveIdx = GetGroupWaveIndex(); - uint waveCount = GetGroupWaveCount(); - GroupNodeOutputRecords outRec = outputData.GetGroupNodeOutputRecords(1); - outRec.Get().value = waveIdx + waveCount; - outRec.OutputComplete(); -} \ No newline at end of file diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/templates/variadic-202x.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/templates/variadic-202x.hlsl new file mode 100644 index 0000000000..acfbba4749 --- /dev/null +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/templates/variadic-202x.hlsl @@ -0,0 +1,24 @@ +// RUN: %dxc -E main -T ps_6_0 -HV 202x %s | FileCheck %s +// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float 1.300000e+01) + +// Verify template and function parameter packs, pack expansions, and +// sizeof...() in DXIL. + +template +T Sum(T First) { + return First; +} + +template +T Sum(T First, U Second, Rest... Others) { + return First + Sum(Second, Others...); +} + +template +uint CountArgs(Args... args) { + return sizeof...(Args); +} + +float main() : SV_Target { + return Sum(1.0, 2.0, 3.0, 4.0) + CountArgs(1, 2, 3); +} diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/templates/variadic-builtin-templates.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/templates/variadic-builtin-templates.hlsl new file mode 100644 index 0000000000..866a7e44d1 --- /dev/null +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/templates/variadic-builtin-templates.hlsl @@ -0,0 +1,36 @@ +// RUN: %dxc -E main -T ps_6_0 -HV 202x %s | FileCheck %s + +// Verify pack expansion into HLSL vector, matrix, and resource templates. + +template +struct Holder { + StructuredBuffer Buf; +}; +Holder g_Holder : register(t0); + +template +vector MakeVector(T First, Rest... Others) { + return vector(First, Others...); +} + +template +struct MatrixWrapper { + matrix M; +}; + +// CHECK: call %dx.types.Handle @dx.op.createHandle(i32 57 +// CHECK: call %dx.types.ResRet.f32 @dx.op.bufferLoad.f32 +// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0 +// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1 +// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2 +// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3 +float4 main(float4 a : A) : SV_Target { + vector v = MakeVector(a.x, a.y, a.z, a.w); + + MatrixWrapper mw; + mw.M = matrix(v.x, v.y, v.z, v.w); + + float bufVal = g_Holder.Buf.Load(0); + + return float4(mw.M._11, mw.M._22, bufVal, v.w); +} diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/templates/variadic-initlist-scalarize.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/templates/variadic-initlist-scalarize.hlsl new file mode 100644 index 0000000000..79c6abdd35 --- /dev/null +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/templates/variadic-initlist-scalarize.hlsl @@ -0,0 +1,69 @@ +// RUN: %dxc -E main -T ps_6_0 -HV 202x %s | FileCheck %s + +// Compare pack-expanded and explicit initializer-list scalarization using +// shader inputs so the results remain observable in DXIL. + +struct PairOf2 { + float2 lo; + float2 hi; +}; + +// Vector target filled from mixed vector+vector pack elements. +template +float4 PackVectorMixed(Ts... vals) { + float4 v = { vals... }; + return v; +} +float4 ManualVectorMixed(float2 a, float2 b) { + float4 v = { a, b }; + return v; +} + +// A flat initializer list overflowing across the boundary of an array of +// vectors. +template +float2 PackArrayOverflow(Ts... vals) { + float2 arr[2] = { vals... }; + return arr[0] + arr[1]; +} +float2 ManualArrayOverflow(float a, float b, float c, float d) { + float2 arr[2] = { a, b, c, d }; + return arr[0] + arr[1]; +} + +// Struct-member scalarization, including a vector-typed member. +template +PairOf2 PackStruct(Ts... vals) { + PairOf2 s = { vals... }; + return s; +} +PairOf2 ManualStruct(float2 a, float2 b) { + PairOf2 s = { a, b }; + return s; +} + +// CHECK: define void @main() +// CHECK-DAG: fmul fast float %{{.*}}, 2.000000e+00 +// CHECK-DAG: fmul fast float %{{.*}}, 6.000000e+00 +// CHECK-DAG: fmul fast float %{{.*}}, 4.000000e+00 +// CHECK-DAG: fmul fast float %{{.*}}, 4.000000e+00 +// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0 +// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1 +// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2 +// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3 +float4 main(float4 inp : A) : SV_Target { + float2 lo = inp.xy; + float2 hi = inp.zw; + + float4 vp = PackVectorMixed(lo, hi); + float4 vm = ManualVectorMixed(lo, hi); + + float2 op = PackArrayOverflow(inp.x, inp.y, inp.z, inp.w); + float2 om = ManualArrayOverflow(inp.x, inp.y, inp.z, inp.w); + + PairOf2 sp = PackStruct(lo, hi); + PairOf2 sm = ManualStruct(lo, hi); + + return vp + vm + float4(op + om, 0, 0) + + float4(sp.lo + sm.lo, sp.hi + sm.hi); +} diff --git a/tools/clang/test/LitDXILValidation/GroupWave/group-wave-invalid-ds.ll b/tools/clang/test/LitDXILValidation/GroupWave/group-wave-invalid-ds.ll index 6c4f3c47bc..087b5bc3ef 100644 --- a/tools/clang/test/LitDXILValidation/GroupWave/group-wave-invalid-ds.ll +++ b/tools/clang/test/LitDXILValidation/GroupWave/group-wave-invalid-ds.ll @@ -11,8 +11,8 @@ define void @mainDS() { %1 = call float @dx.op.domainLocation.f32(i32 105, i8 0) ; DomainLocation(component) %2 = call float @dx.op.domainLocation.f32(i32 105, i8 1) ; DomainLocation(component) %3 = call float @dx.op.domainLocation.f32(i32 105, i8 2) ; DomainLocation(component) - %4 = call i32 @dx.op.getGroupWaveIndex(i32 -2147483647) ; GetGroupWaveIndex() - %5 = call i32 @dx.op.getGroupWaveCount(i32 -2147483646) ; GetGroupWaveCount() + %4 = call i32 @dx.op.getGroupWaveIndex(i32 312) ; GetGroupWaveIndex() + %5 = call i32 @dx.op.getGroupWaveCount(i32 313) ; GetGroupWaveCount() %6 = call float @dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 0, i32 0) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) %7 = insertelement <4 x float> undef, float %6, i64 0 %8 = call float @dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 1, i32 0) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) diff --git a/tools/clang/test/LitDXILValidation/GroupWave/group-wave-invalid-gs.ll b/tools/clang/test/LitDXILValidation/GroupWave/group-wave-invalid-gs.ll index 798fb35b3f..741fd26a9e 100644 --- a/tools/clang/test/LitDXILValidation/GroupWave/group-wave-invalid-gs.ll +++ b/tools/clang/test/LitDXILValidation/GroupWave/group-wave-invalid-gs.ll @@ -8,8 +8,8 @@ target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:3 target triple = "dxil-ms-dx" define void @mainGS() { - %1 = call i32 @dx.op.getGroupWaveIndex(i32 -2147483647) ; GetGroupWaveIndex() - %2 = call i32 @dx.op.getGroupWaveCount(i32 -2147483646) ; GetGroupWaveCount() + %1 = call i32 @dx.op.getGroupWaveIndex(i32 312) ; GetGroupWaveIndex() + %2 = call i32 @dx.op.getGroupWaveCount(i32 313) ; GetGroupWaveCount() br label %4 ;