Merge branch 'main' into users/c8ef/generator
This commit is contained in:
commit
e456ba9196
3517 changed files with 177165 additions and 102602 deletions
50
.ci/monolithic-macos.sh
Executable file
50
.ci/monolithic-macos.sh
Executable file
|
|
@ -0,0 +1,50 @@
|
|||
#!/usr/bin/env bash
|
||||
#===----------------------------------------------------------------------===##
|
||||
#
|
||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
#===----------------------------------------------------------------------===##
|
||||
|
||||
#
|
||||
# This script performs a monolithic build of the monorepo and runs the tests of
|
||||
# most projects on macOS.
|
||||
#
|
||||
|
||||
source .ci/utils.sh
|
||||
|
||||
projects="${1}"
|
||||
targets="${2}"
|
||||
runtimes="${3}"
|
||||
runtime_targets="${4}"
|
||||
|
||||
start-group "CMake"
|
||||
|
||||
xcrun cmake -G Ninja \
|
||||
-B "${BUILD_DIR}" \
|
||||
-S "${MONOREPO_ROOT}"/llvm \
|
||||
-D LLVM_ENABLE_PROJECTS="${projects}" \
|
||||
-D LLVM_ENABLE_RUNTIMES="${runtimes}" \
|
||||
-D LLVM_DISABLE_ASSEMBLY_FILES=ON \
|
||||
-D CMAKE_BUILD_TYPE=Release \
|
||||
-D LLDB_INCLUDE_TESTS=OFF \
|
||||
-D LLVM_ENABLE_ASSERTIONS=ON \
|
||||
-D Python3_EXECUTABLE="${RUNNER_TEMP}/venv/bin/python3" \
|
||||
-D LLVM_LIT_ARGS="-v --xunit-xml-output ${BUILD_DIR}/test-results.xml --use-unique-output-file-name --timeout=1200 --time-tests --succinct" \
|
||||
-D CMAKE_C_COMPILER_LAUNCHER=sccache \
|
||||
-D CMAKE_CXX_COMPILER_LAUNCHER=sccache
|
||||
|
||||
start-group "ninja"
|
||||
|
||||
if [[ -n "${targets}" ]]; then
|
||||
ninja -C "${BUILD_DIR}" ${targets} 2>&1 | tee ninja.log
|
||||
cp ${BUILD_DIR}/.ninja_log ninja.ninja_log
|
||||
fi
|
||||
|
||||
if [[ -n "${runtime_targets}" ]]; then
|
||||
start-group "ninja Runtimes"
|
||||
|
||||
ninja -C "${BUILD_DIR}" ${runtime_targets} 2>&1 | tee ninja_runtimes.log
|
||||
cp ${BUILD_DIR}/.ninja_log ninja_runtimes.ninja_log
|
||||
fi
|
||||
5
.github/CODEOWNERS
vendored
5
.github/CODEOWNERS
vendored
|
|
@ -11,7 +11,6 @@
|
|||
# See https://llvm.org/docs/DeveloperPolicy.html#maintainers as well as the
|
||||
# Maintainers.md files in the the respective subproject directories.
|
||||
|
||||
/bolt/ @llvm/reviewers-bolt
|
||||
/libc/ @llvm/reviewers-libc
|
||||
/libcxx/ @llvm/reviewers-libcxx
|
||||
/libcxxabi/ @llvm/reviewers-libcxxabi
|
||||
|
|
@ -178,8 +177,12 @@
|
|||
# MLIR IRDL-related
|
||||
/mlir/**/*IRDL* @moxinilian
|
||||
|
||||
# BOLT
|
||||
/bolt/ @aaupov @maksfb @rafaelauler @ayermolo @yota9 @paschalis-mpeis @yozhu @yavtuk
|
||||
|
||||
# Bazel build system.
|
||||
/utils/bazel/ @rupprecht @keith @aaronmondal @googlewalt
|
||||
/utils/bazel/llvm-project-overlay/libc/ @labath @kaladron
|
||||
|
||||
# InstallAPI and TextAPI
|
||||
/llvm/**/TextAPI/ @cyndyishida
|
||||
|
|
|
|||
4
.github/workflows/libc-fullbuild-tests.yml
vendored
4
.github/workflows/libc-fullbuild-tests.yml
vendored
|
|
@ -16,8 +16,8 @@ jobs:
|
|||
runs-on: ${{ matrix.os }}
|
||||
container:
|
||||
image: ${{ (startsWith(matrix.os, 'ubuntu-24.04-arm') &&
|
||||
'ghcr.io/llvm/arm64v8/libc-ubuntu-24.04:latest@sha256:138636a45bb70f7b51a858b282e66291cb3c5c85371afee09032a5e09b263395') ||
|
||||
'ghcr.io/llvm/libc-ubuntu-24.04:latest@sha256:a902fb53bdad5e4a4bb6c11b6584e717a7b3d6e886f1ea58e11f95e46226249c'}}
|
||||
'ghcr.io/llvm/arm64v8/libc-ubuntu-24.04:latest@sha256:9ca390ed3546754c1d7cb669033c532c28d95a0327551c5754cbf72375178e37') ||
|
||||
'ghcr.io/llvm/libc-ubuntu-24.04:latest@sha256:8fee4c9ce5a1fd095686593cd36e032c48a31b6ae575378c82accd1d86a08d59'}}
|
||||
# We need to enable privileged containers so that certain libc tests
|
||||
# have the necessary permissions (like SYS_TIME). There are no security
|
||||
# implications as we are already running in an isolated VM.
|
||||
|
|
|
|||
66
.github/workflows/libcxx-benchmark-commit.yml
vendored
66
.github/workflows/libcxx-benchmark-commit.yml
vendored
|
|
@ -3,18 +3,25 @@
|
|||
# it requires several inputs that allow customizing its behavior.
|
||||
|
||||
name: "[libc++] Run benchmark suite against commit"
|
||||
run-name: "[libc++] Run benchmark suite against ${{ inputs.commit }} on ${{ inputs.lnt-machine }}"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
# TODO: Support dispatching only to selected configurations.
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
commit:
|
||||
description: 'The libc++ commit to benchmark'
|
||||
required: true
|
||||
type: string
|
||||
lnt-machine:
|
||||
description: 'The LNT machine to run the benchmarks on'
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- macos-26.5-arm64
|
||||
- linux-x86_64
|
||||
benchmark-suite-version:
|
||||
description: 'The version of the benchmark suite to use (a LLVM monorepo SHA)'
|
||||
required: false
|
||||
|
|
@ -36,19 +43,51 @@ on:
|
|||
default: http://lnt.llvm.org
|
||||
|
||||
jobs:
|
||||
# Determine which configuration to run based on the `lnt-machine` input.
|
||||
select-machine:
|
||||
runs-on: ubuntu-24.04
|
||||
outputs:
|
||||
matrix: ${{ steps.select.outputs.matrix }}
|
||||
steps:
|
||||
- name: Select the configuration to benchmark on
|
||||
id: select
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
env:
|
||||
LNT_MACHINE: ${{ inputs.lnt-machine }}
|
||||
with:
|
||||
script: |
|
||||
const MACHINES = [
|
||||
{
|
||||
'lnt-machine': 'macos-26.5-arm64',
|
||||
runner: ['self-hosted', 'macOS', 'ARM64', '26', '26.5'],
|
||||
cxx: 'clang++',
|
||||
'running-on': 'macos',
|
||||
'xcode-version': '26.5',
|
||||
},
|
||||
{
|
||||
'lnt-machine': 'linux-x86_64',
|
||||
runner: 'llvm-premerge-libcxx-runners',
|
||||
cxx: 'clang++-22',
|
||||
'running-on': 'linux',
|
||||
},
|
||||
];
|
||||
|
||||
const requested = process.env.LNT_MACHINE;
|
||||
const selected = MACHINES.filter(m => m['lnt-machine'] === requested);
|
||||
if (selected.length === 0) {
|
||||
const known = MACHINES.map(m => m['lnt-machine']).join(', ');
|
||||
core.setFailed(`Unknown LNT machine '${requested}' (known machines: ${known})`);
|
||||
return;
|
||||
}
|
||||
|
||||
core.setOutput('matrix', JSON.stringify(selected));
|
||||
|
||||
run-benchmarks:
|
||||
needs:
|
||||
- select-machine
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- lnt-machine: macos-26.5-arm64
|
||||
runner: ["self-hosted", "macOS", "ARM64", "26", "26.5"]
|
||||
cxx: clang++
|
||||
running-on: macos
|
||||
xcode-version: '26.5'
|
||||
- lnt-machine: linux-x86_64
|
||||
runner: llvm-premerge-libcxx-runners
|
||||
cxx: clang++-22
|
||||
running-on: linux
|
||||
include: ${{ fromJSON(needs.select-machine.outputs.matrix) }}
|
||||
fail-fast: false
|
||||
runs-on: ${{ matrix.runner }}
|
||||
env:
|
||||
|
|
@ -91,6 +130,7 @@ jobs:
|
|||
COMMIT: ${{ inputs.commit }}
|
||||
BENCHMARK_SUITE_VERSION: ${{ inputs.benchmark-suite-version }}
|
||||
FILTER: ${{ inputs.filter }}
|
||||
LNT_MACHINE: ${{ matrix.lnt-machine }}
|
||||
run: |
|
||||
filter_arg=()
|
||||
if [ -n "${FILTER}" ]; then
|
||||
|
|
@ -98,7 +138,7 @@ jobs:
|
|||
fi
|
||||
libcxx/utils/ci/lnt/run-benchmarks \
|
||||
--test-suite-commit "${BENCHMARK_SUITE_VERSION}" \
|
||||
--machine ${{ matrix.lnt-machine }} \
|
||||
--machine "${LNT_MACHINE}" \
|
||||
--compiler "${COMPILER}" \
|
||||
--benchmark-commit "${COMMIT}" \
|
||||
"${filter_arg[@]}" \
|
||||
|
|
@ -114,5 +154,5 @@ jobs:
|
|||
run: |
|
||||
libcxx/utils/ci/lnt/submit-benchmarks \
|
||||
--lnt-url "${LNT_URL}" \
|
||||
--test-suite libcxx2 \
|
||||
--test-suite libcxx \
|
||||
"${COMMIT}.json"
|
||||
|
|
|
|||
23
.github/workflows/llvm-abi-tests.yml
vendored
23
.github/workflows/llvm-abi-tests.yml
vendored
|
|
@ -93,23 +93,37 @@ jobs:
|
|||
ref: ${{ github.sha }}
|
||||
repo: ${{ github.repository }}
|
||||
steps:
|
||||
- name: Check for cached baseline ABI
|
||||
if: ${{ matrix.name == 'build-baseline' }}
|
||||
id: cache
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 #v6.1.0
|
||||
with:
|
||||
key: ${{ matrix.ref}}.abi
|
||||
path: |
|
||||
${{ matrix.ref }}.abi
|
||||
llvm.symbols
|
||||
|
||||
- name: Download source code
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: ${{ matrix.ref }}
|
||||
repository: ${{ matrix.repo }}
|
||||
- name: Configure
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
mkdir install
|
||||
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DLLVM_TARGETS_TO_BUILD="" -DLLVM_BUILD_LLVM_DYLIB=ON -DCMAKE_INSTALL_PREFIX="$(pwd)"/install llvm
|
||||
- name: Build
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
# Need to run install-LLVM twice to ensure the symlink is installed (this is a bug).
|
||||
run: |
|
||||
ninja -C build install-LLVM
|
||||
ninja -C build install-LLVM
|
||||
ninja -C build install-llvm-headers
|
||||
- name: Dump ABI
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
env:
|
||||
REF: ${{ matrix.ref }}
|
||||
ABI_HEADERS: ${{ needs.abi-dump-setup.outputs.ABI_HEADERS }}
|
||||
|
|
@ -138,6 +152,15 @@ jobs:
|
|||
name: symbol-list
|
||||
path: llvm.symbols
|
||||
|
||||
- name: Cache baseline ABI
|
||||
if: ${{ matrix.name == 'build-baseline' }}
|
||||
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 #v6.1.0
|
||||
with:
|
||||
key: ${{ matrix.ref }}.abi
|
||||
path: |
|
||||
${{ matrix.ref }}.abi
|
||||
llvm.symbols
|
||||
|
||||
abi-compare:
|
||||
if: github.repository_owner == 'llvm'
|
||||
runs-on: ubuntu-24.04
|
||||
|
|
|
|||
31
.github/workflows/premerge.yaml
vendored
31
.github/workflows/premerge.yaml
vendored
|
|
@ -218,6 +218,8 @@ jobs:
|
|||
outputs:
|
||||
macos-projects: ${{ steps.vars.outputs.macos-projects }}
|
||||
macos-check-targets: ${{ steps.vars.outputs.macos-check-targets }}
|
||||
macos-runtimes: ${{ steps.vars.outputs.macos-runtimes }}
|
||||
macos-runtimes-check-targets: ${{ steps.vars.outputs.macos-runtimes-check-targets }}
|
||||
steps:
|
||||
# For pull requests we get the changed files from the GitHub API, so we
|
||||
# only need a sparse checkout of .ci/ to run compute_projects.py. For
|
||||
|
|
@ -261,6 +263,8 @@ jobs:
|
|||
|
||||
echo "macos-projects=${projects_to_build}" >> $GITHUB_OUTPUT
|
||||
echo "macos-check-targets=${project_check_targets}" >> $GITHUB_OUTPUT
|
||||
echo "macos-runtimes=${runtimes_to_build}" >> $GITHUB_OUTPUT
|
||||
echo "macos-runtimes-check-targets=${runtimes_check_targets}" >> $GITHUB_OUTPUT
|
||||
|
||||
premerge-check-macos:
|
||||
name: Build and Test macOS arm64
|
||||
|
|
@ -282,6 +286,10 @@ jobs:
|
|||
run: |
|
||||
brew install ninja cmake
|
||||
command -v sccache >/dev/null || brew install sccache
|
||||
- name: Set up Python venv
|
||||
run: |
|
||||
"$(brew --prefix python@3.14)/bin/python3.14" -m venv "${RUNNER_TEMP}/venv"
|
||||
echo "${RUNNER_TEMP}/venv/bin" >> "$GITHUB_PATH"
|
||||
- name: Build and Test
|
||||
timeout-minutes: 240
|
||||
env:
|
||||
|
|
@ -289,30 +297,17 @@ jobs:
|
|||
SCCACHE_REGION: us-west-2
|
||||
PROJECTS: ${{ needs.premerge-compute-macos.outputs.macos-projects }}
|
||||
CHECK_TARGETS: ${{ needs.premerge-compute-macos.outputs.macos-check-targets }}
|
||||
RUNTIMES: ${{ needs.premerge-compute-macos.outputs.macos-runtimes }}
|
||||
RUNTIMES_CHECK_TARGETS: ${{ needs.premerge-compute-macos.outputs.macos-runtimes-check-targets }}
|
||||
CLANG_TOOLCHAIN_PROGRAM_TIMEOUT: 120
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
GITHUB_PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
run: |
|
||||
export SCCACHE_IDLE_TIMEOUT=0
|
||||
mkdir -p artifacts
|
||||
SCCACHE_LOG=info SCCACHE_ERROR_LOG=$(pwd)/artifacts/sccache.log sccache --start-server
|
||||
|
||||
xcrun cmake -G Ninja \
|
||||
-B build \
|
||||
-S llvm \
|
||||
-DLLVM_ENABLE_PROJECTS="${PROJECTS}" \
|
||||
-DLLVM_DISABLE_ASSEMBLY_FILES=ON \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DLLDB_INCLUDE_TESTS=OFF \
|
||||
-DLLVM_ENABLE_ASSERTIONS=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=sccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=sccache
|
||||
|
||||
ninja -C build ${CHECK_TARGETS}
|
||||
- name: Show sccache stats
|
||||
if: always()
|
||||
run: |
|
||||
mkdir -p artifacts
|
||||
sccache --show-stats
|
||||
sccache --show-stats >> artifacts/sccache_stats.txt
|
||||
./.ci/monolithic-macos.sh "${PROJECTS}" "${CHECK_TARGETS}" "${RUNTIMES}" "${RUNTIMES_CHECK_TARGETS}"
|
||||
- name: Upload Artifacts
|
||||
# In some cases, Github will fail to upload the artifact. We want to
|
||||
# continue anyways as a failed artifact upload is an infra failure, not
|
||||
|
|
|
|||
15
.github/workflows/release-binaries.yml
vendored
15
.github/workflows/release-binaries.yml
vendored
|
|
@ -53,9 +53,6 @@ permissions:
|
|||
jobs:
|
||||
prepare:
|
||||
name: Prepare to build binaries
|
||||
environment:
|
||||
deployment: false
|
||||
name: ${{ case( github.event_name == 'pull_request', null, 'release') }}
|
||||
runs-on: ${{ inputs.runs-on }}
|
||||
if: github.repository_owner == 'llvm'
|
||||
outputs:
|
||||
|
|
@ -83,14 +80,6 @@ jobs:
|
|||
with:
|
||||
release-version: ${{ inputs.release-version }}
|
||||
|
||||
- name: Check Permissions
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: ./.github/workflows/require-team-membership
|
||||
with:
|
||||
team-slug: llvm-release-managers
|
||||
LLVM_TOKEN_GENERATOR_CLIENT_ID: ${{ secrets.LLVM_TOKEN_GENERATOR_CLIENT_ID }}
|
||||
LLVM_TOKEN_GENERATOR_PRIVATE_KEY: ${{ secrets.LLVM_TOKEN_GENERATOR_PRIVATE_KEY }}
|
||||
|
||||
# The name of the Windows binaries uses the version from source, so we need
|
||||
# to fetch it here.
|
||||
- id: version-from-source
|
||||
|
|
@ -368,6 +357,9 @@ jobs:
|
|||
|
||||
upload-release-binaries:
|
||||
name: "Upload Release Binaries"
|
||||
environment:
|
||||
deployment: false
|
||||
name: release
|
||||
needs:
|
||||
- prepare
|
||||
- build-release-package
|
||||
|
|
@ -385,6 +377,7 @@ jobs:
|
|||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: |
|
||||
.github/workflows/require-team-membership
|
||||
.github/workflows/upload-release-artifact
|
||||
.github/workflows/validate-release-version
|
||||
llvm/utils/release/github-upload-release.py
|
||||
|
|
|
|||
3
.github/workflows/release-sources.yml
vendored
3
.github/workflows/release-sources.yml
vendored
|
|
@ -135,7 +135,7 @@ jobs:
|
|||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: |
|
||||
.github/workflows/upload-release-artifact
|
||||
.github/
|
||||
llvm/utils/release/github-upload-release.py
|
||||
llvm/utils/git/requirements.txt
|
||||
sparse-checkout-cone-mode: false
|
||||
|
|
@ -143,6 +143,7 @@ jobs:
|
|||
- name: Upload Artifacts
|
||||
uses: ./.github/workflows/upload-release-artifact
|
||||
with:
|
||||
release-version: ${{ inputs.release-version }}
|
||||
artifact-id: ${{ needs.release-sources.outputs.artifact-id }}
|
||||
attestation-name: ${{ needs.inputs.outputs.ref }}-sources-attestation
|
||||
digest: ${{ needs.release-sources.outputs.digest }}
|
||||
|
|
|
|||
4
.github/workflows/release-tasks.yml
vendored
4
.github/workflows/release-tasks.yml
vendored
|
|
@ -65,6 +65,10 @@ jobs:
|
|||
needs:
|
||||
- validate-tag
|
||||
- release-create
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
attestations: write
|
||||
uses: ./.github/workflows/release-documentation.yml
|
||||
with:
|
||||
release-version: ${{ needs.validate-tag.outputs.release-version }}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ inputs:
|
|||
team-slug:
|
||||
description: >-
|
||||
The team name (in slug form) that the github actor must be a member of.
|
||||
requried: true
|
||||
required: true
|
||||
LLVM_TOKEN_GENERATOR_CLIENT_ID:
|
||||
description: >-
|
||||
Client ID for our GitHub App we use for generating access tokens.
|
||||
|
|
|
|||
|
|
@ -427,6 +427,11 @@ public:
|
|||
PseudoProbeDecoder = Decoder;
|
||||
}
|
||||
|
||||
/// Release the pseudo probe decoder once probes have been updated, freeing
|
||||
/// its (potentially large) address-to-probe maps before later, memory-heavy
|
||||
/// phases such as debug info rewriting.
|
||||
void resetPseudoProbeDecoder() { PseudoProbeDecoder.reset(); }
|
||||
|
||||
/// Return BinaryFunction containing a given \p Address or nullptr if
|
||||
/// no registered function contains the \p Address.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#ifndef BOLT_CORE_DEBUG_DATA_H
|
||||
#define BOLT_CORE_DEBUG_DATA_H
|
||||
|
||||
#include "llvm/ADT/STLFunctionalExtras.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/DIE.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
||||
|
|
@ -63,6 +64,20 @@ findAttributeInfo(const DWARFDie DIE,
|
|||
std::optional<AttrInfo> findAttributeInfo(const DWARFDie DIE,
|
||||
dwarf::Attribute Attr);
|
||||
|
||||
/// Streams the DIEs of \p Unit one at a time via
|
||||
/// DWARFDebugInfoEntry::extractFast, invoking \p Callback on each non-null DIE,
|
||||
/// without ever materializing the unit's full DIE vector (as
|
||||
/// DWARFUnit::dies() / extractDIEsToVector() would). Keeping those vectors out
|
||||
/// of memory is a meaningful RSS win during debug-info processing -- BOLT's
|
||||
/// memory-heaviest phase -- especially for split-DWARF binaries with tens of
|
||||
/// thousands of .dwo units.
|
||||
///
|
||||
/// Only DIE attributes should be inspected in \p Callback: the tree structure
|
||||
/// is not reconstructed, so DWARFDie::children() / getParent() / getSibling()
|
||||
/// are unavailable on the visited DIEs.
|
||||
void forEachDIEInUnit(DWARFUnit &Unit,
|
||||
llvm::function_ref<void(const DWARFDie &)> Callback);
|
||||
|
||||
// DWARF5 Header in order of encoding.
|
||||
// Types represent encoding sizes.
|
||||
using UnitLengthType = uint64_t;
|
||||
|
|
|
|||
|
|
@ -1791,8 +1791,15 @@ void BinaryContext::preprocessDWODebugInfo() {
|
|||
}
|
||||
// Prevent failures when DWOName is already an absolute path.
|
||||
sys::path::make_absolute(DWOCompDir, AbsolutePath);
|
||||
// Extract only the .dwo CU DIE here: we just need the DWO unit pointer
|
||||
// (for DWOCUs) and the isDWOUnit()/DWOId checks. The full DIE vector is
|
||||
// never read off this cached array -- every consumer streams the DIEs on
|
||||
// demand with DWARFDebugInfoEntry::extractFast (DIEBuilder::
|
||||
// constructFromUnit / collectReferencedTypeSignatures).
|
||||
DWARFUnit *DWOCU =
|
||||
DwarfUnit->getNonSkeletonUnitDIE(false, AbsolutePath).getDwarfUnit();
|
||||
DwarfUnit
|
||||
->getNonSkeletonUnitDIE(/*ExtractUnitDIEOnly=*/true, AbsolutePath)
|
||||
.getDwarfUnit();
|
||||
if (!DWOCU->isDWOUnit()) {
|
||||
this->outs()
|
||||
<< "BOLT-WARNING: Debug Fission: DWO debug information for "
|
||||
|
|
@ -2022,38 +2029,10 @@ void BinaryContext::collectDebugScopeBoundaries() {
|
|||
continue;
|
||||
DWARFUnit *DIEUnit = CUDie.getDwarfUnit();
|
||||
|
||||
// For split DWARF, preprocessDWODebugInfo already fully extracts the .dwo's
|
||||
// DIE array.
|
||||
if (DIEUnit->isDWOUnit()) {
|
||||
for (const DWARFDebugInfoEntry &Entry : DIEUnit->dies())
|
||||
processScopeDie(DWARFDie(DIEUnit, &Entry));
|
||||
continue;
|
||||
}
|
||||
// Walk the unit's DIEs by streaming them one at a time. Track nesting depth
|
||||
// with a counter: a DIE with children descends a level (++), a null entry
|
||||
// (sibling-chain terminator) ascends (--), the unit-end offset limits the
|
||||
// walk. This is done to avoid recording all DIEs in a vector like
|
||||
// DWARFUnit's extractDIEsToVector() does, since that is more work than
|
||||
// needed if we just want to lookup specific tags.
|
||||
DWARFDataExtractor DebugInfoData = DIEUnit->getDebugInfoExtractor();
|
||||
uint64_t DIEOffset = DIEUnit->getOffset() + DIEUnit->getHeaderSize();
|
||||
const uint64_t NextCUOffset = DIEUnit->getNextUnitOffset();
|
||||
DWARFDebugInfoEntry DIEEntry;
|
||||
int32_t CurrentDepth = 1;
|
||||
while (CurrentDepth > 0 && DIEOffset < NextCUOffset &&
|
||||
DIEEntry.extractFast(*DIEUnit, &DIEOffset, DebugInfoData,
|
||||
NextCUOffset, 0)) {
|
||||
const DWARFAbbreviationDeclaration *Abbrev =
|
||||
DIEEntry.getAbbreviationDeclarationPtr();
|
||||
if (!Abbrev) {
|
||||
// End of the current sibling chain.
|
||||
--CurrentDepth;
|
||||
continue;
|
||||
}
|
||||
processScopeDie(DWARFDie(DIEUnit, &DIEEntry));
|
||||
if (Abbrev->hasChildren())
|
||||
++CurrentDepth;
|
||||
}
|
||||
// Stream the unit's DIEs one at a time rather than recording them all in a
|
||||
// vector (as DWARFUnit's extractDIEsToVector() does): only DIE tags/ranges
|
||||
// are inspected, so the tree structure is not needed.
|
||||
forEachDIEInUnit(*DIEUnit, processScopeDie);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "bolt/Core/DIEBuilder.h"
|
||||
#include "bolt/Core/BinaryContext.h"
|
||||
#include "bolt/Core/DebugData.h"
|
||||
#include "bolt/Core/ParallelUtilities.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/BinaryFormat/Dwarf.h"
|
||||
|
|
@ -283,23 +284,17 @@ void DIEBuilder::buildTypeUnits(DebugStrOffsetsWriter *StrOffsetWriter,
|
|||
}
|
||||
}
|
||||
|
||||
/// Recursively collects type unit signatures from the given DIE and all of its
|
||||
/// children.
|
||||
/// Collects the signatures of all type units referenced (via DW_FORM_ref_sig8)
|
||||
/// by any DIE of \p U. The DIEs are streamed with forEachDIEInUnit so the
|
||||
/// unit's full DIE vector is never materialized.
|
||||
///
|
||||
/// Note: De-duplication of the collected signatures is handled at the outer
|
||||
/// level by registerUnit.
|
||||
static void collectReferencedTypeSignatures(DWARFDie Die,
|
||||
static void collectReferencedTypeSignatures(DWARFUnit &U,
|
||||
DenseSet<uint64_t> &ProcessedTU,
|
||||
SmallVectorImpl<uint64_t> &TUlist) {
|
||||
SmallVector<DWARFDie, 8> DIElist;
|
||||
DIElist.push_back(Die);
|
||||
|
||||
while (!DIElist.empty()) {
|
||||
DWARFDie Current = DIElist.pop_back_val();
|
||||
if (!Current)
|
||||
continue;
|
||||
|
||||
for (const DWARFAttribute &Attr : Current.attributes()) {
|
||||
forEachDIEInUnit(U, [&](const DWARFDie &Die) {
|
||||
for (const DWARFAttribute &Attr : Die.attributes()) {
|
||||
if (Attr.Value.getForm() != dwarf::DW_FORM_ref_sig8)
|
||||
continue;
|
||||
if (const std::optional<uint64_t> Signature =
|
||||
|
|
@ -307,10 +302,7 @@ static void collectReferencedTypeSignatures(DWARFDie Die,
|
|||
if (ProcessedTU.insert(*Signature).second)
|
||||
TUlist.push_back(*Signature);
|
||||
}
|
||||
|
||||
for (DWARFDie Child : Current.children())
|
||||
DIElist.push_back(Child);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void DIEBuilder::buildDWPTypeUnitsForUnit(DWARFUnit &U) {
|
||||
|
|
@ -319,7 +311,7 @@ void DIEBuilder::buildDWPTypeUnitsForUnit(DWARFUnit &U) {
|
|||
DenseSet<uint64_t> ProcessedTU;
|
||||
SmallVector<uint64_t, 8> TUlist;
|
||||
// Collecting signatures of type units referenced by this unit.
|
||||
collectReferencedTypeSignatures(U.getUnitDIE(), ProcessedTU, TUlist);
|
||||
collectReferencedTypeSignatures(U, ProcessedTU, TUlist);
|
||||
|
||||
getState().Type = U.getVersion() < 5 ? ProcessingType::DWARF4TUs
|
||||
: ProcessingType::DWARF5TUs;
|
||||
|
|
@ -336,7 +328,7 @@ void DIEBuilder::buildDWPTypeUnitsForUnit(DWARFUnit &U) {
|
|||
if (!UnitId || getState().CloneUnitCtxMap[*UnitId].IsConstructed)
|
||||
continue;
|
||||
|
||||
collectReferencedTypeSignatures(TU->getUnitDIE(), ProcessedTU, TUlist);
|
||||
collectReferencedTypeSignatures(*TU, ProcessedTU, TUlist);
|
||||
}
|
||||
|
||||
// Ensure original order of processing type units
|
||||
|
|
|
|||
|
|
@ -101,6 +101,25 @@ std::optional<AttrInfo> findAttributeInfo(const DWARFDie DIE,
|
|||
return findAttributeInfo(DIE, AbbrevDecl, *Index);
|
||||
}
|
||||
|
||||
void forEachDIEInUnit(DWARFUnit &Unit,
|
||||
function_ref<void(const DWARFDie &)> Callback) {
|
||||
DWARFDataExtractor DebugInfoData = Unit.getDebugInfoExtractor();
|
||||
uint64_t DIEOffset = Unit.getOffset() + Unit.getHeaderSize();
|
||||
const uint64_t NextCUOffset = Unit.getNextUnitOffset();
|
||||
DWARFDebugInfoEntry DIEEntry;
|
||||
// ParentIdx is passed as 0 throughout: we visit every DIE but never
|
||||
// reconstruct the tree, so the parent linkage extractFast would record is
|
||||
// unused. The single reusable transient entry means no DIE vector is built.
|
||||
while (DIEOffset < NextCUOffset &&
|
||||
DIEEntry.extractFast(Unit, &DIEOffset, DebugInfoData, NextCUOffset,
|
||||
/*ParentIdx=*/0)) {
|
||||
if (!DIEEntry.getAbbreviationDeclarationPtr())
|
||||
continue; // Null entry: terminator of a sibling chain.
|
||||
DWARFDie Die(&Unit, &DIEEntry);
|
||||
Callback(Die);
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
static void printLE64(const std::string &S) {
|
||||
for (uint32_t I = 0, Size = S.size(); I < Size; ++I) {
|
||||
|
|
|
|||
|
|
@ -257,6 +257,7 @@ bool BinaryFunctionPass::shouldPrint(const BinaryFunction &BF) const {
|
|||
}
|
||||
|
||||
void NormalizeCFG::runOnFunction(BinaryFunction &BF) {
|
||||
const BinaryContext &BC = BF.getBinaryContext();
|
||||
uint64_t NumRemoved = 0;
|
||||
uint64_t NumDuplicateEdges = 0;
|
||||
uint64_t NeedsFixBranches = 0;
|
||||
|
|
@ -286,7 +287,14 @@ void NormalizeCFG::runOnFunction(BinaryFunction &BF) {
|
|||
// Redirect all predecessors to the successor block.
|
||||
while (!BB.pred_empty()) {
|
||||
BinaryBasicBlock *Predecessor = *BB.pred_begin();
|
||||
if (Predecessor->hasJumpTable())
|
||||
// Do not redirect a predecessor that reaches this block via an indirect
|
||||
// branch. This covers both a regular jump table and an unresolved
|
||||
// "unknown control flow" indirect jump (in --strict mode), where the
|
||||
// instruction has no jump table annotation but the jump table data still
|
||||
// references this block. Removing this block would leave a dangling
|
||||
// reference in .rodata, an undefined jump table entry at emission time.
|
||||
const MCInst *LastInst = Predecessor->getLastNonPseudoInstr();
|
||||
if (LastInst && BC.MIB->isIndirectBranch(*LastInst))
|
||||
break;
|
||||
|
||||
if (Predecessor == Successor)
|
||||
|
|
|
|||
|
|
@ -589,40 +589,28 @@ static SmallVector<SmallVector<DWARFUnit *>> partitionCUs(DWARFContext &DwCtx,
|
|||
}
|
||||
if (RefAddrAbbrevs.empty())
|
||||
continue;
|
||||
// Track CUs involved in cross-CU references via DW_FORM_ref_addr.
|
||||
uint64_t DIEOffset = CU->getOffset() + CU->getHeaderSize();
|
||||
const uint64_t NextCUOffset = CU->getNextUnitOffset();
|
||||
DWARFDataExtractor DebugInfoData = CU->getDebugInfoExtractor();
|
||||
DWARFDebugInfoEntry DIEEntry;
|
||||
// extractFast() here only attributes are inspected here, so ParentIdx is
|
||||
// passed as a dummy value.
|
||||
while (DIEOffset < NextCUOffset) {
|
||||
if (!DIEEntry.extractFast(*CU, &DIEOffset, DebugInfoData, NextCUOffset,
|
||||
/*ParentIdx=*/0))
|
||||
break;
|
||||
const DWARFAbbreviationDeclaration *Abbrev =
|
||||
DIEEntry.getAbbreviationDeclarationPtr();
|
||||
if (Abbrev) {
|
||||
if (RefAddrAbbrevs.count(Abbrev)) {
|
||||
DWARFDie Die(CU, &DIEEntry);
|
||||
for (const DWARFAttribute &Attr : Die.attributes()) {
|
||||
if (Attr.Value.getForm() != dwarf::DW_FORM_ref_addr)
|
||||
continue;
|
||||
auto OptRef = Attr.Value.getAsDebugInfoReference();
|
||||
if (!OptRef)
|
||||
continue;
|
||||
DWARFUnit *TargetCU = DwCtx.getUnitForOffset(*OptRef);
|
||||
if (!TargetCU || TargetCU == CU)
|
||||
continue;
|
||||
if (CrossRefSet.insert(CU).second)
|
||||
EC.insert(CU);
|
||||
if (CrossRefSet.insert(TargetCU).second)
|
||||
EC.insert(TargetCU);
|
||||
EC.unionSets(CU, TargetCU);
|
||||
}
|
||||
}
|
||||
// Track CUs involved in cross-CU references via DW_FORM_ref_addr. Only DIE
|
||||
// attributes are inspected, so forEachDIEInUnit streams the DIEs without
|
||||
// materializing the unit's full DIE vector.
|
||||
forEachDIEInUnit(*CU, [&](const DWARFDie &Die) {
|
||||
if (!RefAddrAbbrevs.count(Die.getAbbreviationDeclarationPtr()))
|
||||
return;
|
||||
for (const DWARFAttribute &Attr : Die.attributes()) {
|
||||
if (Attr.Value.getForm() != dwarf::DW_FORM_ref_addr)
|
||||
continue;
|
||||
auto OptRef = Attr.Value.getAsDebugInfoReference();
|
||||
if (!OptRef)
|
||||
continue;
|
||||
DWARFUnit *TargetCU = DwCtx.getUnitForOffset(*OptRef);
|
||||
if (!TargetCU || TargetCU == CU)
|
||||
continue;
|
||||
if (CrossRefSet.insert(CU).second)
|
||||
EC.insert(CU);
|
||||
if (CrossRefSet.insert(TargetCU).second)
|
||||
EC.insert(TargetCU);
|
||||
EC.unionSets(CU, TargetCU);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
DenseMap<DWARFUnit *, SmallVector<DWARFUnit *>> MembersByLeader;
|
||||
|
|
|
|||
|
|
@ -104,6 +104,13 @@ Error PseudoProbeRewriter::postEmitFinalizer() {
|
|||
parsePseudoProbe();
|
||||
updatePseudoProbes();
|
||||
|
||||
// The decoder's address-to-probe maps can be very large and are no longer
|
||||
// needed once probes have been updated. Release both our reference and the
|
||||
// one held by BinaryContext so the memory is freed before the memory-heavy
|
||||
// debug info rewriting phase runs.
|
||||
BC.resetPseudoProbeDecoder();
|
||||
ProbeDecoderPtr.reset();
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2633,8 +2633,8 @@ void RewriteInstance::adjustCommandLineOptions() {
|
|||
BC->UseCompactAligner = opts::UseCompactAligner;
|
||||
BC->X86AlignBranchBoundaryHotOnly = opts::X86AlignBranchBoundaryHotOnly;
|
||||
|
||||
if (BC->isX86() && opts::Lite.getNumOccurrences() == 0 && !opts::StrictMode &&
|
||||
!opts::UseOldText)
|
||||
if ((BC->isX86() || BC->isAArch64()) && opts::Lite.getNumOccurrences() == 0 &&
|
||||
!opts::StrictMode && !opts::UseOldText)
|
||||
opts::Lite = true;
|
||||
|
||||
if (opts::Lite && opts::UseOldText) {
|
||||
|
|
@ -5990,7 +5990,7 @@ void RewriteInstance::patchELFAllocatableRelrSection(
|
|||
RelOffset = RelOffset == 0 ? SectionAddress + Rel.Offset : RelOffset;
|
||||
assert((RelOffset & 1) == 0 && "Wrong relocation offset");
|
||||
RelOffsets.emplace(RelOffset);
|
||||
FixAddend(Section, Rel, RelOffset);
|
||||
FixAddend(Section, Rel, getFileOffsetForAddress(RelOffset));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -156,6 +156,8 @@ Error SDTRewriter::postEmitFinalizer() {
|
|||
SDTNotePatcher->addLE64Patch(SDTInfo.PCOffset, NewAddress);
|
||||
}
|
||||
|
||||
SDTMarkers.clear();
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,8 +21,23 @@
|
|||
# RUN: llvm-readelf -rsW %t.relr.bolt | FileCheck --check-prefix=RELRELFCHECK %s
|
||||
# RUN: llvm-readelf -SW %t.relr.bolt | FileCheck --check-prefix=RELRSZCHECK %s
|
||||
|
||||
// Check that RELR addends are patched at file offsets rather than virtual
|
||||
// addresses when the two differ.
|
||||
# RUN: %clang %cflags -fPIC -pie %t.o -o %t.relr.bias.exe -nostdlib \
|
||||
# RUN: -Wl,-q -Wl,-z,notext -Wl,--pack-dyn-relocs=relr \
|
||||
# RUN: -Wl,--image-base=0x20000
|
||||
# RUN: llvm-objcopy --remove-section .rela.mytext %t.relr.bias.exe
|
||||
# RUN: llvm-readelf -lW %t.relr.bias.exe | FileCheck --check-prefix=BIAS %s
|
||||
# RUN: llvm-bolt %t.relr.bias.exe -o %t.relr.bias.bolt --use-old-text=0 \
|
||||
# RUN: --lite=0
|
||||
# RUN: llvm-objdump -j .text -d -z %t.relr.bias.bolt | \
|
||||
# RUN: FileCheck %s --check-prefix=ADDENDCHECK
|
||||
|
||||
// Check that the CI value was updated
|
||||
# CHECK: [[#%x,ADDR:]] <exitLocal>:
|
||||
|
||||
# BIAS: LOAD {{.*}} 0x0000000000020000
|
||||
|
||||
# CHECK: {{.*}} <$d>:
|
||||
# CHECK-NEXT: {{.*}} .word 0x{{[0]+}}[[#ADDR]]
|
||||
# CHECK-NEXT: {{.*}} .word 0x00000000
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
# RUN: %clang %cflags -O0 %t.o -o %t.exe -Wl,-q
|
||||
# RUN: link_fdata %s %t.o %t.fdata
|
||||
# RUN: llvm-bolt %t.exe -o %t.bolt \
|
||||
# RUN: --data %t.fdata | FileCheck %s
|
||||
# RUN: --data %t.fdata --lite=0 | FileCheck %s
|
||||
|
||||
# CHECK: BOLT-INFO: Inserted 1 stubs in the hot area and 0 stubs in the cold area.
|
||||
|
||||
|
|
|
|||
99
bolt/test/X86/jump-table-empty-block-strict.s
Normal file
99
bolt/test/X86/jump-table-empty-block-strict.s
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
## This reproduces a bug where a PIC jump table entry points to a basic block
|
||||
## that becomes empty after the remove-nops pass.
|
||||
##
|
||||
## In relocation mode BOLT creates the jump table object from the PC-relative
|
||||
## leaq JUMP_TABLE(%rip) reference (BinaryContext::handleAddressRef) whenever
|
||||
## the referenced memory looks like a PIC jump table. This is independent of
|
||||
## whether the indirect jump dispatch is recognized. The jump table annotation
|
||||
## is attached to the jmp only when analyzeIndirectBranch matches the dispatch
|
||||
## pattern -- and the pattern below defeats it by materializing the jump table
|
||||
## base twice, into two separate registers. So the jump table object and its
|
||||
## .rodata entries exist and reference basic blocks, but the jmp has no jump
|
||||
## table annotation, i.e. BinaryBasicBlock::hasJumpTable() is false for it.
|
||||
##
|
||||
## In --strict mode the function is still fully processed: it stays simple with
|
||||
## the block marked as unknown control flow. Jump table entry 0 targets a
|
||||
## nop-only block that falls through to the next block. remove-nops empties that
|
||||
## block, and NormalizeCFG used to redirect its predecessor and delete the empty
|
||||
## block -- it did not recognize the block as a jump table target because the
|
||||
## predecessor's hasJumpTable() is false. The jump table object still referenced
|
||||
## the deleted block by label, leaving a dangling reference in .rodata and
|
||||
## failing emission with "Undefined temporary symbol".
|
||||
##
|
||||
## The fix keeps the block because its predecessor ends in an indirect branch.
|
||||
|
||||
# REQUIRES: system-linux
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o
|
||||
# RUN: llvm-strip --strip-unneeded %t.o
|
||||
# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q -no-pie
|
||||
# RUN: llvm-bolt %t.exe -o %t.out --lite=0 -v=1 --strict=1 \
|
||||
# RUN: -print-cfg -print-only=main 2>&1 | FileCheck %s
|
||||
|
||||
## Confirm we exercise the unknown-control-flow / PIC jump table path.
|
||||
# CHECK: Unknown CF : true
|
||||
# CHECK: jmpq {{.*}}%rax # UNKNOWN CONTROL FLOW
|
||||
# CHECK: PIC Jump table JUMP_TABLE for function main
|
||||
|
||||
## Emission must succeed: the (empty) jump table target block is preserved so
|
||||
## its label stays defined.
|
||||
# CHECK-NOT: Undefined temporary symbol
|
||||
# CHECK-NOT: BOLT-ERROR: Emission failed
|
||||
|
||||
.text
|
||||
.globl main
|
||||
.type main, %function
|
||||
.p2align 2
|
||||
main:
|
||||
LBB0:
|
||||
subq $0x38, %rsp
|
||||
cmpl $0x4, %edi
|
||||
ja LBBdefault
|
||||
|
||||
## Jump table dispatch. Materializing the jump table base twice (into %rax and
|
||||
## then %rdx) prevents analyzeIndirectBranch from recognizing the pattern, so no
|
||||
## jump table annotation is attached to the jmp and it stays unknown control
|
||||
## flow in strict mode.
|
||||
LBB1:
|
||||
movl %edi, %eax
|
||||
leaq (,%rax,4), %rdx
|
||||
leaq JUMP_TABLE(%rip), %rax
|
||||
movl (%rdx,%rax), %eax
|
||||
cltq
|
||||
leaq JUMP_TABLE(%rip), %rdx
|
||||
addq %rdx, %rax
|
||||
jmpq *%rax
|
||||
|
||||
## Jump table entry 0 target: a single nop that falls through to LBBjoin. The
|
||||
## remove-nops pass empties this block; NormalizeCFG would (without the fix)
|
||||
## delete it while the jump table still references it.
|
||||
LBBnop:
|
||||
nop
|
||||
LBBjoin:
|
||||
addq $0x38, %rsp
|
||||
ret
|
||||
|
||||
LBBc1:
|
||||
movl $0x1, %eax
|
||||
jmp LBBjoin2
|
||||
LBBc2:
|
||||
movl $0x2, %eax
|
||||
LBBjoin2:
|
||||
addq $0x38, %rsp
|
||||
ret
|
||||
|
||||
LBBdefault:
|
||||
xorl %eax, %eax
|
||||
addq $0x38, %rsp
|
||||
ret
|
||||
.size main, .-main
|
||||
|
||||
.rodata
|
||||
## jump table, entries must be R_X86_64_PC32 relocs
|
||||
.globl JUMP_TABLE
|
||||
JUMP_TABLE:
|
||||
.long LBBnop-JUMP_TABLE
|
||||
.long LBBc1-JUMP_TABLE
|
||||
.long LBBc2-JUMP_TABLE
|
||||
.long LBBjoin-JUMP_TABLE
|
||||
.long LBBc1-JUMP_TABLE
|
||||
|
|
@ -167,7 +167,7 @@ void UseStdMinMaxCheck::check(const MatchFinder::MatchResult &Result) {
|
|||
const auto *BinaryOp = Result.Nodes.getNodeAs<BinaryOperator>("binaryOp");
|
||||
const BinaryOperatorKind BinaryOpcode = BinaryOp->getOpcode();
|
||||
const SourceLocation IfLocation = If->getIfLoc();
|
||||
const SourceLocation ThenLocation = If->getEndLoc();
|
||||
SourceLocation ThenLocation = If->getEndLoc();
|
||||
|
||||
auto ReplaceAndDiagnose = [&](const StringRef FunctionName) {
|
||||
const SourceManager &Source = *Result.SourceManager;
|
||||
|
|
@ -218,6 +218,12 @@ void UseStdMinMaxCheck::check(const MatchFinder::MatchResult &Result) {
|
|||
if (Semi != StringRef::npos && PostInner.take_front(Semi).trim().empty())
|
||||
PostInner = PostInner.drop_front(Semi + 1);
|
||||
AppendNormalized(PostInner);
|
||||
} else if (const auto SemiTok =
|
||||
Lexer::findNextToken(ThenLocation, Source, LO);
|
||||
SemiTok && SemiTok->is(tok::semi)) {
|
||||
AppendNormalized(
|
||||
GetSourceText(ThenLocation, SemiTok->getLocation()).rtrim());
|
||||
ThenLocation = SemiTok->getLocation();
|
||||
}
|
||||
|
||||
diag(IfLocation, "use `%0` instead of `%1`")
|
||||
|
|
|
|||
|
|
@ -171,13 +171,6 @@ TEST(PreamblePatchTest, ContainsNewIncludes) {
|
|||
Field(&Inclusion::HashLine, 4))));
|
||||
}
|
||||
|
||||
TEST(PreamblePatchTest, MainFileIsEscaped) {
|
||||
auto Includes = collectPatchedIncludes("#include <a.h>", "", "file\"name.cpp")
|
||||
.MainFileIncludes;
|
||||
EXPECT_THAT(Includes, ElementsAre(AllOf(Field(&Inclusion::Written, "<a.h>"),
|
||||
Field(&Inclusion::HashLine, 0))));
|
||||
}
|
||||
|
||||
TEST(PreamblePatchTest, PatchesPreambleIncludes) {
|
||||
MockFS FS;
|
||||
IgnoreDiagnostics Diags;
|
||||
|
|
|
|||
|
|
@ -121,6 +121,10 @@ Changes in existing checks
|
|||
exclusively for overload resolution. Added the :option:`IgnoredTypes`
|
||||
option to allow customizing the set of ignored types.
|
||||
|
||||
- Improved :doc:`readability-use-std-min-max
|
||||
<clang-tidy/checks/readability/use-std-min-max>` check by fixing spurious
|
||||
trailing semicolons and lost comments when the ``if`` body has no braces.
|
||||
|
||||
Removed checks
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
|
|
|
|||
|
|
@ -7,11 +7,12 @@ Finds and removes redundant `void` argument lists.
|
|||
Works in C++ and in C23 and up.
|
||||
|
||||
Examples:
|
||||
: | Initial code | Code with applied fixes |
|
||||
| --------------------------------- | ------------------------- |
|
||||
| `int f(void);` | `int f();` |
|
||||
| `int (*f(void))(void);` | `int (*f())();` |
|
||||
| `typedef int (*f_t(void))(void);` | `typedef int (*f_t())();` |
|
||||
| `void (C::*p)(void);` | `void (C::*p)();` |
|
||||
| `C::C(void) {}` | `C::C() {}` |
|
||||
| `C::~C(void) {}` | `C::~C() {}` |
|
||||
|
||||
| Initial code | Code with applied fixes |
|
||||
| --------------------------------- | ------------------------- |
|
||||
| `int f(void);` | `int f();` |
|
||||
| `int (*f(void))(void);` | `int (*f())();` |
|
||||
| `typedef int (*f_t(void))(void);` | `typedef int (*f_t())();` |
|
||||
| `void (C::*p)(void);` | `void (C::*p)();` |
|
||||
| `C::C(void) {}` | `C::C() {}` |
|
||||
| `C::~C(void) {}` | `C::~C() {}` |
|
||||
|
|
|
|||
|
|
@ -7,14 +7,16 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "AnalysisInternal.h"
|
||||
#include "TypesInternal.h"
|
||||
#include "clang-include-cleaner/Types.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/Tooling/Inclusions/StandardLibrary.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include <utility>
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include <vector>
|
||||
|
||||
namespace clang::include_cleaner {
|
||||
|
|
@ -26,13 +28,19 @@ template <typename T> Hints completeIfDefinition(T *D) {
|
|||
}
|
||||
|
||||
Hints declHints(const Decl *D) {
|
||||
// Definition is only needed for classes and templates for completeness.
|
||||
// For C++, definition is only needed for classes and templates for
|
||||
// completeness. For Objective-C, definition is needed for classes and
|
||||
// protocols. TagDecl covers enums and structs.
|
||||
if (auto *TD = llvm::dyn_cast<TagDecl>(D))
|
||||
return completeIfDefinition(TD);
|
||||
else if (auto *CTD = llvm::dyn_cast<ClassTemplateDecl>(D))
|
||||
return completeIfDefinition(CTD);
|
||||
else if (auto *FTD = llvm::dyn_cast<FunctionTemplateDecl>(D))
|
||||
return completeIfDefinition(FTD);
|
||||
else if (auto *OID = llvm::dyn_cast<ObjCInterfaceDecl>(D))
|
||||
return completeIfDefinition(OID);
|
||||
else if (auto *OPD = llvm::dyn_cast<ObjCProtocolDecl>(D))
|
||||
return completeIfDefinition(OPD);
|
||||
// Any other declaration is assumed usable.
|
||||
return Hints::CompleteSymbol;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/NestedNameSpecifier.h"
|
||||
#include "clang/AST/RecursiveASTVisitor.h"
|
||||
#include "clang/AST/TemplateBase.h"
|
||||
#include "clang/AST/TemplateName.h"
|
||||
|
|
@ -25,7 +24,6 @@
|
|||
#include "clang/Basic/OperatorKinds.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/STLFunctionalExtras.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
|
|
@ -395,6 +393,170 @@ public:
|
|||
report(E->getExprLoc(), E->getOperatorDelete(), RefType::Ambiguous);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Objective-C support
|
||||
|
||||
bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
|
||||
reportType(TL.getNameLoc(), TL.getIFaceDecl());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Protocols are odd in that they are covered by Traverse instead of Visit.
|
||||
bool TraverseObjCProtocolLoc(ObjCProtocolLoc ProtocolLoc) {
|
||||
if (auto *Proto = ProtocolLoc.getProtocol()) {
|
||||
report(ProtocolLoc.getLocation(), Proto);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
|
||||
if (auto *Interface = D->getClassInterface()) {
|
||||
report(D->getLocation(), Interface);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
|
||||
// Identify the selector and the method declaration
|
||||
if (auto *Method = E->getMethodDecl()) {
|
||||
// Report the method as a used symbol
|
||||
report(E->getSelectorStartLoc(), Method);
|
||||
}
|
||||
|
||||
// If it's a class message, report the interface/class as used
|
||||
if (E->getReceiverKind() == ObjCMessageExpr::Class) {
|
||||
if (auto *Interface = E->getReceiverInterface()) {
|
||||
report(E->getReceiverRange().getBegin(), Interface);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitObjCPropertyDecl(clang::ObjCPropertyDecl *PD) {
|
||||
reportType(PD->getLocation(), PD);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
|
||||
// Unconditionally report property declarations and their backing accessor
|
||||
// methods. Dot-notation or pseudo-object references (`foo.bar`) require
|
||||
// the underlying property definition or getters/setters to compile.
|
||||
// Bypassing transient compiler state flags (isMessagingGetter/
|
||||
// isMessagingSetter) guarantees that the declaring
|
||||
// header keeps the properties recorded as used.
|
||||
if (E->isExplicitProperty()) {
|
||||
if (auto *Prop = E->getExplicitProperty()) {
|
||||
report(E->getLocation(), Prop);
|
||||
if (auto *Getter = Prop->getGetterMethodDecl())
|
||||
report(E->getLocation(), Getter);
|
||||
if (auto *Setter = Prop->getSetterMethodDecl())
|
||||
report(E->getLocation(), Setter);
|
||||
}
|
||||
} else {
|
||||
if (auto *Getter = E->getImplicitPropertyGetter())
|
||||
report(E->getLocation(), Getter);
|
||||
if (auto *Setter = E->getImplicitPropertySetter())
|
||||
report(E->getLocation(), Setter);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitObjCProtocolExpr(ObjCProtocolExpr *E) {
|
||||
if (auto *Proto = E->getProtocol()) {
|
||||
report(E->getProtocolIdLoc(), Proto);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitCastExpr(CastExpr *E) {
|
||||
// Handle implicit or explicit casts between Objective-C object pointers
|
||||
// aimed towards protocol-qualification (e.g., `ClassName *` to
|
||||
// `id<Proto>`).
|
||||
QualType SourceType = E->getSubExpr()->getType();
|
||||
QualType DestType = E->getType();
|
||||
|
||||
const auto *SrcPtr = SourceType->getAs<ObjCObjectPointerType>();
|
||||
const auto *DestPtr = DestType->getAs<ObjCObjectPointerType>();
|
||||
|
||||
// If we're casting from a known class pointer to protocol conformance.
|
||||
if (SrcPtr && DestPtr && SrcPtr->getInterfaceDecl()) {
|
||||
const ObjCInterfaceDecl *Class = SrcPtr->getInterfaceDecl();
|
||||
ASTContext &Ctx = Class->getASTContext();
|
||||
|
||||
// For every protocol required by the destination type.
|
||||
for (const ObjCProtocolDecl *Proto : DestPtr->quals()) {
|
||||
const ObjCInterfaceDecl *Current = Class;
|
||||
// Search the inheritance hierarchy for the provider of conformance.
|
||||
while (Current) {
|
||||
bool ConformsDirectly = false;
|
||||
for (const auto *PI : Current->protocols()) {
|
||||
if (Ctx.ProtocolCompatibleWithProtocol(
|
||||
const_cast<ObjCProtocolDecl *>(Proto),
|
||||
const_cast<ObjCProtocolDecl *>(PI))) {
|
||||
ConformsDirectly = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If the class itself provides the conformance directly, we don't
|
||||
// need to keep searching Categories.
|
||||
if (ConformsDirectly)
|
||||
break;
|
||||
|
||||
// If the class doesn't declare direct conformance but conformance is
|
||||
// injected via a visible Category attached to this class, note that
|
||||
// the category header is required by recording an Implicit reference
|
||||
// to it.
|
||||
for (const auto *Cat : Current->visible_categories()) {
|
||||
for (auto *PI : Cat->protocols()) {
|
||||
if (Ctx.ProtocolCompatibleWithProtocol(
|
||||
const_cast<ObjCProtocolDecl *>(Proto),
|
||||
const_cast<ObjCProtocolDecl *>(PI))) {
|
||||
report(E->getExprLoc(), const_cast<ObjCCategoryDecl *>(Cat),
|
||||
RefType::Implicit);
|
||||
}
|
||||
}
|
||||
}
|
||||
Current = Current->getSuperClass();
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
|
||||
// A category declaration depends on its base interface.
|
||||
if (auto *Interface = D->getClassInterface()) {
|
||||
report(D->getLocation(), Interface);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
|
||||
// Implementation requires the base interface.
|
||||
if (auto *Interface = D->getClassInterface()) {
|
||||
report(D->getLocation(), Interface);
|
||||
}
|
||||
// Implementation requires the category declaration.
|
||||
if (auto *Category = D->getCategoryDecl()) {
|
||||
report(D->getCategoryNameLoc(), Category);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D) {
|
||||
// An alias declaration requires the underlying class.
|
||||
if (auto *Aliased = D->getClassInterface()) {
|
||||
report(D->getLocation(), Aliased);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
|
||||
if (auto *Ivar = E->getDecl()) {
|
||||
report(E->getLocation(), Ivar);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "llvm/Testing/Annotations/Annotations.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include <cassert>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -46,7 +47,12 @@ public:
|
|||
LocateExample(llvm::StringRef AnnotatedCode)
|
||||
: Target(AnnotatedCode), AST([this] {
|
||||
TestInputs Inputs(Target.code());
|
||||
Inputs.ExtraArgs.push_back("-std=c++17");
|
||||
if (Target.code().starts_with("@")) {
|
||||
Inputs.ExtraArgs.push_back("-x");
|
||||
Inputs.ExtraArgs.push_back("objective-c");
|
||||
} else {
|
||||
Inputs.ExtraArgs.push_back("-std=c++17");
|
||||
}
|
||||
return Inputs;
|
||||
}()) {}
|
||||
|
||||
|
|
@ -161,9 +167,13 @@ TEST(LocateSymbol, CompleteSymbolHint) {
|
|||
{
|
||||
// Completeness is only absent in cases that matters.
|
||||
const llvm::StringLiteral Cases[] = {
|
||||
"enum ^foo : int; enum ^foo : int {};",
|
||||
"enum class ^foo; enum class ^foo {};",
|
||||
"struct ^foo; struct ^foo {};",
|
||||
"template <typename> struct ^foo; template <typename> struct ^foo {};",
|
||||
"template <typename> void ^foo(); template <typename> void ^foo() {};",
|
||||
"@class ^foo; @interface ^foo @end",
|
||||
"@protocol ^foo; @protocol ^foo @end",
|
||||
};
|
||||
for (auto &Case : Cases) {
|
||||
SCOPED_TRACE(Case);
|
||||
|
|
|
|||
|
|
@ -41,8 +41,9 @@ using testing::ElementsAre;
|
|||
// Referencing: int x = ^foo();
|
||||
// There must be exactly one referencing location marked.
|
||||
// Returns target decls.
|
||||
std::vector<Decl::Kind> testWalk(llvm::StringRef TargetCode,
|
||||
llvm::StringRef ReferencingCode) {
|
||||
std::vector<Decl::Kind>
|
||||
testWalk(llvm::StringRef TargetCode, llvm::StringRef ReferencingCode,
|
||||
std::vector<std::string> ExtraArgs = {"-std=c++20"}) {
|
||||
llvm::Annotations Target(TargetCode);
|
||||
llvm::Annotations Referencing(ReferencingCode);
|
||||
|
||||
|
|
@ -50,7 +51,8 @@ std::vector<Decl::Kind> testWalk(llvm::StringRef TargetCode,
|
|||
Inputs.ExtraFiles["target.h"] = Target.code().str();
|
||||
Inputs.ExtraArgs.push_back("-include");
|
||||
Inputs.ExtraArgs.push_back("target.h");
|
||||
Inputs.ExtraArgs.push_back("-std=c++20");
|
||||
for (const auto &Arg : ExtraArgs)
|
||||
Inputs.ExtraArgs.push_back(Arg);
|
||||
TestAST AST(Inputs);
|
||||
const auto &SM = AST.sourceManager();
|
||||
|
||||
|
|
@ -576,5 +578,293 @@ TEST(WalkAST, CleanupAttr) {
|
|||
"void foo() { __attribute__((__cleanup__(^freep))) char* x = 0; }");
|
||||
}
|
||||
|
||||
TEST(WalkAST, ObjCInterfaceTypeLoc) {
|
||||
testWalk(R"objc(
|
||||
@interface $explicit^MyClass
|
||||
@end
|
||||
)objc",
|
||||
R"objc(
|
||||
void test() {
|
||||
^MyClass *obj;
|
||||
}
|
||||
)objc",
|
||||
{"-x", "objective-c"});
|
||||
}
|
||||
|
||||
TEST(WalkAST, ObjCImplementationDeclDependsOnInterface) {
|
||||
testWalk(R"objc(
|
||||
@interface $explicit^MyClass
|
||||
@end
|
||||
)objc",
|
||||
R"objc(
|
||||
@implementation ^MyClass
|
||||
@end
|
||||
)objc",
|
||||
{"-x", "objective-c"});
|
||||
}
|
||||
|
||||
TEST(WalkAST, ObjCMessageExprSelectorLoc) {
|
||||
testWalk(R"objc(
|
||||
@interface MyClass
|
||||
$explicit^- (void)doSomething;
|
||||
@end
|
||||
)objc",
|
||||
R"objc(
|
||||
void test(MyClass *obj) {
|
||||
[obj ^doSomething];
|
||||
}
|
||||
)objc",
|
||||
{"-x", "objective-c"});
|
||||
}
|
||||
|
||||
TEST(WalkAST, ObjCMessageExprClassReceiver) {
|
||||
testWalk(R"objc(
|
||||
@interface $explicit^MyClass
|
||||
+ (void)classMethod;
|
||||
@end
|
||||
)objc",
|
||||
R"objc(
|
||||
void test() {
|
||||
[^MyClass classMethod];
|
||||
}
|
||||
)objc",
|
||||
{"-x", "objective-c"});
|
||||
}
|
||||
|
||||
TEST(WalkAST, ObjCPropertyRefExprExplicit) {
|
||||
testWalk(R"objc(
|
||||
@interface MyClass
|
||||
@property(nonatomic) int $explicit^foo;
|
||||
@end
|
||||
)objc",
|
||||
R"objc(
|
||||
void test(MyClass *obj) {
|
||||
int x = obj.^foo;
|
||||
}
|
||||
)objc",
|
||||
{"-x", "objective-c"});
|
||||
}
|
||||
|
||||
TEST(WalkAST, ObjCPropertyRefExprImplicitGetter) {
|
||||
testWalk(R"objc(
|
||||
@interface MyClass
|
||||
$explicit^- (int)foo;
|
||||
@end
|
||||
)objc",
|
||||
R"objc(
|
||||
void test(MyClass *obj) {
|
||||
int x = obj.^foo;
|
||||
}
|
||||
)objc",
|
||||
{"-x", "objective-c"});
|
||||
}
|
||||
|
||||
TEST(WalkAST, ObjCPropertyRefExprImplicitSetter) {
|
||||
testWalk(R"objc(
|
||||
@interface MyClass
|
||||
$explicit^- (void)setFoo:(int)val;
|
||||
@end
|
||||
)objc",
|
||||
R"objc(
|
||||
void test(MyClass *obj) {
|
||||
obj.^foo = 42;
|
||||
}
|
||||
)objc",
|
||||
{"-x", "objective-c"});
|
||||
}
|
||||
|
||||
TEST(WalkAST, ObjCPropertyRefExprExplicitSetter) {
|
||||
testWalk(R"objc(
|
||||
@interface MyClass
|
||||
@property(nonatomic) int $explicit^foo;
|
||||
@end
|
||||
)objc",
|
||||
R"objc(
|
||||
void test(MyClass *obj) {
|
||||
obj.^foo = 42;
|
||||
}
|
||||
)objc",
|
||||
{"-x", "objective-c"});
|
||||
}
|
||||
|
||||
TEST(WalkAST, ObjCPropertyRefExprProtocol) {
|
||||
testWalk(R"objc(
|
||||
@protocol MyProtocol
|
||||
@property(nonatomic) int $explicit^foo;
|
||||
@end
|
||||
)objc",
|
||||
R"objc(
|
||||
void test(id<MyProtocol> obj) {
|
||||
int x = obj.^foo;
|
||||
}
|
||||
)objc",
|
||||
{"-x", "objective-c"});
|
||||
}
|
||||
|
||||
TEST(WalkAST, ObjCProtocolInType) {
|
||||
testWalk(R"objc(
|
||||
@protocol $explicit^MyProtocol
|
||||
@end
|
||||
)objc",
|
||||
R"objc(
|
||||
void test() {
|
||||
id<^MyProtocol> obj;
|
||||
}
|
||||
)objc",
|
||||
{"-x", "objective-c"});
|
||||
}
|
||||
|
||||
TEST(WalkAST, ObjCProtocolInClassInterface) {
|
||||
testWalk(R"objc(
|
||||
@protocol $explicit^MyProtocol
|
||||
@end
|
||||
)objc",
|
||||
R"objc(
|
||||
@interface MyClass <^MyProtocol>
|
||||
@end
|
||||
)objc",
|
||||
{"-x", "objective-c"});
|
||||
}
|
||||
|
||||
TEST(WalkAST, ObjCProtocolInProtocolInheritance) {
|
||||
testWalk(R"objc(
|
||||
@protocol $explicit^ParentProtocol
|
||||
@end
|
||||
)objc",
|
||||
R"objc(
|
||||
@protocol MyProtocol <^ParentProtocol>
|
||||
@end
|
||||
)objc",
|
||||
{"-x", "objective-c"});
|
||||
}
|
||||
|
||||
TEST(WalkAST, ObjCProtocolExpr) {
|
||||
testWalk(R"objc(
|
||||
@protocol $explicit^MyProtocol
|
||||
@end
|
||||
)objc",
|
||||
R"objc(
|
||||
void test() {
|
||||
Protocol* p = @protocol(^MyProtocol);
|
||||
}
|
||||
)objc",
|
||||
{"-x", "objective-c"});
|
||||
}
|
||||
|
||||
TEST(WalkAST, ObjCCategoryDeclDependsOnInterface) {
|
||||
testWalk(R"objc(
|
||||
@interface $explicit^MyClass
|
||||
@end
|
||||
)objc",
|
||||
R"objc(
|
||||
@interface ^MyClass (Category)
|
||||
@end
|
||||
)objc",
|
||||
{"-x", "objective-c"});
|
||||
}
|
||||
|
||||
TEST(WalkAST, ObjCCategoryImplDependsOnInterface) {
|
||||
testWalk(R"objc(
|
||||
@interface $explicit^MyClass
|
||||
@end
|
||||
)objc",
|
||||
R"objc(
|
||||
@interface MyClass (Category)
|
||||
@end
|
||||
@implementation ^MyClass (Category)
|
||||
@end
|
||||
)objc",
|
||||
{"-x", "objective-c"});
|
||||
}
|
||||
|
||||
TEST(WalkAST, ObjCCategoryImplDependsOnCategoryDecl) {
|
||||
testWalk(R"objc(
|
||||
@interface MyClass
|
||||
@end
|
||||
@interface $explicit^MyClass (Category)
|
||||
@end
|
||||
)objc",
|
||||
R"objc(
|
||||
@implementation MyClass (^Category)
|
||||
@end
|
||||
)objc",
|
||||
{"-x", "objective-c"});
|
||||
}
|
||||
|
||||
TEST(WalkAST, ObjCImplicitCastToProtocolConformingCategory) {
|
||||
testWalk(R"objc(
|
||||
@protocol MyProtocol
|
||||
@end
|
||||
@interface MyClass
|
||||
@end
|
||||
@interface $implicit^MyClass (MyCategory) <MyProtocol>
|
||||
@end
|
||||
)objc",
|
||||
R"objc(
|
||||
void test(MyClass *obj) {
|
||||
id<MyProtocol> p = ^obj;
|
||||
}
|
||||
)objc",
|
||||
{"-x", "objective-c"});
|
||||
}
|
||||
|
||||
TEST(WalkAST, ObjCCompatibleAliasDecl) {
|
||||
testWalk(R"objc(
|
||||
@interface $explicit^MyClass
|
||||
@end
|
||||
)objc",
|
||||
R"objc(
|
||||
^@compatibility_alias AliasName MyClass;
|
||||
)objc",
|
||||
{"-x", "objective-c"});
|
||||
}
|
||||
|
||||
TEST(WalkAST, ObjCCompatibleAliasUsage) {
|
||||
testWalk(R"objc(
|
||||
@interface $explicit^MyClass
|
||||
@end
|
||||
@compatibility_alias AliasName MyClass;
|
||||
)objc",
|
||||
R"objc(
|
||||
void test() {
|
||||
^AliasName *obj;
|
||||
}
|
||||
)objc",
|
||||
{"-x", "objective-c"});
|
||||
}
|
||||
|
||||
TEST(WalkAST, ObjCIvarRefExprExplicit) {
|
||||
testWalk(R"objc(
|
||||
@interface MyClass {
|
||||
@public
|
||||
int $explicit^foo;
|
||||
}
|
||||
@end
|
||||
)objc",
|
||||
R"objc(
|
||||
void test(MyClass *obj) {
|
||||
int x = obj->^foo;
|
||||
}
|
||||
)objc",
|
||||
{"-x", "objective-c"});
|
||||
}
|
||||
|
||||
TEST(WalkAST, ObjCIvarRefExprFree) {
|
||||
testWalk(R"objc(
|
||||
@interface MyClass {
|
||||
int $explicit^foo;
|
||||
}
|
||||
@end
|
||||
)objc",
|
||||
R"objc(
|
||||
@implementation MyClass
|
||||
- (void)test {
|
||||
int x = ^foo;
|
||||
}
|
||||
@end
|
||||
)objc",
|
||||
{"-x", "objective-c"});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace clang::include_cleaner
|
||||
|
|
|
|||
|
|
@ -253,6 +253,18 @@ void testVectorSizeType() {
|
|||
value = v.size();
|
||||
}
|
||||
|
||||
namespace gh208708 {
|
||||
void f(int &n) {
|
||||
// CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::max` instead of `<`
|
||||
// CHECK-FIXES: n = std::max(n, -1);
|
||||
if (n < -1) n = -1 ;
|
||||
|
||||
// CHECK-MESSAGES: :[[@LINE+2]]:3: warning: use `std::min` instead of `>`
|
||||
// CHECK-FIXES: n = std::min(n, 1); /*use clamp when c++17 or later is enabled*/
|
||||
if (n > 1) n = 1/*use clamp when c++17 or later is enabled*/;
|
||||
}
|
||||
} // namespace gh208708
|
||||
|
||||
namespace gh121676 {
|
||||
|
||||
void useLeft() {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ Sirraide \
|
|||
aeternalmail@gmail.com (email), [Sirraide](https://github.com/Sirraide) (GitHub), Ætérnal (Discord), Sirraide (Discourse)
|
||||
|
||||
Mariya Podchishchaeva \
|
||||
mariya.podchishchaeva@intel.com (email), [Fznamznon](https://github.com/Fznamznon) (GitHub), fznamznon (Discord), Fznamznon (Discourse)
|
||||
fznamznon23@gmail.com (email), [Fznamznon](https://github.com/Fznamznon) (GitHub), fznamznon (Discord), Fznamznon (Discourse)
|
||||
|
||||
### Recovery AST
|
||||
|
||||
|
|
@ -167,7 +167,7 @@ i@maskray.me (email), MaskRay (Phabricator), [MaskRay](https://github.com/MaskRa
|
|||
### Constant Expressions
|
||||
|
||||
Mariya Podchishchaeva \
|
||||
mariya.podchishchaeva@intel.com (email), [Fznamznon](https://github.com/Fznamznon) (GitHub), fznamznon (Discord), Fznamznon (Discourse)
|
||||
fznamznon23@gmail.com (email), [Fznamznon](https://github.com/Fznamznon) (GitHub), fznamznon (Discord), Fznamznon (Discourse)
|
||||
|
||||
### Thread Safety Analysis
|
||||
|
||||
|
|
|
|||
|
|
@ -199,13 +199,31 @@ foreach(target aarch64-unknown-linux-gnu;armv7-unknown-linux-gnueabihf;i386-unkn
|
|||
endforeach()
|
||||
|
||||
if(FUCHSIA_SDK)
|
||||
# Since there is only one build of the toolchain runtimes for users doing any
|
||||
# supported -ffuchsia-api-level=... build, target the oldest unretired level.
|
||||
file(READ "${FUCHSIA_SDK}/version_history.json" FUCHSIA_SDK_VERSION_HISTORY)
|
||||
string(JSON FUCHSIA_SDK_API_LEVEL_COUNT LENGTH "${FUCHSIA_SDK_VERSION_HISTORY}" "data" "api_levels")
|
||||
math(EXPR FUCHSIA_SDK_API_LEVEL_MAXIDX "${FUCHSIA_SDK_API_LEVEL_COUNT} - 1")
|
||||
set(FUCHSIA_API_LEVEL 0)
|
||||
foreach(idx RANGE ${FUCHSIA_SDK_API_LEVEL_MAXIDX})
|
||||
string(JSON FUCHSIA_API_LEVEL_NAME MEMBER "${FUCHSIA_SDK_VERSION_HISTORY}" "data" "api_levels" ${idx})
|
||||
string(JSON FUCHSIA_API_LEVEL_PHASE GET "${FUCHSIA_SDK_VERSION_HISTORY}" "data" "api_levels" "${FUCHSIA_API_LEVEL_NAME}" "phase")
|
||||
if(NOT "${FUCHSIA_API_LEVEL_PHASE}" STREQUAL "retired")
|
||||
set(FUCHSIA_API_LEVEL_INT ${FUCHSIA_API_LEVEL_NAME})
|
||||
if(FUCHSIA_API_LEVEL EQUAL 0 OR FUCHSIA_API_LEVEL_INT LESS FUCHSIA_API_LEVEL)
|
||||
set(FUCHSIA_API_LEVEL ${FUCHSIA_API_LEVEL_INT})
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
message(STATUS "Runtimes target Fuchsia API level ${FUCHSIA_API_LEVEL}")
|
||||
|
||||
set(FUCHSIA_aarch64-unknown-fuchsia_NAME arm64)
|
||||
set(FUCHSIA_arm-unknown-fuchsia_NAME arm)
|
||||
set(FUCHSIA_i386-unknown-fuchsia_NAME x64)
|
||||
set(FUCHSIA_x86_64-unknown-fuchsia_NAME x64)
|
||||
set(FUCHSIA_riscv64-unknown-fuchsia_NAME riscv64)
|
||||
foreach(target i386-unknown-fuchsia;x86_64-unknown-fuchsia;aarch64-unknown-fuchsia;arm-unknown-fuchsia;riscv64-unknown-fuchsia)
|
||||
set(FUCHSIA_${target}_COMPILER_FLAGS "--target=${target} -I${FUCHSIA_SDK}/pkg/sync/include -I${FUCHSIA_SDK}/pkg/fdio/include -fstack-size-section -fexperimental-call-graph-section")
|
||||
set(FUCHSIA_${target}_COMPILER_FLAGS "--target=${target} -ffuchsia-api-level=${FUCHSIA_API_LEVEL} -I${FUCHSIA_SDK}/pkg/sync/include -I${FUCHSIA_SDK}/pkg/fdio/include -fstack-size-section -fexperimental-call-graph-section")
|
||||
set(FUCHSIA_${target}_LINKER_FLAGS "-L${FUCHSIA_SDK}/arch/${FUCHSIA_${target}_NAME}/lib")
|
||||
set(FUCHSIA_${target}_SYSROOT "${FUCHSIA_SDK}/arch/${FUCHSIA_${target}_NAME}/sysroot")
|
||||
endforeach()
|
||||
|
|
|
|||
|
|
@ -6821,6 +6821,16 @@ the configuration (without a prefix: ``Auto``).
|
|||
# include "A.inc" # include "A.h"
|
||||
# include "A-util.h" # include "A.inc"
|
||||
|
||||
* ``bool Natural`` Whether or not includes are sorted by natural ordering i.e., whether
|
||||
embedded runs of digits are compared as numbers rather than sequences of
|
||||
characters.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
true: false:
|
||||
#include "A2.h" vs. #include "A10.h"
|
||||
#include "A10.h" #include "A2.h"
|
||||
|
||||
|
||||
.. _SortJavaStaticImport:
|
||||
|
||||
|
|
@ -7393,6 +7403,35 @@ the configuration (without a prefix: ``Auto``).
|
|||
|
||||
|
||||
|
||||
.. _SpacesInBlockComments:
|
||||
|
||||
**SpacesInBlockComments** (``SpacesInBlockCommentsStyle``) :versionbadge:`clang-format 24` :ref:`¶ <SpacesInBlockComments>`
|
||||
The SpacesInBlockCommentsStyle to use for ordinary block comments.
|
||||
Documentation comments such as ``/** ... */`` and ``/*! ... */``
|
||||
and parameter comments ending with ``=`` before the closing ``*/`` are
|
||||
left unchanged.
|
||||
|
||||
Possible values:
|
||||
|
||||
* ``SIBCS_Never`` (in configuration: ``Never``)
|
||||
Remove spaces after ``/*`` and before ``*/``.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
/*comment*/
|
||||
|
||||
* ``SIBCS_Always`` (in configuration: ``Always``)
|
||||
Add spaces after ``/*`` and before ``*/``.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
/* comment */
|
||||
|
||||
* ``SIBCS_Leave`` (in configuration: ``Leave``)
|
||||
Leave existing spaces unchanged.
|
||||
|
||||
|
||||
|
||||
.. _SpacesInCStyleCastParentheses:
|
||||
|
||||
**SpacesInCStyleCastParentheses** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ <SpacesInCStyleCastParentheses>`
|
||||
|
|
|
|||
|
|
@ -62,6 +62,18 @@ honored, and calls use the caller's features, matching GCC. Per-function
|
|||
features cannot lower the translation-unit ABI level;
|
||||
`-fclang-abi-compat=23` restores the previous behavior. (#GH193298)
|
||||
|
||||
- On MIPS, a `_Complex` value with an integer element type is now returned packed
|
||||
into a single integer register when it fits in one, matching GCC. A `_Complex char` or
|
||||
`_Complex short`, and on N32/N64 also a `_Complex int`, is no longer returned
|
||||
with one part per register. `-fclang-abi-compat=23` restores the previous
|
||||
behavior. (#GH212109)
|
||||
|
||||
- On MIPS N32/N64, a `_Complex float` or `_Complex double` argument is now packed
|
||||
into integer registers, or onto the stack, once there is no longer room to give
|
||||
each of its parts a floating-point register, matching GCC. Clang previously
|
||||
always passed the parts separately. `-fclang-abi-compat=23` restores the previous
|
||||
behavior. (#GH212109)
|
||||
|
||||
### AST Dumping Potentially Breaking Changes
|
||||
|
||||
### Clang Frontend Potentially Breaking Changes
|
||||
|
|
@ -95,6 +107,10 @@ features cannot lower the translation-unit ABI level;
|
|||
|
||||
#### C++2d Feature Support
|
||||
|
||||
- Clang now supports [P3658R1](https://wg21.link/p3658r1) (Adjust identifier
|
||||
following new Unicode recommendations), applied as a DR to all C++ language
|
||||
modes.
|
||||
|
||||
#### C++2c Feature Support
|
||||
|
||||
- Clang now supports [P3533R2](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3533r2.html) (constexpr virtual inheritance).
|
||||
|
|
@ -345,11 +361,17 @@ features cannot lower the translation-unit ABI level;
|
|||
- Fixed an assertion failure when passing a wide string literal to `__builtin_nan`. (#GH212108)
|
||||
- Fixed a constraint comparison bug in partial ordering. (#GH182671)
|
||||
- Fixed a rejected-valid case that used an explicit object parameter in an out-of-line definition of a nested class member. (#GH136472)
|
||||
- Fixed an assertion on omp taskloop transparent (#GH197162)
|
||||
- Fixed a bug where `__func__`, `__PRETTY_FUNCTION__` and `__FUNCTION__` were not resolving to the proper function when inside a lambda return type (#GH211811)
|
||||
- Fixed USR generation for declarations whose signature mentions a class-type
|
||||
non-type template parameter. (#GH212351)
|
||||
|
||||
#### Bug Fixes to Compiler Builtins
|
||||
|
||||
- Fixed a crash when classifying a call to a builtin with dependent arguments,
|
||||
such as when the call is used as an `auto` non-type template argument.
|
||||
- Fixed a crash in ``__builtin_dump_struct`` when ``-Werror`` promotes
|
||||
format warnings to errors. (#GH211943)
|
||||
|
||||
#### Bug Fixes to Attribute Support
|
||||
|
||||
|
|
@ -359,9 +381,14 @@ features cannot lower the translation-unit ABI level;
|
|||
the `sized_by`/`sized_by_or_null` attributes. Because `sized_by` and
|
||||
`sized_by_or_null` describe the size in bytes rather than a count of elements,
|
||||
they are now correctly accepted on such pointers.
|
||||
- Propagate attributes on redeclarations across modules.
|
||||
|
||||
#### Bug Fixes to C++ Support
|
||||
|
||||
- Fixed an issue where `__typeof__` incorrectly rejected cv-qualified function types.
|
||||
|
||||
- Fixed a bug where top-level CV qualifiers (such as ``const``) were dropped from pointers modified by Microsoft pointer attributes (like ``__ptr32`` and ``__ptr64``) and WebAssembly's ``__funcref``.
|
||||
|
||||
- Fixed an issue where we tried to compare invalid NTTPs for variable declarations, which ended up in hitting an assertion with a constrained non-plain-auto NTTP, which we don't quite implement yet. (#GH208658)
|
||||
|
||||
- Fixed a crash when a using-declaration naming an unresolvable member of a
|
||||
|
|
@ -379,10 +406,24 @@ features cannot lower the translation-unit ABI level;
|
|||
`[](Types... = args...) {}`). Clang now diagnoses the illegal default
|
||||
argument instead of asserting. (#GH210714)
|
||||
|
||||
- Fixed a crash on invalid code where a ``decltype`` not followed by ``(`` was
|
||||
parsed where a nested-name-specifier could appear (e.g. ``int decltype = 0;``).
|
||||
Clang now diagnoses the error instead of asserting. (#GH211207)
|
||||
|
||||
- Fixed a crash when computing the implicit deletion of a defaulted comparison
|
||||
operator required an access check that ran while an enclosing declaration
|
||||
was still being parsed. (#GH210692)
|
||||
|
||||
- A workaround that was introduced to fix an issue with the `<format>` header present in some versions of
|
||||
libstdc++15 has been extended to support preprocessed input. Previously, splitting the preprocessing and
|
||||
compilation step would result in the fix not being applied. (#GH160314)
|
||||
|
||||
- A defaulted copy or move assignment operator for a union was left with an
|
||||
empty body and copied nothing when the operator was actually called, for
|
||||
example through a pointer to member. Clang now synthesizes a whole-object
|
||||
copy so the union's object representation is copied, matching the defaulted
|
||||
union copy constructor.
|
||||
|
||||
#### Bug Fixes to AST Handling
|
||||
|
||||
- Fixed a non-deterministic ordering of unused local typedefs that made
|
||||
|
|
@ -393,6 +434,8 @@ features cannot lower the translation-unit ABI level;
|
|||
|
||||
#### Miscellaneous Clang Crashes Fixed
|
||||
- Fixed a crash when instantiating an invalid dependent friend destructor declaration in a class template. (#GH210234)
|
||||
- Fixed an assertion failure in `-extract-api` when a documentation comment
|
||||
contains invalid UTF-8. (#GH212393)
|
||||
|
||||
### OpenACC Specific Changes
|
||||
|
||||
|
|
@ -426,6 +469,12 @@ features cannot lower the translation-unit ABI level;
|
|||
|
||||
#### Windows Support
|
||||
|
||||
- Fixed a bug where Clang did not match the MSVC ABI on Arm64 when an
|
||||
over-aligned base class is followed by another base class. MSVC on Arm64 (but
|
||||
not Arm64EC or x64) reuses the tail padding of the over-aligned base for the
|
||||
subsequent base; Clang now does the same.
|
||||
([#210174](https://github.com/llvm/llvm-project/issues/210174))
|
||||
|
||||
#### LoongArch Support
|
||||
|
||||
#### RISC-V Support
|
||||
|
|
@ -454,8 +503,13 @@ features cannot lower the translation-unit ABI level;
|
|||
|
||||
### clang-format
|
||||
|
||||
- Add `SpacesInBlockComments` option to control spacing after `/*` and
|
||||
before `*/` in ordinary block comments.
|
||||
|
||||
### libclang
|
||||
|
||||
- visit identifier initializers in lambda capture as VarDecl instead of VariableRef. Warning: this changes behaviour.
|
||||
|
||||
### Code Completion
|
||||
|
||||
### Static Analyzer
|
||||
|
|
|
|||
|
|
@ -510,9 +510,10 @@ Use of these attributes has been deprecated.
|
|||
|
||||
### Function Pointers
|
||||
|
||||
Thread safety attributes may also be applied to function pointer variables and
|
||||
fields. The attributes describe the locking behavior of calling through that
|
||||
pointer, and the analysis will check calls through the pointer accordingly.
|
||||
Thread safety attributes may also be applied to variables, fields, and
|
||||
parameters of function pointer (or, in C++, function reference) type. The
|
||||
attributes describe the locking behavior of calling through that pointer, and
|
||||
the analysis will check calls through the pointer accordingly.
|
||||
|
||||
```c++
|
||||
Mutex mu;
|
||||
|
|
@ -531,16 +532,22 @@ void test(Ops *ops) {
|
|||
ops->read();
|
||||
unlock_fn();
|
||||
}
|
||||
|
||||
void visit_all(void (*visit)(int) REQUIRES(mu), int n) {
|
||||
lock_fn();
|
||||
visit(n); // OK: 'mu' is held here
|
||||
unlock_fn();
|
||||
}
|
||||
```
|
||||
|
||||
Note that the attributes are on the *variable* (or field), not on the function
|
||||
pointer type. Assigning a function with different (or no) attributes to an
|
||||
annotated function pointer variable is not diagnosed. The analysis trusts the
|
||||
annotations on the variable at the call site.
|
||||
Note that the attributes are on the *variable* (or field, or parameter), not on
|
||||
the function pointer type. Assigning a function with different (or no)
|
||||
attributes to an annotated function pointer variable is not diagnosed. The
|
||||
analysis trusts the annotations on the variable at the call site.
|
||||
|
||||
This support is limited to plain function pointers. Pointers-to-member
|
||||
functions, blocks, and wrapper types such as `std::function` are not
|
||||
supported yet.
|
||||
This support is limited to plain function pointers and function references.
|
||||
Pointers-to-member functions, blocks, and wrapper types such as `std::function`
|
||||
are not supported yet.
|
||||
|
||||
### Warning flags
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "clang/APINotes/Types.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/VersionTuple.h"
|
||||
|
|
@ -169,6 +170,16 @@ public:
|
|||
lookupCXXMethod(ContextID CtxID, llvm::StringRef Name,
|
||||
llvm::ArrayRef<std::string> Parameters);
|
||||
|
||||
/// Build the selector key for the given C++ method.
|
||||
std::optional<APINotesFunctionSelectorKey>
|
||||
getCXXMethodSelectorKey(ContextID CtxID, llvm::StringRef Name);
|
||||
|
||||
/// Build the selector key for the given C++ method with an exact parameter
|
||||
/// selector.
|
||||
std::optional<APINotesFunctionSelectorKey>
|
||||
getCXXMethodSelectorKey(ContextID CtxID, llvm::StringRef Name,
|
||||
llvm::ArrayRef<std::string> Parameters);
|
||||
|
||||
/// Look for information regarding the given global variable.
|
||||
///
|
||||
/// \param Name The name of the global variable.
|
||||
|
|
@ -195,6 +206,27 @@ public:
|
|||
llvm::ArrayRef<std::string> Parameters,
|
||||
std::optional<Context> Ctx = std::nullopt);
|
||||
|
||||
/// Build the selector key for the given global function.
|
||||
std::optional<APINotesFunctionSelectorKey>
|
||||
getGlobalFunctionSelectorKey(llvm::StringRef Name,
|
||||
std::optional<Context> Ctx = std::nullopt);
|
||||
|
||||
/// Build the selector key for the given global function with an exact
|
||||
/// parameter selector.
|
||||
std::optional<APINotesFunctionSelectorKey>
|
||||
getGlobalFunctionSelectorKey(llvm::StringRef Name,
|
||||
llvm::ArrayRef<std::string> Parameters,
|
||||
std::optional<Context> Ctx = std::nullopt);
|
||||
|
||||
/// Collect exact parameter selector keys stored by this reader.
|
||||
void collectExactFunctionParameterSelectors(
|
||||
llvm::SmallVectorImpl<APINotesFunctionSelectorKey> &Selectors);
|
||||
|
||||
/// Reconstruct parameter selector strings for a stored exact selector key.
|
||||
std::optional<llvm::SmallVector<std::string, 4>>
|
||||
getParameterSelectorSpellingsForDiagnostics(
|
||||
const APINotesFunctionSelectorKey &Key);
|
||||
|
||||
/// Look for information regarding the given enumerator.
|
||||
///
|
||||
/// \param Name The name of the enumerator.
|
||||
|
|
|
|||
|
|
@ -11,9 +11,16 @@
|
|||
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMapInfo.h"
|
||||
#include "llvm/ADT/Hashing.h"
|
||||
#include "llvm/ADT/PointerEmbeddedInt.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <climits>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
|
@ -22,6 +29,17 @@ class raw_ostream;
|
|||
|
||||
namespace clang {
|
||||
namespace api_notes {
|
||||
|
||||
template <typename RangeT>
|
||||
std::string formatAPINotesParameterSelector(RangeT &&Parameters) {
|
||||
std::string Result;
|
||||
llvm::raw_string_ostream OS(Result);
|
||||
OS << "[";
|
||||
llvm::interleaveComma(Parameters, OS);
|
||||
OS << "]";
|
||||
return Result;
|
||||
}
|
||||
|
||||
enum class RetainCountConventionKind {
|
||||
None,
|
||||
CFReturnsRetained,
|
||||
|
|
@ -988,6 +1006,83 @@ struct Context {
|
|||
Context(ContextID id, ContextKind kind) : id(id), kind(kind) {}
|
||||
};
|
||||
|
||||
using IdentifierID = llvm::PointerEmbeddedInt<unsigned, 31>;
|
||||
|
||||
/// A key for a stored global-function or C++-method API notes entry.
|
||||
///
|
||||
/// The key is represented by the ID of its parent context, the declaration
|
||||
/// name, and optional exact parameter types.
|
||||
struct FunctionTableKey {
|
||||
uint32_t parentContextID;
|
||||
uint32_t nameID;
|
||||
std::optional<llvm::SmallVector<IdentifierID, 2>> parameterTypeIDs;
|
||||
|
||||
FunctionTableKey() : parentContextID(-1), nameID(-1) {}
|
||||
|
||||
FunctionTableKey(uint32_t ParentContextID, uint32_t NameID)
|
||||
: parentContextID(ParentContextID), nameID(NameID) {}
|
||||
|
||||
FunctionTableKey(uint32_t ParentContextID, uint32_t NameID,
|
||||
const llvm::SmallVectorImpl<IdentifierID> &ParameterTypeIDs)
|
||||
: parentContextID(ParentContextID), nameID(NameID) {
|
||||
parameterTypeIDs.emplace(ParameterTypeIDs.begin(), ParameterTypeIDs.end());
|
||||
}
|
||||
|
||||
FunctionTableKey(std::optional<Context> ParentCtx, IdentifierID NameID)
|
||||
: parentContextID(ParentCtx ? ParentCtx->id.Value
|
||||
: static_cast<uint32_t>(-1)),
|
||||
nameID(NameID) {}
|
||||
|
||||
FunctionTableKey(std::optional<Context> ParentCtx, IdentifierID NameID,
|
||||
const llvm::SmallVectorImpl<IdentifierID> &ParameterTypeIDs)
|
||||
: parentContextID(ParentCtx ? ParentCtx->id.Value
|
||||
: static_cast<uint32_t>(-1)),
|
||||
nameID(NameID) {
|
||||
parameterTypeIDs.emplace(ParameterTypeIDs.begin(), ParameterTypeIDs.end());
|
||||
}
|
||||
|
||||
llvm::hash_code hashValue() const {
|
||||
auto Hash = llvm::hash_combine(parentContextID, nameID,
|
||||
static_cast<bool>(parameterTypeIDs));
|
||||
if (parameterTypeIDs) {
|
||||
Hash = llvm::hash_combine(Hash, parameterTypeIDs->size());
|
||||
for (IdentifierID TypeID : *parameterTypeIDs)
|
||||
Hash = llvm::hash_combine(Hash, static_cast<unsigned>(TypeID));
|
||||
}
|
||||
return Hash;
|
||||
}
|
||||
};
|
||||
|
||||
inline bool operator==(const FunctionTableKey &LHS,
|
||||
const FunctionTableKey &RHS) {
|
||||
return LHS.parentContextID == RHS.parentContextID &&
|
||||
LHS.nameID == RHS.nameID &&
|
||||
LHS.parameterTypeIDs == RHS.parameterTypeIDs;
|
||||
}
|
||||
|
||||
/// Stable reader-facing identity for an API notes function selector entry.
|
||||
///
|
||||
/// The key keeps the serialized function table identity together with the table
|
||||
/// kind. parentContextID names only the declaration context and does not say
|
||||
/// whether the entry came from the global-function or C++-method table.
|
||||
struct APINotesFunctionSelectorKey {
|
||||
FunctionTableKey Key;
|
||||
bool IsCXXMethod = false;
|
||||
|
||||
APINotesFunctionSelectorKey getWithoutParameterSelector() const {
|
||||
return {FunctionTableKey(Key.parentContextID, Key.nameID), IsCXXMethod};
|
||||
}
|
||||
|
||||
llvm::hash_code hashValue() const {
|
||||
return llvm::hash_combine(Key.hashValue(), IsCXXMethod);
|
||||
}
|
||||
};
|
||||
|
||||
inline bool operator==(const APINotesFunctionSelectorKey &LHS,
|
||||
const APINotesFunctionSelectorKey &RHS) {
|
||||
return LHS.Key == RHS.Key && LHS.IsCXXMethod == RHS.IsCXXMethod;
|
||||
}
|
||||
|
||||
/// A temporary reference to an Objective-C selector, suitable for
|
||||
/// referencing selector data on the stack.
|
||||
///
|
||||
|
|
@ -1001,4 +1096,30 @@ struct ObjCSelectorRef {
|
|||
} // namespace api_notes
|
||||
} // namespace clang
|
||||
|
||||
namespace llvm {
|
||||
template <> struct DenseMapInfo<clang::api_notes::FunctionTableKey> {
|
||||
static unsigned getHashValue(const clang::api_notes::FunctionTableKey &Key) {
|
||||
return Key.hashValue();
|
||||
}
|
||||
|
||||
static bool isEqual(const clang::api_notes::FunctionTableKey &LHS,
|
||||
const clang::api_notes::FunctionTableKey &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct DenseMapInfo<clang::api_notes::APINotesFunctionSelectorKey> {
|
||||
static unsigned
|
||||
getHashValue(const clang::api_notes::APINotesFunctionSelectorKey &Key) {
|
||||
return Key.hashValue();
|
||||
}
|
||||
|
||||
static bool
|
||||
isEqual(const clang::api_notes::APINotesFunctionSelectorKey &LHS,
|
||||
const clang::api_notes::APINotesFunctionSelectorKey &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -24,10 +24,10 @@
|
|||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/AST/TemplateBase.h"
|
||||
#include "clang/AST/TypeBase.h"
|
||||
#include "clang/Basic/BuiltinTraits.h"
|
||||
#include "clang/Basic/CharInfo.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/SyncScope.h"
|
||||
#include "clang/Basic/TypeTraits.h"
|
||||
#include "llvm/ADT/APFloat.h"
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@
|
|||
#include "clang/AST/TemplateBase.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/UnresolvedSet.h"
|
||||
#include "clang/Basic/BuiltinTraits.h"
|
||||
#include "clang/Basic/ExceptionSpecificationType.h"
|
||||
#include "clang/Basic/ExpressionTraits.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "clang/Basic/Lambda.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
|
|
@ -39,7 +39,6 @@
|
|||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
#include "clang/Basic/TemplateKinds.h"
|
||||
#include "clang/Basic/TypeTraits.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
|
|
|
|||
|
|
@ -485,13 +485,13 @@ public:
|
|||
/// ObjCSelectorExpr used for \@selector in Objective-C.
|
||||
class ObjCSelectorExpr : public Expr {
|
||||
Selector SelName;
|
||||
SourceLocation AtLoc, RParenLoc;
|
||||
SourceLocation AtLoc, SelNameLoc, RParenLoc;
|
||||
|
||||
public:
|
||||
ObjCSelectorExpr(QualType T, Selector selInfo, SourceLocation at,
|
||||
SourceLocation rp)
|
||||
SourceLocation selNameLoc, SourceLocation rp)
|
||||
: Expr(ObjCSelectorExprClass, T, VK_PRValue, OK_Ordinary),
|
||||
SelName(selInfo), AtLoc(at), RParenLoc(rp) {
|
||||
SelName(selInfo), AtLoc(at), SelNameLoc(selNameLoc), RParenLoc(rp) {
|
||||
setDependence(ExprDependence::None);
|
||||
}
|
||||
explicit ObjCSelectorExpr(EmptyShell Empty)
|
||||
|
|
@ -501,8 +501,10 @@ public:
|
|||
void setSelector(Selector S) { SelName = S; }
|
||||
|
||||
SourceLocation getAtLoc() const { return AtLoc; }
|
||||
SourceLocation getSelectorNameLoc() const { return SelNameLoc; }
|
||||
SourceLocation getRParenLoc() const { return RParenLoc; }
|
||||
void setAtLoc(SourceLocation L) { AtLoc = L; }
|
||||
void setSelectorNameLoc(SourceLocation L) { SelNameLoc = L; }
|
||||
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
|
||||
|
||||
SourceLocation getBeginLoc() const LLVM_READONLY { return AtLoc; }
|
||||
|
|
|
|||
|
|
@ -2967,7 +2967,40 @@ public:
|
|||
/// #pragma omp atomic update
|
||||
/// \endcode
|
||||
/// In this example directive '#pragma omp atomic' has 'update' clause.
|
||||
/// Also, this class represents 'update' clause in '#pragma omp depobj'
|
||||
class OMPUpdateClause : public OMPClause {
|
||||
public:
|
||||
/// Build 'update' clause.
|
||||
///
|
||||
/// \param StartLoc Starting location of the clause.
|
||||
/// \param EndLoc Ending location of the clause.
|
||||
OMPUpdateClause(SourceLocation StartLoc, SourceLocation EndLoc)
|
||||
: OMPClause(llvm::omp::OMPC_update, StartLoc, EndLoc) {}
|
||||
|
||||
/// Build an empty clause.
|
||||
OMPUpdateClause()
|
||||
: OMPClause(llvm::omp::OMPC_update, SourceLocation(), SourceLocation()) {}
|
||||
|
||||
child_range children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
|
||||
const_child_range children() const {
|
||||
return const_child_range(const_child_iterator(), const_child_iterator());
|
||||
}
|
||||
|
||||
child_range used_children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
const_child_range used_children() const {
|
||||
return const_child_range(const_child_iterator(), const_child_iterator());
|
||||
}
|
||||
|
||||
static bool classof(const OMPClause *T) {
|
||||
return T->getClauseKind() == llvm::omp::OMPC_update;
|
||||
}
|
||||
};
|
||||
|
||||
/// This class represents 'update' clause in '#pragma omp depobj'
|
||||
/// directive.
|
||||
///
|
||||
/// \code
|
||||
|
|
@ -2975,38 +3008,32 @@ public:
|
|||
/// \endcode
|
||||
/// In this example directive '#pragma omp depobj' has 'update' clause with 'in'
|
||||
/// dependence kind.
|
||||
class OMPUpdateClause final
|
||||
class OMPUpdateDependObjectsClause final
|
||||
: public OMPClause,
|
||||
private llvm::TrailingObjects<OMPUpdateClause, SourceLocation,
|
||||
OpenMPDependClauseKind> {
|
||||
private llvm::TrailingObjects<OMPUpdateDependObjectsClause,
|
||||
SourceLocation, OpenMPDependClauseKind> {
|
||||
friend class OMPClauseReader;
|
||||
friend TrailingObjects;
|
||||
|
||||
/// true if extended version of the clause for 'depobj' directive.
|
||||
bool IsExtended = false;
|
||||
|
||||
/// Define the sizes of each trailing object array except the last one. This
|
||||
/// is required for TrailingObjects to work properly.
|
||||
size_t numTrailingObjects(OverloadToken<SourceLocation>) const {
|
||||
// 2 locations: for '(' and argument location.
|
||||
return IsExtended ? 2 : 0;
|
||||
return 2;
|
||||
}
|
||||
|
||||
/// Sets the location of '(' in clause for 'depobj' directive.
|
||||
void setLParenLoc(SourceLocation Loc) {
|
||||
assert(IsExtended && "Expected extended clause.");
|
||||
*getTrailingObjects<SourceLocation>() = Loc;
|
||||
}
|
||||
|
||||
/// Sets the location of '(' in clause for 'depobj' directive.
|
||||
void setArgumentLoc(SourceLocation Loc) {
|
||||
assert(IsExtended && "Expected extended clause.");
|
||||
*std::next(getTrailingObjects<SourceLocation>(), 1) = Loc;
|
||||
}
|
||||
|
||||
/// Sets the dependence kind for the clause for 'depobj' directive.
|
||||
void setDependencyKind(OpenMPDependClauseKind DK) {
|
||||
assert(IsExtended && "Expected extended clause.");
|
||||
*getTrailingObjects<OpenMPDependClauseKind>() = DK;
|
||||
}
|
||||
|
||||
|
|
@ -3014,25 +3041,15 @@ class OMPUpdateClause final
|
|||
///
|
||||
/// \param StartLoc Starting location of the clause.
|
||||
/// \param EndLoc Ending location of the clause.
|
||||
OMPUpdateClause(SourceLocation StartLoc, SourceLocation EndLoc,
|
||||
bool IsExtended)
|
||||
: OMPClause(llvm::omp::OMPC_update, StartLoc, EndLoc),
|
||||
IsExtended(IsExtended) {}
|
||||
OMPUpdateDependObjectsClause(SourceLocation StartLoc, SourceLocation EndLoc)
|
||||
: OMPClause(llvm::omp::OMPC_update_depend_objects, StartLoc, EndLoc) {}
|
||||
|
||||
/// Build an empty clause.
|
||||
OMPUpdateClause(bool IsExtended)
|
||||
: OMPClause(llvm::omp::OMPC_update, SourceLocation(), SourceLocation()),
|
||||
IsExtended(IsExtended) {}
|
||||
OMPUpdateDependObjectsClause()
|
||||
: OMPClause(llvm::omp::OMPC_update_depend_objects, SourceLocation(),
|
||||
SourceLocation()) {}
|
||||
|
||||
public:
|
||||
/// Creates clause for 'atomic' directive.
|
||||
///
|
||||
/// \param C AST context.
|
||||
/// \param StartLoc Starting location of the clause.
|
||||
/// \param EndLoc Ending location of the clause.
|
||||
static OMPUpdateClause *Create(const ASTContext &C, SourceLocation StartLoc,
|
||||
SourceLocation EndLoc);
|
||||
|
||||
/// Creates clause for 'depobj' directive.
|
||||
///
|
||||
/// \param C AST context.
|
||||
|
|
@ -3041,21 +3058,15 @@ public:
|
|||
/// \param ArgumentLoc Location of the argument.
|
||||
/// \param DK Dependence kind.
|
||||
/// \param EndLoc Ending location of the clause.
|
||||
static OMPUpdateClause *Create(const ASTContext &C, SourceLocation StartLoc,
|
||||
SourceLocation LParenLoc,
|
||||
SourceLocation ArgumentLoc,
|
||||
OpenMPDependClauseKind DK,
|
||||
SourceLocation EndLoc);
|
||||
static OMPUpdateDependObjectsClause *
|
||||
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||
SourceLocation ArgumentLoc, OpenMPDependClauseKind DK,
|
||||
SourceLocation EndLoc);
|
||||
|
||||
/// Creates an empty clause with the place for \a N variables.
|
||||
///
|
||||
/// \param C AST context.
|
||||
/// \param IsExtended true if extended clause for 'depobj' directive must be
|
||||
/// created.
|
||||
static OMPUpdateClause *CreateEmpty(const ASTContext &C, bool IsExtended);
|
||||
|
||||
/// Checks if the clause is the extended clauses for 'depobj' directive.
|
||||
bool isExtended() const { return IsExtended; }
|
||||
static OMPUpdateDependObjectsClause *CreateEmpty(const ASTContext &C);
|
||||
|
||||
child_range children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
|
|
@ -3074,24 +3085,21 @@ public:
|
|||
|
||||
/// Gets the location of '(' in clause for 'depobj' directive.
|
||||
SourceLocation getLParenLoc() const {
|
||||
assert(IsExtended && "Expected extended clause.");
|
||||
return *getTrailingObjects<SourceLocation>();
|
||||
}
|
||||
|
||||
/// Gets the location of argument in clause for 'depobj' directive.
|
||||
SourceLocation getArgumentLoc() const {
|
||||
assert(IsExtended && "Expected extended clause.");
|
||||
return *std::next(getTrailingObjects<SourceLocation>(), 1);
|
||||
}
|
||||
|
||||
/// Gets the dependence kind in clause for 'depobj' directive.
|
||||
OpenMPDependClauseKind getDependencyKind() const {
|
||||
assert(IsExtended && "Expected extended clause.");
|
||||
return *getTrailingObjects<OpenMPDependClauseKind>();
|
||||
}
|
||||
|
||||
static bool classof(const OMPClause *T) {
|
||||
return T->getClauseKind() == llvm::omp::OMPC_update;
|
||||
return T->getClauseKind() == llvm::omp::OMPC_update_depend_objects;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -97,6 +97,12 @@ private:
|
|||
/// which is the alignment of the object without virtual bases.
|
||||
CharUnits NonVirtualAlignment;
|
||||
|
||||
/// NonRequiredNVAlignment - The non-virtual alignment (in chars) of an
|
||||
/// object ignoring any over-alignment imposed via `alignas` /
|
||||
/// `__declspec(align)` (i.e. the record's required alignment) on the record
|
||||
/// or its bases.
|
||||
CharUnits NonRequiredNVAlignment;
|
||||
|
||||
/// PreferredNVAlignment - The preferred non-virtual alignment (in chars) of
|
||||
/// an object, which is the preferred alignment of the object without
|
||||
/// virtual bases.
|
||||
|
|
@ -164,6 +170,7 @@ private:
|
|||
CharUnits datasize, ArrayRef<uint64_t> fieldoffsets,
|
||||
CharUnits nonvirtualsize, CharUnits nonvirtualalignment,
|
||||
CharUnits preferrednvalignment,
|
||||
CharUnits nonrequirednvalignment,
|
||||
CharUnits SizeOfLargestEmptySubobject,
|
||||
const CXXRecordDecl *PrimaryBase, bool IsPrimaryBaseVirtual,
|
||||
const CXXRecordDecl *BaseSharingVBPtr,
|
||||
|
|
@ -222,6 +229,15 @@ public:
|
|||
return CXXInfo->NonVirtualAlignment;
|
||||
}
|
||||
|
||||
/// getNonRequiredNVAlignment - Get the non-virtual alignment (in chars) of an
|
||||
/// object ignoring over-alignment imposed via `alignas` / `__declspec(align)`
|
||||
/// on the object or its bases. Only meaningful for the Microsoft ABI.
|
||||
CharUnits getNonRequiredNVAlignment() const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
|
||||
return CXXInfo->NonRequiredNVAlignment;
|
||||
}
|
||||
|
||||
/// getPreferredNVAlignment - Get the preferred non-virtual alignment (in
|
||||
/// chars) of an object, which is the preferred alignment of the object
|
||||
/// without virtual bases.
|
||||
|
|
|
|||
|
|
@ -3710,6 +3710,12 @@ bool RecursiveASTVisitor<Derived>::VisitOMPUpdateClause(OMPUpdateClause *) {
|
|||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPUpdateDependObjectsClause(
|
||||
OMPUpdateDependObjectsClause *) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPCaptureClause(OMPCaptureClause *) {
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@
|
|||
#include "clang/AST/DependenceFlags.h"
|
||||
#include "clang/AST/OperationKinds.h"
|
||||
#include "clang/AST/StmtIterator.h"
|
||||
#include "clang/Basic/BuiltinTraits.h"
|
||||
#include "clang/Basic/CapturedStmt.h"
|
||||
#include "clang/Basic/ExpressionTraits.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "clang/Basic/Lambda.h"
|
||||
|
|
@ -27,7 +27,6 @@
|
|||
#include "clang/Basic/OperatorKinds.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
#include "clang/Basic/TypeTraits.h"
|
||||
#include "llvm/ADT/APFloat.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/BitmaskEnum.h"
|
||||
|
|
|
|||
|
|
@ -74,13 +74,13 @@
|
|||
#include "clang/ASTMatchers/ASTMatchersMacros.h"
|
||||
#include "clang/ASTMatchers/LowLevelHelpers.h"
|
||||
#include "clang/Basic/AttrKinds.h"
|
||||
#include "clang/Basic/BuiltinTraits.h"
|
||||
#include "clang/Basic/ExceptionSpecificationType.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
#include "clang/Basic/TypeTraits.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
|
|
|
|||
|
|
@ -162,6 +162,43 @@ public:
|
|||
size_t param_size() const { return parameters().size(); }
|
||||
bool param_empty() const { return parameters().empty(); }
|
||||
|
||||
/// \returns actual arguments for expression-backed calls, or an empty range
|
||||
/// for declaration-backed calls and call kinds with implicit or synthesized
|
||||
/// argument lists, such as allocators and destructors.
|
||||
ArrayRef<const Expr *> arguments() const {
|
||||
if (!E)
|
||||
return {};
|
||||
|
||||
switch (K) {
|
||||
case Function:
|
||||
case Block: {
|
||||
const auto *CE = cast<CallExpr>(E);
|
||||
return {CE->getArgs(), CE->getNumArgs()};
|
||||
}
|
||||
case ObjCMethod: {
|
||||
const auto *ME = cast<ObjCMessageExpr>(E);
|
||||
return {ME->getArgs(), ME->getNumArgs()};
|
||||
}
|
||||
case Constructor: {
|
||||
const auto *CE = cast<CXXConstructExpr>(E);
|
||||
return {CE->getArgs(), CE->getNumArgs()};
|
||||
}
|
||||
case Destructor:
|
||||
case InheritedConstructor:
|
||||
case Allocator:
|
||||
case Deallocator:
|
||||
return {};
|
||||
}
|
||||
llvm_unreachable("Unknown AnyCall::Kind");
|
||||
}
|
||||
|
||||
using arg_const_iterator = ArrayRef<const Expr *>::const_iterator;
|
||||
arg_const_iterator arg_begin() const { return arguments().begin(); }
|
||||
arg_const_iterator arg_end() const { return arguments().end(); }
|
||||
size_t arg_size() const { return arguments().size(); }
|
||||
bool arg_empty() const { return arguments().empty(); }
|
||||
const Expr *getArg(unsigned I) const { return arguments()[I]; }
|
||||
|
||||
QualType getReturnType(ASTContext &Ctx) const {
|
||||
switch (K) {
|
||||
case Function:
|
||||
|
|
|
|||
|
|
@ -149,6 +149,12 @@ ABI_VER_MAJOR(22)
|
|||
/// This causes clang to:
|
||||
/// - Ignore per-function target attributes when determining the x86 AVX ABI
|
||||
/// level.
|
||||
/// - On MIPS, return a `_Complex` value with an integer element type with one
|
||||
/// part per integer register, instead of packing it into a single register
|
||||
/// where it fits.
|
||||
/// - On MIPS N32/N64, always pass a `_Complex float` or `_Complex double`
|
||||
/// argument as its two parts, one floating-point register each, instead of
|
||||
/// packing it into integer registers once there is no room for both.
|
||||
ABI_VER_MAJOR(23)
|
||||
|
||||
/// Conform to the underlying platform's C and C++ ABIs as closely as we can.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
//===--- TypeTraits.h - C++ Type Traits Support Enumerations ----*- C++ -*-===//
|
||||
//===--- BuiltinTraits.h - C++ Traits Support Enumerations ----*- C++ -*-=====//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// Defines enumerations for the type traits support.
|
||||
/// Defines enumerations for traits support.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
|
@ -38,18 +38,26 @@ namespace clang {
|
|||
// UETT_ ...
|
||||
// UETT_Last == last UETT_XX in the enum.
|
||||
// };
|
||||
|
||||
/// Names for the expression traits.
|
||||
// enum ExpressionTrait {
|
||||
// ET_ ...
|
||||
// ET_Last == last ET_XX in the enum.
|
||||
// };
|
||||
#define EMIT_ENUMS
|
||||
#include "clang/Basic/Traits.inc"
|
||||
|
||||
/// Return the internal name of type trait \p T. Never null.
|
||||
/// Return the internal name of the trait \p T. Never null.
|
||||
const char *getTraitName(TypeTrait T) LLVM_READONLY;
|
||||
const char *getTraitName(ArrayTypeTrait T) LLVM_READONLY;
|
||||
const char *getTraitName(UnaryExprOrTypeTrait T) LLVM_READONLY;
|
||||
const char *getTraitName(ExpressionTrait T) LLVM_READONLY;
|
||||
|
||||
/// Return the spelling of the type trait \p TT. Never null.
|
||||
/// Return the spelling of the trait \p T. Never null.
|
||||
const char *getTraitSpelling(TypeTrait T) LLVM_READONLY;
|
||||
const char *getTraitSpelling(ArrayTypeTrait T) LLVM_READONLY;
|
||||
const char *getTraitSpelling(UnaryExprOrTypeTrait T) LLVM_READONLY;
|
||||
const char *getTraitSpelling(ExpressionTrait T) LLVM_READONLY;
|
||||
|
||||
/// Return the arity of the type trait \p T.
|
||||
unsigned getTypeTraitArity(TypeTrait T) LLVM_READONLY;
|
||||
|
|
@ -5545,6 +5545,12 @@ def HLSLInterlockedOr : LangBuiltin<"HLSL_LANG"> {
|
|||
let Prototype = "void (...)";
|
||||
}
|
||||
|
||||
def HLSLInterlockedXor : LangBuiltin<"HLSL_LANG"> {
|
||||
let Spellings = ["__builtin_hlsl_interlocked_xor"];
|
||||
let Attributes = [NoThrow];
|
||||
let Prototype = "void (...)";
|
||||
}
|
||||
|
||||
def HLSLWaveActiveBallot : LangBuiltin<"HLSL_LANG"> {
|
||||
let Spellings = ["__builtin_hlsl_wave_active_ballot"];
|
||||
let Attributes = [NoThrow, Const];
|
||||
|
|
@ -5647,18 +5653,6 @@ def HLSLClamp : LangBuiltin<"HLSL_LANG"> {
|
|||
let Prototype = "void(...)";
|
||||
}
|
||||
|
||||
def HLSLCrossFloat: LangBuiltin<"HLSL_LANG"> {
|
||||
let Spellings = ["__builtin_hlsl_crossf32"];
|
||||
let Attributes = [NoThrow, Const];
|
||||
let Prototype = "_ExtVector<3, float>(_ExtVector<3, float>, _ExtVector<3, float>)";
|
||||
}
|
||||
|
||||
def HLSLCrossHalf: LangBuiltin<"HLSL_LANG"> {
|
||||
let Spellings = ["__builtin_hlsl_crossf16"];
|
||||
let Attributes = [NoThrow, Const];
|
||||
let Prototype = "_ExtVector<3, __fp16>(_ExtVector<3, __fp16>, _ExtVector<3, __fp16>)";
|
||||
}
|
||||
|
||||
def HLSLDegrees : LangBuiltin<"HLSL_LANG"> {
|
||||
let Spellings = ["__builtin_hlsl_elementwise_degrees"];
|
||||
let Attributes = [NoThrow, Const, CustomTypeChecking];
|
||||
|
|
|
|||
|
|
@ -761,8 +761,12 @@ def __builtin_amdgcn_s_barrier_join : AMDGPUBuiltin<"void(void *)", [], "gfx12-i
|
|||
def __builtin_amdgcn_s_barrier_leave : AMDGPUBuiltin<"void(_Constant short)", [], "gfx12-insts">;
|
||||
def __builtin_amdgcn_s_get_barrier_state : AMDGPUBuiltin<"unsigned int(int)", [], "gfx12-insts">;
|
||||
def __builtin_amdgcn_s_get_named_barrier_state : AMDGPUBuiltin<"unsigned int(void *)", [], "gfx12-insts">;
|
||||
def __builtin_amdgcn_s_prefetch_data : AMDGPUBuiltin<"void(void const *, unsigned int)", [Const], "gfx12-insts">;
|
||||
def __builtin_amdgcn_s_buffer_prefetch_data : AMDGPUBuiltin<"void(__amdgpu_buffer_rsrc_t, _Constant int, unsigned int)", [Const], "gfx12-insts">;
|
||||
def __builtin_amdgcn_s_prefetch_data : AMDGPUBuiltin<"void(void const *, unsigned int)", [Const], "smem-prefetch-insts">;
|
||||
def __builtin_amdgcn_s_prefetch_inst : AMDGPUBuiltin<"void(void const *, unsigned int)", [Const], "smem-prefetch-insts"> {
|
||||
let Documentation = [DocPrefetchInst_GFX12];
|
||||
let ArgNames = ["ptr", "len"];
|
||||
}
|
||||
def __builtin_amdgcn_s_buffer_prefetch_data : AMDGPUBuiltin<"void(__amdgpu_buffer_rsrc_t, _Constant int, unsigned int)", [Const], "smem-prefetch-insts">;
|
||||
|
||||
def __builtin_amdgcn_global_load_tr_b64_v2i32 : AMDGPUBuiltin<"_ExtVector<2, int>(_ExtVector<2, int> address_space<1> *)", [Const], "gfx12-insts,wavefrontsize32">;
|
||||
def __builtin_amdgcn_global_load_tr_b128_v8i16 : AMDGPUBuiltin<"_ExtVector<8, short>(_ExtVector<8, short> address_space<1> *)", [Const], "gfx12-insts,wavefrontsize32">;
|
||||
|
|
@ -1047,7 +1051,7 @@ def __builtin_amdgcn_exp2_bf16 : AMDGPUBuiltin<"__bf16(__bf16)", [Const], "bf16-
|
|||
def __builtin_amdgcn_sin_bf16 : AMDGPUBuiltin<"__bf16(__bf16)", [Const], "bf16-trans-insts">;
|
||||
def __builtin_amdgcn_cos_bf16 : AMDGPUBuiltin<"__bf16(__bf16)", [Const], "bf16-trans-insts">;
|
||||
|
||||
def __builtin_amdgcn_cvt_sr_pk_bf16_f32 : AMDGPUBuiltin<"_ExtVector<2, __bf16>(float, float, int)", [Const], "bf16-cvt-insts">;
|
||||
def __builtin_amdgcn_cvt_sr_pk_bf16_f32 : AMDGPUBuiltin<"_ExtVector<2, __bf16>(float, float, int)", [Const], "cvt-sr-pk-bf16-f32-inst">;
|
||||
def __builtin_amdgcn_cvt_sr_pk_f16_f32 : AMDGPUBuiltin<"_ExtVector<2, _Float16>(float, float, int)", [Const], "gfx1250-insts">;
|
||||
def __builtin_amdgcn_cvt_f16_fp8 : AMDGPUBuiltin<"_Float16(int, _Constant int)", [Const], "gfx1250-insts">;
|
||||
def __builtin_amdgcn_cvt_f16_bf8 : AMDGPUBuiltin<"_Float16(int, _Constant int)", [Const], "gfx1250-insts">;
|
||||
|
|
|
|||
|
|
@ -78,6 +78,13 @@ between standard floating-point types, integer types and packed low-precision fo
|
|||
}];
|
||||
}
|
||||
|
||||
def DocCatAMDGPUPrefetch : DocumentationCategory<"Prefetch Builtins"> {
|
||||
let Content = [{
|
||||
These builtins provide access to AMDGPU prefetch instructions, including instructions
|
||||
for prefetching data and instructions.
|
||||
}];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ABI / Special Register Builtins — Documentation records
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
@ -725,7 +732,7 @@ value gives an undefined result.
|
|||
|
||||
def DocCatSBufferLoad : DocumentationCategory<"S-Buffer Load Builtins"> {
|
||||
let Content = [{
|
||||
These builtins lower to ``llvm.amdgcn.s.buffer.load`` and issue an
|
||||
These builtins lower to ``llvm.amdgcn.ptr.s.buffer.load`` and issue an
|
||||
``s_buffer_load`` when the byte offset is uniform across the wavefront.
|
||||
When the offset is divergent, the backend may lower to a ``buffer_load``.
|
||||
|
||||
|
|
@ -742,8 +749,7 @@ When the offset is divergent, the backend may lower to a ``buffer_load``.
|
|||
|
||||
These builtins take the buffer resource as ``__amdgpu_buffer_rsrc_t``, which
|
||||
can be created with ``__builtin_amdgcn_make_buffer_rsrc``. The backend
|
||||
lowers the resource to the 4-dword SGPR descriptor required by
|
||||
``llvm.amdgcn.s.buffer.load``.
|
||||
lowers the resource to the 4-dword SGPR descriptor required by the instruction.
|
||||
|
||||
The return type selects the load width. Separate builtins are provided for
|
||||
each supported scalar and vector element type.
|
||||
|
|
@ -793,3 +799,16 @@ using the scale factor ``scale``, then converts the values to a packed
|
|||
integers.
|
||||
}];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Prefetch Builtins
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def DocPrefetchInst_GFX12 : Documentation {
|
||||
let Category = DocCatAMDGPUPrefetch;
|
||||
let Content = [{
|
||||
Prefetch instructions into I-Cache from the address given by ``ptr`` pointing
|
||||
to instruction memory, with the length specified by ``len``, which should be
|
||||
0-31 (1-32 chunks, units of 128 bytes).
|
||||
}];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -584,6 +584,17 @@ private:
|
|||
DiagSuppressionMapping;
|
||||
|
||||
public:
|
||||
/// Returns a cache key representing the diagnostic state at \p Loc.
|
||||
const void *getDiagStateKeyForLoc(SourceLocation Loc) const {
|
||||
return GetDiagStateForLoc(Loc);
|
||||
}
|
||||
|
||||
/// True if an active diagnostic suppression mapping makes severity dependent
|
||||
/// on the file path.
|
||||
bool hasDiagSuppressionMapping() const {
|
||||
return static_cast<bool>(DiagSuppressionMapping);
|
||||
}
|
||||
|
||||
explicit DiagnosticsEngine(IntrusiveRefCntPtr<DiagnosticIDs> Diags,
|
||||
DiagnosticOptions &DiagOpts,
|
||||
DiagnosticConsumer *client = nullptr,
|
||||
|
|
@ -1113,6 +1124,22 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// RAII class that temporarily sets the "ignore all warnings" state on a
|
||||
/// DiagnosticsEngine and restores the previous state on destruction. Use it to
|
||||
/// silence warnings around a self-contained region of diagnostics, such as a
|
||||
/// compiler-synthesized call whose arguments are known to be correct.
|
||||
class IgnoreAllWarningDiagRAII {
|
||||
DiagnosticsEngine &Diag;
|
||||
bool OldValue;
|
||||
|
||||
public:
|
||||
explicit IgnoreAllWarningDiagRAII(DiagnosticsEngine &Diag)
|
||||
: Diag(Diag), OldValue(Diag.getIgnoreAllWarnings()) {
|
||||
Diag.setIgnoreAllWarnings(true);
|
||||
}
|
||||
~IgnoreAllWarningDiagRAII() { Diag.setIgnoreAllWarnings(OldValue); }
|
||||
};
|
||||
|
||||
/// The streaming interface shared between DiagnosticBuilder and
|
||||
/// PartialDiagnostic. This class is not intended to be constructed directly
|
||||
/// but only as base class of DiagnosticBuilder and PartialDiagnostic builder.
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ def note_constexpr_depth_limit_exceeded : Note<
|
|||
def note_constexpr_call_limit_exceeded : Note<
|
||||
"constexpr evaluation hit maximum call limit">;
|
||||
def note_constexpr_step_limit_exceeded : Note<
|
||||
"constexpr evaluation hit maximum step limit; possible infinite loop?">;
|
||||
"constexpr evaluation hit maximum step limit of %0; possible infinite loop?">;
|
||||
def note_constexpr_heap_alloc_limit_exceeded : Note<
|
||||
"constexpr evaluation hit maximum heap allocation limit">;
|
||||
def note_constexpr_this : Note<
|
||||
|
|
@ -355,8 +355,9 @@ def note_constexpr_new_negative : Note<
|
|||
def note_constexpr_new_too_large : Note<
|
||||
"cannot allocate array; evaluated array bound %0 is too large">;
|
||||
def note_constexpr_new_exceeds_limits : Note<
|
||||
"cannot allocate array; evaluated array bound %0 exceeds the limit (%1); "
|
||||
"use '-fconstexpr-steps' to increase this limit">;
|
||||
"cannot allocate array; evaluated array bound %0 exceeds the limit (%1)">;
|
||||
def note_constexpr_steps : Note<
|
||||
"use -fconstexpr-steps= to increase this limit (=0 will remove the limit)">;
|
||||
def note_constexpr_new_too_small : Note<
|
||||
"cannot allocate array; evaluated array bound %0 is too small to hold "
|
||||
"%1 explicitly initialized elements">;
|
||||
|
|
|
|||
|
|
@ -455,6 +455,8 @@ def warn_omp_gpu_unsupported_clause: Warning<
|
|||
def warn_omp_gpu_unsupported_modifier_for_clause: Warning<
|
||||
"modifier '%0' is currently not supported on a GPU for the '%1' clause; modifier ignored">,
|
||||
InGroup<OpenMPClauses>;
|
||||
def err_omp_unified_shared_memory_unsupported : Error<
|
||||
"target architecture '%0' does not support unified addressing">;
|
||||
|
||||
// Static Analyzer Core
|
||||
def err_unknown_analyzer_checker_or_package : Error<
|
||||
|
|
|
|||
|
|
@ -145,6 +145,8 @@ def warn_utf8_symbol_homoglyph : Warning<
|
|||
def warn_utf8_symbol_zero_width : Warning<
|
||||
"identifier contains character %0 that is invisible in "
|
||||
"some environments">, InGroup<DiagGroup<"unicode-zero-width">>;
|
||||
defm mathematical_notation : CXX29Compat<
|
||||
"mathematical notation character %0 in an identifier is">;
|
||||
def ext_mathematical_notation : ExtWarn<
|
||||
"mathematical notation character %0 in an identifier is a Clang extension">,
|
||||
InGroup<DiagGroup<"mathematical-notation-identifier-extension">>;
|
||||
|
|
@ -864,6 +866,13 @@ def err_pp_include_in_arc_cf_code_audited : Error<
|
|||
def err_pp_eof_in_arc_cf_code_audited : Error<
|
||||
"'#pragma clang arc_cf_code_audited' was not ended within this file">;
|
||||
|
||||
def err_pp_pragma_set_pp_state_expected_name : Error<
|
||||
"expected identifier after '#pragma clang __set_pp_state'">;
|
||||
def err_pp_pragma_set_pp_state_expected_int_after : Error<
|
||||
"expected integer after '#pragma clang __set_pp_state %0'">;
|
||||
def err_pp_pragma_set_pp_state_invalid_arg : Error<
|
||||
"invalid argument %0 in '#pragma clang __set_pp_state'">;
|
||||
|
||||
def warn_pp_date_time : Warning<
|
||||
"expansion of date or time macro is not reproducible">,
|
||||
ShowInSystemHeader, DefaultIgnore, InGroup<DiagGroup<"date-time">>;
|
||||
|
|
|
|||
|
|
@ -4350,7 +4350,7 @@ def warn_thread_attribute_decl_not_pointer : Warning<
|
|||
InGroup<ThreadSafetyAttributes>, DefaultIgnore;
|
||||
def warn_thread_attribute_not_on_scoped_lockable_param : Warning<
|
||||
"%0 attribute applies to function parameters only if their type is a "
|
||||
"reference to a 'scoped_lockable'-annotated type">,
|
||||
"function pointer or a reference to a 'scoped_lockable'-annotated type">,
|
||||
InGroup<ThreadSafetyAttributes>, DefaultIgnore;
|
||||
def warn_thread_attribute_requires_preceded : Warning<
|
||||
"%0 attribute on %1 must be preceded by %2 attribute">,
|
||||
|
|
@ -13852,6 +13852,11 @@ def warn_hlsl_assigning_local_resource_is_not_unique
|
|||
|
||||
def err_hlsl_push_constant_unique
|
||||
: Error<"cannot have more than one push constant block">;
|
||||
def err_hlsl_sample_double_element_type
|
||||
: Error<"'%0' is not supported for resources containing %1">;
|
||||
def err_hlsl_sample_integer_element_type
|
||||
: Error<"'%0' on resources containing %1 requires shader model 6.7 or "
|
||||
"newer; the target shader model is %2">;
|
||||
def err_hlsl_samplecmp_requires_float
|
||||
: Error<"'SampleCmp' and 'SampleCmpLevelZero' require resource to contain "
|
||||
"a floating point type">;
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
//===- ExpressionTraits.h - C++ Expression Traits Support Enums -*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// Defines enumerations for expression traits intrinsics.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_BASIC_EXPRESSIONTRAITS_H
|
||||
#define LLVM_CLANG_BASIC_EXPRESSIONTRAITS_H
|
||||
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
enum ExpressionTrait {
|
||||
#define EXPRESSION_TRAIT(Spelling, Name, Key) ET_##Name,
|
||||
#include "clang/Basic/Traits.inc"
|
||||
ET_Last = -1 // ET_Last == last ET_XX in the enum.
|
||||
#define EXPRESSION_TRAIT(Spelling, Name, Key) +1
|
||||
#include "clang/Basic/Traits.inc"
|
||||
};
|
||||
|
||||
/// Return the internal name of type trait \p T. Never null.
|
||||
const char *getTraitName(ExpressionTrait T) LLVM_READONLY;
|
||||
|
||||
/// Return the spelling of the type trait \p TT. Never null.
|
||||
const char *getTraitSpelling(ExpressionTrait T) LLVM_READONLY;
|
||||
|
||||
} // namespace clang
|
||||
|
||||
#endif
|
||||
|
|
@ -554,30 +554,6 @@ def hlsl_countbits : HLSLBuiltin<"countbits"> {
|
|||
let VaryingVecSizes = [2, 3, 4];
|
||||
}
|
||||
|
||||
// Returns the cross product of two floating-point, 3D vectors.
|
||||
def hlsl_cross_float : HLSLBuiltin<"cross", "__builtin_hlsl_crossf32"> {
|
||||
let Args = [VectorType<FloatTy, 3>, VectorType<FloatTy, 3>];
|
||||
let ReturnType = VectorType<FloatTy, 3>;
|
||||
}
|
||||
|
||||
def hlsl_cross_half : HLSLBuiltin<"cross", "__builtin_hlsl_crossf16"> {
|
||||
let Doc = [{
|
||||
\fn T cross(T x, T y)
|
||||
\brief Returns the cross product of two floating-point, 3D vectors.
|
||||
\param x [in] The first floating-point, 3D vector.
|
||||
\param y [in] The second floating-point, 3D vector.
|
||||
|
||||
Result is the cross product of x and y, i.e., the resulting
|
||||
components are, in order :
|
||||
x[1] * y[2] - y[1] * x[2]
|
||||
x[2] * y[0] - y[2] * x[0]
|
||||
x[0] * y[1] - y[0] * x[1]
|
||||
}];
|
||||
let Args = [VectorType<HalfTy, 3>, VectorType<HalfTy, 3>];
|
||||
let ReturnType = VectorType<HalfTy, 3>;
|
||||
let Availability = SM6_2;
|
||||
}
|
||||
|
||||
// Converts a floating-point, 4D vector set by a D3DCOLOR to a UBYTE4.
|
||||
def hlsl_d3d_color_to_ubyte4 : HLSLBuiltin<"D3DCOLORtoUBYTE4"> {
|
||||
let Doc = [{
|
||||
|
|
@ -708,6 +684,27 @@ def hlsl_degrees : HLSLOneArgBuiltin<"degrees", "__builtin_hlsl_elementwise_degr
|
|||
let VaryingTypes = [HalfTy, FloatTy];
|
||||
let VaryingMatDims = [];
|
||||
}
|
||||
// Returns the cross product of two floating-point, 3D vectors.
|
||||
def hlsl_cross : HLSLTwoArgDetail<"cross", "cross_impl"> {
|
||||
let Doc = [{
|
||||
\fn T cross(T x, T y)
|
||||
\brief Returns the cross product of two floating-point, 3D vectors.
|
||||
\param x [in] The first floating-point, 3D vector.
|
||||
\param y [in] The second floating-point, 3D vector.
|
||||
|
||||
Result is the cross product of x and y, i.e., the resulting
|
||||
components are, in order :
|
||||
x[1] * y[2] - y[1] * x[2]
|
||||
x[2] * y[0] - y[2] * x[0]
|
||||
x[0] * y[1] - y[0] * x[1]
|
||||
}];
|
||||
let ParamNames = ["x", "y"];
|
||||
let VaryingTypes = [HalfTy, FloatTy];
|
||||
let VaryingScalar = 0;
|
||||
let VaryingVecSizes = [3];
|
||||
let VaryingMatDims = [];
|
||||
let IsConstexpr = 1;
|
||||
}
|
||||
|
||||
// Returns a distance scalar between X and Y.
|
||||
// The distance between X and Y is length(X - Y).
|
||||
|
|
|
|||
|
|
@ -10,161 +10,121 @@
|
|||
#define LLVM_CLANG_BASIC_OFFLOADARCH_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include <cstdint>
|
||||
#include <tuple>
|
||||
|
||||
namespace llvm {
|
||||
class Triple;
|
||||
template <typename T> class SmallVectorImpl;
|
||||
namespace NVPTX {
|
||||
enum GPUKind : uint8_t;
|
||||
}
|
||||
namespace AMDGPU {
|
||||
enum GPUKind : uint8_t;
|
||||
}
|
||||
} // namespace llvm
|
||||
|
||||
namespace clang {
|
||||
|
||||
enum class OffloadArch {
|
||||
Unused,
|
||||
Unknown,
|
||||
// TODO: Deprecate and remove GPU architectures older than sm_52.
|
||||
SM_20,
|
||||
SM_21,
|
||||
SM_30,
|
||||
// This has a name conflict with sys/mac.h on AIX, rename it as a workaround.
|
||||
SM_32_,
|
||||
SM_35,
|
||||
SM_37,
|
||||
SM_50,
|
||||
SM_52,
|
||||
SM_53,
|
||||
SM_60,
|
||||
SM_61,
|
||||
SM_62,
|
||||
SM_70,
|
||||
SM_72,
|
||||
SM_75,
|
||||
SM_80,
|
||||
SM_86,
|
||||
SM_87,
|
||||
SM_88,
|
||||
SM_89,
|
||||
SM_90,
|
||||
SM_90a,
|
||||
SM_100,
|
||||
SM_100a,
|
||||
SM_100f,
|
||||
SM_101,
|
||||
SM_101a,
|
||||
SM_101f,
|
||||
SM_103,
|
||||
SM_103a,
|
||||
SM_103f,
|
||||
SM_110,
|
||||
SM_110a,
|
||||
SM_110f,
|
||||
SM_120,
|
||||
SM_120a,
|
||||
SM_120f,
|
||||
SM_121,
|
||||
SM_121a,
|
||||
SM_121f,
|
||||
GFX600,
|
||||
GFX601,
|
||||
GFX602,
|
||||
GFX700,
|
||||
GFX701,
|
||||
GFX702,
|
||||
GFX703,
|
||||
GFX704,
|
||||
GFX705,
|
||||
GFX801,
|
||||
GFX802,
|
||||
GFX803,
|
||||
GFX805,
|
||||
GFX810,
|
||||
GFX9_GENERIC,
|
||||
GFX900,
|
||||
GFX902,
|
||||
GFX904,
|
||||
GFX906,
|
||||
GFX908,
|
||||
GFX909,
|
||||
GFX90a,
|
||||
GFX90c,
|
||||
GFX9_4_GENERIC,
|
||||
GFX942,
|
||||
GFX950,
|
||||
GFX10_1_GENERIC,
|
||||
GFX1010,
|
||||
GFX1011,
|
||||
GFX1012,
|
||||
GFX1013,
|
||||
GFX10_3_GENERIC,
|
||||
GFX1030,
|
||||
GFX1031,
|
||||
GFX1032,
|
||||
GFX1033,
|
||||
GFX1034,
|
||||
GFX1035,
|
||||
GFX1036,
|
||||
GFX11_GENERIC,
|
||||
GFX1100,
|
||||
GFX1101,
|
||||
GFX1102,
|
||||
GFX1103,
|
||||
GFX1150,
|
||||
GFX1151,
|
||||
GFX1152,
|
||||
GFX1153,
|
||||
GFX1154,
|
||||
GFX11_7_GENERIC,
|
||||
GFX1170,
|
||||
GFX1171,
|
||||
GFX1172,
|
||||
GFX12_GENERIC,
|
||||
GFX1200,
|
||||
GFX1201,
|
||||
GFX12_5_GENERIC,
|
||||
GFX1250,
|
||||
GFX1251,
|
||||
GFX13_GENERIC,
|
||||
GFX1310,
|
||||
AMDGCNSPIRV,
|
||||
Generic, // A processor model named 'generic' if the target backend defines a
|
||||
// public one.
|
||||
// Intel CPUs
|
||||
GRANITERAPIDS,
|
||||
// Intel GPUs
|
||||
BMG_G21,
|
||||
LAST = BMG_G21,
|
||||
/// A processor an offloading action can target. This is a tagged handle pairing
|
||||
/// a TargetArch with the matching TargetParser GPU kind; it does not enumerate
|
||||
/// individual GPUs, so new targets are added in the TargetParser data alone.
|
||||
class OffloadArch {
|
||||
public:
|
||||
enum class TargetArch : uint8_t {
|
||||
Unused, // Default-constructed; no architecture bound.
|
||||
Unknown, // A name that matched no known architecture.
|
||||
NVPTX, // Kind is an llvm::NVPTX::GPUKind.
|
||||
AMDGPU, // Kind is an llvm::AMDGPU::GPUKind.
|
||||
SPIRV, // The 'amdgcnspirv' pseudo target.
|
||||
IntelCPU, // Kind is an IntelArch.
|
||||
IntelGPU, // Kind is an IntelArch.
|
||||
Generic, // The 'generic' processor model.
|
||||
};
|
||||
|
||||
CudaDefault = OffloadArch::SM_52,
|
||||
HIPDefault = OffloadArch::GFX906,
|
||||
// Intel architectures, which have no TargetParser list yet.
|
||||
enum class IntelArch : uint32_t {
|
||||
GRANITERAPIDS,
|
||||
BMG_G21,
|
||||
};
|
||||
|
||||
private:
|
||||
// Interpreted according to V; unused for the tagless TargetArch values.
|
||||
uint32_t Kind = 0;
|
||||
TargetArch V = TargetArch::Unused;
|
||||
|
||||
constexpr OffloadArch(TargetArch V, uint32_t Kind) : Kind(Kind), V(V) {}
|
||||
|
||||
public:
|
||||
constexpr OffloadArch() = default;
|
||||
|
||||
static OffloadArch getNVPTX(llvm::NVPTX::GPUKind K) {
|
||||
return {TargetArch::NVPTX, static_cast<uint32_t>(K)};
|
||||
}
|
||||
static OffloadArch getAMDGPU(llvm::AMDGPU::GPUKind K) {
|
||||
return {TargetArch::AMDGPU, static_cast<uint32_t>(K)};
|
||||
}
|
||||
static constexpr OffloadArch getIntel(TargetArch V, IntelArch A) {
|
||||
return {V, static_cast<uint32_t>(A)};
|
||||
}
|
||||
static constexpr OffloadArch getUnused() { return {TargetArch::Unused, 0}; }
|
||||
static constexpr OffloadArch getUnknown() { return {TargetArch::Unknown, 0}; }
|
||||
static constexpr OffloadArch getSPIRV() { return {TargetArch::SPIRV, 0}; }
|
||||
static constexpr OffloadArch getGeneric() { return {TargetArch::Generic, 0}; }
|
||||
|
||||
/// Default architectures used when the user does not specify one.
|
||||
static OffloadArch CudaDefault();
|
||||
static OffloadArch HIPDefault();
|
||||
|
||||
TargetArch targetArch() const { return V; }
|
||||
|
||||
bool isNVPTX() const { return V == TargetArch::NVPTX; }
|
||||
bool isAMDGPU() const { return V == TargetArch::AMDGPU; }
|
||||
bool isSPIRV() const { return V == TargetArch::SPIRV; }
|
||||
bool isIntelCPU() const { return V == TargetArch::IntelCPU; }
|
||||
bool isIntelGPU() const { return V == TargetArch::IntelGPU; }
|
||||
bool isIntel() const { return isIntelCPU() || isIntelGPU(); }
|
||||
bool isGeneric() const { return V == TargetArch::Generic; }
|
||||
bool isUnused() const { return V == TargetArch::Unused; }
|
||||
bool isUnknown() const { return V == TargetArch::Unknown; }
|
||||
|
||||
// Only valid when isNVPTX() / isAMDGPU() respectively.
|
||||
llvm::NVPTX::GPUKind nvptxKind() const {
|
||||
return static_cast<llvm::NVPTX::GPUKind>(Kind);
|
||||
}
|
||||
llvm::AMDGPU::GPUKind amdgpuKind() const {
|
||||
return static_cast<llvm::AMDGPU::GPUKind>(Kind);
|
||||
}
|
||||
|
||||
bool operator==(const OffloadArch &Other) const {
|
||||
return V == Other.V && Kind == Other.Kind;
|
||||
}
|
||||
bool operator!=(const OffloadArch &Other) const { return !(*this == Other); }
|
||||
|
||||
bool operator<(const OffloadArch &Other) const {
|
||||
return std::tie(V, Kind) < std::tie(Other.V, Other.Kind);
|
||||
}
|
||||
};
|
||||
|
||||
static inline bool IsNVIDIAOffloadArch(OffloadArch A) {
|
||||
return A >= OffloadArch::SM_20 && A < OffloadArch::GFX600;
|
||||
}
|
||||
|
||||
static inline bool IsAMDOffloadArch(OffloadArch A) {
|
||||
// Generic processor model is for testing only.
|
||||
return A >= OffloadArch::GFX600 && A < OffloadArch::Generic;
|
||||
}
|
||||
|
||||
static inline bool IsIntelCPUOffloadArch(OffloadArch Arch) {
|
||||
return Arch >= OffloadArch::GRANITERAPIDS && Arch < OffloadArch::BMG_G21;
|
||||
}
|
||||
|
||||
static inline bool IsIntelGPUOffloadArch(OffloadArch Arch) {
|
||||
return Arch >= OffloadArch::BMG_G21 && Arch <= OffloadArch::LAST;
|
||||
}
|
||||
|
||||
static inline bool IsIntelOffloadArch(OffloadArch Arch) {
|
||||
return IsIntelCPUOffloadArch(Arch) || IsIntelGPUOffloadArch(Arch);
|
||||
inline bool IsNVIDIAOffloadArch(OffloadArch A) { return A.isNVPTX(); }
|
||||
inline bool IsAMDOffloadArch(OffloadArch A) {
|
||||
// amdgcnspirv is compiled through the AMDGPU toolchain.
|
||||
return A.isAMDGPU() || A.isSPIRV();
|
||||
}
|
||||
inline bool IsIntelCPUOffloadArch(OffloadArch A) { return A.isIntelCPU(); }
|
||||
inline bool IsIntelGPUOffloadArch(OffloadArch A) { return A.isIntelGPU(); }
|
||||
inline bool IsIntelOffloadArch(OffloadArch A) { return A.isIntel(); }
|
||||
|
||||
const char *OffloadArchToString(OffloadArch A);
|
||||
const char *OffloadArchToVirtualArchString(OffloadArch A);
|
||||
|
||||
// Convert a string to an OffloadArch enum value. Returns
|
||||
// OffloadArch::Unknown if the string is not recognized.
|
||||
// Convert a string to an OffloadArch. Returns an Unknown OffloadArch if the
|
||||
// string is not recognized.
|
||||
OffloadArch StringToOffloadArch(llvm::StringRef S);
|
||||
|
||||
/// Append the canonical names of all NVIDIA and AMDGPU GPUs.
|
||||
void fillValidOffloadArchList(llvm::SmallVectorImpl<llvm::StringRef> &Values);
|
||||
|
||||
llvm::Triple OffloadArchToTriple(const llvm::Triple &DefaultToolchainTriple,
|
||||
OffloadArch ID);
|
||||
|
||||
|
|
@ -173,19 +133,19 @@ llvm::Triple OffloadArchToTriple(const llvm::Triple &DefaultToolchainTriple,
|
|||
struct BoundArch {
|
||||
llvm::StringRef ArchName;
|
||||
|
||||
/// The parsed offload architecture enum.
|
||||
/// Will be OffloadArch::Unknown if ArchName not recognized.
|
||||
OffloadArch Arch = OffloadArch::Unused;
|
||||
/// The parsed offload architecture.
|
||||
/// Will be an Unknown OffloadArch if ArchName is not recognized.
|
||||
OffloadArch Arch = OffloadArch::getUnused();
|
||||
|
||||
BoundArch() = default;
|
||||
explicit BoundArch(llvm::StringRef Name)
|
||||
: ArchName(Name),
|
||||
Arch(Name.empty() ? OffloadArch::Unknown : StringToOffloadArch(Name)) {}
|
||||
: ArchName(Name), Arch(Name.empty() ? OffloadArch::getUnknown()
|
||||
: StringToOffloadArch(Name)) {}
|
||||
|
||||
BoundArch(llvm::StringRef Name, OffloadArch A) : ArchName(Name), Arch(A) {}
|
||||
|
||||
bool empty() const { return ArchName.empty(); }
|
||||
explicit operator bool() const { return Arch != OffloadArch::Unused; }
|
||||
explicit operator bool() const { return !Arch.isUnused(); }
|
||||
|
||||
bool operator==(const BoundArch &Other) const {
|
||||
return Arch == Other.Arch && ArchName == Other.ArchName;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,9 @@ template <class T> struct OptionalUnsigned {
|
|||
OptionalUnsigned(T Val) : Rep(static_cast<underlying_type>(Val) + 1) {
|
||||
assert(has_value());
|
||||
}
|
||||
OptionalUnsigned(int) = delete;
|
||||
|
||||
template <class U, std::enable_if_t<std::is_signed_v<U>, bool> = false>
|
||||
OptionalUnsigned(U) = delete;
|
||||
|
||||
constexpr static OptionalUnsigned
|
||||
fromInternalRepresentation(underlying_type Rep) {
|
||||
|
|
|
|||
|
|
@ -23,40 +23,8 @@ namespace clang {
|
|||
|
||||
/// Constants for TokenKinds.def
|
||||
enum TokenKey : unsigned {
|
||||
KEYC99 = 0x1,
|
||||
KEYCXX = 0x2,
|
||||
KEYCXX11 = 0x4,
|
||||
KEYGNU = 0x8,
|
||||
KEYMS = 0x10,
|
||||
BOOLSUPPORT = 0x20,
|
||||
KEYALTIVEC = 0x40,
|
||||
KEYNOCXX = 0x80,
|
||||
KEYBORLAND = 0x100,
|
||||
KEYOPENCLC = 0x200,
|
||||
KEYC23 = 0x400,
|
||||
KEYNOMS18 = 0x800,
|
||||
KEYNOOPENCL = 0x1000,
|
||||
WCHARSUPPORT = 0x2000,
|
||||
HALFSUPPORT = 0x4000,
|
||||
CHAR8SUPPORT = 0x8000,
|
||||
KEYOBJC = 0x10000,
|
||||
KEYZVECTOR = 0x20000,
|
||||
KEYCOROUTINES = 0x40000,
|
||||
KEYMODULES = 0x80000,
|
||||
KEYCXX20 = 0x100000,
|
||||
KEYOPENCLCXX = 0x200000,
|
||||
KEYMSCOMPAT = 0x400000,
|
||||
KEYSYCL = 0x800000,
|
||||
KEYCUDA = 0x1000000,
|
||||
KEYZOS = 0x2000000,
|
||||
KEYHLSL = 0x4000000,
|
||||
KEYFIXEDPOINT = 0x8000000,
|
||||
KEYDEFERTS = 0x10000000,
|
||||
KEYNOHLSL = 0x20000000,
|
||||
KEYMAX = KEYNOHLSL, // The maximum key
|
||||
KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20,
|
||||
KEYALL = (KEYMAX | (KEYMAX - 1)) & ~KEYNOMS18 & ~KEYNOOPENCL &
|
||||
~KEYNOHLSL // KEYNOMS18, KEYNOOPENCL, KEYNOHLSL excluded.
|
||||
#define EMIT_TOKENKEY
|
||||
#include "clang/Basic/Traits.inc"
|
||||
};
|
||||
|
||||
namespace tok {
|
||||
|
|
|
|||
34
clang/include/clang/CIR/CIRDataLayoutSpec.h
Normal file
34
clang/include/clang/CIR/CIRDataLayoutSpec.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
//===-- CIRDataLayoutSpec.h - DLTI data layout for CIR modules --*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares a helper that attaches the DLTI data-layout spec,
|
||||
// including the CIR-native pointer entry, to a CIR module.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef CLANG_CIR_CIRDATALAYOUTSPEC_H
|
||||
#define CLANG_CIR_CIRDATALAYOUTSPEC_H
|
||||
|
||||
namespace llvm {
|
||||
class DataLayout;
|
||||
} // namespace llvm
|
||||
|
||||
namespace mlir {
|
||||
class ModuleOp;
|
||||
} // namespace mlir
|
||||
|
||||
namespace cir {
|
||||
|
||||
/// Translate \p dl into a DLTI data-layout spec and attach it to \p mod.
|
||||
/// On top of the plain mlir::translateDataLayout entries this adds a
|
||||
/// #cir.ptr_spec entry keyed on !cir.ptr, which CIR pointer types read for
|
||||
/// their size and alignment; without it pointer widths default to 64 bits.
|
||||
void setMLIRDataLayout(mlir::ModuleOp mod, const llvm::DataLayout &dl);
|
||||
|
||||
} // namespace cir
|
||||
|
||||
#endif // CLANG_CIR_CIRDATALAYOUTSPEC_H
|
||||
|
|
@ -797,6 +797,107 @@ def CIR_CmpThreeWayInfoAttr : CIR_Attr<"CmpThreeWayInfo", "cmp3way_info"> {
|
|||
let canHaveIllegalCXXABIType = 0;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// FenvAttr
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def CIR_FPDynamicRoundingMode : CIR_I32EnumAttr<
|
||||
"FPDynamicRoundingMode", "floating-point dynamic rounding mode", [
|
||||
I32EnumAttrCase<"ToNearest", 0, "tonearest">,
|
||||
I32EnumAttrCase<"Downward", 1, "downward">,
|
||||
I32EnumAttrCase<"Upward", 2, "upward">,
|
||||
I32EnumAttrCase<"UpwardZero", 3, "upwardzero">,
|
||||
I32EnumAttrCase<"ToNearestAway", 4, "tonearestaway">,
|
||||
I32EnumAttrCase<"Unknown", 7, "unknown">
|
||||
]> {
|
||||
let description = [{
|
||||
The known dynamic rounding mode at the point the instruction is executed.
|
||||
If the actual dynamic rounding mode differs from this value, the behavior
|
||||
is undefined.
|
||||
}];
|
||||
let genSpecializedAttr = 0;
|
||||
}
|
||||
|
||||
def CIR_FPExceptionMode : CIR_I32EnumAttr<
|
||||
"FPExceptionMode", "floating-point exception mode", [
|
||||
I32EnumAttrCase<"Unknown", 0, "unknown">,
|
||||
I32EnumAttrCase<"Masked", 1, "masked">,
|
||||
I32EnumAttrCase<"Unmasked", 2, "unmasked">
|
||||
]> {
|
||||
let description = [{
|
||||
The known floating-point exception mode at the point the instruction is
|
||||
executed. If the actual exception mode differs from this value, the
|
||||
behavior is undefined.
|
||||
}];
|
||||
let genSpecializedAttr = 0;
|
||||
}
|
||||
|
||||
def CIR_FenvAttr : CIR_Attr<"Fenv", "fenv"> {
|
||||
let summary = "Describes floating-point environment constraints";
|
||||
let description = [{
|
||||
The `#cir.fenv` attribute describes constraints on the floating-point
|
||||
handling of a floating-point operation. It is attached to floating-point
|
||||
operations to capture rounding and exception behavior. All of its
|
||||
parameters are optional.
|
||||
|
||||
- `dynamic_rounding_mode`: the known dynamic rounding mode at the point the
|
||||
instruction is executed. Otherwise the behavior is undefined.
|
||||
- `except_mode`: the known exception mode at the point the instruction is
|
||||
executed. Otherwise the behavior is undefined.
|
||||
- `strict_except`: if `false`, any case that would produce an FP exception
|
||||
produces it non-deterministically instead (i.e. it may or may not occur).
|
||||
This means the FP status is written non-deterministically, and, if
|
||||
exceptions are unmasked, the instruction traps non-deterministically.
|
||||
|
||||
An absent `dynamic_rounding_mode` defaults to `unknown`, an absent
|
||||
`except_mode` defaults to `masked`, and an absent `strict_except` defaults
|
||||
to `false`.
|
||||
|
||||
Example:
|
||||
```
|
||||
#cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown,
|
||||
strict_except = true>
|
||||
```
|
||||
}];
|
||||
|
||||
let parameters = (ins
|
||||
OptionalParameter<
|
||||
"std::optional<cir::FPDynamicRoundingMode>">:$dynamic_rounding_mode,
|
||||
OptionalParameter<"std::optional<cir::FPExceptionMode>">:$except_mode,
|
||||
OptionalParameter<"mlir::BoolAttr">:$strict_except);
|
||||
|
||||
let assemblyFormat = [{
|
||||
`<` struct($dynamic_rounding_mode, $except_mode, $strict_except) `>`
|
||||
}];
|
||||
|
||||
let extraClassDeclaration = [{
|
||||
static constexpr cir::FPDynamicRoundingMode
|
||||
getDefaultDynamicRoundingMode() {
|
||||
return cir::FPDynamicRoundingMode::Unknown;
|
||||
}
|
||||
|
||||
static constexpr cir::FPExceptionMode getDefaultExceptionMode() {
|
||||
return cir::FPExceptionMode::Masked;
|
||||
}
|
||||
|
||||
cir::FPDynamicRoundingMode getDynamicRoundingModeOrDefault() const {
|
||||
return getDynamicRoundingMode().value_or(
|
||||
getDefaultDynamicRoundingMode());
|
||||
}
|
||||
|
||||
cir::FPExceptionMode getExceptionModeOrDefault() const {
|
||||
return getExceptMode().value_or(getDefaultExceptionMode());
|
||||
}
|
||||
|
||||
bool getStrictExceptOrDefault() const {
|
||||
mlir::BoolAttr strictExcept = getStrictExcept();
|
||||
return strictExcept && strictExcept.getValue();
|
||||
}
|
||||
}];
|
||||
|
||||
let canHaveIllegalCXXABIType = 0;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GlobalViewAttr
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
@ -1087,6 +1188,52 @@ def CIR_TargetAddressSpaceAttr : CIR_Attr< "TargetAddressSpace",
|
|||
let canHaveIllegalCXXABIType = 0;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// PtrSpecAttr
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def CIR_PtrSpecAttr : CIR_Attr<"PtrSpec", "ptr_spec"> {
|
||||
let summary = "!cir.ptr data layout spec";
|
||||
let description = [{
|
||||
Pointer data layout for `!cir.ptr`: `size`, `abi` and `preferred` are
|
||||
required bitwidths; `index` is the optional bitwidth for index
|
||||
computations, defaulting to `size`. All present values must be divisible
|
||||
by 8, with `preferred` >= `abi`.
|
||||
|
||||
This is the CIR-native analogue of the ptr dialect's `#ptr.spec`; a
|
||||
native attribute keeps CIR's data-layout queries free of any ptr-dialect
|
||||
dependency.
|
||||
|
||||
Used as the value of the `!cir.ptr<!cir.void>`-keyed data-layout entry:
|
||||
|
||||
```mlir
|
||||
#dlti.dl_spec<!cir.ptr<!cir.void> =
|
||||
#cir.ptr_spec<size = 64, abi = 64, preferred = 64>>
|
||||
```
|
||||
}];
|
||||
let parameters = (ins
|
||||
"uint32_t":$size,
|
||||
"uint32_t":$abi,
|
||||
"uint32_t":$preferred,
|
||||
DefaultValuedParameter<"uint32_t", "kOptionalSpecValue">:$index
|
||||
);
|
||||
let skipDefaultBuilders = 1;
|
||||
let builders = [
|
||||
AttrBuilder<(ins "uint32_t":$size, "uint32_t":$abi, "uint32_t":$preferred,
|
||||
CArg<"uint32_t", "kOptionalSpecValue">:$index), [{
|
||||
return $_get($_ctxt, size, abi, preferred, index);
|
||||
}]>
|
||||
];
|
||||
let assemblyFormat = "`<` struct(params) `>`";
|
||||
let extraClassDeclaration = [{
|
||||
/// Sentinel value marking the optional `index` parameter as unset.
|
||||
static constexpr uint32_t kOptionalSpecValue =
|
||||
std::numeric_limits<uint32_t>::max();
|
||||
}];
|
||||
let genVerifyDecl = 1;
|
||||
let canHaveIllegalCXXABIType = 0;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ConstComplexAttr
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
|||
|
|
@ -42,6 +42,45 @@ using BuilderOpStateCallbackRef = llvm::function_ref<void(
|
|||
namespace cir {
|
||||
void buildTerminatedBody(mlir::OpBuilder &builder, mlir::Location loc);
|
||||
|
||||
/// The process floating-point environment, including its rounding mode and
|
||||
/// exception state.
|
||||
struct FloatingPointEnvironmentResource
|
||||
: public mlir::SideEffects::Resource::Base<
|
||||
FloatingPointEnvironmentResource> {
|
||||
mlir::StringRef getName() const final { return "FloatingPointEnvironment"; }
|
||||
bool isAddressable() const final { return false; }
|
||||
};
|
||||
|
||||
template <typename ConcreteType>
|
||||
class FenvOpTrait : public mlir::OpTrait::TraitBase<ConcreteType, FenvOpTrait> {
|
||||
public:
|
||||
mlir::Speculation::Speculatability getSpeculatability() {
|
||||
// Masked exceptions cannot trap. When strict_except is false, exception
|
||||
// side effects are non-deterministic, so speculation is still safe.
|
||||
FPEnvConstrainedOpInterface fenvOp = getFenvOp();
|
||||
if (fenvOp.getFenvExceptionMode() == cir::FPExceptionMode::Masked &&
|
||||
!fenvOp.getFenvStrictExcept())
|
||||
return mlir::Speculation::Speculatable;
|
||||
|
||||
return mlir::Speculation::NotSpeculatable;
|
||||
}
|
||||
|
||||
void getEffects(
|
||||
llvm::SmallVectorImpl<mlir::MemoryEffects::EffectInstance> &effects) {
|
||||
if (!getFenvOp().getFenvAttr())
|
||||
return;
|
||||
effects.emplace_back(mlir::MemoryEffects::Read::get(),
|
||||
FloatingPointEnvironmentResource::get());
|
||||
effects.emplace_back(mlir::MemoryEffects::Write::get(),
|
||||
FloatingPointEnvironmentResource::get());
|
||||
}
|
||||
|
||||
private:
|
||||
FPEnvConstrainedOpInterface getFenvOp() {
|
||||
return mlir::cast<FPEnvConstrainedOpInterface>(this->getOperation());
|
||||
}
|
||||
};
|
||||
|
||||
/// Look up the RecordLayoutAttr for a named record in the module's
|
||||
/// cir.record_layouts dictionary. Asserts if the entry is missing.
|
||||
RecordLayoutAttr getRecordLayout(mlir::ModuleOp module, mlir::StringAttr name);
|
||||
|
|
|
|||
|
|
@ -73,8 +73,20 @@ include "mlir/Interfaces/SideEffectInterfaces.td"
|
|||
//
|
||||
// If you want fully customized LLVM IR lowering logic, simply exclude the
|
||||
// `llvmOp` field from your CIR operation definition.
|
||||
//
|
||||
// The `constrainedLLVMIntrinsic` field enables a specialized variant of this
|
||||
// generated lowering for floating-point operations that carry an optional
|
||||
// `fenv` attribute. When it is set and the operation has an `fenv` attribute
|
||||
// the operation is lowering to a call to the corresponding constrained fp
|
||||
// intrinsic. If `constrainedLLVMIntrinsic` is set `llvmOp` must be set as well.
|
||||
//
|
||||
// `constrainedLLVMIntrinsicHasRoundingMode` indicates whether the constrained
|
||||
// intrinsic takes a rounding-mode metadata argument in addition to the
|
||||
// exception-behavior metadata argument.
|
||||
class LLVMLoweringInfo {
|
||||
string llvmOp = "";
|
||||
string constrainedLLVMIntrinsic = "";
|
||||
bit constrainedLLVMIntrinsicHasRoundingMode = true;
|
||||
}
|
||||
|
||||
class LoweringBuilders<dag p> {
|
||||
|
|
@ -122,6 +134,37 @@ class HasAtMostOneOfAttrs<list<string> names> : PredOpTrait<
|
|||
HasAtMostOneOfAttrsPred<!foreach(name, names, "$" # name)>
|
||||
>;
|
||||
|
||||
// Like `SameTypeOperands`, but the operands are pointers that are only required
|
||||
// to share the same pointee type; they may still differ in address space (e.g.
|
||||
// a `cir.copy` that assigns through an address-space-qualified pointer).
|
||||
def SameOperandsPointeeType : PredOpTrait<
|
||||
"all operands have the same pointee type (address spaces may differ)",
|
||||
CPred<[{
|
||||
llvm::all_equal(llvm::map_range($_op.getOperands(), [](mlir::Value v) {
|
||||
return mlir::cast<cir::PointerType>(v.getType()).getPointee();
|
||||
}))
|
||||
}]>
|
||||
>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Floating-Point Environment Traits
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def CIR_FenvOpTrait : NativeOpTrait<"FenvOpTrait"> {
|
||||
let cppNamespace = "::cir";
|
||||
}
|
||||
|
||||
defvar CIR_FenvOpTraits = [
|
||||
CIR_FPEnvConstrainedOpInterface,
|
||||
ConditionallySpeculatable,
|
||||
MemoryEffectsOpInterface,
|
||||
CIR_FenvOpTrait
|
||||
];
|
||||
|
||||
// Passed as CIR_BinaryOp's hasNoMemoryEffect: fenv ops compute effects
|
||||
// dynamically via FenvOpTrait, so they must not inherit NoMemoryEffect.
|
||||
defvar CIR_DynamicMemoryEffects = 0;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CastOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
@ -201,9 +244,9 @@ def CIR_CastKind : CIR_I32EnumAttr<"CastKind", "cast kind", [
|
|||
I32EnumAttrCase<"bool_to_float", 1000>,
|
||||
]>;
|
||||
|
||||
def CIR_CastOp : CIR_Op<"cast", [
|
||||
Pure, DeclareOpInterfaceMethods<PromotableOpInterface>
|
||||
]> {
|
||||
def CIR_CastOp : CIR_Op<"cast", !listconcat([
|
||||
DeclareOpInterfaceMethods<PromotableOpInterface>
|
||||
], CIR_FenvOpTraits)> {
|
||||
let summary = "Conversion between values of different types";
|
||||
let description = [{
|
||||
Apply the usual C/C++ conversion rules between values. This operation models
|
||||
|
|
@ -239,6 +282,13 @@ def CIR_CastOp : CIR_Op<"cast", [
|
|||
|
||||
- `bool_to_float`
|
||||
|
||||
The optional `fenv` attribute describes constraints on the floating-point
|
||||
handling of the operation. It is only valid for floating-point cast kinds:
|
||||
`floating`, `int_to_float`, `float_to_int`, `float_to_bool`,
|
||||
`bool_to_float`, `float_to_complex`, `float_complex_to_real`,
|
||||
`float_complex_to_bool`, `float_complex`, `float_complex_to_int_complex`,
|
||||
and `int_complex_to_float_complex`.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
|
|
@ -246,16 +296,27 @@ def CIR_CastOp : CIR_Op<"cast", [
|
|||
...
|
||||
%x = cir.cast array_to_ptrdecay %0
|
||||
: !cir.ptr<!cir.array<i32 x 10>> -> !cir.ptr<i32>
|
||||
%y = cir.cast floating %f : !cir.double -> !cir.float {
|
||||
fenv = #cir.fenv<>
|
||||
}
|
||||
```
|
||||
}];
|
||||
|
||||
let arguments = (ins CIR_CastKind:$kind, CIR_AnyType:$src);
|
||||
let arguments = (ins CIR_CastKind:$kind, CIR_AnyType:$src,
|
||||
OptionalAttr<CIR_FenvAttr>:$fenv);
|
||||
let results = (outs CIR_AnyType:$result);
|
||||
|
||||
let assemblyFormat = [{
|
||||
$kind $src `:` type($src) `->` type($result) attr-dict
|
||||
}];
|
||||
|
||||
let builders = [
|
||||
OpBuilder<(ins "mlir::Type":$result, "cir::CastKind":$kind,
|
||||
"mlir::Value":$src), [{
|
||||
build($_builder, $_state, result, kind, src, cir::FenvAttr{});
|
||||
}]>
|
||||
];
|
||||
|
||||
// The input and output types should match the cast kind.
|
||||
let hasVerifier = 1;
|
||||
let hasFolder = 1;
|
||||
|
|
@ -1852,6 +1913,35 @@ def CIR_GotoOp : CIR_Op<"goto", [Terminator]> {
|
|||
let hasLLVMLowering = false;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// IndirectGotoOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def CIR_IndirectGotoOp : CIR_Op<"indirect_goto", [Terminator]> {
|
||||
let summary = "Symbolic indirect goto";
|
||||
let description = [{
|
||||
Transfers control to the block whose address is held in `$addr`, the
|
||||
void-pointer value of a `goto *expr;` (the GNU computed-goto extension).
|
||||
Like `cir.goto`, it is symbolic: it references no successor block, so it is
|
||||
valid inside any region even before `FlattenCFG` merges nested scopes.
|
||||
`GotoSolver` runs after `FlattenCFG` and rewrites each `cir.indirect_goto`
|
||||
into a `cir.br` to a shared block holding a `cir.indirect_br` over every
|
||||
address-taken label.
|
||||
|
||||
Example:
|
||||
|
||||
```mlir
|
||||
%0 = cir.load %p : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
|
||||
cir.indirect_goto %0 : !cir.ptr<!void>
|
||||
```
|
||||
}];
|
||||
|
||||
let arguments = (ins CIR_VoidPtrType:$addr);
|
||||
let assemblyFormat = [{ $addr `:` qualified(type($addr)) attr-dict }];
|
||||
|
||||
let hasLLVMLowering = false;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// LabelOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
@ -1882,7 +1972,9 @@ class CIR_UnaryOp<string mnemonic, Type type, list<Trait> traits = []>
|
|||
DeclareOpInterfaceMethods<CIR_UnaryOpInterface>
|
||||
], traits)>
|
||||
{
|
||||
let arguments = (ins type:$input);
|
||||
dag commonArgs = (ins type:$input);
|
||||
|
||||
let arguments = commonArgs;
|
||||
|
||||
let results = (outs type:$result);
|
||||
|
||||
|
|
@ -2420,12 +2512,14 @@ def CIR_CmpOpKind : CIR_I32EnumAttr<"CmpOpKind", "compare operation kind", [
|
|||
I32EnumAttrCase<"uno", 7>
|
||||
]>;
|
||||
|
||||
def CIR_CmpOp : CIR_Op<"cmp", [Pure, SameTypeOperands]> {
|
||||
def CIR_CmpOp : CIR_Op<"cmp",
|
||||
!listconcat([SameTypeOperands], CIR_FenvOpTraits)> {
|
||||
let summary = "Compare two values and produce a boolean result";
|
||||
let description = [{
|
||||
The `cir.cmp` operation compares two operands of the same type and produces
|
||||
a `!cir.bool` result. It supports integral, floating-point, and pointer
|
||||
types.
|
||||
a `!cir.bool` result. It supports integral, boolean, floating-point, and
|
||||
pointer types. Booleans (including enums with a boolean underlying type)
|
||||
are compared as unsigned integers.
|
||||
|
||||
The following comparison predicates are available:
|
||||
|
||||
|
|
@ -2443,16 +2537,22 @@ def CIR_CmpOp : CIR_Op<"cmp", [Pure, SameTypeOperands]> {
|
|||
The `one` and `uno` predicates are floating-point specific: `one` is
|
||||
ordered not-equal (false for NaN), `uno` tests if either operand is NaN.
|
||||
|
||||
The optional `fenv` attribute describes constraints on the floating-point
|
||||
handling of the operation. It is only valid for floating-point
|
||||
comparisons.
|
||||
|
||||
```
|
||||
%0 = cir.cmp gt %1, %2 : !s32i
|
||||
%1 = cir.cmp eq %a, %b : !cir.ptr<!u8i>
|
||||
%2 = cir.cmp lt %x, %y : !cir.float {fenv = #cir.fenv<>}
|
||||
```
|
||||
}];
|
||||
|
||||
let arguments = (ins
|
||||
CIR_CmpOpKind:$kind,
|
||||
CIR_ComparableType:$lhs,
|
||||
CIR_ComparableType:$rhs
|
||||
CIR_ComparableType:$rhs,
|
||||
OptionalAttr<CIR_FenvAttr>:$fenv
|
||||
);
|
||||
|
||||
let results = (outs CIR_BoolType:$result);
|
||||
|
|
@ -2461,6 +2561,18 @@ def CIR_CmpOp : CIR_Op<"cmp", [Pure, SameTypeOperands]> {
|
|||
$kind $lhs `,` $rhs `:` type($lhs) attr-dict
|
||||
}];
|
||||
|
||||
let builders = [
|
||||
OpBuilder<(ins "cir::CmpOpKind":$kind, "mlir::Value":$lhs,
|
||||
"mlir::Value":$rhs), [{
|
||||
build($_builder, $_state, kind, lhs, rhs, cir::FenvAttr{});
|
||||
}]>,
|
||||
OpBuilder<(ins "mlir::Type":$result, "cir::CmpOpKind":$kind,
|
||||
"mlir::Value":$lhs, "mlir::Value":$rhs), [{
|
||||
build($_builder, $_state, result, kind, lhs, rhs, cir::FenvAttr{});
|
||||
}]>
|
||||
];
|
||||
|
||||
let hasVerifier = 1;
|
||||
let isLLVMLoweringRecursive = true;
|
||||
let hasCXXABILowering = true;
|
||||
}
|
||||
|
|
@ -2563,17 +2675,21 @@ def CIR_MulOverflowOp : CIR_BinOpOverflow<"mul.overflow", [Commutative]> {
|
|||
|
||||
// Base class for all CIR binary arithmetic/logic operations.
|
||||
// `type` constrains the lhs/rhs/result type.
|
||||
class CIR_BinaryOp<string mnemonic, Type type, list<Trait> traits = []>
|
||||
: CIR_Op<mnemonic, !listconcat([
|
||||
NoMemoryEffect, SameOperandsAndResultType,
|
||||
class CIR_BinaryOp<string mnemonic, Type type, list<Trait> traits = [],
|
||||
bit hasNoMemoryEffect = 1>
|
||||
: CIR_Op<mnemonic, !listconcat(
|
||||
!if(hasNoMemoryEffect, [NoMemoryEffect], []), [
|
||||
SameOperandsAndResultType,
|
||||
DeclareOpInterfaceMethods<CIR_BinaryOpInterface>
|
||||
], traits)>
|
||||
{
|
||||
let arguments = (ins
|
||||
dag commonArgs = (ins
|
||||
type:$lhs,
|
||||
type:$rhs
|
||||
);
|
||||
|
||||
let arguments = commonArgs;
|
||||
|
||||
let results = (outs type:$result);
|
||||
|
||||
let assemblyFormat = [{
|
||||
|
|
@ -2749,9 +2865,23 @@ def CIR_RemOp : CIR_BinaryOp<"rem", CIR_AnyIntOrVecOfIntType> {
|
|||
|
||||
// Base class for floating-point binary arithmetic operations. The lhs, rhs,
|
||||
// and result must all be the same floating-point scalar or vector type.
|
||||
//
|
||||
// The optional `fenv` attribute describes constraints on the floating-point
|
||||
// handling of the operation.
|
||||
class CIR_FPBinaryOp<string mnemonic, list<Trait> traits = []>
|
||||
: CIR_BinaryOp<mnemonic, CIR_AnyFloatOrVecOfFloatType,
|
||||
!listconcat([Pure], traits)>;
|
||||
!listconcat(CIR_FenvOpTraits, traits),
|
||||
CIR_DynamicMemoryEffects> {
|
||||
let arguments = !con(commonArgs, (ins OptionalAttr<CIR_FenvAttr>:$fenv));
|
||||
|
||||
let constrainedLLVMIntrinsic = mnemonic;
|
||||
|
||||
let builders = [
|
||||
OpBuilder<(ins "mlir::Value":$lhs, "mlir::Value":$rhs), [{
|
||||
build($_builder, $_state, lhs, rhs, cir::FenvAttr{});
|
||||
}]>
|
||||
];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// FAddOp
|
||||
|
|
@ -4708,7 +4838,7 @@ def CIR_CoReturnOp : CIR_Op<"co_return", [
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def CIR_CopyOp : CIR_Op<"copy",[
|
||||
SameTypeOperands,
|
||||
SameOperandsPointeeType,
|
||||
DeclareOpInterfaceMethods<PromotableMemOpInterface>
|
||||
]> {
|
||||
let summary = "Copies contents from a CIR pointer to another";
|
||||
|
|
@ -4718,7 +4848,9 @@ def CIR_CopyOp : CIR_Op<"copy",[
|
|||
|
||||
The number of bytes copied is inferred from the pointee type. The pointee
|
||||
type of `src` and `dst` must match and both must implement the
|
||||
`DataLayoutTypeInterface`.
|
||||
`DataLayoutTypeInterface`. The pointers may differ in address space (e.g.
|
||||
when assigning through an address-space-qualified pointer); when the two
|
||||
pointer types differ, both are printed, `src` first.
|
||||
|
||||
The `volatile` keyword indicates that the operation is volatile.
|
||||
|
||||
|
|
@ -4754,7 +4886,7 @@ def CIR_CopyOp : CIR_Op<"copy",[
|
|||
$dst (`align` `(` $dst_alignment^ `)`)?
|
||||
(`volatile` $is_volatile^)?
|
||||
(`skip_tail_padding` $skip_tail_padding^)?
|
||||
attr-dict `:` qualified(type($dst))
|
||||
attr-dict `:` custom<CopyTypes>(type($src), type($dst))
|
||||
}];
|
||||
let hasVerifier = 1;
|
||||
|
||||
|
|
@ -5617,7 +5749,8 @@ def CIR_VecExtractOp : CIR_Op<"vec.extract", [
|
|||
// VecCmpOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def CIR_VecCmpOp : CIR_Op<"vec.cmp", [Pure, SameTypeOperands]> {
|
||||
def CIR_VecCmpOp : CIR_Op<"vec.cmp",
|
||||
!listconcat([SameTypeOperands], CIR_FenvOpTraits)> {
|
||||
let summary = "Compare two vectors";
|
||||
let description = [{
|
||||
The `cir.vec.cmp` operation does an element-wise comparison of two vectors
|
||||
|
|
@ -5625,16 +5758,24 @@ def CIR_VecCmpOp : CIR_Op<"vec.cmp", [Pure, SameTypeOperands]> {
|
|||
whose element type is the signed integral type that is the same size as the
|
||||
element type of the operands. The values in the result are 0 or -1.
|
||||
|
||||
The optional `fenv` attribute describes constraints on the floating-point
|
||||
handling of the operation. It is only valid for floating-point vector
|
||||
comparisons.
|
||||
|
||||
```
|
||||
%eq = cir.vec.cmp(eq, %vec_a, %vec_b) : !cir.vector<4 x !s32i>, !cir.vector<4 x !s32i>
|
||||
%lt = cir.vec.cmp(lt, %vec_a, %vec_b) : !cir.vector<4 x !s32i>, !cir.vector<4 x !s32i>
|
||||
%gt = cir.vec.cmp(gt, %va, %vb) : !cir.vector<4 x !cir.float>, !cir.vector<4 x !s32i> {
|
||||
fenv = #cir.fenv<>
|
||||
}
|
||||
```
|
||||
}];
|
||||
|
||||
let arguments = (ins
|
||||
CIR_CmpOpKind:$kind,
|
||||
CIR_VectorType:$lhs,
|
||||
CIR_VectorType:$rhs
|
||||
CIR_VectorType:$rhs,
|
||||
OptionalAttr<CIR_FenvAttr>:$fenv
|
||||
);
|
||||
|
||||
let results = (outs CIR_VectorType:$result);
|
||||
|
|
@ -5644,6 +5785,14 @@ def CIR_VecCmpOp : CIR_Op<"vec.cmp", [Pure, SameTypeOperands]> {
|
|||
qualified(type($result)) attr-dict
|
||||
}];
|
||||
|
||||
let builders = [
|
||||
OpBuilder<(ins "mlir::Type":$result, "cir::CmpOpKind":$kind,
|
||||
"mlir::Value":$lhs, "mlir::Value":$rhs), [{
|
||||
build($_builder, $_state, result, kind, lhs, rhs, cir::FenvAttr{});
|
||||
}]>
|
||||
];
|
||||
|
||||
let hasVerifier = 1;
|
||||
let hasFolder = 1;
|
||||
}
|
||||
|
||||
|
|
@ -6905,15 +7054,26 @@ def CIR_PtrDiffOp : CIR_Op<"ptr_diff", [Pure, SameTypeOperands]> {
|
|||
// Floating Point Ops
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// The optional `fenv` attribute describes constraints on the floating-point
|
||||
// handling of the operation.
|
||||
class CIR_UnaryFPToFPBuiltinOp<string mnemonic, string llvmOpName>
|
||||
: CIR_Op<mnemonic, [Pure, SameOperandsAndResultType]>
|
||||
: CIR_Op<mnemonic,
|
||||
!listconcat([SameOperandsAndResultType], CIR_FenvOpTraits)>
|
||||
{
|
||||
let arguments = (ins CIR_AnyFloatOrVecOfFloatType:$src);
|
||||
let arguments = (ins CIR_AnyFloatOrVecOfFloatType:$src,
|
||||
OptionalAttr<CIR_FenvAttr>:$fenv);
|
||||
let results = (outs CIR_AnyFloatOrVecOfFloatType:$result);
|
||||
|
||||
let assemblyFormat = "$src `:` type($src) attr-dict";
|
||||
|
||||
let builders = [
|
||||
OpBuilder<(ins "mlir::Value":$src), [{
|
||||
build($_builder, $_state, src, cir::FenvAttr{});
|
||||
}]>
|
||||
];
|
||||
|
||||
let llvmOp = llvmOpName;
|
||||
let constrainedLLVMIntrinsic = mnemonic;
|
||||
}
|
||||
|
||||
def CIR_SqrtOp : CIR_UnaryFPToFPBuiltinOp<"sqrt", "SqrtOp"> {
|
||||
|
|
@ -6975,6 +7135,8 @@ def CIR_CeilOp : CIR_UnaryFPToFPBuiltinOp<"ceil", "FCeilOp"> {
|
|||
|
||||
Floating-point exceptions are ignored, and it does not set `errno`.
|
||||
}];
|
||||
|
||||
let constrainedLLVMIntrinsicHasRoundingMode = 0;
|
||||
}
|
||||
|
||||
def CIR_CosOp : CIR_UnaryFPToFPBuiltinOp<"cos", "CosOp"> {
|
||||
|
|
@ -6987,6 +7149,16 @@ def CIR_CosOp : CIR_UnaryFPToFPBuiltinOp<"cos", "CosOp"> {
|
|||
}];
|
||||
}
|
||||
|
||||
def CIR_CoshOp : CIR_UnaryFPToFPBuiltinOp<"cosh", "CoshOp"> {
|
||||
let summary = "Computes the floating-point hyperbolic cosine value";
|
||||
let description = [{
|
||||
`cir.cosh` computes the hyperbolic cosine of a floating-point operand and
|
||||
returns a result of the same type.
|
||||
|
||||
Floating-point exceptions are ignored, and it does not set `errno`.
|
||||
}];
|
||||
}
|
||||
|
||||
def CIR_ExpOp : CIR_UnaryFPToFPBuiltinOp<"exp", "ExpOp"> {
|
||||
let summary = "Computes the floating-point base-e exponential value";
|
||||
let description = [{
|
||||
|
|
@ -6997,6 +7169,16 @@ def CIR_ExpOp : CIR_UnaryFPToFPBuiltinOp<"exp", "ExpOp"> {
|
|||
}];
|
||||
}
|
||||
|
||||
def CIR_Exp10Op : CIR_UnaryFPToFPBuiltinOp<"exp10", "Exp10Op"> {
|
||||
let summary = "Computes the floating-point base-10 exponential value";
|
||||
let description = [{
|
||||
`cir.exp10` computes the base-10 exponential of a floating-point operand and
|
||||
returns a result of the same type.
|
||||
|
||||
Floating-point exceptions are ignored, and it does not set `errno`.
|
||||
}];
|
||||
}
|
||||
|
||||
def CIR_Exp2Op : CIR_UnaryFPToFPBuiltinOp<"exp2", "Exp2Op"> {
|
||||
let summary = "Computes the floating-point base-2 exponential value";
|
||||
let description = [{
|
||||
|
|
@ -7067,6 +7249,8 @@ def CIR_RoundOp : CIR_UnaryFPToFPBuiltinOp<"round", "RoundOp"> {
|
|||
|
||||
Floating-point exceptions are ignored, and it does not set `errno`.
|
||||
}];
|
||||
|
||||
let constrainedLLVMIntrinsicHasRoundingMode = 0;
|
||||
}
|
||||
|
||||
def CIR_RoundEvenOp : CIR_UnaryFPToFPBuiltinOp<"roundeven", "RoundEvenOp"> {
|
||||
|
|
@ -7077,6 +7261,8 @@ def CIR_RoundEvenOp : CIR_UnaryFPToFPBuiltinOp<"roundeven", "RoundEvenOp"> {
|
|||
|
||||
Floating-point exceptions are ignored, and it does not set `errno`.
|
||||
}];
|
||||
|
||||
let constrainedLLVMIntrinsicHasRoundingMode = 0;
|
||||
}
|
||||
|
||||
def CIR_SinOp : CIR_UnaryFPToFPBuiltinOp<"sin", "SinOp"> {
|
||||
|
|
@ -7089,6 +7275,16 @@ def CIR_SinOp : CIR_UnaryFPToFPBuiltinOp<"sin", "SinOp"> {
|
|||
}];
|
||||
}
|
||||
|
||||
def CIR_SinhOp : CIR_UnaryFPToFPBuiltinOp<"sinh", "SinhOp"> {
|
||||
let summary = "Computes the floating-point hyperbolic sine";
|
||||
let description = [{
|
||||
`cir.sinh` computes the hyperbolic sine of a floating-point operand and
|
||||
returns a result of the same type.
|
||||
|
||||
Floating-point exceptions are ignored, and it does not set `errno`.
|
||||
}];
|
||||
}
|
||||
|
||||
def CIR_TanOp : CIR_UnaryFPToFPBuiltinOp<"tan", "TanOp"> {
|
||||
let summary = "Computes the floating-point tangent";
|
||||
let description = [{
|
||||
|
|
@ -7099,6 +7295,16 @@ def CIR_TanOp : CIR_UnaryFPToFPBuiltinOp<"tan", "TanOp"> {
|
|||
}];
|
||||
}
|
||||
|
||||
def CIR_TanhOp : CIR_UnaryFPToFPBuiltinOp<"tanh", "TanhOp"> {
|
||||
let summary = "Computes the floating-point hyperbolic tangent";
|
||||
let description = [{
|
||||
`cir.tanh` computes the hyperbolic tangent of a floating-point operand and
|
||||
returns a result of the same type.
|
||||
|
||||
Floating-point exceptions are ignored, and it does not set `errno`.
|
||||
}];
|
||||
}
|
||||
|
||||
def CIR_TruncOp : CIR_UnaryFPToFPBuiltinOp<"trunc", "FTruncOp"> {
|
||||
let summary = "Truncates floating-point value to integer";
|
||||
let description = [{
|
||||
|
|
@ -7107,6 +7313,8 @@ def CIR_TruncOp : CIR_UnaryFPToFPBuiltinOp<"trunc", "FTruncOp"> {
|
|||
|
||||
Floating-point exceptions are ignored, and it does not set `errno`.
|
||||
}];
|
||||
|
||||
let constrainedLLVMIntrinsicHasRoundingMode = 0;
|
||||
}
|
||||
|
||||
def CIR_FAbsOp : CIR_UnaryFPToFPBuiltinOp<"fabs", "FAbsOp"> {
|
||||
|
|
@ -7117,6 +7325,10 @@ def CIR_FAbsOp : CIR_UnaryFPToFPBuiltinOp<"fabs", "FAbsOp"> {
|
|||
|
||||
Floating-point exceptions are ignored, and it does not set `errno`.
|
||||
}];
|
||||
|
||||
// fabs is exact and does not raise exceptions, so it is always lowered to
|
||||
// the plain llvm.fabs intrinsic.
|
||||
let constrainedLLVMIntrinsic = "";
|
||||
}
|
||||
|
||||
def CIR_AbsOp : CIR_Op<"abs", [Pure, SameOperandsAndResultType]> {
|
||||
|
|
@ -7163,12 +7375,15 @@ def CIR_FloorOp : CIR_UnaryFPToFPBuiltinOp<"floor", "FFloorOp"> {
|
|||
%y = cir.floor %x : !cir.double
|
||||
```
|
||||
}];
|
||||
|
||||
let constrainedLLVMIntrinsicHasRoundingMode = 0;
|
||||
}
|
||||
|
||||
class CIR_UnaryFPToIntBuiltinOp<string mnemonic, string llvmOpName>
|
||||
: CIR_Op<mnemonic, [Pure]>
|
||||
: CIR_Op<mnemonic, CIR_FenvOpTraits>
|
||||
{
|
||||
let arguments = (ins CIR_AnyFloatType:$src);
|
||||
let arguments = (ins CIR_AnyFloatType:$src,
|
||||
OptionalAttr<CIR_FenvAttr>:$fenv);
|
||||
let results = (outs CIR_IntType:$result);
|
||||
|
||||
let summary = [{
|
||||
|
|
@ -7180,7 +7395,14 @@ class CIR_UnaryFPToIntBuiltinOp<string mnemonic, string llvmOpName>
|
|||
$src `:` type($src) `->` type($result) attr-dict
|
||||
}];
|
||||
|
||||
let builders = [
|
||||
OpBuilder<(ins "mlir::Type":$result, "mlir::Value":$src), [{
|
||||
build($_builder, $_state, result, src, cir::FenvAttr{});
|
||||
}]>
|
||||
];
|
||||
|
||||
let llvmOp = llvmOpName;
|
||||
let constrainedLLVMIntrinsic = mnemonic;
|
||||
}
|
||||
|
||||
def CIR_LroundOp : CIR_UnaryFPToIntBuiltinOp<"lround", "LroundOp"> {
|
||||
|
|
@ -7189,6 +7411,8 @@ def CIR_LroundOp : CIR_UnaryFPToIntBuiltinOp<"lround", "LroundOp"> {
|
|||
`cir.lround` rounds a floating-point value to the nearest integer value,
|
||||
rounding halfway cases away from zero, and returns the result as a `long`.
|
||||
}];
|
||||
|
||||
let constrainedLLVMIntrinsicHasRoundingMode = 0;
|
||||
}
|
||||
|
||||
def CIR_LlroundOp : CIR_UnaryFPToIntBuiltinOp<"llround", "LlroundOp"> {
|
||||
|
|
@ -7198,6 +7422,8 @@ def CIR_LlroundOp : CIR_UnaryFPToIntBuiltinOp<"llround", "LlroundOp"> {
|
|||
rounding halfway cases away from zero, and returns the result as a
|
||||
`long long`.
|
||||
}];
|
||||
|
||||
let constrainedLLVMIntrinsicHasRoundingMode = 0;
|
||||
}
|
||||
|
||||
def CIR_LrintOp : CIR_UnaryFPToIntBuiltinOp<"lrint", "LrintOp"> {
|
||||
|
|
@ -7217,14 +7443,16 @@ def CIR_LlrintOp : CIR_UnaryFPToIntBuiltinOp<"llrint", "LlrintOp"> {
|
|||
}
|
||||
|
||||
class CIR_BinaryFPToFPBuiltinOp<string mnemonic, string llvmOpName>
|
||||
: CIR_Op<mnemonic, [Pure, SameOperandsAndResultType]> {
|
||||
: CIR_Op<mnemonic,
|
||||
!listconcat([SameOperandsAndResultType], CIR_FenvOpTraits)> {
|
||||
let summary = [{
|
||||
libc builtin equivalent ignoring floating-point exceptions and errno.
|
||||
}];
|
||||
|
||||
let arguments = (ins
|
||||
CIR_AnyFloatOrVecOfFloatType:$lhs,
|
||||
CIR_AnyFloatOrVecOfFloatType:$rhs
|
||||
CIR_AnyFloatOrVecOfFloatType:$rhs,
|
||||
OptionalAttr<CIR_FenvAttr>:$fenv
|
||||
);
|
||||
|
||||
let results = (outs CIR_AnyFloatOrVecOfFloatType:$result);
|
||||
|
|
@ -7233,6 +7461,13 @@ class CIR_BinaryFPToFPBuiltinOp<string mnemonic, string llvmOpName>
|
|||
$lhs `,` $rhs `:` qualified(type($lhs)) attr-dict
|
||||
}];
|
||||
|
||||
let builders = [
|
||||
OpBuilder<(ins "mlir::Type":$result, "mlir::Value":$lhs,
|
||||
"mlir::Value":$rhs), [{
|
||||
build($_builder, $_state, result, lhs, rhs, cir::FenvAttr{});
|
||||
}]>
|
||||
];
|
||||
|
||||
let llvmOp = llvmOpName;
|
||||
}
|
||||
|
||||
|
|
@ -7242,6 +7477,9 @@ def CIR_CopysignOp : CIR_BinaryFPToFPBuiltinOp<"copysign", "CopySignOp"> {
|
|||
`cir.copysign` returns a value with the magnitude of the first operand
|
||||
and the sign of the second operand.
|
||||
}];
|
||||
|
||||
// copysign is exact and does not raise exceptions, so it is always lowered
|
||||
// to the plain llvm.copysign intrinsic.
|
||||
}
|
||||
|
||||
def CIR_FMaxNumOp : CIR_BinaryFPToFPBuiltinOp<"fmaxnum", "MaxNumOp"> {
|
||||
|
|
@ -7260,6 +7498,9 @@ def CIR_FMaximumOp : CIR_BinaryFPToFPBuiltinOp<"fmaximum", "MaximumOp"> {
|
|||
`cir.fmaximum` returns the larger of its two operands according to
|
||||
IEEE 754-2019 semantics. If either operand is NaN, NaN is returned.
|
||||
}];
|
||||
|
||||
let constrainedLLVMIntrinsic = "maximum";
|
||||
let constrainedLLVMIntrinsicHasRoundingMode = 0;
|
||||
}
|
||||
|
||||
def CIR_FMinNumOp : CIR_BinaryFPToFPBuiltinOp<"fminnum", "MinNumOp"> {
|
||||
|
|
@ -7278,6 +7519,9 @@ def CIR_FMinimumOp : CIR_BinaryFPToFPBuiltinOp<"fminimum", "MinimumOp"> {
|
|||
`cir.fminimum` returns the smaller of its two operands according to
|
||||
IEEE 754-2019 semantics. If either operand is NaN, NaN is returned.
|
||||
}];
|
||||
|
||||
let constrainedLLVMIntrinsic = "minimum";
|
||||
let constrainedLLVMIntrinsicHasRoundingMode = 0;
|
||||
}
|
||||
|
||||
def CIR_FModOp : CIR_BinaryFPToFPBuiltinOp<"fmod", "FRemOp"> {
|
||||
|
|
@ -7286,6 +7530,9 @@ def CIR_FModOp : CIR_BinaryFPToFPBuiltinOp<"fmod", "FRemOp"> {
|
|||
`cir.fmod` computes the floating-point remainder of dividing the first
|
||||
operand by the second operand.
|
||||
}];
|
||||
|
||||
// fmod maps to the constrained frem intrinsic.
|
||||
let constrainedLLVMIntrinsic = "frem";
|
||||
}
|
||||
|
||||
def CIR_PowOp : CIR_BinaryFPToFPBuiltinOp<"pow", "PowOp"> {
|
||||
|
|
@ -7294,6 +7541,8 @@ def CIR_PowOp : CIR_BinaryFPToFPBuiltinOp<"pow", "PowOp"> {
|
|||
`cir.pow` computes the first operand raised to the power of the second
|
||||
operand.
|
||||
}];
|
||||
|
||||
let constrainedLLVMIntrinsic = "pow";
|
||||
}
|
||||
|
||||
def CIR_ATan2Op : CIR_BinaryFPToFPBuiltinOp<"atan2", "ATan2Op"> {
|
||||
|
|
@ -7302,6 +7551,8 @@ def CIR_ATan2Op : CIR_BinaryFPToFPBuiltinOp<"atan2", "ATan2Op"> {
|
|||
`cir.atan2` computes the arc tangent of the first operand divided by the
|
||||
second operand, using the signs of both to determine the quadrant.
|
||||
}];
|
||||
|
||||
let constrainedLLVMIntrinsic = "atan2";
|
||||
}
|
||||
|
||||
def CIR_FrexpOp : CIR_Op<"frexp", [Pure]> {
|
||||
|
|
@ -7346,18 +7597,27 @@ def CIR_ModfOp : CIR_Op<"modf", [Pure]> {
|
|||
}
|
||||
|
||||
class CIR_TernaryFPToFPBuiltinOp<string mnemonic, string llvmOpName>
|
||||
: CIR_Op<mnemonic, [Pure, SameOperandsAndResultType]>
|
||||
: CIR_Op<mnemonic,
|
||||
!listconcat([SameOperandsAndResultType], CIR_FenvOpTraits)>
|
||||
{
|
||||
let arguments = (ins
|
||||
let arguments = (ins
|
||||
CIR_AnyFloatOrVecOfFloatType:$a,
|
||||
CIR_AnyFloatOrVecOfFloatType:$b,
|
||||
CIR_AnyFloatOrVecOfFloatType:$c
|
||||
CIR_AnyFloatOrVecOfFloatType:$c,
|
||||
OptionalAttr<CIR_FenvAttr>:$fenv
|
||||
);
|
||||
|
||||
|
||||
let results = (outs CIR_AnyFloatOrVecOfFloatType:$result);
|
||||
|
||||
let assemblyFormat = "$a `,` $b `,` $c `:` type($a) attr-dict";
|
||||
|
||||
let builders = [
|
||||
OpBuilder<(ins "mlir::Type":$result, "mlir::Value":$a, "mlir::Value":$b,
|
||||
"mlir::Value":$c), [{
|
||||
build($_builder, $_state, result, a, b, c, cir::FenvAttr{});
|
||||
}]>
|
||||
];
|
||||
|
||||
let llvmOp = llvmOpName;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -402,8 +402,8 @@ def CIR_AnyScalarType : AnyTypeOf<CIR_ScalarTypes, "cir scalar type"> {
|
|||
def CIR_AnyMethodType : CIR_TypeBase<"::cir::MethodType", "method type">;
|
||||
|
||||
def CIR_ComparableType
|
||||
: AnyTypeOf<[CIR_AnyIntType, CIR_AnyFloatType, CIR_AnyPtrType,
|
||||
CIR_AnyComplexType, CIR_AnyVPtrType,
|
||||
: AnyTypeOf<[CIR_AnyIntType, CIR_AnyBoolType, CIR_AnyFloatType,
|
||||
CIR_AnyPtrType, CIR_AnyComplexType, CIR_AnyVPtrType,
|
||||
CIR_AnyDataMemberType, CIR_AnyMethodType],
|
||||
"comparable type"> {
|
||||
let cppFunctionName = "isComparableType";
|
||||
|
|
|
|||
|
|
@ -239,7 +239,9 @@ def CIR_ComplexType : CIR_Type<"Complex", "complex", [
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def CIR_PointerType : CIR_Type<"Pointer", "ptr", [
|
||||
DeclareTypeInterfaceMethods<DataLayoutTypeInterface>,
|
||||
DeclareTypeInterfaceMethods<DataLayoutTypeInterface,
|
||||
["getPreferredAlignment", "getIndexBitwidth", "areCompatible",
|
||||
"verifyEntries"]>,
|
||||
DeclareTypeInterfaceMethods<CIR_SizedTypeInterface>
|
||||
]> {
|
||||
let summary = "CIR pointer type";
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/Mangle.h"
|
||||
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
|
||||
#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
|
||||
|
||||
/// Include the generated interface declarations.
|
||||
|
|
|
|||
|
|
@ -211,6 +211,47 @@ let cppNamespace = "::cir" in {
|
|||
}];
|
||||
}
|
||||
|
||||
def CIR_FPEnvConstrainedOpInterface
|
||||
: OpInterface<"FPEnvConstrainedOpInterface"> {
|
||||
let description = [{
|
||||
Interface for floating-point operations that carry an optional
|
||||
`#cir.fenv` attribute. It provides effective values for each field,
|
||||
substituting the floating-point environment defaults for absent fields.
|
||||
}];
|
||||
|
||||
let methods = [
|
||||
InterfaceMethod<
|
||||
"Return the `#cir.fenv` attribute, or a null attribute if absent.",
|
||||
"cir::FenvAttr", "getFenvAttr", (ins), [{}],
|
||||
/*defaultImplementation=*/[{
|
||||
return $_op.getFenvAttr();
|
||||
}]>,
|
||||
InterfaceMethod<
|
||||
"Return the effective dynamic rounding mode.",
|
||||
"cir::FPDynamicRoundingMode", "getFenvDynamicRoundingMode", (ins),
|
||||
[{}], /*defaultImplementation=*/[{
|
||||
cir::FenvAttr fenv = $_op.getFenvAttr();
|
||||
return fenv ? fenv.getDynamicRoundingModeOrDefault()
|
||||
: cir::FenvAttr::getDefaultDynamicRoundingMode();
|
||||
}]>,
|
||||
InterfaceMethod<
|
||||
"Return the effective floating-point exception mode.",
|
||||
"cir::FPExceptionMode", "getFenvExceptionMode", (ins), [{}],
|
||||
/*defaultImplementation=*/[{
|
||||
cir::FenvAttr fenv = $_op.getFenvAttr();
|
||||
return fenv ? fenv.getExceptionModeOrDefault()
|
||||
: cir::FenvAttr::getDefaultExceptionMode();
|
||||
}]>,
|
||||
InterfaceMethod<
|
||||
"Return the effective strict-exception flag.",
|
||||
"bool", "getFenvStrictExcept", (ins), [{}],
|
||||
/*defaultImplementation=*/[{
|
||||
cir::FenvAttr fenv = $_op.getFenvAttr();
|
||||
return fenv ? fenv.getStrictExceptOrDefault() : false;
|
||||
}]>,
|
||||
];
|
||||
}
|
||||
|
||||
def CIR_BinaryOpInterface : OpInterface<"BinaryOpInterface"> {
|
||||
let description = [{
|
||||
Common interface for CIR binary arithmetic and logic operations.
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ struct MissingFeatures {
|
|||
static bool opCallReturn() { return false; }
|
||||
static bool opCallArgEvaluationOrder() { return false; }
|
||||
static bool opCallCallConv() { return false; }
|
||||
static bool opCallMustTail() { return false; }
|
||||
static bool opCallThunkTailHint() { return false; }
|
||||
static bool opCallInAlloca() { return false; }
|
||||
static bool opCallAttrs() { return false; }
|
||||
static bool opCallSurroundingTry() { return false; }
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ public:
|
|||
virtual void handleVisibleModule(std::string ModuleName) = 0;
|
||||
|
||||
virtual void handleContextHash(std::string Hash) = 0;
|
||||
|
||||
virtual void finishQuery(StringRef ModuleName, bool Success) {}
|
||||
};
|
||||
} // namespace clang::dependencies
|
||||
|
||||
|
|
|
|||
|
|
@ -69,20 +69,6 @@ struct DiagnosticsEngineWithDiagOpts {
|
|||
DiagnosticConsumer &DC);
|
||||
};
|
||||
|
||||
struct TextDiagnosticsPrinterWithOutput {
|
||||
// We need to bound the lifetime of the data that supports the DiagPrinter
|
||||
// with it together so they have the same lifetime.
|
||||
std::string DiagnosticOutput;
|
||||
llvm::raw_string_ostream DiagnosticsOS;
|
||||
std::unique_ptr<DiagnosticOptions> DiagOpts;
|
||||
TextDiagnosticPrinter DiagPrinter;
|
||||
|
||||
TextDiagnosticsPrinterWithOutput(ArrayRef<std::string> CommandLine)
|
||||
: DiagnosticsOS(DiagnosticOutput),
|
||||
DiagOpts(createDiagOptions(CommandLine)),
|
||||
DiagPrinter(DiagnosticsOS, *DiagOpts) {}
|
||||
};
|
||||
|
||||
std::unique_ptr<CompilerInvocation>
|
||||
createCompilerInvocation(ArrayRef<std::string> CommandLine,
|
||||
DiagnosticsEngine &Diags);
|
||||
|
|
|
|||
|
|
@ -28,10 +28,6 @@ namespace clang {
|
|||
|
||||
class DependencyOutputOptions;
|
||||
|
||||
namespace tooling {
|
||||
class CompilerInstanceWithContext;
|
||||
}
|
||||
|
||||
namespace dependencies {
|
||||
|
||||
class DependencyConsumer;
|
||||
|
|
@ -64,6 +60,18 @@ public:
|
|||
DiagnosticConsumer &DiagConsumer,
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS = nullptr);
|
||||
|
||||
/// By-name scanning over a single cc1 command line. Builds a scanning session
|
||||
/// local to this call, then pulls module names from \p getNextName until it
|
||||
/// returns std::nullopt. Results flow to \p DepConsumer (per-name status via
|
||||
/// finishQuery); diagnostics flow to \p DiagConsumer.
|
||||
/// \returns false if session setup failed, true otherwise.
|
||||
bool computeDependenciesByName(
|
||||
StringRef CWD, ArrayRef<std::string> CC1CommandLine,
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS,
|
||||
DiagnosticConsumer &DiagConsumer, DependencyActionController &Controller,
|
||||
llvm::function_ref<std::optional<std::string>()> getNextName,
|
||||
DependencyConsumer &DepConsumer);
|
||||
|
||||
/// Creates the effective VFS that will be used for the scan.
|
||||
///
|
||||
/// If provided, OverlayFS will be overlaid on top of the Worker's dependency
|
||||
|
|
@ -79,6 +87,15 @@ public:
|
|||
return TracingFS.get();
|
||||
}
|
||||
|
||||
// MaxNumOfByNameQueries is the upper limit of the number of names the by-name
|
||||
// scanning API (computeDependenciesByName) can drain per call. At the time of
|
||||
// this commit, the estimated number of total unique importable names is
|
||||
// around 3000 from Apple's SDKs. We usually import them in parallel, so it is
|
||||
// unlikely that all names are scanned by the same worker. Therefore the 64k
|
||||
// (20x our estimate) size is sufficient to hold the unique source locations
|
||||
// to report diagnostics per worker.
|
||||
static const int32_t MaxNumOfByNameQueries = 1 << 16;
|
||||
|
||||
private:
|
||||
/// The parent dependency scanning service.
|
||||
DependencyScanningService &Service;
|
||||
|
|
@ -89,7 +106,7 @@ private:
|
|||
/// The tracing VFS overlaid on top of the base VFS.
|
||||
IntrusiveRefCntPtr<llvm::vfs::TracingFileSystem> TracingFS;
|
||||
|
||||
friend tooling::CompilerInstanceWithContext;
|
||||
friend class CompilerInstanceWithContext;
|
||||
};
|
||||
} // end namespace dependencies
|
||||
} // end namespace clang
|
||||
|
|
|
|||
|
|
@ -50,6 +50,10 @@ void addLinkerCompressDebugSectionsOption(const ToolChain &TC,
|
|||
const llvm::opt::ArgList &Args,
|
||||
llvm::opt::ArgStringList &CmdArgs);
|
||||
|
||||
void renderDebugInfoCompressionArgs(const llvm::opt::ArgList &Args,
|
||||
llvm::opt::ArgStringList &CmdArgs,
|
||||
const Driver &D, const ToolChain &TC);
|
||||
|
||||
void claimNoWarnArgs(const llvm::opt::ArgList &Args);
|
||||
|
||||
bool addSanitizerRuntimes(const ToolChain &TC, const llvm::opt::ArgList &Args,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "clang/Basic/Cuda.h"
|
||||
#include "clang/Driver/Driver.h"
|
||||
#include "llvm/TargetParser/NVPTXTargetParser.h"
|
||||
#include <bitset>
|
||||
|
||||
namespace clang {
|
||||
|
|
@ -28,9 +29,9 @@ private:
|
|||
std::string IncludePath;
|
||||
llvm::StringMap<std::string> LibDeviceMap;
|
||||
|
||||
// CUDA architectures for which we have raised an error in
|
||||
// CheckCudaVersionSupportsArch.
|
||||
mutable std::bitset<(int)OffloadArch::LAST> ArchsWithBadVersion;
|
||||
// NVIDIA architectures (indexed by GPUKind) for which we have raised an error
|
||||
// in CheckCudaVersionSupportsArch.
|
||||
mutable std::bitset<llvm::NVPTX::GK_LAST + 1> ArchsWithBadVersion;
|
||||
|
||||
public:
|
||||
CudaInstallationDetector(const Driver &D, const llvm::Triple &HostTriple,
|
||||
|
|
|
|||
|
|
@ -5074,9 +5074,18 @@ struct FormatStyle {
|
|||
/// # include "A-util.h" # include "A.inc"
|
||||
/// \endcode
|
||||
bool IgnoreExtension;
|
||||
/// Whether or not includes are sorted by natural ordering i.e., whether
|
||||
/// embedded runs of digits are compared as numbers rather than sequences of
|
||||
/// characters.
|
||||
/// \code
|
||||
/// true: false:
|
||||
/// #include "A2.h" vs. #include "A10.h"
|
||||
/// #include "A10.h" #include "A2.h"
|
||||
/// \endcode
|
||||
bool Natural;
|
||||
bool operator==(const SortIncludesOptions &R) const {
|
||||
return Enabled == R.Enabled && IgnoreCase == R.IgnoreCase &&
|
||||
IgnoreExtension == R.IgnoreExtension;
|
||||
IgnoreExtension == R.IgnoreExtension && Natural == R.Natural;
|
||||
}
|
||||
bool operator!=(const SortIncludesOptions &R) const {
|
||||
return !(*this == R);
|
||||
|
|
@ -5590,6 +5599,30 @@ struct FormatStyle {
|
|||
/// \version 3.4
|
||||
SpacesInAnglesStyle SpacesInAngles;
|
||||
|
||||
/// Styles for controlling spacing after ``/*`` and before ``*/`` in block
|
||||
/// comments.
|
||||
enum SpacesInBlockCommentsStyle : int8_t {
|
||||
/// Remove spaces after ``/*`` and before ``*/``.
|
||||
/// \code
|
||||
/// /*comment*/
|
||||
/// \endcode
|
||||
SIBCS_Never,
|
||||
/// Add spaces after ``/*`` and before ``*/``.
|
||||
/// \code
|
||||
/// /* comment */
|
||||
/// \endcode
|
||||
SIBCS_Always,
|
||||
/// Leave existing spaces unchanged.
|
||||
SIBCS_Leave
|
||||
};
|
||||
|
||||
/// The SpacesInBlockCommentsStyle to use for ordinary block comments.
|
||||
/// Documentation comments such as ``/** ... */`` and ``/*! ... */``
|
||||
/// and parameter comments ending with ``=`` before the closing ``*/`` are
|
||||
/// left unchanged.
|
||||
/// \version 24
|
||||
SpacesInBlockCommentsStyle SpacesInBlockComments;
|
||||
|
||||
/// If ``true``, spaces will be inserted around if/for/switch/while
|
||||
/// conditions.
|
||||
/// This option is **deprecated**. See ``InConditionalStatements`` of
|
||||
|
|
@ -6241,6 +6274,7 @@ struct FormatStyle {
|
|||
SpaceInEmptyBraces == R.SpaceInEmptyBraces &&
|
||||
SpacesBeforeTrailingComments == R.SpacesBeforeTrailingComments &&
|
||||
SpacesInAngles == R.SpacesInAngles &&
|
||||
SpacesInBlockComments == R.SpacesInBlockComments &&
|
||||
SpacesInContainerLiterals == R.SpacesInContainerLiterals &&
|
||||
SpacesInLineCommentPrefix.Minimum ==
|
||||
R.SpacesInLineCommentPrefix.Minimum &&
|
||||
|
|
|
|||
|
|
@ -342,6 +342,10 @@ public:
|
|||
/// is read.
|
||||
virtual void PragmaAssumeNonNullEnd(SourceLocation Loc) {}
|
||||
|
||||
/// Callback invoked when a \#pragma clang __set_pp_state directive is read.
|
||||
virtual void PragmaSetPPState(SourceLocation Loc, IdentifierInfo *MacroName,
|
||||
std::uint64_t Value) {}
|
||||
|
||||
/// Called by Preprocessor::HandleMacroExpandedIdentifier when a
|
||||
/// macro invocation is found.
|
||||
virtual void MacroExpands(const Token &MacroNameTok,
|
||||
|
|
@ -700,6 +704,12 @@ public:
|
|||
Second->PragmaAssumeNonNullEnd(Loc);
|
||||
}
|
||||
|
||||
void PragmaSetPPState(SourceLocation Loc, IdentifierInfo *MacroName,
|
||||
std::uint64_t Value) override {
|
||||
First->PragmaSetPPState(Loc, MacroName, Value);
|
||||
Second->PragmaSetPPState(Loc, MacroName, Value);
|
||||
}
|
||||
|
||||
void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
|
||||
SourceRange Range, const MacroArgs *Args) override {
|
||||
First->MacroExpands(MacroNameTok, MD, Range, Args);
|
||||
|
|
|
|||
|
|
@ -2549,6 +2549,15 @@ public:
|
|||
/// in ""'s.
|
||||
bool GetIncludeFilenameSpelling(SourceLocation Loc,StringRef &Buffer);
|
||||
|
||||
/// Turn the specified lexer token into a fully checked and spelled
|
||||
/// filename, e.g. as an operand of \#line and \#.
|
||||
///
|
||||
/// The caller is expected to provide a buffer that is large enough to hold
|
||||
/// the spelling of the filename, but is also expected to handle the case
|
||||
/// when this method decides to use a different buffer.
|
||||
///
|
||||
void GetLineDirectiveFilenameSpelling(SourceLocation Loc, StringRef &Buffer);
|
||||
|
||||
/// Given a "foo" or \<foo> reference, look up the indicated file.
|
||||
///
|
||||
/// Returns std::nullopt on failure. \p isAngled indicates whether the file
|
||||
|
|
@ -2818,6 +2827,7 @@ private:
|
|||
|
||||
public:
|
||||
std::optional<std::uint64_t> getStdLibCxxVersion();
|
||||
void setStdLibCxxVersion(std::uint64_t Version);
|
||||
bool NeedsStdLibCxxWorkaroundBefore(std::uint64_t FixedVersion);
|
||||
|
||||
private:
|
||||
|
|
@ -2978,6 +2988,9 @@ private:
|
|||
// Pragmas.
|
||||
void HandlePragmaDirective(PragmaIntroducer Introducer);
|
||||
|
||||
// Cached identifiers used to implement __set_pp_state.
|
||||
IdentifierInfo *Ident__GLIBCXX__;
|
||||
|
||||
public:
|
||||
void HandlePragmaOnce(Token &OnceTok);
|
||||
void HandlePragmaMark(Token &MarkTok);
|
||||
|
|
@ -2989,8 +3002,13 @@ public:
|
|||
void HandlePragmaIncludeAlias(Token &Tok);
|
||||
void HandlePragmaModuleBuild(Token &Tok);
|
||||
void HandlePragmaHdrstop(Token &Tok);
|
||||
void HandlePragmaSetPPState(PragmaIntroducer Introducer, Token &Tok);
|
||||
IdentifierInfo *ParsePragmaPushOrPopMacro(Token &Tok);
|
||||
|
||||
/// Check whether this is a macro name that can be used as an argument to
|
||||
/// '#pragma clang __set_pp_state'.
|
||||
bool isPragmaSetPPStateMacro(IdentifierInfo *II);
|
||||
|
||||
// Return true and store the first token only if any CommentHandler
|
||||
// has inserted some tokens and getCommentRetentionState() is false.
|
||||
bool HandleComment(Token &result, SourceRange Comment);
|
||||
|
|
|
|||
|
|
@ -4301,11 +4301,11 @@ def fno_openmp_target_new_runtime : Flag<["-"], "fno-openmp-target-new-runtime">
|
|||
Group<f_Group>, Flags<[HelpHidden]>, Visibility<[ClangOption, CC1Option]>;
|
||||
def fopenmp_target_fast : Flag<["-"], "fopenmp-target-fast">,
|
||||
Group<f_Group>, Flags<[NoArgumentUnused, HelpHidden]>,
|
||||
Visibility<[ClangOption]>,
|
||||
Visibility<[ClangOption, FlangOption]>,
|
||||
HelpText<"Assert common GPU usage patterns to enable OpenMP runtime optimizations">;
|
||||
def fno_openmp_target_fast : Flag<["-"], "fno-openmp-target-fast">,
|
||||
Group<f_Group>, Flags<[NoArgumentUnused, HelpHidden]>,
|
||||
Visibility<[ClangOption]>;
|
||||
Visibility<[ClangOption, FlangOption]>;
|
||||
defm openmp_optimistic_collapse : BoolFOption<"openmp-optimistic-collapse",
|
||||
LangOpts<"OpenMPOptimisticCollapse">, DefaultFalse,
|
||||
PosFlag<SetTrue, [], [ClangOption, CC1Option]>,
|
||||
|
|
@ -5307,8 +5307,10 @@ def gmodules : Flag <["-"], "gmodules">, Group<gN_Group>,
|
|||
" or precompiled headers">;
|
||||
def gno_modules : Flag <["-"], "gno-modules">, Group<g_flags_Group>;
|
||||
def gz_EQ : Joined<["-"], "gz=">, Group<g_flags_Group>,
|
||||
Visibility<[ClangOption, FlangOption]>,
|
||||
HelpText<"DWARF debug sections compression type">;
|
||||
def gz : Flag<["-"], "gz">, Alias<gz_EQ>, AliasArgs<["zlib"]>, Group<g_flags_Group>;
|
||||
def gz : Flag<["-"], "gz">, Alias<gz_EQ>, AliasArgs<["zlib"]>,
|
||||
Visibility<[ClangOption, FlangOption]>, Group<g_flags_Group>;
|
||||
def gembed_source : Flag<["-"], "gembed-source">, Group<g_flags_Group>,
|
||||
Visibility<[ClangOption, CC1Option]>,
|
||||
HelpText<"Embed source text in DWARF debug sections">,
|
||||
|
|
@ -7950,6 +7952,12 @@ def dwarf_debug_flags : Separate<["-"], "dwarf-debug-flags">,
|
|||
MarshallingInfoString<CodeGenOpts<"DwarfDebugFlags">>;
|
||||
def dwarf_version_EQ : Joined<["-"], "dwarf-version=">,
|
||||
MarshallingInfoInt<CodeGenOpts<"DwarfVersion">>;
|
||||
def compress_debug_sections_EQ : Joined<["-", "--"], "compress-debug-sections=">,
|
||||
HelpText<"DWARF debug sections compression type">, Values<"none,zlib,zstd">,
|
||||
NormalizedValuesScope<"llvm::DebugCompressionType">, NormalizedValues<["None", "Zlib", "Zstd"]>,
|
||||
MarshallingInfoEnum<CodeGenOpts<"CompressDebugSections">, "None">;
|
||||
def compress_debug_sections : Flag<["-", "--"], "compress-debug-sections">,
|
||||
Alias<compress_debug_sections_EQ>, AliasArgs<["zlib"]>;
|
||||
|
||||
} // let Visibility = [CC1Option, CC1AsOption, FC1Option]
|
||||
|
||||
|
|
@ -7969,12 +7977,6 @@ def debugger_tuning_EQ : Joined<["-"], "debugger-tuning=">,
|
|||
Values<"gdb,lldb,sce,dbx">,
|
||||
NormalizedValuesScope<"llvm::DebuggerKind">, NormalizedValues<["GDB", "LLDB", "SCE", "DBX"]>,
|
||||
MarshallingInfoEnum<CodeGenOpts<"DebuggerTuning">, "Default">;
|
||||
def compress_debug_sections_EQ : Joined<["-", "--"], "compress-debug-sections=">,
|
||||
HelpText<"DWARF debug sections compression type">, Values<"none,zlib,zstd">,
|
||||
NormalizedValuesScope<"llvm::DebugCompressionType">, NormalizedValues<["None", "Zlib", "Zstd"]>,
|
||||
MarshallingInfoEnum<CodeGenOpts<"CompressDebugSections">, "None">;
|
||||
def compress_debug_sections : Flag<["-", "--"], "compress-debug-sections">,
|
||||
Alias<compress_debug_sections_EQ>, AliasArgs<["zlib"]>;
|
||||
def mno_exec_stack : Flag<["-"], "mnoexecstack">,
|
||||
HelpText<"Mark the file as not needing an executable stack">,
|
||||
MarshallingInfoFlag<CodeGenOpts<"NoExecStack">>;
|
||||
|
|
|
|||
|
|
@ -277,6 +277,12 @@ class Parser : public CodeCompletionHandler {
|
|||
/// Implementations are in Parser.cpp
|
||||
///@{
|
||||
|
||||
private:
|
||||
/// Prepare the parser and its components.
|
||||
///
|
||||
/// The lack of initialization can lead to missing functionality.
|
||||
void Initialize();
|
||||
|
||||
public:
|
||||
friend class ColonProtectionRAIIObject;
|
||||
friend class PoisonSEHIdentifiersRAIIObject;
|
||||
|
|
@ -304,10 +310,6 @@ public:
|
|||
typedef OpaquePtr<DeclGroupRef> DeclGroupPtrTy;
|
||||
typedef OpaquePtr<TemplateName> TemplateTy;
|
||||
|
||||
/// Initialize - Warm up the parser.
|
||||
///
|
||||
void Initialize();
|
||||
|
||||
/// Parse the first top-level declaration in a translation unit.
|
||||
///
|
||||
/// \verbatim
|
||||
|
|
|
|||
|
|
@ -66,6 +66,10 @@ private:
|
|||
Policy PolicyOverrides;
|
||||
void clearOverrides();
|
||||
|
||||
/// Caches results for getPolicyInEffectAt().
|
||||
/// Flushed whenever a diagnostic pragma changes severities.
|
||||
llvm::DenseMap<const void *, Policy> PolicyCache[4];
|
||||
|
||||
/// \name Statistics
|
||||
/// @{
|
||||
|
||||
|
|
@ -134,6 +138,9 @@ public:
|
|||
// will override the policy used to issue warnings.
|
||||
Policy &getPolicyOverrides() { return PolicyOverrides; }
|
||||
|
||||
/// Drop cached getPolicyInEffectAt() results (diagnostic state changed).
|
||||
void clearPolicyCache();
|
||||
|
||||
void PrintStats() const;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -879,6 +879,8 @@ public:
|
|||
/// is known.
|
||||
bool AfterParameterList = true;
|
||||
|
||||
bool BeforeCompoundStatement = true;
|
||||
|
||||
ParmVarDecl *ExplicitObjectParameter = nullptr;
|
||||
|
||||
/// Source range covering the lambda introducer [...].
|
||||
|
|
|
|||
|
|
@ -35,12 +35,12 @@
|
|||
#include "clang/AST/TypeLoc.h"
|
||||
#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h"
|
||||
#include "clang/Basic/AttrSubjectMatchRules.h"
|
||||
#include "clang/Basic/BuiltinTraits.h"
|
||||
#include "clang/Basic/Builtins.h"
|
||||
#include "clang/Basic/CapturedStmt.h"
|
||||
#include "clang/Basic/Cuda.h"
|
||||
#include "clang/Basic/DiagnosticSema.h"
|
||||
#include "clang/Basic/ExceptionSpecificationType.h"
|
||||
#include "clang/Basic/ExpressionTraits.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "clang/Basic/Lambda.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
|
|
@ -54,7 +54,6 @@
|
|||
#include "clang/Basic/StackExhaustionHandler.h"
|
||||
#include "clang/Basic/TemplateKinds.h"
|
||||
#include "clang/Basic/TokenKinds.h"
|
||||
#include "clang/Basic/TypeTraits.h"
|
||||
#include "clang/Sema/AnalysisBasedWarnings.h"
|
||||
#include "clang/Sema/Attr.h"
|
||||
#include "clang/Sema/CleanupInfo.h"
|
||||
|
|
@ -157,6 +156,7 @@ enum class OverloadCandidateParamOrder : char;
|
|||
enum OverloadCandidateRewriteKind : unsigned;
|
||||
class OverloadCandidateSet;
|
||||
class Preprocessor;
|
||||
struct APINotesSelectorDiagnosticState;
|
||||
class SemaAMDGPU;
|
||||
class SemaARM;
|
||||
class SemaAVR;
|
||||
|
|
@ -1313,6 +1313,8 @@ public:
|
|||
SourceManager &SourceMgr;
|
||||
api_notes::APINotesManager APINotes;
|
||||
|
||||
std::unique_ptr<APINotesSelectorDiagnosticState> APINotesSelectorDiagnostics;
|
||||
|
||||
/// A RAII object to enter scope of a compound statement.
|
||||
class CompoundScopeRAII {
|
||||
public:
|
||||
|
|
@ -1665,6 +1667,10 @@ public:
|
|||
/// Apply the 'Type:' annotation to the specified declaration
|
||||
void ApplyAPINotesType(Decl *D, StringRef TypeString);
|
||||
|
||||
/// Diagnose exact API notes selectors that were not matched by any
|
||||
/// declaration processed in this translation unit.
|
||||
void DiagnoseUnusedAPINotesSelectors();
|
||||
|
||||
/// Whether APINotes should be gathered for all applicable Swift language
|
||||
/// versions, without being applied. Leaving clients of the current module
|
||||
/// to select and apply the correct version.
|
||||
|
|
@ -3580,7 +3586,7 @@ public:
|
|||
|
||||
/// A cache of the flags available in enumerations with the flag_enum
|
||||
/// attribute.
|
||||
mutable llvm::DenseMap<const EnumDecl *, llvm::APInt> FlagBitsCache;
|
||||
llvm::DenseMap<const EnumDecl *, llvm::APInt> FlagBitsCache;
|
||||
|
||||
/// A cache of enumerator values for enums checked by -Wassign-enum.
|
||||
llvm::DenseMap<const EnumDecl *, llvm::SmallVector<llvm::APSInt>>
|
||||
|
|
|
|||
|
|
@ -691,7 +691,8 @@ public:
|
|||
|
||||
/// ParseObjCSelectorExpression - Build selector expression for \@selector
|
||||
ExprResult ParseObjCSelectorExpression(Selector Sel, SourceLocation AtLoc,
|
||||
SourceLocation SelLoc,
|
||||
SourceLocation SelKWLoc,
|
||||
SourceLocation SelNameLoc,
|
||||
SourceLocation LParenLoc,
|
||||
SourceLocation RParenLoc,
|
||||
bool WarnMultipleSelectors);
|
||||
|
|
|
|||
|
|
@ -1012,12 +1012,12 @@ public:
|
|||
SourceLocation LParenLoc,
|
||||
SourceLocation MLoc, SourceLocation KindLoc,
|
||||
SourceLocation EndLoc);
|
||||
/// Called on well-formed 'update' clause.
|
||||
OMPClause *ActOnOpenMPUpdateClause(OpenMPDependClauseKind Kind,
|
||||
SourceLocation KindLoc,
|
||||
SourceLocation StartLoc,
|
||||
SourceLocation LParenLoc,
|
||||
SourceLocation EndLoc);
|
||||
/// Called on well-formed 'update_depend_objects' clause.
|
||||
OMPClause *ActOnOpenMPUpdateDependObjectsClause(OpenMPDependClauseKind Kind,
|
||||
SourceLocation KindLoc,
|
||||
SourceLocation StartLoc,
|
||||
SourceLocation LParenLoc,
|
||||
SourceLocation EndLoc);
|
||||
/// Called on well-formed 'holds' clause.
|
||||
OMPClause *ActOnOpenMPHoldsClause(Expr *E, SourceLocation StartLoc,
|
||||
SourceLocation LParenLoc,
|
||||
|
|
|
|||
|
|
@ -75,8 +75,8 @@ public:
|
|||
|
||||
/// Last function called on the visitor, no further calls to VisitNode
|
||||
/// would follow.
|
||||
virtual void finalizeVisitor(BugReporterContext &BRC,
|
||||
const ExplodedNode *EndPathNode,
|
||||
virtual void finalizeVisitor(const ExplodedNode *EndPathNode,
|
||||
BugReporterContext &BRC,
|
||||
PathSensitiveBugReport &BR);
|
||||
|
||||
/// Provide custom definition for the final diagnostic piece on the
|
||||
|
|
@ -84,8 +84,8 @@ public:
|
|||
///
|
||||
/// NOTE that this function can be implemented on at most one used visitor,
|
||||
/// and otherwise it crahes at runtime.
|
||||
virtual PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC,
|
||||
const ExplodedNode *N,
|
||||
virtual PathDiagnosticPieceRef getEndPath(const ExplodedNode *N,
|
||||
BugReporterContext &BRC,
|
||||
PathSensitiveBugReport &BR);
|
||||
|
||||
virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
|
||||
|
|
@ -541,7 +541,7 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *N,
|
||||
void finalizeVisitor(const ExplodedNode *N, BugReporterContext &BRC,
|
||||
PathSensitiveBugReport &BR) override;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ public:
|
|||
BugReporterContext &BRC,
|
||||
PathSensitiveBugReport &BR) override;
|
||||
|
||||
void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *EndPathNode,
|
||||
void finalizeVisitor(const ExplodedNode *EndPathNode, BugReporterContext &BRC,
|
||||
PathSensitiveBugReport &BR) override;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ class CoreEngine {
|
|||
|
||||
public:
|
||||
using BlocksExhausted =
|
||||
std::vector<std::pair<BlockEdge, const ExplodedNode *>>;
|
||||
std::vector<std::pair<BlockEntrance, const ExplodedNode *>>;
|
||||
|
||||
using BlocksAborted =
|
||||
std::vector<std::pair<const CFGBlock *, const ExplodedNode *>>;
|
||||
|
|
|
|||
|
|
@ -388,8 +388,8 @@ public:
|
|||
ExplodedNode *Pred, ExplodedNodeSet &Dst);
|
||||
|
||||
/// Called by CoreEngine when processing the entrance of a CFGBlock.
|
||||
void processCFGBlockEntrance(const BlockEdge &L, const BlockEntrance &BE,
|
||||
NodeBuilder &Builder, ExplodedNode *Pred);
|
||||
void processCFGBlockEntrance(const BlockEntrance &BE, NodeBuilder &Builder,
|
||||
ExplodedNode *Pred);
|
||||
|
||||
void runCheckersForBlockEntrance(const BlockEntrance &Entrance,
|
||||
ExplodedNode *Pred, ExplodedNodeSet &Dst);
|
||||
|
|
|
|||
|
|
@ -478,20 +478,8 @@ private:
|
|||
static void computeAdjustment(SymbolRef &Sym, llvm::APSInt &Adjustment);
|
||||
};
|
||||
|
||||
/// Try to simplify a given symbolic expression based on the constraints in
|
||||
/// State. This is needed because the Environment bindings are not getting
|
||||
/// updated when a new constraint is added to the State. If the symbol is
|
||||
/// simplified to a non-symbol (e.g. to a constant) then the original symbol
|
||||
/// is returned. We use this function in the family of assumeSymNE/EQ/LT/../GE
|
||||
/// functions where we can work only with symbols. Use the other function
|
||||
/// (simplifyToSVal) if you are interested in a simplification that may yield
|
||||
/// a concrete constant value.
|
||||
SymbolRef simplify(ProgramStateRef State, SymbolRef Sym);
|
||||
|
||||
/// Try to simplify a given symbolic expression's associated `SVal` based on the
|
||||
/// constraints in State. This is very similar to `simplify`, but this function
|
||||
/// always returns the simplified SVal. The simplified SVal might be a single
|
||||
/// constant (i.e. `ConcreteInt`).
|
||||
/// constraints in State.
|
||||
SVal simplifyToSVal(ProgramStateRef State, SymbolRef Sym);
|
||||
|
||||
} // namespace ento
|
||||
|
|
|
|||
|
|
@ -101,16 +101,21 @@ public:
|
|||
dependencies::LookupModuleOutputCallback LookupModuleOutput,
|
||||
std::optional<llvm::MemoryBufferRef> TUBuffer = std::nullopt);
|
||||
|
||||
/// Given a compilation context specified via the Clang driver command-line,
|
||||
/// gather modular dependencies of module with the given name, and return the
|
||||
/// information needed for explicit build.
|
||||
/// TODO: this method should be removed as soon as Swift and our C-APIs adopt
|
||||
/// CompilerInstanceWithContext. We are keeping it here so that it is easier
|
||||
/// to coordinate with Swift and C-API changes.
|
||||
llvm::Expected<dependencies::TranslationUnitDeps> getModuleDependencies(
|
||||
StringRef ModuleName, ArrayRef<std::string> CommandLine, StringRef CWD,
|
||||
const llvm::DenseSet<dependencies::ModuleID> &AlreadySeen,
|
||||
dependencies::DependencyActionController &Controller);
|
||||
/// By-name scanning given a Clang command-line. The scanning context is
|
||||
/// initialized once and reused for each name pulled from
|
||||
/// \p getNextName until it returns std::nullopt. Results flow to
|
||||
/// \p DepConsumer (with per-name status via finishQuery); diagnostics flow to
|
||||
/// \p DiagConsumer.
|
||||
///
|
||||
/// \returns true if the scanning context initialized successfully and all
|
||||
/// scans succeeded. Query the DepConsumer for the state of each individual
|
||||
/// scan.
|
||||
bool getByNameDependencies(
|
||||
StringRef CWD, ArrayRef<std::string> CommandLine,
|
||||
DiagnosticConsumer &DiagConsumer,
|
||||
dependencies::DependencyActionController &Controller,
|
||||
llvm::function_ref<std::optional<std::string>()> getNextName,
|
||||
dependencies::DependencyConsumer &DepConsumer);
|
||||
|
||||
/// Returns the worker tracing VFS, if it was requested via the service.
|
||||
llvm::vfs::TracingFileSystem *getWorkerTracingVFS() const {
|
||||
|
|
@ -119,8 +124,6 @@ public:
|
|||
|
||||
private:
|
||||
dependencies::DependencyScanningWorker Worker;
|
||||
|
||||
friend class CompilerInstanceWithContext;
|
||||
};
|
||||
|
||||
/// Run the dependency scanning worker for the given driver or frontend
|
||||
|
|
@ -141,110 +144,6 @@ bool computeDependencies(
|
|||
dependencies::DependencyActionController &Controller,
|
||||
DiagnosticConsumer &DiagConsumer,
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS = nullptr);
|
||||
|
||||
class CompilerInstanceWithContext {
|
||||
// Context
|
||||
dependencies::DependencyScanningWorker &Worker;
|
||||
llvm::StringRef CWD;
|
||||
std::vector<std::string> CommandLine;
|
||||
|
||||
// Context - Diagnostics engine.
|
||||
DiagnosticConsumer *DiagConsumer = nullptr;
|
||||
std::unique_ptr<dependencies::DiagnosticsEngineWithDiagOpts>
|
||||
DiagEngineWithCmdAndOpts;
|
||||
std::unique_ptr<dependencies::TextDiagnosticsPrinterWithOutput>
|
||||
DiagPrinterWithOS;
|
||||
|
||||
// Context - compiler invocation
|
||||
std::unique_ptr<CompilerInvocation> OriginalInvocation;
|
||||
|
||||
// Context - output options
|
||||
std::unique_ptr<DependencyOutputOptions> OutputOpts;
|
||||
|
||||
// Context - stable directory handling
|
||||
llvm::SmallVector<StringRef> StableDirs;
|
||||
dependencies::PrebuiltModulesAttrsMap PrebuiltModuleASTMap;
|
||||
|
||||
// Compiler Instance
|
||||
std::unique_ptr<CompilerInstance> CIPtr;
|
||||
|
||||
// Source location offset.
|
||||
int32_t SrcLocOffset = 0;
|
||||
|
||||
CompilerInstanceWithContext(dependencies::DependencyScanningWorker &Worker,
|
||||
StringRef CWD,
|
||||
const std::vector<std::string> &CMD)
|
||||
: Worker(Worker), CWD(CWD), CommandLine(CMD) {};
|
||||
|
||||
bool initialize(dependencies::DependencyActionController &Controller,
|
||||
std::unique_ptr<dependencies::DiagnosticsEngineWithDiagOpts>
|
||||
DiagEngineWithDiagOpts,
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS);
|
||||
|
||||
public:
|
||||
/// @brief Initialize the tool's compiler instance from the commandline.
|
||||
/// The compiler instance only takes a `-cc1` job, so this method
|
||||
/// builds the `-cc1` job from the CommandLine input.
|
||||
/// @param Tool The dependency scanning tool whose compiler instance
|
||||
/// with context is initialized.
|
||||
/// @param CWD The current working directory.
|
||||
/// @param CommandLine This command line may be a driver command or a cc1
|
||||
/// command.
|
||||
/// @param DC A diagnostics consumer to report error if the initialization
|
||||
/// fails.
|
||||
static std::optional<CompilerInstanceWithContext> initializeFromCommandline(
|
||||
DependencyScanningTool &Tool, StringRef CWD,
|
||||
ArrayRef<std::string> CommandLine,
|
||||
dependencies::DependencyActionController &Controller,
|
||||
DiagnosticConsumer &DC);
|
||||
|
||||
/// @brief Initializing the context and the compiler instance.
|
||||
/// This method must be called before calling
|
||||
/// computeDependenciesByNameWithContext.
|
||||
/// @param CWD The current working directory used during the scan.
|
||||
/// @param CommandLine The commandline used for the scan.
|
||||
/// @return Error if the initializaiton fails.
|
||||
static llvm::Expected<CompilerInstanceWithContext>
|
||||
initializeOrError(DependencyScanningTool &Tool, StringRef CWD,
|
||||
ArrayRef<std::string> CommandLine,
|
||||
dependencies::DependencyActionController &Controller);
|
||||
|
||||
bool
|
||||
computeDependencies(StringRef ModuleName,
|
||||
dependencies::DependencyConsumer &Consumer,
|
||||
dependencies::DependencyActionController &Controller);
|
||||
|
||||
/// @brief Computes the dependeny for the module named ModuleName.
|
||||
/// @param ModuleName The name of the module for which this method computes
|
||||
///. dependencies.
|
||||
/// @param AlreadySeen This stores modules which have previously been
|
||||
/// reported. Use the same instance for all calls to this
|
||||
/// function for a single \c DependencyScanningTool in a
|
||||
/// single build. Note that this parameter is not part of
|
||||
/// the context because it can be shared across different
|
||||
/// worker threads and each worker thread may update it.
|
||||
/// @param LookupModuleOutput This function is called to fill in
|
||||
/// "-fmodule-file=", "-o" and other output
|
||||
/// arguments for dependencies.
|
||||
/// @return An instance of \c TranslationUnitDeps if the scan is successful.
|
||||
/// Otherwise it returns an error.
|
||||
llvm::Expected<dependencies::TranslationUnitDeps>
|
||||
computeDependenciesByNameOrError(
|
||||
StringRef ModuleName,
|
||||
const llvm::DenseSet<dependencies::ModuleID> &AlreadySeen,
|
||||
dependencies::DependencyActionController &Controller);
|
||||
|
||||
// MaxNumOfQueries is the upper limit of the number of names the by-name
|
||||
// scanning API (computeDependencies) can support after a
|
||||
// CompilerInstanceWithContext is initialized. At the time of this commit, the
|
||||
// estimated number of total unique importable names is around 3000 from
|
||||
// Apple's SDKs. We usually import them in parallel, so it is unlikely that
|
||||
// all names are all scanned by the same dependency scanning worker. Therefore
|
||||
// the 64k (20x bigger than our estimate) size is sufficient to hold the
|
||||
// unique source locations to report diagnostics per worker.
|
||||
static const int32_t MaxNumOfQueries = 1 << 16;
|
||||
};
|
||||
|
||||
} // end namespace tooling
|
||||
} // end namespace clang
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ const uint16_t VERSION_MINOR = 41; // 39 for BoundsSafety;
|
|||
const uint8_t kSwiftConforms = 1;
|
||||
const uint8_t kSwiftDoesNotConform = 2;
|
||||
|
||||
using IdentifierID = llvm::PointerEmbeddedInt<unsigned, 31>;
|
||||
using IdentifierIDField = llvm::BCVBR<16>;
|
||||
|
||||
using SelectorID = llvm::PointerEmbeddedInt<unsigned, 31>;
|
||||
|
|
@ -365,47 +364,6 @@ constexpr uint8_t FunctionKeyHasParameterSelector = 0x01;
|
|||
constexpr unsigned FunctionTableKeyBaseLength =
|
||||
sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint16_t);
|
||||
|
||||
struct FunctionTableKey {
|
||||
uint32_t parentContextID;
|
||||
uint32_t nameID;
|
||||
std::optional<llvm::SmallVector<IdentifierID, 2>> parameterTypeIDs;
|
||||
|
||||
FunctionTableKey() : parentContextID(-1), nameID(-1) {}
|
||||
|
||||
FunctionTableKey(uint32_t ParentContextID, uint32_t NameID)
|
||||
: parentContextID(ParentContextID), nameID(NameID) {}
|
||||
|
||||
FunctionTableKey(uint32_t ParentContextID, uint32_t NameID,
|
||||
const llvm::SmallVectorImpl<IdentifierID> &ParameterTypeIDs)
|
||||
: parentContextID(ParentContextID), nameID(NameID) {
|
||||
parameterTypeIDs.emplace(ParameterTypeIDs.begin(), ParameterTypeIDs.end());
|
||||
}
|
||||
|
||||
FunctionTableKey(std::optional<Context> ParentCtx, IdentifierID NameID)
|
||||
: parentContextID(ParentCtx ? ParentCtx->id.Value
|
||||
: static_cast<uint32_t>(-1)),
|
||||
nameID(NameID) {}
|
||||
|
||||
FunctionTableKey(std::optional<Context> ParentCtx, IdentifierID NameID,
|
||||
const llvm::SmallVectorImpl<IdentifierID> &ParameterTypeIDs)
|
||||
: parentContextID(ParentCtx ? ParentCtx->id.Value
|
||||
: static_cast<uint32_t>(-1)),
|
||||
nameID(NameID) {
|
||||
parameterTypeIDs.emplace(ParameterTypeIDs.begin(), ParameterTypeIDs.end());
|
||||
}
|
||||
|
||||
llvm::hash_code hashValue() const {
|
||||
auto Hash = llvm::hash_combine(parentContextID, nameID,
|
||||
static_cast<bool>(parameterTypeIDs));
|
||||
if (parameterTypeIDs) {
|
||||
Hash = llvm::hash_combine(Hash, parameterTypeIDs->size());
|
||||
for (IdentifierID TypeID : *parameterTypeIDs)
|
||||
Hash = llvm::hash_combine(Hash, static_cast<unsigned>(TypeID));
|
||||
}
|
||||
return Hash;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename GetIdentifierFn>
|
||||
std::optional<FunctionTableKey>
|
||||
getFunctionKeyImpl(uint32_t ParentContextID, llvm::StringRef Name,
|
||||
|
|
@ -438,13 +396,6 @@ getFunctionKeyImpl(uint32_t ParentContextID, llvm::StringRef Name,
|
|||
return FunctionTableKey(ParentContextID, *NameID, ParameterTypeIDs);
|
||||
}
|
||||
|
||||
inline bool operator==(const FunctionTableKey &lhs,
|
||||
const FunctionTableKey &rhs) {
|
||||
return lhs.parentContextID == rhs.parentContextID &&
|
||||
lhs.nameID == rhs.nameID &&
|
||||
lhs.parameterTypeIDs == rhs.parameterTypeIDs;
|
||||
}
|
||||
|
||||
} // namespace api_notes
|
||||
} // namespace clang
|
||||
|
||||
|
|
@ -492,18 +443,6 @@ template <> struct DenseMapInfo<clang::api_notes::SingleDeclTableKey> {
|
|||
}
|
||||
};
|
||||
|
||||
template <> struct DenseMapInfo<clang::api_notes::FunctionTableKey> {
|
||||
static unsigned
|
||||
getHashValue(const clang::api_notes::FunctionTableKey &value) {
|
||||
return value.hashValue();
|
||||
}
|
||||
|
||||
static bool isEqual(const clang::api_notes::FunctionTableKey &lhs,
|
||||
const clang::api_notes::FunctionTableKey &rhs) {
|
||||
return lhs == rhs;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -15,10 +15,14 @@
|
|||
#include "clang/APINotes/APINotesReader.h"
|
||||
#include "APINotesFormat.h"
|
||||
#include "clang/APINotes/Types.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/Hashing.h"
|
||||
#include "llvm/Bitstream/BitstreamReader.h"
|
||||
#include "llvm/Support/DJB.h"
|
||||
#include "llvm/Support/OnDiskHashTable.h"
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace clang {
|
||||
namespace api_notes {
|
||||
|
|
@ -758,6 +762,9 @@ public:
|
|||
/// The identifier table.
|
||||
std::unique_ptr<SerializedIdentifierTable> IdentifierTable;
|
||||
|
||||
/// Lazy reverse lookup cache from identifier ID to string.
|
||||
std::optional<llvm::DenseMap<uint32_t, llvm::StringRef>> IdentifierStrings;
|
||||
|
||||
using SerializedContextIDTable =
|
||||
llvm::OnDiskIterableChainedHashTable<ContextIDTableInfo>;
|
||||
|
||||
|
|
@ -833,6 +840,17 @@ public:
|
|||
/// optional if the string is unknown.
|
||||
std::optional<IdentifierID> getIdentifier(llvm::StringRef Str);
|
||||
|
||||
/// Retrieve the identifier string for the given ID, or an empty optional if
|
||||
/// the ID is unknown.
|
||||
std::optional<llvm::StringRef> getIdentifierString(IdentifierID ID);
|
||||
|
||||
/// Collect exact parameter selector keys stored in the given function-like
|
||||
/// table.
|
||||
template <typename TableT>
|
||||
void collectExactFunctionParameterSelectors(
|
||||
TableT &Table,
|
||||
llvm::SmallVectorImpl<APINotesFunctionSelectorKey> &Selectors);
|
||||
|
||||
/// Retrieve the selector ID for the given selector, or an empty
|
||||
/// optional if the string is unknown.
|
||||
std::optional<SelectorID> getSelector(ObjCSelectorRef Selector);
|
||||
|
|
@ -893,6 +911,54 @@ APINotesReader::Implementation::getIdentifier(llvm::StringRef Str) {
|
|||
return *Known;
|
||||
}
|
||||
|
||||
std::optional<llvm::StringRef>
|
||||
APINotesReader::Implementation::getIdentifierString(IdentifierID ID) {
|
||||
if (!IdentifierTable)
|
||||
return std::nullopt;
|
||||
|
||||
if (ID == IdentifierID(0))
|
||||
return llvm::StringRef();
|
||||
|
||||
if (!IdentifierStrings) {
|
||||
IdentifierStrings.emplace();
|
||||
// keys() and data() iterate over the same serialized entries in lockstep.
|
||||
// The serialized hash-table order is not guaranteed to be identifier-ID
|
||||
// order, so keep an explicit ID-to-string map rather than indexing a vector
|
||||
// by ID.
|
||||
auto Identifiers = IdentifierTable->keys();
|
||||
auto IDs = IdentifierTable->data();
|
||||
auto Identifier = Identifiers.begin();
|
||||
auto KnownID = IDs.begin();
|
||||
auto IdentifierEnd = Identifiers.end();
|
||||
auto KnownIDEnd = IDs.end();
|
||||
for (; Identifier != IdentifierEnd && KnownID != KnownIDEnd;
|
||||
++Identifier, ++KnownID)
|
||||
IdentifierStrings->try_emplace(static_cast<uint32_t>(*KnownID),
|
||||
*Identifier);
|
||||
}
|
||||
|
||||
auto Known = IdentifierStrings->find(static_cast<uint32_t>(ID));
|
||||
if (Known == IdentifierStrings->end())
|
||||
return std::nullopt;
|
||||
return Known->second;
|
||||
}
|
||||
|
||||
template <typename TableT>
|
||||
void APINotesReader::Implementation::collectExactFunctionParameterSelectors(
|
||||
TableT &Table,
|
||||
llvm::SmallVectorImpl<APINotesFunctionSelectorKey> &Selectors) {
|
||||
static_assert(std::is_same_v<TableT, SerializedGlobalFunctionTable> ||
|
||||
std::is_same_v<TableT, SerializedCXXMethodTable>);
|
||||
constexpr bool IsCXXMethod = std::is_same_v<TableT, SerializedCXXMethodTable>;
|
||||
|
||||
for (const FunctionTableKey &Key : Table.keys()) {
|
||||
if (!Key.parameterTypeIDs)
|
||||
continue;
|
||||
|
||||
Selectors.push_back(APINotesFunctionSelectorKey{Key, IsCXXMethod});
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<FunctionTableKey>
|
||||
APINotesReader::Implementation::getFunctionKey(uint32_t ParentContextID,
|
||||
llvm::StringRef Name) {
|
||||
|
|
@ -2351,6 +2417,26 @@ auto APINotesReader::lookupCXXMethod(ContextID CtxID, llvm::StringRef Name,
|
|||
return lookupCXXMethodImpl(CtxID, Name, Parameters);
|
||||
}
|
||||
|
||||
std::optional<APINotesFunctionSelectorKey>
|
||||
APINotesReader::getCXXMethodSelectorKey(ContextID CtxID, llvm::StringRef Name) {
|
||||
std::optional<FunctionTableKey> Key =
|
||||
Implementation->getFunctionKey(CtxID.Value, Name);
|
||||
if (!Key)
|
||||
return std::nullopt;
|
||||
return APINotesFunctionSelectorKey{*Key, /*IsCXXMethod=*/true};
|
||||
}
|
||||
|
||||
std::optional<APINotesFunctionSelectorKey>
|
||||
APINotesReader::getCXXMethodSelectorKey(
|
||||
ContextID CtxID, llvm::StringRef Name,
|
||||
llvm::ArrayRef<std::string> Parameters) {
|
||||
std::optional<FunctionTableKey> Key =
|
||||
Implementation->getFunctionKey(CtxID.Value, Name, Parameters);
|
||||
if (!Key)
|
||||
return std::nullopt;
|
||||
return APINotesFunctionSelectorKey{*Key, /*IsCXXMethod=*/true};
|
||||
}
|
||||
|
||||
auto APINotesReader::lookupCXXMethodImpl(ContextID CtxID, llvm::StringRef Name)
|
||||
-> VersionedInfo<CXXMethodInfo> {
|
||||
if (!Implementation->CXXMethodTable)
|
||||
|
|
@ -2418,6 +2504,55 @@ auto APINotesReader::lookupGlobalFunction(
|
|||
return lookupGlobalFunctionImpl(Name, Parameters, Ctx);
|
||||
}
|
||||
|
||||
std::optional<APINotesFunctionSelectorKey>
|
||||
APINotesReader::getGlobalFunctionSelectorKey(llvm::StringRef Name,
|
||||
std::optional<Context> Ctx) {
|
||||
std::optional<FunctionTableKey> Key =
|
||||
Implementation->getFunctionKey(Ctx, Name);
|
||||
if (!Key)
|
||||
return std::nullopt;
|
||||
return APINotesFunctionSelectorKey{*Key, /*IsCXXMethod=*/false};
|
||||
}
|
||||
|
||||
std::optional<APINotesFunctionSelectorKey>
|
||||
APINotesReader::getGlobalFunctionSelectorKey(
|
||||
llvm::StringRef Name, llvm::ArrayRef<std::string> Parameters,
|
||||
std::optional<Context> Ctx) {
|
||||
std::optional<FunctionTableKey> Key =
|
||||
Implementation->getFunctionKey(Ctx, Name, Parameters);
|
||||
if (!Key)
|
||||
return std::nullopt;
|
||||
return APINotesFunctionSelectorKey{*Key, /*IsCXXMethod=*/false};
|
||||
}
|
||||
|
||||
void APINotesReader::collectExactFunctionParameterSelectors(
|
||||
llvm::SmallVectorImpl<APINotesFunctionSelectorKey> &Selectors) {
|
||||
if (Implementation->GlobalFunctionTable)
|
||||
Implementation->collectExactFunctionParameterSelectors(
|
||||
*Implementation->GlobalFunctionTable, Selectors);
|
||||
if (Implementation->CXXMethodTable)
|
||||
Implementation->collectExactFunctionParameterSelectors(
|
||||
*Implementation->CXXMethodTable, Selectors);
|
||||
}
|
||||
|
||||
std::optional<llvm::SmallVector<std::string, 4>>
|
||||
APINotesReader::getParameterSelectorSpellingsForDiagnostics(
|
||||
const APINotesFunctionSelectorKey &Key) {
|
||||
if (!Key.Key.parameterTypeIDs)
|
||||
return std::nullopt;
|
||||
|
||||
llvm::SmallVector<std::string, 4> ParameterSpellings;
|
||||
ParameterSpellings.reserve(Key.Key.parameterTypeIDs->size());
|
||||
for (IdentifierID TypeID : *Key.Key.parameterTypeIDs) {
|
||||
std::optional<llvm::StringRef> TypeName =
|
||||
Implementation->getIdentifierString(TypeID);
|
||||
if (!TypeName)
|
||||
return std::nullopt;
|
||||
ParameterSpellings.push_back(TypeName->str());
|
||||
}
|
||||
return ParameterSpellings;
|
||||
}
|
||||
|
||||
auto APINotesReader::lookupGlobalFunctionImpl(llvm::StringRef Name,
|
||||
std::optional<Context> Ctx)
|
||||
-> VersionedInfo<GlobalFunctionInfo> {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
namespace clang {
|
||||
namespace api_notes {
|
||||
|
||||
LLVM_DUMP_METHOD void CommonEntityInfo::dump(llvm::raw_ostream &OS) const {
|
||||
if (Unavailable)
|
||||
OS << "[Unavailable] (" << UnavailableMsg << ")" << ' ';
|
||||
|
|
|
|||
|
|
@ -18,11 +18,16 @@
|
|||
#include "clang/APINotes/Types.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "llvm/Support/VersionTuple.h"
|
||||
#include "llvm/Support/YAMLTraits.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -788,6 +793,22 @@ bool clang::api_notes::parseAndDumpAPINotes(StringRef YI,
|
|||
namespace {
|
||||
using namespace api_notes;
|
||||
|
||||
static std::string
|
||||
getFunctionSelectorKey(llvm::StringRef Name,
|
||||
llvm::ArrayRef<llvm::StringRef> Parameters) {
|
||||
llvm::SmallString<64> Key;
|
||||
llvm::raw_svector_ostream OS(Key);
|
||||
auto AppendKeyPart = [&OS](llvm::StringRef Part) {
|
||||
OS << Part.size() << ':' << Part;
|
||||
};
|
||||
|
||||
AppendKeyPart(Name);
|
||||
OS << ';';
|
||||
for (llvm::StringRef Parameter : Parameters)
|
||||
AppendKeyPart(Parameter);
|
||||
return Key.str().str();
|
||||
}
|
||||
|
||||
class YAMLConverter {
|
||||
const Module &M;
|
||||
APINotesWriter Writer;
|
||||
|
|
@ -1162,11 +1183,24 @@ public:
|
|||
Writer.addField(TagCtxID, Field.Name, FI, SwiftVersion);
|
||||
}
|
||||
|
||||
llvm::StringSet<> KnownMethodSelectors;
|
||||
for (const auto &CXXMethod : T.Methods) {
|
||||
auto WhereParameters = getWhereParameters(CXXMethod);
|
||||
if (!WhereParameters.first)
|
||||
continue;
|
||||
|
||||
if (WhereParameters.second) {
|
||||
if (!KnownMethodSelectors
|
||||
.insert(getFunctionSelectorKey(CXXMethod.Name,
|
||||
*WhereParameters.second))
|
||||
.second) {
|
||||
emitError(llvm::Twine("multiple API notes entries for C++ method '") +
|
||||
CXXMethod.Name + "' with Where.Parameters " +
|
||||
formatAPINotesParameterSelector(*WhereParameters.second));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
CXXMethodInfo MI;
|
||||
convertFunction(CXXMethod, MI);
|
||||
if (WhereParameters.second)
|
||||
|
|
@ -1243,13 +1277,26 @@ public:
|
|||
|
||||
// Write all global functions.
|
||||
llvm::StringSet<> KnownNameOnlyFunctions;
|
||||
llvm::StringSet<> KnownFunctionSelectors;
|
||||
for (const auto &Function : TLItems.Functions) {
|
||||
auto WhereParameters = getWhereParameters(Function);
|
||||
if (!WhereParameters.first)
|
||||
continue;
|
||||
|
||||
// Check for duplicate name-only global functions. Selector-aware
|
||||
// duplicate diagnostics are handled by a later overload-matching PR.
|
||||
if (WhereParameters.second) {
|
||||
if (!KnownFunctionSelectors
|
||||
.insert(getFunctionSelectorKey(Function.Name,
|
||||
*WhereParameters.second))
|
||||
.second) {
|
||||
emitError(
|
||||
llvm::Twine("multiple API notes entries for global function '") +
|
||||
Function.Name + "' with Where.Parameters " +
|
||||
formatAPINotesParameterSelector(*WhereParameters.second));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for duplicate name-only global functions.
|
||||
if (!WhereParameters.second &&
|
||||
!KnownNameOnlyFunctions.insert(Function.Name).second) {
|
||||
emitError(llvm::Twine("multiple definitions of global function '") +
|
||||
|
|
|
|||
|
|
@ -4038,7 +4038,7 @@ bool Compiler<Emitter>::VisitOffsetOfExpr(const OffsetOfExpr *E) {
|
|||
if (IndexT == PT_IntAP || IndexT == PT_IntAPS) {
|
||||
if (!this->visit(ArrayIndexExpr))
|
||||
return false;
|
||||
if (!this->emitCastNoOverflow(IndexT, E))
|
||||
if (!this->emitCastAPToOffsetIndex(IndexT, E))
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -476,7 +476,7 @@ bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc,
|
|||
// If we're evaluating the initializer for a constexpr variable in C23, we may
|
||||
// only read other contexpr variables. Abort here since this one isn't
|
||||
// constexpr.
|
||||
if (const auto *VD = dyn_cast_if_present<VarDecl>(S.EvaluatingDecl);
|
||||
if (const auto *VD = S.EvaluatingDecl;
|
||||
VD && VD->isConstexpr() && S.getLangOpts().C23)
|
||||
return Invalid(S, OpPC);
|
||||
|
||||
|
|
@ -1572,10 +1572,7 @@ static bool diagnoseTypeIdField(InterpState &S, CodePtr OpPC,
|
|||
Ptr.asTypeidPointer().TypeInfoType->getAsRecordDecl());
|
||||
if (!R)
|
||||
return false;
|
||||
const Record::Field *Field =
|
||||
llvm::find_if(R->fields(), [=](const Record::Field &F) -> bool {
|
||||
return F.Offset == Offset;
|
||||
});
|
||||
const Record::Field *Field = R->findField(Offset);
|
||||
if (!Field)
|
||||
return false;
|
||||
|
||||
|
|
@ -1892,8 +1889,8 @@ bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
|
|||
if (!CheckCallDepth(S, OpPC))
|
||||
return false;
|
||||
|
||||
auto Memory = new char[InterpFrame::allocSize(Func)];
|
||||
auto NewFrame = new (Memory) InterpFrame(S, Func, S.PC, VarArgSize);
|
||||
auto *Memory = new char[InterpFrame::allocSize(Func)];
|
||||
auto *NewFrame = new (Memory) InterpFrame(S, Func, S.PC, VarArgSize);
|
||||
InterpFrame *FrameBefore = S.Current;
|
||||
S.Current = NewFrame;
|
||||
|
||||
|
|
@ -1985,8 +1982,8 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
|
|||
if (!CheckCallDepth(S, OpPC))
|
||||
return cleanup();
|
||||
|
||||
auto Memory = new char[InterpFrame::allocSize(Func)];
|
||||
auto NewFrame = new (Memory) InterpFrame(S, Func, S.PC, VarArgSize);
|
||||
auto *Memory = new char[InterpFrame::allocSize(Func)];
|
||||
auto *NewFrame = new (Memory) InterpFrame(S, Func, S.PC, VarArgSize);
|
||||
InterpFrame *FrameBefore = S.Current;
|
||||
S.Current = NewFrame;
|
||||
|
||||
|
|
@ -2064,6 +2061,7 @@ static bool getDynamicDecl(InterpState &S, CodePtr OpPC, PtrView TypePtr,
|
|||
return DynamicDecl != nullptr;
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct DynamicCastResult {
|
||||
UnsignedOrNone Offset = std::nullopt;
|
||||
bool Ambiguous = false;
|
||||
|
|
@ -2088,6 +2086,7 @@ struct DynamicCastResult {
|
|||
}
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// Walk UP the type hierarchy, starting at the decl of R to find Needle.
|
||||
static DynamicCastResult findRecordBase(const ASTContext &Ctx, const Record *R,
|
||||
|
|
@ -2286,7 +2285,7 @@ bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
|
|||
return false;
|
||||
assert(DynamicDecl);
|
||||
|
||||
const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl());
|
||||
const auto *StaticDecl = Func->getParentDecl();
|
||||
const auto *InitialFunction = cast<CXXMethodDecl>(Callee);
|
||||
const CXXMethodDecl *Overrider;
|
||||
|
||||
|
|
@ -3080,7 +3079,7 @@ static bool castBackMemberPointer(InterpState &S,
|
|||
unsigned OldPathLength = MemberPtr.getPathLength();
|
||||
unsigned NewPathLength = OldPathLength - 1;
|
||||
bool IsDerivedMember = NewPathLength != 0;
|
||||
auto NewPath = S.allocMemberPointerPath(NewPathLength);
|
||||
auto *NewPath = S.allocMemberPointerPath(NewPathLength);
|
||||
std::copy_n(MemberPtr.path(), NewPathLength, NewPath);
|
||||
|
||||
S.Stk.push<MemberPointer>(MemberPtr.atInstanceBase(BaseOffset, NewPathLength,
|
||||
|
|
@ -3096,7 +3095,7 @@ static bool appendToMemberPointer(InterpState &S,
|
|||
unsigned OldPathLength = MemberPtr.getPathLength();
|
||||
unsigned NewPathLength = OldPathLength + 1;
|
||||
|
||||
auto NewPath = S.allocMemberPointerPath(NewPathLength);
|
||||
auto *NewPath = S.allocMemberPointerPath(NewPathLength);
|
||||
std::copy_n(MemberPtr.path(), OldPathLength, NewPath);
|
||||
NewPath[OldPathLength] = cast<CXXRecordDecl>(BaseDecl);
|
||||
|
||||
|
|
@ -3180,7 +3179,7 @@ bool CopyMemberPtrPath(InterpState &S, const RecordDecl *Entry,
|
|||
unsigned OldPathLength = MemberPtr.getPathLength();
|
||||
unsigned NewPathLength = OldPathLength + 1;
|
||||
|
||||
auto NewPath = S.allocMemberPointerPath(NewPathLength);
|
||||
auto *NewPath = S.allocMemberPointerPath(NewPathLength);
|
||||
std::copy_n(MemberPtr.path(), OldPathLength, NewPath);
|
||||
NewPath[OldPathLength] = cast<CXXRecordDecl>(Entry);
|
||||
|
||||
|
|
@ -3223,7 +3222,7 @@ bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth,
|
|||
}
|
||||
|
||||
// FIXME: Would be nice to generate this instead of hardcoding it here.
|
||||
constexpr bool OpReturns(Opcode Op) {
|
||||
[[maybe_unused]] static constexpr bool OpReturns(Opcode Op) {
|
||||
return Op == OP_RetVoid || Op == OP_RetValue || Op == OP_NoRet ||
|
||||
Op == OP_RetSint8 || Op == OP_RetUint8 || Op == OP_RetSint16 ||
|
||||
Op == OP_RetUint16 || Op == OP_RetSint32 || Op == OP_RetUint32 ||
|
||||
|
|
|
|||
|
|
@ -2910,10 +2910,11 @@ bool CastAPS(InterpState &S, uint32_t BitWidth) {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Cast an AP integer to Sint64, failing constant evaluation if the value is
|
||||
// negative or too large to fit (i.e. truncation would change the value).
|
||||
// Cast an AP integer to Sint64 for use as an offsetof array index, failing
|
||||
// constant evaluation if the value is negative or too large to fit in Sint64
|
||||
// (i.e. truncation would change the value).
|
||||
template <PrimType Name, class T = typename PrimConv<Name>::T>
|
||||
bool CastNoOverflow(InterpState &S, CodePtr OpPC) {
|
||||
bool CastAPToOffsetIndex(InterpState &S, CodePtr OpPC) {
|
||||
T Source = S.Stk.pop<T>();
|
||||
APSInt Val = Source.toAPSInt();
|
||||
if (Val.isNegative() || Val.getActiveBits() > 63)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue