@@ -131,7 +131,7 @@ | |||
/bolt/ @aaupov @maksfb @rafaelauler @ayermolo @dcci @yota9 | /bolt/ @aaupov @maksfb @rafaelauler @ayermolo @dcci @yota9 | ||
# Bazel build system. | # Bazel build system. | ||
-/utils/bazel/ @rupprecht @keith | +/utils/bazel/ @rupprecht @keith @aaronmondal | ||
# InstallAPI and TextAPI | # InstallAPI and TextAPI | ||
/llvm/**/TextAPI/ @cyndyishida | /llvm/**/TextAPI/ @cyndyishida |
@@ -20,24 +20,31 @@ on: | |||
jobs: | jobs: | ||
build-ci-container: | build-ci-container: | ||
if: github.repository_owner | if: github.repository_owner | ||
- runs-on: depot-ubuntu-22.04-16 | + runs-on: ${{ matrix.runs-on }} | ||
- outputs: | + strategy: | ||
- container-name: ${{ steps.vars.outputs.container-name }} | + matrix: | ||
- container-name-agent: ${{ steps.vars.outputs.container-name-agent }} | + include: | ||
- container-name-tag: ${{ steps.vars.outputs.container-name-tag }} | + # The arch names should match the names used on dockerhub. | ||
- container-name-agent-tag: ${{ steps.vars.outputs.container-name-agent-tag }} | + # See https://github.com/docker-library/official-images#architectures-other-than-amd64 | ||
- container-filename: ${{ steps.vars.outputs.container-filename }} | + - arch: amd64 | ||
- container-agent-filename: ${{ steps.vars.outputs.container-agent-filename }} | + runs-on: depot-ubuntu-22.04-16 | ||
+ - arch: arm64v8 | |||
+ runs-on: depot-ubuntu-22.04-arm-16 | |||
steps: | steps: | ||
- name: Checkout LLVM | - name: Checkout LLVM | ||
uses: actions/checkout@v4 | uses: actions/checkout@v4 | ||
with: | with: | ||
sparse-checkout: .github/workflows/containers/github-action-ci/ | sparse-checkout: .github/workflows/containers/github-action-ci/ | ||
+ # podman is not installed by default on the ARM64 images. | |||
+ - name: Install Podman | |||
+ if: runner.arch == 'ARM64' | |||
+ run: | | |||
+ sudo apt-get install podman | |||
- name: Write Variables | - name: Write Variables | ||
id: vars | id: vars | ||
run: | | run: | | ||
- tag=`date +%s` | + tag=$(git rev-parse --short=12 HEAD) | ||
- container_name="ghcr.io/$GITHUB_REPOSITORY_OWNER/ci-ubuntu-22.04" | + container_name="ghcr.io/$GITHUB_REPOSITORY_OWNER/${{ matrix.arch }}/ci-ubuntu-22.04" | ||
echo "container-name=$container_name" >> $GITHUB_OUTPUT | echo "container-name=$container_name" >> $GITHUB_OUTPUT | ||
echo "container-name-agent=$container_name-agent" >> $GITHUB_OUTPUT | echo "container-name-agent=$container_name-agent" >> $GITHUB_OUTPUT | ||
echo "container-name-tag=$container_name:$tag" >> $GITHUB_OUTPUT | echo "container-name-tag=$container_name:$tag" >> $GITHUB_OUTPUT | ||
@@ -61,7 +68,7 @@ jobs: | |||
- name: Upload container image | - name: Upload container image | ||
uses: actions/upload-artifact@v4 | uses: actions/upload-artifact@v4 | ||
with: | with: | ||
- name: container | + name: container-${{ matrix.arch }} | ||
path: "*.tar" | path: "*.tar" | ||
retention-days: 14 | retention-days: 14 | ||
@@ -84,18 +91,29 @@ jobs: | |||
steps: | steps: | ||
- name: Download container | - name: Download container | ||
uses: actions/download-artifact@v4 | uses: actions/download-artifact@v4 | ||
- with: | |||
- name: container | |||
- name: Push Container | - name: Push Container | ||
run: | | run: | | ||
- podman load -i ${{ needs.build-ci-container.outputs.container-filename }} | + function push_container { | ||
- podman tag ${{ needs.build-ci-container.outputs.container-name-tag }} ${{ needs.build-ci-container.outputs.container-name }}:latest | + image_name=$1 | ||
+ latest_name=$(echo $image_name | sed 's/:[a-f0-9]\+$/:latest/g') | |||
+ podman tag $image_name $latest_name | |||
+ echo "Pushing $image_name ..." | |||
+ podman push $image_name | |||
+ echo "Pushing $latest_name ..." | |||
+ podman push $latest_name | |||
+ } | |||
+ | |||
podman login -u ${{ github.actor }} -p $GITHUB_TOKEN ghcr.io | podman login -u ${{ github.actor }} -p $GITHUB_TOKEN ghcr.io | ||
- podman push ${{ needs.build-ci-container.outputs.container-name-tag }} | + for f in $(find . -iname *.tar); do | ||
- podman push ${{ needs.build-ci-container.outputs.container-name }}:latest | + image_name=$(podman load -q -i $f | sed 's/Loaded image: //g') | ||
+ push_container $image_name | |||
- podman load -i ${{ needs.build-ci-container.outputs.container-agent-filename }} | + if echo $image_name | grep '/amd64/'; then | ||
- podman tag ${{ needs.build-ci-container.outputs.container-name-agent-tag }} ${{ needs.build-ci-container.outputs.container-name-agent }}:latest | + # For amd64, create an alias with the arch component removed. | ||
- podman push ${{ needs.build-ci-container.outputs.container-name-agent-tag }} | + # This matches the convention used on dockerhub. | ||
- podman push ${{ needs.build-ci-container.outputs.container-name-agent }}:latest | + default_image_na | ||
+ podman tag $image_name $default_image_na | |||
+ push_container $default_image_na | |||
+ fi | |||
+ done |
@@ -15,6 +15,7 @@ jobs: | |||
strategy: | strategy: | ||
fail-fast: false | fail-fast: false | ||
matrix: | matrix: | ||
+ build_type: [Debug, Release, MinSizeRel] | |||
include: | include: | ||
- os: ubuntu-24.04 | - os: ubuntu-24.04 | ||
ccache-variant: sccache | ccache-variant: sccache | ||
@@ -68,7 +69,7 @@ jobs: | |||
cmake -B ${{ steps.strings.outputs.build-output-dir }} | cmake -B ${{ steps.strings.outputs.build-output-dir }} | ||
-DCMAKE_CXX_COMPI | -DCMAKE_CXX_COMPI | ||
-DCMAKE_C_COMPILE | -DCMAKE_C_COMPILE | ||
- - | + -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} | ||
-DCMAKE_C_COMPILE | -DCMAKE_C_COMPILE | ||
-DCMAKE_CXX_COMPI | -DCMAKE_CXX_COMPI | ||
-DCMAKE_INSTALL_P | -DCMAKE_INSTALL_P |
@@ -16,6 +16,7 @@ jobs: | |||
# Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. | # Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. | ||
fail-fast: false | fail-fast: false | ||
matrix: | matrix: | ||
+ build_type: [Debug, Release, MinSizeRel] | |||
include: | include: | ||
# TODO: add linux gcc when it is fixed | # TODO: add linux gcc when it is fixed | ||
- os: ubuntu-24.04 | - os: ubuntu-24.04 | ||
@@ -95,7 +96,7 @@ jobs: | |||
cmake -B ${{ steps.strings.outputs.build-output-dir }} | cmake -B ${{ steps.strings.outputs.build-output-dir }} | ||
-DCMAKE_CXX_COMPI | -DCMAKE_CXX_COMPI | ||
-DCMAKE_C_COMPILE | -DCMAKE_C_COMPILE | ||
- - | + -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} | ||
-DCMAKE_C_COMPILE | -DCMAKE_C_COMPILE | ||
-DCMAKE_CXX_COMPI | -DCMAKE_CXX_COMPI | ||
-DCMAKE_POLICY_DE | -DCMAKE_POLICY_DE |
@@ -9,7 +9,6 @@ name: Build Docker images for libc++ CI | |||
permissions: | permissions: | ||
contents: read | contents: read | ||
- packages: write | |||
on: | on: | ||
push: | push: |
@@ -5,6 +5,15 @@ permissions: | |||
on: | on: | ||
pull_request: | pull_request: | ||
+ types: | |||
+ - opened | |||
+ - synchronize | |||
+ - reopened | |||
+ # When a PR is closed, we still start this workflow, but then skip | |||
+ # all the jobs, which makes it effectively a no-op. The reason to | |||
+ # do this is that it allows us to take advantage of concurrency groups | |||
+ # to cancel in progress CI jobs whenever the PR is closed. | |||
+ - closed | |||
paths: | paths: | ||
- .github/workflows/premerge.yaml | - .github/workflows/premerge.yaml | ||
push: | push: | ||
@@ -12,13 +21,16 @@ on: | |||
- 'main' | - 'main' | ||
- 'release/**' | - 'release/**' | ||
+concurrency: | |||
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} | |||
+ cancel-in-progress: true | |||
+ | |||
jobs: | jobs: | ||
premerge-checks-linux: | premerge-checks-linux: | ||
- if: github.repository_owner | + if: >- | ||
+ github.repository_owner | |||
+ (github.event_name != 'pull_request' || github.event.action != 'closed') | |||
runs-on: llvm-premerge-linux-runners | runs-on: llvm-premerge-linux-runners | ||
- concurrency: | |||
- group: ${{ github.workflow }}-linux-${{ github.event.pull_request.number || github.sha }} | |||
- cancel-in-progress: true | |||
steps: | steps: | ||
- name: Checkout LLVM | - name: Checkout LLVM | ||
uses: actions/checkout@v4 | uses: actions/checkout@v4 | ||
@@ -73,11 +85,10 @@ jobs: | |||
./.ci/monolithic-linux.sh "$(echo ${linux_projects} | tr ' ' ';')" "$(echo ${linux_check_targ | ./.ci/monolithic-linux.sh "$(echo ${linux_projects} | tr ' ' ';')" "$(echo ${linux_check_targ | ||
premerge-checks-windows: | premerge-checks-windows: | ||
- if: github.repository_owner | + if: >- | ||
+ github.repository_owner | |||
+ (github.event_name != 'pull_request' || github.event.action != 'closed') | |||
runs-on: llvm-premerge-windows-runners | runs-on: llvm-premerge-windows-runners | ||
- concurrency: | |||
- group: ${{ github.workflow }}-windows-${{ github.event.pull_request.number || github.sha }} | |||
- cancel-in-progress: true | |||
defaults: | defaults: | ||
run: | run: | ||
shell: bash | shell: bash | ||
@@ -135,13 +146,11 @@ jobs: | |||
permerge-check-macos: | permerge-check-macos: | ||
runs-on: macos-14 | runs-on: macos-14 | ||
- concurrency: | |||
- group: ${{ github.workflow }}-macos-${{ github.event.pull_request.number || github.sha }} | |||
- cancel-in-progress: true | |||
if: >- | if: >- | ||
github.repository_owner | github.repository_owner | ||
(startswith(github.ref_name, 'release/') || | (startswith(github.ref_name, 'release/') || | ||
- startswith(github.base_ref, 'release/')) | + startswith(github.base_ref, 'release/')) && | ||
+ (github.event_name != 'pull_request' || github.event.action != 'closed') | |||
steps: | steps: | ||
- name: Checkout LLVM | - name: Checkout LLVM | ||
uses: actions/checkout@v4 | uses: actions/checkout@v4 |
@@ -58,7 +58,6 @@ jobs: | |||
target-cmake-flags: ${{ steps.vars.outputs.target-cmake-flags }} | target-cmake-flags: ${{ steps.vars.outputs.target-cmake-flags }} | ||
ccache: ${{ steps.vars.outputs.ccache }} | ccache: ${{ steps.vars.outputs.ccache }} | ||
build-flang: ${{ steps.vars.outputs.build-flang }} | build-flang: ${{ steps.vars.outputs.build-flang }} | ||
- enable-pgo: ${{ steps.vars.outputs.enable-pgo }} | |||
release-binary-basename: ${{ steps.vars.outputs.release-binary-basename }} | release-binary-basename: ${{ steps.vars.outputs.release-binary-basename }} | ||
release-binary-filename: ${{ steps.vars.outputs.release-binary-filename }} | release-binary-filename: ${{ steps.vars.outputs.release-binary-filename }} | ||
build-runs-on: ${{ steps.vars.outputs.build-runs-on }} | build-runs-on: ${{ steps.vars.outputs.build-runs-on }} | ||
@@ -130,9 +129,6 @@ jobs: | |||
echo ccache=sccache >> $GITHUB_OUTPUT | echo ccache=sccache >> $GITHUB_OUTPUT | ||
fi | fi | ||
- # Detect necessary CMake flags | |||
- echo "enable-pgo=false" >> $GITHUB_OUTPUT | |||
- target_cmake_fla | |||
# The macOS builds try to cross compile some libraries so we need to | # The macOS builds try to cross compile some libraries so we need to | ||
# add extra CMake args to disable them. | # add extra CMake args to disable them. | ||
# See https://github.com/llvm/llvm-project/issues/99767 | # See https://github.com/llvm/llvm-project/issues/99767 | ||
@@ -238,13 +234,14 @@ jobs: | |||
${{ needs.prepare.outputs.target-cmake-flags }} \ | ${{ needs.prepare.outputs.target-cmake-flags }} \ | ||
-C clang/cmake/caches/Release.cmake \ | -C clang/cmake/caches/Release.cmake \ | ||
-DBOOTSTRAP_LLVM_ | -DBOOTSTRAP_LLVM_ | ||
- - | + -DBOOTSTRAP_BOOTSTRAP_CPACK_PACKAGE_FILE_NAME="${{ needs.prepare.outputs.release-binary-basename }}" | ||
- name: Build | - name: Build | ||
shell: bash | shell: bash | ||
run: | | run: | | ||
ninja -v -C ${{ steps.setup-stage.outputs.build-prefix }}/build stage2-package | ninja -v -C ${{ steps.setup-stage.outputs.build-prefix }}/build stage2-package | ||
- | + release_dir=`find ${{ steps.setup-stage.outputs.build-prefix }}/build -iname 'stage2-bins'` | ||
+ mv $release_dir/${{ needs.prepare.outputs.release-binary-filename }} . | |||
- uses: actions/upload-artifact@26f96dfa697d77e8 | - uses: actions/upload-artifact@26f96dfa697d77e8 | ||
with: | with: | ||
@@ -259,7 +256,7 @@ jobs: | |||
shell: bash | shell: bash | ||
run: | | run: | | ||
find ${{ steps.setup-stage.outputs.build-prefix }}/build -iname ${{ needs.prepare.outputs.release-binary-filename }} -delete | find ${{ steps.setup-stage.outputs.build-prefix }}/build -iname ${{ needs.prepare.outputs.release-binary-filename }} -delete | ||
- | + find ${{ steps.setup-stage.outputs.build-prefix }}/build -iname _CPack_Packages -prune -exec rm -r {} + | ||
- name: Save Stage | - name: Save Stage | ||
uses: ./workflows-main/.github/workflows/release-binaries-save-stage | uses: ./workflows-main/.github/workflows/release-binaries-save-stage |
@@ -89,20 +89,10 @@ jobs: | |||
needs: | needs: | ||
- validate-tag | - validate-tag | ||
- release-create | - release-create | ||
- strategy: | + uses: ./.github/workflows/release-binaries-all.yml | ||
- fail-fast: false | |||
- matrix: | |||
- runs-on: | |||
- - ubuntu-22.04 | |||
- - windows-2022 | |||
- - macos-13 | |||
- - macos-14 | |||
- | |||
- uses: ./.github/workflows/release-binaries.yml | |||
with: | with: | ||
release-version: ${{ needs.validate-tag.outputs.release-version }} | release-version: ${{ needs.validate-tag.outputs.release-version }} | ||
upload: true | upload: true | ||
- runs-on: ${{ matrix.runs-on }} | |||
# Called workflows don't have access to secrets by default, so we need to explicitly pass secrets that we use. | # Called workflows don't have access to secrets by default, so we need to explicitly pass secrets that we use. | ||
secrets: | secrets: | ||
RELEASE_TASKS_US | RELEASE_TASKS_US |
@@ -1435,6 +1435,17 @@ public: | |||
bool PrintRelocations | bool PrintRelocations | ||
StringRef Endl = "\n") const; | StringRef Endl = "\n") const; | ||
+ /// Print data when embedded in the instruction stream keeping the format | |||
+ /// similar to printInstruction | |||
+ void printData(raw_ostream &OS, ArrayRef<uint8_t> Data, | |||
+ uint64_t Offset) const; | |||
+ | |||
+ /// Extract data from the binary corresponding to [Address, Address + Size) | |||
+ /// range. Return an empty ArrayRef if the address range does not belong to | |||
+ /// any section in the binary, crosses a section boundary, or falls into a | |||
+ /// virtual section. | |||
+ ArrayRef<uint8_t> extractData(uint64_t Address, uint64_t Size) const; | |||
+ | |||
/// Print a range of instructions. | /// Print a range of instructions. | ||
template <typename Itr> | template <typename Itr> | ||
uint64_t | uint64_t |
@@ -2060,6 +2060,11 @@ public: | |||
return Islands ? Islands->getAlignment() : 1; | return Islands ? Islands->getAlignment() : 1; | ||
} | } | ||
+ /// If there is a constant island in the range [StartOffset, EndOffset), | |||
+ /// return its address. | |||
+ std::optional<uint64_t> getIslandInRange | |||
+ uint64_t EndOffset) const; | |||
+ | |||
uint64_t | uint64_t | ||
estimateConstant | estimateConstant | ||
if (!Islands) | if (!Islands) |
@@ -1759,7 +1759,11 @@ void BinaryContext::p | |||
dwarf::toString(CU->getUnitDIE().find(dwarf::DW_AT_name), nullptr); | dwarf::toString(CU->getUnitDIE().find(dwarf::DW_AT_name), nullptr); | ||
if (std::optional<uint64_t> DWOID = CU->getDWOId()) { | if (std::optional<uint64_t> DWOID = CU->getDWOId()) { | ||
auto Iter = DWOCUs.find(*DWOID); | auto Iter = DWOCUs.find(*DWOID); | ||
- assert(Iter != DWOCUs.end() && "DWO CU was not found."); | + if (Iter == DWOCUs.end()) { | ||
+ this->errs() << "BOLT-ERROR: DWO CU was not found for " << Name | |||
+ << '\n'; | |||
+ exit(1); | |||
+ } | |||
Name = dwarf::toString( | Name = dwarf::toString( | ||
Iter->second->getUnitDIE().find(dwarf::DW_AT_name), nullptr); | Iter->second->getUnitDIE().find(dwarf::DW_AT_name), nullptr); | ||
} | } | ||
@@ -1942,6 +1946,43 @@ static void printDebugInfo(r | |||
OS << " discriminator:" << Row.Discriminator; | OS << " discriminator:" << Row.Discriminator; | ||
} | } | ||
+ArrayRef<uint8_t> BinaryContext::extractData(uint64_t Address, | |||
+ uint64_t Size) const { | |||
+ ArrayRef<uint8_t> Res; | |||
+ | |||
+ const ErrorOr<const BinarySection &> Section = getSectionForAdd | |||
+ if (!Section || Section->isVirtual()) | |||
+ return Res; | |||
+ | |||
+ if (!Section->containsRange(Address, Size)) | |||
+ return Res; | |||
+ | |||
+ auto *Bytes = | |||
+ reinterpret_cast | |||
+ return ArrayRef<uint8_t>(Bytes + Address - Section->getAddress(), Size); | |||
+} | |||
+ | |||
+void BinaryContext::printData(raw_ostream &OS, ArrayRef<uint8_t> Data, | |||
+ uint64_t Offset) const { | |||
+ DataExtractor DE(Data, AsmInfo->isLittleEndian(), | |||
+ AsmInfo->getCodePointerSi | |||
+ uint64_t DataOffset = 0; | |||
+ while (DataOffset + 4 <= Data.size()) { | |||
+ OS << format(" %08" PRIx64 ": \t.word\t0x", Offset + DataOffset); | |||
+ const auto Word = DE.getUnsigned(&DataOffset, 4); | |||
+ OS << Twine::utohexstr(Word) << '\n'; | |||
+ } | |||
+ if (DataOffset + 2 <= Data.size()) { | |||
+ OS << format(" %08" PRIx64 ": \t.short\t0x", Offset + DataOffset); | |||
+ const auto Short = DE.getUnsigned(&DataOffset, 2); | |||
+ OS << Twine::utohexstr(Short) << '\n'; | |||
+ } | |||
+ if (DataOffset + 1 == Data.size()) { | |||
+ OS << format(" %08" PRIx64 ": \t.byte\t0x%x\n", Offset + DataOffset, | |||
+ Data[DataOffset]); | |||
+ } | |||
+} | |||
+ | |||
void BinaryContext::printInstruction | void BinaryContext::printInstruction | ||
uint64_t Offset, | uint64_t Offset, | ||
const BinaryFunction *Function, | const BinaryFunction *Function, |
@@ -491,11 +491,27 @@ void BinaryFunction:: | |||
// Offset of the instruction in function. | // Offset of the instruction in function. | ||
uint64_t Offset = 0; | uint64_t Offset = 0; | ||
+ auto printConstantIsl | |||
+ assert(Start <= End && "Invalid range"); | |||
+ std::optional<uint64_t> IslandOffset = getIslandInRange | |||
+ | |||
+ if (!IslandOffset) | |||
+ return; | |||
+ | |||
+ const size_t IslandSize = getSizeOfDataInC | |||
+ BC.printData(OS, BC.extractData(getAddress() + *IslandOffset, IslandSize), | |||
+ *IslandOffset); | |||
+ }; | |||
+ | |||
if (BasicBlocks.empty() && !Instructions.empty()) { | if (BasicBlocks.empty() && !Instructions.empty()) { | ||
// Print before CFG was built. | // Print before CFG was built. | ||
+ uint64_t PrevOffset = 0; | |||
for (const std::pair<const uint32_t, MCInst> &II : Instructions) { | for (const std::pair<const uint32_t, MCInst> &II : Instructions) { | ||
Offset = II.first; | Offset = II.first; | ||
+ // Print any constant islands inbeetween the instructions. | |||
+ printConstantIsl | |||
+ | |||
// Print label if exists at this offset. | // Print label if exists at this offset. | ||
auto LI = Labels.find(Offset); | auto LI = Labels.find(Offset); | ||
if (LI != Labels.end()) { | if (LI != Labels.end()) { | ||
@@ -506,7 +522,12 @@ void BinaryFunction:: | |||
} | } | ||
BC.printInstruction | BC.printInstruction | ||
+ | |||
+ PrevOffset = Offset; | |||
} | } | ||
+ | |||
+ // Print any data at the end of the function. | |||
+ printConstantIsl | |||
} | } | ||
StringRef SplitPointMsg = ""; | StringRef SplitPointMsg = ""; | ||
@@ -1048,6 +1069,19 @@ size_t BinaryFunction:: | |||
return getSize() - Offset; | return getSize() - Offset; | ||
} | } | ||
+std::optional<uint64_t> | |||
+BinaryFunction::getIslandInRange | |||
+ uint64_t EndOffset) const { | |||
+ if (!Islands) | |||
+ return std::nullopt; | |||
+ | |||
+ auto Iter = llvm::lower_bound(Islands->DataOffsets, StartOffset); | |||
+ if (Iter != Islands->DataOffsets.end() && *Iter < EndOffset) | |||
+ return *Iter; | |||
+ | |||
+ return std::nullopt; | |||
+} | |||
+ | |||
bool BinaryFunction::isZeroPaddingAt(uint64_t Offset) const { | bool BinaryFunction::isZeroPaddingAt(uint64_t Offset) const { | ||
ArrayRef<uint8_t> FunctionData = *getData(); | ArrayRef<uint8_t> FunctionData = *getData(); | ||
uint64_t EndOfCode = getSize(); | uint64_t EndOfCode = getSize(); |
@@ -18,6 +18,7 @@ | |||
#include "llvm/Object/Archive.h" | #include "llvm/Object/Archive.h" | ||
#include "llvm/Object/ObjectFile.h" | #include "llvm/Object/ObjectFile.h" | ||
#include "llvm/Support/Path.h" | #include "llvm/Support/Path.h" | ||
+#include "llvm/Support/Program.h" | |||
#define DEBUG_TYPE "bolt-rtlib" | #define DEBUG_TYPE "bolt-rtlib" | ||
@@ -38,6 +39,23 @@ std::string RuntimeLibrary:: | |||
llvm::sys::path::append(LibPath, "lib" LLVM_LIBDIR_SUFF | llvm::sys::path::append(LibPath, "lib" LLVM_LIBDIR_SUFF | ||
} | } | ||
llvm::sys::path::append(LibPath, LibFileName); | llvm::sys::path::append(LibPath, LibFileName); | ||
+ if (!llvm::sys::fs::exists(LibPath)) { | |||
+ // If it is a symlink, check the directory that the symlink points to. | |||
+ if (llvm::sys::fs::is_symlink_file(ToolPath)) { | |||
+ SmallString<256> RealPath; | |||
+ llvm::sys::fs::real_path(ToolPath, RealPath); | |||
+ if (llvm::ErrorOr<std::string> P = | |||
+ llvm::sys::findProgramByNam | |||
+ outs() << "BOLT-INFO: library not found: " << LibPath << "\n" | |||
+ << "BOLT-INFO: " << ToolPath << " is a symlink; will look up " | |||
+ << LibFileName | |||
+ << " at the target directory that the symlink points to\n"; | |||
+ return getLibPath(*P, LibFileName); | |||
+ } | |||
+ } | |||
+ errs() << "BOLT-ERROR: library not found: " << LibPath << "\n"; | |||
+ exit(1); | |||
+ } | |||
return std::string(LibPath); | return std::string(LibPath); | ||
} | } | ||
@@ -0,0 +1,31 @@ | |||
+## Check that llvm-bolt prints data embedded in code. | |||
+ | |||
+# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o | |||
+# RUN: %clang %cflags -fno-PIC -no-pie %t.o -o %t.exe -nostdlib \ | |||
+# RUN: -fuse-ld=lld -Wl,-q | |||
+ | |||
+## Check disassembly of BOLT input. | |||
+# RUN: llvm-objdump %t.exe -d | FileCheck %s | |||
+ | |||
+# RUN: llvm-bolt %t.exe -o %t.bolt --print-disasm | FileCheck %s | |||
+ | |||
+.text | |||
+.balign 4 | |||
+ | |||
+.global _start | |||
+.type _start, %function | |||
+_start: | |||
+ mov x0, #0x0 | |||
+ .word 0x4f82e010 | |||
+ ret | |||
+ .byte 0x0, 0xff, 0x42 | |||
+# CHECK-LABEL: _start | |||
+# CHECK: mov x0, #0x0 | |||
+# CHECK-NEXT: .word 0x4f82e010 | |||
+# CHECK-NEXT: ret | |||
+# CHECK-NEXT: .short 0xff00 | |||
+# CHECK-NEXT: .byte 0x42 | |||
+.size _start, .-_start | |||
+ | |||
+## Force relocation mode. | |||
+ .reloc 0, R_AARCH64_NONE |
@@ -2,7 +2,9 @@ | |||
// REQUIRES: system-linux | // REQUIRES: system-linux | ||
-// RUN: %clangxx %cxxflags -O1 -Wl,-q,-znow %s -o %t.exe | +// RUN: %clang %cflags -fpic -shared -xc /dev/null -o %t.so | ||
+// Link against a DSO to ensure PLT entries. | |||
+// RUN: %clangxx %cxxflags -O1 -Wl,-q,-znow %s %t.so -o %t.exe | |||
// RUN: llvm-bolt %t.exe -o %t.bolt.exe --plt=all --print-only=.*main.* \ | // RUN: llvm-bolt %t.exe -o %t.bolt.exe --plt=all --print-only=.*main.* \ | ||
// RUN: --print-finalized 2>&1 | FileCheck %s | // RUN: --print-finalized 2>&1 | FileCheck %s | ||
@@ -1,6 +1,8 @@ | |||
// Verify that PLTCall optimization works. | // Verify that PLTCall optimization works. | ||
-RUN: %clang %cflags %p/../Inputs/plt-tailcall.c \ | +RUN: %clang %cflags -fpic -shared -xc /dev/null -o %t.so | ||
+// Link against a DSO to ensure PLT entries. | |||
+RUN: %clang %cflags %p/../Inputs/plt-tailcall.c %t.so \ | |||
RUN: -o %t -Wl,-q | RUN: -o %t -Wl,-q | ||
RUN: llvm-bolt %t -o %t.bolt --plt=all --print-plt --print-only=foo | FileCheck %s | RUN: llvm-bolt %t -o %t.bolt --plt=all --print-plt --print-only=foo | FileCheck %s | ||
@@ -1,7 +1,9 @@ | |||
## Ensures that a call continuation fallthrough count is set when using | ## Ensures that a call continuation fallthrough count is set when using | ||
## pre-aggregated perf data. | ## pre-aggregated perf data. | ||
-# RUN: %clangxx %cxxflags %s -o %t -Wl,-q -nostdlib | +# RUN: %clang %cflags -fpic -shared -xc /dev/null -o %t.so | ||
+## Link against a DSO to ensure PLT entries. | |||
+# RUN: %clangxx %cxxflags %s %t.so -o %t -Wl,-q -nostdlib | |||
# RUN: link_fdata %s %t %t.pa1 PREAGG | # RUN: link_fdata %s %t %t.pa1 PREAGG | ||
# RUN: link_fdata %s %t %t.pa2 PREAGG2 | # RUN: link_fdata %s %t %t.pa2 PREAGG2 | ||
# RUN: link_fdata %s %t %t.pa3 PREAGG3 | # RUN: link_fdata %s %t %t.pa3 PREAGG3 |
@@ -3,7 +3,9 @@ | |||
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o | # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o | ||
# RUN: llvm-strip --strip-unneeded %t.o | # RUN: llvm-strip --strip-unneeded %t.o | ||
-# RUN: %clangxx %cflags %t.o -o %t.exe | +# RUN: %clang %cflags -fpic -shared -xc /dev/null -o %t.so | ||
+## Link against a DSO to ensure PLT entries. | |||
+# RUN: %clangxx %cflags %t.o %t.so -o %t.exe | |||
# RUN: llvm-bolt %t.exe -o %t --reorder-blocks=cache --print-after-lowering \ | # RUN: llvm-bolt %t.exe -o %t --reorder-blocks=cache --print-after-lowering \ | ||
# RUN: --print-only=_Z10SolveCubicdd | # RUN: --print-only=_Z10SolveCubicdd | ||
# | # |
@@ -1,6 +1,8 @@ | |||
// Verify that PLTCall optimization works. | // Verify that PLTCall optimization works. | ||
-RUN: %clang %cflags %p/../Inputs/plt-tailcall.c \ | +RUN: %clang %cflags -fpic -shared -xc /dev/null -o %t.so | ||
+// Link against a DSO to ensure PLT entries. | |||
+RUN: %clang %cflags %p/../Inputs/plt-tailcall.c %t.so \ | |||
RUN: -o %t -Wl,-q | RUN: -o %t -Wl,-q | ||
RUN: llvm-bolt %t -o %t.bolt --plt=all --print-plt --print-only=foo | FileCheck %s | RUN: llvm-bolt %t -o %t.bolt --plt=all --print-plt --print-only=foo | FileCheck %s | ||
@@ -2,7 +2,9 @@ | |||
// REQUIRES: system-linux | // REQUIRES: system-linux | ||
-// RUN: %clangxx %cxxflags -O1 -Wl,-q,-znow %s -o %t.exe | +// RUN: %clang %cflags -fpic -shared -xc /dev/null -o %t.so | ||
+// Link against a DSO to ensure PLT entries. | |||
+// RUN: %clangxx %cxxflags -O1 -Wl,-q,-znow %s %t.so -o %t.exe | |||
// RUN: llvm-bolt %t.exe -o %t.bolt.exe --plt=all | // RUN: llvm-bolt %t.exe -o %t.bolt.exe --plt=all | ||
// RUN: %t.bolt.exe | // RUN: %t.bolt.exe | ||
@@ -1,14 +1,15 @@ | |||
// This test checks that the pointers to PLT are properly updated. | // This test checks that the pointers to PLT are properly updated. | ||
-// The test | +// The test uses lld and links against a DSO to ensure PLT entries. | ||
+RUN: %clang %cflags -fpic -shared -xc /dev/null -o %t.so | |||
// Non-PIE: | // Non-PIE: | ||
-RUN: %clang %cflags -no-pie %p/../Inputs/plt.c -fuse-ld=lld \ | +RUN: %clang %cflags -no-pie %p/../Inputs/plt.c %t.so -fuse-ld=lld \ | ||
RUN: -o %t.lld.exe -Wl,-q | RUN: -o %t.lld.exe -Wl,-q | ||
RUN: llvm-bolt %t.lld.exe -o %t.lld.bolt.exe --use-old-text=0 --lite=0 | RUN: llvm-bolt %t.lld.exe -o %t.lld.bolt.exe --use-old-text=0 --lite=0 | ||
RUN: %t.lld.bolt.exe | FileCheck %s | RUN: %t.lld.bolt.exe | FileCheck %s | ||
// PIE: | // PIE: | ||
-RUN: %clang %cflags -fPIC -pie %p/../Inputs/plt.c -fuse-ld=lld \ | +RUN: %clang %cflags -fPIC -pie %p/../Inputs/plt.c %t.so -fuse-ld=lld \ | ||
RUN: -o %t.lld.pie.exe -Wl,-q | RUN: -o %t.lld.pie.exe -Wl,-q | ||
RUN: llvm-bolt %t.lld.pie.exe -o %t.lld.bolt.pie.exe --use-old-text=0 --lite=0 | RUN: llvm-bolt %t.lld.pie.exe -o %t.lld.bolt.pie.exe --use-old-text=0 --lite=0 | ||
RUN: %t.lld.bolt.pie.exe | FileCheck %s | RUN: %t.lld.bolt.pie.exe | FileCheck %s |
@@ -494,18 +494,31 @@ genReferencesBlo | |||
static std::unique_ptr<TagNode> | static std::unique_ptr<TagNode> | ||
writeFileDefinit | writeFileDefinit | ||
std::optional<StringRef> RepositoryUrl = std::nullopt) { | std::optional<StringRef> RepositoryUrl = std::nullopt) { | ||
- if (!L.IsFileInRootDir | + if (!L.IsFileInRootDir && !RepositoryUrl) | ||
return std::make_unique<TagNode>( | return std::make_unique<TagNode>( | ||
HTMLTag::TAG_P, "Defined at line " + std::to_string(L.LineNumber) + | HTMLTag::TAG_P, "Defined at line " + std::to_string(L.LineNumber) + | ||
" of file " + L.Filename); | " of file " + L.Filename); | ||
SmallString<128> FileURL(*RepositoryUrl); | SmallString<128> FileURL(*RepositoryUrl); | ||
- llvm::sys::path::append( | + llvm::sys::path::append( | ||
+ FileURL, llvm::sys::path::Style::posix, | |||
+ // If we're on Windows, the file name will be in the wrong format, and | |||
+ // append won't convert the full path being appended to the correct | |||
+ // format, so we need to do that here. | |||
+ llvm::sys::path::convert_to_slash | |||
+ L.Filename, | |||
+ // The style here is the current style of the path, not the one we're | |||
+ // targeting. If the string is already in the posix style, it will do | |||
+ // nothing. | |||
+ llvm::sys::path::Style::windows)); | |||
auto Node = std::make_unique<TagNode>(HTMLTag::TAG_P); | auto Node = std::make_unique<TagNode>(HTMLTag::TAG_P); | ||
Node->Children.emplace_back(std::make_unique<TextNode>("Defined at line ")); | Node->Children.emplace_back(std::make_unique<TextNode>("Defined at line ")); | ||
auto LocNumberNode = | auto LocNumberNode = | ||
std::make_unique<TagNode>(HTMLTag::TAG_A, std::to_string(L.LineNumber)); | std::make_unique<TagNode>(HTMLTag::TAG_A, std::to_string(L.LineNumber)); | ||
// The links to a specific line in the source code use the github / | // The links to a specific line in the source code use the github / | ||
// googlesource notation so it won't work for all hosting pages. | // googlesource notation so it won't work for all hosting pages. | ||
+ // FIXME: we probably should have a configuration setting for line number | |||
+ // rendering in the HTML. For example, GitHub uses #L22, while googlesource | |||
+ // uses #22 for line numbers. | |||
LocNumberNode->Attributes.emplace_back( | LocNumberNode->Attributes.emplace_back( | ||
"href", (FileURL + "#" + std::to_string(L.LineNumber)).str()); | "href", (FileURL + "#" + std::to_string(L.LineNumber)).str()); | ||
Node->Children.emplace_back(std::move(LocNumberNode)); | Node->Children.emplace_back(std::move(LocNumberNode)); | ||
@@ -964,7 +977,7 @@ HTMLGenerator::g | |||
for (const auto &Group : FileToInfos) { | for (const auto &Group : FileToInfos) { | ||
std::error_code FileErr; | std::error_code FileErr; | ||
llvm::raw_fd_ostream InfoOS(Group.getKey(), FileErr, | llvm::raw_fd_ostream InfoOS(Group.getKey(), FileErr, | ||
- | + llvm::sys::fs::OF_Text); | ||
if (FileErr) { | if (FileErr) { | ||
return llvm::createStringErro | return llvm::createStringErro | ||
Group.getKey().str().c_str()); | Group.getKey().str().c_str()); | ||
@@ -1047,7 +1060,7 @@ static llvm::Error serializeIndex(C | |||
llvm::SmallString<128> FilePath; | llvm::SmallString<128> FilePath; | ||
llvm::sys::path::native(CDCtx.OutDirectory, FilePath); | llvm::sys::path::native(CDCtx.OutDirectory, FilePath); | ||
llvm::sys::path::append(FilePath, "index_json.js"); | llvm::sys::path::append(FilePath, "index_json.js"); | ||
- llvm::raw_fd_ostream OS(FilePath, FileErr, | + llvm::raw_fd_ostream OS(FilePath, FileErr, llvm::sys::fs::OF_Text); | ||
if (FileErr != OK) { | if (FileErr != OK) { | ||
return llvm::createStringErro | return llvm::createStringErro | ||
"error creating index file: " + | "error creating index file: " + | ||
@@ -1108,7 +1121,7 @@ static llvm::Error genIndex(const ClangDocContext &CDCtx) { | |||
llvm::SmallString<128> IndexPath; | llvm::SmallString<128> IndexPath; | ||
llvm::sys::path::native(CDCtx.OutDirectory, IndexPath); | llvm::sys::path::native(CDCtx.OutDirectory, IndexPath); | ||
llvm::sys::path::append(IndexPath, "index.html"); | llvm::sys::path::append(IndexPath, "index.html"); | ||
- llvm::raw_fd_ostream IndexOS(IndexPath, FileErr, | + llvm::raw_fd_ostream IndexOS(IndexPath, FileErr, llvm::sys::fs::OF_Text); | ||
if (FileErr != OK) { | if (FileErr != OK) { | ||
return llvm::createStringErro | return llvm::createStringErro | ||
"error creating main index: " + | "error creating main index: " + |
@@ -300,7 +300,7 @@ static llvm::Error serializeIndex(C | |||
llvm::SmallString<128> FilePath; | llvm::SmallString<128> FilePath; | ||
llvm::sys::path::native(CDCtx.OutDirectory, FilePath); | llvm::sys::path::native(CDCtx.OutDirectory, FilePath); | ||
llvm::sys::path::append(FilePath, "all_files.md"); | llvm::sys::path::append(FilePath, "all_files.md"); | ||
- llvm::raw_fd_ostream OS(FilePath, FileErr, | + llvm::raw_fd_ostream OS(FilePath, FileErr, llvm::sys::fs::OF_Text); | ||
if (FileErr) | if (FileErr) | ||
return llvm::createStringErro | return llvm::createStringErro | ||
"error creating index file: " + | "error creating index file: " + | ||
@@ -323,7 +323,7 @@ static llvm::Error genIndex(ClangDo | |||
llvm::SmallString<128> FilePath; | llvm::SmallString<128> FilePath; | ||
llvm::sys::path::native(CDCtx.OutDirectory, FilePath); | llvm::sys::path::native(CDCtx.OutDirectory, FilePath); | ||
llvm::sys::path::append(FilePath, "index.md"); | llvm::sys::path::append(FilePath, "index.md"); | ||
- llvm::raw_fd_ostream OS(FilePath, FileErr, | + llvm::raw_fd_ostream OS(FilePath, FileErr, llvm::sys::fs::OF_Text); | ||
if (FileErr) | if (FileErr) | ||
return llvm::createStringErro | return llvm::createStringErro | ||
"error creating index file: " + | "error creating index file: " + | ||
@@ -407,7 +407,7 @@ MDGenerator::gen | |||
for (const auto &Group : FileToInfos) { | for (const auto &Group : FileToInfos) { | ||
std::error_code FileErr; | std::error_code FileErr; | ||
llvm::raw_fd_ostream InfoOS(Group.getKey(), FileErr, | llvm::raw_fd_ostream InfoOS(Group.getKey(), FileErr, | ||
- | + llvm::sys::fs::OF_Text); | ||
if (FileErr) { | if (FileErr) { | ||
return llvm::createStringErro | return llvm::createStringErro | ||
Group.getKey().str().c_str()); | Group.getKey().str().c_str()); |
@@ -347,7 +347,7 @@ YAMLGenerator::g | |||
} | } | ||
std::error_code FileErr; | std::error_code FileErr; | ||
- llvm::raw_fd_ostream InfoOS(Path, FileErr, | + llvm::raw_fd_ostream InfoOS(Path, FileErr, llvm::sys::fs::OF_Text); | ||
if (FileErr) { | if (FileErr) { | ||
return llvm::createStringErro | return llvm::createStringErro | ||
Path.c_str()); | Path.c_str()); |
@@ -131,7 +131,7 @@ FuzzySymbolIndex | |||
llvm::Expected<std::unique_ptr<FuzzySymbolIndex | llvm::Expected<std::unique_ptr<FuzzySymbolIndex | ||
FuzzySymbolIndex | FuzzySymbolIndex | ||
- auto Buffer = llvm::MemoryBuffer::getFile(FilePath); | + auto Buffer = llvm::MemoryBuffer::getFile(FilePath, /*IsText=*/true); | ||
if (!Buffer) | if (!Buffer) | ||
return llvm::errorCodeToError | return llvm::errorCodeToError | ||
return std::make_unique<MemSymbolIndex>( | return std::make_unique<MemSymbolIndex>( |
@@ -22,7 +22,7 @@ namespace include_fixer { | |||
llvm::ErrorOr<std::unique_ptr<YamlSymbolIndex>> | llvm::ErrorOr<std::unique_ptr<YamlSymbolIndex>> | ||
YamlSymbolIndex::createFromFile(llvm::StringRef FilePath) { | YamlSymbolIndex::createFromFile(llvm::StringRef FilePath) { | ||
- auto Buffer = llvm::MemoryBuffer::getFile(FilePath); | + auto Buffer = llvm::MemoryBuffer::getFile(FilePath, /*IsText=*/true); | ||
if (!Buffer) | if (!Buffer) | ||
return Buffer.getError(); | return Buffer.getError(); | ||
@@ -95,7 +95,7 @@ bool Merge(llvm::Stri | |||
// Parse YAML files in parallel. | // Parse YAML files in parallel. | ||
Pool.async( | Pool.async( | ||
[&AddSymbols](std::string Path) { | [&AddSymbols](std::string Path) { | ||
- auto Buffer = llvm::MemoryBuffer::getFile(Path); | + auto Buffer = llvm::MemoryBuffer::getFile(Path, /*IsText=*/true); | ||
if (!Buffer) { | if (!Buffer) { | ||
llvm::errs() << "Can't open " << Path << "\n"; | llvm::errs() << "Can't open " << Path << "\n"; | ||
return; | return; | ||
@@ -114,7 +114,7 @@ bool Merge(llvm::Stri | |||
} | } | ||
} | } | ||
- llvm::raw_fd_ostream OS(OutputFile, EC, | + llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::OF_Text); | ||
if (EC) { | if (EC) { | ||
llvm::errs() << "Can't open '" << OutputFile << "': " << EC.message() | llvm::errs() << "Can't open '" << OutputFile << "': " << EC.message() | ||
<< '\n'; | << '\n'; |
@@ -415,7 +415,7 @@ int includeFixerMain | |||
llvm::errs() << llvm::toString(InsertStyle.takeError()) << "\n"; | llvm::errs() << llvm::toString(InsertStyle.takeError()) << "\n"; | ||
return 1; | return 1; | ||
} | } | ||
- auto Buffer = llvm::MemoryBuffer::getFile(FilePath); | + auto Buffer = llvm::MemoryBuffer::getFile(FilePath, /*IsText=*/true); | ||
if (!Buffer) { | if (!Buffer) { | ||
errs() << "Couldn't open file: " + FilePath.str() + ": " | errs() << "Couldn't open file: " + FilePath.str() + ": " | ||
<< Buffer.getError().message() + "\n"; | << Buffer.getError().message() + "\n"; |
@@ -82,7 +82,7 @@ void StringConstructo | |||
Finder->addMatcher( | Finder->addMatcher( | ||
cxxConstructExpr | cxxConstructExpr | ||
hasDeclaration(cxxMethodDecl(hasName("basic_string"))), | hasDeclaration(cxxMethodDecl(hasName("basic_string"))), | ||
- hasArgument(0, hasType(qualType(isInteger()))), | + argumentCountIs(2), hasArgument(0, hasType(qualType(isInteger()))), | ||
hasArgument(1, hasType(qualType(isInteger()))), | hasArgument(1, hasType(qualType(isInteger()))), | ||
anyOf( | anyOf( | ||
// Detect the expression: string('x', 40); | // Detect the expression: string('x', 40); | ||
@@ -102,7 +102,7 @@ void StringConstructo | |||
cxxConstructExpr | cxxConstructExpr | ||
hasDeclaration(cxxConstructorDe | hasDeclaration(cxxConstructorDe | ||
cxxRecordDecl(hasAnyName(removeNamespaces | cxxRecordDecl(hasAnyName(removeNamespaces | ||
- hasArgument(0, hasType(CharPtrType)), | + argumentCountIs(2), hasArgument(0, hasType(CharPtrType)), | ||
hasArgument(1, hasType(isInteger())), | hasArgument(1, hasType(isInteger())), | ||
anyOf( | anyOf( | ||
// Detect the expression: string("...", 0); | // Detect the expression: string("...", 0); | ||
@@ -114,7 +114,34 @@ void StringConstructo | |||
// Detect the expression: string("lit", 5) | // Detect the expression: string("lit", 5) | ||
allOf(hasArgument(0, ConstStrLiteral.bind("literal-with-length")), | allOf(hasArgument(0, ConstStrLiteral.bind("literal-with-length")), | ||
hasArgument(1, ignoringParenImp | hasArgument(1, ignoringParenImp | ||
- integerLiteral().bind( | + integerLiteral().bind("length")))))) | ||
+ .bind("constructor"), | |||
+ this); | |||
+ | |||
+ // Check the literal string constructor with char pointer, start position and | |||
+ // length parameters. [i.e. string (const char* s, size_t pos, size_t count);] | |||
+ Finder->addMatcher( | |||
+ cxxConstructExpr | |||
+ hasDeclaration(cxxConstructorDe | |||
+ cxxRecordDecl(hasAnyName(removeNamespaces | |||
+ argumentCountIs(3), hasArgument(0, hasType(CharPtrType)), | |||
+ hasArgument(1, hasType(qualType(isInteger()))), | |||
+ hasArgument(2, hasType(qualType(isInteger()))), | |||
+ anyOf( | |||
+ // Detect the expression: string("...", 1, 0); | |||
+ hasArgument(2, ZeroExpr.bind("empty-string")), | |||
+ // Detect the expression: string("...", -4, 1); | |||
+ hasArgument(1, NegativeExpr.bind("negative-pos")), | |||
+ // Detect the expression: string("...", 0, -4); | |||
+ hasArgument(2, NegativeExpr.bind("negative-length")), | |||
+ // Detect the expression: string("lit", 0, 0x1234567); | |||
+ hasArgument(2, LargeLengthExpr.bind("large-length")), | |||
+ // Detect the expression: string("lit", 1, 5) | |||
+ allOf(hasArgument(0, ConstStrLiteral.bind("literal-with-length")), | |||
+ hasArgument( | |||
+ 1, ignoringParenImp | |||
+ hasArgument(2, ignoringParenImp | |||
+ integerLiteral().bind("length")))))) | |||
.bind("constructor"), | .bind("constructor"), | ||
this); | this); | ||
@@ -155,14 +182,27 @@ void StringConstructo | |||
diag(Loc, "constructor creating an empty string"); | diag(Loc, "constructor creating an empty string"); | ||
} else if (Result.Nodes.getNodeAs<Expr>("negative-length")) { | } else if (Result.Nodes.getNodeAs<Expr>("negative-length")) { | ||
diag(Loc, "negative value used as length parameter"); | diag(Loc, "negative value used as length parameter"); | ||
+ } else if (Result.Nodes.getNodeAs<Expr>("negative-pos")) { | |||
+ diag(Loc, "negative value used as position of the " | |||
+ "first character parameter"); | |||
} else if (Result.Nodes.getNodeAs<Expr>("large-length")) { | } else if (Result.Nodes.getNodeAs<Expr>("large-length")) { | ||
if (WarnOnLargeLengt | if (WarnOnLargeLengt | ||
diag(Loc, "suspicious large length parameter"); | diag(Loc, "suspicious large length parameter"); | ||
} else if (Result.Nodes.getNodeAs<Expr>("literal-with-length")) { | } else if (Result.Nodes.getNodeAs<Expr>("literal-with-length")) { | ||
const auto *Str = Result.Nodes.getNodeAs<StringLiteral>("str"); | const auto *Str = Result.Nodes.getNodeAs<StringLiteral>("str"); | ||
- const auto * | + const auto *Length = Result.Nodes.getNodeAs<IntegerLiteral>("length"); | ||
- if ( | + if (Length->getValue().ugt(Str->getLength())) { | ||
diag(Loc, "length is bigger than string literal size"); | diag(Loc, "length is bigger than string literal size"); | ||
+ return; | |||
+ } | |||
+ if (const auto *Pos = Result.Nodes.getNodeAs<IntegerLiteral>("pos")) { | |||
+ if (Pos->getValue().uge(Str->getLength())) { | |||
+ diag(Loc, "position of the first character parameter is bigger than " | |||
+ "string literal character range"); | |||
+ } else if (Length->getValue().ugt( | |||
+ (Str->getLength() - Pos->getValue()).getZExtValue())) { | |||
+ diag(Loc, "length is bigger than remaining string literal size"); | |||
+ } | |||
} | } | ||
} else if (const auto *Ptr = Result.Nodes.getNodeAs<Expr>("from-ptr")) { | } else if (const auto *Ptr = Result.Nodes.getNodeAs<Expr>("from-ptr")) { | ||
Expr::EvalResult ConstPtr; | Expr::EvalResult ConstPtr; |
@@ -139,10 +139,8 @@ static bool areEquivalentExp | |||
return cast<BinaryOperator>(Left)->getOpcode() == | return cast<BinaryOperator>(Left)->getOpcode() == | ||
cast<BinaryOperator>(Right)->getOpcode(); | cast<BinaryOperator>(Right)->getOpcode(); | ||
case Stmt::UnaryExprOrTypeT | case Stmt::UnaryExprOrTypeT | ||
- const auto *LeftUnaryExpr = | + const auto *LeftUnaryExpr = cast<UnaryExprOrTypeTraitExpr>(Left); | ||
- | + const auto *RightUnaryExpr = cast<UnaryExprOrTypeTraitExpr>(Right); | ||
- const auto *RightUnaryExpr = | |||
- cast<UnaryExprOrTypeT | |||
if (LeftUnaryExpr->isArgumentType() && RightUnaryExpr->isArgumentType()) | if (LeftUnaryExpr->isArgumentType() && RightUnaryExpr->isArgumentType()) | ||
return LeftUnaryExpr->getKind() == RightUnaryExpr->getKind() && | return LeftUnaryExpr->getKind() == RightUnaryExpr->getKind() && | ||
LeftUnaryExpr->getArgumentType() == | LeftUnaryExpr->getArgumentType() == | ||
@@ -699,7 +697,8 @@ static bool retrieveRelation | |||
Symbol = OverloadedOperat | Symbol = OverloadedOperat | ||
OperandExpr = OverloadedOperat | OperandExpr = OverloadedOperat | ||
- Opcode = BinaryOperator::getOverloadedOpcode( | + Opcode = BinaryOperator::getOverloadedOpcode( | ||
+ OverloadedOperat | |||
if (!retrieveIntegerC | if (!retrieveIntegerC | ||
return false; | return false; | ||
@@ -728,7 +727,8 @@ static bool retrieveRelation | |||
} | } | ||
// Checks for expressions like (X == 4) && (Y != 9) | // Checks for expressions like (X == 4) && (Y != 9) | ||
-static bool areSidesBinaryConstExpressions(const BinaryOperator *&BinOp, | +static bool areSidesBinaryConstExpressions(const BinaryOperator *&BinOp, | ||
+ const ASTContext *AstCtx) { | |||
const auto *LhsBinOp = dyn_cast<BinaryOperator>(BinOp->getLHS()); | const auto *LhsBinOp = dyn_cast<BinaryOperator>(BinOp->getLHS()); | ||
const auto *RhsBinOp = dyn_cast<BinaryOperator>(BinOp->getRHS()); | const auto *RhsBinOp = dyn_cast<BinaryOperator>(BinOp->getRHS()); | ||
@@ -747,6 +747,28 @@ static bool areSidesBinaryCo | |||
return false; | return false; | ||
} | } | ||
+static bool areSidesBinaryCo | |||
+ const BinaryOperator *&BinOp, const ASTContext *AstCtx) { | |||
+ if (areSidesBinaryCo | |||
+ return true; | |||
+ | |||
+ const Expr *Lhs = BinOp->getLHS(); | |||
+ const Expr *Rhs = BinOp->getRHS(); | |||
+ | |||
+ if (!Lhs || !Rhs) | |||
+ return false; | |||
+ | |||
+ auto IsDefineExpr = [AstCtx](const Expr *E) { | |||
+ const SourceRange Lsr = E->getSourceRange(); | |||
+ if (!Lsr.getBegin().isMacroID() || E->isValueDependent | |||
+ !E->isIntegerConstan | |||
+ return false; | |||
+ return true; | |||
+ }; | |||
+ | |||
+ return IsDefineExpr(Lhs) || IsDefineExpr(Rhs); | |||
+} | |||
+ | |||
// Retrieves integer constant subexpressions from binary operator expressions | // Retrieves integer constant subexpressions from binary operator expressions | ||
// that have two equivalent sides. | // that have two equivalent sides. | ||
// E.g.: from (X == 5) && (X == 5) retrieves 5 and 5. | // E.g.: from (X == 5) && (X == 5) retrieves 5 and 5. | ||
@@ -785,7 +807,7 @@ static bool retrieveConstExp | |||
} | } | ||
static bool isSameRawIdentif | static bool isSameRawIdentif | ||
- | + const SourceManager &SM) { | ||
if (T1.getKind() != T2.getKind()) | if (T1.getKind() != T2.getKind()) | ||
return false; | return false; | ||
if (T1.isNot(tok::raw_identifier)) | if (T1.isNot(tok::raw_identifier)) | ||
@@ -808,8 +830,8 @@ static bool areExprsFromDiff | |||
const ASTContext *AstCtx) { | const ASTContext *AstCtx) { | ||
if (!LhsExpr || !RhsExpr) | if (!LhsExpr || !RhsExpr) | ||
return false; | return false; | ||
- SourceRange Lsr = LhsExpr->getSourceRange(); | + const SourceRange Lsr = LhsExpr->getSourceRange(); | ||
- SourceRange Rsr = RhsExpr->getSourceRange(); | + const SourceRange Rsr = RhsExpr->getSourceRange(); | ||
if (!Lsr.getBegin().isMacroID() || !Rsr.getBegin().isMacroID()) | if (!Lsr.getBegin().isMacroID() || !Rsr.getBegin().isMacroID()) | ||
return false; | return false; | ||
@@ -847,11 +869,83 @@ static bool areExprsMacroAnd | |||
if (!LhsExpr || !RhsExpr) | if (!LhsExpr || !RhsExpr) | ||
return false; | return false; | ||
- SourceLocation LhsLoc = LhsExpr->getExprLoc(); | + const SourceLocation LhsLoc = LhsExpr->getExprLoc(); | ||
- SourceLocation RhsLoc = RhsExpr->getExprLoc(); | + const SourceLocation RhsLoc = RhsExpr->getExprLoc(); | ||
return LhsLoc.isMacroID() != RhsLoc.isMacroID(); | return LhsLoc.isMacroID() != RhsLoc.isMacroID(); | ||
} | } | ||
+ | |||
+static bool areStringsSameIg | |||
+ const llvm::StringRef Right) { | |||
+ if (Left == Right) | |||
+ return true; | |||
+ | |||
+ // Do running comparison ignoring spaces | |||
+ llvm::StringRef L = Left.trim(); | |||
+ llvm::StringRef R = Right.trim(); | |||
+ while (!L.empty() && !R.empty()) { | |||
+ L = L.ltrim(); | |||
+ R = R.ltrim(); | |||
+ if (L.empty() && R.empty()) | |||
+ return true; | |||
+ // If symbol compared are different ==> strings are not the same | |||
+ if (L.front() != R.front()) | |||
+ return false; | |||
+ L = L.drop_front(); | |||
+ R = R.drop_front(); | |||
+ } | |||
+ return L.empty() && R.empty(); | |||
+} | |||
+ | |||
+static bool areExprsSameMacr | |||
+ const ASTContext *Context) { | |||
+ | |||
+ if (!BinOp) | |||
+ return false; | |||
+ | |||
+ const Expr *Lhs = BinOp->getLHS(); | |||
+ const Expr *Rhs = BinOp->getRHS(); | |||
+ const SourceManager &SM = Context->getSourceManager | |||
+ | |||
+ const SourceRange Lsr = Lhs->getSourceRange(); | |||
+ const SourceRange Rsr = Rhs->getSourceRange(); | |||
+ if (Lsr.getBegin().isMacroID()) { | |||
+ // Left is macro so right macro too | |||
+ if (Rsr.getBegin().isMacroID()) { | |||
+ // Both sides are macros so they are same macro or literal | |||
+ const llvm::StringRef L = Lexer::getSourceText( | |||
+ CharSourceRange::getTokenRange(Lsr), SM, Context->getLangOpts(), 0); | |||
+ const llvm::StringRef R = Lexer::getSourceText( | |||
+ CharSourceRange::getTokenRange(Rsr), SM, Context->getLangOpts(), 0); | |||
+ return areStringsSameIg | |||
+ } | |||
+ // Left is macro but right is not so they are not same macro or literal | |||
+ return false; | |||
+ } | |||
+ const auto *Lil = dyn_cast<IntegerLiteral>(Lhs); | |||
+ const auto *Ril = dyn_cast<IntegerLiteral>(Rhs); | |||
+ if (Lil && Ril) | |||
+ return Lil->getValue() == Ril->getValue(); | |||
+ | |||
+ const auto *LStrl = dyn_cast<StringLiteral>(Lhs); | |||
+ const auto *RStrl = dyn_cast<StringLiteral>(Rhs); | |||
+ if (Lil && Ril) { | |||
+ const llvm::StringRef L = Lexer::getSourceText( | |||
+ CharSourceRange::getTokenRange(LStrl->getBeginLoc()), SM, | |||
+ Context->getLangOpts(), 0); | |||
+ const llvm::StringRef R = Lexer::getSourceText( | |||
+ CharSourceRange::getTokenRange(RStrl->getBeginLoc()), SM, | |||
+ Context->getLangOpts(), 0); | |||
+ return L.compare(R) == 0; | |||
+ } | |||
+ | |||
+ const auto *Lbl = dyn_cast<CXXBoolLiteralEx | |||
+ const auto *Rbl = dyn_cast<CXXBoolLiteralEx | |||
+ if (Lbl && Rbl) | |||
+ return Lbl->getValue() == Rbl->getValue(); | |||
+ | |||
+ return false; | |||
+} | |||
} // namespace | } // namespace | ||
void RedundantExpress | void RedundantExpress | ||
@@ -1089,7 +1183,6 @@ static bool exprEvaluatesToS | |||
((Opcode == BO_And || Opcode == BO_AndAssign) && ~Value == 0); | ((Opcode == BO_And || Opcode == BO_AndAssign) && ~Value == 0); | ||
} | } | ||
- | |||
void RedundantExpress | void RedundantExpress | ||
const MatchFinder::MatchResult &Result) { | const MatchFinder::MatchResult &Result) { | ||
if (const auto *ComparisonOperat | if (const auto *ComparisonOperat | ||
@@ -1134,8 +1227,8 @@ void RedundantExpress | |||
ConstExpr)) | ConstExpr)) | ||
return; | return; | ||
- if((Value != 0 && ~Value != 0) || Sym->getExprLoc().isMacroID()) | + if ((Value != 0 && ~Value != 0) || Sym->getExprLoc().isMacroID()) | ||
- | + return; | ||
SourceLocation Loc = IneffectiveOpera | SourceLocation Loc = IneffectiveOpera | ||
@@ -1276,19 +1369,23 @@ void RedundantExpress | |||
return; | return; | ||
} | } | ||
- if ( | + if (areSidesBinaryConstExpressionsOrDefinesOrIntegerConstant( | ||
+ BinOp, Result.Context)) { | |||
const Expr *LhsConst = nullptr, *RhsConst = nullptr; | const Expr *LhsConst = nullptr, *RhsConst = nullptr; | ||
BinaryOperatorKi | BinaryOperatorKi | ||
- | + if (areSidesBinaryCo | ||
- | + if (!retrieveConstExprFromBothSides(BinOp, MainOpcode, SideOpcode, | ||
- | + LhsConst, RhsConst, Result.Context)) | ||
- | + return; | ||
- | + | ||
- | + if (areExprsFromDifferentMacros(LhsConst, RhsConst, Result.Context) || | ||
- | + areExprsMacroAndNonMacro(LhsConst, RhsConst)) | ||
- | + return; | ||
+ } else { | |||
+ if (!areExprsSameMacr | |||
+ return; | |||
+ } | |||
} | } | ||
- | |||
diag(BinOp->getOperatorLoc(), "both sides of operator are equivalent"); | diag(BinOp->getOperatorLoc(), "both sides of operator are equivalent"); | ||
} | } | ||
@@ -97,10 +97,19 @@ New check aliases | |||
Changes in existing checks | Changes in existing checks | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
+- Improved :doc:`bugprone-string-constructor | |||
+ <clang-tidy/checks/bugprone/string-constructor>` check to find suspicious | |||
+ calls of ``std::string`` constructor with char pointer, start position and | |||
+ length parameters. | |||
+ | |||
- Improved :doc:`bugprone-unsafe-functions | - Improved :doc:`bugprone-unsafe-functions | ||
<clang-tidy/checks/bugprone/unsafe-functions>` check to allow specifying | <clang-tidy/checks/bugprone/unsafe-functions>` check to allow specifying | ||
additional C++ member functions to match. | additional C++ member functions to match. | ||
+- Improved :doc:`misc-redundant-expression | |||
+ <clang-tidy/checks/misc/redundant-expression>` check by providing additional | |||
+ examples and fixing some macro related false positives. | |||
+ | |||
Removed checks | Removed checks | ||
^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^ | ||
@@ -21,6 +21,7 @@ Examples: | |||
.. code-block:: c++ | .. code-block:: c++ | ||
std::string("test", 200); // Will include random characters after "test". | std::string("test", 200); // Will include random characters after "test". | ||
+ std::string("test", 2, 5); // Will include random characters after "st". | |||
std::string_view("test", 200); | std::string_view("test", 200); | ||
Creating an empty string from constructors with parameters is considered | Creating an empty string from constructors with parameters is considered | ||
@@ -31,8 +32,19 @@ Examples: | |||
.. code-block:: c++ | .. code-block:: c++ | ||
std::string("test", 0); // Creation of an empty string. | std::string("test", 0); // Creation of an empty string. | ||
+ std::string("test", 1, 0); | |||
std::string_view("test", 0); | std::string_view("test", 0); | ||
+Passing an invalid first character position parameter to constructor will | |||
+cause ``std::out_of_range`` exception at runtime. | |||
+ | |||
+Examples: | |||
+ | |||
+.. code-block:: c++ | |||
+ | |||
+ std::string("test", -1, 10); // Negative first character position. | |||
+ std::string("test", 10, 10); // First character position is bigger than string literal character range". | |||
+ | |||
Options | Options | ||
------- | ------- | ||
@@ -19,12 +19,14 @@ Examples: | |||
.. code-block:: c++ | .. code-block:: c++ | ||
- ((x+1) | (x+1)) | + ((x+1) | (x+1)) // (x+1) is redundant | ||
- (p->x == p->x) | + (p->x == p->x) // always true | ||
- (p->x < p->x) | + (p->x < p->x) // always false | ||
- (speed - speed + 1 == 12) | + (speed - speed + 1 == 12) // speed - speed is always zero | ||
- int b = a | 4 | a | + int b = a | 4 | a // identical expr on both sides | ||
- ((x=1) | (x=1)) | + ((x=1) | (x=1)) // expression is identical | ||
+ (DEFINE_1 | DEFINE_1) // same macro on the both sides | |||
+ ((DEF_1 + DEF_2) | (DEF_1+DEF_2)) // expressions differ in spaces only | |||
Floats are handled except in the case that NaNs are checked like so: | Floats are handled except in the case that NaNs are checked like so: | ||
@@ -8,4 +8,5 @@ double Circle::area() const { | |||
double Circle::perimeter() const { | double Circle::perimeter() const { | ||
return 3.141 * radius_; | return 3.141 * radius_; | ||
-} |
@@ -1,6 +1,6 @@ | |||
// RUN: rm -rf %t && mkdir -p %t/docs %t/build | // RUN: rm -rf %t && mkdir -p %t/docs %t/build | ||
// RUN: sed 's|$test_dir|%/S|g' %S/Inputs/basic-project/database_templat | // RUN: sed 's|$test_dir|%/S|g' %S/Inputs/basic-project/database_templat | ||
-// RUN: clang-doc --format=html --output=%t/docs --executor=all-TUs %t/build/compile_commands.json | +// RUN: clang-doc --format=html --output=%t/docs --executor=all-TUs %t/build/compile_commands.json --repository=https://repository.com | ||
// RUN: FileCheck %s -input-file=%t/docs/index_json.js -check-prefix=JSON-INDEX | // RUN: FileCheck %s -input-file=%t/docs/index_json.js -check-prefix=JSON-INDEX | ||
// RUN: FileCheck %s -input-file=%t/docs/GlobalNamespace/Shape.html -check-prefix=HTML-SHAPE | // RUN: FileCheck %s -input-file=%t/docs/GlobalNamespace/Shape.html -check-prefix=HTML-SHAPE | ||
// RUN: FileCheck %s -input-file=%t/docs/GlobalNamespace/Calculator.html -check-prefix=HTML-CALC | // RUN: FileCheck %s -input-file=%t/docs/GlobalNamespace/Calculator.html -check-prefix=HTML-CALC | ||
@@ -54,130 +54,183 @@ | |||
// JSON-INDEX-NEXT: }; | // JSON-INDEX-NEXT: }; | ||
// JSON-INDEX-NEXT: } | // JSON-INDEX-NEXT: } | ||
-// | +// HTML-SHAPE: <h1>class Shape</h1> | ||
-// HTML-SHAPE: <p>Defined at line 8 of file {{.*}}Shape.h</p> | +// HTML-SHAPE-NEXT: <p> | ||
-// HTML-SHAPE: <div>brief</div> | +// HTML-SHAPE-NEXT: Defined at line | ||
-// HTML-SHAPE: <p> Abstract base class for shapes.</p> | +// HTML-SHAPE-NEXT: <a href="https://repository.com/./include/Shape.h#8">8</a> | ||
-// HTML-SHAPE: <p> Provides a common interface for different types of shapes.</p> | +// HTML-SHAPE-NEXT: of file | ||
-// HTML-SHAPE: <h2 id="Functions">Functions</h2> | +// HTML-SHAPE-NEXT: <a href="https://repository.com/./include/Shape.h">Shape.h</a> | ||
-// HTML-SHAPE: <h3 id="{{([0-9A-F]{40})}}">area</h3> | +// HTML-SHAPE-NEXT: </p> | ||
-// HTML-SHAPE: <p>public double area()</p> | +// HTML-SHAPE: <div>brief</div> | ||
-// HTML-SHAPE: <div>brief</div> | +// HTML-SHAPE: <p> Abstract base class for shapes.</p> | ||
-// HTML-SHAPE: <p> Calculates the area of the shape.</p> | +// HTML-SHAPE: <p> Provides a common interface for different types of shapes.</p> | ||
-// HTML-SHAPE: <h3 id="{{([0-9A-F]{40})}}">perimeter</h3> | +// HTML-SHAPE: <h2 id="Functions">Functions</h2> | ||
-// HTML-SHAPE: <p>public double perimeter()</p> | +// HTML-SHAPE: <h3 id="{{([0-9A-F]{40})}}">area</h3> | ||
-// HTML-SHAPE: <div>brief</div> | +// HTML-SHAPE: <p>public double area()</p> | ||
-// HTML-SHAPE: <p> Calculates the perimeter of the shape.</p> | +// HTML-SHAPE: <div>brief</div> | ||
-// HTML-SHAPE: <div>return</div> | +// HTML-SHAPE: <p> Calculates the area of the shape.</p> | ||
-// HTML-SHAPE: <p> double The perimeter of the shape.</p> | +// HTML-SHAPE: <h3 id="{{([0-9A-F]{40})}}">perimeter</h3> | ||
-// HTML-SHAPE: <h3 id="{{([0-9A-F]{40})}}">~Shape</h3> | +// HTML-SHAPE: <p>public double perimeter()</p> | ||
-// HTML-SHAPE: <p>public void ~Shape()</p> | +// HTML-SHAPE: <div>brief</div> | ||
-// HTML-SHAPE: <p>Defined at line 13 of file {{.*}}Shape.h</p> | +// HTML-SHAPE: <p> Calculates the perimeter of the shape.</p> | ||
-// | +// HTML-SHAPE: <div>return</div> | ||
-// HTML-SHAPE: <p> Virtual destructor.</p> | +// HTML-SHAPE: <p> double The perimeter of the shape.</p> | ||
+// HTML-SHAPE: <h3 id="{{([0-9A-F]{40})}}">~Shape</h3> | |||
+// HTML-SHAPE: <p>public void ~Shape()</p> | |||
+// HTML-SHAPE: Defined at line | |||
+// HTML-SHAPE-NEXT: <a href="https://repository.com/./include/Shape.h#13">13</a> | |||
+// HTML-SHAPE-NEXT: of file | |||
+// HTML-SHAPE-NEXT: <a href="https://repository.com/./include/Shape.h">Shape.h</a> | |||
+// HTML-SHAPE: <div>brief</div> | |||
+// HTML-SHAPE: <p> Virtual destructor.</p> | |||
-// | +// HTML-CALC: <h1>class Calculator</h1> | ||
-// HTML-CALC: <p>Defined at line 8 of file {{.*}}Calculator.h</p> | +// HTML-CALC-NEXT: <p> | ||
-// HTML-CALC: <div>brief</div> | +// HTML-CALC-NEXT: Defined at line | ||
-// HTML-CALC: <p> A simple calculator class.</p> | +// HTML-CALC-NEXT: <a href="https://repository.com/./include/Calculator.h#8">8</a> | ||
-// HTML-CALC: <p> Provides basic arithmetic operations.</p> | +// HTML-CALC-NEXT: of file | ||
-// HTML-CALC: <h2 id="Functions">Functions</h2> | +// HTML-CALC-NEXT: <a href="https://repository.com/./include/Calculator.h">Calculator.h</a> | ||
-// HTML-CALC: <h3 id="{{([0-9A-F]{40})}}">add</h3> | +// HTML-CALC-NEXT: </p> | ||
-// HTML-CALC: <p>public int add(int a, int b)</p> | +// HTML-CALC: <div>brief</div> | ||
-// HTML-CALC: <p>Defined at line 3 of file {{.*}}Calculator.cpp</p> | +// HTML-CALC: <p> A simple calculator class.</p> | ||
-// HTML-CALC: <div>brief</div> | +// HTML-CALC: <p> Provides basic arithmetic operations.</p> | ||
-// HTML-CALC: <p> Adds two integers.</p> | +// HTML-CALC: <h2 id="Functions">Functions</h2> | ||
-// HTML-CALC: <div>return</div> | +// HTML-CALC: <h3 id="{{([0-9A-F]{40})}}">add</h3> | ||
-// HTML-CALC: <p> int The sum of a and b.</p> | +// HTML-CALC: <p>public int add(int a, int b)</p> | ||
-// HTML-CALC: <h3 id="{{([0-9A-F]{40})}}">subtract</h3> | +// HTML-CALC: Defined at line | ||
-// HTML-CALC: <p>public int subtract(int a, int b)</p> | +// HTML-CALC-NEXT: <a href="https://repository.com/./src/Calculator.cpp#3">3</a> | ||
-// HTML-CALC: <p>Defined at line 7 of file {{.*}}Calculator.cpp</p> | +// HTML-CALC-NEXT: of file | ||
-// HTML-CALC: <div>brief</div> | +// HTML-CALC-NEXT: <a href="https://repository.com/./src/Calculator.cpp">Calculator.cpp</a> | ||
-// HTML-CALC: <p> Subtracts the second integer from the first.</p> | +// HTML-CALC: <div>brief</div> | ||
-// HTML-CALC: <div>return</div> | +// HTML-CALC: <p> Adds two integers.</p> | ||
-// HTML-CALC: <p> int The result of a - b.</p> | +// HTML-CALC: <div>return</div> | ||
-// HTML-CALC: <h3 id="{{([0-9A-F]{40})}}">multiply</h3> | +// HTML-CALC: <p> int The sum of a and b.</p> | ||
-// HTML-CALC: <p>public int multiply(int a, int b)</p> | +// HTML-CALC: <h3 id="{{([0-9A-F]{40})}}">subtract</h3> | ||
-// HTML-CALC: <p>Defined at line 11 of file {{.*}}Calculator.cpp</p> | +// HTML-CALC: <p>public int subtract(int a, int b)</p> | ||
-// HTML-CALC: <div>brief</div> | +// HTML-CALC: Defined at line | ||
-// HTML-CALC: <p> Multiplies two integers.</p> | +// HTML-CALC-NEXT: <a href="https://repository.com/./src/Calculator.cpp#7">7</a> | ||
-// HTML-CALC: <div>return</div> | +// HTML-CALC-NEXT: of file | ||
-// HTML-CALC: <p> int The product of a and b.</p> | +// HTML-CALC-NEXT: <a href="https://repository.com/./src/Calculator.cpp">Calculator.cpp</a> | ||
-// HTML-CALC: <h3 id="{{([0-9A-F]{40})}}">divide</h3> | +// HTML-CALC: <div>brief</div> | ||
-// HTML-CALC: <p>public double divide(int a, int b)</p> | +// HTML-CALC: <p> Subtracts the second integer from the first.</p> | ||
-// HTML-CALC: <p>Defined at line 15 of file {{.*}}Calculator.cpp</p> | +// HTML-CALC: <div>return</div> | ||
-// HTML-CALC: <div>brief</div> | +// HTML-CALC: <p> int The result of a - b.</p> | ||
-// HTML-CALC: <p> Divides the first integer by the second.</p> | +// HTML-CALC: <h3 id="{{([0-9A-F]{40})}}">multiply</h3> | ||
-// HTML-CALC: <div>return</div> | +// HTML-CALC: <p>public int multiply(int a, int b)</p> | ||
-// HTML-CALC: <p> double The result of a / b.</p> | +// HTML-CALC: Defined at line | ||
-// HTML-CALC: <div>throw</div> | +// HTML-CALC-NEXT: <a href="https://repository.com/./src/Calculator.cpp#11">11</a> | ||
-// HTML-CALC: <p>if b is zero.</p> | +// HTML-CALC-NEXT: of file | ||
+// HTML-CALC-NEXT: <a href="https://repository.com/./src/Calculator.cpp">Calculator.cpp</a> | |||
+// HTML-CALC: <div>brief</div> | |||
+// HTML-CALC: <p> Multiplies two integers.</p> | |||
+// HTML-CALC: <div>return</div> | |||
+// HTML-CALC: <p> int The product of a and b.</p> | |||
+// HTML-CALC: <h3 id="{{([0-9A-F]{40})}}">divide</h3> | |||
+// HTML-CALC: <p>public double divide(int a, int b)</p> | |||
+// HTML-CALC: Defined at line | |||
+// HTML-CALC-NEXT: <a href="https://repository.com/./src/Calculator.cpp#15">15</a> | |||
+// HTML-CALC-NEXT: of file | |||
+// HTML-CALC-NEXT: <a href="https://repository.com/./src/Calculator.cpp">Calculator.cpp</a> | |||
+// HTML-CALC: <div>brief</div> | |||
+// HTML-CALC: <p> Divides the first integer by the second.</p> | |||
+// HTML-CALC: <div>return</div> | |||
+// HTML-CALC: <p> double The result of a / b.</p> | |||
+// HTML-CALC: <div>throw</div> | |||
+// HTML-CALC: <p>if b is zero.</p> | |||
-// | +// HTML-RECTANGLE: <h1>class Rectangle</h1> | ||
-// HTML-RECTANGLE: <p>Defined at line 10 of file {{.*}}Rectangle.h</p> | +// HTML-RECTANGLE-NEXT: <p> | ||
-// HTML-RECTANGLE: <p> Represents a rectangle with a given width and height.</p | +// HTML-RECTANGLE-NEXT: Defined at line | ||
-// HTML-RECTANGLE: <p> | +// HTML-RECTANGLE-NEXT: <a href="https://repository.com/./include/Rectangle.h#10">10</a> | ||
-// HTML- | +// HTML-RECTANGLE-NEXT: of file | ||
-// HTML-RECTANGLE: <a href="Shape.html">Shape</a> | +// HTML-RECTANGLE-NEXT: <a href="https://repository.com/./include/Rectangle.h">Rectangle.h</a> | ||
-// HTML- | +// HTML-RECTANGLE-NEXT: </p> | ||
-// HTML-RECTANGLE: <h2 id="Members">Members</h2> | +// HTML-RECTANGLE: <p> Represents a rectangle with a given width and height.</p> | ||
-// HTML-RECTANGLE: <p> Width of the rectangle.</p> | +// HTML-RECTANGLE: <p> | ||
-// HTML-RECTANGLE: <div>private double width_</div> | +// HTML-RECTANGLE: Inherits from | ||
-// HTML-RECTANGLE: <p> Height of the rectangle.</p> | +// HTML-RECTANGLE: <a href="Shape.html">Shape</a> | ||
-// HTML-RECTANGLE: <div>private double height_</div> | +// HTML-RECTANGLE: </p> | ||
-// HTML-RECTANGLE: <h2 id="Functions">Functions</h2> | +// HTML-RECTANGLE: <h2 id="Members">Members</h2> | ||
-// HTML-RECTANGLE: <h3 id="{{([0-9A-F]{40})}}">Rectangle</h3> | +// HTML-RECTANGLE: <p> Width of the rectangle.</p> | ||
-// HTML-RECTANGLE: <p>public void Rectangle(double width, double height)</p> | +// HTML-RECTANGLE: <div>private double width_</div> | ||
-// HTML-RECTANGLE: <p>Defined at line 3 of file {{.*}}Rectangle.cpp</p> | +// HTML-RECTANGLE: <p> Height of the rectangle.</p> | ||
-// | +// HTML-RECTANGLE: <div>private double height_</div> | ||
-// HTML-RECTANGLE: <p> Constructs a new Rectangle object.</p> | +// HTML-RECTANGLE: <h2 id="Functions">Functions</h2> | ||
-// | +// HTML-RECTANGLE: <h3 id="{{([0-9A-F]{40})}}">Rectangle</h3> | ||
-// HTML-RECTANGLE: <p>public double area()</p> | +// HTML-RECTANGLE: <p>public void Rectangle(double width, double height)</p> | ||
-// HTML-RECTANGLE: <p>Defined at line 6 of file {{.*}}Rectangle.cpp</p> | +// HTML-RECTANGLE: Defined at line | ||
-// HTML-RECTANGLE: <div>brief</div> | +// HTML-RECTANGLE-NEXT: <a href="https://repository.com/./src/Rectangle.cpp#3">3</a> | ||
-// HTML-RECTANGLE: <p> Calculates the area of the rectangle.</p> | +// HTML-RECTANGLE-NEXT: of file | ||
-// HTML-RECTANGLE: <div>return</div> | +// HTML-RECTANGLE-NEXT: <a href="https://repository.com/./src/Rectangle.cpp">Rectangle.cpp</a> | ||
-// HTML-RECTANGLE: <p> double The area of the rectangle.</p> | +// HTML-RECTANGLE: <div>brief</div> | ||
-// HTML-RECTANGLE: <h3 id="{{([0-9A-F]{40})}}">perimeter</h3> | +// HTML-RECTANGLE: <p> Constructs a new Rectangle object.</p> | ||
-// HTML-RECTANGLE: <p>public double perimeter()</p> | +// HTML-RECTANGLE: <h3 id="{{([0-9A-F]{40})}}">area</h3> | ||
-// HTML-RECTANGLE: <p>Defined at line 10 of file {{.*}}Rectangle.cpp</p> | +// HTML-RECTANGLE: <p>public double area()</p> | ||
-// HTML-RECTANGLE: <div>brief</div> | +// HTML-RECTANGLE: Defined at line | ||
-// HTML-RECTANGLE: <p> Calculates the perimeter of the rectangle.</p> | +// HTML-RECTANGLE-NEXT: <a href="https://repository.com/./src/Rectangle.cpp#6">6</a> | ||
-// HTML-RECTANGLE: <div>return</div> | +// HTML-RECTANGLE-NEXT: of file | ||
-// HTML-RECTANGLE: <p> double The perimeter of the rectangle.</p> | +// HTML-RECTANGLE-NEXT: <a href="https://repository.com/./src/Rectangle.cpp">Rectangle.cpp</a> | ||
+// HTML-RECTANGLE: <div>brief</div> | |||
+// HTML-RECTANGLE: <p> Calculates the area of the rectangle.</p> | |||
+// HTML-RECTANGLE: <div>return</div> | |||
+// HTML-RECTANGLE: <p> double The area of the rectangle.</p> | |||
+// HTML-RECTANGLE: <h3 id="{{([0-9A-F]{40})}}">perimeter</h3> | |||
+// HTML-RECTANGLE: <p>public double perimeter()</p> | |||
+// HTML-RECTANGLE: Defined at line | |||
+// HTML-RECTANGLE-NEXT: <a href="https://repository.com/./src/Rectangle.cpp#10">10</a> | |||
+// HTML-RECTANGLE-NEXT: of file | |||
+// HTML-RECTANGLE-NEXT: <a href="https://repository.com/./src/Rectangle.cpp">Rectangle.cpp</a> | |||
+// HTML-RECTANGLE: <div>brief</div> | |||
+// HTML-RECTANGLE: <p> Calculates the perimeter of the rectangle.</p> | |||
+// HTML-RECTANGLE: <div>return</div> | |||
+// HTML-RECTANGLE: <p> double The perimeter of the rectangle.</p> | |||
-// | +// HTML-CIRCLE: <h1>class Circle</h1> | ||
-// HTML-CIRCLE: <p>Defined at line 10 of file {{.*}}Circle.h</p> | +// HTML-CIRCLE-NEXT: <p> | ||
-// HTML-CIRCLE: <div>brief</div> | +// HTML-CIRCLE-NEXT: Defined at line | ||
-// HTML-CIRCLE: <p> Circle class derived from Shape.</p> | +// HTML-CIRCLE-NEXT: <a href="https://repository.com/./include/Circle.h#10">10</a> | ||
-// HTML-CIRCLE: <p> Represents a circle with a given radius.</p> | +// HTML-CIRCLE-NEXT: of file | ||
-// HTML-CIRCLE: <p> | +// HTML-CIRCLE-NEXT: <a href="https://repository.com/./include/Circle.h">Circle.h</a> | ||
-// HTML-CIRCLE: Inherits from | +// HTML-CIRCLE-NEXT: </p> | ||
-// HTML-CIRCLE: <a href="Shape.html">Shape</a> | +// HTML-CIRCLE: <div>brief</div> | ||
-// HTML-CIRCLE: </p> | +// HTML-CIRCLE: <p> Circle class derived from Shape.</p> | ||
-// HTML-CIRCLE: <h2 id="Members">Members</h2> | +// HTML-CIRCLE: <p> Represents a circle with a given radius.</p> | ||
-// HTML-CIRCLE: <p> Radius of the circle.</p> | +// HTML-CIRCLE: <p> | ||
-// HTML-CIRCLE: <div>private double radius_</div> | +// HTML-CIRCLE: Inherits from | ||
-// HTML-CIRCLE: <h2 id="Functions">Functions</h2> | +// HTML-CIRCLE: <a href="Shape.html">Shape</a> | ||
-// HTML-CIRCLE: <h3 id="{{([0-9A-F]{40})}}">Circle</h3> | +// HTML-CIRCLE: </p> | ||
-// HTML-CIRCLE: <p>public void Circle(double radius)</p> | +// HTML-CIRCLE: <h2 id="Members">Members</h2> | ||
-// HTML-CIRCLE: <p>Defined at line 3 of file {{.*}}Circle.cpp</p> | +// HTML-CIRCLE: <p> Radius of the circle.</p> | ||
-// | +// HTML-CIRCLE: <div>private double radius_</div> | ||
-// HTML-CIRCLE: <p> Constructs a new Circle object.</p> | +// HTML-CIRCLE: <h2 id="Functions">Functions</h2> | ||
-// | +// HTML-CIRCLE: <h3 id="{{([0-9A-F]{40})}}">Circle</h3> | ||
-// | +// HTML-CIRCLE: <p>public void Circle(double radius)</p> | ||
-// HTML-CIRCLE: <p>Defined at line 5 of file {{.*}}Circle.cpp</p> | +// HTML-CIRCLE: Defined at line | ||
-// HTML-CIRCLE: <div>brief</div> | +// HTML-CIRCLE-NEXT: <a href="https://repository.com/./src/Circle.cpp#3">3</a> | ||
-// HTML-CIRCLE: <p> Calculates the area of the circle.</p> | +// HTML-CIRCLE-NEXT: of file | ||
-// HTML-CIRCLE: <div>return</div> | +// HTML-CIRCLE-NEXT: <a href="https://repository.com/./src/Circle.cpp">Circle.cpp</a> | ||
-// HTML-CIRCLE: <p> double The area of the circle.</p> | +// HTML-CIRCLE: <div>brief</div> | ||
-// HTML-CIRCLE: <h3 id="{{([0-9A-F]{40})}}">perimeter</h3> | +// HTML-CIRCLE: <p> Constructs a new Circle object.</p> | ||
-// HTML-CIRCLE: <p>public double perimeter()</p> | +// HTML-CIRCLE: <h3 id="{{([0-9A-F]{40})}}">area</h3> | ||
-// HTML-CIRCLE: <p>Defined at line 9 of file {{.*}}Circle.cpp</p> | +// HTML-CIRCLE: <p>public double area()</p> | ||
-// HTML-CIRCLE: <div>brief</div> | +// HTML-CIRCLE: Defined at line | ||
-// HTML-CIRCLE: <p> Calculates the perimeter of the circle.</p> | +// HTML-CIRCLE-NEXT: <a href="https://repository.com/./src/Circle.cpp#5">5</a> | ||
-// HTML-CIRCLE: <div>return</div> | +// HTML-CIRCLE-NEXT: of file | ||
-// HTML-CIRCLE: <p> double The perimeter of the circle.</p> | +// HTML-CIRCLE-NEXT: <a href="https://repository.com/./src/Circle.cpp">Circle.cpp</a> | ||
+// HTML-CIRCLE: <div>brief</div> | |||
+// HTML-CIRCLE: <p> Calculates the area of the circle.</p> | |||
+// HTML-CIRCLE: <div>return</div> | |||
+// HTML-CIRCLE: <p> double The area of the circle.</p> | |||
+// HTML-CIRCLE: <h3 id="{{([0-9A-F]{40})}}">perimeter</h3> | |||
+// HTML-CIRCLE: <p>public double perimeter()</p> | |||
+// HTML-CIRCLE: Defined at line | |||
+// HTML-CIRCLE-NEXT: <a href="https://repository.com/./src/Circle.cpp#9">9</a> | |||
+// HTML-CIRCLE-NEXT: of file | |||
+// HTML-CIRCLE-NEXT: <a href="https://repository.com/./src/Circle.cpp">Circle.cpp</a> | |||
+// HTML-CIRCLE: <div>brief</div> | |||
+// HTML-CIRCLE: <p> Calculates the perimeter of the circle.</p> | |||
+// HTML-CIRCLE: <div>return</div> | |||
+// HTML-CIRCLE: <p> double The perimeter of the circle.</p> | |||
// MD-CALC: # class Calculator | // MD-CALC: # class Calculator | ||
// MD-CALC: *Defined at .{{[\/]}}include{{[\/]}}Calculator.h#8* | // MD-CALC: *Defined at .{{[\/]}}include{{[\/]}}Calculator.h#8* | ||
@@ -286,4 +339,4 @@ | |||
// MD-ALL-FILES: ## [GlobalNamespace](GlobalNamespace{{[\/]}}index.md) | // MD-ALL-FILES: ## [GlobalNamespace](GlobalNamespace{{[\/]}}index.md) | ||
// MD-INDEX: # C/C++ Reference | // MD-INDEX: # C/C++ Reference | ||
-// MD-INDEX: * Namespace: [GlobalNamespace](GlobalNamespace) |
@@ -11,6 +11,7 @@ struct basic_string { | |||
basic_string(const C*, unsigned int size); | basic_string(const C*, unsigned int size); | ||
basic_string(const C *, const A &allocator = A()); | basic_string(const C *, const A &allocator = A()); | ||
basic_string(unsigned int size, C c); | basic_string(unsigned int size, C c); | ||
+ basic_string(const C*, unsigned int pos, unsigned int size); | |||
}; | }; | ||
typedef basic_string<char> string; | typedef basic_string<char> string; | ||
typedef basic_string<wchar_t> wstring; | typedef basic_string<wchar_t> wstring; | ||
@@ -61,6 +62,21 @@ void Test() { | |||
// CHECK-MESSAGES: [[@LINE-1]]:15: warning: constructing string from nullptr is undefined behaviour | // CHECK-MESSAGES: [[@LINE-1]]:15: warning: constructing string from nullptr is undefined behaviour | ||
std::string q7 = 0; | std::string q7 = 0; | ||
// CHECK-MESSAGES: [[@LINE-1]]:20: warning: constructing string from nullptr is undefined behaviour | // CHECK-MESSAGES: [[@LINE-1]]:20: warning: constructing string from nullptr is undefined behaviour | ||
+ | |||
+ std::string r1("test", 1, 0); | |||
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: constructor creating an empty string | |||
+ std::string r2("test", 0, -4); | |||
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: negative value used as length parameter | |||
+ std::string r3("test", -4, 1); | |||
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: negative value used as position of the first character parameter | |||
+ std::string r4("test", 0, 0x1000000); | |||
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: suspicious large length parameter | |||
+ std::string r5("test", 0, 5); | |||
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger than string literal size | |||
+ std::string r6("test", 3, 2); | |||
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger than remaining string literal size | |||
+ std::string r7("test", 4, 1); | |||
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: position of the first character parameter is bigger than string literal character range | |||
} | } | ||
void TestView() { | void TestView() { | ||
@@ -82,6 +98,17 @@ void TestView() { | |||
// CHECK-MESSAGES: [[@LINE-1]]:25: warning: constructing string from nullptr is undefined behaviour | // CHECK-MESSAGES: [[@LINE-1]]:25: warning: constructing string from nullptr is undefined behaviour | ||
} | } | ||
+void TestUnsignedArgu | |||
+ std::string s0("test", 0u); | |||
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: constructor creating an empty string | |||
+ std::string s1(0x1000000ull, 'x'); | |||
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: suspicious large length parameter | |||
+ std::string s2("test", 3ull, 2u); | |||
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger than remaining string literal size | |||
+ std::string s3("test", 0u, 5ll); | |||
+ // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger than string literal size | |||
+} | |||
+ | |||
std::string StringFromZero() { | std::string StringFromZero() { | ||
return 0; | return 0; | ||
// CHECK-MESSAGES: [[@LINE-1]]:10: warning: constructing string from nullptr is undefined behaviour | // CHECK-MESSAGES: [[@LINE-1]]:10: warning: constructing string from nullptr is undefined behaviour | ||
@@ -101,6 +128,9 @@ void Valid() { | |||
std::string s3("test"); | std::string s3("test"); | ||
std::string s4("test\000", 5); | std::string s4("test\000", 5); | ||
std::string s6("te" "st", 4); | std::string s6("te" "st", 4); | ||
+ std::string s7("test", 0, 4); | |||
+ std::string s8("test", 3, 1); | |||
+ std::string s9("te" "st", 1, 2); | |||
std::string_view emptyv(); | std::string_view emptyv(); | ||
std::string_view sv1("test", 4); | std::string_view sv1("test", 4); |
@@ -1,4 +1,5 @@ | |||
// RUN: %check_clang_tidy | // RUN: %check_clang_tidy | ||
+// RUN: %check_clang_tidy | |||
typedef __INT64_TYPE__ I64; | typedef __INT64_TYPE__ I64; | ||
@@ -91,6 +92,223 @@ int TestSimpleEquiva | |||
return 0; | return 0; | ||
} | } | ||
+#ifndef TEST_MACRO | |||
+#define VAL_1 2 | |||
+#define VAL_3 3 | |||
+#else | |||
+#define VAL_1 3 | |||
+#define VAL_3 2 | |||
+#endif | |||
+ | |||
+#define VAL_2 2 | |||
+ | |||
+#ifndef TEST_MACRO | |||
+#define VAL_4 2 + 1 | |||
+#define VAL_6 3 + 1 | |||
+#else | |||
+#define VAL_4 3 + 1 | |||
+#define VAL_6 2 + 1 | |||
+#endif | |||
+ | |||
+#define VAL_5 2 + 1 | |||
+ | |||
+struct TestStruct | |||
+{ | |||
+ int mA; | |||
+ int mB; | |||
+ int mC[10]; | |||
+}; | |||
+ | |||
+int TestDefineEquiva | |||
+ | |||
+ int int_val1 = 3; | |||
+ int int_val2 = 4; | |||
+ int int_val = 0; | |||
+ const int cint_val2 = 4; | |||
+ | |||
+ // Cases which should not be reported | |||
+ if (VAL_1 != VAL_2) return 0; | |||
+ if (VAL_3 != VAL_2) return 0; | |||
+ if (VAL_1 == VAL_2) return 0; | |||
+ if (VAL_3 == VAL_2) return 0; | |||
+ if (VAL_1 >= VAL_2) return 0; | |||
+ if (VAL_3 >= VAL_2) return 0; | |||
+ if (VAL_1 <= VAL_2) return 0; | |||
+ if (VAL_3 <= VAL_2) return 0; | |||
+ if (VAL_1 < VAL_2) return 0; | |||
+ if (VAL_3 < VAL_2) return 0; | |||
+ if (VAL_1 > VAL_2) return 0; | |||
+ if (VAL_3 > VAL_2) return 0; | |||
+ | |||
+ if (VAL_4 != VAL_5) return 0; | |||
+ if (VAL_6 != VAL_5) return 0; | |||
+ if (VAL_6 == VAL_5) return 0; | |||
+ if (VAL_4 >= VAL_5) return 0; | |||
+ if (VAL_6 >= VAL_5) return 0; | |||
+ if (VAL_4 <= VAL_5) return 0; | |||
+ if (VAL_6 <= VAL_5) return 0; | |||
+ if (VAL_4 > VAL_5) return 0; | |||
+ if (VAL_6 > VAL_5) return 0; | |||
+ if (VAL_4 < VAL_5) return 0; | |||
+ if (VAL_6 < VAL_5) return 0; | |||
+ | |||
+ if (VAL_1 != 2) return 0; | |||
+ if (VAL_3 == 3) return 0; | |||
+ | |||
+ if (VAL_1 >= VAL_1) return 0; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: both sides of operator are equivalent | |||
+ if (VAL_2 <= VAL_2) return 0; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: both sides of operator are equivalent | |||
+ if (VAL_3 > VAL_3) return 0; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: both sides of operator are equivalent | |||
+ if (VAL_4 < VAL_4) return 0; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: both sides of operator are equivalent | |||
+ if (VAL_6 == VAL_6) return 2; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: both sides of operator are equivalent | |||
+ if (VAL_5 != VAL_5) return 2; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: both sides of operator are equivalent | |||
+ | |||
+ // Test prefixes | |||
+ if (+VAL_6 == +VAL_6) return 2; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: both sides of operator are equivalent | |||
+ if (-VAL_6 == -VAL_6) return 2; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: both sides of operator are equivalent | |||
+ if ((+VAL_6) == (+VAL_6)) return 2; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: both sides of operator are equivalent | |||
+ if ((-VAL_6) == (-VAL_6)) return 2; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: both sides of operator are equivalent | |||
+ | |||
+ if (1 >= 1) return 0; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: both sides of operator are equivalent | |||
+ if (0xFF <= 0xFF) return 0; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: both sides of operator are equivalent | |||
+ if (042 > 042) return 0; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: both sides of operator are equivalent | |||
+ | |||
+ int_val = (VAL_6 == VAL_6)?int_val1: int_val2; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: both sides of operator are equivalent | |||
+ int_val = (042 > 042)?int_val1: int_val2; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: both sides of operator are equivalent | |||
+ | |||
+ | |||
+ // Ternary operator cases which should not be reported | |||
+ int_val = (VAL_4 == VAL_5)? int_val1: int_val2; | |||
+ int_val = (VAL_3 != VAL_2)? int_val1: int_val2; | |||
+ int_val = (VAL_6 != 10)? int_val1: int_val2; | |||
+ int_val = (VAL_6 != 3)? int_val1: int_val2; | |||
+ int_val = (VAL_6 != 4)? int_val1: int_val2; | |||
+ int_val = (VAL_6 == 3)? int_val1: int_val2; | |||
+ int_val = (VAL_6 == 4)? int_val1: int_val2; | |||
+ | |||
+ TestStruct tsVar1 = { | |||
+ .mA = 3, | |||
+ .mB = int_val, | |||
+ .mC[0 ... VAL_2 - 2] = int_val + 1, | |||
+ }; | |||
+ | |||
+ TestStruct tsVar2 = { | |||
+ .mA = 3, | |||
+ .mB = int_val, | |||
+ .mC[0 ... cint_val2 - 2] = int_val + 1, | |||
+ }; | |||
+ | |||
+ TestStruct tsVar3 = { | |||
+ .mA = 3, | |||
+ .mB = int_val, | |||
+ .mC[0 ... VAL_3 - VAL_3] = int_val + 1, | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: both sides of operator are equivalent | |||
+ }; | |||
+ | |||
+ TestStruct tsVar4 = { | |||
+ .mA = 3, | |||
+ .mB = int_val, | |||
+ .mC[0 ... 5 - 5] = int_val + 1, | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: both sides of operator are equivalent | |||
+ }; | |||
+ | |||
+ return 1 + int_val + sizeof(tsVar1) + sizeof(tsVar2) + | |||
+ sizeof(tsVar3) + sizeof(tsVar4); | |||
+} | |||
+ | |||
+#define LOOP_DEFINE 1 | |||
+ | |||
+unsigned int testLoops(const unsigned int arr1[LOOP_DEFINE]) | |||
+{ | |||
+ unsigned int localIndex; | |||
+ for (localIndex = LOOP_DEFINE - 1; localIndex > 0; localIndex--) | |||
+ { | |||
+ } | |||
+ for (localIndex = LOOP_DEFINE - 1; 10 > 10; localIndex--) | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:41: warning: both sides of operator are equivalent | |||
+ { | |||
+ } | |||
+ | |||
+ for (localIndex = LOOP_DEFINE - 1; LOOP_DEFINE > LOOP_DEFINE; localIndex--) | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:50: warning: both sides of operator are equivalent | |||
+ { | |||
+ } | |||
+ | |||
+ return localIndex; | |||
+} | |||
+ | |||
+#define getValue(a) a | |||
+#define getValueM(a) a | |||
+ | |||
+int TestParamDefine() { | |||
+ int ret = 0; | |||
+ | |||
+ // Negative cases | |||
+ ret += getValue(VAL_6) == getValue(2); | |||
+ ret += getValue(VAL_6) == getValue(3); | |||
+ ret += getValue(VAL_5) == getValue(2); | |||
+ ret += getValue(VAL_5) == getValue(3); | |||
+ ret += getValue(1) > getValue( 2); | |||
+ ret += getValue(VAL_1) == getValue(VAL_2); | |||
+ ret += getValue(VAL_1) != getValue(VAL_2); | |||
+ ret += getValue(VAL_1) == getValueM(VAL_1); | |||
+ ret += getValue(VAL_1 + VAL_2) == getValueM(VAL_1 + VAL_2); | |||
+ ret += getValue(1) == getValueM(1); | |||
+ ret += getValue(false) == getValueM(false); | |||
+ ret += -getValue(1) > +getValue( 1); | |||
+ | |||
+ // Positive cases | |||
+ ret += (+getValue(1)) > (+getValue( 1)); | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: both sides of operator are equivalent | |||
+ ret += (-getValue(1)) > (-getValue( 1)); | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: both sides of operator are equivalent | |||
+ | |||
+ ret += +getValue(1) > +getValue( 1); | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: both sides of operator are equivalent | |||
+ ret += -getValue(1) > -getValue( 1); | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: both sides of operator are equivalent | |||
+ | |||
+ ret += getValue(1) > getValue( 1); | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: both sides of operator are equivalent | |||
+ ret += getValue(1) > getValue( 1 ); | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: both sides of operator are equivalent | |||
+ ret += getValue(1) > getValue( 1); | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: both sides of operator are equivalent | |||
+ ret += getValue( 1) > getValue( 1); | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: both sides of operator are equivalent | |||
+ ret += getValue( 1 ) > getValue( 1); | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: both sides of operator are equivalent | |||
+ ret += getValue( VAL_5 ) > getValue(VAL_5); | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: both sides of operator are equivalent | |||
+ ret += getValue( VAL_5 ) > getValue( VAL_5); | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: both sides of operator are equivalent | |||
+ ret += getValue( VAL_5 ) > getValue( VAL_5 ) ; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: both sides of operator are equivalent | |||
+ ret += getValue(VAL_5) > getValue( VAL_5 ) ; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: both sides of operator are equivalent | |||
+ ret += getValue(VAL_1+VAL_2) > getValue(VAL_1 + VAL_2) ; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: both sides of operator are equivalent | |||
+ ret += getValue(VAL_1)+getValue(VAL_2) > getValue(VAL_1) + getValue( VAL_2) ; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:42: warning: both sides of operator are equivalent | |||
+ ret += (getValue(VAL_1)+getValue(VAL_2)) > (getValue(VAL_1) + getValue( VAL_2) ) ; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:44: warning: both sides of operator are equivalent | |||
+ return ret; | |||
+} | |||
+ | |||
template <int DX> | template <int DX> | ||
int TestSimpleEquiva | int TestSimpleEquiva | ||
if (DX > 0 && DX > 0) return 1; | if (DX > 0 && DX > 0) return 1; |
@@ -319,7 +319,12 @@ TEST(HTMLGenerat | |||
<a href="path/to/int.html">int</a> | <a href="path/to/int.html">int</a> | ||
P) | P) | ||
</p> | </p> | ||
- <p>Defined at line 10 of file dir/test.cpp</p> | + <p> | ||
+ Defined at line | |||
+ <a href="https://www.repository.com/dir/test.cpp#10">10</a> | |||
+ of file | |||
+ <a href="https://www.repository.com/dir/test.cpp">test.cpp</a> | |||
+ </p> | |||
</div> | </div> | ||
<div id="sidebar-right" class="col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right"></div> | <div id="sidebar-right" class="col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right"></div> | ||
</main> | </main> |
@@ -190,8 +190,8 @@ foreach(target aarch64-unknown- | |||
set(RUNTIMES_${target}_LLVM_ENABLE_RUN | set(RUNTIMES_${target}_LLVM_ENABLE_RUN | ||
# Enable FatLTO for Linux and baremetal runtimes | # Enable FatLTO for Linux and baremetal runtimes | ||
- set(RUNTIMES_${target}_LLVM_ENABLE_LTO | + set(RUNTIMES_${target}_LLVM_ENABLE_LTO OFF CACHE BOOL "") | ||
- set(RUNTIMES_${target}_LLVM_ENABLE_FATLTO | + set(RUNTIMES_${target}_LLVM_ENABLE_FATLTO OFF CACHE BOOL "") | ||
# Use .build-id link. | # Use .build-id link. | ||
list(APPEND RUNTIME_BUILD_ID | list(APPEND RUNTIME_BUILD_ID | ||
@@ -276,8 +276,8 @@ if(FUCHSIA_SDK) | |||
set(RUNTIMES_${target}+asan+noexcept_LIBCXX_ | set(RUNTIMES_${target}+asan+noexcept_LIBCXX_ | ||
# Enable FatLTO for Fuchsia runtimes | # Enable FatLTO for Fuchsia runtimes | ||
- set(RUNTIMES_${target}_LLVM_ENABLE_LTO | + set(RUNTIMES_${target}_LLVM_ENABLE_LTO OFF CACHE BOOL "") | ||
- set(RUNTIMES_${target}_LLVM_ENABLE_FATLTO | + set(RUNTIMES_${target}_LLVM_ENABLE_FATLTO OFF CACHE BOOL "") | ||
# Use .build-id link. | # Use .build-id link. | ||
list(APPEND RUNTIME_BUILD_ID | list(APPEND RUNTIME_BUILD_ID | ||
@@ -378,8 +378,8 @@ foreach(target armv6m-none-eabi | |||
set(RUNTIMES_${target}_LLVM_ENABLE_RUN | set(RUNTIMES_${target}_LLVM_ENABLE_RUN | ||
# Enable FatLTO for baremetal runtimes | # Enable FatLTO for baremetal runtimes | ||
- set(RUNTIMES_${target}_LLVM_ENABLE_LTO | + set(RUNTIMES_${target}_LLVM_ENABLE_LTO OFF CACHE BOOL "") | ||
- set(RUNTIMES_${target}_LLVM_ENABLE_FATLTO | + set(RUNTIMES_${target}_LLVM_ENABLE_FATLTO OFF CACHE BOOL "") | ||
endforeach() | endforeach() | ||
foreach(target riscv32-unknown-elf) | foreach(target riscv32-unknown-elf) | ||
@@ -433,8 +433,8 @@ foreach(target riscv32-unknown- | |||
set(RUNTIMES_${target}_LLVM_ENABLE_RUN | set(RUNTIMES_${target}_LLVM_ENABLE_RUN | ||
# Enable FatLTO for baremetal runtimes | # Enable FatLTO for baremetal runtimes | ||
- set(RUNTIMES_${target}_LLVM_ENABLE_LTO | + set(RUNTIMES_${target}_LLVM_ENABLE_LTO OFF CACHE BOOL "") | ||
- set(RUNTIMES_${target}_LLVM_ENABLE_FATLTO | + set(RUNTIMES_${target}_LLVM_ENABLE_FATLTO OFF CACHE BOOL "") | ||
endforeach() | endforeach() | ||
set(LLVM_BUILTIN_TAR | set(LLVM_BUILTIN_TAR |
@@ -777,13 +777,13 @@ the transformed pseudo code of function ``alloc_buf()`` in the example below. | |||
size_t count; | size_t count; | ||
} sized_buf_t; | } sized_buf_t; | ||
- void alloc_buf(sized_buf_t *sbuf, | + void alloc_buf(sized_buf_t *sbuf, size_t nelems) { | ||
sbuf->buf = (int *)malloc(sizeof(int) * nelems); | sbuf->buf = (int *)malloc(sizeof(int) * nelems); | ||
sbuf->count = nelems; | sbuf->count = nelems; | ||
} | } | ||
// Transformed pseudo code: | // Transformed pseudo code: | ||
- void alloc_buf(sized_buf_t *sbuf, | + void alloc_buf(sized_buf_t *sbuf, size_t nelems) { | ||
// Materialize RHS values: | // Materialize RHS values: | ||
int *tmp_ptr = (int *)malloc(sizeof(int) * nelems); | int *tmp_ptr = (int *)malloc(sizeof(int) * nelems); | ||
int tmp_count = nelems; | int tmp_count = nelems; | ||
@@ -959,7 +959,8 @@ that has the define. | |||
#if defined(__has_feature) && __has_feature(bounds_safety) | #if defined(__has_feature) && __has_feature(bounds_safety) | ||
#define __counted_by(T) __attribute__((__counted_by__(T))) | #define __counted_by(T) __attribute__((__counted_by__(T))) | ||
// ... other bounds annotations | // ... other bounds annotations | ||
- #else #define __counted_by(T) // defined as nothing | + #else | ||
+ #define __counted_by(T) // defined as nothing | |||
// ... other bounds annotations | // ... other bounds annotations | ||
#endif | #endif | ||
@@ -987,7 +988,7 @@ and it does not guarantee other types of memory safety properties. Consequently, | |||
it may not prevent some of the secondary bounds safety violations caused by | it may not prevent some of the secondary bounds safety violations caused by | ||
other types of safety violations such as type confusion. For instance, | other types of safety violations such as type confusion. For instance, | ||
``-fbounds-safety`` does not perform type-safety checks on conversions between | ``-fbounds-safety`` does not perform type-safety checks on conversions between | ||
- | +``__single`` pointers of different pointee types (e.g., ``char *__single`` → | ||
``void *__single`` → ``int *__single``) beyond what the foundation languages | ``void *__single`` → ``int *__single``) beyond what the foundation languages | ||
(C/C++) already offer. | (C/C++) already offer. | ||
@@ -1003,4 +1004,4 @@ Try it out | |||
Your feedback on the programming model is valuable. You may want to follow the | Your feedback on the programming model is valuable. You may want to follow the | ||
instruction in :doc:`BoundsSafetyAdop | instruction in :doc:`BoundsSafetyAdop | ||
-and please send your feedback to `Yeoul Na <mailto:yeoul_na@apple.com>`_. |
@@ -134,7 +134,7 @@ same basic block and without side effect in between. | |||
int *__counted_by(count) buf; size_t count; | int *__counted_by(count) buf; size_t count; | ||
} sized_buf_t; | } sized_buf_t; | ||
- void alloc_buf(sized_buf_t *sbuf, | + void alloc_buf(sized_buf_t *sbuf, size_t nelems) { | ||
sbuf->buf = (int *)malloc(sizeof(int) * nelems); | sbuf->buf = (int *)malloc(sizeof(int) * nelems); | ||
sbuf->count = nelems; | sbuf->count = nelems; | ||
} | } |
@@ -2182,6 +2182,24 @@ the configuration (without a prefix: ``Auto``). | |||
aaaaaaaaaaaaaaaa | aaaaaaaaaaaaaaaa | ||
} | } | ||
+.. _BinPackLongBrac | |||
+ | |||
+**BinPackLongBrace | |||
+ If ``BinPackLongBrace | |||
+ ``BinPackArguments | |||
+ initializer list. | |||
+ | |||
+ .. code-block:: c++ | |||
+ | |||
+ BinPackLongBrace | |||
+ vector<int> x{ vector<int> x{1, 2, ..., | |||
+ 20, 21}; | |||
+ 1, | |||
+ 2, | |||
+ ..., | |||
+ 20, | |||
+ 21}; | |||
+ | |||
.. _BinPackParamete | .. _BinPackParamete | ||
**BinPackParameter | **BinPackParameter | ||
@@ -3421,6 +3439,35 @@ the configuration (without a prefix: ``Auto``). | |||
+.. _BreakBeforeTemp | |||
+ | |||
+**BreakBeforeTempl | |||
+ If ``true``, break before a template closing bracket (``>``) when there is | |||
+ a line break after the matching opening bracket (``<``). | |||
+ | |||
+ .. code-block:: c++ | |||
+ | |||
+ true: | |||
+ template <typename Foo, typename Bar> | |||
+ | |||
+ template <typename Foo, | |||
+ typename Bar> | |||
+ | |||
+ template < | |||
+ typename Foo, | |||
+ typename Bar | |||
+ > | |||
+ | |||
+ false: | |||
+ template <typename Foo, typename Bar> | |||
+ | |||
+ template <typename Foo, | |||
+ typename Bar> | |||
+ | |||
+ template < | |||
+ typename Foo, | |||
+ typename Bar> | |||
+ | |||
.. _BreakBeforeTern | .. _BreakBeforeTern | ||
**BreakBeforeTerna | **BreakBeforeTerna |
@@ -336,6 +336,15 @@ cross-DSO function address equality. These properties make KCFI easier to | |||
adopt in low-level software. KCFI is limited to checking only function | adopt in low-level software. KCFI is limited to checking only function | ||
pointers, and isn't compatible with executable-only memory. | pointers, and isn't compatible with executable-only memory. | ||
+``-fsanitize-kcfi-arity`` | |||
+----------------------------- | |||
+ | |||
+For supported targets, this feature extends kCFI by telling the compiler to | |||
+record information about each indirect-callable function's arity (i.e., the | |||
+number of arguments passed in registers) into the binary. Some kernel CFI | |||
+techniques, such as FineIBT, may be able to use this information to provide | |||
+enhanced security. | |||
+ | |||
Member Function Pointer Call Checking | Member Function Pointer Call Checking | ||
===================================== | ===================================== | ||
@@ -1803,10 +1803,6 @@ The following type trait primitives are supported by Clang. Those traits marked | |||
* ``__is_pointer_int | * ``__is_pointer_int | ||
* ``__is_polymorphic | * ``__is_polymorphic | ||
* ``__is_reference`` (C++, Embarcadero) | * ``__is_reference`` (C++, Embarcadero) | ||
-* ``__is_referenceab | |||
- Returns true if a type is referenceable, and false otherwise. A referenceable | |||
- type is a type that's either an object type, a reference type, or an unqualified | |||
- function type. This trait is deprecated and will be removed in Clang 21. | |||
* ``__is_rvalue_refe | * ``__is_rvalue_refe | ||
* ``__is_same`` (C++, Embarcadero) | * ``__is_same`` (C++, Embarcadero) | ||
* ``__is_same_as`` (GCC): Synonym for ``__is_same``. | * ``__is_same_as`` (GCC): Synonym for ``__is_same``. |
@@ -364,6 +364,8 @@ implementation. | |||
+=============================================================+===========================+===========================+==========================================================================+ | +=============================================================+===========================+===========================+==========================================================================+ | ||
| free-agent threads | :none:`unclaimed` | :none:`unclaimed` | | | | free-agent threads | :none:`unclaimed` | :none:`unclaimed` | | | ||
+-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | ||
+| threadset clause | :`worked on` | :none:`unclaimed` | | | |||
++-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | |||
| Recording of task graphs | :none:`unclaimed` | :none:`unclaimed` | | | | Recording of task graphs | :none:`unclaimed` | :none:`unclaimed` | | | ||
+-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | ||
| Parallel inductions | :none:`unclaimed` | :none:`unclaimed` | | | | Parallel inductions | :none:`unclaimed` | :none:`unclaimed` | | | ||
@@ -410,13 +412,13 @@ implementation. | |||
+-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | ||
| Extensions to interop construct | :none:`unclaimed` | :none:`unclaimed` | | | | Extensions to interop construct | :none:`unclaimed` | :none:`unclaimed` | | | ||
+-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | ||
-| no_openmp_constructs | | +| no_openmp_constructs | :good:`done` | :none:`unclaimed` | https://github.com/llvm/llvm-project/pull/125933 | | ||
+-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | ||
| safe_sync and progress with identifier and API | :none:`unclaimed` | :none:`unclaimed` | | | | safe_sync and progress with identifier and API | :none:`unclaimed` | :none:`unclaimed` | | | ||
+-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | ||
-| OpenMP directives in concurrent loop regions | | +| OpenMP directives in concurrent loop regions | :good:`done` | :none:`unclaimed` | https://github.com/llvm/llvm-project/pull/125621 | | ||
+-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | ||
-| atomics constructs on concurrent loop regions | | +| atomics constructs on concurrent loop regions | :good:`done` | :none:`unclaimed` | https://github.com/llvm/llvm-project/pull/125621 | | ||
+-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | ||
| Loop construct with DO CONCURRENT | :none:`unclaimed` | :none:`unclaimed` | | | | Loop construct with DO CONCURRENT | :none:`unclaimed` | :none:`unclaimed` | | | ||
+-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | ||
@@ -454,9 +456,7 @@ implementation. | |||
+-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | ||
| map-type modifiers in arbitrary position | :none:`unclaimed` | :none:`unclaimed` | | | | map-type modifiers in arbitrary position | :none:`unclaimed` | :none:`unclaimed` | | | ||
+-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | ||
-| | +| Lift nesting restriction on concurrent loop | :good:`done` | :none:`unclaimed` | https://github.com/llvm/llvm-project/pull/125621 | | ||
-+-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | |||
-| Lift nesting restriction on concurrent loop | :none:`unclaimed` | :none:`unclaimed` | | | |||
+-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | ||
| priority clause for target constructs | :none:`unclaimed` | :none:`unclaimed` | | | | priority clause for target constructs | :none:`unclaimed` | :none:`unclaimed` | | | ||
+-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ | +-------------------------------------------------------------+---------------------------+---------------------------+--------------------------------------------------------------------------+ |
@@ -42,9 +42,15 @@ C/C++ Language Potentially Breaking Changes | |||
C++ Specific Potentially Breaking Changes | C++ Specific Potentially Breaking Changes | ||
----------------------------------------- | ----------------------------------------- | ||
+- The type trait builtin ``__is_referenceab | |||
+ very few users and all the type traits that could benefit from it in the | |||
+ standard library already have their own bespoke builtins. | |||
+ | |||
ABI Changes in This Version | ABI Changes in This Version | ||
--------------------------- | --------------------------- | ||
+- Return larger CXX records in memory instead of using AVX registers. Code compiled with older clang will be incompatible with newer version of the clang unless -fclang-abi-compat=20 is provided. (#GH120670) | |||
+ | |||
AST Dumping Potentially Breaking Changes | AST Dumping Potentially Breaking Changes | ||
---------------------------------------- | ---------------------------------------- | ||
@@ -98,6 +104,10 @@ Non-comprehensiv | |||
New Compiler Flags | New Compiler Flags | ||
------------------ | ------------------ | ||
+- New option ``-fprofile-continuous`` added to enable continuous profile syncing to file (#GH124353, `docs <https://clang.llvm.org/docs/UsersManual.html#cmdoption-fprofile-continuous>`_). | |||
+ The feature has `existed <https://clang.llvm.org/docs/SourceBasedCodeC | |||
+ for a while and this is just a user facing option. | |||
+ | |||
Deprecated Compiler Flags | Deprecated Compiler Flags | ||
------------------------- | ------------------------- | ||
@@ -110,9 +120,22 @@ Removed Compiler Flags | |||
Attribute Changes in Clang | Attribute Changes in Clang | ||
-------------------------- | -------------------------- | ||
+- The ``no_sanitize`` attribute now accepts both ``gnu`` and ``clang`` names. | |||
+- Clang now diagnoses use of declaration attributes on void parameters. (#GH108819) | |||
+ | |||
Improvements to Clang's diagnostics | Improvements to Clang's diagnostics | ||
----------------------------------- | ----------------------------------- | ||
+- Improve the diagnostics for deleted default constructor errors for C++ class | |||
+ initializer lists that don't explicitly list a class member and thus attempt | |||
+ to implicitly default construct that member. | |||
+- The ``-Wunique-object-duplication`` warning has been added to warn about objects | |||
+ which are supposed to only exist once per program, but may get duplicated when | |||
+ built into a shared library. | |||
+- Fixed a bug where Clang's Analysis did not correctly model the destructor behavior of ``union`` members (#GH119415). | |||
+- A statement attribute applied to a ``case`` label no longer suppresses | |||
+ 'bypassing variable initialization' diagnostics (#84072). | |||
+ | |||
Improvements to Clang's time-trace | Improvements to Clang's time-trace | ||
---------------------------------- | ---------------------------------- | ||
@@ -129,16 +152,23 @@ Bug Fixes to Compiler Builtins | |||
Bug Fixes to Attribute Support | Bug Fixes to Attribute Support | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
+ - Fixed crash when a parameter to the ``clang::annotate`` attribute evaluates to ``void``. See #GH119125 | |||
Bug Fixes to C++ Support | Bug Fixes to C++ Support | ||
^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^ | ||
+- Clang is now better at keeping track of friend function template instance contexts. (#GH55509) | |||
+- The initialization kind of elements of structured bindings | |||
+ direct-list-initialized from an array is corrected to direct-initialization. | |||
+ | |||
Bug Fixes to AST Handling | Bug Fixes to AST Handling | ||
^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
Miscellaneous Bug Fixes | Miscellaneous Bug Fixes | ||
^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^ | ||
+- HTML tags in comments that span multiple lines are now parsed correctly by Clang's comment parser. (#GH120843) | |||
+ | |||
Miscellaneous Clang Crashes Fixed | Miscellaneous Clang Crashes Fixed | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
@@ -154,6 +184,11 @@ AMDGPU Support | |||
NVPTX Support | NVPTX Support | ||
^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^ | ||
+Hexagon Support | |||
+^^^^^^^^^^^^^^^ | |||
+ | |||
+- The default compilation target has been changed from V60 to V68. | |||
+ | |||
X86 Support | X86 Support | ||
^^^^^^^^^^^ | ^^^^^^^^^^^ | ||
@@ -210,6 +245,10 @@ AST Matchers | |||
clang-format | clang-format | ||
------------ | ------------ | ||
+- Adds ``BreakBeforeTempl | |||
+- Adds ``BinPackLongBrace | |||
+ long (20 item or more) braced list initializer lists. | |||
+ | |||
libclang | libclang | ||
-------- | -------- | ||
@@ -219,13 +258,14 @@ Code Completion | |||
Static Analyzer | Static Analyzer | ||
--------------- | --------------- | ||
-- Clang currently support extending lifetime of object bound to | |||
- reference members of aggregates in CFG and ExprEngine, that are | |||
- created from default member initializer. | |||
- | |||
New features | New features | ||
^^^^^^^^^^^^ | ^^^^^^^^^^^^ | ||
+A new flag - `-static-libclosure` was introduced to support statically linking | |||
+the runtime for the Blocks extension on Windows. This flag currently only | |||
+changes the code generation, and even then, only on Windows. This does not | |||
+impact the linker behaviour like the other `-static-*` flags. | |||
+ | |||
Crash and bug fixes | Crash and bug fixes | ||
^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^ | ||
@@ -235,6 +275,11 @@ Improvements | |||
Moved checkers | Moved checkers | ||
^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^ | ||
+- After lots of improvements, the checker ``alpha.security.ArrayBoundV2`` is | |||
+ renamed to ``security.ArrayBound``. As this checker is stable now, the old | |||
+ checker ``alpha.security.ArrayBound`` (which was searching for the same kind | |||
+ of bugs with an different, simpler and less accurate algorithm) is removed. | |||
+ | |||
.. _release-notes-sanitizers: | .. _release-notes-sanitizers: | ||
Sanitizers | Sanitizers | ||
@@ -245,6 +290,7 @@ Python Binding Changes | |||
OpenMP Support | OpenMP Support | ||
-------------- | -------------- | ||
+- Added support 'no_openmp_constr | |||
Improvements | Improvements | ||
^^^^^^^^^^^^ | ^^^^^^^^^^^^ |
@@ -94,6 +94,11 @@ directory structure will be created. Additionally, the following special | |||
not specified (i.e the pattern is "%m"), it's assumed that ``N = 1``. The | not specified (i.e the pattern is "%m"), it's assumed that ``N = 1``. The | ||
merge pool specifier can only occur once per filename pattern. | merge pool specifier can only occur once per filename pattern. | ||
+* "%b" expands out to the binary ID (build ID). It can be used with "%Nm" to | |||
+ avoid binary signature collisions. To use it, the program should be compiled | |||
+ with the build ID linker option (``--build-id`` for GNU ld or LLD, | |||
+ ``/build-id`` for lld-link on Windows). Linux, Windows and AIX are supported. | |||
+ | |||
* "%c" expands out to nothing, but enables a mode in which profile counter | * "%c" expands out to nothing, but enables a mode in which profile counter | ||
updates are continuously synced to a file. This means that if the | updates are continuously synced to a file. This means that if the | ||
instrumented program crashes, or is killed by a signal, perfect coverage | instrumented program crashes, or is killed by a signal, perfect coverage |
@@ -27,7 +27,7 @@ reduce these impacts. | |||
The TypeSanitizer Algorithm | The TypeSanitizer Algorithm | ||
=========================== | =========================== | ||
For each TBAA type-access descriptor, encoded in LLVM IR using TBAA Metadata, the instrumentation | For each TBAA type-access descriptor, encoded in LLVM IR using TBAA Metadata, the instrumentation | ||
-pass generates descriptor | +pass generates descriptor tables. Thus there is a unique pointer to each type (and access descriptor). | ||
These tables are comdat (except for anonymous-namespace types), so the pointer values are unique | These tables are comdat (except for anonymous-namespace types), so the pointer values are unique | ||
across the program. | across the program. | ||
@@ -2223,6 +2223,12 @@ are listed below. | |||
This option is currently experimental. | This option is currently experimental. | ||
+.. option:: -fsanitize-kcfi-arity | |||
+ | |||
+ Extends kernel indirect call forward-edge control flow integrity with | |||
+ additional function arity information (for supported targets). See | |||
+ :doc:`ControlFlowInteg | |||
+ | |||
.. option:: -fstrict-vtable-pointers | .. option:: -fstrict-vtable-pointers | ||
Enable optimizations based on the strict rules for overwriting polymorphic | Enable optimizations based on the strict rules for overwriting polymorphic | ||
@@ -2959,7 +2965,8 @@ instrumentation: | |||
environment variable to specify an alternate file. If non-default file name | environment variable to specify an alternate file. If non-default file name | ||
is specified by both the environment variable and the command line option, | is specified by both the environment variable and the command line option, | ||
the environment variable takes precedence. The file name pattern specified | the environment variable takes precedence. The file name pattern specified | ||
- can include different modifiers: ``%p``, ``%h``, ``%m``, ``%t``, and | + can include different modifiers: ``%p``, ``%h``, ``%m``, ``%b``, ``%t``, and | ||
+ ``%c``. | |||
Any instance of ``%p`` in that file name will be replaced by the process | Any instance of ``%p`` in that file name will be replaced by the process | ||
ID, so that you can easily distinguish the profile output from multiple | ID, so that you can easily distinguish the profile output from multiple | ||
@@ -2981,11 +2988,11 @@ instrumentation: | |||
``%p`` is that the storage requirement for raw profile data files is greatly | ``%p`` is that the storage requirement for raw profile data files is greatly | ||
increased. To avoid issues like this, the ``%m`` specifier can used in the profile | increased. To avoid issues like this, the ``%m`` specifier can used in the profile | ||
name. When this specifier is used, the profiler runtime will substitute ``%m`` | name. When this specifier is used, the profiler runtime will substitute ``%m`` | ||
- with | + with an integer identifier associated with the instrumented binary. Additionally, | ||
multiple raw profiles dumped from different processes that share a file system (can be | multiple raw profiles dumped from different processes that share a file system (can be | ||
on different hosts) will be automatically merged by the profiler runtime during the | on different hosts) will be automatically merged by the profiler runtime during the | ||
dumping. If the program links in multiple instrumented shared libraries, each library | dumping. If the program links in multiple instrumented shared libraries, each library | ||
- will dump the profile data into its own profile data file (with its | + will dump the profile data into its own profile data file (with its integer | ||
id embedded in the profile name). Note that the merging enabled by ``%m`` is for raw | id embedded in the profile name). Note that the merging enabled by ``%m`` is for raw | ||
profile data generated by profiler runtime. The resulting merged "raw" profile data | profile data generated by profiler runtime. The resulting merged "raw" profile data | ||
file still needs to be converted to a different format expected by the compiler ( | file still needs to be converted to a different format expected by the compiler ( | ||
@@ -2995,6 +3002,12 @@ instrumentation: | |||
$ LLVM_PROFILE_FIL | $ LLVM_PROFILE_FIL | ||
+ Although rare, binary signatures used by the ``%m`` specifier can have | |||
+ collisions. In this case, the ``%b`` specifier, which expands to the binary | |||
+ ID (build ID in ELF and COFF), can be added. To use it, the program should be | |||
+ compiled with the build ID linker option (``--build-id`` for GNU ld or LLD, | |||
+ ``/build-id`` for lld-link on Windows). Linux, Windows and AIX are supported. | |||
+ | |||
See `this <SourceBasedCodeC | See `this <SourceBasedCodeC | ||
about the ``%t``, and ``%c`` modifiers. | about the ``%t``, and ``%c`` modifiers. | ||
@@ -3112,6 +3125,24 @@ indexed format, regardeless whether it is produced by frontend or the IR pass. | |||
overhead. ``prefer-atomic`` will be transformed to ``atomic`` when supported | overhead. ``prefer-atomic`` will be transformed to ``atomic`` when supported | ||
by the target, or ``single`` otherwise. | by the target, or ``single`` otherwise. | ||
+.. option:: -fprofile-continuous | |||
+ | |||
+ Enables the continuous instrumentation profiling where profile counter updates | |||
+ are continuously synced to a file. This option sets any neccessary modifiers | |||
+ (currently ``%c``) in the default profile filename and passes any necessary | |||
+ flags to the middle-end to support this mode. Value profiling is not supported | |||
+ in continuous mode. | |||
+ | |||
+ .. code-block:: console | |||
+ | |||
+ $ clang++ -O2 -fprofile-generate -fprofile-continuous code.cc -o code | |||
+ | |||
+ Running ``./code`` will collect the profile and write it to the | |||
+ ``default_xxxx.profraw`` file. However, if ``./code`` abruptly terminates or | |||
+ does not call ``exit()``, in continuous mode the profile collected up to the | |||
+ point of termination will be available in ``default_xxxx.profraw`` while in | |||
+ the non-continuous mode, no profile file is generated. | |||
+ | |||
.. option:: -ftemporal-profile | .. option:: -ftemporal-profile | ||
Enables the temporal profiling extension for IRPGO to improve startup time by | Enables the temporal profiling extension for IRPGO to improve startup time by |
@@ -1332,10 +1332,69 @@ security | |||
Security related checkers. | Security related checkers. | ||
+.. _security-ArrayBound: | |||
+ | |||
+security.ArrayBound (C, C++) | |||
+"""""""""""""""""""""""""""" | |||
+Report out of bounds access to memory that is before the start or after the end | |||
+of the accessed region (array, heap-allocated region, string literal etc.). | |||
+This usually means incorrect indexing, but the checker also detects access via | |||
+the operators ``*`` and ``->``. | |||
+ | |||
+.. code-block:: c | |||
+ | |||
+ void test_underflow(int x) { | |||
+ int buf[100][100]; | |||
+ if (x < 0) | |||
+ buf[0][x] = 1; // warn | |||
+ } | |||
+ | |||
+ void test_overflow() { | |||
+ int buf[100]; | |||
+ int *p = buf + 100; | |||
+ *p = 1; // warn | |||
+ } | |||
+ | |||
+If checkers like :ref:`unix-Malloc` or :ref:`cplusplus-NewDelete` are enabled | |||
+to model the behavior of ``malloc()``, ``operator new`` and similar | |||
+allocators), then this checker can also reports out of bounds access to | |||
+dynamically allocated memory: | |||
+ | |||
+.. code-block:: cpp | |||
+ | |||
+ int *test_dynamic() { | |||
+ int *mem = new int[100]; | |||
+ mem[-1] = 42; // warn | |||
+ return mem; | |||
+ } | |||
+ | |||
+In uncertain situations (when the checker can neither prove nor disprove that | |||
+overflow occurs), the checker assumes that the the index (more precisely, the | |||
+memory offeset) is within bounds. | |||
+ | |||
+However, if :ref:`optin-taint-GenericTaint` is enabled and the index/offset is | |||
+tainted (i.e. it is influenced by an untrusted souce), then this checker | |||
+reports the potential out of bounds access: | |||
+ | |||
+.. code-block:: c | |||
+ | |||
+ void test_with_tainte | |||
+ char s[] = "abc"; | |||
+ int x = getchar(); | |||
+ char c = s[x]; // warn: potential out of bounds access with tainted index | |||
+ } | |||
+ | |||
+.. note:: | |||
+ | |||
+ This checker is an improved and renamed version of the checker that was | |||
+ previously known as ``alpha.security.ArrayBoundV2``. The old checker | |||
+ ``alpha.security.ArrayBound`` was removed when the (previously | |||
+ "experimental") V2 variant became stable enough for regular use. | |||
+ | |||
.. _security-cert-env-InvalidPtr: | .. _security-cert-env-InvalidPtr: | ||
security.cert.env.InvalidPtr | security.cert.env.InvalidPtr | ||
- | +"""""""""""""""""""""""""""" | ||
Corresponds to SEI CERT Rules `ENV31-C <https://wiki.sei.cmu.edu/confluence/display/c/ENV31-C.+Do+not+rely+on+an+environment+pointer+following+an+operation+that+may+invalidate+it>`_ and `ENV34-C <https://wiki.sei.cmu.edu/confluence/display/c/ENV34-C.+Do+not+store+pointers+returned+by+certain+functions>`_. | Corresponds to SEI CERT Rules `ENV31-C <https://wiki.sei.cmu.edu/confluence/display/c/ENV31-C.+Do+not+rely+on+an+environment+pointer+following+an+operation+that+may+invalidate+it>`_ and `ENV34-C <https://wiki.sei.cmu.edu/confluence/display/c/ENV34-C.+Do+not+store+pointers+returned+by+certain+functions>`_. | ||
@@ -3216,78 +3275,6 @@ Warns against using one vs. many plural pattern in code when generating localize | |||
alpha.security | alpha.security | ||
^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^ | ||
-.. _alpha-security-ArrayBound: | |||
- | |||
-alpha.security.ArrayBound (C) | |||
-""""""""""""""""""""""""""""" | |||
-Warn about buffer overflows (older checker). | |||
- | |||
-.. code-block:: c | |||
- | |||
- void test() { | |||
- char *s = ""; | |||
- char c = s[1]; // warn | |||
- } | |||
- | |||
- struct seven_words { | |||
- int c[7]; | |||
- }; | |||
- | |||
- void test() { | |||
- struct seven_words a, *p; | |||
- p = &a; | |||
- p[0] = a; | |||
- p[1] = a; | |||
- p[2] = a; // warn | |||
- } | |||
- | |||
- // note: requires unix.Malloc or | |||
- // alpha.unix.MallocWithAnnota | |||
- void test() { | |||
- int *p = malloc(12); | |||
- p[3] = 4; // warn | |||
- } | |||
- | |||
- void test() { | |||
- char a[2]; | |||
- int *b = (int*)a; | |||
- b[1] = 3; // warn | |||
- } | |||
- | |||
-.. _alpha-security-ArrayBoundV2: | |||
- | |||
-alpha.security.ArrayBoundV2 (C) | |||
-""""""""""""""""""""""""""""""" | |||
-Warn about buffer overflows (newer checker). | |||
- | |||
-.. code-block:: c | |||
- | |||
- void test() { | |||
- char *s = ""; | |||
- char c = s[1]; // warn | |||
- } | |||
- | |||
- void test() { | |||
- int buf[100]; | |||
- int *p = buf; | |||
- p = p + 99; | |||
- p[1] = 1; // warn | |||
- } | |||
- | |||
- // note: compiler has internal check for this. | |||
- // Use -Wno-array-bounds to suppress compiler warning. | |||
- void test() { | |||
- int buf[100][100]; | |||
- buf[0][-1] = 1; // warn | |||
- } | |||
- | |||
- // note: requires optin.taint check turned on. | |||
- void test() { | |||
- char s[] = "abc"; | |||
- int x = getchar(); | |||
- char c = s[x]; // warn: index is tainted | |||
- } | |||
- | |||
.. _alpha-security-ReturnPtrRange: | .. _alpha-security-ReturnPtrRange: | ||
alpha.security.ReturnPtrRange (C) | alpha.security.ReturnPtrRange (C) |
@@ -11,3 +11,4 @@ Contents: | |||
developer-docs/InitializerLists | developer-docs/InitializerLists | ||
developer-docs/nullability | developer-docs/nullability | ||
developer-docs/RegionStore | developer-docs/RegionStore | ||
+ developer-docs/PerformanceInves |
@@ -0,0 +1,137 @@ | |||
+========================= | |||
+Performance Investigation | |||
+========================= | |||
+ | |||
+Multiple factors contribute to the time it takes to analyze a file with Clang Static Analyzer. | |||
+A translation unit contains multiple entry points, each of which take multiple steps to analyze. | |||
+ | |||
+Performance analysis using ``-ftime-trace`` | |||
+=========================================== | |||
+ | |||
+You can add the ``-ftime-trace=file.json`` option to break down the analysis time into individual entry points and steps within each entry point. | |||
+You can explore the generated JSON file in a Chromium browser using the ``chrome://tracing`` URL, | |||
+or using `speedscope <https://speedscope.app>`_. | |||
+Once you narrow down to specific analysis steps you are interested in, you can more effectively employ heavier profilers, | |||
+such as `Perf <https://perfwiki.github.io/main/>`_ and `Callgrind <https://valgrind.org/docs/manual/cl-manual.html>`_. | |||
+ | |||
+Each analysis step has a time scope in the trace, corresponds to processing of an exploded node, and is designated with a ``ProgramPoint``. | |||
+If the ``ProgramPoint`` is associated with a location, you can see it on the scope metadata label. | |||
+ | |||
+Here is an example of a time trace produced with | |||
+ | |||
+.. code-block:: bash | |||
+ :caption: Clang Static Analyzer invocation to generate a time trace of string.c analysis. | |||
+ | |||
+ clang -cc1 -analyze -verify clang/test/Analysis/string.c \ | |||
+ -analyzer-checker=core,unix,alpha.unix.cstring,debug.ExprInspection \ | |||
+ -ftime-trace=trace.json -ftime-trace-granularity=1 | |||
+ | |||
+.. image:: ../images/speedscope.png | |||
+ | |||
+On the speedscope screenshot above, under the first time ruler is the bird's-eye view of the entire trace that spans a little over 60 milliseconds. | |||
+Under the second ruler (focused on the 18.09-18.13ms time point) you can see a narrowed-down portion. | |||
+The second box ("HandleCode memset...") that spans entire screen (and actually extends beyond it) corresponds to the analysis of ``memset16_region_ | |||
+Below it, you can find multiple sub-scopes each corresponding to processing of a single exploded node. | |||
+ | |||
+- First: a ``PostStmt`` for some statement on line 1634. This scope has a selected subscope "CheckerManager::runCheckersForCa | |||
+- Four other nodes, too small to be discernible at this zoom level | |||
+- Last on this screenshot: another ``PostStmt`` for a statement on line 1635. | |||
+ | |||
+In addition to the ``-ftime-trace`` option, you can use ``-ftime-trace-granularity`` to fine-tune the time trace. | |||
+ | |||
+- ``-ftime-trace-granularity=NN`` dumps only time scopes that are longer than NN microseconds. | |||
+- ``-ftime-trace-verbose`` enables some additional dumps in the frontend related to template instantiations. | |||
+ At the moment, it has no effect on the traces from the static analyzer. | |||
+ | |||
+Note: Both Chrome-tracing and speedscope tools might struggle with time traces above 100 MB in size. | |||
+Luckily, in most cases the default max-steps boundary of 225 000 produces the traces of approximately that size | |||
+for a single entry point. | |||
+You can use ``-analyze-function=get_global_optio | |||
+ | |||
+ | |||
+Performance analysis using ``perf`` | |||
+=================================== | |||
+ | |||
+`Perf <https://perfwiki.github.io/main/>`_ is a tool for conducting sampling-based profiling. | |||
+It's easy to start profiling, you only have 2 prerequisites. | |||
+Build with ``-fno-omit-frame-pointer`` and debug info (``-g``). | |||
+You can use release builds, but probably the easiest is to set the ``CMAKE_BUILD_TYPE | |||
+along with ``CMAKE_CXX_FLAGS="-fno-omit-frame-pointer"`` when configuring ``llvm``. | |||
+Here is how to `get started <https://llvm.org/docs/CMake.html#quick-start>`_ if you are in trouble. | |||
+ | |||
+.. code-block:: bash | |||
+ :caption: Running the Clang Static Analyzer through ``perf`` to gather samples of the execution. | |||
+ | |||
+ # -F: Sampling frequency, use `-F max` for maximal frequency | |||
+ # -g: Enable call-graph recording for both kernel and user space | |||
+ perf record -F 99 -g -- clang -cc1 -analyze -verify clang/test/Analysis/string.c \ | |||
+ -analyzer-checker=core,unix,alpha.unix.cstring,debug.ExprInspection | |||
+ | |||
+Once you have the profile data, you can use it to produce a Flame graph. | |||
+A Flame graph is a visual representation of the stack frames of the samples. | |||
+Common stack frame prefixes are squashed together, making up a wider bar. | |||
+The wider the bar, the more time was spent under that particular stack frame, | |||
+giving a sense of how the overall execution time was spent. | |||
+ | |||
+Clone the `FlameGraph <https://github.com/brendangregg/FlameGraph>`_ git repository, | |||
+as we will use some scripts from there to convert the ``perf`` samples into a Flame graph. | |||
+It's also useful to check out Brendan Gregg's (the author of FlameGraph) | |||
+`homepage <https://www.brendangregg.com/FlameGraphs/cpuflamegraphs.html>`_. | |||
+ | |||
+ | |||
+.. code-block:: bash | |||
+ :caption: Converting the ``perf`` profile into a Flamegraph, then opening it in Firefox. | |||
+ | |||
+ perf script | /path/to/FlameGraph/stackcollapse-perf.pl > perf.folded | |||
+ /path/to/FlameGraph/flamegraph.pl perf.folded > perf.svg | |||
+ firefox perf.svg | |||
+ | |||
+.. image:: ../images/flamegraph.png | |||
+ | |||
+ | |||
+Performance analysis using ``uftrace`` | |||
+====================================== | |||
+ | |||
+`uftrace <https://github.com/namhyung/uftrace/wiki/Tutorial#getting-started>`_ is a great tool to generate rich profile data | |||
+that you can use to focus and drill down into the timeline of your application. | |||
+We will use it to generate Chromium trace JSON. | |||
+In contrast to ``perf``, this approach statically instruments every function, so it should be more precise and thorough than the sampling-based approaches like ``perf``. | |||
+In contrast to using ``-ftime-trace``, functions don't need to opt-in to be profiled using ``llvm::TimeTraceScope``. | |||
+All functions are profiled due to automatic static instrumentation. | |||
+ | |||
+There is only one prerequisite to use this tool. | |||
+You need to build the binary you are about to instrument using ``-pg`` or ``-finstrument-functions``. | |||
+This will make it run substantially slower but allows rich instrumentation. | |||
+It will also consume many gigabites of storage for a single trace unless filter flags are used during recording. | |||
+ | |||
+.. code-block:: bash | |||
+ :caption: Recording with ``uftrace``, then dumping the result as a Chrome trace JSON. | |||
+ | |||
+ uftrace record clang -cc1 -analyze -verify clang/test/Analysis/string.c \ | |||
+ -analyzer-checker=core,unix,alpha.unix.cstring,debug.ExprInspection | |||
+ uftrace dump --filter=".*::AnalysisConsumer | |||
+ | |||
+.. image:: ../images/uftrace_detailed | |||
+ | |||
+In this picture, you can see the functions below the Static Analyzer's entry point, which takes at least 300 nanoseconds to run, visualized by Chrome's ``about:tracing`` page | |||
+You can also see how deep function calls we may have due to AST visitors. | |||
+ | |||
+Using different filters can reduce the number of functions to record. | |||
+For the common options, refer to the ``uftrace`` `documentation <https://github.com/namhyung/uftrace/blob/master/doc/uftrace-record.md#common-options>`_. | |||
+ | |||
+Similar filters can be applied for dumping too. That way you can reuse the same (detailed) | |||
+recording to selectively focus on some special part using a refinement of the filter flags. | |||
+Remember, the trace JSON needs to fit into Chrome's ``about:tracing`` or `speedscope <https://speedscope.app>`_, | |||
+thus it needs to be of a limited size. | |||
+If you do not apply filters on recording, you will collect a large trace and every dump operation | |||
+would need to sieve through the much larger recording which may be annoying if done repeatedly. | |||
+ | |||
+If the trace JSON is still too large to load, have a look at the dump as plain text and look for frequent entries that refer to non-interesting parts. | |||
+Once you have some of those, add them as ``--hide`` flags to the ``uftrace dump`` call. | |||
+To see what functions appear frequently in the trace, use this command: | |||
+ | |||
+.. code-block:: bash | |||
+ | |||
+ cat trace.json | grep -Po '"name":"(.+)"' | sort | uniq -c | sort -nr | head -n 50 | |||
+ | |||
+``uftrace`` can also dump the report as a Flame graph using ``uftrace dump --framegraph``. |
@@ -2206,7 +2206,11 @@ enum CXCursorKind { | |||
*/ | */ | ||
CXCursor_OpenACC | CXCursor_OpenACC | ||
- CXCursor_LastStm | + /** OpenACC atomic Construct. | ||
+ */ | |||
+ CXCursor_OpenACC | |||
+ | |||
+ CXCursor_LastStm | |||
/** | /** | ||
* Cursor that represents the translation unit itself. | * Cursor that represents the translation unit itself. |
@@ -1733,6 +1733,47 @@ public: | |||
unsigned NumPositiveBits, | unsigned NumPositiveBits, | ||
QualType &BestPromotionTyp | QualType &BestPromotionTyp | ||
+ /// Determine whether the given integral value is representable within | |||
+ /// the given type T. | |||
+ bool isRepresentableI | |||
+ | |||
+ /// Compute NumNegativeBits and NumPositiveBits for an enum based on | |||
+ /// the constant values of its enumerators. | |||
+ template <typename RangeT> | |||
+ bool computeEnumBits(RangeT EnumConstants, unsigned &NumNegativeBits, | |||
+ unsigned &NumPositiveBits) { | |||
+ NumNegativeBits = 0; | |||
+ NumPositiveBits = 0; | |||
+ bool MembersRepresent | |||
+ for (auto *Elem : EnumConstants) { | |||
+ EnumConstantDecl | |||
+ if (!ECD) | |||
+ continue; // Already issued a diagnostic. | |||
+ | |||
+ llvm::APSInt InitVal = ECD->getInitVal(); | |||
+ if (InitVal.isUnsigned() || InitVal.isNonNegative()) { | |||
+ // If the enumerator is zero that should still be counted as a positive | |||
+ // bit since we need a bit to store the value zero. | |||
+ unsigned ActiveBits = InitVal.getActiveBits(); | |||
+ NumPositiveBits = std::max({NumPositiveBits, | |||
+ } else { | |||
+ NumNegativeBits = | |||
+ std::max(NumNegativeBits, | |||
+ } | |||
+ | |||
+ MembersRepresent | |||
+ } | |||
+ | |||
+ // If we have an empty set of enumerators we still need one bit. | |||
+ // From [dcl.enum]p8 | |||
+ // If the enumerator-list is empty, the values of the enumeration are as if | |||
+ // the enumeration had a single enumerator with value 0 | |||
+ if (!NumPositiveBits && !NumNegativeBits) | |||
+ NumPositiveBits = 1; | |||
+ | |||
+ return MembersRepresent | |||
+ } | |||
+ | |||
QualType | QualType | ||
getUnresolvedUsi | getUnresolvedUsi | ||
@@ -2298,6 +2298,13 @@ public: | |||
FunctionDeclBits | FunctionDeclBits | ||
} | } | ||
+ bool isInstantiatedFr | |||
+ return FunctionDeclBits | |||
+ } | |||
+ void setInstantiatedF | |||
+ FunctionDeclBits | |||
+ } | |||
+ | |||
/// Whether this function is "trivial" in some specialized C++ senses. | /// Whether this function is "trivial" in some specialized C++ senses. | ||
/// Can only be true for default constructors, copy constructors, | /// Can only be true for default constructors, copy constructors, | ||
/// copy assignment operators, and destructors. Not meaningful until | /// copy assignment operators, and destructors. Not meaningful until |
@@ -1257,8 +1257,11 @@ public: | |||
int64_t getID() const; | int64_t getID() const; | ||
/// Looks through the Decl's underlying type to extract a FunctionType | /// Looks through the Decl's underlying type to extract a FunctionType | ||
- /// when possible. | + /// when possible. This includes direct FunctionDecls, along with various | ||
- /// have a FunctionType. | + /// function types and typedefs. This includes function pointers/references, | ||
+ /// member function pointers, and optionally if \p BlocksToo is set | |||
+ /// Objective-C block pointers. Returns nullptr if the type underlying the | |||
+ /// Decl does not have a FunctionType. | |||
const FunctionType *getFunctionType(bool BlocksToo = true) const; | const FunctionType *getFunctionType(bool BlocksToo = true) const; | ||
// Looks through the Decl's underlying type to determine if it's a | // Looks through the Decl's underlying type to determine if it's a | ||
@@ -1777,6 +1780,8 @@ protected: | |||
uint64_t HasImplicitRetur | uint64_t HasImplicitRetur | ||
LLVM_PREFERRED_T | LLVM_PREFERRED_T | ||
uint64_t IsLateTemplatePa | uint64_t IsLateTemplatePa | ||
+ LLVM_PREFERRED_T | |||
+ uint64_t IsInstantiatedFr | |||
/// Kind of contexpr specifier as defined by ConstexprSpecKin | /// Kind of contexpr specifier as defined by ConstexprSpecKin | ||
LLVM_PREFERRED_T | LLVM_PREFERRED_T | ||
@@ -1827,7 +1832,7 @@ protected: | |||
}; | }; | ||
/// Number of inherited and non-inherited bits in FunctionDeclBitf | /// Number of inherited and non-inherited bits in FunctionDeclBitf | ||
- enum { NumFunctionDeclBits = NumDeclContextBits + | + enum { NumFunctionDeclBits = NumDeclContextBits + 32 }; | ||
/// Stores the bits used by CXXConstructorDe | /// Stores the bits used by CXXConstructorDe | ||
/// NumCXXConstructo | /// NumCXXConstructo | ||
@@ -1838,12 +1843,12 @@ protected: | |||
LLVM_PREFERRED_T | LLVM_PREFERRED_T | ||
uint64_t : NumFunctionDeclB | uint64_t : NumFunctionDeclB | ||
- /// | + /// 19 bits to fit in the remaining available space. | ||
/// Note that this makes CXXConstructorDe | /// Note that this makes CXXConstructorDe | ||
/// exactly 64 bits and thus the width of NumCtorInitializ | /// exactly 64 bits and thus the width of NumCtorInitializ | ||
/// will need to be shrunk if some bit is added to NumDeclContextBi | /// will need to be shrunk if some bit is added to NumDeclContextBi | ||
/// NumFunctionDeclB | /// NumFunctionDeclB | ||
- uint64_t NumCtorInitializers : | + uint64_t NumCtorInitializers : 16; | ||
LLVM_PREFERRED_T | LLVM_PREFERRED_T | ||
uint64_t IsInheritingCons | uint64_t IsInheritingCons | ||
@@ -1857,7 +1862,7 @@ protected: | |||
}; | }; | ||
/// Number of inherited and non-inherited bits in CXXConstructorDe | /// Number of inherited and non-inherited bits in CXXConstructorDe | ||
- enum { NumCXXConstructorDeclBits = NumFunctionDeclBits + | + enum { NumCXXConstructorDeclBits = NumFunctionDeclBits + 19 }; | ||
/// Stores the bits used by ObjCMethodDecl. | /// Stores the bits used by ObjCMethodDecl. | ||
/// If modified NumObjCMethodDec | /// If modified NumObjCMethodDec |
@@ -1011,6 +1011,26 @@ public: | |||
return getTemplatedDecl | return getTemplatedDecl | ||
} | } | ||
+ bool isCompatibleWith | |||
+ return getTemplatedDecl | |||
+ isThisDeclaratio | |||
+ } | |||
+ | |||
+ // This bit closely tracks 'RedeclarableTemp | |||
+ // except this is per declaration, while the redeclarable field is | |||
+ // per chain. This indicates a template redeclaration which | |||
+ // is compatible with the definition, in the non-trivial case | |||
+ // where this is not already a definition. | |||
+ // This is only really needed for instantiating the definition of friend | |||
+ // function templates, which can have redeclarations in different template | |||
+ // contexts. | |||
+ // The bit is actually stored in the FunctionDecl for space efficiency | |||
+ // reasons. | |||
+ void setInstantiatedF | |||
+ getTemplatedDecl | |||
+ RedeclarableTemp | |||
+ } | |||
+ | |||
/// Return the specialization with the provided arguments if it exists, | /// Return the specialization with the provided arguments if it exists, | ||
/// otherwise return the insertion point. | /// otherwise return the insertion point. | ||
FunctionDecl *findSpecializati | FunctionDecl *findSpecializati | ||
@@ -1841,15 +1861,23 @@ class ClassTemplateSpe | |||
LLVM_PREFERRED_T | LLVM_PREFERRED_T | ||
unsigned SpecializationKi | unsigned SpecializationKi | ||
+ /// Indicate that we have matched a parameter pack with a non pack | |||
+ /// argument, when the opposite match is also allowed. | |||
+ /// This needs to be cached as deduction is performed during declaration, | |||
+ /// and we need the information to be preserved so that it is consistent | |||
+ /// during instantiation. | |||
+ bool StrictPackMatch : 1; | |||
+ | |||
protected: | protected: | ||
ClassTemplateSpe | ClassTemplateSpe | ||
DeclContext *DC, SourceLocation StartLoc, | DeclContext *DC, SourceLocation StartLoc, | ||
SourceLocation IdLoc, | SourceLocation IdLoc, | ||
ClassTemplateDec | ClassTemplateDec | ||
ArrayRef<TemplateArgument | ArrayRef<TemplateArgument | ||
+ bool StrictPackMatch, | |||
ClassTemplateSpe | ClassTemplateSpe | ||
- | + ClassTemplateSpecializationDecl(ASTContext &C, Kind DK); | ||
public: | public: | ||
friend class ASTDeclReader; | friend class ASTDeclReader; | ||
@@ -1859,7 +1887,7 @@ public: | |||
Create(ASTContext &Context, TagKind TK, DeclContext *DC, | Create(ASTContext &Context, TagKind TK, DeclContext *DC, | ||
SourceLocation StartLoc, SourceLocation IdLoc, | SourceLocation StartLoc, SourceLocation IdLoc, | ||
ClassTemplateDec | ClassTemplateDec | ||
- ArrayRef<TemplateArgument> Args, | + ArrayRef<TemplateArgument> Args, bool StrictPackMatch, | ||
ClassTemplateSpe | ClassTemplateSpe | ||
static ClassTemplateSpe | static ClassTemplateSpe | ||
GlobalDeclID ID); | GlobalDeclID ID); | ||
@@ -1930,6 +1958,10 @@ public: | |||
SpecializationKi | SpecializationKi | ||
} | } | ||
+ bool hasStrictPackMat | |||
+ | |||
+ void setStrictPackMat | |||
+ | |||
/// Get the point of instantiation (if any), or null if none. | /// Get the point of instantiation (if any), or null if none. | ||
SourceLocation getPointOfInstan | SourceLocation getPointOfInstan | ||
return PointOfInstantia | return PointOfInstantia |
@@ -6678,7 +6678,6 @@ public: | |||
class AtomicExpr : public Expr { | class AtomicExpr : public Expr { | ||
public: | public: | ||
enum AtomicOp { | enum AtomicOp { | ||
-#define BUILTIN(ID, TYPE, ATTRS) | |||
#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) AO ## ID, | #define ATOMIC_BUILTIN(ID, TYPE, ATTRS) AO ## ID, | ||
#include "clang/Basic/Builtins.inc" | #include "clang/Basic/Builtins.inc" | ||
// Avoid trailing comma | // Avoid trailing comma | ||
@@ -6742,7 +6741,6 @@ public: | |||
AtomicOp getOp() const { return Op; } | AtomicOp getOp() const { return Op; } | ||
StringRef getOpAsString() const { | StringRef getOpAsString() const { | ||
switch (Op) { | switch (Op) { | ||
-#define BUILTIN(ID, TYPE, ATTRS) | |||
#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \ | #define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \ | ||
case AO##ID: \ | case AO##ID: \ | ||
return #ID; | return #ID; |
@@ -5040,7 +5040,7 @@ public: | |||
} | } | ||
const FieldDecl *getInitializedFi | const FieldDecl *getInitializedFi | ||
- return | + return dyn_cast_if_present<FieldDecl *>(ArrayFillerOrUnionFieldInit); | ||
} | } | ||
child_range children() { | child_range children() { |
@@ -2423,6 +2423,28 @@ public: | |||
OMPNoOpenMPRouti | OMPNoOpenMPRouti | ||
}; | }; | ||
+/// This represents the 'no_openmp_constr | |||
+//// '#pragma omp assume' directive. | |||
+/// | |||
+/// \code | |||
+/// #pragma omp assume no_openmp_constr | |||
+/// \endcode | |||
+/// In this example directive '#pragma omp assume' has a 'no_openmp_constr | |||
+/// clause. | |||
+class OMPNoOpenMPConst | |||
+ : public OMPNoChildClause | |||
+public: | |||
+ /// Build 'no_openmp_constr | |||
+ /// | |||
+ /// \param StartLoc Starting location of the clause. | |||
+ /// \param EndLoc Ending location of the clause. | |||
+ OMPNoOpenMPConst | |||
+ : OMPNoChildClause | |||
+ | |||
+ /// Build an empty clause. | |||
+ OMPNoOpenMPConst | |||
+}; | |||
+ | |||
/// This represents the 'no_parallelism' clause in the '#pragma omp assume' | /// This represents the 'no_parallelism' clause in the '#pragma omp assume' | ||
/// directive. | /// directive. | ||
/// | /// | ||
@@ -9451,7 +9473,8 @@ struct TargetOMPContext | |||
TargetOMPContext | TargetOMPContext | ||
std::function<void(StringRef)> &&DiagUnknownTrait | std::function<void(StringRef)> &&DiagUnknownTrait | ||
const FunctionDecl *CurrentFunctionD | const FunctionDecl *CurrentFunctionD | ||
- ArrayRef<llvm::omp::TraitProperty> ConstructTraits | + ArrayRef<llvm::omp::TraitProperty> ConstructTraits, | ||
+ int DeviceNum); | |||
virtual ~TargetOMPContext | virtual ~TargetOMPContext | ||
@@ -367,6 +367,9 @@ CAST_OPERATION(H | |||
// Non-decaying array RValue cast (HLSL only). | // Non-decaying array RValue cast (HLSL only). | ||
CAST_OPERATION(HLSLArrayRValue) | CAST_OPERATION(HLSLArrayRValue) | ||
+// Aggregate by Value cast (HLSL only). | |||
+CAST_OPERATION(HLSLElementwiseC | |||
+ | |||
//===- Binary Operations -------------------------------------------------===// | //===- Binary Operations -------------------------------------------------===// | ||
// Operators listed in order of precedence. | // Operators listed in order of precedence. | ||
// Note that additions to this should also update the StmtVisitor class, | // Note that additions to this should also update the StmtVisitor class, |
@@ -3544,6 +3544,12 @@ bool RecursiveASTVisi | |||
return true; | return true; | ||
} | } | ||
+template <typename Derived> | |||
+bool RecursiveASTVisi | |||
+ OMPNoOpenMPConst | |||
+ return true; | |||
+} | |||
+ | |||
template <typename Derived> | template <typename Derived> | ||
bool RecursiveASTVisi | bool RecursiveASTVisi | ||
OMPNoParallelism | OMPNoParallelism | ||
@@ -4099,6 +4105,8 @@ DEF_TRAVERSE_STM | |||
{ TRY_TO(VisitOpenACCClau | { TRY_TO(VisitOpenACCClau | ||
DEF_TRAVERSE_STM | DEF_TRAVERSE_STM | ||
{ TRY_TO(VisitOpenACCClau | { TRY_TO(VisitOpenACCClau | ||
+DEF_TRAVERSE_STM | |||
+ { TRY_TO(TraverseOpenACCA | |||
// Traverse HLSL: Out argument expression | // Traverse HLSL: Out argument expression | ||
DEF_TRAVERSE_STM | DEF_TRAVERSE_STM |
@@ -751,5 +751,50 @@ public: | |||
Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, | Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, | ||
SourceLocation End, ArrayRef<const OpenACCClause *> Clauses); | SourceLocation End, ArrayRef<const OpenACCClause *> Clauses); | ||
}; | }; | ||
+ | |||
+// This class represents the 'atomic' construct, which has an associated | |||
+// statement, but no clauses. | |||
+class OpenACCAtomicCon | |||
+ | |||
+ friend class ASTStmtReader; | |||
+ OpenACCAtomicKin | |||
+ | |||
+ OpenACCAtomicCon | |||
+ : OpenACCAssociate | |||
+ OpenACCAtomicCon | |||
+ SourceLocation{}, SourceLocation{}, SourceLocation{}, | |||
+ /*AssociatedStmt=*/nullptr) {} | |||
+ | |||
+ OpenACCAtomicCon | |||
+ OpenACCAtomicKin | |||
+ Stmt *AssociatedStmt) | |||
+ : OpenACCAssociate | |||
+ OpenACCDirective | |||
+ DirectiveLoc, End, AssociatedStmt), | |||
+ AtomicKind(AtKind) {} | |||
+ | |||
+ void setAssociatedStm | |||
+ OpenACCAssociate | |||
+ } | |||
+ | |||
+public: | |||
+ static bool classof(const Stmt *T) { | |||
+ return T->getStmtClass() == OpenACCAtomicCon | |||
+ } | |||
+ | |||
+ static OpenACCAtomicCon | |||
+ static OpenACCAtomicCon | |||
+ Create(const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, | |||
+ OpenACCAtomicKin | |||
+ | |||
+ OpenACCAtomicKin | |||
+ const Stmt *getAssociatedStm | |||
+ return OpenACCAssociate | |||
+ } | |||
+ Stmt *getAssociatedStm | |||
+ return OpenACCAssociate | |||
+ } | |||
+}; | |||
+ | |||
} // namespace clang | } // namespace clang | ||
#endif // LLVM_CLANG_AST_S | #endif // LLVM_CLANG_AST_S |
@@ -420,6 +420,7 @@ public: | |||
void VisitOpenACCSetC | void VisitOpenACCSetC | ||
void VisitOpenACCShut | void VisitOpenACCShut | ||
void VisitOpenACCUpda | void VisitOpenACCUpda | ||
+ void VisitOpenACCAtom | |||
void VisitOpenACCAste | void VisitOpenACCAste | ||
void VisitEmbedExpr(const EmbedExpr *S); | void VisitEmbedExpr(const EmbedExpr *S); | ||
void VisitAtomicExpr(const AtomicExpr *AE); | void VisitAtomicExpr(const AtomicExpr *AE); |
@@ -2489,7 +2489,28 @@ extern const internal::Variad | |||
extern const internal::VariadicDynCastA | extern const internal::VariadicDynCastA | ||
imaginaryLiteral | imaginaryLiteral | ||
-/// Matches fixed | +/// Matches fixed-point literals eg. | ||
+/// 0.5r, 0.5hr, 0.5lr, 0.5uhr, 0.5ur, 0.5ulr | |||
+/// 1.0k, 1.0hk, 1.0lk, 1.0uhk, 1.0uk, 1.0ulk | |||
+/// Exponents 1.0e10k | |||
+/// Hexadecimal numbers 0x0.2p2r | |||
+/// | |||
+/// Does not match implicit conversions such as first two lines: | |||
+/// \code | |||
+/// short _Accum sa = 2; | |||
+/// _Accum a = 12.5; | |||
+/// _Accum b = 1.25hk; | |||
+/// _Fract c = 0.25hr; | |||
+/// _Fract v = 0.35uhr; | |||
+/// _Accum g = 1.45uhk; | |||
+/// _Accum decexp1 = 1.575e1k; | |||
+/// \endcode | |||
+/// \compile_args{-ffixed-point;-std=c99} | |||
+/// | |||
+/// The matcher \matcher{fixedPointLitera | |||
+/// \match{1.25hk}, \match{0.25hr}, \match{0.35uhr}, | |||
+/// \match{1.45uhk}, \match{1.575e1k}, but does not | |||
+/// match \nomatch{12.5} and \nomatch{2} from the code block. | |||
extern const internal::VariadicDynCastA | extern const internal::VariadicDynCastA | ||
fixedPointLitera | fixedPointLitera | ||
@@ -85,6 +85,9 @@ public: | |||
LoopExitKind, | LoopExitKind, | ||
EpsilonKind}; | EpsilonKind}; | ||
+ static StringRef getProgramPointK | |||
+ std::optional<SourceLocation> getSourceLocatio | |||
+ | |||
private: | private: | ||
const void *Data1; | const void *Data1; | ||
llvm::PointerIntPair<const void *, 2, unsigned> Data2; | llvm::PointerIntPair<const void *, 2, unsigned> Data2; |
@@ -198,7 +198,7 @@ def OpenCLKernelFunc | |||
// inclusive nature of subject testing). | // inclusive nature of subject testing). | ||
def HasFunctionProto | def HasFunctionProto | ||
[{(S->getFunctionType(true) != nullptr && | [{(S->getFunctionType(true) != nullptr && | ||
- | + isa<FunctionProtoType>(S->getFunctionType())) || | ||
isa<ObjCMethodDecl>(S) || | isa<ObjCMethodDecl>(S) || | ||
isa<BlockDecl>(S)}], | isa<BlockDecl>(S)}], | ||
"non-K&R-style functions">; | "non-K&R-style functions">; | ||
@@ -380,6 +380,13 @@ class Clang<string name, bit allowInC = 1, int version = 1> | |||
bit AllowInC = allowInC; | bit AllowInC = allowInC; | ||
} | } | ||
+// This spelling combines the spellings of GCC and Clang for cases where the | |||
+// spellings are equivalent for compile compatibility. | |||
+class ClangGCC<string name, bit allowInC = 1, int version = 1> | |||
+ : Spelling<name, "ClangGCC", version> { | |||
+ bit AllowInC = allowInC; | |||
+} | |||
+ | |||
// HLSL Annotation spellings | // HLSL Annotation spellings | ||
class HLSLAnnotation<string name> : Spelling<name, "HLSLAnnotation">; | class HLSLAnnotation<string name> : Spelling<name, "HLSLAnnotation">; | ||
@@ -3677,7 +3684,7 @@ def X86ForceAlignArg | |||
} | } | ||
def NoSanitize : InheritableAttr { | def NoSanitize : InheritableAttr { | ||
- let Spellings = [ | + let Spellings = [ClangGCC<"no_sanitize">]; | ||
let Args = [VariadicStringAr | let Args = [VariadicStringAr | ||
let Subjects = SubjectList<[Function, ObjCMethod, GlobalVar], ErrorDiag>; | let Subjects = SubjectList<[Function, ObjCMethod, GlobalVar], ErrorDiag>; | ||
let Documentation = [NoSanitizeDocs]; | let Documentation = [NoSanitizeDocs]; |
@@ -5274,6 +5274,7 @@ optimization passes are aware of the following assumptions: | |||
"omp_no_openmp" | "omp_no_openmp" | ||
"omp_no_openmp_ro | "omp_no_openmp_ro | ||
"omp_no_paralleli | "omp_no_paralleli | ||
+ "omp_no_openmp_co | |||
The OpenMP standard defines the meaning of OpenMP assumptions ("omp_XYZ" is | The OpenMP standard defines the meaning of OpenMP assumptions ("omp_XYZ" is | ||
spelled "XYZ" in the `OpenMP 5.1 Standard`_). | spelled "XYZ" in the `OpenMP 5.1 Standard`_). |
@@ -18,6 +18,7 @@ | |||
#include "llvm/ADT/ArrayRef.h" | #include "llvm/ADT/ArrayRef.h" | ||
#include "llvm/ADT/StringMap.h" | #include "llvm/ADT/StringMap.h" | ||
#include "llvm/ADT/StringRef.h" | #include "llvm/ADT/StringRef.h" | ||
+#include "llvm/ADT/StringTable.h" | |||
#include <cstring> | #include <cstring> | ||
// VC++ defines 'alloca' as an object-like macro, which interferes with our | // VC++ defines 'alloca' as an object-like macro, which interferes with our | ||
@@ -55,6 +56,7 @@ struct HeaderDesc { | |||
#undef HEADER | #undef HEADER | ||
} ID; | } ID; | ||
+ constexpr HeaderDesc() : ID() {} | |||
constexpr HeaderDesc(HeaderID ID) : ID(ID) {} | constexpr HeaderDesc(HeaderID ID) : ID(ID) {} | ||
const char *getName() const; | const char *getName() const; | ||
@@ -62,20 +64,160 @@ struct HeaderDesc { | |||
namespace Builtin { | namespace Builtin { | ||
enum ID { | enum ID { | ||
- NotBuiltin | + NotBuiltin = 0, // This is not a builtin function. | ||
-#define BUILTIN(ID, TYPE, ATTRS) BI##ID, | +#define GET_BUILTIN_ENUM | ||
#include "clang/Basic/Builtins.inc" | #include "clang/Basic/Builtins.inc" | ||
+#undef GET_BUILTIN_ENUM | |||
FirstTSBuiltin | FirstTSBuiltin | ||
}; | }; | ||
+struct InfosShard; | |||
+ | |||
+/// The info used to represent each builtin. | |||
struct Info { | struct Info { | ||
- llvm::StringLiteral Name; | + // Rather than store pointers to the string literals describing these four | ||
- const char *Type, *Attributes; | + // aspects of builtins, we store offsets into a common string table. | ||
- const char *Features; | + struct StrOffsets { | ||
- HeaderDesc Header; | + llvm::StringTable::Offset Name = {}; | ||
- LanguageID Langs; | + llvm::StringTable::Offset Type = {}; | ||
+ llvm::StringTable::Offset Attributes = {}; | |||
+ | |||
+ // Defaults to the empty string offset. | |||
+ llvm::StringTable::Offset Features = {}; | |||
+ } Offsets; | |||
+ | |||
+ HeaderDesc Header = HeaderDesc::NO_HEADER; | |||
+ LanguageID Langs = ALL_LANGUAGES; | |||
+ | |||
+ /// Get the name for the builtin represented by this `Info` object. | |||
+ /// | |||
+ /// Must be provided the `Shard` for this `Info` object. | |||
+ std::string getName(const InfosShard &Shard) const; | |||
}; | }; | ||
+/// A constexpr function to construct an infos array from X-macros. | |||
+/// | |||
+/// The input array uses the same data structure, but the offsets are actually | |||
+/// _lengths_ when input. This is all we can compute from the X-macro approach | |||
+/// to builtins. This function will convert these lengths into actual offsets to | |||
+/// a string table built up through sequentially appending strings with the | |||
+/// given lengths. | |||
+template <size_t N> | |||
+static constexpr std::array<Info, N> MakeInfos(std::array<Info, N> Infos) { | |||
+ // Translate lengths to offsets. We start past the initial empty string at | |||
+ // offset zero. | |||
+ unsigned Offset = 1; | |||
+ for (Info &I : Infos) { | |||
+ Info::StrOffsets NewOffsets = {}; | |||
+ NewOffsets.Name = Offset; | |||
+ Offset += I.Offsets.Name.value(); | |||
+ NewOffsets.Type = Offset; | |||
+ Offset += I.Offsets.Type.value(); | |||
+ NewOffsets.Attributes = Offset; | |||
+ Offset += I.Offsets.Attributes.value(); | |||
+ NewOffsets.Features = Offset; | |||
+ Offset += I.Offsets.Features.value(); | |||
+ I.Offsets = NewOffsets; | |||
+ } | |||
+ return Infos; | |||
+} | |||
+ | |||
+/// A shard of a target's builtins string table and info. | |||
+/// | |||
+/// Target builtins are sharded across multiple tables due to different | |||
+/// structures, origins, and also to improve the overall scaling by avoiding a | |||
+/// single table across all builtins. | |||
+struct InfosShard { | |||
+ const llvm::StringTable *Strings; | |||
+ llvm::ArrayRef<Info> Infos; | |||
+ | |||
+ llvm::StringLiteral NamePrefix = ""; | |||
+}; | |||
+ | |||
+// A detail macro used below to emit a string literal that, after string literal | |||
+// concatenation, ends up triggering the `-Woverlength-strings` warning. While | |||
+// the warning is useful in general to catch accidentally excessive strings, | |||
+// here we are creating them intentionally. | |||
+// | |||
+// This relies on a subtle aspect of `_Pragma`: that the *diagnostic* ones don't | |||
+// turn into actual tokens that would disrupt string literal concatenation. | |||
+#ifdef __clang__ | |||
+#define CLANG_BUILTIN_DE | |||
+ _Pragma("clang diagnostic push") \ | |||
+ _Pragma("clang diagnostic ignored \"-Woverlength-strings\"") \ | |||
+ S _Pragma("clang diagnostic pop") | |||
+#else | |||
+#define CLANG_BUILTIN_DE | |||
+#endif | |||
+ | |||
+// We require string tables to start with an empty string so that a `0` offset | |||
+// can always be used to refer to an empty string. To satisfy that when building | |||
+// string tables with X-macros, we use this start macro prior to expanding the | |||
+// X-macros. | |||
+#define CLANG_BUILTIN_ST | |||
+ | |||
+// A macro that can be used with `Builtins.def` and similar files as an X-macro | |||
+// to add the string arguments to a builtin string table. This is typically the | |||
+// target for the `BUILTIN`, `LANGBUILTIN`, or `LIBBUILTIN` macros in those | |||
+// files. | |||
+#define CLANG_BUILTIN_ST | |||
+ CLANG_BUILTIN_DE | |||
+ | |||
+// A macro that can be used with target builtin `.def` and `.inc` files as an | |||
+// X-macro to add the string arguments to a builtin string table. this is | |||
+// typically the target for the `TARGET_BUILTIN` macro. | |||
+#define CLANG_TARGET_BUI | |||
+ CLANG_BUILTIN_DE | |||
+ | |||
+// A macro that can be used with target builtin `.def` and `.inc` files as an | |||
+// X-macro to add the string arguments to a builtin string table. this is | |||
+// typically the target for the `TARGET_HEADER_BU | |||
+// to `TARGET_BUILTIN` because the `FEATURE` string changes position. | |||
+#define CLANG_TARGET_HEA | |||
+ FEATURE) \ | |||
+ CLANG_BUILTIN_DE | |||
+ | |||
+// A detail macro used internally to compute the desired string table | |||
+// `StrOffsets` struct for arguments to `MakeInfos`. | |||
+#define CLANG_BUILTIN_DE | |||
+ Builtin::Info::StrOffsets { \ | |||
+ sizeof(#ID), sizeof(TYPE), sizeof(ATTRS), sizeof("") \ | |||
+ } | |||
+ | |||
+// A detail macro used internally to compute the desired string table | |||
+// `StrOffsets` struct for arguments to `Storage::Make`. | |||
+#define CLANG_TARGET_BUI | |||
+ Builtin::Info::StrOffsets { \ | |||
+ sizeof(#ID), sizeof(TYPE), sizeof(ATTRS), sizeof(FEATURE) \ | |||
+ } | |||
+ | |||
+// A set of macros that can be used with builtin `.def' files as an X-macro to | |||
+// create an `Info` struct for a particular builtin. It both computes the | |||
+// `StrOffsets` value for the string table (the lengths here, translated to | |||
+// offsets by the `MakeInfos` function), and the other metadata for each | |||
+// builtin. | |||
+// | |||
+// There is a corresponding macro for each of `BUILTIN`, `LANGBUILTIN`, | |||
+// `LIBBUILTIN`, `TARGET_BUILTIN`, and `TARGET_HEADER_BU | |||
+#define CLANG_BUILTIN_EN | |||
+ Builtin::Info{CLANG_BUILTIN_DE | |||
+ HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | |||
+#define CLANG_LANGBUILTI | |||
+ Builtin::Info{CLANG_BUILTIN_DE | |||
+ HeaderDesc::NO_HEADER, LANG}, | |||
+#define CLANG_LIBBUILTIN | |||
+ Builtin::Info{CLANG_BUILTIN_DE | |||
+ HeaderDesc::HEADER, LANG}, | |||
+#define CLANG_TARGET_BUI | |||
+ Builtin::Info{ \ | |||
+ CLANG_TARGET_BUI | |||
+ HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | |||
+#define CLANG_TARGET_HEA | |||
+ FEATURE) \ | |||
+ Builtin::Info{ \ | |||
+ CLANG_TARGET_BUI | |||
+ HeaderDesc::HEADER, LANG}, | |||
+ | |||
/// Holds information about both target-independent and | /// Holds information about both target-independent and | ||
/// target-specific builtins, allowing easy queries by clients. | /// target-specific builtins, allowing easy queries by clients. | ||
/// | /// | ||
@@ -83,11 +225,16 @@ struct Info { | |||
/// AuxTSRecords. Their IDs are shifted up by TSRecords.size() and need to | /// AuxTSRecords. Their IDs are shifted up by TSRecords.size() and need to | ||
/// be translated back with getAuxBuiltinID() before use. | /// be translated back with getAuxBuiltinID() before use. | ||
class Context { | class Context { | ||
- llvm::ArrayRef<Info> TSRecords; | + llvm::SmallVector<InfosShard> BuiltinShards; | ||
- llvm::ArrayRef<Info> AuxTSRecords; | + | ||
+ llvm::SmallVector<InfosShard> TargetShards; | |||
+ llvm::SmallVector<InfosShard> AuxTargetShards; | |||
+ | |||
+ unsigned NumTargetBuiltin | |||
+ unsigned NumAuxTargetBuil | |||
public: | public: | ||
- Context() | + Context(); | ||
/// Perform target-specific initialization | /// Perform target-specific initialization | ||
/// \param AuxTarget Target info to incorporate builtins from. May be nullptr. | /// \param AuxTarget Target info to incorporate builtins from. May be nullptr. | ||
@@ -100,13 +247,17 @@ public: | |||
/// Return the identifier name for the specified builtin, | /// Return the identifier name for the specified builtin, | ||
/// e.g. "__builtin_abs". | /// e.g. "__builtin_abs". | ||
- llvm::StringRef getName(unsigned ID) const { return getRecord(ID).Name; } | + std::string getName(unsigned ID) const; | ||
- /// Return | + /// Return the identifier name for the specified builtin inside single quotes | ||
+ /// for a diagnostic, e.g. "'__builtin_abs'". | |||
std::string getQuotedName(unsigned ID) const; | std::string getQuotedName(unsigned ID) const; | ||
/// Get the type descriptor string for the specified builtin. | /// Get the type descriptor string for the specified builtin. | ||
- const char *getTypeString(unsigned ID) | + const char *getTypeString(unsigned ID) const; | ||
+ | |||
+ /// Get the attributes descriptor string for the specified builtin. | |||
+ const char *getAttributesStr | |||
/// Return true if this function is a target-specific builtin. | /// Return true if this function is a target-specific builtin. | ||
bool isTSBuiltin(unsigned ID) const { | bool isTSBuiltin(unsigned ID) const { | ||
@@ -115,40 +266,40 @@ public: | |||
/// Return true if this function has no side effects. | /// Return true if this function has no side effects. | ||
bool isPure(unsigned ID) const { | bool isPure(unsigned ID) const { | ||
- return strchr( | + return strchr(getAttributesString(ID), 'U') != nullptr; | ||
} | } | ||
/// Return true if this function has no side effects and doesn't | /// Return true if this function has no side effects and doesn't | ||
/// read memory. | /// read memory. | ||
bool isConst(unsigned ID) const { | bool isConst(unsigned ID) const { | ||
- return strchr( | + return strchr(getAttributesString(ID), 'c') != nullptr; | ||
} | } | ||
/// Return true if we know this builtin never throws an exception. | /// Return true if we know this builtin never throws an exception. | ||
bool isNoThrow(unsigned ID) const { | bool isNoThrow(unsigned ID) const { | ||
- return strchr( | + return strchr(getAttributesString(ID), 'n') != nullptr; | ||
} | } | ||
/// Return true if we know this builtin never returns. | /// Return true if we know this builtin never returns. | ||
bool isNoReturn(unsigned ID) const { | bool isNoReturn(unsigned ID) const { | ||
- return strchr( | + return strchr(getAttributesString(ID), 'r') != nullptr; | ||
} | } | ||
/// Return true if we know this builtin can return twice. | /// Return true if we know this builtin can return twice. | ||
bool isReturnsTwice(unsigned ID) const { | bool isReturnsTwice(unsigned ID) const { | ||
- return strchr( | + return strchr(getAttributesString(ID), 'j') != nullptr; | ||
} | } | ||
/// Returns true if this builtin does not perform the side-effects | /// Returns true if this builtin does not perform the side-effects | ||
/// of its arguments. | /// of its arguments. | ||
bool isUnevaluated(unsigned ID) const { | bool isUnevaluated(unsigned ID) const { | ||
- return strchr( | + return strchr(getAttributesString(ID), 'u') != nullptr; | ||
} | } | ||
/// Return true if this is a builtin for a libc/libm function, | /// Return true if this is a builtin for a libc/libm function, | ||
/// with a "__builtin_" prefix (e.g. __builtin_abs). | /// with a "__builtin_" prefix (e.g. __builtin_abs). | ||
bool isLibFunction(unsigned ID) const { | bool isLibFunction(unsigned ID) const { | ||
- return strchr( | + return strchr(getAttributesString(ID), 'F') != nullptr; | ||
} | } | ||
/// Determines whether this builtin is a predefined libc/libm | /// Determines whether this builtin is a predefined libc/libm | ||
@@ -159,21 +310,21 @@ public: | |||
/// they do not, but they are recognized as builtins once we see | /// they do not, but they are recognized as builtins once we see | ||
/// a declaration. | /// a declaration. | ||
bool isPredefinedLibF | bool isPredefinedLibF | ||
- return strchr( | + return strchr(getAttributesString(ID), 'f') != nullptr; | ||
} | } | ||
/// Returns true if this builtin requires appropriate header in other | /// Returns true if this builtin requires appropriate header in other | ||
/// compilers. In Clang it will work even without including it, but we can emit | /// compilers. In Clang it will work even without including it, but we can emit | ||
/// a warning about missing header. | /// a warning about missing header. | ||
bool isHeaderDependen | bool isHeaderDependen | ||
- return strchr( | + return strchr(getAttributesString(ID), 'h') != nullptr; | ||
} | } | ||
/// Determines whether this builtin is a predefined compiler-rt/libgcc | /// Determines whether this builtin is a predefined compiler-rt/libgcc | ||
/// function, such as "__clear_cache", where we know the signature a | /// function, such as "__clear_cache", where we know the signature a | ||
/// priori. | /// priori. | ||
bool isPredefinedRunt | bool isPredefinedRunt | ||
- return strchr( | + return strchr(getAttributesString(ID), 'i') != nullptr; | ||
} | } | ||
/// Determines whether this builtin is a C++ standard library function | /// Determines whether this builtin is a C++ standard library function | ||
@@ -181,7 +332,7 @@ public: | |||
/// specialization, where the signature is determined by the standard library | /// specialization, where the signature is determined by the standard library | ||
/// declaration. | /// declaration. | ||
bool isInStdNamespace | bool isInStdNamespace | ||
- return strchr( | + return strchr(getAttributesString(ID), 'z') != nullptr; | ||
} | } | ||
/// Determines whether this builtin can have its address taken with no | /// Determines whether this builtin can have its address taken with no | ||
@@ -195,33 +346,33 @@ public: | |||
/// Determines whether this builtin has custom typechecking. | /// Determines whether this builtin has custom typechecking. | ||
bool hasCustomTypeche | bool hasCustomTypeche | ||
- return strchr( | + return strchr(getAttributesString(ID), 't') != nullptr; | ||
} | } | ||
/// Determines whether a declaration of this builtin should be recognized | /// Determines whether a declaration of this builtin should be recognized | ||
/// even if the type doesn't match the specified signature. | /// even if the type doesn't match the specified signature. | ||
bool allowTypeMismatc | bool allowTypeMismatc | ||
- return strchr( | + return strchr(getAttributesString(ID), 'T') != nullptr || | ||
hasCustomTypeche | hasCustomTypeche | ||
} | } | ||
/// Determines whether this builtin has a result or any arguments which | /// Determines whether this builtin has a result or any arguments which | ||
/// are pointer types. | /// are pointer types. | ||
bool hasPtrArgsOrResu | bool hasPtrArgsOrResu | ||
- return strchr( | + return strchr(getTypeString(ID), '*') != nullptr; | ||
} | } | ||
/// Return true if this builtin has a result or any arguments which are | /// Return true if this builtin has a result or any arguments which are | ||
/// reference types. | /// reference types. | ||
bool hasReferenceArgs | bool hasReferenceArgs | ||
- return strchr( | + return strchr(getTypeString(ID), '&') != nullptr || | ||
- strchr( | + strchr(getTypeString(ID), 'A') != nullptr; | ||
} | } | ||
/// If this is a library function that comes from a specific | /// If this is a library function that comes from a specific | ||
/// header, retrieve that header name. | /// header, retrieve that header name. | ||
const char *getHeaderName(unsigned ID) const { | const char *getHeaderName(unsigned ID) const { | ||
- return | + return getInfo(ID).Header.getName(); | ||
} | } | ||
/// Determine whether this builtin is like printf in its | /// Determine whether this builtin is like printf in its | ||
@@ -246,27 +397,25 @@ public: | |||
/// Such functions can be const when the MathErrno lang option and FP | /// Such functions can be const when the MathErrno lang option and FP | ||
/// exceptions are disabled. | /// exceptions are disabled. | ||
bool isConstWithoutEr | bool isConstWithoutEr | ||
- return strchr( | + return strchr(getAttributesString(ID), 'e') != nullptr; | ||
} | } | ||
bool isConstWithoutEx | bool isConstWithoutEx | ||
- return strchr( | + return strchr(getAttributesString(ID), 'g') != nullptr; | ||
} | } | ||
- const char *getRequiredFeatures(unsigned ID) | + const char *getRequiredFeatures(unsigned ID) const; | ||
- return getRecord(ID).Features; | |||
- } | |||
unsigned getRequiredVecto | unsigned getRequiredVecto | ||
/// Return true if builtin ID belongs to AuxTarget. | /// Return true if builtin ID belongs to AuxTarget. | ||
bool isAuxBuiltinID(unsigned ID) const { | bool isAuxBuiltinID(unsigned ID) const { | ||
- return ID >= (Builtin::FirstTSBuiltin + | + return ID >= (Builtin::FirstTSBuiltin + NumTargetBuiltins); | ||
} | } | ||
/// Return real builtin ID (i.e. ID it would have during compilation | /// Return real builtin ID (i.e. ID it would have during compilation | ||
/// for AuxTarget). | /// for AuxTarget). | ||
- unsigned getAuxBuiltinID(unsigned ID) const { return ID - | + unsigned getAuxBuiltinID(unsigned ID) const { return ID - NumTargetBuiltins; } | ||
/// Returns true if this is a libc/libm function without the '__builtin_' | /// Returns true if this is a libc/libm function without the '__builtin_' | ||
/// prefix. | /// prefix. | ||
@@ -278,16 +427,19 @@ public: | |||
/// Return true if this function can be constant evaluated by Clang frontend. | /// Return true if this function can be constant evaluated by Clang frontend. | ||
bool isConstantEvalua | bool isConstantEvalua | ||
- return strchr( | + return strchr(getAttributesString(ID), 'E') != nullptr; | ||
} | } | ||
/// Returns true if this is an immediate (consteval) function | /// Returns true if this is an immediate (consteval) function | ||
bool isImmediate(unsigned ID) const { | bool isImmediate(unsigned ID) const { | ||
- return strchr( | + return strchr(getAttributesString(ID), 'G') != nullptr; | ||
} | } | ||
private: | private: | ||
- const Info &getRecord(unsigned ID) const; | + std::pair<const InfosShard &, const Info &> | ||
+ getShardAndInfo(unsigned ID) const; | |||
+ | |||
+ const Info &getInfo(unsigned ID) const { return getShardAndInfo(ID).second; } | |||
/// Helper function for isPrintfLike and isScanfLike. | /// Helper function for isPrintfLike and isScanfLike. | ||
bool isLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg, | bool isLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg, |
@@ -206,13 +206,6 @@ BUILTIN(__builti | |||
// Misc | // Misc | ||
BUILTIN(__builtin_sponen | BUILTIN(__builtin_sponen | ||
-// Builtins for implementing ACLE MVE intrinsics. (Unlike NEON, these | |||
-// don't need to live in a separate BuiltinsMVE.def, because they | |||
-// aren't included from both here and BuiltinsAArch64.def.) | |||
-#include "clang/Basic/arm_mve_builtins | |||
- | |||
-#include "clang/Basic/arm_cde_builtins | |||
- | |||
// MSVC | // MSVC | ||
LANGBUILTIN(__emit, "vIUiC", "", ALL_MS_LANGUAGES | LANGBUILTIN(__emit, "vIUiC", "", ALL_MS_LANGUAGES | ||
@@ -86,6 +86,13 @@ def Consteval : Attribute<"EG">; | |||
// indicated by the remaining indices. | // indicated by the remaining indices. | ||
class Callback<list<int> ArgIndices> : MultiIndexAttrib | class Callback<list<int> ArgIndices> : MultiIndexAttrib | ||
+// Prefixes | |||
+// ======== | |||
+ | |||
+class NamePrefix<string spelling> { | |||
+ string Spelling = spelling; | |||
+} | |||
+ | |||
// Builtin kinds | // Builtin kinds | ||
// ============= | // ============= | ||
@@ -99,6 +106,9 @@ class Builtin { | |||
bit RequiresUndef = 0; | bit RequiresUndef = 0; | ||
// Enables builtins to generate `long long` outside of OpenCL and `long` inside. | // Enables builtins to generate `long long` outside of OpenCL and `long` inside. | ||
bit EnableOpenCLLong | bit EnableOpenCLLong | ||
+ // Requires a common prefix to be prepended. Each generated set of builtins | |||
+ // can optionally extract one common prefix that is handled separately. | |||
+ NamePrefix RequiredNamePref | |||
} | } | ||
class AtomicBuiltin : Builtin; | class AtomicBuiltin : Builtin; |
@@ -56,10 +56,13 @@ def HVXV65 : HVXV<"65", HVXV66>; | |||
def HVXV62 : HVXV<"62", HVXV65>; | def HVXV62 : HVXV<"62", HVXV65>; | ||
def HVXV60 : HVXV<"60", HVXV62>; | def HVXV60 : HVXV<"60", HVXV62>; | ||
+def HexagonPrefix : NamePrefix<"__builtin_HEXAGO | |||
+ | |||
class HexagonBuiltin<string prototype> : TargetBuiltin { | class HexagonBuiltin<string prototype> : TargetBuiltin { | ||
- let Spellings = [ | + let Spellings = [NAME]; | ||
let Prototype = prototype; | let Prototype = prototype; | ||
let Features = V5.Features; | let Features = V5.Features; | ||
+ let RequiredNamePref | |||
} | } | ||
class HexagonBuiltinNo | class HexagonBuiltinNo |
@@ -1,28 +0,0 @@ | |||
-//==- BuiltinsLoongArc | |||
-// | |||
-// 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 defines the LoongArch-specific builtin function database. Users of | |||
-// this file must define the BUILTIN macro to make use of this information. | |||
-// | |||
-//===----------------------------------------------------------------------===// | |||
- | |||
-#if defined(BUILTIN) && !defined(TARGET_BUILTIN) | |||
-# define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS) | |||
-#endif | |||
- | |||
-// Definition of LoongArch basic builtins. | |||
-#include "clang/Basic/BuiltinsLoongArc | |||
- | |||
-// Definition of LSX builtins. | |||
-#include "clang/Basic/BuiltinsLoongArc | |||
- | |||
-// Definition of LASX builtins. | |||
-#include "clang/Basic/BuiltinsLoongArc | |||
- | |||
-#undef BUILTIN | |||
-#undef TARGET_BUILTIN |
@@ -1,22 +0,0 @@ | |||
-//===--- BuiltinsNEON.def - NEON Builtin function database ------*- 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 defines the NEON-specific builtin function database. Users of | |||
-// this file must define the BUILTIN macro to make use of this information. | |||
-// | |||
-//===----------------------------------------------------------------------===// | |||
- | |||
-// The format of this database matches clang/Basic/Builtins.def. | |||
- | |||
-#define GET_NEON_BUILTIN | |||
-#include "clang/Basic/arm_neon.inc" | |||
-#include "clang/Basic/arm_fp16.inc" | |||
-#undef GET_NEON_BUILTIN | |||
- | |||
-#undef BUILTIN | |||
-#undef TARGET_BUILTIN |
@@ -1138,5 +1138,6 @@ UNALIASED_CUSTOM | |||
// FIXME: Obviously incomplete. | // FIXME: Obviously incomplete. | ||
#undef BUILTIN | #undef BUILTIN | ||
+#undef TARGET_BUILTIN | |||
#undef CUSTOM_BUILTIN | #undef CUSTOM_BUILTIN | ||
#undef UNALIASED_CUSTOM | #undef UNALIASED_CUSTOM |
@@ -1,22 +0,0 @@ | |||
-//==- BuiltinsRISCVVec | |||
-// | |||
-// 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 defines the RISC-V-specific builtin function database. Users of | |||
-// this file must define the BUILTIN macro to make use of this information. | |||
-// | |||
-//===----------------------------------------------------------------------===// | |||
- | |||
-#if defined(BUILTIN) && !defined(TARGET_BUILTIN) | |||
-# define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS) | |||
-#endif | |||
- | |||
-#include "clang/Basic/riscv_vector_bui | |||
-#include "clang/Basic/riscv_sifive_vec | |||
- | |||
-#undef BUILTIN | |||
-#undef TARGET_BUILTIN |
@@ -1,21 +0,0 @@ | |||
-//===--- BuiltinsSME.def - SME Builtin function database --------*- 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 defines the SME-specific builtin function database. Users of | |||
-// this file must define the BUILTIN macro to make use of this information. | |||
-// | |||
-//===----------------------------------------------------------------------===// | |||
- | |||
-// The format of this database matches clang/Basic/Builtins.def. | |||
- | |||
-#define GET_SME_BUILTINS | |||
-#include "clang/Basic/arm_sme_builtins | |||
-#undef GET_SME_BUILTINS | |||
- | |||
-#undef BUILTIN | |||
-#undef TARGET_BUILTIN |
@@ -1,22 +0,0 @@ | |||
-//===--- BuiltinsSVE.def - SVE Builtin function database --------*- 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 defines the SVE-specific builtin function database. Users of | |||
-// this file must define the BUILTIN macro to make use of this information. | |||
-// | |||
-//===----------------------------------------------------------------------===// | |||
- | |||
-// The format of this database matches clang/Basic/Builtins.def. | |||
- | |||
-#define GET_SVE_BUILTINS | |||
-#include "clang/Basic/arm_sve_builtins | |||
-#include "clang/Basic/BuiltinsAArch64N | |||
-#undef GET_SVE_BUILTINS | |||
- | |||
-#undef BUILTIN | |||
-#undef TARGET_BUILTIN |
@@ -12,10 +12,13 @@ | |||
include "clang/Basic/BuiltinsBase.td" | include "clang/Basic/BuiltinsBase.td" | ||
+def X86Prefix : NamePrefix<"__builtin_ia32_">; | |||
+ | |||
class X86Builtin<string prototype> : TargetBuiltin { | class X86Builtin<string prototype> : TargetBuiltin { | ||
- let Spellings = [ | + let Spellings = [NAME]; | ||
let Prototype = prototype; | let Prototype = prototype; | ||
let EnableOpenCLLong | let EnableOpenCLLong | ||
+ let RequiredNamePref | |||
} | } | ||
class X86NoPrefixBuilt | class X86NoPrefixBuilt |
@@ -221,6 +221,7 @@ AFFECTING_VALUE_ | |||
AFFECTING_VALUE_ | AFFECTING_VALUE_ | ||
CODEGENOPT(AtomicProfileUpd | CODEGENOPT(AtomicProfileUpd | ||
+CODEGENOPT(ContinuousProfil | |||
/// Choose profile instrumenation kind or no instrumentation. | /// Choose profile instrumenation kind or no instrumentation. | ||
ENUM_CODEGENOPT(ProfileInstr, ProfileInstrKind | ENUM_CODEGENOPT(ProfileInstr, ProfileInstrKind | ||
/// Choose profile kind for PGO use compilation. | /// Choose profile kind for PGO use compilation. | ||
@@ -277,6 +278,7 @@ CODEGENOPT(Sanit | |||
///< CFI icall function signatures | ///< CFI icall function signatures | ||
CODEGENOPT(SanitizeCfiCanon | CODEGENOPT(SanitizeCfiCanon | ||
///< instead of creating a local jump table. | ///< instead of creating a local jump table. | ||
+CODEGENOPT(SanitizeKcfiArit | |||
CODEGENOPT(SanitizeCoverage | CODEGENOPT(SanitizeCoverage | ||
///< instrumentation. | ///< instrumentation. | ||
CODEGENOPT(SanitizeCoverage | CODEGENOPT(SanitizeCoverage | ||
@@ -319,6 +321,7 @@ CODEGENOPT(TimeP | |||
CODEGENOPT(TimeTrace , 1, 0) ///< Set when -ftime-trace is enabled. | CODEGENOPT(TimeTrace , 1, 0) ///< Set when -ftime-trace is enabled. | ||
VALUE_CODEGENOPT | VALUE_CODEGENOPT | ||
///< traced by time profiler | ///< traced by time profiler | ||
+CODEGENOPT(InterchangeLoops | |||
CODEGENOPT(UnrollLoops , 1, 0) ///< Control whether loops are unrolled. | CODEGENOPT(UnrollLoops , 1, 0) ///< Control whether loops are unrolled. | ||
CODEGENOPT(RerollLoops , 1, 0) ///< Control whether loops are rerolled. | CODEGENOPT(RerollLoops , 1, 0) ///< Control whether loops are rerolled. | ||
CODEGENOPT(NoUseJumpTables , 1, 0) ///< Set when -fno-jump-tables is enabled. | CODEGENOPT(NoUseJumpTables , 1, 0) ///< Set when -fno-jump-tables is enabled. | ||
@@ -469,6 +472,10 @@ CODEGENOPT(CtorD | |||
/// by the Windows kernel to enable import call optimization. | /// by the Windows kernel to enable import call optimization. | ||
CODEGENOPT(ImportCallOptimi | CODEGENOPT(ImportCallOptimi | ||
+/// Controls whether we generate code for static linking of libclosure | |||
+/// (BlocksRuntime) on Windows. | |||
+CODEGENOPT(StaticClosure, 1, 0) | |||
+ | |||
/// FIXME: Make DebugOptions its own top-level .def file. | /// FIXME: Make DebugOptions its own top-level .def file. | ||
#include "DebugOptions.def" | #include "DebugOptions.def" | ||
@@ -209,6 +209,8 @@ def err_drv_cannot_o | |||
"cannot read randomize layout seed file '%0'">; | "cannot read randomize layout seed file '%0'">; | ||
def err_drv_invalid_ | def err_drv_invalid_ | ||
"invalid version number in '%0'">; | "invalid version number in '%0'">; | ||
+def err_drv_kcfi_ari | |||
+ "target '%0' is unsupported by -fsanitize-kcfi-arity">; | |||
def err_drv_no_linke | def err_drv_no_linke | ||
"'%0': unable to pass LLVM bit-code files to linker">; | "'%0': unable to pass LLVM bit-code files to linker">; | ||
def err_drv_no_ast_s | def err_drv_no_ast_s |
@@ -694,6 +694,36 @@ def SuspiciousMemacc | |||
NonTrivialMemacc | NonTrivialMemacc | ||
def StaticInInline : DiagGroup<"static-in-inline">; | def StaticInInline : DiagGroup<"static-in-inline">; | ||
def StaticLocalInInl | def StaticLocalInInl | ||
+def UniqueObjectDupl | |||
+ code Documentation = [{ | |||
+Warns when objects which are supposed to be globally unique might get duplicated | |||
+when built into a shared library. | |||
+ | |||
+If an object with hidden visibility is built into a shared library, each instance | |||
+of the library will get its own copy. This can cause very subtle bugs if there was | |||
+only supposed to be one copy of the object in question: singletons aren't single, | |||
+changes to one object won't affect the others, the object's initializer will run | |||
+once per copy, etc. | |||
+ | |||
+Specifically, this warning fires when it detects an object which: | |||
+ 1. Appears in a header file (so it might get compiled into multiple libaries), and | |||
+ 2. Has external linkage (otherwise it's supposed to be duplicated), and | |||
+ 3. Has hidden visibility. | |||
+ | |||
+As well as one of the following: | |||
+ 1. The object is mutable, or | |||
+ 2. The object's initializer definitely has side effects. | |||
+ | |||
+The warning is best resolved by making the object ``const`` (if possible), or by explicitly | |||
+giving the object non-hidden visibility, e.g. using ``__attribute((visibility("default")))``. | |||
+Note that all levels of a pointer variable must be constant; ``const int*`` will | |||
+trigger the warning because the pointer itself is mutable. | |||
+ | |||
+This warning is currently disabled on Windows since it uses import/export rules | |||
+instead of visibility. | |||
+}]; | |||
+} | |||
+ | |||
def GNUStaticFloatIn | def GNUStaticFloatIn | ||
def StaticFloatInit : DiagGroup<"static-float-init", [GNUStaticFloatIn | def StaticFloatInit : DiagGroup<"static-float-init", [GNUStaticFloatIn | ||
// Allow differentiation between GNU statement expressions in a macro versus | // Allow differentiation between GNU statement expressions in a macro versus |
@@ -350,10 +350,11 @@ def warn_arm_interru | |||
InGroup<DiagGroup<"arm-interrupt-vfp-clobber">>; | InGroup<DiagGroup<"arm-interrupt-vfp-clobber">>; | ||
def err_arm_interrup | def err_arm_interrup | ||
"interrupt service routine cannot be called directly">; | "interrupt service routine cannot be called directly">; | ||
-def | +def warn_interrupt_signal_attribute_invalid : Warning< | ||
- "%select{MIPS|MSP430|RISC-V}0 'interrupt' attribute only applies to " | + "%select{MIPS|MSP430|RISC-V|AVR}0 '%select{interrupt|signal}1' " | ||
- "functions that have %select{no parameters|a 'void' return type}1">, | + "attribute only applies to functions that have " | ||
- InGroup<IgnoredAttribute | + "%select{no parameters|a 'void' return type}2">, | ||
+ InGroup<IgnoredAttribute | |||
def warn_riscv_repea | def warn_riscv_repea | ||
"repeated RISC-V 'interrupt' attribute">, InGroup<IgnoredAttribute | "repeated RISC-V 'interrupt' attribute">, InGroup<IgnoredAttribute | ||
def note_riscv_repea | def note_riscv_repea | ||
@@ -490,7 +491,7 @@ def warn_qual_return | |||
"'%0' type qualifier%s1 on return type %plural{1:has|:have}1 no effect">, | "'%0' type qualifier%s1 on return type %plural{1:has|:have}1 no effect">, | ||
InGroup<IgnoredQualifier | InGroup<IgnoredQualifier | ||
def warn_qual_base_t | def warn_qual_base_t | ||
- "'%0' qualifier%s1 on base class type %2 | + "'%0' qualifier%s1 on base class type %2 %plural{1:has|:have}1 no effect">, | ||
InGroup<IgnoredQualifier | InGroup<IgnoredQualifier | ||
def warn_deprecated_ | def warn_deprecated_ | ||
@@ -3832,6 +3833,9 @@ def warn_type_attrib | |||
"'%0' only applies to %select{function|pointer|" | "'%0' only applies to %select{function|pointer|" | ||
"Objective-C object or block pointer}1 types; type here is %2">, | "Objective-C object or block pointer}1 types; type here is %2">, | ||
InGroup<IgnoredAttribute | InGroup<IgnoredAttribute | ||
+def warn_attribute_o | |||
+ "attribute %0 cannot be applied to a 'void' parameter">, | |||
+ InGroup<IgnoredAttribute | |||
def err_type_attribu | def err_type_attribu | ||
warn_type_attrib | warn_type_attrib | ||
def warn_incomplete_ | def warn_incomplete_ | ||
@@ -6113,6 +6117,8 @@ def note_deleted_spe | |||
"destructor}5" | "destructor}5" | ||
"%select{||s||}4" | "%select{||s||}4" | ||
"|is an ObjC pointer}6">; | "|is an ObjC pointer}6">; | ||
+def note_default_con | |||
+ : Note<"default constructed field %0 declared here">; | |||
def note_deleted_def | def note_deleted_def | ||
"%select{default constructor of|constructor inherited by}0 " | "%select{default constructor of|constructor inherited by}0 " | ||
"%1 is implicitly deleted because field %2 of " | "%1 is implicitly deleted because field %2 of " | ||
@@ -6167,6 +6173,15 @@ def warn_static_loca | |||
def note_convert_inl | def note_convert_inl | ||
"use 'static' to give inline function %0 internal linkage">; | "use 'static' to give inline function %0 internal linkage">; | ||
+def warn_possible_ob | |||
+ "%0 may be duplicated when built into a shared library: " | |||
+ "it is mutable, has hidden visibility, and external linkage">, | |||
+ InGroup<UniqueObjectDupl | |||
+def warn_possible_ob | |||
+ "initializeation of %0 may run twice when built into a shared library: " | |||
+ "it has hidden visibility and external linkage">, | |||
+ InGroup<UniqueObjectDupl | |||
+ | |||
def ext_redefinition | def ext_redefinition | ||
"redefinition of typedef %0 is a C11 feature">, | "redefinition of typedef %0 is a C11 feature">, | ||
InGroup<DiagGroup<"typedef-redefinition"> >; | InGroup<DiagGroup<"typedef-redefinition"> >; | ||
@@ -9182,6 +9197,8 @@ def err_cuda_device_ | |||
def err_dynamic_var_ | def err_dynamic_var_ | ||
"dynamic initialization is not supported for " | "dynamic initialization is not supported for " | ||
"__device__, __constant__, __shared__, and __managed__ variables">; | "__device__, __constant__, __shared__, and __managed__ variables">; | ||
+def err_cuda_ctor_dt | |||
+ : Error<"CUDA does not support global %0 for __device__ functions">; | |||
def err_shared_var_i | def err_shared_var_i | ||
"initialization is not supported for __shared__ variables">; | "initialization is not supported for __shared__ variables">; | ||
def err_cuda_vla : Error< | def err_cuda_vla : Error< | ||
@@ -12903,6 +12920,48 @@ def err_acc_update_a | |||
: Error<"OpenACC 'update' construct may not appear in place of the " | : Error<"OpenACC 'update' construct may not appear in place of the " | ||
"statement following a%select{n if statement| while statement| do " | "statement following a%select{n if statement| while statement| do " | ||
"statement| switch statement| label statement}0">; | "statement| switch statement| label statement}0">; | ||
+def err_acc_invalid_ | |||
+ : Error<"statement associated with OpenACC 'atomic%select{| " | |||
+ "%1}0' directive is invalid">; | |||
+def note_acc_atomic_ | |||
+ : Note<"expected " | |||
+ "%enum_select<OACCAtomicExpr>{%Assign{assignment}|%UnaryCompAssign{" | |||
+ "assignment, compound assignment, increment, or decrement}}0 " | |||
+ "expression">; | |||
+def note_acc_atomic_ | |||
+ : Note<"unary operator not supported, only increment and decrement " | |||
+ "operations permitted">; | |||
+def note_acc_atomic_ | |||
+ : Note<"binary operator not supported, only +, *, -, /, &, ^, |, <<, or >> " | |||
+ "are permitted">; | |||
+def note_acc_atomic_ | |||
+ : Note<"compound binary operator not supported, only +=, *=, -=, /=, &=, " | |||
+ "^=, |=, <<=, or >>= are permitted">; | |||
+ | |||
+def note_acc_atomic_ | |||
+ : Note<"%select{left |right |}0operand to " | |||
+ "%enum_select<OACCAtomicOpKind | |||
+ "compound assignment}|%Inc{increment}|" | |||
+ "%Dec{decrement}}1 " | |||
+ "expression must be " | |||
+ "%enum_select<OACCLValScalar>{%LVal{an l-value}|%Scalar{of scalar " | |||
+ "type (was %3)}}2">; | |||
+def note_acc_atomic_ | |||
+ : Note<"'atomic capture' with a compound statement only supports two " | |||
+ "statements">; | |||
+def note_acc_atomic_ | |||
+ "hand side of assignment operator">; | |||
+def note_acc_atomic_ | |||
+ : Note<"left hand side of assignment operation('%0') must match one side " | |||
+ "of the sub-operation on the right hand side('%1' and '%2')">; | |||
+def note_acc_atomic_ | |||
+ : Note<"variable %select{|in unary expression|on right hand side of " | |||
+ "assignment|on left hand side of assignment|on left hand side of " | |||
+ "compound assignment|on left hand side of assignment}2('%3') must " | |||
+ "match variable used %select{|in unary expression|on right hand " | |||
+ "side of assignment|<not possible>|on left hand side of compound " | |||
+ "assignment|on left hand side of assignment}0('%1') from the first " | |||
+ "statement">; | |||
// AMDGCN builtins diagnostics | // AMDGCN builtins diagnostics | ||
def err_amdgcn_globa | def err_amdgcn_globa |
@@ -28,5 +28,5 @@ OPTION(FPEvalMet | |||
OPTION(Float16ExcessPre | OPTION(Float16ExcessPre | ||
OPTION(BFloat16ExcessPr | OPTION(BFloat16ExcessPr | ||
OPTION(MathErrno, bool, 1, BFloat16ExcessPr | OPTION(MathErrno, bool, 1, BFloat16ExcessPr | ||
-OPTION(ComplexRange, LangOptions::ComplexRangeKind, | +OPTION(ComplexRange, LangOptions::ComplexRangeKind, 3, MathErrno) | ||
#undef OPTION | #undef OPTION |
@@ -254,6 +254,7 @@ FEATURE(is_trivi | |||
FEATURE(is_trivially_cop | FEATURE(is_trivially_cop | ||
FEATURE(is_union, LangOpts.CPlusPlus) | FEATURE(is_union, LangOpts.CPlusPlus) | ||
FEATURE(kcfi, LangOpts.Sanitize.has(SanitizerKind::KCFI)) | FEATURE(kcfi, LangOpts.Sanitize.has(SanitizerKind::KCFI)) | ||
+FEATURE(kcfi_arity, LangOpts.Sanitize.has(SanitizerKind::KCFI)) | |||
FEATURE(modules, LangOpts.Modules) | FEATURE(modules, LangOpts.Modules) | ||
FEATURE(safe_stack, LangOpts.Sanitize.has(SanitizerKind::SafeStack)) | FEATURE(safe_stack, LangOpts.Sanitize.has(SanitizerKind::SafeStack)) | ||
FEATURE(shadow_call_stac | FEATURE(shadow_call_stac |
@@ -101,8 +101,9 @@ enum class InterestingIdent | |||
NUM_OBJC_KEYWORD | NUM_OBJC_KEYWORD | ||
NotBuiltin, | NotBuiltin, | ||
-#define BUILTIN(ID, TYPE, ATTRS) BI##ID, | +#define GET_BUILTIN_ENUM | ||
#include "clang/Basic/Builtins.inc" | #include "clang/Basic/Builtins.inc" | ||
+#undef GET_BUILTIN_ENUM | |||
FirstTSBuiltin, | FirstTSBuiltin, | ||
NotInterestingId | NotInterestingId |
@@ -238,7 +238,7 @@ BENIGN_LANGOPT(N | |||
BENIGN_LANGOPT(AllowRecip , 1, 0, "Permit Floating Point reciprocal") | BENIGN_LANGOPT(AllowRecip , 1, 0, "Permit Floating Point reciprocal") | ||
BENIGN_LANGOPT(ApproxFunc , 1, 0, "Permit Floating Point approximation") | BENIGN_LANGOPT(ApproxFunc , 1, 0, "Permit Floating Point approximation") | ||
-ENUM_LANGOPT(ComplexRange, ComplexRangeKind, | +ENUM_LANGOPT(ComplexRange, ComplexRangeKind, 3, CX_None, "Enable use of range reduction for complex arithmetics.") | ||
BENIGN_LANGOPT(ObjCGCBitmapPrin | BENIGN_LANGOPT(ObjCGCBitmapPrin | ||
@@ -250,6 +250,11 @@ public: | |||
/// passing them as if they had a size of 1 byte. | /// passing them as if they had a size of 1 byte. | ||
Ver19, | Ver19, | ||
+ /// Attempt to be ABI-compatible with code generated by Clang 20.0.x. | |||
+ /// This causes clang to: | |||
+ /// - Incorrectly return C++ records in AVX registers on x86_64. | |||
+ Ver20, | |||
+ | |||
/// Conform to the underlying platform's C and C++ ABIs as closely | /// Conform to the underlying platform's C and C++ ABIs as closely | ||
/// as we can. | /// as we can. | ||
Latest | Latest | ||
@@ -643,9 +648,12 @@ public: | |||
// Define accessors/mutators for language options of enumeration type. | // Define accessors/mutators for language options of enumeration type. | ||
#define LANGOPT(Name, Bits, Default, Description) | #define LANGOPT(Name, Bits, Default, Description) | ||
-#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) | +#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ | ||
- Type get##Name() const { return static_cast<Type>(Name); } | + Type get##Name() const { return static_cast<Type>(Name); } \ | ||
- void set##Name(Type Value) { Name = static_cast<unsigned>(Value); } | + void set##Name(Type Value) { \ | ||
+ assert(static_cast<unsigned>(Value) < (1u << Bits)); \ | |||
+ Name = static_cast<unsigned>(Value); \ | |||
+ } | |||
#include "clang/Basic/LangOptions.def" | #include "clang/Basic/LangOptions.def" | ||
/// Are we compiling a module? | /// Are we compiling a module? | ||
@@ -954,11 +962,14 @@ public: | |||
void applyChanges(FPOptionsOverrid | void applyChanges(FPOptionsOverrid | ||
// We can define most of the accessors automatically: | // We can define most of the accessors automatically: | ||
+ // TODO: consider enforcing the assertion that value fits within bits | |||
+ // statically. | |||
#define OPTION(NAME, TYPE, WIDTH, PREVIOUS) \ | #define OPTION(NAME, TYPE, WIDTH, PREVIOUS) \ | ||
TYPE get##NAME() const { \ | TYPE get##NAME() const { \ | ||
return static_cast<TYPE>((Value & NAME##Mask) >> NAME##Shift); \ | return static_cast<TYPE>((Value & NAME##Mask) >> NAME##Shift); \ | ||
} \ | } \ | ||
void set##NAME(TYPE value) { \ | void set##NAME(TYPE value) { \ | ||
+ assert(storage_type(value) < (1u << WIDTH)); \ | |||
Value = (Value & ~NAME##Mask) | (storage_type(value) << NAME##Shift); \ | Value = (Value & ~NAME##Mask) | (storage_type(value) << NAME##Shift); \ | ||
} | } | ||
#include "clang/Basic/FPOptions.def" | #include "clang/Basic/FPOptions.def" |
@@ -171,9 +171,34 @@ enum class OpenACCAtomicKin | |||
Write, | Write, | ||
Update, | Update, | ||
Capture, | Capture, | ||
- Invalid, | + None, | ||
}; | }; | ||
+template <typename StreamTy> | |||
+inline StreamTy &printOpenACCAtom | |||
+ switch (AK) { | |||
+ case OpenACCAtomicKin | |||
+ return Out << "read"; | |||
+ case OpenACCAtomicKin | |||
+ return Out << "write"; | |||
+ case OpenACCAtomicKin | |||
+ return Out << "update"; | |||
+ case OpenACCAtomicKin | |||
+ return Out << "capture"; | |||
+ case OpenACCAtomicKin | |||
+ return Out << "<none>"; | |||
+ } | |||
+ llvm_unreachable | |||
+} | |||
+inline const StreamingDiagnos | |||
+ OpenACCAtomicKin | |||
+ return printOpenACCAtom | |||
+} | |||
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &Out, | |||
+ OpenACCAtomicKin | |||
+ return printOpenACCAtom | |||
+} | |||
+ | |||
/// Represents the kind of an OpenACC clause. | /// Represents the kind of an OpenACC clause. | ||
enum class OpenACCClauseKin | enum class OpenACCClauseKin | ||
/// 'finalize' clause, allowed on 'exit data' directive. | /// 'finalize' clause, allowed on 'exit data' directive. |
@@ -399,6 +399,14 @@ bool isOpenMPInformat | |||
/// \return true - if the above condition is met for this directive | /// \return true - if the above condition is met for this directive | ||
/// otherwise - false. | /// otherwise - false. | ||
bool isOpenMPCapturin | bool isOpenMPCapturin | ||
+ | |||
+/// Checks if the specified directive is an order concurrent nestable | |||
+/// directive that can be nested within region corresponding to construct | |||
+/// on which order clause was specified with concurrent as ordering argument. | |||
+/// \param DKind Specified directive. | |||
+/// \return true - if the above condition is met for this directive | |||
+/// otherwise - false. | |||
+bool isOpenMPOrderCon | |||
} | } | ||
template <> | template <> |
@@ -319,6 +319,7 @@ def OpenACCInitConst | |||
def OpenACCShutdownC | def OpenACCShutdownC | ||
def OpenACCSetConstr | def OpenACCSetConstr | ||
def OpenACCUpdateCon | def OpenACCUpdateCon | ||
+def OpenACCAtomicCon | |||
// OpenACC Additional Expressions. | // OpenACC Additional Expressions. | ||
def OpenACCAsteriskS | def OpenACCAsteriskS |
@@ -26,30 +26,50 @@ namespace clang { | |||
namespace NEON { | namespace NEON { | ||
enum { | enum { | ||
LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, | LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, | ||
-#define BUILTIN(ID, TYPE, ATTRS) BI##ID, | +#define GET_NEON_BUILTIN | ||
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BI##ID, | +#include "clang/Basic/arm_neon.inc" | ||
-#include "clang/Basic/BuiltinsNEON.def" | + FirstFp16Builtin | ||
+ LastNeonBuiltin = FirstFp16Builtin | |||
+#include "clang/Basic/arm_fp16.inc" | |||
+#undef GET_NEON_BUILTIN | |||
FirstTSBuiltin | FirstTSBuiltin | ||
}; | }; | ||
} | } | ||
/// ARM builtins | /// ARM builtins | ||
namespace ARM { | namespace ARM { | ||
- | + enum { | ||
- | + LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, | ||
- | + LastNEONBuiltin = NEON::FirstTSBuiltin - 1, | ||
+#define GET_MVE_BUILTIN_ | |||
+#include "clang/Basic/arm_mve_builtins | |||
+#undef GET_MVE_BUILTIN_ | |||
+ FirstCDEBuiltin, | |||
+ LastMVEBuiltin = FirstCDEBuiltin - 1, | |||
+#define GET_CDE_BUILTIN_ | |||
+#include "clang/Basic/arm_cde_builtins | |||
+#undef GET_CDE_BUILTIN_ | |||
+ FirstARMBuiltin, | |||
+ LastCDEBuiltin = FirstARMBuiltin - 1, | |||
#define BUILTIN(ID, TYPE, ATTRS) BI##ID, | #define BUILTIN(ID, TYPE, ATTRS) BI##ID, | ||
#include "clang/Basic/BuiltinsARM.def" | #include "clang/Basic/BuiltinsARM.def" | ||
- | + LastTSBuiltin | ||
- | + }; | ||
} | } | ||
namespace SVE { | namespace SVE { | ||
enum { | enum { | ||
LastNEONBuiltin = NEON::FirstTSBuiltin - 1, | LastNEONBuiltin = NEON::FirstTSBuiltin - 1, | ||
-#define BUILTIN(ID, TYPE, ATTRS) BI##ID, | +#define GET_SVE_BUILTIN_ | ||
+#include "clang/Basic/arm_sve_builtins | |||
+#undef GET_SVE_BUILTIN_ | |||
+ FirstNeonBridgeB | |||
+ LastSveBuiltin = FirstNeonBridgeB | |||
+#define GET_SVE_BUILTINS | |||
#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BI##ID, | #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BI##ID, | ||
-#include "clang/Basic/ | +#include "clang/Basic/BuiltinsAArch64NeonSVEBridge.def" | ||
+#undef TARGET_BUILTIN | |||
+#undef GET_SVE_BUILTINS | |||
FirstTSBuiltin, | FirstTSBuiltin, | ||
}; | }; | ||
} | } | ||
@@ -57,9 +77,9 @@ namespace clang { | |||
namespace SME { | namespace SME { | ||
enum { | enum { | ||
LastSVEBuiltin = SVE::FirstTSBuiltin - 1, | LastSVEBuiltin = SVE::FirstTSBuiltin - 1, | ||
-#define BUILTIN(ID, TYPE, ATTRS) BI##ID, | +#define GET_SME_BUILTIN_ | ||
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BI##ID, | +#include "clang/Basic/arm_sme_builtins | ||
-#include "clang/Basic/BuiltinsSME.def" | +#undef GET_SME_BUILTIN_ | ||
FirstTSBuiltin, | FirstTSBuiltin, | ||
}; | }; | ||
} | } | ||
@@ -83,8 +103,9 @@ namespace clang { | |||
namespace BPF { | namespace BPF { | ||
enum { | enum { | ||
LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, | LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, | ||
- #define BUILTIN(ID, TYPE, ATTRS) BI##ID, | +#define GET_BUILTIN_ENUM | ||
- | +#include "clang/Basic/BuiltinsBPF.inc" | ||
+#undef GET_BUILTIN_ENUM | |||
LastTSBuiltin | LastTSBuiltin | ||
}; | }; | ||
} | } | ||
@@ -103,8 +124,9 @@ namespace clang { | |||
namespace NVPTX { | namespace NVPTX { | ||
enum { | enum { | ||
LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, | LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, | ||
-#define BUILTIN(ID, TYPE, ATTRS) BI##ID, | +#define GET_BUILTIN_ENUM | ||
#include "clang/Basic/BuiltinsNVPTX.inc" | #include "clang/Basic/BuiltinsNVPTX.inc" | ||
+#undef GET_BUILTIN_ENUM | |||
LastTSBuiltin | LastTSBuiltin | ||
}; | }; | ||
} | } | ||
@@ -123,8 +145,9 @@ namespace clang { | |||
namespace SPIRV { | namespace SPIRV { | ||
enum { | enum { | ||
LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, | LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, | ||
-#define BUILTIN(ID, TYPE, ATTRS) BI##ID, | +#define GET_BUILTIN_ENUM | ||
#include "clang/Basic/BuiltinsSPIRV.inc" | #include "clang/Basic/BuiltinsSPIRV.inc" | ||
+#undef GET_BUILTIN_ENUM | |||
LastTSBuiltin | LastTSBuiltin | ||
}; | }; | ||
} // namespace SPIRV | } // namespace SPIRV | ||
@@ -133,12 +156,14 @@ namespace clang { | |||
namespace X86 { | namespace X86 { | ||
enum { | enum { | ||
LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, | LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, | ||
-#define BUILTIN(ID, TYPE, ATTRS) BI##ID, | +#define GET_BUILTIN_ENUM | ||
#include "clang/Basic/BuiltinsX86.inc" | #include "clang/Basic/BuiltinsX86.inc" | ||
+#undef GET_BUILTIN_ENUM | |||
FirstX86_64Built | FirstX86_64Built | ||
LastX86CommonBui | LastX86CommonBui | ||
-#define BUILTIN(ID, TYPE, ATTRS) BI##ID, | +#define GET_BUILTIN_ENUM | ||
#include "clang/Basic/BuiltinsX86_64.inc" | #include "clang/Basic/BuiltinsX86_64.inc" | ||
+#undef GET_BUILTIN_ENUM | |||
LastTSBuiltin | LastTSBuiltin | ||
}; | }; | ||
} | } | ||
@@ -156,8 +181,12 @@ namespace clang { | |||
namespace RISCVVector { | namespace RISCVVector { | ||
enum { | enum { | ||
LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, | LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, | ||
-#define BUILTIN(ID, TYPE, ATTRS) BI##ID, | +#define GET_RISCVV_BUILT | ||
-#include "clang/Basic/ | +#include "clang/Basic/riscv_vector_builtins.inc" | ||
+ FirstSiFiveBuilt | |||
+ LastRVVBuiltin = FirstSiFiveBuilt | |||
+#include "clang/Basic/riscv_sifive_vec | |||
+#undef GET_RISCVV_BUILT | |||
FirstTSBuiltin, | FirstTSBuiltin, | ||
}; | }; | ||
} | } | ||
@@ -168,8 +197,9 @@ namespace clang { | |||
LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, | LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, | ||
FirstRVVBuiltin = clang::Builtin::FirstTSBuiltin, | FirstRVVBuiltin = clang::Builtin::FirstTSBuiltin, | ||
LastRVVBuiltin = RISCVVector::FirstTSBuiltin - 1, | LastRVVBuiltin = RISCVVector::FirstTSBuiltin - 1, | ||
-#define BUILTIN(ID, TYPE, ATTRS) BI##ID, | +#define GET_BUILTIN_ENUM | ||
#include "clang/Basic/BuiltinsRISCV.inc" | #include "clang/Basic/BuiltinsRISCV.inc" | ||
+#undef GET_BUILTIN_ENUM | |||
LastTSBuiltin | LastTSBuiltin | ||
}; | }; | ||
} // namespace RISCV | } // namespace RISCV | ||
@@ -178,8 +208,16 @@ namespace clang { | |||
namespace LoongArch { | namespace LoongArch { | ||
enum { | enum { | ||
LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, | LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, | ||
-#define | +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BI##ID, | ||
-#include "clang/Basic/ | +#include "clang/Basic/BuiltinsLoongArchBase.def" | ||
+ FirstLSXBuiltin, | |||
+ LastBaseBuiltin = FirstLSXBuiltin - 1, | |||
+#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BI##ID, | |||
+#include "clang/Basic/BuiltinsLoongArc | |||
+ FirstLASXBuiltin | |||
+ LastLSXBuiltin = FirstLASXBuiltin | |||
+#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BI##ID, | |||
+#include "clang/Basic/BuiltinsLoongArc | |||
LastTSBuiltin | LastTSBuiltin | ||
}; | }; | ||
} // namespace LoongArch | } // namespace LoongArch | ||
@@ -356,8 +394,9 @@ namespace clang { | |||
namespace Hexagon { | namespace Hexagon { | ||
enum { | enum { | ||
LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, | LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, | ||
-#define BUILTIN(ID, TYPE, ATTRS) BI##ID, | +#define GET_BUILTIN_ENUM | ||
#include "clang/Basic/BuiltinsHexagon.inc" | #include "clang/Basic/BuiltinsHexagon.inc" | ||
+#undef GET_BUILTIN_ENUM | |||
LastTSBuiltin | LastTSBuiltin | ||
}; | }; | ||
} | } |
@@ -16,6 +16,7 @@ | |||
#include "clang/Basic/AddressSpaces.h" | #include "clang/Basic/AddressSpaces.h" | ||
#include "clang/Basic/BitmaskEnum.h" | #include "clang/Basic/BitmaskEnum.h" | ||
+#include "clang/Basic/Builtins.h" | |||
#include "clang/Basic/CFProtectionOpti | #include "clang/Basic/CFProtectionOpti | ||
#include "clang/Basic/CodeGenOptions.h" | #include "clang/Basic/CodeGenOptions.h" | ||
#include "clang/Basic/LLVM.h" | #include "clang/Basic/LLVM.h" | ||
@@ -32,6 +33,7 @@ | |||
#include "llvm/ADT/StringMap.h" | #include "llvm/ADT/StringMap.h" | ||
#include "llvm/ADT/StringRef.h" | #include "llvm/ADT/StringRef.h" | ||
#include "llvm/ADT/StringSet.h" | #include "llvm/ADT/StringSet.h" | ||
+#include "llvm/ADT/StringTable.h" | |||
#include "llvm/Frontend/OpenMP/OMPGridValues.h" | #include "llvm/Frontend/OpenMP/OMPGridValues.h" | ||
#include "llvm/IR/DerivedTypes.h" | #include "llvm/IR/DerivedTypes.h" | ||
#include "llvm/Support/DataTypes.h" | #include "llvm/Support/DataTypes.h" | ||
@@ -1016,10 +1018,10 @@ public: | |||
virtual void getTargetDefines | virtual void getTargetDefines | ||
MacroBuilder &Builder) const = 0; | MacroBuilder &Builder) const = 0; | ||
- /// Return information about target-specific builtins for | + /// Return information about target-specific builtins for the current primary | ||
- /// | + /// target, and info about which builtins are non-portable across the current | ||
- /// | + /// set of primary and secondary targets. | ||
- virtual | + virtual llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const = 0; | ||
/// Returns target-specific min and max values VScale_Range. | /// Returns target-specific min and max values VScale_Range. | ||
virtual std::optional<std::pair<unsigned, unsigned>> | virtual std::optional<std::pair<unsigned, unsigned>> | ||
@@ -1469,6 +1471,7 @@ public: | |||
/// specification | /// specification | ||
virtual bool validateBranchPr | virtual bool validateBranchPr | ||
BranchProtection | BranchProtection | ||
+ const LangOptions &LO, | |||
StringRef &Err) const { | StringRef &Err) const { | ||
Err = ""; | Err = ""; | ||
return false; | return false; | ||
@@ -1659,7 +1662,7 @@ public: | |||
// access target-specific GPU grid values that must be consistent between | // access target-specific GPU grid values that must be consistent between | ||
// host RTL (plugin), deviceRTL and clang. | // host RTL (plugin), deviceRTL and clang. | ||
virtual const llvm::omp::GV &getGridValue() const { | virtual const llvm::omp::GV &getGridValue() const { | ||
- llvm_unreachable | + return llvm::omp::SPIRVGridValues; | ||
} | } | ||
/// Retrieve the name of the platform as it is used in the | /// Retrieve the name of the platform as it is used in the |
@@ -546,7 +546,6 @@ TYPE_TRAIT_1(__i | |||
TYPE_TRAIT_1(__is_bounded_arr | TYPE_TRAIT_1(__is_bounded_arr | ||
TYPE_TRAIT_1(__is_unbounded_a | TYPE_TRAIT_1(__is_unbounded_a | ||
TYPE_TRAIT_1(__is_scoped_enum | TYPE_TRAIT_1(__is_scoped_enum | ||
-TYPE_TRAIT_1(__is_referenceab | |||
TYPE_TRAIT_1(__can_pass_in_re | TYPE_TRAIT_1(__can_pass_in_re | ||
TYPE_TRAIT_2(__reference_bind | TYPE_TRAIT_2(__reference_bind | ||
TYPE_TRAIT_2(__reference_cons | TYPE_TRAIT_2(__reference_cons |
@@ -110,11 +110,11 @@ multiclass ZARead<string n_suffix, string t, string i_prefix, list<ImmCheck> ch> | |||
} | } | ||
} | } | ||
-defm SVREAD_ZA8 : ZARead<"za8", | +defm SVREAD_ZA8 : ZARead<"za8", "cUcm", "aarch64_sme_read", [ImmCheck<2, ImmCheck0_0>]>; | ||
defm SVREAD_ZA16 : ZARead<"za16", "sUshb", "aarch64_sme_read | defm SVREAD_ZA16 : ZARead<"za16", "sUshb", "aarch64_sme_read | ||
defm SVREAD_ZA32 : ZARead<"za32", "iUif", "aarch64_sme_read | defm SVREAD_ZA32 : ZARead<"za32", "iUif", "aarch64_sme_read | ||
defm SVREAD_ZA64 : ZARead<"za64", "lUld", "aarch64_sme_read | defm SVREAD_ZA64 : ZARead<"za64", "lUld", "aarch64_sme_read | ||
-defm SVREAD_ZA128 : ZARead<"za128", | +defm SVREAD_ZA128 : ZARead<"za128", "csilUcUsUiUlmhbfd", "aarch64_sme_readq", [ImmCheck<2, ImmCheck0_15>]>; | ||
//////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// | ||
// Write horizontal/vertical ZA slices | // Write horizontal/vertical ZA slices | ||
@@ -131,11 +131,11 @@ multiclass ZAWrite<string n_suffix, string t, string i_prefix, list<ImmCheck> ch | |||
} | } | ||
} | } | ||
-defm SVWRITE_ZA8 : ZAWrite<"za8", | +defm SVWRITE_ZA8 : ZAWrite<"za8", "cUcm", "aarch64_sme_write", [ImmCheck<0, ImmCheck0_0>]>; | ||
defm SVWRITE_ZA16 : ZAWrite<"za16", "sUshb", "aarch64_sme_writ | defm SVWRITE_ZA16 : ZAWrite<"za16", "sUshb", "aarch64_sme_writ | ||
defm SVWRITE_ZA32 : ZAWrite<"za32", "iUif", "aarch64_sme_writ | defm SVWRITE_ZA32 : ZAWrite<"za32", "iUif", "aarch64_sme_writ | ||
defm SVWRITE_ZA64 : ZAWrite<"za64", "lUld", "aarch64_sme_writ | defm SVWRITE_ZA64 : ZAWrite<"za64", "lUld", "aarch64_sme_writ | ||
-defm SVWRITE_ZA128 : ZAWrite<"za128", | +defm SVWRITE_ZA128 : ZAWrite<"za128", "csilUcUsUiUlmhbfd", "aarch64_sme_writeq", [ImmCheck<0, ImmCheck0_15>]>; | ||
//////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// | ||
// SME - Zero | // SME - Zero | ||
@@ -350,7 +350,7 @@ multiclass ZAWrite_VG<strin | |||
} | } | ||
let SMETargetGuard = "sme2" in { | let SMETargetGuard = "sme2" in { | ||
- defm SVWRITE_ZA8 : ZAWrite_VG<"za8", | + defm SVWRITE_ZA8 : ZAWrite_VG<"za8", "cUcm", "aarch64_sme_write", [ImmCheck<0, ImmCheck0_0>]>; | ||
defm SVWRITE_ZA16 : ZAWrite_VG<"za16", "sUshb", "aarch64_sme_writ | defm SVWRITE_ZA16 : ZAWrite_VG<"za16", "sUshb", "aarch64_sme_writ | ||
defm SVWRITE_ZA32 : ZAWrite_VG<"za32", "iUif", "aarch64_sme_writ | defm SVWRITE_ZA32 : ZAWrite_VG<"za32", "iUif", "aarch64_sme_writ | ||
defm SVWRITE_ZA64 : ZAWrite_VG<"za64", "lUld", "aarch64_sme_writ | defm SVWRITE_ZA64 : ZAWrite_VG<"za64", "lUld", "aarch64_sme_writ | ||
@@ -366,7 +366,7 @@ multiclass ZARead_VG<string | |||
} | } | ||
let SMETargetGuard = "sme2" in { | let SMETargetGuard = "sme2" in { | ||
- defm SVREAD_ZA8 : ZARead_VG<"za8", | + defm SVREAD_ZA8 : ZARead_VG<"za8", "cUcm", "aarch64_sme_read", [ImmCheck<0, ImmCheck0_0>]>; | ||
defm SVREAD_ZA16 : ZARead_VG<"za16", "sUshb", "aarch64_sme_read | defm SVREAD_ZA16 : ZARead_VG<"za16", "sUshb", "aarch64_sme_read | ||
defm SVREAD_ZA32 : ZARead_VG<"za32", "iUif", "aarch64_sme_read | defm SVREAD_ZA32 : ZARead_VG<"za32", "iUif", "aarch64_sme_read | ||
defm SVREAD_ZA64 : ZARead_VG<"za64", "lUld", "aarch64_sme_read | defm SVREAD_ZA64 : ZARead_VG<"za64", "lUld", "aarch64_sme_read | ||
@@ -722,7 +722,7 @@ def IN_STREAMING_MOD | |||
// lookup table expand four contiguous registers | // lookup table expand four contiguous registers | ||
// | // | ||
let SMETargetGuard = "sme2" in { | let SMETargetGuard = "sme2" in { | ||
- def SVLUTI2_LANE_ZT_X4 : Inst<"svluti2_lane_zt_{d}_x4", "4.di[i", | + def SVLUTI2_LANE_ZT_X4 : Inst<"svluti2_lane_zt_{d}_x4", "4.di[i", "cUcsUsiUimbhf", MergeNone, "aarch64_sme_luti2_lane_zt_x4", [IsStreaming, IsInZT0], [ImmCheck<0, ImmCheck0_0>, ImmCheck<2, ImmCheck0_3>]>; | ||
def SVLUTI4_LANE_ZT_ | def SVLUTI4_LANE_ZT_ | ||
} | } | ||
@@ -730,16 +730,16 @@ let SMETargetGuard = "sme2" in { | |||
// lookup table expand one register | // lookup table expand one register | ||
// | // | ||
let SMETargetGuard = "sme2" in { | let SMETargetGuard = "sme2" in { | ||
- def SVLUTI2_LANE_ZT : Inst<"svluti2_lane_zt_{d}", "di[i", | + def SVLUTI2_LANE_ZT : Inst<"svluti2_lane_zt_{d}", "di[i", "cUcsUsiUimbhf", MergeNone, "aarch64_sme_luti2_lane_zt", [IsStreaming, IsInZT0], [ImmCheck<0, ImmCheck0_0>, ImmCheck<2, ImmCheck0_15>]>; | ||
- def SVLUTI4_LANE_ZT : Inst<"svluti4_lane_zt_{d}", "di[i", | + def SVLUTI4_LANE_ZT : Inst<"svluti4_lane_zt_{d}", "di[i", "cUcsUsiUimbhf", MergeNone, "aarch64_sme_luti4_lane_zt", [IsStreaming, IsInZT0], [ImmCheck<0, ImmCheck0_0>, ImmCheck<2, ImmCheck0_7>]>; | ||
} | } | ||
// | // | ||
// lookup table expand two contiguous registers | // lookup table expand two contiguous registers | ||
// | // | ||
let SMETargetGuard = "sme2" in { | let SMETargetGuard = "sme2" in { | ||
- def SVLUTI2_LANE_ZT_X2 : Inst<"svluti2_lane_zt_{d}_x2", "2.di[i", | + def SVLUTI2_LANE_ZT_X2 : Inst<"svluti2_lane_zt_{d}_x2", "2.di[i", "cUcsUsiUimbhf", MergeNone, "aarch64_sme_luti2_lane_zt_x2", [IsStreaming, IsInZT0], [ImmCheck<0, ImmCheck0_0>, ImmCheck<2, ImmCheck0_7>]>; | ||
- def SVLUTI4_LANE_ZT_X2 : Inst<"svluti4_lane_zt_{d}_x2", "2.di[i", | + def SVLUTI4_LANE_ZT_X2 : Inst<"svluti4_lane_zt_{d}_x2", "2.di[i", "cUcsUsiUimbhf", MergeNone, "aarch64_sme_luti4_lane_zt_x2", [IsStreaming, IsInZT0], [ImmCheck<0, ImmCheck0_0>, ImmCheck<2, ImmCheck0_3>]>; | ||
} | } | ||
// | // | ||
@@ -748,30 +748,30 @@ let SMETargetGuard = "sme2" in { | |||
// FDOT | // FDOT | ||
let SMETargetGuard = "sme-f8f32" in { | let SMETargetGuard = "sme-f8f32" in { | ||
- def SVDOT_LANE_FP8_ZA32_VG1x2 : Inst<"svdot_lane_za32[_mf8] | + def SVDOT_LANE_FP8_ZA32_VG1x2 : Inst<"svdot_lane_za32[_mf8]_vg1x2", "vm2di>", "m", MergeNone, "aarch64_sme_fp8_fdot_lane_za32_vg1x2", [IsStreaming, IsInOutZA, IsOverloadNone], [ImmCheck<3, ImmCheck0_3>]>; | ||
- def SVDOT_LANE_FP8_ZA32_VG1x4 : Inst<"svdot_lane_za32[_mf8] | + def SVDOT_LANE_FP8_ZA32_VG1x4 : Inst<"svdot_lane_za32[_mf8]_vg1x4", "vm4di>", "m", MergeNone, "aarch64_sme_fp8_fdot_lane_za32_vg1x4", [IsStreaming, IsInOutZA, IsOverloadNone], [ImmCheck<3, ImmCheck0_3>]>; | ||
- def SVVDOTB_LANE_FP8_ZA32_VG1x4 : Inst<"svvdotb_lane_za32[_mf8] | + def SVVDOTB_LANE_FP8_ZA32_VG1x4 : Inst<"svvdotb_lane_za32[_mf8]_vg1x4", "vm2di>", "m", MergeNone, "aarch64_sme_fp8_fvdotb_lane_za32_vg1x4", [IsOverloadNone, IsStreaming, IsInOutZA], [ImmCheck<3, ImmCheck0_3>]>; | ||
- def SVVDOTT_LANE_FP8_ZA32_VG1x4 : Inst<"svvdott_lane_za32[_mf8] | + def SVVDOTT_LANE_FP8_ZA32_VG1x4 : Inst<"svvdott_lane_za32[_mf8]_vg1x4", "vm2di>", "m", MergeNone, "aarch64_sme_fp8_fvdott_lane_za32_vg1x4", [IsOverloadNone, IsStreaming, IsInOutZA], [ImmCheck<3, ImmCheck0_3>]>; | ||
- def SVDOT_SINGLE_FP8_ZA32_VG1x2 : Inst<"svdot[_single]_za32[_mf8] | + def SVDOT_SINGLE_FP8_ZA32_VG1x2 : Inst<"svdot[_single]_za32[_mf8]_vg1x2", "vm2d>", "m", MergeNone, "aarch64_sme_fp8_fdot_single_za32_vg1x2", [IsStreaming, IsInOutZA, IsOverloadNone], []>; | ||
- def SVDOT_SINGLE_FP8_ZA32_VG1x4 : Inst<"svdot[_single]_za32[_mf8] | + def SVDOT_SINGLE_FP8_ZA32_VG1x4 : Inst<"svdot[_single]_za32[_mf8]_vg1x4", "vm4d>", "m", MergeNone, "aarch64_sme_fp8_fdot_single_za32_vg1x4", [IsStreaming, IsInOutZA, IsOverloadNone], []>; | ||
- def SVDOT_MULTI_FP8_ZA32_VG1x2 : Inst<"svdot_za32[_mf8] | + def SVDOT_MULTI_FP8_ZA32_VG1x2 : Inst<"svdot_za32[_mf8]_vg1x2", "vm22>", "m", MergeNone, "aarch64_sme_fp8_fdot_multi_za32_vg1x2", [IsStreaming, IsInOutZA, IsOverloadNone], []>; | ||
- def SVDOT_MULTI_FP8_ZA32_VG1x4 : Inst<"svdot_za32[_mf8] | + def SVDOT_MULTI_FP8_ZA32_VG1x4 : Inst<"svdot_za32[_mf8]_vg1x4", "vm44>", "m", MergeNone, "aarch64_sme_fp8_fdot_multi_za32_vg1x4", [IsStreaming, IsInOutZA, IsOverloadNone], []>; | ||
} | } | ||
let SMETargetGuard = "sme-f8f16" in { | let SMETargetGuard = "sme-f8f16" in { | ||
- def SVDOT_LANE_FP8_ZA16_VG1x2 : Inst<"svdot_lane_za16[_mf8] | + def SVDOT_LANE_FP8_ZA16_VG1x2 : Inst<"svdot_lane_za16[_mf8]_vg1x2", "vm2di>", "m", MergeNone, "aarch64_sme_fp8_fdot_lane_za16_vg1x2", [IsStreaming, IsInOutZA, IsOverloadNone], [ImmCheck<3, ImmCheck0_7>]>; | ||
- def SVDOT_LANE_FP8_ZA16_VG1x4 : Inst<"svdot_lane_za16[_mf8] | + def SVDOT_LANE_FP8_ZA16_VG1x4 : Inst<"svdot_lane_za16[_mf8]_vg1x4", "vm4di>", "m", MergeNone, "aarch64_sme_fp8_fdot_lane_za16_vg1x4", [IsStreaming, IsInOutZA, IsOverloadNone], [ImmCheck<3, ImmCheck0_7>]>; | ||
- def SVVDOT_LANE_FP8_ZA16_VG1x2 : Inst<"svvdot_lane_za16[_mf8] | + def SVVDOT_LANE_FP8_ZA16_VG1x2 : Inst<"svvdot_lane_za16[_mf8]_vg1x2", "vm2di>", "m", MergeNone, "aarch64_sme_fp8_fvdot_lane_za16_vg1x2", [IsOverloadNone, IsStreaming, IsInOutZA], [ImmCheck<3, ImmCheck0_7>]>; | ||
- def SVDOT_SINGLE_FP8_ZA16_VG1x2 : Inst<"svdot[_single]_za16[_mf8] | + def SVDOT_SINGLE_FP8_ZA16_VG1x2 : Inst<"svdot[_single]_za16[_mf8]_vg1x2", "vm2d>", "m", MergeNone, "aarch64_sme_fp8_fdot_single_za16_vg1x2", [IsStreaming, IsInOutZA, IsOverloadNone], []>; | ||
- def SVDOT_SINGLE_FP8_ZA16_VG1x4 : Inst<"svdot[_single]_za16[_mf8] | + def SVDOT_SINGLE_FP8_ZA16_VG1x4 : Inst<"svdot[_single]_za16[_mf8]_vg1x4", "vm4d>", "m", MergeNone, "aarch64_sme_fp8_fdot_single_za16_vg1x4", [IsStreaming, IsInOutZA, IsOverloadNone], []>; | ||
- def SVDOT_MULTI_FP8_ZA16_VG1x2 : Inst<"svdot_za16[_mf8] | + def SVDOT_MULTI_FP8_ZA16_VG1x2 : Inst<"svdot_za16[_mf8]_vg1x2", "vm22>", "m", MergeNone, "aarch64_sme_fp8_fdot_multi_za16_vg1x2", [IsStreaming, IsInOutZA, IsOverloadNone], []>; | ||
- def SVDOT_MULTI_FP8_ZA16_VG1x4 : Inst<"svdot_za16[_mf8] | + def SVDOT_MULTI_FP8_ZA16_VG1x4 : Inst<"svdot_za16[_mf8]_vg1x4", "vm44>", "m", MergeNone, "aarch64_sme_fp8_fdot_multi_za16_vg1x4", [IsStreaming, IsInOutZA, IsOverloadNone], []>; | ||
} | } | ||
//////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// | ||
@@ -811,12 +811,12 @@ multiclass ZAReadz<string n_suffix, string vg_num, string t, string i_prefix, li | |||
} | } | ||
} | } | ||
-defm SVREADZ_ZA8_X2 : ZAReadz<"za8", "2", | +defm SVREADZ_ZA8_X2 : ZAReadz<"za8", "2", "cUcm", "aarch64_sme_readz", [ImmCheck<0, ImmCheck0_0>]>; | ||
defm SVREADZ_ZA16_X2 : ZAReadz<"za16", "2", "sUshb", "aarch64_sme_read | defm SVREADZ_ZA16_X2 : ZAReadz<"za16", "2", "sUshb", "aarch64_sme_read | ||
defm SVREADZ_ZA32_X2 : ZAReadz<"za32", "2", "iUif", "aarch64_sme_read | defm SVREADZ_ZA32_X2 : ZAReadz<"za32", "2", "iUif", "aarch64_sme_read | ||
defm SVREADZ_ZA64_X2 : ZAReadz<"za64", "2", "lUld", "aarch64_sme_read | defm SVREADZ_ZA64_X2 : ZAReadz<"za64", "2", "lUld", "aarch64_sme_read | ||
-defm SVREADZ_ZA8_X4 : ZAReadz<"za8", "4", | +defm SVREADZ_ZA8_X4 : ZAReadz<"za8", "4", "cUcm", "aarch64_sme_readz", [ImmCheck<0, ImmCheck0_0>]>; | ||
defm SVREADZ_ZA16_X4 : ZAReadz<"za16", "4", "sUshb", "aarch64_sme_read | defm SVREADZ_ZA16_X4 : ZAReadz<"za16", "4", "sUshb", "aarch64_sme_read | ||
defm SVREADZ_ZA32_X4 : ZAReadz<"za32", "4", "iUif", "aarch64_sme_read | defm SVREADZ_ZA32_X4 : ZAReadz<"za32", "4", "iUif", "aarch64_sme_read | ||
defm SVREADZ_ZA64_X4 : ZAReadz<"za64", "4", "lUld", "aarch64_sme_read | defm SVREADZ_ZA64_X4 : ZAReadz<"za64", "4", "lUld", "aarch64_sme_read | ||
@@ -834,15 +834,15 @@ multiclass ZAReadzSingle<st | |||
} | } | ||
} | } | ||
-defm SVREADZ_ZA8 : ZAReadzSingle<"za8", | +defm SVREADZ_ZA8 : ZAReadzSingle<"za8", "cUcm", "aarch64_sme_readz", [ImmCheck<0, ImmCheck0_0>]>; | ||
defm SVREADZ_ZA16 : ZAReadzSingle<"za16", "sUshb", "aarch64_sme_read | defm SVREADZ_ZA16 : ZAReadzSingle<"za16", "sUshb", "aarch64_sme_read | ||
defm SVREADZ_ZA32 : ZAReadzSingle<"za32", "iUif", "aarch64_sme_read | defm SVREADZ_ZA32 : ZAReadzSingle<"za32", "iUif", "aarch64_sme_read | ||
defm SVREADZ_ZA64 : ZAReadzSingle<"za64", "lUld", "aarch64_sme_read | defm SVREADZ_ZA64 : ZAReadzSingle<"za64", "lUld", "aarch64_sme_read | ||
-defm SVREADZ_ZA128 : ZAReadzSingle<"za128", | +defm SVREADZ_ZA128 : ZAReadzSingle<"za128", "csilUcUiUsUlmbhfd", "aarch64_sme_readz_q", [ImmCheck<0, ImmCheck0_15>]>; | ||
multiclass ZAReadzArray<string vg_num>{ | multiclass ZAReadzArray<string vg_num>{ | ||
let SMETargetGuard = "sme2p1" in { | let SMETargetGuard = "sme2p1" in { | ||
- def NAME # _B : SInst<"svreadz_za8_{d}_vg1x" # vg_num, vg_num # "m", | + def NAME # _B : SInst<"svreadz_za8_{d}_vg1x" # vg_num, vg_num # "m", "cUcm", MergeNone, "aarch64_sme_readz_x" # vg_num, [IsStreaming, IsInOutZA]>; | ||
def NAME # _H : SInst<"svreadz_za16_{d}_vg1x" # vg_num, vg_num # "m", "sUsbh", MergeNone, "aarch64_sme_read | def NAME # _H : SInst<"svreadz_za16_{d}_vg1x" # vg_num, vg_num # "m", "sUsbh", MergeNone, "aarch64_sme_read | ||
def NAME # _S : SInst<"svreadz_za32_{d}_vg1x" # vg_num, vg_num # "m", "iUif", MergeNone, "aarch64_sme_read | def NAME # _S : SInst<"svreadz_za32_{d}_vg1x" # vg_num, vg_num # "m", "iUif", MergeNone, "aarch64_sme_read | ||
def NAME # _D : SInst<"svreadz_za64_{d}_vg1x" # vg_num, vg_num # "m", "lUld", MergeNone, "aarch64_sme_read | def NAME # _D : SInst<"svreadz_za64_{d}_vg1x" # vg_num, vg_num # "m", "lUld", MergeNone, "aarch64_sme_read | ||
@@ -859,51 +859,51 @@ let SMETargetGuard = "sme-lutv2" in { | |||
} | } | ||
let SMETargetGuard = "sme-f8f32" in { | let SMETargetGuard = "sme-f8f32" in { | ||
- def SVMOPA_FP8_ZA32 : Inst<"svmopa_za32[_mf8] | + def SVMOPA_FP8_ZA32 : Inst<"svmopa_za32[_mf8]_m", "viPPdd>", "m", MergeNone, "aarch64_sme_fp8_fmopa_za32", | ||
- [IsStreaming, IsInOutZA, | + [IsStreaming, IsInOutZA, IsOverloadNone], [ImmCheck<0, ImmCheck0_3>]>; | ||
// FMLALL (indexed) | // FMLALL (indexed) | ||
- def SVMLA_FP8_LANE_ZA32_VG4x1 : Inst<"svmla_lane_za32[_mf8] | + def SVMLA_FP8_LANE_ZA32_VG4x1 : Inst<"svmla_lane_za32[_mf8]_vg4x1", "vmddi>", "m", MergeNone, "aarch64_sme_fp8_fmlall_lane_za32_vg4x1", | ||
- [IsStreaming, IsInOutZA, | + [IsStreaming, IsInOutZA, IsOverloadNone], [ImmCheck<3, ImmCheck0_15>]>; | ||
- def SVMLA_FP8_LANE_ZA32_VG4x2 : Inst<"svmla_lane_za32[_mf8] | + def SVMLA_FP8_LANE_ZA32_VG4x2 : Inst<"svmla_lane_za32[_mf8]_vg4x2", "vm2di>", "m", MergeNone, "aarch64_sme_fp8_fmlall_lane_za32_vg4x2", | ||
- [IsStreaming, IsInOutZA, | + [IsStreaming, IsInOutZA, IsOverloadNone], [ImmCheck<3, ImmCheck0_15>]>; | ||
- def SVMLA_FP8_LANE_ZA16_VG4x4 : Inst<"svmla_lane_za32[_mf8] | + def SVMLA_FP8_LANE_ZA16_VG4x4 : Inst<"svmla_lane_za32[_mf8]_vg4x4", "vm4di>", "m", MergeNone, "aarch64_sme_fp8_fmlall_lane_za32_vg4x4", | ||
- [IsStreaming, IsInOutZA, | + [IsStreaming, IsInOutZA, IsOverloadNone], [ImmCheck<3, ImmCheck0_15>]>; | ||
// FMLALL (single) | // FMLALL (single) | ||
- def SVMLA_FP8_SINGLE_ZA32_VG4x1 : Inst<"svmla[_single]_za32[_mf8] | + def SVMLA_FP8_SINGLE_ZA32_VG4x1 : Inst<"svmla[_single]_za32[_mf8]_vg4x1", "vmdd>", "m", MergeNone, "aarch64_sme_fp8_fmlall_single_za32_vg4x1", | ||
- [IsStreaming, IsInOutZA, | + [IsStreaming, IsInOutZA, IsOverloadNone], []>; | ||
- def SVMLA_FP8_SINGLE_ZA32_VG4x2 : Inst<"svmla[_single]_za32[_mf8] | + def SVMLA_FP8_SINGLE_ZA32_VG4x2 : Inst<"svmla[_single]_za32[_mf8]_vg4x2", "vm2d>", "m", MergeNone, "aarch64_sme_fp8_fmlall_single_za32_vg4x2", | ||
- [IsStreaming, IsInOutZA, | + [IsStreaming, IsInOutZA, IsOverloadNone], []>; | ||
- def SVMLA_FP8_SINGLE_ZA32_VG4x4 : Inst<"svmla[_single]_za32[_mf8] | + def SVMLA_FP8_SINGLE_ZA32_VG4x4 : Inst<"svmla[_single]_za32[_mf8]_vg4x4", "vm4d>", "m", MergeNone, "aarch64_sme_fp8_fmlall_single_za32_vg4x4", | ||
- [IsStreaming, IsInOutZA, | + [IsStreaming, IsInOutZA, IsOverloadNone], []>; | ||
// FMLALL (multiple) | // FMLALL (multiple) | ||
- def SVMLA_FP8_MULTI_ZA32_VG4x2 : Inst<"svmla_za32[_mf8] | + def SVMLA_FP8_MULTI_ZA32_VG4x2 : Inst<"svmla_za32[_mf8]_vg4x2", "vm22>", "m", MergeNone, "aarch64_sme_fp8_fmlall_multi_za32_vg4x2", | ||
- [IsStreaming, IsInOutZA, | + [IsStreaming, IsInOutZA, IsOverloadNone], []>; | ||
- def SVMLA_FP8_MULTI_ZA32_VG4x4 : Inst<"svmla_za32[_mf8] | + def SVMLA_FP8_MULTI_ZA32_VG4x4 : Inst<"svmla_za32[_mf8]_vg4x4", "vm44>", "m", MergeNone, "aarch64_sme_fp8_fmlall_multi_za32_vg4x4", | ||
- [IsStreaming, IsInOutZA, | + [IsStreaming, IsInOutZA, IsOverloadNone], []>; | ||
} | } | ||
let SMETargetGuard = "sme-f8f16" in { | let SMETargetGuard = "sme-f8f16" in { | ||
- def SVMOPA_FP8_ZA16 : Inst<"svmopa_za16[_mf8] | + def SVMOPA_FP8_ZA16 : Inst<"svmopa_za16[_mf8]_m", "viPPdd>", "m", MergeNone, "aarch64_sme_fp8_fmopa_za16", | ||
- [IsStreaming, IsInOutZA, | + [IsStreaming, IsInOutZA, IsOverloadNone], [ImmCheck<0, ImmCheck0_1>]>; | ||
// FMLAL (indexed) | // FMLAL (indexed) | ||
- def SVMLA_FP8_LANE_ZA16_VG2x1 : Inst<"svmla_lane_za16[_mf8] | + def SVMLA_FP8_LANE_ZA16_VG2x1 : Inst<"svmla_lane_za16[_mf8]_vg2x1", "vmddi>", "m", MergeNone, "aarch64_sme_fp8_fmlal_lane_za16_vg2x1", | ||
- [IsStreaming, IsInOutZA, | + [IsStreaming, IsInOutZA, IsOverloadNone], [ImmCheck<3, ImmCheck0_15>]>; | ||
- def SVMLA_FP8_LANE_ZA16_VG2x2 : Inst<"svmla_lane_za16[_mf8] | + def SVMLA_FP8_LANE_ZA16_VG2x2 : Inst<"svmla_lane_za16[_mf8]_vg2x2", "vm2di>", "m", MergeNone, "aarch64_sme_fp8_fmlal_lane_za16_vg2x2", | ||
- [IsStreaming, IsInOutZA, | + [IsStreaming, IsInOutZA, IsOverloadNone], [ImmCheck<3, ImmCheck0_15>]>; | ||
- def SVMLA_FP8_LANE_ZA16_VG2x4 : Inst<"svmla_lane_za16[_mf8] | + def SVMLA_FP8_LANE_ZA16_VG2x4 : Inst<"svmla_lane_za16[_mf8]_vg2x4", "vm4di>", "m", MergeNone, "aarch64_sme_fp8_fmlal_lane_za16_vg2x4", | ||
- [IsStreaming, IsInOutZA, | + [IsStreaming, IsInOutZA, IsOverloadNone], [ImmCheck<3, ImmCheck0_15>]>; | ||
// FMLAL (single) | // FMLAL (single) | ||
- def SVMLA_FP8_SINGLE_ZA16_VG2x1 : Inst<"svmla[_single]_za16[_mf8] | + def SVMLA_FP8_SINGLE_ZA16_VG2x1 : Inst<"svmla[_single]_za16[_mf8]_vg2x1", "vmdd>", "m", MergeNone, "aarch64_sme_fp8_fmlal_single_za16_vg2x1", | ||
- [IsStreaming, IsInOutZA, | + [IsStreaming, IsInOutZA, IsOverloadNone], []>; | ||
- def SVMLA_FP8_SINGLE_ZA16_VG2x2 : Inst<"svmla[_single]_za16[_mf8] | + def SVMLA_FP8_SINGLE_ZA16_VG2x2 : Inst<"svmla[_single]_za16[_mf8]_vg2x2", "vm2d>", "m", MergeNone, "aarch64_sme_fp8_fmlal_single_za16_vg2x2", | ||
- [IsStreaming, IsInOutZA, | + [IsStreaming, IsInOutZA, IsOverloadNone], []>; | ||
- def SVMLA_FP8_SINGLE_ZA16_VG2x4 : Inst<"svmla[_single]_za16[_mf8] | + def SVMLA_FP8_SINGLE_ZA16_VG2x4 : Inst<"svmla[_single]_za16[_mf8]_vg2x4", "vm4d>", "m", MergeNone, "aarch64_sme_fp8_fmlal_single_za16_vg2x4", | ||
- [IsStreaming, IsInOutZA, | + [IsStreaming, IsInOutZA, IsOverloadNone], []>; | ||
// FMLAL (multiple) | // FMLAL (multiple) | ||
- def SVMLA_FP8_MULTI_ZA16_VG2x2 : Inst<"svmla_za16[_mf8] | + def SVMLA_FP8_MULTI_ZA16_VG2x2 : Inst<"svmla_za16[_mf8]_vg2x2", "vm22>", "m", MergeNone, "aarch64_sme_fp8_fmlal_multi_za16_vg2x2", | ||
- [IsStreaming, IsInOutZA, | + [IsStreaming, IsInOutZA, IsOverloadNone], []>; | ||
- def SVMLA_FP8_MULTI_ZA16_VG2x4 : Inst<"svmla_za16[_mf8] | + def SVMLA_FP8_MULTI_ZA16_VG2x4 : Inst<"svmla_za16[_mf8]_vg2x4", "vm44>", "m", MergeNone, "aarch64_sme_fp8_fmlal_multi_za16_vg2x4", | ||
- [IsStreaming, IsInOutZA, | + [IsStreaming, IsInOutZA, IsOverloadNone], []>; | ||
} | } | ||
} // let SVETargetGuard = InvalidMode | } // let SVETargetGuard = InvalidMode |
@@ -2104,7 +2104,7 @@ let SVETargetGuard = "sve2p1", SMETargetGuard = "sme" in { | |||
def SVSCLAMP : SInst<"svclamp[_{d}]", "dddd", "csil", MergeNone, "aarch64_sve_scla | def SVSCLAMP : SInst<"svclamp[_{d}]", "dddd", "csil", MergeNone, "aarch64_sve_scla | ||
def SVUCLAMP : SInst<"svclamp[_{d}]", "dddd", "UcUsUiUl", MergeNone, "aarch64_sve_ucla | def SVUCLAMP : SInst<"svclamp[_{d}]", "dddd", "UcUsUiUl", MergeNone, "aarch64_sve_ucla | ||
-defm SVREVD : SInstZPZ<"svrevd", | +defm SVREVD : SInstZPZ<"svrevd", "csilUcUsUiUlmbhfd", "aarch64_sve_revd">; | ||
} | } | ||
let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in { | let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in { | ||
@@ -2223,8 +2223,8 @@ let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in { | |||
def SVADD_SINGLE_X4 : SInst<"svadd[_single_{d}_x4]", "44d", "cUcsUsiUilUl", MergeNone, "aarch64_sve_add_ | def SVADD_SINGLE_X4 : SInst<"svadd[_single_{d}_x4]", "44d", "cUcsUsiUilUl", MergeNone, "aarch64_sve_add_ | ||
// 2-way and 4-way selects | // 2-way and 4-way selects | ||
- def SVSEL_X2 : SInst<"svsel[_{d}_x2]", "2}22", | + def SVSEL_X2 : SInst<"svsel[_{d}_x2]", "2}22", "cUcsUsiUilUlmbhfd", MergeNone, "aarch64_sve_sel_x2", [IsStreaming], []>; | ||
- def SVSEL_X4 : SInst<"svsel[_{d}_x4]", "4}44", | + def SVSEL_X4 : SInst<"svsel[_{d}_x4]", "4}44", "cUcsUsiUilUlmbhfd", MergeNone, "aarch64_sve_sel_x4", [IsStreaming], []>; | ||
// SRSHL / URSHL | // SRSHL / URSHL | ||
def SVSRSHL_SINGLE_X | def SVSRSHL_SINGLE_X | ||
@@ -2402,15 +2402,15 @@ let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in { | |||
// | // | ||
let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in { | let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in { | ||
- def SVZIP_X2 : SInst<"svzip[_{d}_x2]", "22", | + def SVZIP_X2 : SInst<"svzip[_{d}_x2]", "22", "cUcsUsiUilUlmbhfd", MergeNone, "aarch64_sve_zip_x2", [IsStreaming], []>; | ||
- def SVZIPQ_X2 : SInst<"svzipq[_{d}_x2]", "22", | + def SVZIPQ_X2 : SInst<"svzipq[_{d}_x2]", "22", "cUcsUsiUilUlmbhfd", MergeNone, "aarch64_sve_zipq_x2", [IsStreaming], []>; | ||
- def SVZIP_X4 : SInst<"svzip[_{d}_x4]", "44", | + def SVZIP_X4 : SInst<"svzip[_{d}_x4]", "44", "cUcsUsiUilUlmbhfd", MergeNone, "aarch64_sve_zip_x4", [IsStreaming], []>; | ||
- def SVZIPQ_X4 : SInst<"svzipq[_{d}_x4]", "44", | + def SVZIPQ_X4 : SInst<"svzipq[_{d}_x4]", "44", "cUcsUsiUilUlmbhfd", MergeNone, "aarch64_sve_zipq_x4", [IsStreaming], []>; | ||
- def SVUZP_X2 : SInst<"svuzp[_{d}_x2]", "22", | + def SVUZP_X2 : SInst<"svuzp[_{d}_x2]", "22", "cUcsUsiUilUlmbhfd", MergeNone, "aarch64_sve_uzp_x2", [IsStreaming], []>; | ||
- def SVUZPQ_X2 : SInst<"svuzpq[_{d}_x2]", "22", | + def SVUZPQ_X2 : SInst<"svuzpq[_{d}_x2]", "22", "cUcsUsiUilUlmbhfd", MergeNone, "aarch64_sve_uzpq_x2", [IsStreaming], []>; | ||
- def SVUZP_X4 : SInst<"svuzp[_{d}_x4]", "44", | + def SVUZP_X4 : SInst<"svuzp[_{d}_x4]", "44", "cUcsUsiUilUlmbhfd", MergeNone, "aarch64_sve_uzp_x4", [IsStreaming], []>; | ||
- def SVUZPQ_X4 : SInst<"svuzpq[_{d}_x4]", "44", | + def SVUZPQ_X4 : SInst<"svuzpq[_{d}_x4]", "44", "cUcsUsiUilUlmbhfd", MergeNone, "aarch64_sve_uzpq_x4", [IsStreaming], []>; | ||
} | } | ||
// | // | ||
@@ -2432,18 +2432,18 @@ let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2,fp8" in { | |||
def FSCALE_X4 : Inst<"svscale[_{d}_x4]", "444.x", "fhd", MergeNone, "aarch64_sme_fp8_ | def FSCALE_X4 : Inst<"svscale[_{d}_x4]", "444.x", "fhd", MergeNone, "aarch64_sme_fp8_ | ||
// Convert from FP8 to half-precision/BFloat16 multi-vector | // Convert from FP8 to half-precision/BFloat16 multi-vector | ||
- def SVF1CVT_X2 : Inst<"svcvt1_{d}[_mf8] | + def SVF1CVT_X2 : Inst<"svcvt1_{d}[_mf8]_x2", "2~>", "bh", MergeNone, "aarch64_sve_fp8_cvt1_x2", [IsStreaming], []>; | ||
- def SVF2CVT_X2 : Inst<"svcvt2_{d}[_mf8] | + def SVF2CVT_X2 : Inst<"svcvt2_{d}[_mf8]_x2", "2~>", "bh", MergeNone, "aarch64_sve_fp8_cvt2_x2", [IsStreaming], []>; | ||
// Convert from FP8 to deinterleaved half-precision/BFloat16 multi-vector | // Convert from FP8 to deinterleaved half-precision/BFloat16 multi-vector | ||
- def SVF1CVTL_X2 : Inst<"svcvtl1_{d}[_mf8] | + def SVF1CVTL_X2 : Inst<"svcvtl1_{d}[_mf8]_x2", "2~>", "bh", MergeNone, "aarch64_sve_fp8_cvtl1_x2", [IsStreaming], []>; | ||
- def SVF2CVTL_X2 : Inst<"svcvtl2_{d}[_mf8] | + def SVF2CVTL_X2 : Inst<"svcvtl2_{d}[_mf8]_x2", "2~>", "bh", MergeNone, "aarch64_sve_fp8_cvtl2_x2", [IsStreaming], []>; | ||
// Convert from single/half/bfloat multivector to FP8 | // Convert from single/half/bfloat multivector to FP8 | ||
- def SVFCVT_X2 : Inst<"svcvt_mf8[_{d}_x2] | + def SVFCVT_X2 : Inst<"svcvt_mf8[_{d}_x2]", "~2>", "bh", MergeNone, "aarch64_sve_fp8_cvt_x2", [IsStreaming], []>; | ||
- def SVFCVT_X4 : Inst<"svcvt_mf8[_{d}_x4] | + def SVFCVT_X4 : Inst<"svcvt_mf8[_{d}_x4]", "~4>", "f", MergeNone, "aarch64_sve_fp8_cvt_x4", [IsOverloadNone, IsStreaming], []>; | ||
// interleaved | // interleaved | ||
- def SVFCVTN_X4 : Inst<"svcvtn_mf8[_{d}_x4] | + def SVFCVTN_X4 : Inst<"svcvtn_mf8[_{d}_x4]", "~4>", "f", MergeNone, "aarch64_sve_fp8_cvtn_x4", [IsOverloadNone, IsStreaming], []>; | ||
} | } | ||
let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in { | let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in { | ||
@@ -2464,67 +2464,67 @@ let SVETargetGuard = "sve2,fp8", SMETargetGuard = "sme2,fp8" in { | |||
// SVE FP8 widening conversions | // SVE FP8 widening conversions | ||
// 8-bit floating-point convert to BFloat16/Float16 | // 8-bit floating-point convert to BFloat16/Float16 | ||
- def SVF1CVT : SInst<"svcvt1_{d}[_mf8] | + def SVF1CVT : SInst<"svcvt1_{d}[_mf8]", "d~>", "bh", MergeNone, "aarch64_sve_fp8_cvt1", [VerifyRuntimeMode]>; | ||
- def SVF2CVT : SInst<"svcvt2_{d}[_mf8] | + def SVF2CVT : SInst<"svcvt2_{d}[_mf8]", "d~>", "bh", MergeNone, "aarch64_sve_fp8_cvt2", [VerifyRuntimeMode]>; | ||
// 8-bit floating-point convert to BFloat16/Float16 (top) | // 8-bit floating-point convert to BFloat16/Float16 (top) | ||
- def SVF1CVTLT : SInst<"svcvtlt1_{d}[_mf8] | + def SVF1CVTLT : SInst<"svcvtlt1_{d}[_mf8]", "d~>", "bh", MergeNone, "aarch64_sve_fp8_cvtlt1", [VerifyRuntimeMode]>; | ||
- def SVF2CVTLT : SInst<"svcvtlt2_{d}[_mf8] | + def SVF2CVTLT : SInst<"svcvtlt2_{d}[_mf8]", "d~>", "bh", MergeNone, "aarch64_sve_fp8_cvtlt2", [VerifyRuntimeMode]>; | ||
// BFloat16/Float16 convert, narrow and interleave to 8-bit floating-point | // BFloat16/Float16 convert, narrow and interleave to 8-bit floating-point | ||
- def SVFCVTN : SInst<"svcvtn_mf8[_{d}_x2] | + def SVFCVTN : SInst<"svcvtn_mf8[_{d}_x2]", "~2>", "bh", MergeNone, "aarch64_sve_fp8_cvtn", [VerifyRuntimeMode]>; | ||
// Single-precision convert, narrow and interleave to 8-bit floating-point (top and bottom) | // Single-precision convert, narrow and interleave to 8-bit floating-point (top and bottom) | ||
- def SVFCVTNB : SInst<"svcvtnb_mf8[_f32_x2] | + def SVFCVTNB : SInst<"svcvtnb_mf8[_f32_x2]", "~2>", "f", MergeNone, "aarch64_sve_fp8_cvtnb", [VerifyRuntimeMode]>; | ||
- def SVFCVTNT : SInst<"svcvtnt_mf8[_f32_x2] | + def SVFCVTNT : SInst<"svcvtnt_mf8[_f32_x2]", "~~2>", "f", MergeNone, "aarch64_sve_fp8_cvtnt", [VerifyRuntimeMode]>; | ||
} | } | ||
let SVETargetGuard = "sve2,fp8dot2", SMETargetGuard ="sme,ssve-fp8dot2" in { | let SVETargetGuard = "sve2,fp8dot2", SMETargetGuard ="sme,ssve-fp8dot2" in { | ||
// 8-bit floating-point dot product to half-precision (vectors) | // 8-bit floating-point dot product to half-precision (vectors) | ||
- def SVFDOT_2WAY : SInst<"svdot[_f16_mf8] | + def SVFDOT_2WAY : SInst<"svdot[_f16_mf8]", "dd~~>", "h", MergeNone, "aarch64_sve_fp8_fdot", [VerifyRuntimeMode]>; | ||
- def SVFDOT_N_2WAY : SInst<"svdot[_n_f16_mf8] | + def SVFDOT_N_2WAY : SInst<"svdot[_n_f16_mf8]", "dd~!>", "h", MergeNone, "aarch64_sve_fp8_fdot", [VerifyRuntimeMode]>; | ||
// 8-bit floating-point dot product to half-precision (indexed) | // 8-bit floating-point dot product to half-precision (indexed) | ||
- def SVFDOT_LANE_2WAY : SInst<"svdot_lane[_f16_mf8] | + def SVFDOT_LANE_2WAY : SInst<"svdot_lane[_f16_mf8]", "dd~~i>", "h", MergeNone, "aarch64_sve_fp8_fdot_lane", [VerifyRuntimeMode], [ImmCheck<3, ImmCheck0_7>]>; | ||
} | } | ||
let SVETargetGuard = "sve2,fp8dot4", SMETargetGuard ="sme,ssve-fp8dot4" in { | let SVETargetGuard = "sve2,fp8dot4", SMETargetGuard ="sme,ssve-fp8dot4" in { | ||
// 8-bit floating-point dot product to single-precision (vectors) | // 8-bit floating-point dot product to single-precision (vectors) | ||
- def SVFDOT_4WAY : SInst<"svdot[_f32_mf8] | + def SVFDOT_4WAY : SInst<"svdot[_f32_mf8]", "dd~~>", "f", MergeNone, "aarch64_sve_fp8_fdot", [VerifyRuntimeMode]>; | ||
- def SVFDOT_N_4WAY : SInst<"svdot[_n_f32_mf8] | + def SVFDOT_N_4WAY : SInst<"svdot[_n_f32_mf8]", "dd~!>", "f", MergeNone, "aarch64_sve_fp8_fdot", [VerifyRuntimeMode]>; | ||
// 8-bit floating-point dot product to single-precision (indexed) | // 8-bit floating-point dot product to single-precision (indexed) | ||
- def SVFDOT_LANE_4WAY : SInst<"svdot_lane[_f32_mf8] | + def SVFDOT_LANE_4WAY : SInst<"svdot_lane[_f32_mf8]", "dd~~i>", "f", MergeNone, "aarch64_sve_fp8_fdot_lane", [VerifyRuntimeMode], [ImmCheck<3, ImmCheck0_3>]>; | ||
} | } | ||
let SVETargetGuard = "sve2,fp8fma", SMETargetGuard = "sme,ssve-fp8fma" in { | let SVETargetGuard = "sve2,fp8fma", SMETargetGuard = "sme,ssve-fp8fma" in { | ||
// 8-bit floating-point multiply-add long to half-precision (bottom) | // 8-bit floating-point multiply-add long to half-precision (bottom) | ||
- def SVFMLALB : SInst<"svmlalb[_f16_mf8] | + def SVFMLALB : SInst<"svmlalb[_f16_mf8]", "dd~~>", "h", MergeNone, "aarch64_sve_fp8_fmlalb", [VerifyRuntimeMode]>; | ||
- def SVFMLALB_N : SInst<"svmlalb[_n_f16_mf8] | + def SVFMLALB_N : SInst<"svmlalb[_n_f16_mf8]", "dd~!>", "h", MergeNone, "aarch64_sve_fp8_fmlalb", [VerifyRuntimeMode]>; | ||
- // 8-bit floating-point multiply-add long to | + // 8-bit floating-point multiply-add long to half-precision (bottom, indexed) | ||
- def SVFMLALB_LANE : SInst<"svmlalb_lane[_f16_mf8] | + def SVFMLALB_LANE : SInst<"svmlalb_lane[_f16_mf8]", "dd~~i>", "h", MergeNone, "aarch64_sve_fp8_fmlalb_lane", [VerifyRuntimeMode], [ImmCheck<3, ImmCheck0_15>]>; | ||
// 8-bit floating-point multiply-add long to half-precision (top) | // 8-bit floating-point multiply-add long to half-precision (top) | ||
- def SVFMLALT : SInst<"svmlalt[_f16_mf8] | + def SVFMLALT : SInst<"svmlalt[_f16_mf8]", "dd~~>", "h", MergeNone, "aarch64_sve_fp8_fmlalt", [VerifyRuntimeMode]>; | ||
- def SVFMLALT_N : SInst<"svmlalt[_n_f16_mf8] | + def SVFMLALT_N : SInst<"svmlalt[_n_f16_mf8]", "dd~!>", "h", MergeNone, "aarch64_sve_fp8_fmlalt", [VerifyRuntimeMode]>; | ||
// 8-bit floating-point multiply-add long to half-precision (top, indexed) | // 8-bit floating-point multiply-add long to half-precision (top, indexed) | ||
- def SVFMLALT_LANE : SInst<"svmlalt_lane[_f16_mf8] | + def SVFMLALT_LANE : SInst<"svmlalt_lane[_f16_mf8]", "dd~~i>", "h", MergeNone, "aarch64_sve_fp8_fmlalt_lane", [VerifyRuntimeMode], [ImmCheck<3, ImmCheck0_15>]>; | ||
// 8-bit floating-point multiply-add long long to single-precision (all top/bottom variants) | // 8-bit floating-point multiply-add long long to single-precision (all top/bottom variants) | ||
- def SVFMLALLBB : SInst<"svmlallbb[_f32_mf8] | + def SVFMLALLBB : SInst<"svmlallbb[_f32_mf8]", "dd~~>", "f", MergeNone, "aarch64_sve_fp8_fmlallbb", [VerifyRuntimeMode]>; | ||
- def SVFMLALLBB_N : SInst<"svmlallbb[_n_f32_mf8] | + def SVFMLALLBB_N : SInst<"svmlallbb[_n_f32_mf8]", "dd~!>", "f", MergeNone, "aarch64_sve_fp8_fmlallbb", [VerifyRuntimeMode]>; | ||
- def SVFMLALLBT : SInst<"svmlallbt[_f32_mf8] | + def SVFMLALLBT : SInst<"svmlallbt[_f32_mf8]", "dd~~>", "f", MergeNone, "aarch64_sve_fp8_fmlallbt", [VerifyRuntimeMode]>; | ||
- def SVFMLALLBT_N : SInst<"svmlallbt[_n_f32_mf8] | + def SVFMLALLBT_N : SInst<"svmlallbt[_n_f32_mf8]", "dd~!>", "f", MergeNone, "aarch64_sve_fp8_fmlallbt", [VerifyRuntimeMode]>; | ||
- def SVFMLALLTB : SInst<"svmlalltb[_f32_mf8] | + def SVFMLALLTB : SInst<"svmlalltb[_f32_mf8]", "dd~~>", "f", MergeNone, "aarch64_sve_fp8_fmlalltb", [VerifyRuntimeMode]>; | ||
- def SVFMLALLTB_N : SInst<"svmlalltb[_n_f32_mf8] | + def SVFMLALLTB_N : SInst<"svmlalltb[_n_f32_mf8]", "dd~!>", "f", MergeNone, "aarch64_sve_fp8_fmlalltb", [VerifyRuntimeMode]>; | ||
- def SVFMLALLTT : SInst<"svmlalltt[_f32_mf8] | + def SVFMLALLTT : SInst<"svmlalltt[_f32_mf8]", "dd~~>", "f", MergeNone, "aarch64_sve_fp8_fmlalltt", [VerifyRuntimeMode]>; | ||
- def SVFMLALLTT_N : SInst<"svmlalltt[_n_f32_mf8] | + def SVFMLALLTT_N : SInst<"svmlalltt[_n_f32_mf8]", "dd~!>", "f", MergeNone, "aarch64_sve_fp8_fmlalltt", [VerifyRuntimeMode]>; | ||
// 8-bit floating-point multiply-add long long to single-precision (indexed, all top/bottom variants) | // 8-bit floating-point multiply-add long long to single-precision (indexed, all top/bottom variants) | ||
- def SVFMLALLBB_LANE : SInst<"svmlallbb_lane[_f32_mf8] | + def SVFMLALLBB_LANE : SInst<"svmlallbb_lane[_f32_mf8]", "dd~~i>", "f", MergeNone, "aarch64_sve_fp8_fmlallbb_lane", [VerifyRuntimeMode], [ImmCheck<3, ImmCheck0_7>]>; | ||
- def SVFMLALLBT_LANE : SInst<"svmlallbt_lane[_f32_mf8] | + def SVFMLALLBT_LANE : SInst<"svmlallbt_lane[_f32_mf8]", "dd~~i>", "f", MergeNone, "aarch64_sve_fp8_fmlallbt_lane", [VerifyRuntimeMode], [ImmCheck<3, ImmCheck0_7>]>; | ||
- def SVFMLALLTB_LANE : SInst<"svmlalltb_lane[_f32_mf8] | + def SVFMLALLTB_LANE : SInst<"svmlalltb_lane[_f32_mf8]", "dd~~i>", "f", MergeNone, "aarch64_sve_fp8_fmlalltb_lane", [VerifyRuntimeMode], [ImmCheck<3, ImmCheck0_7>]>; | ||
- def SVFMLALLTT_LANE : SInst<"svmlalltt_lane[_f32_mf8] | + def SVFMLALLTT_LANE : SInst<"svmlalltt_lane[_f32_mf8]", "dd~~i>", "f", MergeNone, "aarch64_sve_fp8_fmlalltt_lane", [VerifyRuntimeMode], [ImmCheck<3, ImmCheck0_7>]>; | ||
} | } |
@@ -0,0 +1,52 @@ | |||
+//===- CIRAttrVisitor.h - Visitor for CIR attributes ------------*- 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 defines the CirAttrVisitor interface. | |||
+// | |||
+//===----------------------------------------------------------------------===// | |||
+ | |||
+#ifndef LLVM_CLANG_CIR_D | |||
+#define LLVM_CLANG_CIR_D | |||
+ | |||
+#include "clang/CIR/Dialect/IR/CIRAttrs.h" | |||
+ | |||
+namespace cir { | |||
+ | |||
+template <typename ImplClass, typename RetTy> class CirAttrVisitor { | |||
+public: | |||
+ // FIXME: Create a TableGen list to automatically handle new attributes | |||
+ RetTy visit(mlir::Attribute attr) { | |||
+ if (const auto intAttr = mlir::dyn_cast<cir::IntAttr>(attr)) | |||
+ return getImpl().visitCirIntAttr(intAttr); | |||
+ if (const auto fltAttr = mlir::dyn_cast<cir::FPAttr>(attr)) | |||
+ return getImpl().visitCirFPAttr(fltAttr); | |||
+ if (const auto ptrAttr = mlir::dyn_cast<cir::ConstPtrAttr>(attr)) | |||
+ return getImpl().visitCirConstPtr | |||
+ llvm_unreachable | |||
+ } | |||
+ | |||
+ // If the implementation chooses not to implement a certain visit | |||
+ // method, fall back to the parent. | |||
+ RetTy visitCirIntAttr(cir::IntAttr attr) { | |||
+ return getImpl().visitCirAttr(attr); | |||
+ } | |||
+ RetTy visitCirFPAttr(cir::FPAttr attr) { | |||
+ return getImpl().visitCirAttr(attr); | |||
+ } | |||
+ RetTy visitCirConstPtr | |||
+ return getImpl().visitCirAttr(attr); | |||
+ } | |||
+ | |||
+ RetTy visitCirAttr(mlir::Attribute attr) { return RetTy(); } | |||
+ | |||
+ ImplClass &getImpl() { return *static_cast<ImplClass *>(this); } | |||
+}; | |||
+ | |||
+} // namespace cir | |||
+ | |||
+#endif // LLVM_CLANG_CIR_D |
@@ -12,8 +12,6 @@ | |||
#ifndef CLANG_CIR_LOWERT | #ifndef CLANG_CIR_LOWERT | ||
#define CLANG_CIR_LOWERT | #define CLANG_CIR_LOWERT | ||
-#include "mlir/Pass/Pass.h" | |||
- | |||
#include <memory> | #include <memory> | ||
namespace llvm { | namespace llvm { |
@@ -0,0 +1,43 @@ | |||
+//===---- MissingFeatures.h - Checks for unimplemented features -*- 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 introduces some helper classes to guard against features that | |||
+// CIR dialect supports that we do not have and also do not have great ways to | |||
+// assert against. | |||
+// | |||
+//===----------------------------------------------------------------------===// | |||
+ | |||
+#ifndef CLANG_CIR_MISSIN | |||
+#define CLANG_CIR_MISSIN | |||
+ | |||
+namespace cir { | |||
+ | |||
+// As a way to track features that haven't yet been implemented this class | |||
+// explicitly contains a list of static fns that will return false that you | |||
+// can guard against. If and when a feature becomes implemented simply changing | |||
+// this return to true will cause compilation to fail at all the points in which | |||
+// we noted that we needed to address. This is a much more explicit way to | |||
+// handle "TODO"s. | |||
+struct MissingFeatures { | |||
+ // Address space related | |||
+ static bool addressSpace() { return false; } | |||
+ | |||
+ // This isn't needed until we add support for bools. | |||
+ static bool convertTypeForMe | |||
+ | |||
+ // Unhandled global/linkage information. | |||
+ static bool opGlobalDSOLocal | |||
+ static bool opGlobalThreadLo | |||
+ static bool opGlobalConstant | |||
+ static bool opGlobalAlignmen | |||
+ static bool opGlobalLinkage() { return false; } | |||
+}; | |||
+ | |||
+} // namespace cir | |||
+ | |||
+#endif // CLANG_CIR_MISSIN |
@@ -797,22 +797,14 @@ private: | |||
const ToolChain &getToolChain(const llvm::opt::ArgList &Args, | const ToolChain &getToolChain(const llvm::opt::ArgList &Args, | ||
const llvm::Triple &Target) const; | const llvm::Triple &Target) const; | ||
- /// @} | + /// Retrieves a ToolChain for a particular \p Target triple for offloading. | ||
- | |||
- /// Retrieves a ToolChain for a particular device \p Target triple | |||
- /// | |||
- /// \param[in] HostTC is the host ToolChain paired with the device | |||
- /// | |||
- /// \param[in] TargetDeviceOffl | |||
- /// an Offloading action that is optionally passed to a ToolChain (used by | |||
- /// CUDA, to specify if it's used in conjunction with OpenMP) | |||
/// | /// | ||
/// Will cache ToolChains for the life of the driver object, and create them | /// Will cache ToolChains for the life of the driver object, and create them | ||
/// on-demand. | /// on-demand. | ||
- const ToolChain | + const ToolChain &getOffloadToolChain(const llvm::opt::ArgList &Args, | ||
- const llvm::opt::ArgList &Args, const llvm::Triple &Target, | + const Action::OffloadKind Kind, | ||
- const ToolChain &HostTC, | + const llvm::Triple &Target, | ||
- const Action::OffloadKind &TargetDeviceOffl | + const llvm::Triple &AuxTarget) const; | ||
/// Get bitmasks for which option flags to include and exclude based on | /// Get bitmasks for which option flags to include and exclude based on | ||
/// the driver mode. | /// the driver mode. |
@@ -932,7 +932,9 @@ def W_Joined : Joined<["-"], "W">, Group<W_Group>, | |||
def Xanalyzer : Separate<["-"], "Xanalyzer">, | def Xanalyzer : Separate<["-"], "Xanalyzer">, | ||
HelpText<"Pass <arg> to the static analyzer">, MetaVarName<"<arg>">, | HelpText<"Pass <arg> to the static analyzer">, MetaVarName<"<arg>">, | ||
Group<StaticAnalyzer_G | Group<StaticAnalyzer_G | ||
-def Xarch__ : JoinedAndSeparate<["-"], "Xarch_">, Flags<[NoXarchOption] | +def Xarch__ : JoinedAndSeparate<["-"], "Xarch_">, Flags<[NoXarchOption]>, | ||
+ HelpText<"Pass <arg> to the compiliation if the target matches <arch>">, | |||
+ MetaVarName<"<arch> <arg>">; | |||
def Xarch_host : Separate<["-"], "Xarch_host">, Flags<[NoXarchOption]>, | def Xarch_host : Separate<["-"], "Xarch_host">, Flags<[NoXarchOption]>, | ||
HelpText<"Pass <arg> to the CUDA/HIP host compilation">, MetaVarName<"<arg>">; | HelpText<"Pass <arg> to the CUDA/HIP host compilation">, MetaVarName<"<arg>">; | ||
def Xarch_device : Separate<["-"], "Xarch_device">, Flags<[NoXarchOption]>, | def Xarch_device : Separate<["-"], "Xarch_device">, Flags<[NoXarchOption]>, | ||
@@ -1115,8 +1117,8 @@ def fno_convergent_f | |||
// Common offloading options | // Common offloading options | ||
let Group = offload_Group in { | let Group = offload_Group in { | ||
-def offload_arch_EQ : Joined<["--"], "offload-arch=">, | +def offload_arch_EQ : Joined<["--"], "offload-arch=">, | ||
- Visibility<[ClangOption, FlangOption]>, | + Visibility<[ClangOption, FlangOption]>, Flags<[NoXarchOption]>, | ||
HelpText<"Specify an offloading device architecture for CUDA, HIP, or OpenMP. (e.g. sm_35). " | HelpText<"Specify an offloading device architecture for CUDA, HIP, or OpenMP. (e.g. sm_35). " | ||
"If 'native' is used the compiler will detect locally installed architectures. " | "If 'native' is used the compiler will detect locally installed architectures. " | ||
"For HIP offloading, the device architecture can be followed by target ID features " | "For HIP offloading, the device architecture can be followed by target ID features " | ||
@@ -1793,6 +1795,11 @@ def fprofile_update_ | |||
Values<"atomic,prefer-atomic,single">, | Values<"atomic,prefer-atomic,single">, | ||
MetaVarName<"<method>">, HelpText<"Set update method of profile counters">, | MetaVarName<"<method>">, HelpText<"Set update method of profile counters">, | ||
MarshallingInfoF | MarshallingInfoF | ||
+def fprofile_continu | |||
+ Group<f_Group>, Visibility<[ClangOption, CC1Option]>, | |||
+ HelpText<"Enable continuous instrumentation profiling mode">, | |||
+ MarshallingInfoF | |||
+ | |||
defm pseudo_probe_for | defm pseudo_probe_for | ||
CodeGenOpts<"PseudoProbeForPr | CodeGenOpts<"PseudoProbeForPr | ||
PosFlag<SetTrue, [], [ClangOption], "Emit">, | PosFlag<SetTrue, [], [ClangOption], "Emit">, | ||
@@ -2524,6 +2531,10 @@ defm sanitize_cfi_can | |||
"Do not make">, | "Do not make">, | ||
BothFlags<[], [ClangOption], " the jump table addresses canonical in the symbol table">>, | BothFlags<[], [ClangOption], " the jump table addresses canonical in the symbol table">>, | ||
Group<f_clang_Group>; | Group<f_clang_Group>; | ||
+def fsanitize_kcfi_a | |||
+ Group<f_clang_Group>, | |||
+ HelpText<"Embed function arity information into the KCFI patchable function prefix">, | |||
+ MarshallingInfoF | |||
defm sanitize_stats : BoolOption<"f", "sanitize-stats", | defm sanitize_stats : BoolOption<"f", "sanitize-stats", | ||
CodeGenOpts<"SanitizeStats">, DefaultFalse, | CodeGenOpts<"SanitizeStats">, DefaultFalse, | ||
PosFlag<SetTrue, [], [ClangOption], "Enable">, | PosFlag<SetTrue, [], [ClangOption], "Enable">, | ||
@@ -3410,8 +3421,6 @@ def fno_strict_alias | |||
def fstruct_path_tba | def fstruct_path_tba | ||
def fno_struct_path_ | def fno_struct_path_ | ||
def fno_strict_enums | def fno_strict_enums | ||
-def fno_strict_overf | |||
- Visibility<[ClangOption, FlangOption]>; | |||
defm init_global_zero | defm init_global_zero | ||
PosFlag<SetTrue, [], [FlangOption, FC1Option], | PosFlag<SetTrue, [], [FlangOption, FC1Option], | ||
"Zero initialize globals without default initialization (default)">, | "Zero initialize globals without default initialization (default)">, | ||
@@ -3923,7 +3932,9 @@ defm strict_vtable_po | |||
" overwriting polymorphic C++ objects">, | " overwriting polymorphic C++ objects">, | ||
NegFlag<SetFalse>>; | NegFlag<SetFalse>>; | ||
def fstrict_overflow | def fstrict_overflow | ||
- Visibility<[ClangOption, FlangOption]>; | + Visibility<[ClangOption, CLOption, FlangOption]>; | ||
+def fno_strict_overf | |||
+ Visibility<[ClangOption, CLOption, FlangOption]>; | |||
def fpointer_tbaa : Flag<["-"], "fpointer-tbaa">, Group<f_Group>; | def fpointer_tbaa : Flag<["-"], "fpointer-tbaa">, Group<f_Group>; | ||
def fdriver_only : Flag<["-"], "fdriver-only">, Flags<[NoXarchOption]>, | def fdriver_only : Flag<["-"], "fdriver-only">, Flags<[NoXarchOption]>, | ||
Visibility<[ClangOption, CLOption, DXCOption]>, | Visibility<[ClangOption, CLOption, DXCOption]>, | ||
@@ -4063,6 +4074,10 @@ def ftrap_function_E | |||
Visibility<[ClangOption, CC1Option]>, | Visibility<[ClangOption, CC1Option]>, | ||
HelpText<"Issue call to specified function rather than a trap instruction">, | HelpText<"Issue call to specified function rather than a trap instruction">, | ||
MarshallingInfoS | MarshallingInfoS | ||
+def floop_interchang | |||
+ HelpText<"Enable the loop interchange pass">, Visibility<[ClangOption, CC1Option]>; | |||
+def fno_loop_interch | |||
+ HelpText<"Disable the loop interchange pass">, Visibility<[ClangOption, CC1Option]>; | |||
def funroll_loops : Flag<["-"], "funroll-loops">, Group<f_Group>, | def funroll_loops : Flag<["-"], "funroll-loops">, Group<f_Group>, | ||
HelpText<"Turn on loop unroller">, Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>; | HelpText<"Turn on loop unroller">, Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>; | ||
def fno_unroll_loops | def fno_unroll_loops | ||
@@ -5825,6 +5840,9 @@ def start_no_unused_ | |||
HelpText<"Don't emit warnings about unused arguments for the following arguments">; | HelpText<"Don't emit warnings about unused arguments for the following arguments">; | ||
def static_libgcc : Flag<["-"], "static-libgcc">; | def static_libgcc : Flag<["-"], "static-libgcc">; | ||
def static_libstdcxx | def static_libstdcxx | ||
+def static_libclosur | |||
+ Visibility<[ClangOption, CC1Option]>, | |||
+ HelpText<"Generate code for statically linking libclosure (BlocksRuntime)">; | |||
def static : Flag<["-", "--"], "static">, Group<Link_Group>, | def static : Flag<["-", "--"], "static">, Group<Link_Group>, | ||
Visibility<[ClangOption, FlangOption]>, | Visibility<[ClangOption, FlangOption]>, | ||
Flags<[NoArgumentUnused | Flags<[NoArgumentUnused | ||
@@ -6876,6 +6894,7 @@ defm backslash : OptInFC1FFlag<"b | |||
defm xor_operator : OptInFC1FFlag<"xor-operator", "Enable .XOR. as a synonym of .NEQV.">; | defm xor_operator : OptInFC1FFlag<"xor-operator", "Enable .XOR. as a synonym of .NEQV.">; | ||
defm logical_abbrevia | defm logical_abbrevia | ||
defm implicit_none : OptInFC1FFlag<"implicit-none", "No implicit typing allowed unless overridden by IMPLICIT statements">; | defm implicit_none : OptInFC1FFlag<"implicit-none", "No implicit typing allowed unless overridden by IMPLICIT statements">; | ||
+defm implicit_none_ex | |||
defm underscoring : OptInFC1FFlag<"underscoring", "Appends one trailing underscore to external names">; | defm underscoring : OptInFC1FFlag<"underscoring", "Appends one trailing underscore to external names">; | ||
defm ppc_native_vec_e | defm ppc_native_vec_e | ||
PosFlag<SetTrue, [], [ClangOption], "Specifies PowerPC native vector element order (default)">, | PosFlag<SetTrue, [], [ClangOption], "Specifies PowerPC native vector element order (default)">, |
@@ -43,6 +43,7 @@ class SanitizerArgs { | |||
bool CfiICallGenerali | bool CfiICallGenerali | ||
bool CfiICallNormaliz | bool CfiICallNormaliz | ||
bool CfiCanonicalJump | bool CfiCanonicalJump | ||
+ bool KcfiArity = false; | |||
int AsanFieldPadding | int AsanFieldPadding | ||
bool SharedRuntime = false; | bool SharedRuntime = false; | ||
bool StableABI = false; | bool StableABI = false; |
@@ -1146,11 +1146,29 @@ bool ExtractAPIVisito | |||
StringRef Name = Decl->getName(); | StringRef Name = Decl->getName(); | ||
+ auto nameMatches = [&Name](TagDecl *TagDecl) { | |||
+ StringRef TagName = TagDecl->getName(); | |||
+ | |||
+ if (TagName == Name) | |||
+ return true; | |||
+ | |||
+ // Also check whether the tag decl's name is the same as the typedef name | |||
+ // with prefixed underscores | |||
+ if (TagName.starts_with('_')) { | |||
+ StringRef StrippedName = TagName.ltrim('_'); | |||
+ | |||
+ if (StrippedName == Name) | |||
+ return true; | |||
+ } | |||
+ | |||
+ return false; | |||
+ }; | |||
+ | |||
// If the underlying type was defined as part of the typedef modify it's | // If the underlying type was defined as part of the typedef modify it's | ||
// fragments directly and pretend the typedef doesn't exist. | // fragments directly and pretend the typedef doesn't exist. | ||
if (auto *TagDecl = Decl->getUnderlyingTyp | if (auto *TagDecl = Decl->getUnderlyingTyp | ||
if (TagDecl->isEmbeddedInDecl | if (TagDecl->isEmbeddedInDecl | ||
- Decl->getName() == TagDecl->getName()) { | + nameMatches(TagDecl)) { | ||
SmallString<128> TagUSR; | SmallString<128> TagUSR; | ||
index::generateUSRForDe | index::generateUSRForDe | ||
if (auto *Record = API.findRecordForUSR | if (auto *Record = API.findRecordForUSR | ||
@@ -1164,6 +1182,11 @@ bool ExtractAPIVisito | |||
.append(Name, DeclarationFragm | .append(Name, DeclarationFragm | ||
.appendSemicolon(); | .appendSemicolon(); | ||
+ // Replace the name and subheading in case it's underscored so we can | |||
+ // use the non-underscored version | |||
+ Record->Name = Name; | |||
+ Record->SubHeading = DeclarationFragm | |||
+ | |||
return true; | return true; | ||
} | } | ||
} | } |
@@ -1212,6 +1212,22 @@ struct FormatStyle { | |||
/// \version 3.7 | /// \version 3.7 | ||
bool BinPackArguments | bool BinPackArguments | ||
+ /// If ``BinPackLongBrace | |||
+ /// ``BinPackArguments | |||
+ /// initializer list. | |||
+ /// \code | |||
+ /// BinPackLongBrace | |||
+ /// vector<int> x{ vector<int> x{1, 2, ..., | |||
+ /// 20, 21}; | |||
+ /// 1, | |||
+ /// 2, | |||
+ /// ..., | |||
+ /// 20, | |||
+ /// 21}; | |||
+ /// \endcode | |||
+ /// \version 21 | |||
+ bool BinPackLongBrace | |||
+ | |||
/// Different way to try to fit all parameters on a line. | /// Different way to try to fit all parameters on a line. | ||
enum BinPackParameter | enum BinPackParameter | ||
/// Bin-pack parameters. | /// Bin-pack parameters. | ||
@@ -2252,6 +2268,33 @@ struct FormatStyle { | |||
/// \version 16 | /// \version 16 | ||
BreakBeforeInlin | BreakBeforeInlin | ||
+ /// If ``true``, break before a template closing bracket (``>``) when there is | |||
+ /// a line break after the matching opening bracket (``<``). | |||
+ /// \code | |||
+ /// true: | |||
+ /// template <typename Foo, typename Bar> | |||
+ /// | |||
+ /// template <typename Foo, | |||
+ /// typename Bar> | |||
+ /// | |||
+ /// template < | |||
+ /// typename Foo, | |||
+ /// typename Bar | |||
+ /// > | |||
+ /// | |||
+ /// false: | |||
+ /// template <typename Foo, typename Bar> | |||
+ /// | |||
+ /// template <typename Foo, | |||
+ /// typename Bar> | |||
+ /// | |||
+ /// template < | |||
+ /// typename Foo, | |||
+ /// typename Bar> | |||
+ /// \endcode | |||
+ /// \version 21 | |||
+ bool BreakBeforeTempl | |||
+ | |||
/// If ``true``, ternary operators will be placed after line breaks. | /// If ``true``, ternary operators will be placed after line breaks. | ||
/// \code | /// \code | ||
/// true: | /// true: | ||
@@ -5239,6 +5282,7 @@ struct FormatStyle { | |||
R.AlwaysBreakBefor | R.AlwaysBreakBefor | ||
AttributeMacros == R.AttributeMacros && | AttributeMacros == R.AttributeMacros && | ||
BinPackArguments | BinPackArguments | ||
+ BinPackLongBrace | |||
BinPackParameter | BinPackParameter | ||
BitFieldColonSpa | BitFieldColonSpa | ||
BracedInitialize | BracedInitialize | ||
@@ -5251,6 +5295,7 @@ struct FormatStyle { | |||
BreakBeforeBrace | BreakBeforeBrace | ||
BreakBeforeConce | BreakBeforeConce | ||
BreakBeforeInlin | BreakBeforeInlin | ||
+ BreakBeforeTempl | |||
BreakBeforeTerna | BreakBeforeTerna | ||
BreakBinaryOpera | BreakBinaryOpera | ||
BreakConstructor | BreakConstructor |
@@ -933,7 +933,7 @@ private: | |||
} | } | ||
ArrayRef<ModuleMacro*> getOverriddenMac | ArrayRef<ModuleMacro*> getOverriddenMac | ||
- if (auto *Info = | + if (auto *Info = dyn_cast_if_present<ModuleMacroInfo *>(State)) | ||
return Info->OverriddenMacros | return Info->OverriddenMacros | ||
return {}; | return {}; | ||
} | } |
@@ -3710,6 +3710,7 @@ private: | |||
SourceLocation RParenLoc; | SourceLocation RParenLoc; | ||
SourceLocation EndLoc; | SourceLocation EndLoc; | ||
SourceLocation MiscLoc; | SourceLocation MiscLoc; | ||
+ OpenACCAtomicKin | |||
SmallVector<Expr *> Exprs; | SmallVector<Expr *> Exprs; | ||
SmallVector<OpenACCClause *> Clauses; | SmallVector<OpenACCClause *> Clauses; | ||
// TODO OpenACC: As we implement support for the Atomic, Routine, and Cache | // TODO OpenACC: As we implement support for the Atomic, Routine, and Cache |
@@ -933,7 +933,7 @@ class Sema; | |||
/// Have we matched any packs on the parameter side, versus any non-packs on | /// Have we matched any packs on the parameter side, versus any non-packs on | ||
/// the argument side, in a context where the opposite matching is also | /// the argument side, in a context where the opposite matching is also | ||
/// allowed? | /// allowed? | ||
- bool | + bool StrictPackMatch : 1; | ||
/// True if the candidate was found using ADL. | /// True if the candidate was found using ADL. | ||
LLVM_PREFERRED_T | LLVM_PREFERRED_T | ||
@@ -1010,8 +1010,7 @@ class Sema; | |||
friend class OverloadCandidat | friend class OverloadCandidat | ||
OverloadCandidat | OverloadCandidat | ||
: IsSurrogate(false), IgnoreObjectArgu | : IsSurrogate(false), IgnoreObjectArgu | ||
- TookAddressOfOverload(false), | + TookAddressOfOverload(false), StrictPackMatch(false), | ||
- HasMatchedPackOn | |||
IsADLCandidate(llvm::to_underlying(CallExpr::NotADL)), | IsADLCandidate(llvm::to_underlying(CallExpr::NotADL)), | ||
RewriteKind(CRK_None) {} | RewriteKind(CRK_None) {} | ||
}; | }; |
@@ -3664,6 +3664,12 @@ public: | |||
NonTrivialCUnion | NonTrivialCUnion | ||
unsigned NonTrivialKind); | unsigned NonTrivialKind); | ||
+ /// Certain globally-unique variables might be accidentally duplicated if | |||
+ /// built into multiple shared libraries with hidden visibility. This can | |||
+ /// cause problems if the variable is mutable, its initialization is | |||
+ /// effectful, or its address is taken. | |||
+ bool GloballyUniqueOb | |||
+ | |||
/// AddInitializerTo | /// AddInitializerTo | ||
/// declaration dcl. If DirectInit is true, this is C++ direct | /// declaration dcl. If DirectInit is true, this is C++ direct | ||
/// initialization rather than copy initialization. | /// initialization rather than copy initialization. | ||
@@ -10174,18 +10180,15 @@ public: | |||
/// \param PartialOverloadi | /// \param PartialOverloadi | ||
/// based on an incomplete set of function arguments. This feature is used by | /// based on an incomplete set of function arguments. This feature is used by | ||
/// code completion. | /// code completion. | ||
- void AddOverloadCandidate( | + void AddOverloadCandidate( | ||
- ArrayRef<Expr *> Args, | + FunctionDecl *Function, DeclAccessPair FoundDecl, ArrayRef<Expr *> Args, | ||
- OverloadCandidat | + OverloadCandidat | ||
- bool SuppressUserConv | + bool PartialOverloadi | ||
- bool PartialOverloadi | + bool AllowExplicitCon | ||
- bool AllowExplicit = true, | + ADLCallKind IsADLCandidate = ADLCallKind::NotADL, | ||
- bool AllowExplicitCon | + ConversionSequen | ||
- ADLCallKind IsADLCandidate = ADLCallKind::NotADL, | + OverloadCandidat | ||
- ConversionSequen | + bool AggregateCandida | ||
- OverloadCandidat | |||
- bool AggregateCandida | |||
- bool HasMatchedPackOn | |||
/// Add all of the function declarations in the given function set to | /// Add all of the function declarations in the given function set to | ||
/// the overload candidate set. | /// the overload candidate set. | ||
@@ -10221,7 +10224,7 @@ public: | |||
bool PartialOverloadi | bool PartialOverloadi | ||
ConversionSequen | ConversionSequen | ||
OverloadCandidat | OverloadCandidat | ||
- bool | + bool StrictPackMatch = false); | ||
/// Add a C++ member function template as a candidate to the candidate | /// Add a C++ member function template as a candidate to the candidate | ||
/// set, using template argument deduction to produce an appropriate member | /// set, using template argument deduction to produce an appropriate member | ||
@@ -10268,7 +10271,7 @@ public: | |||
CXXRecordDecl *ActingContext, Expr *From, QualType ToType, | CXXRecordDecl *ActingContext, Expr *From, QualType ToType, | ||
OverloadCandidat | OverloadCandidat | ||
bool AllowExplicit, bool AllowResultConve | bool AllowExplicit, bool AllowResultConve | ||
- bool | + bool StrictPackMatch = false); | ||
/// Adds a conversion function template specialization | /// Adds a conversion function template specialization | ||
/// candidate to the overload set, using template argument deduction | /// candidate to the overload set, using template argument deduction | ||
@@ -11688,7 +11691,7 @@ public: | |||
/// Is set to true when, in the context of TTP matching, a pack parameter | /// Is set to true when, in the context of TTP matching, a pack parameter | ||
/// matches non-pack arguments. | /// matches non-pack arguments. | ||
- bool | + bool StrictPackMatch = false; | ||
}; | }; | ||
/// Check that the given template argument corresponds to the given | /// Check that the given template argument corresponds to the given | ||
@@ -11797,7 +11800,7 @@ public: | |||
TemplateParamete | TemplateParamete | ||
TemplateArgument | TemplateArgument | ||
bool PartialOrdering, | bool PartialOrdering, | ||
- bool * | + bool *StrictPackMatch); | ||
void NoteTemplateLoca | void NoteTemplateLoca | ||
std::optional<SourceRange> ParamRange = {}); | std::optional<SourceRange> ParamRange = {}); | ||
@@ -12491,7 +12494,7 @@ public: | |||
bool isTemplateTempla | bool isTemplateTempla | ||
TemplateParamete | TemplateParamete | ||
const DefaultArguments | const DefaultArguments | ||
- bool PartialOrdering, bool * | + bool PartialOrdering, bool *StrictPackMatch); | ||
/// Mark which template parameters are used in a given expression. | /// Mark which template parameters are used in a given expression. | ||
/// | /// | ||
@@ -13493,8 +13496,8 @@ public: | |||
bool InstantiateClass | bool InstantiateClass | ||
SourceLocation PointOfInstantia | SourceLocation PointOfInstantia | ||
ClassTemplateSpe | ClassTemplateSpe | ||
- TemplateSpecializationKind TSK, bool Complain | + TemplateSpecializationKind TSK, bool Complain, | ||
- bool | + bool PrimaryStrictPackMatch); | ||
/// Instantiates the definitions of all of the member | /// Instantiates the definitions of all of the member | ||
/// of the given class, which is an instantiation of a class template | /// of the given class, which is an instantiation of a class template |
@@ -141,6 +141,9 @@ public: | |||
// Diagnose whether the input ID is uint/unit2/uint3 type. | // Diagnose whether the input ID is uint/unit2/uint3 type. | ||
bool diagnoseInputIDT | bool diagnoseInputIDT | ||
+ bool CanPerformScalar | |||
+ bool ContainsBitField | |||
+ bool CanPerformElemen | |||
ExprResult ActOnOutParamExp | ExprResult ActOnOutParamExp | ||
QualType getInoutParamete | QualType getInoutParamete | ||
@@ -160,9 +163,9 @@ private: | |||
ResourceBindings | ResourceBindings | ||
private: | private: | ||
- void | + void collectResourceBindingsOnVarDecl(VarDecl *D); | ||
- void | + void collectResourceBindingsOnUserRecordDecl(const VarDecl *VD, | ||
- | + const RecordType *RT); | ||
void processExplicitB | void processExplicitB | ||
}; | }; | ||
@@ -695,24 +695,53 @@ public: | |||
/// should check legality of the statement as it appertains to this Construct. | /// should check legality of the statement as it appertains to this Construct. | ||
StmtResult ActOnAssociatedS | StmtResult ActOnAssociatedS | ||
OpenACCDirective | OpenACCDirective | ||
+ OpenACCAtomicKin | |||
ArrayRef<const OpenACCClause *> Clauses, | ArrayRef<const OpenACCClause *> Clauses, | ||
StmtResult AssocStmt); | StmtResult AssocStmt); | ||
+ StmtResult ActOnAssociatedS | |||
+ OpenACCDirective | |||
+ ArrayRef<const OpenACCClause *> Clauses, | |||
+ StmtResult AssocStmt) { | |||
+ return ActOnAssociatedS | |||
+ Clauses, AssocStmt); | |||
+ } | |||
+ /// Called to check the form of the `atomic` construct which has some fairly | |||
+ /// sizable restrictions. | |||
+ StmtResult CheckAtomicAssoc | |||
+ OpenACCAtomicKin | |||
+ StmtResult AssocStmt); | |||
+ | |||
/// Called after the directive has been completely parsed, including the | /// Called after the directive has been completely parsed, including the | ||
/// declaration group or associated statement. | /// declaration group or associated statement. | ||
+ /// DirLoc: Location of the actual directive keyword. | |||
/// LParenLoc: Location of the left paren, if it exists (not on all | /// LParenLoc: Location of the left paren, if it exists (not on all | ||
/// constructs). | /// constructs). | ||
/// MiscLoc: First misc location, if necessary (not all constructs). | /// MiscLoc: First misc location, if necessary (not all constructs). | ||
/// Exprs: List of expressions on the construct itself, if necessary (not all | /// Exprs: List of expressions on the construct itself, if necessary (not all | ||
/// constructs). | /// constructs). | ||
+ /// AK: The atomic kind of the directive, if necessary (atomic only) | |||
/// RParenLoc: Location of the right paren, if it exists (not on all | /// RParenLoc: Location of the right paren, if it exists (not on all | ||
/// constructs). | /// constructs). | ||
+ /// EndLoc: The last source location of the driective. | |||
+ /// Clauses: The list of clauses for the directive, if present. | |||
+ /// AssocStmt: The associated statement for this construct, if necessary. | |||
StmtResult ActOnEndStmtDire | StmtResult ActOnEndStmtDire | ||
OpenACCDirective | OpenACCDirective | ||
SourceLocation LParenLoc, SourceLocation MiscLoc, ArrayRef<Expr *> Exprs, | SourceLocation LParenLoc, SourceLocation MiscLoc, ArrayRef<Expr *> Exprs, | ||
- SourceLocation RParenLoc, SourceLocation EndLoc, | + OpenACCAtomicKind AK, SourceLocation RParenLoc, SourceLocation EndLoc, | ||
ArrayRef<OpenACCClause *> Clauses, StmtResult AssocStmt); | ArrayRef<OpenACCClause *> Clauses, StmtResult AssocStmt); | ||
+ StmtResult ActOnEndStmtDire | |||
+ OpenACCDirective | |||
+ SourceLocation LParenLoc, SourceLocation MiscLoc, ArrayRef<Expr *> Exprs, | |||
+ SourceLocation RParenLoc, SourceLocation EndLoc, | |||
+ ArrayRef<OpenACCClause *> Clauses, StmtResult AssocStmt) { | |||
+ return ActOnEndStmtDire | |||
+ OpenACCAtomicKin | |||
+ Clauses, AssocStmt); | |||
+ } | |||
+ | |||
/// Called after the directive has been completely parsed, including the | /// Called after the directive has been completely parsed, including the | ||
/// declaration group or associated statement. | /// declaration group or associated statement. | ||
DeclGroupRef ActOnEndDeclDire | DeclGroupRef ActOnEndDeclDire |
@@ -849,6 +849,9 @@ public: | |||
ArrayRef<OMPInteropInfo> AppendArgs, SourceLocation AdjustArgsLoc, | ArrayRef<OMPInteropInfo> AppendArgs, SourceLocation AdjustArgsLoc, | ||
SourceLocation AppendArgsLoc, SourceRange SR); | SourceLocation AppendArgsLoc, SourceRange SR); | ||
+ /// Called on device_num selector in context selectors. | |||
+ void ActOnOpenMPDevic | |||
+ | |||
OMPClause *ActOnOpenMPSingl | OMPClause *ActOnOpenMPSingl | ||
SourceLocation StartLoc, | SourceLocation StartLoc, | ||
SourceLocation LParenLoc, | SourceLocation LParenLoc, | ||
@@ -1410,6 +1413,13 @@ public: | |||
void handleOMPAssumeA | void handleOMPAssumeA | ||
+ /// Setter and getter functions for device_num. | |||
+ void setOpenMPDeviceN | |||
+ | |||
+ int getOpenMPDeviceN | |||
+ | |||
+ void setOpenMPDeviceN | |||
+ | |||
private: | private: | ||
void *VarDataSharingAt | void *VarDataSharingAt | ||
@@ -1480,6 +1490,12 @@ private: | |||
/// All `omp assumes` we encountered so far. | /// All `omp assumes` we encountered so far. | ||
SmallVector<OMPAssumeAttr *, 4> OMPAssumeGlobal; | SmallVector<OMPAssumeAttr *, 4> OMPAssumeGlobal; | ||
+ | |||
+ /// Device number specified by the context selector. | |||
+ int DeviceNum = -1; | |||
+ | |||
+ /// Device number identifier specified by the context selector. | |||
+ StringRef DeviceNumID; | |||
}; | }; | ||
} // namespace clang | } // namespace clang |
@@ -54,7 +54,7 @@ class TemplateDeductio | |||
/// Have we matched any packs on the parameter side, versus any non-packs on | /// Have we matched any packs on the parameter side, versus any non-packs on | ||
/// the argument side, in a context where the opposite matching is also | /// the argument side, in a context where the opposite matching is also | ||
/// allowed? | /// allowed? | ||
- bool MatchedPackOnPar | + bool StrictPackMatch = false; | ||
/// The template parameter depth for which we're performing deduction. | /// The template parameter depth for which we're performing deduction. | ||
unsigned DeducedDepth; | unsigned DeducedDepth; | ||
@@ -92,13 +92,9 @@ public: | |||
return DeducedDepth; | return DeducedDepth; | ||
} | } | ||
- bool hasMatchedPackOn | + bool hasStrictPackMat | ||
- return MatchedPackOnPar | |||
- } | |||
- void setMatchedPackOn | + void setStrictPackMat | ||
- MatchedPackOnPar | |||
- } | |||
/// Get the number of explicitly-specified arguments. | /// Get the number of explicitly-specified arguments. | ||
unsigned getNumExplicitAr | unsigned getNumExplicitAr |
@@ -2045,6 +2045,7 @@ enum StmtCode { | |||
STMT_OPENACC_SHU | STMT_OPENACC_SHU | ||
STMT_OPENACC_SET | STMT_OPENACC_SET | ||
STMT_OPENACC_UPD | STMT_OPENACC_UPD | ||
+ STMT_OPENACC_ATO | |||
// HLSL Constructs | // HLSL Constructs | ||
EXPR_HLSL_OUT_AR | EXPR_HLSL_OUT_AR |
@@ -989,30 +989,41 @@ def decodeValueOfObj | |||
let ParentPackage = Security in { | let ParentPackage = Security in { | ||
-def FloatLoopCounter | + def ArrayBoundChecke | ||
- HelpText<"Warn on using a floating point value as a loop counter (CERT: " | + HelpText<"Warn about out of bounds access to memory">, | ||
- "FLP30-C, FLP30-CPP)">, | + Documentation<HasDocumentation | ||
- Dependencies<[SecuritySyntaxCh | + | ||
- Documentation<HasDocumentation | + def FloatLoopCounter | ||
- | + : Checker<"FloatLoopCounter | ||
-def MmapWriteExecChe | + HelpText< | ||
- HelpText<"Warn on mmap() calls with both writable and executable access">, | + "Warn on using a floating point value as a loop counter (CERT: " | ||
- Documentation<HasDocumentation | + "FLP30-C, FLP30-CPP)">, | ||
- | + Dependencies<[SecuritySyntaxCh | ||
-def PointerSubChecke | + Documentation<HasDocumentation | ||
- HelpText<"Check for pointer subtractions on two pointers pointing to " | + | ||
- "different memory chunks">, | + def MmapWriteExecChe | ||
- Documentation<HasDocumentation | + : Checker<"MmapWriteExec">, | ||
- | + HelpText< | ||
-def PutenvStackArray | + "Warn on mmap() calls with both writable and executable access">, | ||
- HelpText<"Finds calls to the function 'putenv' which pass a pointer to " | + Documentation<HasDocumentation | ||
- "an automatic (stack-allocated) array as the argument.">, | + | ||
- Documentation<HasDocumentation | + def PointerSubChecke | ||
- | + : Checker<"PointerSub">, | ||
-def SetgidSetuidOrde | + HelpText<"Check for pointer subtractions on two pointers pointing to " | ||
- HelpText<"Warn on possible reversed order of 'setgid(getgid()))' and " | + "different memory chunks">, | ||
- "'setuid(getuid())' (CERT: POS36-C)">, | + Documentation<HasDocumentation | ||
- Documentation<HasDocumentation | + | ||
+ def PutenvStackArray | |||
+ : Checker<"PutenvStackArray | |||
+ HelpText<"Finds calls to the function 'putenv' which pass a pointer to " | |||
+ "an automatic (stack-allocated) array as the argument.">, | |||
+ Documentation<HasDocumentation | |||
+ | |||
+ def SetgidSetuidOrde | |||
+ : Checker<"SetgidSetuidOrde | |||
+ HelpText<"Warn on possible reversed order of 'setgid(getgid()))' and " | |||
+ "'setuid(getuid())' (CERT: POS36-C)">, | |||
+ Documentation<HasDocumentation | |||
} // end "security" | } // end "security" | ||
@@ -1035,14 +1046,6 @@ let ParentPackage = ENV in { | |||
let ParentPackage = SecurityAlpha in { | let ParentPackage = SecurityAlpha in { | ||
-def ArrayBoundChecke | |||
- HelpText<"Warn about buffer overflows (older checker)">, | |||
- Documentation<HasDocumentation | |||
- | |||
-def ArrayBoundChecke | |||
- HelpText<"Warn about buffer overflows (newer checker)">, | |||
- Documentation<HasDocumentation | |||
- | |||
def ReturnPointerRan | def ReturnPointerRan | ||
HelpText<"Check for an out-of-bound pointer being returned to callers">, | HelpText<"Check for an out-of-bound pointer being returned to callers">, | ||
Documentation<HasDocumentation | Documentation<HasDocumentation |
@@ -35,7 +35,7 @@ public: | |||
/// Match calls to functions from the C standard library. This also | /// Match calls to functions from the C standard library. This also | ||
/// recognizes builtin variants whose name is derived by adding | /// recognizes builtin variants whose name is derived by adding | ||
/// "__builtin", "__inline" or similar prefixes or suffixes; but only | /// "__builtin", "__inline" or similar prefixes or suffixes; but only | ||
- /// matches functions | + /// matches functions that are externally visible and are declared either | ||
/// directly within a TU or in the namespace 'std'. | /// directly within a TU or in the namespace 'std'. | ||
/// For the exact heuristics, see CheckerContext::isCLibraryFuncti | /// For the exact heuristics, see CheckerContext::isCLibraryFuncti | ||
CLibrary, | CLibrary, | ||
@@ -152,7 +152,7 @@ public: | |||
/// exists only when that is not available, for example, when _only_ | /// exists only when that is not available, for example, when _only_ | ||
/// syntactic check is done on a piece of code. | /// syntactic check is done on a piece of code. | ||
/// | /// | ||
- /// Also, StdLibraryFunctionsChecker::Signature is likely a better | + /// Also, StdLibraryFunctionsChecker::Signature is likely a better candidate | ||
/// for syntactic only matching if you are writing a new checker. This is | /// for syntactic only matching if you are writing a new checker. This is | ||
/// handy if a CallDescriptionM | /// handy if a CallDescriptionM | ||
/// | /// | ||
@@ -233,7 +233,7 @@ public: | |||
/// exists only when that is not available, for example, when _only_ | /// exists only when that is not available, for example, when _only_ | ||
/// syntactic check is done on a piece of code. | /// syntactic check is done on a piece of code. | ||
/// | /// | ||
- /// Also, StdLibraryFunctionsChecker::Signature is likely a better | + /// Also, StdLibraryFunctionsChecker::Signature is likely a better candidate | ||
/// for syntactic only matching if you are writing a new checker. This is | /// for syntactic only matching if you are writing a new checker. This is | ||
/// handy if a CallDescriptionM | /// handy if a CallDescriptionM | ||
/// | /// | ||
@@ -274,7 +274,7 @@ public: | |||
/// exists only when that is not available, for example, when _only_ | /// exists only when that is not available, for example, when _only_ | ||
/// syntactic check is done on a piece of code. | /// syntactic check is done on a piece of code. | ||
/// | /// | ||
- /// Also, StdLibraryFunctionsChecker::Signature is likely a better | + /// Also, StdLibraryFunctionsChecker::Signature is likely a better candidate | ||
/// for syntactic only matching if you are writing a new checker. This is | /// for syntactic only matching if you are writing a new checker. This is | ||
/// handy if a CallDescriptionM | /// handy if a CallDescriptionM | ||
/// | /// |
@@ -344,7 +344,7 @@ public: | |||
}; | }; | ||
/// The region containing globals which can be modified by calls to | /// The region containing globals which can be modified by calls to | ||
-/// "internally" defined functions - (for now just) functions other | +/// "internally" defined functions - (for now just) functions other than system | ||
/// calls. | /// calls. | ||
class GlobalInternalSp | class GlobalInternalSp | ||
friend class MemRegionManager | friend class MemRegionManager | ||
@@ -1021,7 +1021,7 @@ public: | |||
} | } | ||
}; | }; | ||
-/// ParamVarRegion - Represents a region for | +/// ParamVarRegion - Represents a region for parameters. Only parameters of the | ||
/// function in the current stack frame are represented as `ParamVarRegion`s. | /// function in the current stack frame are represented as `ParamVarRegion`s. | ||
/// Parameters of top-level analyzed functions as well as captured paremeters | /// Parameters of top-level analyzed functions as well as captured paremeters | ||
/// by lambdas and blocks are repesented as `VarRegion`s. | /// by lambdas and blocks are repesented as `VarRegion`s. |
@@ -55,15 +55,18 @@ enum class ScanningOptimiza | |||
HeaderSearch = 1, | HeaderSearch = 1, | ||
/// Remove warnings from system modules. | /// Remove warnings from system modules. | ||
- SystemWarnings = | + SystemWarnings = (1 << 1), | ||
/// Remove unused -ivfsoverlay arguments. | /// Remove unused -ivfsoverlay arguments. | ||
- VFS = | + VFS = (1 << 2), | ||
/// Canonicalize -D and -U options. | /// Canonicalize -D and -U options. | ||
- Macros = | + Macros = (1 << 3), | ||
- DSS_LAST_BITMASK | + /// Ignore the compiler's working directory if it is safe. | ||
+ IgnoreCWD = (1 << 4), | |||
+ | |||
+ DSS_LAST_BITMASK | |||
Default = All | Default = All | ||
}; | }; | ||
@@ -128,14 +128,17 @@ public: | |||
/// \param LookupModuleOutp | /// \param LookupModuleOutp | ||
/// "-fmodule-file=", "-o" and other output | /// "-fmodule-file=", "-o" and other output | ||
/// arguments for dependencies. | /// arguments for dependencies. | ||
+ /// \param TUBuffer Optional memory buffer for translation unit input. If | |||
+ /// TUBuffer is nullopt, the input should be included in the | |||
+ /// Commandline already. | |||
/// | /// | ||
/// \returns a \c StringError with the diagnostic output if clang errors | /// \returns a \c StringError with the diagnostic output if clang errors | ||
/// occurred, \c TranslationUnitD | /// occurred, \c TranslationUnitD | ||
- llvm::Expected<TranslationUnitDeps> | + llvm::Expected<TranslationUnitDeps> getTranslationUnitDependencies( | ||
- getTranslationUn | + const std::vector<std::string> &CommandLine, StringRef CWD, | ||
- StringRef CWD, | + const llvm::DenseSet<ModuleID> &AlreadySeen, | ||
- const llvm::DenseSet<ModuleID> &AlreadySeen, | + LookupModuleOutp | ||
- LookupModuleOutp | + std::optional<llvm::MemoryBufferRef> TUBuffer = std::nullopt); | ||
/// Given a compilation context specified via the Clang driver command-line, | /// Given a compilation context specified via the Clang driver command-line, | ||
/// gather modular dependencies of module with the given name, and return the | /// gather modular dependencies of module with the given name, and return the |
@@ -17,6 +17,7 @@ | |||
#include "clang/Tooling/DependencyScanni | #include "clang/Tooling/DependencyScanni | ||
#include "llvm/Support/Error.h" | #include "llvm/Support/Error.h" | ||
#include "llvm/Support/FileSystem.h" | #include "llvm/Support/FileSystem.h" | ||
+#include "llvm/Support/MemoryBufferRef.h" | |||
#include <optional> | #include <optional> | ||
#include <string> | #include <string> | ||
@@ -83,9 +84,21 @@ public: | |||
llvm::IntrusiveRefCntP | llvm::IntrusiveRefCntP | ||
/// Run the dependency scanning tool for a given clang driver command-line, | /// Run the dependency scanning tool for a given clang driver command-line, | ||
- /// and report the discovered dependencies to the provided consumer. If | + /// and report the discovered dependencies to the provided consumer. If | ||
- /// | + /// TUBuffer is not nullopt, it is used as TU input for the dependency | ||
- /// \p ModuleName. | + /// scanning. Otherwise, the input should be included as part of the | ||
+ /// command-line. | |||
+ /// | |||
+ /// \returns false if clang errors occurred (with diagnostics reported to | |||
+ /// \c DiagConsumer), true otherwise. | |||
+ bool computeDependenc | |||
+ StringRef WorkingDirectory | |||
+ DependencyConsum | |||
+ DiagnosticConsum | |||
+ std::optional<llvm::MemoryBufferRef> TUBuffer = std::nullopt); | |||
+ | |||
+ /// Run the dependency scanning tool for a given clang driver command-line | |||
+ /// for a specific module. | |||
/// | /// | ||
/// \returns false if clang errors occurred (with diagnostics reported to | /// \returns false if clang errors occurred (with diagnostics reported to | ||
/// \c DiagConsumer), true otherwise. | /// \c DiagConsumer), true otherwise. | ||
@@ -94,13 +107,28 @@ public: | |||
DependencyConsum | DependencyConsum | ||
DependencyAction | DependencyAction | ||
DiagnosticConsum | DiagnosticConsum | ||
- | + StringRef ModuleName); | ||
+ | |||
+ /// Run the dependency scanning tool for a given clang driver command-line | |||
+ /// for a specific translation unit via file system or memory buffer. | |||
+ /// | |||
/// \returns A \c StringError with the diagnostic output if clang errors | /// \returns A \c StringError with the diagnostic output if clang errors | ||
/// occurred, success otherwise. | /// occurred, success otherwise. | ||
llvm::Error computeDependenc | llvm::Error computeDependenc | ||
StringRef WorkingDirectory | StringRef WorkingDirectory | ||
DependencyConsum | DependencyConsum | ||
- | + std::optional<llvm::MemoryBufferRef> TUBuffer = std::nullopt); | ||
+ | |||
+ /// Run the dependency scanning tool for a given clang driver command-line | |||
+ /// for a specific module. | |||
+ /// | |||
+ /// \returns A \c StringError with the diagnostic output if clang errors | |||
+ /// occurred, success otherwise. | |||
+ llvm::Error computeDependenc | |||
+ const std::vector<std::string> &CommandLine, | |||
+ DependencyConsum | |||
+ DependencyAction | |||
+ StringRef ModuleName); | |||
bool shouldEagerLoadM | bool shouldEagerLoadM | ||
@@ -121,6 +149,15 @@ private: | |||
ScanningOptimiza | ScanningOptimiza | ||
/// Whether to set up command-lines to load PCM files eagerly. | /// Whether to set up command-lines to load PCM files eagerly. | ||
bool EagerLoadModules | bool EagerLoadModules | ||
+ | |||
+ /// Private helper functions. | |||
+ bool scanDependencies | |||
+ const std::vector<std::string> &CommandLine, | |||
+ DependencyConsum | |||
+ DependencyAction | |||
+ DiagnosticConsum | |||
+ llvm::IntrusiveRefCntP | |||
+ std::optional<StringRef> ModuleName); | |||
}; | }; | ||
} // end namespace dependencies | } // end namespace dependencies |
@@ -45,16 +45,11 @@ module Clang_Basic { | |||
textual header "clang/Basic/BuiltinsAMDGPU.def" | textual header "clang/Basic/BuiltinsAMDGPU.def" | ||
textual header "clang/Basic/BuiltinsARM.def" | textual header "clang/Basic/BuiltinsARM.def" | ||
textual header "clang/Basic/BuiltinsHexagonM | textual header "clang/Basic/BuiltinsHexagonM | ||
- textual header "clang/Basic/BuiltinsLoongArc | |||
textual header "clang/Basic/BuiltinsLoongArc | textual header "clang/Basic/BuiltinsLoongArc | ||
textual header "clang/Basic/BuiltinsLoongArc | textual header "clang/Basic/BuiltinsLoongArc | ||
textual header "clang/Basic/BuiltinsLoongArc | textual header "clang/Basic/BuiltinsLoongArc | ||
textual header "clang/Basic/BuiltinsMips.def" | textual header "clang/Basic/BuiltinsMips.def" | ||
- textual header "clang/Basic/BuiltinsNEON.def" | |||
textual header "clang/Basic/BuiltinsPPC.def" | textual header "clang/Basic/BuiltinsPPC.def" | ||
- textual header "clang/Basic/BuiltinsRISCVVec | |||
- textual header "clang/Basic/BuiltinsSME.def" | |||
- textual header "clang/Basic/BuiltinsSVE.def" | |||
textual header "clang/Basic/BuiltinsSystemZ.def" | textual header "clang/Basic/BuiltinsSystemZ.def" | ||
textual header "clang/Basic/BuiltinsVE.def" | textual header "clang/Basic/BuiltinsVE.def" | ||
textual header "clang/Basic/BuiltinsVEVL.gen.def" | textual header "clang/Basic/BuiltinsVEVL.gen.def" | ||
@@ -113,6 +108,8 @@ module Clang_Diagnostic | |||
module Parse { header "clang/Basic/DiagnosticParse.h" export * } | module Parse { header "clang/Basic/DiagnosticParse.h" export * } | ||
module Serialization { header "clang/Serialization/SerializationDia | module Serialization { header "clang/Serialization/SerializationDia | ||
module Refactoring { header "clang/Tooling/Refactoring/RefactoringDiagn | module Refactoring { header "clang/Tooling/Refactoring/RefactoringDiagn | ||
+ | |||
+ textual header "clang/Basic/AllDiagnosticKin | |||
} | } | ||
module Clang_Driver { | module Clang_Driver { |
@@ -1055,7 +1055,8 @@ void ASTContext::Prin | |||
void ASTContext::mergeDefinitionI | void ASTContext::mergeDefinitionI | ||
bool NotifyListeners) { | bool NotifyListeners) { | ||
if (NotifyListeners) | if (NotifyListeners) | ||
- if (auto *Listener = getASTMutationListener() | + if (auto *Listener = getASTMutationListener(); | ||
+ Listener && !ND->isUnconditionall | |||
Listener->RedefinedHiddenD | Listener->RedefinedHiddenD | ||
MergedDefModules | MergedDefModules | ||
@@ -3901,7 +3902,7 @@ QualType ASTContext::getA | |||
if (Ty->isArrayParameter | if (Ty->isArrayParameter | ||
return Ty; | return Ty; | ||
assert(Ty->isConstantArrayT | assert(Ty->isConstantArrayT | ||
- const auto *ATy = cast<ConstantArrayType>(Ty); | + const auto *ATy = cast<ConstantArrayType>(Ty.getDesugaredType(*this)); | ||
llvm::FoldingSetNodeID | llvm::FoldingSetNodeID | ||
ATy->Profile(ID, *this, ATy->getElementType(), ATy->getZExtSize(), | ATy->Profile(ID, *this, ATy->getElementType(), ATy->getZExtSize(), | ||
ATy->getSizeExpr(), ATy->getSizeModifier(), | ATy->getSizeExpr(), ATy->getSizeModifier(), | ||
@@ -5319,6 +5320,19 @@ bool ASTContext::comp | |||
return EnumTooLarge; | return EnumTooLarge; | ||
} | } | ||
+bool ASTContext::isRepresentableI | |||
+ assert((T->isIntegralType(*this) || T->isEnumeralType()) && | |||
+ "Integral type required!"); | |||
+ unsigned BitWidth = getIntWidth(T); | |||
+ | |||
+ if (Value.isUnsigned() || Value.isNonNegative()) { | |||
+ if (T->isSignedIntegerO | |||
+ --BitWidth; | |||
+ return Value.getActiveBits() <= BitWidth; | |||
+ } | |||
+ return Value.getSignificantBi | |||
+} | |||
+ | |||
QualType ASTContext::getUnresolvedUsi | QualType ASTContext::getUnresolvedUsi | ||
const UnresolvedUsingT | const UnresolvedUsingT | ||
if (Decl->TypeForDecl) | if (Decl->TypeForDecl) | ||
@@ -7224,6 +7238,16 @@ static bool isSameQualifier( | |||
return !PX && !PY; | return !PX && !PY; | ||
} | } | ||
+static bool hasSameCudaAttrs | |||
+ if (!A->getASTContext().getLangOpts().CUDA) | |||
+ return true; // Target attributes are overloadable in CUDA compilation only. | |||
+ if (A->hasAttr<CUDADeviceAttr>() != B->hasAttr<CUDADeviceAttr>()) | |||
+ return false; | |||
+ if (A->hasAttr<CUDADeviceAttr>() && B->hasAttr<CUDADeviceAttr>()) | |||
+ return A->hasAttr<CUDAHostAttr>() == B->hasAttr<CUDAHostAttr>(); | |||
+ return true; // unattributed and __host__ functions are the same. | |||
+} | |||
+ | |||
/// Determine whether the attributes we can overload on are identical for A and | /// Determine whether the attributes we can overload on are identical for A and | ||
/// B. Will ignore any overloadable attrs represented in the type of A and B. | /// B. Will ignore any overloadable attrs represented in the type of A and B. | ||
static bool hasSameOverloada | static bool hasSameOverloada | ||
@@ -7254,7 +7278,7 @@ static bool hasSameOverloada | |||
if (Cand1ID != Cand2ID) | if (Cand1ID != Cand2ID) | ||
return false; | return false; | ||
} | } | ||
- return | + return hasSameCudaAttrs(A, B); | ||
} | } | ||
bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) const { | bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) const { |
@@ -6320,10 +6320,10 @@ ExpectedDecl ASTNodeImporter: | |||
updateLookupTabl | updateLookupTabl | ||
} else { // Not a partial specialization. | } else { // Not a partial specialization. | ||
- if (GetImportedOrCreateDecl( | + if (GetImportedOrCreateDecl(D2, D, Importer.getToContext(), D->getTagKind(), | ||
- D2, D, Importer.getToContext(), D->getTagKind(), DC, | + DC, *BeginLocOrErr, *IdLocOrErr, ClassTemplate, | ||
- *BeginLocOrErr, *IdLocOrErr, ClassTemplate, TemplateArgs, | + TemplateArgs, D->hasStrictPackMat | ||
- | + PrevDecl)) | ||
return D2; | return D2; | ||
// Update InsertPos, because preceding import calls may have invalidated | // Update InsertPos, because preceding import calls may have invalidated |
@@ -135,11 +135,9 @@ Function *ByteCodeEmitter | |||
// Create a handle over the emitted code. | // Create a handle over the emitted code. | ||
Function *Func = P.getFunction(FuncDecl); | Function *Func = P.getFunction(FuncDecl); | ||
if (!Func) { | if (!Func) { | ||
- unsigned BuiltinID = FuncDecl->getBuiltinID(); | + Func = P.createFunction(FuncDecl, ParamOffset, std::move(ParamTypes), | ||
- Func = | + std::move(ParamDescriptors | ||
- P.createFunction(FuncDecl, ParamOffset, std::move(ParamTypes), | + std::move(ParamOffsets), HasThisPointer, HasRVO); | ||
- std::move(ParamDescriptors | |||
- HasThisPointer, HasRVO, BuiltinID); | |||
} | } | ||
assert(Func); | assert(Func); | ||
@@ -212,8 +210,7 @@ Function *ByteCodeEmitter | |||
Function *Func = | Function *Func = | ||
P.createFunction(BE, ParamOffset, std::move(ParamTypes), | P.createFunction(BE, ParamOffset, std::move(ParamTypes), | ||
std::move(ParamDescriptors | std::move(ParamDescriptors | ||
- /*HasThisPointer=*/false, /*HasRVO=*/false | + /*HasThisPointer=*/false, /*HasRVO=*/false); | ||
- /*IsUnevaluatedBui | |||
assert(Func); | assert(Func); | ||
Func->setDefined(true); | Func->setDefined(true); |
@@ -194,12 +194,12 @@ private: | |||
template <class Emitter> | template <class Emitter> | ||
bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { | bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { | ||
const Expr *SubExpr = CE->getSubExpr(); | const Expr *SubExpr = CE->getSubExpr(); | ||
- switch (CE->getCastKind()) { | |||
- case CK_LValueToRValu | + if (DiscardResult) | ||
- if (DiscardResult) | + return this->delegate(SubExpr); | ||
- return this->discard(SubExpr); | |||
+ switch (CE->getCastKind()) { | |||
+ case CK_LValueToRValu | |||
std::optional<PrimType> SubExprT = classify(SubExpr->getType()); | std::optional<PrimType> SubExprT = classify(SubExpr->getType()); | ||
// Prepare storage for the result. | // Prepare storage for the result. | ||
if (!Initializing && !SubExprT) { | if (!Initializing && !SubExprT) { | ||
@@ -253,9 +253,6 @@ bool Compiler<Emitter | |||
case CK_UncheckedDeri | case CK_UncheckedDeri | ||
case CK_DerivedToBase | case CK_DerivedToBase | ||
- if (DiscardResult) | |||
- return this->discard(SubExpr); | |||
- | |||
if (!this->delegate(SubExpr)) | if (!this->delegate(SubExpr)) | ||
return false; | return false; | ||
@@ -285,9 +282,6 @@ bool Compiler<Emitter | |||
} | } | ||
case CK_BaseToDerived | case CK_BaseToDerived | ||
- if (DiscardResult) | |||
- return this->discard(SubExpr); | |||
- | |||
if (!this->delegate(SubExpr)) | if (!this->delegate(SubExpr)) | ||
return false; | return false; | ||
@@ -302,8 +296,6 @@ bool Compiler<Emitter | |||
if (!SubExpr->getType()->isFloatingType() || | if (!SubExpr->getType()->isFloatingType() || | ||
!CE->getType()->isFloatingType()) | !CE->getType()->isFloatingType()) | ||
return false; | return false; | ||
- if (DiscardResult) | |||
- return this->discard(SubExpr); | |||
if (!this->visit(SubExpr)) | if (!this->visit(SubExpr)) | ||
return false; | return false; | ||
const auto *TargetSemantics = &Ctx.getFloatSemantic | const auto *TargetSemantics = &Ctx.getFloatSemantic | ||
@@ -311,8 +303,6 @@ bool Compiler<Emitter | |||
} | } | ||
case CK_IntegralToFlo | case CK_IntegralToFlo | ||
- if (DiscardResult) | |||
- return this->discard(SubExpr); | |||
std::optional<PrimType> FromT = classify(SubExpr->getType()); | std::optional<PrimType> FromT = classify(SubExpr->getType()); | ||
if (!FromT) | if (!FromT) | ||
return false; | return false; | ||
@@ -327,8 +317,6 @@ bool Compiler<Emitter | |||
case CK_FloatingToBoo | case CK_FloatingToBoo | ||
case CK_FloatingToInt | case CK_FloatingToInt | ||
- if (DiscardResult) | |||
- return this->discard(SubExpr); | |||
std::optional<PrimType> ToT = classify(CE->getType()); | std::optional<PrimType> ToT = classify(CE->getType()); | ||
@@ -352,9 +340,6 @@ bool Compiler<Emitter | |||
case CK_NullToMemberP | case CK_NullToMemberP | ||
if (!this->discard(SubExpr)) | if (!this->discard(SubExpr)) | ||
return false; | return false; | ||
- if (DiscardResult) | |||
- return true; | |||
- | |||
const Descriptor *Desc = nullptr; | const Descriptor *Desc = nullptr; | ||
const QualType PointeeType = CE->getType()->getPointeeType(); | const QualType PointeeType = CE->getType()->getPointeeType(); | ||
if (!PointeeType.isNull()) { | if (!PointeeType.isNull()) { | ||
@@ -371,9 +356,6 @@ bool Compiler<Emitter | |||
} | } | ||
case CK_PointerToInte | case CK_PointerToInte | ||
- if (DiscardResult) | |||
- return this->discard(SubExpr); | |||
- | |||
if (!this->visit(SubExpr)) | if (!this->visit(SubExpr)) | ||
return false; | return false; | ||
@@ -399,8 +381,6 @@ bool Compiler<Emitter | |||
return false; | return false; | ||
if (!this->emitArrayDecay(CE)) | if (!this->emitArrayDecay(CE)) | ||
return false; | return false; | ||
- if (DiscardResult) | |||
- return this->emitPopPtr(CE); | |||
return true; | return true; | ||
} | } | ||
@@ -412,9 +392,6 @@ bool Compiler<Emitter | |||
// FIXME: I think the discard is wrong since the int->ptr cast might cause a | // FIXME: I think the discard is wrong since the int->ptr cast might cause a | ||
// diagnostic. | // diagnostic. | ||
PrimType T = classifyPrim(IntType); | PrimType T = classifyPrim(IntType); | ||
- if (DiscardResult) | |||
- return this->emitPop(T, CE); | |||
- | |||
QualType PtrType = CE->getType(); | QualType PtrType = CE->getType(); | ||
const Descriptor *Desc; | const Descriptor *Desc; | ||
if (std::optional<PrimType> T = classify(PtrType->getPointeeType())) | if (std::optional<PrimType> T = classify(PtrType->getPointeeType())) | ||
@@ -454,10 +431,6 @@ bool Compiler<Emitter | |||
return false; | return false; | ||
return this->emitInvalidCast(CastKind::Reinterpret, /*Fatal=*/true, CE); | return this->emitInvalidCast(CastKind::Reinterpret, /*Fatal=*/true, CE); | ||
} | } | ||
- | |||
- if (DiscardResult) | |||
- return this->discard(SubExpr); | |||
- | |||
QualType SubExprTy = SubExpr->getType(); | QualType SubExprTy = SubExpr->getType(); | ||
std::optional<PrimType> FromT = classify(SubExprTy); | std::optional<PrimType> FromT = classify(SubExprTy); | ||
// Casts from integer/vector to vector. | // Casts from integer/vector to vector. | ||
@@ -493,8 +466,6 @@ bool Compiler<Emitter | |||
case CK_FixedPointToB | case CK_FixedPointToB | ||
case CK_BooleanToSign | case CK_BooleanToSign | ||
case CK_IntegralCast: { | case CK_IntegralCast: { | ||
- if (DiscardResult) | |||
- return this->discard(SubExpr); | |||
std::optional<PrimType> FromT = classify(SubExpr->getType()); | std::optional<PrimType> FromT = classify(SubExpr->getType()); | ||
std::optional<PrimType> ToT = classify(CE->getType()); | std::optional<PrimType> ToT = classify(CE->getType()); | ||
@@ -546,8 +517,6 @@ bool Compiler<Emitter | |||
case CK_IntegralCompl | case CK_IntegralCompl | ||
case CK_FloatingCompl | case CK_FloatingCompl | ||
- if (DiscardResult) | |||
- return this->discard(SubExpr); | |||
if (!this->visit(SubExpr)) | if (!this->visit(SubExpr)) | ||
return false; | return false; | ||
return this->emitComplexBoolC | return this->emitComplexBoolC | ||
@@ -585,9 +554,6 @@ bool Compiler<Emitter | |||
case CK_FloatingCompl | case CK_FloatingCompl | ||
assert(CE->getType()->isAnyComplexType | assert(CE->getType()->isAnyComplexType | ||
assert(SubExpr->getType()->isAnyComplexType | assert(SubExpr->getType()->isAnyComplexType | ||
- if (DiscardResult) | |||
- return this->discard(SubExpr); | |||
- | |||
if (!Initializing) { | if (!Initializing) { | ||
std::optional<unsigned> LocalIndex = allocateLocal(CE); | std::optional<unsigned> LocalIndex = allocateLocal(CE); | ||
if (!LocalIndex) | if (!LocalIndex) | ||
@@ -633,9 +599,6 @@ bool Compiler<Emitter | |||
assert(classify(SubExpr->getType())); | assert(classify(SubExpr->getType())); | ||
assert(CE->getType()->isVectorType()); | assert(CE->getType()->isVectorType()); | ||
- if (DiscardResult) | |||
- return this->discard(SubExpr); | |||
- | |||
if (!Initializing) { | if (!Initializing) { | ||
std::optional<unsigned> LocalIndex = allocateLocal(CE); | std::optional<unsigned> LocalIndex = allocateLocal(CE); | ||
if (!LocalIndex) | if (!LocalIndex) | ||
@@ -3370,15 +3333,23 @@ bool Compiler<Emitter | |||
PrimType SizeT = classifyPrim(Stripped->getType()); | PrimType SizeT = classifyPrim(Stripped->getType()); | ||
+ // Save evaluated array size to a variable. | |||
+ unsigned ArrayLen = allocateLocalPri | |||
+ Stripped, SizeT, /*IsConst=*/false, /*IsExtended=*/false); | |||
+ if (!this->visit(Stripped)) | |||
+ return false; | |||
+ if (!this->emitSetLocal(SizeT, ArrayLen, E)) | |||
+ return false; | |||
+ | |||
if (PlacementDest) { | if (PlacementDest) { | ||
if (!this->visit(PlacementDest)) | if (!this->visit(PlacementDest)) | ||
return false; | return false; | ||
- if (!this->visit(Stripped)) | + if (!this->emitGetLocal(SizeT, ArrayLen, E)) | ||
return false; | return false; | ||
if (!this->emitCheckNewType | if (!this->emitCheckNewType | ||
return false; | return false; | ||
} else { | } else { | ||
- if (!this->visit(Stripped)) | + if (!this->emitGetLocal(SizeT, ArrayLen, E)) | ||
return false; | return false; | ||
if (ElemT) { | if (ElemT) { | ||
@@ -3392,10 +3363,113 @@ bool Compiler<Emitter | |||
} | } | ||
} | } | ||
- if (Init && !this->visitInitializer | + if (Init) { | ||
- return false; | + QualType InitType = Init->getType(); | ||
+ size_t StaticInitElems = 0; | |||
+ const Expr *DynamicInit = nullptr; | |||
+ if (const ConstantArrayTyp | |||
+ Ctx.getASTContext().getAsConstantArr | |||
+ StaticInitElems = CAT->getZExtSize(); | |||
+ if (!this->visitInitializer | |||
+ return false; | |||
- } else { | + if (const auto *ILE = dyn_cast<InitListExpr>(Init); | ||
+ ILE && ILE->hasArrayFiller()) | |||
+ DynamicInit = ILE->getArrayFiller(); | |||
+ } | |||
+ | |||
+ // The initializer initializes a certain number of elements, S. | |||
+ // However, the complete number of elements, N, might be larger than that. | |||
+ // In this case, we need to get an initializer for the remaining elements. | |||
+ // There are to cases: | |||
+ // 1) For the form 'new Struct[n];', the initializer is a | |||
+ // CXXConstructExpr | |||
+ // 2) For the form 'new Struct[n]{1,2,3}', the initializer is an | |||
+ // InitListExpr and the initializer for the remaining elements | |||
+ // is the array filler. | |||
+ | |||
+ if (DynamicInit || InitType->isIncompleteArra | |||
+ const Function *CtorFunc = nullptr; | |||
+ if (const auto *CE = dyn_cast<CXXConstructExpr | |||
+ CtorFunc = getFunction(CE->getConstructor()); | |||
+ if (!CtorFunc) | |||
+ return false; | |||
+ } | |||
+ | |||
+ LabelTy EndLabel = this->getLabel(); | |||
+ LabelTy StartLabel = this->getLabel(); | |||
+ | |||
+ // In the nothrow case, the alloc above might have returned nullptr. | |||
+ // Don't call any constructors that case. | |||
+ if (IsNoThrow) { | |||
+ if (!this->emitDupPtr(E)) | |||
+ return false; | |||
+ if (!this->emitNullPtr(0, nullptr, E)) | |||
+ return false; | |||
+ if (!this->emitEQPtr(E)) | |||
+ return false; | |||
+ if (!this->jumpTrue(EndLabel)) | |||
+ return false; | |||
+ } | |||
+ | |||
+ // Create loop variables. | |||
+ unsigned Iter = allocateLocalPri | |||
+ Stripped, SizeT, /*IsConst=*/false, /*IsExtended=*/false); | |||
+ if (!this->emitConst(StaticInitElems, | |||
+ return false; | |||
+ if (!this->emitSetLocal(SizeT, Iter, E)) | |||
+ return false; | |||
+ | |||
+ this->fallthrough(StartLabel); | |||
+ this->emitLabel(StartLabel); | |||
+ // Condition. Iter < ArrayLen? | |||
+ if (!this->emitGetLocal(SizeT, Iter, E)) | |||
+ return false; | |||
+ if (!this->emitGetLocal(SizeT, ArrayLen, E)) | |||
+ return false; | |||
+ if (!this->emitLT(SizeT, E)) | |||
+ return false; | |||
+ if (!this->jumpFalse(EndLabel)) | |||
+ return false; | |||
+ | |||
+ // Pointer to the allocated array is already on the stack. | |||
+ if (!this->emitGetLocal(SizeT, Iter, E)) | |||
+ return false; | |||
+ if (!this->emitArrayElemPtr | |||
+ return false; | |||
+ | |||
+ if (DynamicInit) { | |||
+ if (std::optional<PrimType> InitT = classify(DynamicInit)) { | |||
+ if (!this->visit(DynamicInit)) | |||
+ return false; | |||
+ if (!this->emitStorePop(*InitT, E)) | |||
+ return false; | |||
+ } else { | |||
+ if (!this->visitInitializer | |||
+ return false; | |||
+ if (!this->emitPopPtr(E)) | |||
+ return false; | |||
+ } | |||
+ } else { | |||
+ assert(CtorFunc); | |||
+ if (!this->emitCall(CtorFunc, 0, E)) | |||
+ return false; | |||
+ } | |||
+ | |||
+ // ++Iter; | |||
+ if (!this->emitGetPtrLocal(Iter, E)) | |||
+ return false; | |||
+ if (!this->emitIncPop(SizeT, E)) | |||
+ return false; | |||
+ | |||
+ if (!this->jump(StartLabel)) | |||
+ return false; | |||
+ | |||
+ this->fallthrough(EndLabel); | |||
+ this->emitLabel(EndLabel); | |||
+ } | |||
+ } | |||
+ } else { // Non-array. | |||
if (PlacementDest) { | if (PlacementDest) { | ||
if (!this->visit(PlacementDest)) | if (!this->visit(PlacementDest)) | ||
return false; | return false; | ||
@@ -4676,7 +4750,7 @@ bool Compiler<Emitter | |||
OCE && OCE->isAssignmentOp()) { | OCE && OCE->isAssignmentOp()) { | ||
// Just like with regular assignments, we need to special-case assignment | // Just like with regular assignments, we need to special-case assignment | ||
// operators here and evaluate the RHS (the second arg) before the LHS (the | // operators here and evaluate the RHS (the second arg) before the LHS (the | ||
- // first arg. We fix this by using a Flip op later. | + // first arg). We fix this by using a Flip op later. | ||
assert(Args.size() == 2); | assert(Args.size() == 2); | ||
IsAssignmentOper | IsAssignmentOper | ||
std::reverse(Args.begin(), Args.end()); | std::reverse(Args.begin(), Args.end()); | ||
@@ -4715,6 +4789,14 @@ bool Compiler<Emitter | |||
} else if (!this->visit(MC->getImplicitObjec | } else if (!this->visit(MC->getImplicitObjec | ||
return false; | return false; | ||
} | } | ||
+ } else if (const auto *PD = | |||
+ dyn_cast<CXXPseudoDestruc | |||
+ const Expr *Base = PD->getBase(); | |||
+ if (!Base->isGLValue()) | |||
+ return this->discard(Base); | |||
+ if (!this->visit(Base)) | |||
+ return false; | |||
+ return this->emitKill(E); | |||
} else if (!FuncDecl) { | } else if (!FuncDecl) { | ||
const Expr *Callee = E->getCallee(); | const Expr *Callee = E->getCallee(); | ||
CalleeOffset = this->allocateLocalPri | CalleeOffset = this->allocateLocalPri | ||
@@ -4991,8 +5073,8 @@ bool Compiler<Emitter | |||
template <class Emitter> | template <class Emitter> | ||
bool Compiler<Emitter>::visitDeclStmt(const DeclStmt *DS) { | bool Compiler<Emitter>::visitDeclStmt(const DeclStmt *DS) { | ||
for (const auto *D : DS->decls()) { | for (const auto *D : DS->decls()) { | ||
- if (isa<StaticAssertDecl, TagDecl, TypedefNameDecl, | + if (isa<StaticAssertDecl, TagDecl, TypedefNameDecl, BaseUsingDecl, | ||
- | + FunctionDecl, NamespaceAliasDecl>(D)) | ||
continue; | continue; | ||
const auto *VD = dyn_cast<VarDecl>(D); | const auto *VD = dyn_cast<VarDecl>(D); | ||
@@ -5596,6 +5678,22 @@ bool Compiler<Emitter | |||
if (!emitFieldInitial | if (!emitFieldInitial | ||
return false; | return false; | ||
+ | |||
+ // Mark all chain links as initialized. | |||
+ unsigned InitFieldOffset = 0; | |||
+ for (const NamedDecl *ND : IFD->chain().drop_back()) { | |||
+ const auto *FD = cast<FieldDecl>(ND); | |||
+ const Record *FieldRecord = this->P.getOrCreateRecor | |||
+ assert(FieldRecord); | |||
+ NestedField = FieldRecord->getField(FD); | |||
+ InitFieldOffset += NestedField->Offset; | |||
+ assert(NestedField); | |||
+ if (!this->emitGetPtrThisFi | |||
+ return false; | |||
+ if (!this->emitFinishInitPo | |||
+ return false; | |||
+ } | |||
+ | |||
} else { | } else { | ||
assert(Init->isDelegatingInit | assert(Init->isDelegatingInit | ||
if (!this->emitThis(InitExpr)) | if (!this->emitThis(InitExpr)) | ||
@@ -5664,6 +5762,21 @@ bool Compiler<Emitter | |||
return this->emitPopPtr(Dtor) && this->emitRetVoid(Dtor); | return this->emitPopPtr(Dtor) && this->emitRetVoid(Dtor); | ||
} | } | ||
+template <class Emitter> | |||
+bool Compiler<Emitter>::compileUnionAssi | |||
+ const CXXMethodDecl *MD) { | |||
+ if (!this->emitThis(MD)) | |||
+ return false; | |||
+ | |||
+ auto PVD = MD->getParamDecl(0); | |||
+ ParamOffset PO = this->Params[PVD]; // Must exist. | |||
+ | |||
+ if (!this->emitGetParam(PT_Ptr, PO.Offset, MD)) | |||
+ return false; | |||
+ | |||
+ return this->emitMemcpy(MD) && this->emitRet(PT_Ptr, MD); | |||
+} | |||
+ | |||
template <class Emitter> | template <class Emitter> | ||
bool Compiler<Emitter>::visitFunc(const FunctionDecl *F) { | bool Compiler<Emitter>::visitFunc(const FunctionDecl *F) { | ||
// Classify the return type. | // Classify the return type. | ||
@@ -5675,9 +5788,16 @@ bool Compiler<Emitter | |||
return this->compileDestructo | return this->compileDestructo | ||
// Emit custom code if this is a lambda static invoker. | // Emit custom code if this is a lambda static invoker. | ||
- if (const auto *MD = dyn_cast<CXXMethodDecl>(F) | + if (const auto *MD = dyn_cast<CXXMethodDecl>(F)) { | ||
- MD && MD->isLambdaStaticIn | + const RecordDecl *RD = MD->getParent(); | ||
- return this->emitLambdaStatic | + | ||
+ if (RD->isUnion() && | |||
+ (MD->isCopyAssignment | |||
+ return this->compileUnionAssi | |||
+ | |||
+ if (MD->isLambdaStaticIn | |||
+ return this->emitLambdaStatic | |||
+ } | |||
// Regular functions. | // Regular functions. | ||
if (const auto *Body = F->getBody()) | if (const auto *Body = F->getBody()) | ||
@@ -6188,9 +6308,6 @@ bool Compiler<Emitter | |||
return this->emitGetPtrParam(It->second.Offset, E); | return this->emitGetPtrParam(It->second.Offset, E); | ||
} | } | ||
- | |||
- if (D->getType()->isReferenceType()) | |||
- return this->emitDummyPtr(D, E); | |||
} | } | ||
// In case we need to re-visit a declaration. | // In case we need to re-visit a declaration. |
@@ -383,6 +383,7 @@ private: | |||
bool emitBuiltinBitCa | bool emitBuiltinBitCa | ||
bool compileConstruct | bool compileConstruct | ||
bool compileDestructo | bool compileDestructo | ||
+ bool compileUnionAssi | |||
bool checkLiteralType | bool checkLiteralType | ||
@@ -61,6 +61,11 @@ struct alignas(void *) GlobalInlineDesc | |||
}; | }; | ||
static_assert(sizeof(GlobalInlineDesc | static_assert(sizeof(GlobalInlineDesc | ||
+enum class Lifetime : uint8_t { | |||
+ Started, | |||
+ Ended, | |||
+}; | |||
+ | |||
/// Inline descriptor embedded in structures and arrays. | /// Inline descriptor embedded in structures and arrays. | ||
/// | /// | ||
/// Such descriptors precede all composite array elements and structure fields. | /// Such descriptors precede all composite array elements and structure fields. | ||
@@ -100,12 +105,14 @@ struct InlineDescriptor | |||
LLVM_PREFERRED_T | LLVM_PREFERRED_T | ||
unsigned IsArrayElement : 1; | unsigned IsArrayElement : 1; | ||
+ Lifetime LifeState; | |||
+ | |||
const Descriptor *Desc; | const Descriptor *Desc; | ||
InlineDescriptor | InlineDescriptor | ||
: Offset(sizeof(InlineDescriptor | : Offset(sizeof(InlineDescriptor | ||
IsBase(false), IsActive(false), IsFieldMutable(false), | IsBase(false), IsActive(false), IsFieldMutable(false), | ||
- IsArrayElement(false), Desc(D) {} | + IsArrayElement(false), LifeState(Lifetime::Started), Desc(D) {} | ||
void dump() const { dump(llvm::errs()); } | void dump() const { dump(llvm::errs()); } | ||
void dump(llvm::raw_ostream &OS) const; | void dump(llvm::raw_ostream &OS) const; |
@@ -240,7 +240,7 @@ LLVM_DUMP_METHOD | |||
else if (isRecord()) | else if (isRecord()) | ||
OS << " record"; | OS << " record"; | ||
else if (isPrimitive()) | else if (isPrimitive()) | ||
- OS << " | + OS << " primitive " << primTypeToString(getPrimType()); | ||
if (isZeroSizeArray()) | if (isZeroSizeArray()) | ||
OS << " zero-size-array"; | OS << " zero-size-array"; |
@@ -19,12 +19,28 @@ Function::Functi | |||
llvm::SmallVectorImpl<PrimType> &&ParamTypes, | llvm::SmallVectorImpl<PrimType> &&ParamTypes, | ||
llvm::DenseMap<unsigned, ParamDescriptor> &&Params, | llvm::DenseMap<unsigned, ParamDescriptor> &&Params, | ||
llvm::SmallVectorImpl<unsigned> &&ParamOffsets, | llvm::SmallVectorImpl<unsigned> &&ParamOffsets, | ||
- bool HasThisPointer, bool HasRVO | + bool HasThisPointer, bool HasRVO) | ||
- : P(P), Source(Source), ArgSize(ArgSize), | + : P(P), Kind(FunctionKind::Normal), Source(Source), ArgSize(ArgSize), | ||
- | + ParamTypes(std::move(ParamTypes)), Params(std::move(Params)), | ||
- HasThisPointer(HasThisPointer), HasRVO(HasRVO), BuiltinID(BuiltinID) { | + ParamOffsets(std::move(ParamOffsets)), HasThisPointer(HasThisPointer), | ||
- if (const auto *F = Source.dyn_cast<const FunctionDecl *>()) | + HasRVO(HasRVO) { | ||
+ if (const auto *F = dyn_cast<const FunctionDecl *>(Source)) { | |||
Variadic = F->isVariadic(); | Variadic = F->isVariadic(); | ||
+ BuiltinID = F->getBuiltinID(); | |||
+ if (const auto *CD = dyn_cast<CXXConstructorDe | |||
+ Virtual = CD->isVirtual(); | |||
+ Kind = FunctionKind::Ctor; | |||
+ } else if (const auto *CD = dyn_cast<CXXDestructorDec | |||
+ Virtual = CD->isVirtual(); | |||
+ Kind = FunctionKind::Dtor; | |||
+ } else if (const auto *MD = dyn_cast<CXXMethodDecl>(F)) { | |||
+ Virtual = MD->isVirtual(); | |||
+ if (MD->isLambdaStaticIn | |||
+ Kind = FunctionKind::LambdaStaticInvo | |||
+ else if (clang::isLambdaCallOper | |||
+ Kind = FunctionKind::LambdaCallOperat | |||
+ } | |||
+ } | |||
} | } | ||
Function::ParamDescriptor Function::getParamDescript | Function::ParamDescriptor Function::getParamDescript | ||
@@ -45,13 +61,6 @@ SourceInfo Function::getSou | |||
return It->second; | return It->second; | ||
} | } | ||
-bool Function::isVirtual() const { | |||
- if (const auto *M = dyn_cast_if_pres | |||
- Source.dyn_cast<const FunctionDecl *>())) | |||
- return M->isVirtual(); | |||
- return false; | |||
-} | |||
- | |||
/// Unevaluated builtins don't get their arguments put on the stack | /// Unevaluated builtins don't get their arguments put on the stack | ||
/// automatically. They instead operate on the AST of their Call | /// automatically. They instead operate on the AST of their Call | ||
/// Expression. | /// Expression. |
@@ -51,6 +51,11 @@ public: | |||
return llvm::make_range(Descriptors.begin(), Descriptors.end()); | return llvm::make_range(Descriptors.begin(), Descriptors.end()); | ||
} | } | ||
+ llvm::iterator_range<LocalVectorTy::const_reverse_it | |||
+ locals_reverse() const { | |||
+ return llvm::reverse(Descriptors); | |||
+ } | |||
+ | |||
private: | private: | ||
/// Object descriptors in this block. | /// Object descriptors in this block. | ||
LocalVectorTy Descriptors; | LocalVectorTy Descriptors; | ||
@@ -80,6 +85,13 @@ using FunctionDeclTy = | |||
/// | /// | ||
class Function final { | class Function final { | ||
public: | public: | ||
+ enum class FunctionKind { | |||
+ Normal, | |||
+ Ctor, | |||
+ Dtor, | |||
+ LambdaStaticInvo | |||
+ LambdaCallOperat | |||
+ }; | |||
using ParamDescriptor = std::pair<PrimType, Descriptor *>; | using ParamDescriptor = std::pair<PrimType, Descriptor *>; | ||
/// Returns the size of the function's local stack. | /// Returns the size of the function's local stack. | ||
@@ -141,43 +153,31 @@ public: | |||
bool isConstexpr() const { return IsValid || isLambdaStaticIn | bool isConstexpr() const { return IsValid || isLambdaStaticIn | ||
/// Checks if the function is virtual. | /// Checks if the function is virtual. | ||
- bool isVirtual() | + bool isVirtual() const { return Virtual; }; | ||
/// Checks if the function is a constructor. | /// Checks if the function is a constructor. | ||
- bool isConstructor() const { | + bool isConstructor() const { return Kind == FunctionKind::Ctor; } | ||
- return isa_and_nonnull<CXXConstructorDe | |||
- dyn_cast<const FunctionDecl *>(Source)); | |||
- } | |||
/// Checks if the function is a destructor. | /// Checks if the function is a destructor. | ||
- bool isDestructor() const { | + bool isDestructor() const { return Kind == FunctionKind::Dtor; } | ||
- return isa_and_nonnull<CXXDestructorDec | |||
- dyn_cast<const FunctionDecl *>(Source)); | |||
- } | |||
- | |||
- /// Returns the parent record decl, if any. | |||
- const CXXRecordDecl *getParentDecl() const { | |||
- if (const auto *MD = dyn_cast_if_pres | |||
- dyn_cast<const FunctionDecl *>(Source))) | |||
- return MD->getParent(); | |||
- return nullptr; | |||
- } | |||
/// Returns whether this function is a lambda static invoker, | /// Returns whether this function is a lambda static invoker, | ||
/// which we generate custom byte code for. | /// which we generate custom byte code for. | ||
bool isLambdaStaticIn | bool isLambdaStaticIn | ||
- if (const auto *MD = dyn_cast_if_pres | + return Kind == FunctionKind::LambdaStaticInvo | ||
- dyn_cast<const FunctionDecl *>(Source))) | |||
- return MD->isLambdaStaticIn | |||
- return false; | |||
} | } | ||
/// Returns whether this function is the call operator | /// Returns whether this function is the call operator | ||
/// of a lambda record decl. | /// of a lambda record decl. | ||
bool isLambdaCallOper | bool isLambdaCallOper | ||
+ return Kind == FunctionKind::LambdaCallOperat | |||
+ } | |||
+ | |||
+ /// Returns the parent record decl, if any. | |||
+ const CXXRecordDecl *getParentDecl() const { | |||
if (const auto *MD = dyn_cast_if_pres | if (const auto *MD = dyn_cast_if_pres | ||
dyn_cast<const FunctionDecl *>(Source))) | dyn_cast<const FunctionDecl *>(Source))) | ||
- return clang::isLambdaCallOper | + return MD->getParent(); | ||
- return | + return nullptr; | ||
} | } | ||
/// Checks if the function is fully done compiling. | /// Checks if the function is fully done compiling. | ||
@@ -213,7 +213,7 @@ public: | |||
bool isThisPointerExp | bool isThisPointerExp | ||
if (const auto *MD = dyn_cast_if_pres | if (const auto *MD = dyn_cast_if_pres | ||
- | + dyn_cast<const FunctionDecl *>(Source))) | ||
return MD->isExplicitObject | return MD->isExplicitObject | ||
return false; | return false; | ||
} | } | ||
@@ -232,7 +232,7 @@ private: | |||
llvm::SmallVectorImpl<PrimType> &&ParamTypes, | llvm::SmallVectorImpl<PrimType> &&ParamTypes, | ||
llvm::DenseMap<unsigned, ParamDescriptor> &&Params, | llvm::DenseMap<unsigned, ParamDescriptor> &&Params, | ||
llvm::SmallVectorImpl<unsigned> &&ParamOffsets, bool HasThisPointer, | llvm::SmallVectorImpl<unsigned> &&ParamOffsets, bool HasThisPointer, | ||
- bool HasRVO | + bool HasRVO); | ||
/// Sets the code of a function. | /// Sets the code of a function. | ||
void setCode(unsigned NewFrameSize, std::vector<std::byte> &&NewCode, | void setCode(unsigned NewFrameSize, std::vector<std::byte> &&NewCode, | ||
@@ -255,6 +255,8 @@ private: | |||
/// Program reference. | /// Program reference. | ||
Program &P; | Program &P; | ||
+ /// Function Kind. | |||
+ FunctionKind Kind; | |||
/// Declaration this function was compiled from. | /// Declaration this function was compiled from. | ||
FunctionDeclTy Source; | FunctionDeclTy Source; | ||
/// Local area size: storage + metadata. | /// Local area size: storage + metadata. | ||
@@ -289,6 +291,7 @@ private: | |||
bool HasBody = false; | bool HasBody = false; | ||
bool Defined = false; | bool Defined = false; | ||
bool Variadic = false; | bool Variadic = false; | ||
+ bool Virtual = false; | |||
unsigned BuiltinID = 0; | unsigned BuiltinID = 0; | ||
public: | public: |
@@ -65,17 +65,17 @@ static void diagnoseNonConst | |||
const ValueDecl *VD); | const ValueDecl *VD); | ||
static bool diagnoseUnknownD | static bool diagnoseUnknownD | ||
const ValueDecl *D) { | const ValueDecl *D) { | ||
- const SourceInfo &E = S.Current->getSource(OpPC); | |||
if (isa<ParmVarDecl>(D)) { | if (isa<ParmVarDecl>(D)) { | ||
if (D->getType()->isReferenceType()) | if (D->getType()->isReferenceType()) | ||
return false; | return false; | ||
+ const SourceInfo &Loc = S.Current->getSource(OpPC); | |||
if (S.getLangOpts().CPlusPlus11) { | if (S.getLangOpts().CPlusPlus11) { | ||
- S.FFDiag( | + S.FFDiag(Loc, diag::note_constexpr_function_param_value_unknown) << D; | ||
S.Note(D->getLocation(), diag::note_declared_at | S.Note(D->getLocation(), diag::note_declared_at | ||
} else { | } else { | ||
- S.FFDiag( | + S.FFDiag(Loc); | ||
} | } | ||
return false; | return false; | ||
} | } | ||
@@ -561,6 +561,18 @@ bool CheckInitialized | |||
return false; | return false; | ||
} | } | ||
+static bool CheckLifetime(InterpState &S, CodePtr OpPC, const Pointer &Ptr, | |||
+ AccessKinds AK) { | |||
+ if (Ptr.getLifetime() == Lifetime::Started) | |||
+ return true; | |||
+ | |||
+ if (!S.checkingPotentia | |||
+ S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_a | |||
+ << AK << /*uninitialized=*/false << S.Current->getRange(OpPC); | |||
+ } | |||
+ return false; | |||
+} | |||
+ | |||
bool CheckGlobalIniti | bool CheckGlobalIniti | ||
if (Ptr.isInitialized()) | if (Ptr.isInitialized()) | ||
return true; | return true; | ||
@@ -605,6 +617,8 @@ bool CheckLoad(Interp | |||
return false; | return false; | ||
if (!CheckActive(S, OpPC, Ptr, AK)) | if (!CheckActive(S, OpPC, Ptr, AK)) | ||
return false; | return false; | ||
+ if (!CheckLifetime(S, OpPC, Ptr, AK)) | |||
+ return false; | |||
if (!CheckInitialized | if (!CheckInitialized | ||
return false; | return false; | ||
if (!CheckTemporary(S, OpPC, Ptr, AK)) | if (!CheckTemporary(S, OpPC, Ptr, AK)) | ||
@@ -634,6 +648,8 @@ bool CheckFinalLoad(I | |||
return false; | return false; | ||
if (!CheckActive(S, OpPC, Ptr, AK_Read)) | if (!CheckActive(S, OpPC, Ptr, AK_Read)) | ||
return false; | return false; | ||
+ if (!CheckLifetime(S, OpPC, Ptr, AK_Read)) | |||
+ return false; | |||
if (!CheckInitialized | if (!CheckInitialized | ||
return false; | return false; | ||
if (!CheckTemporary(S, OpPC, Ptr, AK_Read)) | if (!CheckTemporary(S, OpPC, Ptr, AK_Read)) | ||
@@ -650,6 +666,8 @@ bool CheckStore(Inter | |||
return false; | return false; | ||
if (!CheckDummy(S, OpPC, Ptr, AK_Assign)) | if (!CheckDummy(S, OpPC, Ptr, AK_Assign)) | ||
return false; | return false; | ||
+ if (!CheckLifetime(S, OpPC, Ptr, AK_Assign)) | |||
+ return false; | |||
if (!CheckExtern(S, OpPC, Ptr)) | if (!CheckExtern(S, OpPC, Ptr)) | ||
return false; | return false; | ||
if (!CheckRange(S, OpPC, Ptr, AK_Assign)) | if (!CheckRange(S, OpPC, Ptr, AK_Assign)) | ||
@@ -1546,34 +1564,38 @@ bool CheckNewTypeMism | |||
bool InvalidNewDelete | bool InvalidNewDelete | ||
assert(E); | assert(E); | ||
- if (S.getLangOpts().CPlusPlus26) | |||
- return true; | |||
- | |||
- const auto &Loc = S.Current->getSource(OpPC); | |||
- | |||
if (const auto *NewExpr = dyn_cast<CXXNewExpr>(E)) { | if (const auto *NewExpr = dyn_cast<CXXNewExpr>(E)) { | ||
const FunctionDecl *OperatorNew = NewExpr->getOperatorNew(); | const FunctionDecl *OperatorNew = NewExpr->getOperatorNew(); | ||
- if (!S.getLangOpts().CPlusPlus26 && NewExpr->getNumPlacementA | + if (NewExpr->getNumPlacementA | ||
// This is allowed pre-C++26, but only an std function. | // This is allowed pre-C++26, but only an std function. | ||
- if (S.Current->isStdFunction()) | + if (S.getLangOpts().CPlusPlus26 || S.Current->isStdFunction()) | ||
return true; | return true; | ||
- S.FFDiag( | + S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_placement) | ||
<< /*C++26 feature*/ 1 << E->getSourceRange(); | << /*C++26 feature*/ 1 << E->getSourceRange(); | ||
- } else if (NewExpr->getNumPlacementA | |||
- !OperatorNew->isReservedGlobal | |||
- S.FFDiag(Loc, diag::note_constexpr_n | |||
- << /*Unsupported*/ 0 << E->getSourceRange(); | |||
} else if (!OperatorNew->isReplaceableGlo | } else if (!OperatorNew->isReplaceableGlo | ||
- S.FFDiag(Loc, diag::note_constexpr_n | + S.FFDiag(S.Current->getSource(OpPC), | ||
+ diag::note_constexpr_n | |||
<< isa<CXXMethodDecl>(OperatorNew) << OperatorNew; | << isa<CXXMethodDecl>(OperatorNew) << OperatorNew; | ||
+ return false; | |||
+ } else if (!S.getLangOpts().CPlusPlus26 && | |||
+ NewExpr->getNumPlacementA | |||
+ !OperatorNew->isReservedGlobal | |||
+ if (!S.getLangOpts().CPlusPlus26) { | |||
+ S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_n | |||
+ << /*Unsupported*/ 0 << E->getSourceRange(); | |||
+ return false; | |||
+ } | |||
+ return true; | |||
} | } | ||
} else { | } else { | ||
const auto *DeleteExpr = cast<CXXDeleteExpr>(E); | const auto *DeleteExpr = cast<CXXDeleteExpr>(E); | ||
const FunctionDecl *OperatorDelete = DeleteExpr->getOperatorDelet | const FunctionDecl *OperatorDelete = DeleteExpr->getOperatorDelet | ||
if (!OperatorDelete->isReplaceableGlo | if (!OperatorDelete->isReplaceableGlo | ||
- S.FFDiag(Loc, diag::note_constexpr_n | + S.FFDiag(S.Current->getSource(OpPC), | ||
+ diag::note_constexpr_n | |||
<< isa<CXXMethodDecl>(OperatorDelete) << OperatorDelete; | << isa<CXXMethodDecl>(OperatorDelete) << OperatorDelete; | ||
+ return false; | |||
} | } | ||
} | } | ||
@@ -379,15 +379,14 @@ bool AddSubMulHelper( | |||
APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits)); | APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits)); | ||
// Report undefined behaviour, stopping if required. | // Report undefined behaviour, stopping if required. | ||
- const Expr *E = S.Current->getExpr(OpPC); | |||
- QualType Type = E->getType(); | |||
if (S.checkingForUndef | if (S.checkingForUndef | ||
+ const Expr *E = S.Current->getExpr(OpPC); | |||
+ QualType Type = E->getType(); | |||
SmallString<32> Trunc; | SmallString<32> Trunc; | ||
Value.trunc(Result.bitWidth()) | Value.trunc(Result.bitWidth()) | ||
.toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral | .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral | ||
/*UpperCase=*/true, /*InsertSeparators | /*UpperCase=*/true, /*InsertSeparators | ||
- auto Loc = E->getExprLoc(); | + S.report(E->getExprLoc(), diag::warn_integer_con | ||
- S.report(Loc, diag::warn_integer_con | |||
<< Trunc << Type << E->getSourceRange(); | << Trunc << Type << E->getSourceRange(); | ||
} | } | ||
@@ -737,16 +736,14 @@ bool Neg(InterpState &S, CodePtr OpPC) { | |||
S.Stk.push<T>(Result); | S.Stk.push<T>(Result); | ||
APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1); | APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1); | ||
- const Expr *E = S.Current->getExpr(OpPC); | |||
- QualType Type = E->getType(); | |||
- | |||
if (S.checkingForUndef | if (S.checkingForUndef | ||
+ const Expr *E = S.Current->getExpr(OpPC); | |||
+ QualType Type = E->getType(); | |||
SmallString<32> Trunc; | SmallString<32> Trunc; | ||
NegatedValue.trunc(Result.bitWidth()) | NegatedValue.trunc(Result.bitWidth()) | ||
.toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral | .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral | ||
/*UpperCase=*/true, /*InsertSeparators | /*UpperCase=*/true, /*InsertSeparators | ||
- auto Loc = E->getExprLoc(); | + S.report(E->getExprLoc(), diag::warn_integer_con | ||
- S.report(Loc, diag::warn_integer_con | |||
<< Trunc << Type << E->getSourceRange(); | << Trunc << Type << E->getSourceRange(); | ||
return true; | return true; | ||
} | } | ||
@@ -800,15 +797,14 @@ bool IncDecHelper(Int | |||
APResult = --Value.toAPSInt(Bits); | APResult = --Value.toAPSInt(Bits); | ||
// Report undefined behaviour, stopping if required. | // Report undefined behaviour, stopping if required. | ||
- const Expr *E = S.Current->getExpr(OpPC); | |||
- QualType Type = E->getType(); | |||
if (S.checkingForUndef | if (S.checkingForUndef | ||
+ const Expr *E = S.Current->getExpr(OpPC); | |||
+ QualType Type = E->getType(); | |||
SmallString<32> Trunc; | SmallString<32> Trunc; | ||
APResult.trunc(Result.bitWidth()) | APResult.trunc(Result.bitWidth()) | ||
.toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral | .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral | ||
/*UpperCase=*/true, /*InsertSeparators | /*UpperCase=*/true, /*InsertSeparators | ||
- auto Loc = E->getExprLoc(); | + S.report(E->getExprLoc(), diag::warn_integer_con | ||
- S.report(Loc, diag::warn_integer_con | |||
<< Trunc << Type << E->getSourceRange(); | << Trunc << Type << E->getSourceRange(); | ||
return true; | return true; | ||
} | } | ||
@@ -1258,6 +1254,12 @@ bool GetLocal(InterpS | |||
return true; | return true; | ||
} | } | ||
+static inline bool Kill(InterpState &S, CodePtr OpPC) { | |||
+ const auto &Ptr = S.Stk.pop<Pointer>(); | |||
+ Ptr.endLifetime(); | |||
+ return true; | |||
+} | |||
+ | |||
/// 1) Pops the value from the stack. | /// 1) Pops the value from the stack. | ||
/// 2) Writes the value to the local variable with the | /// 2) Writes the value to the local variable with the | ||
/// given offset. | /// given offset. | ||
@@ -1482,7 +1484,10 @@ bool InitThisBitField | |||
template <PrimType Name, class T = typename PrimConv<Name>::T> | template <PrimType Name, class T = typename PrimConv<Name>::T> | ||
bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) { | bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) { | ||
const T &Value = S.Stk.pop<T>(); | const T &Value = S.Stk.pop<T>(); | ||
- const Pointer | + const Pointer &Ptr = S.Stk.peek<Pointer>(); | ||
+ if (!CheckRange(S, OpPC, Ptr, CSK_Field)) | |||
+ return false; | |||
+ const Pointer &Field = Ptr.atField(I); | |||
Field.deref<T>() = Value; | Field.deref<T>() = Value; | ||
Field.activate(); | Field.activate(); | ||
Field.initialize(); | Field.initialize(); |
@@ -99,7 +99,7 @@ void InterpFrame::ini | |||
} | } | ||
void InterpFrame::destroy(unsigned Idx) { | void InterpFrame::destroy(unsigned Idx) { | ||
- for (auto &Local : Func->getScope(Idx). | + for (auto &Local : Func->getScope(Idx).locals_reverse()) { | ||
S.deallocate(localBlock(Local.Offset)); | S.deallocate(localBlock(Local.Offset)); | ||
} | } | ||
} | } |
@@ -394,6 +394,11 @@ def GetLocal : AccessOpcode { let HasCustomEval = 1; } | |||
// [] -> [Pointer] | // [] -> [Pointer] | ||
def SetLocal : AccessOpcode { let HasCustomEval = 1; } | def SetLocal : AccessOpcode { let HasCustomEval = 1; } | ||
+def Kill : Opcode { | |||
+ let Types = []; | |||
+ let Args = []; | |||
+} | |||
+ | |||
def CheckDecl : Opcode { | def CheckDecl : Opcode { | ||
let Args = [ArgVarDecl]; | let Args = [ArgVarDecl]; | ||
} | } |
@@ -687,6 +687,22 @@ public: | |||
/// Deactivates an entire strurcutre. | /// Deactivates an entire strurcutre. | ||
void deactivate() const; | void deactivate() const; | ||
+ Lifetime getLifetime() const { | |||
+ if (!isBlockPointer()) | |||
+ return Lifetime::Started; | |||
+ if (asBlockPointer().Base < sizeof(InlineDescriptor | |||
+ return Lifetime::Started; | |||
+ return getInlineDesc()->LifeState; | |||
+ } | |||
+ | |||
+ void endLifetime() const { | |||
+ if (!isBlockPointer()) | |||
+ return; | |||
+ if (asBlockPointer().Base < sizeof(InlineDescriptor | |||
+ return; | |||
+ getInlineDesc()->LifeState = Lifetime::Ended; | |||
+ } | |||
+ | |||
/// Compare two pointers. | /// Compare two pointers. | ||
ComparisonCatego | ComparisonCatego | ||
if (!hasSameBase(*this, Other)) | if (!hasSameBase(*this, Other)) |
@@ -18,14 +18,12 @@ using namespace clang; | |||
using namespace clang::interp; | using namespace clang::interp; | ||
unsigned Program::getOrCreateNativ | unsigned Program::getOrCreateNativ | ||
- auto It = NativePointerInd | + auto [It, Inserted] = | ||
- if (It != NativePointerInd | + NativePointerInd | ||
- return It->second; | + if (Inserted) | ||
+ NativePointers.push_back(Ptr); | |||
- unsigned Idx = NativePointers.size(); | + return It->second; | ||
- NativePointers.push_back(Ptr); | |||
- NativePointerInd | |||
- return Idx; | |||
} | } | ||
const void *Program::getNativePointer | const void *Program::getNativePointer | ||
@@ -35,6 +33,7 @@ const void *Program::getNat | |||
unsigned Program::createGlobalStri | unsigned Program::createGlobalStri | ||
const size_t CharWidth = S->getCharByteWidth | const size_t CharWidth = S->getCharByteWidth | ||
const size_t BitWidth = CharWidth * Ctx.getCharBit(); | const size_t BitWidth = CharWidth * Ctx.getCharBit(); | ||
+ unsigned StringLength = S->getLength(); | |||
PrimType CharType; | PrimType CharType; | ||
switch (CharWidth) { | switch (CharWidth) { | ||
@@ -55,15 +54,15 @@ unsigned Program::createG | |||
Base = S; | Base = S; | ||
// Create a descriptor for the string. | // Create a descriptor for the string. | ||
- Descriptor *Desc = | + Descriptor *Desc = | ||
- S->getLength() + 1, | + allocateDescript | ||
- | + /*isConst=*/true, | ||
- | + /*isTemporary=*/false, | ||
- | + /*isMutable=*/false); | ||
// Allocate storage for the string. | // Allocate storage for the string. | ||
// The byte length does not include the null terminator. | // The byte length does not include the null terminator. | ||
- unsigned | + unsigned GlobalIndex = Globals.size(); | ||
unsigned Sz = Desc->getAllocSize(); | unsigned Sz = Desc->getAllocSize(); | ||
auto *G = new (Allocator, Sz) Global(Ctx.getEvalID(), Desc, /*isStatic=*/true, | auto *G = new (Allocator, Sz) Global(Ctx.getEvalID(), Desc, /*isStatic=*/true, | ||
/*isExtern=*/false); | /*isExtern=*/false); | ||
@@ -74,33 +73,32 @@ unsigned Program::createG | |||
// Construct the string in storage. | // Construct the string in storage. | ||
const Pointer Ptr(G->block()); | const Pointer Ptr(G->block()); | ||
- for (unsigned I = | + for (unsigned I = 0; I <= StringLength; ++I) { | ||
- Pointer Field = Ptr.atIndex(I) | + Pointer Field = Ptr.atIndex(I); | ||
- const uint32_t CodePoint = I == | + const uint32_t CodePoint = I == StringLength ? 0 : S->getCodeUnit(I); | ||
switch (CharType) { | switch (CharType) { | ||
case PT_Sint8: { | case PT_Sint8: { | ||
using T = PrimConv<PT_Sint8>::T; | using T = PrimConv<PT_Sint8>::T; | ||
Field.deref<T>() = T::from(CodePoint, BitWidth); | Field.deref<T>() = T::from(CodePoint, BitWidth); | ||
- Field.initialize(); | |||
break; | break; | ||
} | } | ||
case PT_Uint16: { | case PT_Uint16: { | ||
using T = PrimConv<PT_Uint16>::T; | using T = PrimConv<PT_Uint16>::T; | ||
Field.deref<T>() = T::from(CodePoint, BitWidth); | Field.deref<T>() = T::from(CodePoint, BitWidth); | ||
- Field.initialize(); | |||
break; | break; | ||
} | } | ||
case PT_Uint32: { | case PT_Uint32: { | ||
using T = PrimConv<PT_Uint32>::T; | using T = PrimConv<PT_Uint32>::T; | ||
Field.deref<T>() = T::from(CodePoint, BitWidth); | Field.deref<T>() = T::from(CodePoint, BitWidth); | ||
- Field.initialize(); | |||
break; | break; | ||
} | } | ||
default: | default: | ||
llvm_unreachable | llvm_unreachable | ||
} | } | ||
} | } | ||
- return I; | + Ptr.initialize(); | ||
+ | |||
+ return GlobalIndex; | |||
} | } | ||
Pointer Program::getPtrGlobal(unsigned Idx) const { | Pointer Program::getPtrGlobal(unsigned Idx) const { |
@@ -196,6 +196,15 @@ const char *skipWhitespace( | |||
return BufferEnd; | return BufferEnd; | ||
} | } | ||
+const char *skipHorizontalWh | |||
+ const char *BufferEnd) { | |||
+ for (; BufferPtr != BufferEnd; ++BufferPtr) { | |||
+ if (!isHorizontalWhit | |||
+ return BufferPtr; | |||
+ } | |||
+ return BufferEnd; | |||
+} | |||
+ | |||
bool isWhitespace(const char *BufferPtr, const char *BufferEnd) { | bool isWhitespace(const char *BufferPtr, const char *BufferEnd) { | ||
return skipWhitespace(BufferPtr, BufferEnd) == BufferEnd; | return skipWhitespace(BufferPtr, BufferEnd) == BufferEnd; | ||
} | } | ||
@@ -637,17 +646,41 @@ void Lexer::setupAndL | |||
formTokenWithCha | formTokenWithCha | ||
T.setHTMLTagStartN | T.setHTMLTagStartN | ||
- BufferPtr = | + BufferPtr = skipHorizontalWhitespace(BufferPtr, CommentEnd); | ||
+ if (BufferPtr == CommentEnd) { // in BCPL comments | |||
+ State = LS_HTMLStartTag; | |||
+ return; | |||
+ } | |||
const char C = *BufferPtr; | const char C = *BufferPtr; | ||
if (BufferPtr != CommentEnd && | if (BufferPtr != CommentEnd && | ||
- (C == '>' || C == '/' || | + (C == '>' || C == '/' || isVerticalWhitespace(C) || | ||
+ isHTMLIdentifier | |||
State = LS_HTMLStartTag; | State = LS_HTMLStartTag; | ||
} | } | ||
void Lexer::lexHTMLStartTag(Token &T) { | void Lexer::lexHTMLStartTag(Token &T) { | ||
assert(State == LS_HTMLStartTag); | assert(State == LS_HTMLStartTag); | ||
+ // Skip leading whitespace and comment decorations | |||
+ while (isVerticalWhites | |||
+ BufferPtr = skipNewline(BufferPtr, CommentEnd); | |||
+ | |||
+ if (CommentState == LCS_InsideCComme | |||
+ skipLineStarting | |||
+ | |||
+ BufferPtr = skipHorizontalWh | |||
+ if (BufferPtr == CommentEnd) { | |||
+ // HTML starting tags must be defined in a single comment block. | |||
+ // It's likely a user-error where they forgot to terminate the comment. | |||
+ State = LS_Normal; | |||
+ // Since at least one newline was skipped and one token needs to be lexed, | |||
+ // return a newline. | |||
+ formTokenWithCha | |||
+ return; | |||
+ } | |||
+ } | |||
+ | |||
const char *TokenPtr = BufferPtr; | const char *TokenPtr = BufferPtr; | ||
char C = *TokenPtr; | char C = *TokenPtr; | ||
if (isHTMLIdentifier | if (isHTMLIdentifier | ||
@@ -693,14 +726,13 @@ void Lexer::lexHTMLSt | |||
// Now look ahead and return to normal state if we don't see any HTML tokens | // Now look ahead and return to normal state if we don't see any HTML tokens | ||
// ahead. | // ahead. | ||
- BufferPtr = | + BufferPtr = skipHorizontalWhitespace(BufferPtr, CommentEnd); | ||
if (BufferPtr == CommentEnd) { | if (BufferPtr == CommentEnd) { | ||
- State = LS_Normal; | |||
return; | return; | ||
} | } | ||
C = *BufferPtr; | C = *BufferPtr; | ||
- if (!isHTMLIdentifierStartingCharacter(C) && | + if (!isHTMLIdentifierStartingCharacter(C) && !isVerticalWhitespace(C) && | ||
C != '=' && C != '\"' && C != '\'' && C != '>' && C != '/') { | C != '=' && C != '\"' && C != '\'' && C != '>' && C != '/') { | ||
State = LS_Normal; | State = LS_Normal; | ||
return; | return; | ||
@@ -774,8 +806,17 @@ again: | |||
BufferPtr++; | BufferPtr++; | ||
CommentState = LCS_InsideBCPLCo | CommentState = LCS_InsideBCPLCo | ||
- if (State != LS_VerbatimBlock | + switch (State) { | ||
+ case LS_VerbatimBlock | |||
+ case LS_VerbatimBlock | |||
+ break; | |||
+ case LS_HTMLStartTag: | |||
+ BufferPtr = skipHorizontalWh | |||
+ break; | |||
+ default: | |||
State = LS_Normal; | State = LS_Normal; | ||
+ break; | |||
+ } | |||
CommentEnd = findBCPLCommentE | CommentEnd = findBCPLCommentE | ||
goto again; | goto again; | ||
} | } | ||
@@ -807,6 +848,14 @@ again: | |||
while(EndWhitespace != BufferEnd && *EndWhitespace != '/') | while(EndWhitespace != BufferEnd && *EndWhitespace != '/') | ||
EndWhitespace++; | EndWhitespace++; | ||
+ // When lexing the start of an HTML tag (i.e. going through the attributes) | |||
+ // there won't be any newlines generated. | |||
+ if (State == LS_HTMLStartTag && EndWhitespace != BufferEnd) { | |||
+ CommentState = LCS_BeforeCommen | |||
+ BufferPtr = EndWhitespace; | |||
+ goto again; | |||
+ } | |||
+ | |||
// Turn any whitespace between comments (and there is only whitespace | // Turn any whitespace between comments (and there is only whitespace | ||
// between them -- guaranteed by comment extraction) into a newline. We | // between them -- guaranteed by comment extraction) into a newline. We | ||
// have two newlines between C comments in total (first one was synthesized | // have two newlines between C comments in total (first one was synthesized | ||
@@ -829,6 +878,14 @@ again: | |||
BufferPtr += 2; | BufferPtr += 2; | ||
assert(BufferPtr <= BufferEnd); | assert(BufferPtr <= BufferEnd); | ||
+ // When lexing the start of an HTML tag (i.e. going through the | |||
+ // attributes) there won't be any newlines generated - whitespace still | |||
+ // needs to be skipped. | |||
+ if (State == LS_HTMLStartTag && BufferPtr != BufferEnd) { | |||
+ CommentState = LCS_BetweenComme | |||
+ goto again; | |||
+ } | |||
+ | |||
// Synthenize newline just after the C comment, regardless if there is | // Synthenize newline just after the C comment, regardless if there is | ||
// actually a newline. | // actually a newline. | ||
formTokenWithCha | formTokenWithCha |
@@ -3065,6 +3065,7 @@ FunctionDecl::Fu | |||
FunctionDeclBits | FunctionDeclBits | ||
FunctionDeclBits | FunctionDeclBits | ||
FunctionDeclBits | FunctionDeclBits | ||
+ FunctionDeclBits | |||
FunctionDeclBits | FunctionDeclBits | ||
FunctionDeclBits | FunctionDeclBits | ||
FunctionDeclBits | FunctionDeclBits |
@@ -1203,6 +1203,8 @@ const FunctionType *Decl::getFuncti | |||
if (Ty->isFunctionPointe | if (Ty->isFunctionPointe | ||
Ty = Ty->castAs<PointerType>()->getPointeeType(); | Ty = Ty->castAs<PointerType>()->getPointeeType(); | ||
+ else if (Ty->isMemberFunction | |||
+ Ty = Ty->castAs<MemberPointerTyp | |||
else if (Ty->isFunctionRefere | else if (Ty->isFunctionRefere | ||
Ty = Ty->castAs<ReferenceType>()->getPointeeType(); | Ty = Ty->castAs<ReferenceType>()->getPointeeType(); | ||
else if (BlocksToo && Ty->isBlockPointerTy | else if (BlocksToo && Ty->isBlockPointerTy |
@@ -957,18 +957,17 @@ FunctionTemplate | |||
// ClassTemplateSpe | // ClassTemplateSpe | ||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||
- | +ClassTemplateSpecializationDecl::ClassTemplateSpecializationDecl( | ||
-ClassTemplateSpe | + ASTContext &Context, Kind DK, TagKind TK, DeclContext *DC, | ||
- DeclContext *DC, SourceLocation StartLoc, | + SourceLocation StartLoc, SourceLocation IdLoc, | ||
- SourceLocation IdLoc, | + ClassTemplateDec | ||
- ClassTemplateDec | + bool StrictPackMatch, | ||
- ArrayRef<TemplateArgument | |||
- ClassTemplateSpe | |||
: CXXRecordDecl(DK, TK, Context, DC, StartLoc, IdLoc, | : CXXRecordDecl(DK, TK, Context, DC, StartLoc, IdLoc, | ||
SpecializedTempl | SpecializedTempl | ||
- | + SpecializedTemplate(SpecializedTemplate), | ||
- | + TemplateArgs(TemplateArgumentList::CreateCopy(Context, Args)), | ||
- SpecializationKi | + SpecializationKi | ||
+ assert(DK == Kind::ClassTemplateSpe | |||
} | } | ||
ClassTemplateSpe | ClassTemplateSpe | ||
@@ -977,18 +976,14 @@ ClassTemplateSpe | |||
SourceLocation(), nullptr, nullptr), | SourceLocation(), nullptr, nullptr), | ||
SpecializationKi | SpecializationKi | ||
-ClassTemplateSpecializationDecl * | +ClassTemplateSpecializationDecl *ClassTemplateSpecializationDecl::Create( | ||
-ClassTemplateSpe | + ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc, | ||
- DeclContext *DC, | + SourceLocation IdLoc, ClassTemplateDec | ||
- SourceLocation StartLoc, | + ArrayRef<TemplateArgument | ||
- SourceLocation IdLoc, | + ClassTemplateSpe | ||
- ClassTemplateDec | + auto *Result = new (Context, DC) ClassTemplateSpe | ||
- ArrayRef<TemplateArgument | + Context, ClassTemplateSpe | ||
- ClassTemplateSpe | + SpecializedTempl | ||
- auto *Result = | |||
- new (Context, DC) ClassTemplateSpe | |||
- Context, ClassTemplateSpe | |||
- SpecializedTempl | |||
Result->setMayHaveOutOfD | Result->setMayHaveOutOfD | ||
// If the template decl is incomplete, copy the external lexical storage from | // If the template decl is incomplete, copy the external lexical storage from | ||
@@ -1175,7 +1170,9 @@ ClassTemplatePar | |||
ClassTemplatePar | ClassTemplatePar | ||
: ClassTemplateSpe | : ClassTemplateSpe | ||
Context, ClassTemplatePar | Context, ClassTemplatePar | ||
- SpecializedTempl | + // Tracking StrictPackMatch for Partial | ||
+ // Specializations is not needed. | |||
+ SpecializedTempl | |||
TemplateParams(Params), InstantiatedFrom | TemplateParams(Params), InstantiatedFrom | ||
if (AdoptTemplatePar | if (AdoptTemplatePar | ||
setInvalidDecl(); | setInvalidDecl(); |
@@ -1956,6 +1956,7 @@ bool CastExpr::CastCo | |||
case CK_FixedPointToB | case CK_FixedPointToB | ||
case CK_HLSLArrayRVal | case CK_HLSLArrayRVal | ||
case CK_HLSLVectorTru | case CK_HLSLVectorTru | ||
+ case CK_HLSLElementwi | |||
CheckNoBasePath: | CheckNoBasePath: | ||
assert(path_empty() && "Cast kind should not have a base path!"); | assert(path_empty() && "Cast kind should not have a base path!"); | ||
break; | break; |
@@ -12536,10 +12536,9 @@ static const Expr *ignorePointerCa | |||
static bool isDesignatorAtOb | static bool isDesignatorAtOb | ||
assert(!LVal.Designator.Invalid); | assert(!LVal.Designator.Invalid); | ||
- auto IsLastOrInvalidFieldDecl = [&Ctx](const FieldDecl *FD | + auto IsLastOrInvalidFieldDecl = [&Ctx](const FieldDecl *FD) { | ||
const RecordDecl *Parent = FD->getParent(); | const RecordDecl *Parent = FD->getParent(); | ||
- Invalid = Parent->isInvalidDecl(); | + if (Parent->isInvalidDecl() || Parent->isUnion()) | ||
- if (Invalid || Parent->isUnion()) | |||
return true; | return true; | ||
const ASTRecordLayout &Layout = Ctx.getASTRecordLayo | const ASTRecordLayout &Layout = Ctx.getASTRecordLayo | ||
return FD->getFieldIndex() + 1 == Layout.getFieldCount(); | return FD->getFieldIndex() + 1 == Layout.getFieldCount(); | ||
@@ -12548,14 +12547,12 @@ static bool isDesignatorAtOb | |||
auto &Base = LVal.getLValueBase(); | auto &Base = LVal.getLValueBase(); | ||
if (auto *ME = dyn_cast_or_null | if (auto *ME = dyn_cast_or_null | ||
if (auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) { | if (auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) { | ||
- bool Invalid; | + if (!IsLastOrInvalidF | ||
- if (!IsLastOrInvalidF | + return false; | ||
- return Invalid; | |||
} else if (auto *IFD = dyn_cast<IndirectFieldDec | } else if (auto *IFD = dyn_cast<IndirectFieldDec | ||
for (auto *FD : IFD->chain()) { | for (auto *FD : IFD->chain()) { | ||
- bool Invalid; | + if (!IsLastOrInvalidF | ||
- if (!IsLastOrInvalidF | + return false; | ||
- return Invalid; | |||
} | } | ||
} | } | ||
} | } | ||
@@ -12591,9 +12588,8 @@ static bool isDesignatorAtOb | |||
return false; | return false; | ||
BaseType = CT->getElementType(); | BaseType = CT->getElementType(); | ||
} else if (auto *FD = getAsField(Entry)) { | } else if (auto *FD = getAsField(Entry)) { | ||
- bool Invalid; | + if (!IsLastOrInvalidF | ||
- if (!IsLastOrInvalidF | + return false; | ||
- return Invalid; | |||
BaseType = FD->getType(); | BaseType = FD->getType(); | ||
} else { | } else { | ||
assert(getAsBaseClass(Entry) && "Expecting cast to a base class"); | assert(getAsBaseClass(Entry) && "Expecting cast to a base class"); | ||
@@ -15047,6 +15043,7 @@ bool IntExprEvaluator | |||
case CK_NoOp: | case CK_NoOp: | ||
case CK_LValueToRValu | case CK_LValueToRValu | ||
case CK_HLSLArrayRVal | case CK_HLSLArrayRVal | ||
+ case CK_HLSLElementwi | |||
return ExprEvaluatorBas | return ExprEvaluatorBas | ||
case CK_MemberPointer | case CK_MemberPointer | ||
@@ -15905,6 +15902,7 @@ bool ComplexExprEvalu | |||
case CK_IntegralToFix | case CK_IntegralToFix | ||
case CK_MatrixCast: | case CK_MatrixCast: | ||
case CK_HLSLVectorTru | case CK_HLSLVectorTru | ||
+ case CK_HLSLElementwi | |||
llvm_unreachable | llvm_unreachable | ||
case CK_LValueToRValu | case CK_LValueToRValu |
@@ -1003,6 +1003,11 @@ void JSONNodeDumper:: | |||
void JSONNodeDumper::VisitCXXRecordDe | void JSONNodeDumper::VisitCXXRecordDe | ||
VisitRecordDecl(RD); | VisitRecordDecl(RD); | ||
+ if (const auto *CTSD = dyn_cast<ClassTemplateSpe | |||
+ if (CTSD->hasStrictPackMat | |||
+ JOS.attribute("strict-pack-match", true); | |||
+ } | |||
+ | |||
// All other information requires a complete definition. | // All other information requires a complete definition. | ||
if (!RD->isCompleteDefini | if (!RD->isCompleteDefini | ||
return; | return; |
@@ -2810,49 +2810,13 @@ void MicrosoftCXXName | |||
break; | break; | ||
#include "clang/Basic/HLSLIntangibleTy | #include "clang/Basic/HLSLIntangibleTy | ||
-#define SVE_TYPE(Name, Id, SingletonId) \ | + // Issue an error for any type not explicitly handled. | ||
- case BuiltinType::Id: | + default: | ||
-#define SVE_SCALAR_TYPE(Name, MangledName, Id, SingletonId, Bits) | |||
-#include "clang/Basic/AArch64SVEACLETy | |||
-#define PPC_VECTOR_TYPE(Name, Id, Size) \ | |||
- case BuiltinType::Id: | |||
-#include "clang/Basic/PPCTypes.def" | |||
-#define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id: | |||
-#include "clang/Basic/RISCVVTypes.def" | |||
-#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id: | |||
-#include "clang/Basic/AMDGPUTypes.def" | |||
- case BuiltinType::ShortAccum: | |||
- case BuiltinType::Accum: | |||
- case BuiltinType::LongAccum: | |||
- case BuiltinType::UShortAccum: | |||
- case BuiltinType::UAccum: | |||
- case BuiltinType::ULongAccum: | |||
- case BuiltinType::ShortFract: | |||
- case BuiltinType::Fract: | |||
- case BuiltinType::LongFract: | |||
- case BuiltinType::UShortFract: | |||
- case BuiltinType::UFract: | |||
- case BuiltinType::ULongFract: | |||
- case BuiltinType::SatShortAccum: | |||
- case BuiltinType::SatAccum: | |||
- case BuiltinType::SatLongAccum: | |||
- case BuiltinType::SatUShortAccum: | |||
- case BuiltinType::SatUAccum: | |||
- case BuiltinType::SatULongAccum: | |||
- case BuiltinType::SatShortFract: | |||
- case BuiltinType::SatFract: | |||
- case BuiltinType::SatLongFract: | |||
- case BuiltinType::SatUShortFract: | |||
- case BuiltinType::SatUFract: | |||
- case BuiltinType::SatULongFract: | |||
- case BuiltinType::Ibm128: | |||
- case BuiltinType::Float128: { | |||
Error(Range.getBegin(), "built-in type: ", | Error(Range.getBegin(), "built-in type: ", | ||
T->getName(Context.getASTContext().getPrintingPolic | T->getName(Context.getASTContext().getPrintingPolic | ||
<< Range; | << Range; | ||
break; | break; | ||
} | } | ||
- } | |||
} | } | ||
// <type> ::= <function-type> | // <type> ::= <function-type> |
@@ -2073,6 +2073,11 @@ void OMPClausePrinter | |||
OS << "no_openmp_routin | OS << "no_openmp_routin | ||
} | } | ||
+void OMPClausePrinter | |||
+ OMPNoOpenMPConst | |||
+ OS << "no_openmp_constr | |||
+} | |||
+ | |||
void OMPClausePrinter | void OMPClausePrinter | ||
OS << "no_parallelism"; | OS << "no_parallelism"; | ||
} | } | ||
@@ -2927,9 +2932,13 @@ llvm::raw_ostrea | |||
TargetOMPContext | TargetOMPContext | ||
ASTContext &ASTCtx, std::function<void(StringRef)> &&DiagUnknownTrait | ASTContext &ASTCtx, std::function<void(StringRef)> &&DiagUnknownTrait | ||
const FunctionDecl *CurrentFunctionD | const FunctionDecl *CurrentFunctionD | ||
- ArrayRef<llvm::omp::TraitProperty> ConstructTraits) | + ArrayRef<llvm::omp::TraitProperty> ConstructTraits, int DeviceNum) | ||
: OMPContext(ASTCtx.getLangOpts().OpenMPIsTargetDe | : OMPContext(ASTCtx.getLangOpts().OpenMPIsTargetDe | ||
- ASTCtx.getTargetInfo().getTriple() | + ASTCtx.getTargetInfo().getTriple(), | ||
+ ASTCtx.getLangOpts().OMPTargetTriples | |||
+ ? llvm::Triple() | |||
+ : ASTCtx.getLangOpts().OMPTargetTriples | |||
+ DeviceNum), | |||
FeatureValidityC | FeatureValidityC | ||
return ASTCtx.getTargetInfo().isValidFeatureNa | return ASTCtx.getTargetInfo().isValidFeatureNa | ||
}), | }), |
@@ -13,7 +13,6 @@ | |||
#include "clang/AST/ParentMap.h" | #include "clang/AST/ParentMap.h" | ||
#include "clang/AST/Decl.h" | #include "clang/AST/Decl.h" | ||
#include "clang/AST/Expr.h" | #include "clang/AST/Expr.h" | ||
-#include "clang/AST/ExprCXX.h" | |||
#include "clang/AST/StmtObjC.h" | #include "clang/AST/StmtObjC.h" | ||
#include "llvm/ADT/DenseMap.h" | #include "llvm/ADT/DenseMap.h" | ||
@@ -104,22 +103,6 @@ static void BuildParentMap(M | |||
BuildParentMap(M, SubStmt, OVMode); | BuildParentMap(M, SubStmt, OVMode); | ||
} | } | ||
break; | break; | ||
- case Stmt::CXXDefaultArgExp | |||
- if (auto *Arg = dyn_cast<CXXDefaultArgExp | |||
- if (Arg->hasRewrittenInit | |||
- M[Arg->getExpr()] = S; | |||
- BuildParentMap(M, Arg->getExpr(), OVMode); | |||
- } | |||
- } | |||
- break; | |||
- case Stmt::CXXDefaultInitEx | |||
- if (auto *Init = dyn_cast<CXXDefaultInitEx | |||
- if (Init->hasRewrittenInit | |||
- M[Init->getExpr()] = S; | |||
- BuildParentMap(M, Init->getExpr(), OVMode); | |||
- } | |||
- } | |||
- break; | |||
default: | default: | ||
for (Stmt *SubStmt : S->children()) { | for (Stmt *SubStmt : S->children()) { | ||
if (SubStmt) { | if (SubStmt) { |
@@ -287,13 +287,13 @@ void RawCommentList:: | |||
// If this is the first Doxygen comment, save it (because there isn't | // If this is the first Doxygen comment, save it (because there isn't | ||
// anything to merge it with). | // anything to merge it with). | ||
- if (OrderedComments[CommentFile].empty()) { | + auto &OC = OrderedComments[CommentFile]; | ||
- OrderedComments[CommentFile][CommentOffset] = | + if (OC.empty()) { | ||
- | + OC[CommentOffset] = new (Allocator) RawComment(RC); | ||
return; | return; | ||
} | } | ||
- const RawComment &C1 = * | + const RawComment &C1 = *OC.rbegin()->second; | ||
const RawComment &C2 = RC; | const RawComment &C2 = RC; | ||
// Merge comments only if there is only whitespace between them. | // Merge comments only if there is only whitespace between them. |
@@ -305,3 +305,19 @@ OpenACCUpdateCon | |||
new (Mem) OpenACCUpdateCon | new (Mem) OpenACCUpdateCon | ||
return Inst; | return Inst; | ||
} | } | ||
+ | |||
+OpenACCAtomicCon | |||
+OpenACCAtomicCon | |||
+ void *Mem = C.Allocate(sizeof(OpenACCAtomicCon | |||
+ auto *Inst = new (Mem) OpenACCAtomicCon | |||
+ return Inst; | |||
+} | |||
+ | |||
+OpenACCAtomicCon | |||
+ const ASTContext &C, SourceLocation Start, SourceLocation DirectiveLoc, | |||
+ OpenACCAtomicKin | |||
+ void *Mem = C.Allocate(sizeof(OpenACCAtomicCon | |||
+ auto *Inst = new (Mem) | |||
+ OpenACCAtomicCon | |||
+ return Inst; | |||
+} |
@@ -1242,6 +1242,16 @@ void StmtPrinter::Vis | |||
OS << '\n'; | OS << '\n'; | ||
} | } | ||
+void StmtPrinter::VisitOpenACCAtom | |||
+ Indent() << "#pragma acc atomic"; | |||
+ | |||
+ if (S->getAtomicKind() != OpenACCAtomicKin | |||
+ OS << " " << S->getAtomicKind(); | |||
+ | |||
+ OS << '\n'; | |||
+ PrintStmt(S->getAssociatedStm | |||
+} | |||
+ | |||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||
// Expr printing methods. | // Expr printing methods. | ||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||
@@ -1967,7 +1977,6 @@ void StmtPrinter::Vis | |||
void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) { | void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) { | ||
const char *Name = nullptr; | const char *Name = nullptr; | ||
switch (Node->getOp()) { | switch (Node->getOp()) { | ||
-#define BUILTIN(ID, TYPE, ATTRS) | |||
#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \ | #define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \ | ||
case AtomicExpr::AO ## ID: \ | case AtomicExpr::AO ## ID: \ | ||
Name = #ID "("; \ | Name = #ID "("; \ |
@@ -606,6 +606,9 @@ void OMPClauseProfile | |||
void OMPClauseProfile | void OMPClauseProfile | ||
const OMPNoOpenMPRouti | const OMPNoOpenMPRouti | ||
+void OMPClauseProfile | |||
+ const OMPNoOpenMPConst | |||
+ | |||
void OMPClauseProfile | void OMPClauseProfile | ||
const OMPNoParallelism | const OMPNoParallelism | ||
@@ -2809,6 +2812,11 @@ void StmtProfiler::Vi | |||
P.VisitOpenACCClau | P.VisitOpenACCClau | ||
} | } | ||
+void StmtProfiler::VisitOpenACCAtom | |||
+ const OpenACCAtomicCon | |||
+ VisitStmt(S); | |||
+} | |||
+ | |||
void StmtProfiler::VisitHLSLOutArgE | void StmtProfiler::VisitHLSLOutArgE | ||
VisitStmt(S); | VisitStmt(S); | ||
} | } |
@@ -2525,8 +2525,11 @@ void TextNodeDumper:: | |||
OS << " instantiated_fro | OS << " instantiated_fro | ||
dumpPointer(Instance); | dumpPointer(Instance); | ||
} | } | ||
- if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) | + if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { | ||
dumpTemplateSpec | dumpTemplateSpec | ||
+ if (CTSD->hasStrictPackMat | |||
+ OS << " strict-pack-match"; | |||
+ } | |||
dumpNestedNameSp | dumpNestedNameSp | ||
@@ -3041,6 +3044,12 @@ void TextNodeDumper:: | |||
VisitOpenACCCons | VisitOpenACCCons | ||
} | } | ||
+void TextNodeDumper::VisitOpenACCAtom | |||
+ const OpenACCAtomicCon | |||
+ VisitOpenACCCons | |||
+ OS << ' ' << S->getAtomicKind(); | |||
+} | |||
+ | |||
void TextNodeDumper::VisitEmbedExpr(const EmbedExpr *S) { | void TextNodeDumper::VisitEmbedExpr(const EmbedExpr *S) { | ||
AddChild("begin", [=] { OS << S->getStartingEleme | AddChild("begin", [=] { OS << S->getStartingEleme | ||
AddChild("number of elements", [=] { OS << S->getDataElementCo | AddChild("number of elements", [=] { OS << S->getDataElementCo |
@@ -1169,12 +1169,13 @@ void ItaniumVTableBui | |||
// | // | ||
// Do not set ThunkInfo::Method if Idx is already in VTableThunks. This | // Do not set ThunkInfo::Method if Idx is already in VTableThunks. This | ||
// can happen when covariant return adjustment is required too. | // can happen when covariant return adjustment is required too. | ||
- if (!VTableThunks.count(Idx)) { | + auto [It, Inserted] = VTableThunks.try_emplace(Idx); | ||
+ if (Inserted) { | |||
const CXXMethodDecl *Method = VTables.findOriginalMeth | const CXXMethodDecl *Method = VTables.findOriginalMeth | ||
- | + It->second.Method = Method; | ||
- | + It->second.ThisType = Method->getThisType().getTypePtr(); | ||
} | } | ||
- | + It->second.This = ThisAdjustment; | ||
}; | }; | ||
SetThisAdjustmen | SetThisAdjustmen | ||
@@ -1653,8 +1654,9 @@ void ItaniumVTableBui | |||
// findOriginalMeth | // findOriginalMeth | ||
// method in the entry requires adjustment. | // method in the entry requires adjustment. | ||
if (!ReturnAdjustment | if (!ReturnAdjustment | ||
- VTableThunks[Components.size()] | + auto &VTT = VTableThunks[Components.size()]; | ||
- VTableThunks[Components.size()].ThisType = MD->getThisType().getTypePtr(); | + VTT.Method = MD; | ||
+ VTT.ThisType = MD->getThisType().getTypePtr(); | |||
} | } | ||
AddMethod(Overrider.Method, ReturnAdjustment | AddMethod(Overrider.Method, ReturnAdjustment |
@@ -556,10 +556,6 @@ public: | |||
private: | private: | ||
// Visitors to walk an AST and construct the CFG. | // Visitors to walk an AST and construct the CFG. | ||
- CFGBlock *VisitCXXDefaultA | |||
- AddStmtChoice asc); | |||
- CFGBlock *VisitCXXDefaultI | |||
- AddStmtChoice asc); | |||
CFGBlock *VisitInitListExp | CFGBlock *VisitInitListExp | ||
CFGBlock *VisitAddrLabelEx | CFGBlock *VisitAddrLabelEx | ||
CFGBlock *VisitAttributedS | CFGBlock *VisitAttributedS | ||
@@ -2045,6 +2041,8 @@ void CFGBuilder::addI | |||
} | } | ||
// First destroy member objects. | // First destroy member objects. | ||
+ if (RD->isUnion()) | |||
+ return; | |||
for (auto *FI : RD->fields()) { | for (auto *FI : RD->fields()) { | ||
// Check for constant size array. Set type to array element type. | // Check for constant size array. Set type to array element type. | ||
QualType QT = FI->getType(); | QualType QT = FI->getType(); | ||
@@ -2265,10 +2263,16 @@ CFGBlock *CFGBuilder::Vis | |||
asc, ExternallyDestru | asc, ExternallyDestru | ||
case Stmt::CXXDefaultArgExp | case Stmt::CXXDefaultArgExp | ||
- return VisitCXXDefaultA | |||
- | |||
case Stmt::CXXDefaultInitEx | case Stmt::CXXDefaultInitEx | ||
- return VisitCXXDefaultI | + // FIXME: The expression inside a CXXDefaultArgExp | ||
+ // called function's declaration, not by the caller. If we simply add | |||
+ // this expression to the CFG, we could end up with the same Expr | |||
+ // appearing multiple times (PR13385). | |||
+ // | |||
+ // It's likewise possible for multiple CXXDefaultInitEx | |||
+ // expression to be used in the same function (through aggregate | |||
+ // initialization). | |||
+ return VisitStmt(S, asc); | |||
case Stmt::CXXBindTemporary | case Stmt::CXXBindTemporary | ||
return VisitCXXBindTemp | return VisitCXXBindTemp | ||
@@ -2438,40 +2442,6 @@ CFGBlock *CFGBuilder::Vis | |||
return B; | return B; | ||
} | } | ||
-CFGBlock *CFGBuilder::VisitCXXDefaultA | |||
- AddStmtChoice asc) { | |||
- if (Arg->hasRewrittenInit | |||
- if (asc.alwaysAdd(*this, Arg)) { | |||
- autoCreateBlock(); | |||
- appendStmt(Block, Arg); | |||
- } | |||
- return VisitStmt(Arg->getExpr(), asc); | |||
- } | |||
- | |||
- // We can't add the default argument if it's not rewritten because the | |||
- // expression inside a CXXDefaultArgExp | |||
- // declaration, not by the caller, we could end up with the same expression | |||
- // appearing multiple times. | |||
- return VisitStmt(Arg, asc); | |||
-} | |||
- | |||
-CFGBlock *CFGBuilder::VisitCXXDefaultI | |||
- AddStmtChoice asc) { | |||
- if (Init->hasRewrittenInit | |||
- if (asc.alwaysAdd(*this, Init)) { | |||
- autoCreateBlock(); | |||
- appendStmt(Block, Init); | |||
- } | |||
- return VisitStmt(Init->getExpr(), asc); | |||
- } | |||
- | |||
- // We can't add the default initializer if it's not rewritten because multiple | |||
- // CXXDefaultInitEx | |||
- // function (through aggregate initialization). we could end up with the same | |||
- // expression appearing multiple times. | |||
- return VisitStmt(Init, asc); | |||
-} | |||
- | |||
CFGBlock *CFGBuilder::VisitInitListExp | CFGBlock *CFGBuilder::VisitInitListExp | ||
if (asc.alwaysAdd(*this, ILE)) { | if (asc.alwaysAdd(*this, ILE)) { | ||
autoCreateBlock(); | autoCreateBlock(); |
@@ -42,7 +42,8 @@ bool hasSmartPointerC | |||
HasStar = true; | HasStar = true; | ||
StarReturnType = MD->getReturnType() | StarReturnType = MD->getReturnType() | ||
.getNonReferenceT | .getNonReferenceT | ||
- ->getCanonicalTypeUnqualified() | + ->getCanonicalTypeUnqualified() | ||
+ .getUnqualifiedTy | |||
} | } | ||
break; | break; | ||
case OO_Arrow: | case OO_Arrow: | ||
@@ -50,7 +51,8 @@ bool hasSmartPointerC | |||
HasArrow = true; | HasArrow = true; | ||
ArrowReturnType = MD->getReturnType() | ArrowReturnType = MD->getReturnType() | ||
->getPointeeType() | ->getPointeeType() | ||
- ->getCanonicalTypeUnqualified() | + ->getCanonicalTypeUnqualified() | ||
+ .getUnqualifiedTy | |||
} | } | ||
break; | break; | ||
case OO_None: { | case OO_None: { | ||
@@ -62,14 +64,16 @@ bool hasSmartPointerC | |||
HasGet = true; | HasGet = true; | ||
GetReturnType = MD->getReturnType() | GetReturnType = MD->getReturnType() | ||
->getPointeeType() | ->getPointeeType() | ||
- ->getCanonicalTypeUnqualified() | + ->getCanonicalTypeUnqualified() | ||
+ .getUnqualifiedTy | |||
} | } | ||
} else if (II->isStr("value")) { | } else if (II->isStr("value")) { | ||
if (MD->getReturnType()->isReferenceType()) { | if (MD->getReturnType()->isReferenceType()) { | ||
HasValue = true; | HasValue = true; | ||
ValueReturnType = MD->getReturnType() | ValueReturnType = MD->getReturnType() | ||
.getNonReferenceT | .getNonReferenceT | ||
- ->getCanonicalTypeUnqualified() | + ->getCanonicalTypeUnqualified() | ||
+ .getUnqualifiedTy | |||
} | } | ||
} | } | ||
} break; | } break; |
@@ -49,6 +49,121 @@ LLVM_DUMP_METHOD | |||
return printJson(llvm::errs()); | return printJson(llvm::errs()); | ||
} | } | ||
+StringRef ProgramPoint::getProgramPointK | |||
+ switch (K) { | |||
+ case BlockEdgeKind: | |||
+ return "BlockEdge"; | |||
+ case BlockEntranceKin | |||
+ return "BlockEntrance"; | |||
+ case BlockExitKind: | |||
+ return "BlockExit"; | |||
+ case PreStmtKind: | |||
+ return "PreStmt"; | |||
+ case PreStmtPurgeDead | |||
+ return "PreStmtPurgeDead | |||
+ case PostStmtPurgeDea | |||
+ return "PostStmtPurgeDea | |||
+ case PostStmtKind: | |||
+ return "PostStmt"; | |||
+ case PreLoadKind: | |||
+ return "PreLoad"; | |||
+ case PostLoadKind: | |||
+ return "PostLoad"; | |||
+ case PreStoreKind: | |||
+ return "PreStore"; | |||
+ case PostStoreKind: | |||
+ return "PostStore"; | |||
+ case PostConditionKin | |||
+ return "PostCondition"; | |||
+ case PostLValueKind: | |||
+ return "PostLValue"; | |||
+ case PostAllocatorCal | |||
+ return "PostAllocatorCal | |||
+ case PostInitializerK | |||
+ return "PostInitializer"; | |||
+ case CallEnterKind: | |||
+ return "CallEnter"; | |||
+ case CallExitBeginKin | |||
+ return "CallExitBegin"; | |||
+ case CallExitEndKind: | |||
+ return "CallExitEnd"; | |||
+ case FunctionExitKind | |||
+ return "FunctionExit"; | |||
+ case PreImplicitCallK | |||
+ return "PreImplicitCall"; | |||
+ case PostImplicitCall | |||
+ return "PostImplicitCall | |||
+ case LoopExitKind: | |||
+ return "LoopExit"; | |||
+ case EpsilonKind: | |||
+ return "Epsilon"; | |||
+ } | |||
+ llvm_unreachable | |||
+} | |||
+ | |||
+std::optional<SourceLocation> ProgramPoint::getSourceLocatio | |||
+ switch (getKind()) { | |||
+ case BlockEdgeKind: | |||
+ // If needed, the source and or destination beginning can be used to get | |||
+ // source location. | |||
+ return std::nullopt; | |||
+ case BlockEntranceKin | |||
+ // If needed, first statement of the block can be used. | |||
+ return std::nullopt; | |||
+ case BlockExitKind: | |||
+ if (const auto *B = castAs<BlockExit>().getBlock()) { | |||
+ if (const auto *T = B->getTerminatorStm | |||
+ return T->getBeginLoc(); | |||
+ } | |||
+ } | |||
+ return std::nullopt; | |||
+ case PreStmtKind: | |||
+ case PreStmtPurgeDead | |||
+ case PostStmtPurgeDea | |||
+ case PostStmtKind: | |||
+ case PreLoadKind: | |||
+ case PostLoadKind: | |||
+ case PreStoreKind: | |||
+ case PostStoreKind: | |||
+ case PostConditionKin | |||
+ case PostLValueKind: | |||
+ case PostAllocatorCal | |||
+ if (const Stmt *S = castAs<StmtPoint>().getStmt()) | |||
+ return S->getBeginLoc(); | |||
+ return std::nullopt; | |||
+ case PostInitializerK | |||
+ if (const auto *Init = castAs<PostInitializer>().getInitializer()) | |||
+ return Init->getSourceLocatio | |||
+ return std::nullopt; | |||
+ case CallEnterKind: | |||
+ if (const Stmt *S = castAs<CallEnter>().getCallExpr()) | |||
+ return S->getBeginLoc(); | |||
+ return std::nullopt; | |||
+ case CallExitBeginKin | |||
+ if (const Stmt *S = castAs<CallExitBegin>().getReturnStmt()) | |||
+ return S->getBeginLoc(); | |||
+ return std::nullopt; | |||
+ case CallExitEndKind: | |||
+ return std::nullopt; | |||
+ case FunctionExitKind | |||
+ if (const auto *B = castAs<FunctionExitPoin | |||
+ B && B->getTerminatorStm | |||
+ return B->getTerminatorStm | |||
+ return std::nullopt; | |||
+ case PreImplicitCallK | |||
+ return castAs<ImplicitCallPoin | |||
+ case PostImplicitCall | |||
+ return castAs<ImplicitCallPoin | |||
+ case LoopExitKind: | |||
+ if (const Stmt *S = castAs<LoopExit>().getLoopStmt()) | |||
+ return S->getBeginLoc(); | |||
+ return std::nullopt; | |||
+ case EpsilonKind: | |||
+ return std::nullopt; | |||
+ } | |||
+ llvm_unreachable | |||
+} | |||
+ | |||
void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const { | void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const { | ||
const ASTContext &Context = | const ASTContext &Context = | ||
getLocationConte | getLocationConte |
@@ -454,12 +454,11 @@ bool DeadCodeScan::is | |||
return isDeadRoot; | return isDeadRoot; | ||
} | } | ||
-// Check if the given `DeadStmt` is | +// Check if the given `DeadStmt` is a coroutine statement and is a substmt of | ||
-// | +// the coroutine statement. `Block` is the CFGBlock containing the `DeadStmt`. | ||
-template <class... Ts> | +static bool isInCoroutineStm | ||
-static bool isDeadStmtInOneO | |||
// The coroutine statement, co_return, co_await, or co_yield. | // The coroutine statement, co_return, co_await, or co_yield. | ||
- const Stmt * | + const Stmt *CoroStmt = nullptr; | ||
// Find the first coroutine statement after the DeadStmt in the block. | // Find the first coroutine statement after the DeadStmt in the block. | ||
bool AfterDeadStmt = false; | bool AfterDeadStmt = false; | ||
for (CFGBlock::const_iterator I = Block->begin(), E = Block->end(); I != E; | for (CFGBlock::const_iterator I = Block->begin(), E = Block->end(); I != E; | ||
@@ -468,27 +467,32 @@ static bool isDeadStmtInOneO | |||
const Stmt *S = CS->getStmt(); | const Stmt *S = CS->getStmt(); | ||
if (S == DeadStmt) | if (S == DeadStmt) | ||
AfterDeadStmt = true; | AfterDeadStmt = true; | ||
- if (AfterDeadStmt && | + if (AfterDeadStmt && | ||
- TargetStmt = S; | + // For simplicity, we only check simple coroutine statements. | ||
+ (llvm::isa<CoreturnStmt>(S) || llvm::isa<CoroutineSuspend | |||
+ CoroStmt = S; | |||
break; | break; | ||
} | } | ||
} | } | ||
- if ( | + if (!CoroStmt) | ||
return false; | return false; | ||
struct Checker : DynamicRecursive | struct Checker : DynamicRecursive | ||
const Stmt *DeadStmt; | const Stmt *DeadStmt; | ||
- bool | + bool CoroutineSubStmt = false; | ||
- Checker(const Stmt *S) : DeadStmt(S) { | + Checker(const Stmt *S) : DeadStmt(S) { | ||
+ // Statements captured in the CFG can be implicit. | |||
+ ShouldVisitImpli | |||
+ } | |||
bool VisitStmt(Stmt *S) override { | bool VisitStmt(Stmt *S) override { | ||
if (S == DeadStmt) | if (S == DeadStmt) | ||
- | + CoroutineSubStmt = true; | ||
return true; | return true; | ||
} | } | ||
}; | }; | ||
Checker checker(DeadStmt); | Checker checker(DeadStmt); | ||
- checker.TraverseStmt(const_cast<Stmt *>( | + checker.TraverseStmt(const_cast<Stmt *>(CoroStmt)); | ||
- return checker. | + return checker.CoroutineSubStmt; | ||
} | } | ||
static bool isValidDeadStmt(const Stmt *S, const clang::CFGBlock *Block) { | static bool isValidDeadStmt(const Stmt *S, const clang::CFGBlock *Block) { | ||
@@ -499,12 +503,7 @@ static bool isValidDeadStmt( | |||
// Coroutine statements are never considered dead statements, because removing | // Coroutine statements are never considered dead statements, because removing | ||
// them may change the function semantic if it is the only coroutine statement | // them may change the function semantic if it is the only coroutine statement | ||
// of the coroutine. | // of the coroutine. | ||
- // | + return !isInCoroutineStm | ||
- // If the dead stmt is a sub-stmt of CXXDefaultInitEx | |||
- // we would rather expect to find CXXDefaultInitEx | |||
- // a valid dead stmt. | |||
- return !isDeadStmtInOneO | |||
- CXXDefaultArgExp | |||
} | } | ||
const Stmt *DeadCodeScan::findDeadCode(const clang::CFGBlock *Block) { | const Stmt *DeadCodeScan::findDeadCode(const clang::CFGBlock *Block) { |
@@ -379,8 +379,10 @@ void ClassifyRefs::cl | |||
} | } | ||
FindVarResult Var = findVar(E, DC); | FindVarResult Var = findVar(E, DC); | ||
- if (const DeclRefExpr *DRE = Var.getDeclRefExpr()) | + if (const DeclRefExpr *DRE = Var.getDeclRefExpr()) { | ||
- Classification[DRE] = std::max(Classification[DRE], C); | + auto &Class = Classification[DRE]; | ||
+ Class = std::max(Class, C); | |||
+ } | |||
} | } | ||
void ClassifyRefs::VisitDeclStmt(DeclStmt *DS) { | void ClassifyRefs::VisitDeclStmt(DeclStmt *DS) { |
@@ -930,7 +930,7 @@ AST_MATCHER(Call | |||
// The array element type must be compatible with `char` otherwise an | // The array element type must be compatible with `char` otherwise an | ||
// explicit cast will be needed, which will make this check unreachable. | // explicit cast will be needed, which will make this check unreachable. | ||
// Therefore, the array extent is same as its' bytewise size. | // Therefore, the array extent is same as its' bytewise size. | ||
- if (Size- | + if (Size->EvaluateAsInt(ER, Ctx)) { | ||
APSInt EVal = ER.Val.getInt(); // Size must have integer type | APSInt EVal = ER.Val.getInt(); // Size must have integer type | ||
return APSInt::compareValues(EVal, APSInt(CAT->getSize(), true)) != 0; | return APSInt::compareValues(EVal, APSInt(CAT->getSize(), true)) != 0; |
@@ -29,54 +29,120 @@ const char *HeaderDesc::get | |||
llvm_unreachable | llvm_unreachable | ||
} | } | ||
-static constexpr | +static constexpr unsigned NumBuiltins = Builtin::FirstTSBuiltin; | ||
- {"not a builtin function", nullptr, nullptr, nullptr, HeaderDesc::NO_HEADER, | + | ||
- ALL_LANGUAGES}, | +#define GET_BUILTIN_STR_ | ||
-#define BUILTIN(ID, TYPE, ATTRS) \ | +#include "clang/Basic/Builtins.inc" | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | +#undef GET_BUILTIN_STR_ | ||
-#define LANGBUILTIN(ID, TYPE, ATTRS, LANGS) \ | + | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, LANGS}, | +static constexpr Builtin::Info BuiltinInfos[] = { | ||
-#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, LANGS) \ | + Builtin::Info{}, // No-builtin info entry. | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, LANGS}, | +#define GET_BUILTIN_INFO | ||
#include "clang/Basic/Builtins.inc" | #include "clang/Basic/Builtins.inc" | ||
+#undef GET_BUILTIN_INFO | |||
}; | }; | ||
+static_assert(std::size(BuiltinInfos) == NumBuiltins); | |||
-const Builtin::Info &Builtin::Context::getRecord(unsigned ID) const { | +std::pair<const Builtin::InfosShard &, const Builtin::Info &> | ||
- if (ID < Builtin::FirstTSBuiltin) | +Builtin::Context::getShardAndInfo(unsigned ID) const { | ||
- return BuiltinInfo[ID]; | + assert((ID < (Builtin::FirstTSBuiltin + NumTargetBuiltin | ||
- assert(((ID - Builtin::FirstTSBuiltin) < | + NumAuxTargetBuil | ||
- (TSRecords.size() + AuxTSRecords.size())) && | |||
"Invalid builtin ID!"); | "Invalid builtin ID!"); | ||
- if (isAuxBuiltinID(ID)) | + | ||
- return AuxTSRecords[getAuxBuiltinID(ID) - Builtin::FirstTSBuiltin]; | + ArrayRef<InfosShard> Shards = BuiltinShards; | ||
- return TSRecords[ID - Builtin::FirstTSBuiltin]; | + if (isAuxBuiltinID(ID)) { | ||
+ Shards = AuxTargetShards; | |||
+ ID = getAuxBuiltinID(ID) - Builtin::FirstTSBuiltin; | |||
+ } else if (ID >= Builtin::FirstTSBuiltin) { | |||
+ Shards = TargetShards; | |||
+ ID -= Builtin::FirstTSBuiltin; | |||
+ } | |||
+ | |||
+ // Loop over the shards to find the one matching this ID. We don't expect to | |||
+ // have many shards and so its better to search linearly than with a binary | |||
+ // search. | |||
+ for (const auto &Shard : Shards) { | |||
+ if (ID < Shard.Infos.size()) { | |||
+ return {Shard, Shard.Infos[ID]}; | |||
+ } | |||
+ | |||
+ ID -= Shard.Infos.size(); | |||
+ } | |||
+ llvm_unreachable | |||
+} | |||
+ | |||
+std::string Builtin::Info::getName(const Builtin::InfosShard &Shard) const { | |||
+ return (Twine(Shard.NamePrefix) + (*Shard.Strings)[Offsets.Name]).str(); | |||
+} | |||
+ | |||
+/// Return the identifier name for the specified builtin, | |||
+/// e.g. "__builtin_abs". | |||
+std::string Builtin::Context::getName(unsigned ID) const { | |||
+ const auto &[Shard, I] = getShardAndInfo(ID); | |||
+ return I.getName(Shard); | |||
+} | |||
+ | |||
+std::string Builtin::Context::getQuotedName(unsigned ID) const { | |||
+ const auto &[Shard, I] = getShardAndInfo(ID); | |||
+ return (Twine("'") + Shard.NamePrefix + (*Shard.Strings)[I.Offsets.Name] + | |||
+ "'") | |||
+ .str(); | |||
+} | |||
+ | |||
+const char *Builtin::Context::getTypeString(unsigned ID) const { | |||
+ const auto &[Shard, I] = getShardAndInfo(ID); | |||
+ return (*Shard.Strings)[I.Offsets.Type].data(); | |||
} | } | ||
+const char *Builtin::Context::getAttributesStr | |||
+ const auto &[Shard, I] = getShardAndInfo(ID); | |||
+ return (*Shard.Strings)[I.Offsets.Attributes].data(); | |||
+} | |||
+ | |||
+const char *Builtin::Context::getRequiredFeatu | |||
+ const auto &[Shard, I] = getShardAndInfo(ID); | |||
+ return (*Shard.Strings)[I.Offsets.Features].data(); | |||
+} | |||
+ | |||
+Builtin::Context::Context() : BuiltinShards{{&BuiltinStrings, BuiltinInfos}} {} | |||
+ | |||
void Builtin::Context::InitializeTarget | void Builtin::Context::InitializeTarget | ||
const TargetInfo *AuxTarget) { | const TargetInfo *AuxTarget) { | ||
- assert( | + assert(TargetShards.empty() && "Already initialized target?"); | ||
- TSRecords = Target.getTargetBuiltin | + assert(NumTargetBuiltin | ||
- if (AuxTarget) | + TargetShards = Target.getTargetBuiltin | ||
- AuxTSRecords = AuxTarget->getTargetBuiltin | + for (const auto &Shard : TargetShards) | ||
+ NumTargetBuiltin | |||
+ if (AuxTarget) { | |||
+ AuxTargetShards = AuxTarget->getTargetBuiltin | |||
+ for (const auto &Shard : AuxTargetShards) | |||
+ NumAuxTargetBuil | |||
+ } | |||
} | } | ||
bool Builtin::Context::isBuiltinFunc(llvm::StringRef FuncName) { | bool Builtin::Context::isBuiltinFunc(llvm::StringRef FuncName) { | ||
bool InStdNamespace = FuncName.consume_front("std-"); | bool InStdNamespace = FuncName.consume_front("std-"); | ||
- for (unsigned i = Builtin::NotBuiltin + 1; i != Builtin::FirstTSBuiltin; | + for (const auto &Shard : {InfosShard{&BuiltinStrings, BuiltinInfos}}) | ||
- ++i) { | + if (llvm::StringRef FuncNameSuffix = FuncName; | ||
- if (FuncName == BuiltinInfo[i].Name && | + FuncNameSuffix.consume_front(Shard.NamePrefix)) | ||
- (bool)strchr(BuiltinInfo[i].Attributes, 'z') == InStdNamespace) | + for (const auto &I : Shard.Infos) | ||
- return strchr(BuiltinInfo[i].Attributes, 'f') != nullptr; | + if (FuncNameSuffix == (*Shard.Strings)[I.Offsets.Name] && | ||
- } | + (bool)strchr((*Shard.Strings)[I.Offsets.Attributes].data(), 'z') == | ||
+ InStdNamespace) | |||
+ return strchr((*Shard.Strings)[I.Offsets.Attributes].data(), 'f') != | |||
+ nullptr; | |||
return false; | return false; | ||
} | } | ||
/// Is this builtin supported according to the given language options? | /// Is this builtin supported according to the given language options? | ||
-static bool builtinIsSupported(const | +static bool builtinIsSupported(const llvm::StringTable &Strings, | ||
+ const Builtin::Info &BuiltinInfo, | |||
const LangOptions &LangOpts) { | const LangOptions &LangOpts) { | ||
+ auto AttributesStr = Strings[BuiltinInfo.Offsets.Attributes]; | |||
+ | |||
/* Builtins Unsupported */ | /* Builtins Unsupported */ | ||
- if (LangOpts.NoBuiltin && strchr( | + if (LangOpts.NoBuiltin && strchr(AttributesStr.data(), 'f') != nullptr) | ||
return false; | return false; | ||
/* CorBuiltins Unsupported */ | /* CorBuiltins Unsupported */ | ||
if (!LangOpts.Coroutines && (BuiltinInfo.Langs & COR_LANG)) | if (!LangOpts.Coroutines && (BuiltinInfo.Langs & COR_LANG)) | ||
@@ -123,7 +189,7 @@ static bool builtinIsSupport | |||
if (!LangOpts.CPlusPlus && BuiltinInfo.Langs == CXX_LANG) | if (!LangOpts.CPlusPlus && BuiltinInfo.Langs == CXX_LANG) | ||
return false; | return false; | ||
/* consteval Unsupported */ | /* consteval Unsupported */ | ||
- if (!LangOpts.CPlusPlus20 && strchr( | + if (!LangOpts.CPlusPlus20 && strchr(AttributesStr.data(), 'G') != nullptr) | ||
return false; | return false; | ||
return true; | return true; | ||
} | } | ||
@@ -132,22 +198,34 @@ static bool builtinIsSupport | |||
/// appropriate builtin ID # and mark any non-portable builtin identifiers as | /// appropriate builtin ID # and mark any non-portable builtin identifiers as | ||
/// such. | /// such. | ||
void Builtin::Context::initializeBuilti | void Builtin::Context::initializeBuilti | ||
- const | + const LangOptions &LangOpts) { | ||
- // Step #1: mark all target-independent builtins with their ID's. | + { | ||
- for (unsigned i = Builtin::NotBuiltin + 1; i != Builtin::FirstTSBuiltin; ++i) | + unsigned ID = 0; | ||
- if (builtinIsSupport | + // Step #1: mark all target-independent builtins with their ID's. | ||
- Table.get(BuiltinInfo[i].Name).setBuiltinID(i); | + for (const auto &Shard : BuiltinShards) | ||
- } | + for (const auto &I : Shard.Infos) { | ||
- | + // If this is a real builtin (ID != 0) and is supported, add it. | ||
- // Step #2: Register target-specific builtins. | + if (ID != 0 && builtinIsSupport | ||
- for (unsigned i = 0, e = TSRecords.size(); i != e; ++i) | + Table.get(I.getName(Shard)).setBuiltinID(ID); | ||
- if (builtinIsSupport | + ++ID; | ||
- Table.get(TSRecords[i].Name).setBuiltinID(i + Builtin::FirstTSBuiltin); | + } | ||
+ assert(ID == FirstTSBuiltin && "Should have added all non-target IDs!"); | |||
+ | |||
+ // Step #2: Register target-specific builtins. | |||
+ for (const auto &Shard : TargetShards) | |||
+ for (const auto &I : Shard.Infos) { | |||
+ if (builtinIsSupport | |||
+ Table.get(I.getName(Shard)).setBuiltinID(ID); | |||
+ ++ID; | |||
+ } | |||
- | + // Step #3: Register target-specific builtins for AuxTarget. | ||
- for (unsigned i = 0, e = AuxTSRecords.size(); i != e; ++i) | + for (const auto &Shard : AuxTargetShards) | ||
- Table.get(AuxTSRecords[i].Name) | + for (const auto &I : Shard.Infos) { | ||
- .setBuiltinID(i + Builtin::FirstTSBuiltin + TSRecords.size()); | + Table.get(I.getName(Shard)).setBuiltinID(ID); | ||
+ ++ID; | |||
+ } | |||
+ } | |||
// Step #4: Unregister any builtins specified by -fno-builtin-foo. | // Step #4: Unregister any builtins specified by -fno-builtin-foo. | ||
for (llvm::StringRef Name : LangOpts.NoBuiltinFuncs) { | for (llvm::StringRef Name : LangOpts.NoBuiltinFuncs) { | ||
@@ -163,12 +241,8 @@ void Builtin::Context | |||
} | } | ||
} | } | ||
-std::string Builtin::Context::getQuotedName(unsigned ID) const { | |||
- return (llvm::Twine("'") + getName(ID) + "'").str(); | |||
-} | |||
- | |||
unsigned Builtin::Context::getRequiredVecto | unsigned Builtin::Context::getRequiredVecto | ||
- const char *WidthPos = ::strchr( | + const char *WidthPos = ::strchr(getAttributesString(ID), 'V'); | ||
if (!WidthPos) | if (!WidthPos) | ||
return 0; | return 0; | ||
@@ -191,7 +265,7 @@ bool Builtin::Context | |||
assert(::toupper(Fmt[0]) == Fmt[1] && | assert(::toupper(Fmt[0]) == Fmt[1] && | ||
"Format string is not in the form \"xX\""); | "Format string is not in the form \"xX\""); | ||
- const char *Like = ::strpbrk( | + const char *Like = ::strpbrk(getAttributesString(ID), Fmt); | ||
if (!Like) | if (!Like) | ||
return false; | return false; | ||
@@ -218,7 +292,7 @@ bool Builtin::Context | |||
bool Builtin::Context::performsCallback | bool Builtin::Context::performsCallback | ||
SmallVectorImpl<int> &Encoding) const { | SmallVectorImpl<int> &Encoding) const { | ||
- const char *CalleePos = ::strchr( | + const char *CalleePos = ::strchr(getAttributesString(ID), 'C'); | ||
if (!CalleePos) | if (!CalleePos) | ||
return false; | return false; | ||
@@ -765,6 +765,12 @@ bool clang::isOpenMPC | |||
return false; | return false; | ||
} | } | ||
+bool clang::isOpenMPOrderCon | |||
+ OpenMPDirectiveK | |||
+ return DKind == OMPD_atomic || DKind == OMPD_loop || DKind == OMPD_simd || | |||
+ DKind == OMPD_parallel || isOpenMPLoopTran | |||
+} | |||
+ | |||
void clang::getOpenMPCapture | void clang::getOpenMPCapture | ||
SmallVectorImpl<OpenMPDirectiveK | SmallVectorImpl<OpenMPDirectiveK | ||
OpenMPDirectiveK | OpenMPDirectiveK |
@@ -26,36 +26,106 @@ | |||
using namespace clang; | using namespace clang; | ||
using namespace clang::targets; | using namespace clang::targets; | ||
-static constexpr | +static constexpr int NumNeonBuiltins = | ||
-#define BUILTIN(ID, TYPE, ATTRS) \ | + NEON::FirstFp16Builtin | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | +static constexpr int NumFp16Builtins = | ||
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ | + NEON::FirstTSBuiltin - NEON::FirstFp16Builtin | ||
- {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | +static constexpr int NumSVEBuiltins = | ||
-#include "clang/Basic/BuiltinsNEON.def" | + SVE::FirstNeonBridgeB | ||
- | +static constexpr int NumSVENeonBridge | ||
-#define BUILTIN(ID, TYPE, ATTRS) \ | + SVE::FirstTSBuiltin - SVE::FirstNeonBridgeB | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | +static constexpr int NumSMEBuiltins = SME::FirstTSBuiltin - SVE::FirstTSBuiltin; | ||
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ | +static constexpr int NumAArch64Builti | ||
- {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + AArch64::LastTSBuiltin - SME::FirstTSBuiltin; | ||
-#include "clang/Basic/BuiltinsSVE.def" | +static constexpr int NumBuiltins = | ||
- | + AArch64::LastTSBuiltin - Builtin::FirstTSBuiltin; | ||
-#define BUILTIN(ID, TYPE, ATTRS) \ | +static_assert(NumBuiltins == | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + (NumNeonBuiltins + NumFp16Builtins + NumSVEBuiltins + | ||
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ | + NumSVENeonBridge | ||
- {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + | ||
-#include "clang/Basic/BuiltinsSME.def" | +namespace clang { | ||
- | +namespace NEON { | ||
-#define BUILTIN(ID, TYPE, ATTRS) \ | +#define GET_NEON_BUILTIN | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | +#include "clang/Basic/arm_neon.inc" | ||
-#define LANGBUILTIN(ID, TYPE, ATTRS, LANG) \ | +#undef GET_NEON_BUILTIN | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, LANG}, | + | ||
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ | +static constexpr std::array<Builtin::Info, NumNeonBuiltins> BuiltinInfos = { | ||
- {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | +#define GET_NEON_BUILTIN | ||
-#define TARGET_HEADER_BU | +#include "clang/Basic/arm_neon.inc" | ||
- {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::HEADER, LANGS}, | +#undef GET_NEON_BUILTIN | ||
-#include "clang/Basic/BuiltinsAArch64.def" | |||
}; | }; | ||
+namespace FP16 { | |||
+#define GET_NEON_BUILTIN | |||
+#include "clang/Basic/arm_fp16.inc" | |||
+#undef GET_NEON_BUILTIN | |||
+ | |||
+static constexpr std::array<Builtin::Info, NumFp16Builtins> BuiltinInfos = { | |||
+#define GET_NEON_BUILTIN | |||
+#include "clang/Basic/arm_fp16.inc" | |||
+#undef GET_NEON_BUILTIN | |||
+}; | |||
+} // namespace FP16 | |||
+} // namespace NEON | |||
+ | |||
+namespace SVE { | |||
+#define GET_SVE_BUILTIN_ | |||
+#include "clang/Basic/arm_sve_builtins | |||
+#undef GET_SVE_BUILTIN_ | |||
+ | |||
+static constexpr std::array<Builtin::Info, NumSVEBuiltins> BuiltinInfos = { | |||
+#define GET_SVE_BUILTIN_ | |||
+#include "clang/Basic/arm_sve_builtins | |||
+#undef GET_SVE_BUILTIN_ | |||
+}; | |||
+} // namespace SVE | |||
+ | |||
+namespace SME { | |||
+#define GET_SME_BUILTIN_ | |||
+#include "clang/Basic/arm_sme_builtins | |||
+#undef GET_SME_BUILTIN_ | |||
+ | |||
+static constexpr std::array<Builtin::Info, NumSMEBuiltins> BuiltinInfos = { | |||
+#define GET_SME_BUILTIN_ | |||
+#include "clang/Basic/arm_sme_builtins | |||
+#undef GET_SME_BUILTIN_ | |||
+}; | |||
+} // namespace SME | |||
+} // namespace clang | |||
+ | |||
+static constexpr llvm::StringTable BuiltinSVENeonBr | |||
+ CLANG_BUILTIN_ST | |||
+#define TARGET_BUILTIN CLANG_TARGET_BUI | |||
+#define GET_SVE_BUILTINS | |||
+#include "clang/Basic/BuiltinsAArch64N | |||
+#undef GET_SVE_BUILTINS | |||
+#undef TARGET_BUILTIN | |||
+ ; | |||
+static constexpr llvm::StringTable BuiltinAArch64St | |||
+ CLANG_BUILTIN_ST | |||
+#define BUILTIN CLANG_BUILTIN_ST | |||
+#define TARGET_BUILTIN CLANG_TARGET_BUI | |||
+#define TARGET_HEADER_BU | |||
+#include "clang/Basic/BuiltinsAArch64.def" | |||
+ ; | |||
+ | |||
+static constexpr auto BuiltinSVENeonBr | |||
+ Builtin::MakeInfos<NumSVENeonBridge | |||
+#define TARGET_BUILTIN CLANG_TARGET_BUI | |||
+#define GET_SVE_BUILTINS | |||
+#include "clang/Basic/BuiltinsAArch64N | |||
+#undef GET_SVE_BUILTINS | |||
+#undef TARGET_BUILTIN | |||
+ }); | |||
+static constexpr auto BuiltinAArch64In | |||
+ Builtin::MakeInfos<NumAArch64Builti | |||
+#define BUILTIN CLANG_BUILTIN_EN | |||
+#define TARGET_BUILTIN CLANG_TARGET_BUI | |||
+#define LANGBUILTIN CLANG_LANGBUILTI | |||
+#define TARGET_HEADER_BU | |||
+#include "clang/Basic/BuiltinsAArch64.def" | |||
+ }); | |||
+ | |||
void AArch64TargetInf | void AArch64TargetInf | ||
if (*ArchInfo == llvm::AArch64::ARMV8R) { | if (*ArchInfo == llvm::AArch64::ARMV8R) { | ||
HasDotProd = true; | HasDotProd = true; | ||
@@ -253,11 +323,19 @@ bool AArch64TargetInf | |||
bool AArch64TargetInf | bool AArch64TargetInf | ||
BranchProtection | BranchProtection | ||
+ const LangOptions &LO, | |||
StringRef &Err) const { | StringRef &Err) const { | ||
llvm::ARM::ParsedBranchProt | llvm::ARM::ParsedBranchProt | ||
if (!llvm::ARM::parseBranchProte | if (!llvm::ARM::parseBranchProte | ||
return false; | return false; | ||
+ // GCS is currently untested with ptrauth-returns, but enabling this could be | |||
+ // allowed in future after testing with a suitable system. | |||
+ if (LO.PointerAuthRetur | |||
+ (PBP.Scope != "none" || PBP.BranchProtection | |||
+ PBP.GuardedControlSt | |||
+ return false; | |||
+ | |||
BPI.SignReturnAddr = | BPI.SignReturnAddr = | ||
llvm::StringSwitch<LangOptions::SignReturnAddres | llvm::StringSwitch<LangOptions::SignReturnAddres | ||
.Case("non-leaf", LangOptions::SignReturnAddres | .Case("non-leaf", LangOptions::SignReturnAddres | ||
@@ -697,9 +775,17 @@ void AArch64TargetInf | |||
} | } | ||
} | } | ||
-ArrayRef<Builtin::Info> AArch64TargetInf | +llvm::SmallVector<Builtin::InfosShard> | ||
- return llvm::ArrayRef(BuiltinInfo, clang::AArch64::LastTSBuiltin - | +AArch64TargetInf | ||
- Builtin::FirstTSBuiltin); | + return { | ||
+ {&NEON::BuiltinStrings, NEON::BuiltinInfos, "__builtin_neon_"}, | |||
+ {&NEON::FP16::BuiltinStrings, NEON::FP16::BuiltinInfos, | |||
+ "__builtin_neon_"}, | |||
+ {&SVE::BuiltinStrings, SVE::BuiltinInfos, "__builtin_sve_"}, | |||
+ {&BuiltinSVENeonBr | |||
+ {&SME::BuiltinStrings, SME::BuiltinInfos, "__builtin_sme_"}, | |||
+ {&BuiltinAArch64St | |||
+ }; | |||
} | } | ||
std::optional<std::pair<unsigned, unsigned>> | std::optional<std::pair<unsigned, unsigned>> |
@@ -132,6 +132,7 @@ public: | |||
bool validateBranchPr | bool validateBranchPr | ||
BranchProtection | BranchProtection | ||
+ const LangOptions &LO, | |||
StringRef &Err) const override; | StringRef &Err) const override; | ||
bool isValidCPUName(StringRef Name) const override; | bool isValidCPUName(StringRef Name) const override; | ||
@@ -181,7 +182,7 @@ public: | |||
void getTargetDefines | void getTargetDefines | ||
MacroBuilder &Builder) const override; | MacroBuilder &Builder) const override; | ||
- | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override; | ||
std::optional<std::pair<unsigned, unsigned>> | std::optional<std::pair<unsigned, unsigned>> | ||
getVScaleRange(const LangOptions &LangOpts, | getVScaleRange(const LangOptions &LangOpts, |
@@ -89,13 +89,21 @@ const LangASMap AMDGPUTargetInfo | |||
} // namespace targets | } // namespace targets | ||
} // namespace clang | } // namespace clang | ||
-static constexpr | +static constexpr int NumBuiltins = | ||
-#define BUILTIN(ID, TYPE, ATTRS) \ | + clang::AMDGPU::LastTSBuiltin - Builtin::FirstTSBuiltin; | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + | ||
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ | +static constexpr llvm::StringTable BuiltinStrings = | ||
- {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + CLANG_BUILTIN_ST | ||
+#define BUILTIN CLANG_BUILTIN_ST | |||
+#define TARGET_BUILTIN CLANG_TARGET_BUI | |||
#include "clang/Basic/BuiltinsAMDGPU.def" | #include "clang/Basic/BuiltinsAMDGPU.def" | ||
-}; | + ; | ||
+ | |||
+static constexpr auto BuiltinInfos = Builtin::MakeInfos<NumBuiltins>({ | |||
+#define BUILTIN CLANG_BUILTIN_EN | |||
+#define TARGET_BUILTIN CLANG_TARGET_BUI | |||
+#include "clang/Basic/BuiltinsAMDGPU.def" | |||
+}); | |||
const char *const AMDGPUTargetInfo | const char *const AMDGPUTargetInfo | ||
"v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", | "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", | ||
@@ -267,9 +275,9 @@ void AMDGPUTargetInfo | |||
!isAMDGCN(getTriple())); | !isAMDGCN(getTriple())); | ||
} | } | ||
-ArrayRef<Builtin::Info> AMDGPUTargetInfo | +llvm::SmallVector<Builtin::InfosShard> | ||
- return llvm::ArrayRef(BuiltinInfo, | +AMDGPUTargetInfo | ||
- clang::AMDGPU::LastTSBuiltin - Builtin::FirstTSBuiltin); | + return {{&BuiltinStrings, BuiltinInfos}}; | ||
} | } | ||
void AMDGPUTargetInfo | void AMDGPUTargetInfo |
@@ -257,7 +257,7 @@ public: | |||
StringRef CPU, | StringRef CPU, | ||
const std::vector<std::string> &FeatureVec) const override; | const std::vector<std::string> &FeatureVec) const override; | ||
- | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override; | ||
bool useFP16Conversio | bool useFP16Conversio | ||
@@ -40,7 +40,9 @@ public: | |||
void getTargetDefines | void getTargetDefines | ||
MacroBuilder &Builder) const override; | MacroBuilder &Builder) const override; | ||
- ArrayRef<Builtin::Info> getTargetBuiltin | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltin | ||
+ return {}; | |||
+ } | |||
BuiltinVaListKin | BuiltinVaListKin | ||
return TargetInfo::VoidPtrBuiltinVa | return TargetInfo::VoidPtrBuiltinVa |
@@ -405,6 +405,7 @@ bool ARMTargetInfo::i | |||
bool ARMTargetInfo::validateBranchPr | bool ARMTargetInfo::validateBranchPr | ||
BranchProtection | BranchProtection | ||
+ const LangOptions &LO, | |||
StringRef &Err) const { | StringRef &Err) const { | ||
llvm::ARM::ParsedBranchProt | llvm::ARM::ParsedBranchProt | ||
if (!llvm::ARM::parseBranchProte | if (!llvm::ARM::parseBranchProte | ||
@@ -1074,31 +1075,99 @@ void ARMTargetInfo::g | |||
} | } | ||
} | } | ||
-static constexpr Builtin::Info BuiltinInfo[] = { | +static constexpr int NumBuiltins = ARM::LastTSBuiltin - Builtin::FirstTSBuiltin; | ||
-#define BUILTIN(ID, TYPE, ATTRS) \ | +static constexpr int NumNeonBuiltins = | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + NEON::FirstFp16Builtin | ||
-#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ | +static constexpr int NumFp16Builtins = | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, ALL_LANGUAGES}, | + NEON::FirstTSBuiltin - NEON::FirstFp16Builtin | ||
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ | +static constexpr int NumMVEBuiltins = | ||
- {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + ARM::FirstCDEBuiltin - NEON::FirstTSBuiltin; | ||
-#include "clang/Basic/BuiltinsNEON.def" | +static constexpr int NumCDEBuiltins = | ||
- | + ARM::FirstARMBuiltin - ARM::FirstCDEBuiltin; | ||
-#define BUILTIN(ID, TYPE, ATTRS) \ | +static constexpr int NumARMBuiltins = ARM::LastTSBuiltin - ARM::FirstARMBuiltin; | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | +static_assert(NumBuiltins == | ||
-#define LANGBUILTIN(ID, TYPE, ATTRS, LANG) \ | + (NumNeonBuiltins + NumFp16Builtins + NumMVEBuiltins + | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, LANG}, | + NumCDEBuiltins + NumARMBuiltins)); | ||
-#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ | + | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, ALL_LANGUAGES}, | +namespace clang { | ||
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ | +namespace NEON { | ||
- {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | +#define GET_NEON_BUILTIN | ||
-#define TARGET_HEADER_BU | +#include "clang/Basic/arm_neon.inc" | ||
- {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::HEADER, LANGS}, | +#undef GET_NEON_BUILTIN | ||
-#include "clang/Basic/BuiltinsARM.def" | + | ||
+static constexpr std::array<Builtin::Info, NumNeonBuiltins> BuiltinInfos = { | |||
+#define GET_NEON_BUILTIN | |||
+#include "clang/Basic/arm_neon.inc" | |||
+#undef GET_NEON_BUILTIN | |||
+}; | |||
+ | |||
+namespace FP16 { | |||
+#define GET_NEON_BUILTIN | |||
+#include "clang/Basic/arm_fp16.inc" | |||
+#undef GET_NEON_BUILTIN | |||
+ | |||
+static constexpr std::array<Builtin::Info, NumFp16Builtins> BuiltinInfos = { | |||
+#define GET_NEON_BUILTIN | |||
+#include "clang/Basic/arm_fp16.inc" | |||
+#undef GET_NEON_BUILTIN | |||
+}; | |||
+} // namespace FP16 | |||
+} // namespace NEON | |||
+} // namespace clang | |||
+ | |||
+namespace { | |||
+namespace MVE { | |||
+#define GET_MVE_BUILTIN_ | |||
+#include "clang/Basic/arm_mve_builtins | |||
+#undef GET_MVE_BUILTIN_ | |||
+ | |||
+static constexpr std::array<Builtin::Info, NumMVEBuiltins> BuiltinInfos = { | |||
+#define GET_MVE_BUILTIN_ | |||
+#include "clang/Basic/arm_mve_builtins | |||
+#undef GET_MVE_BUILTIN_ | |||
}; | }; | ||
+} // namespace MVE | |||
-ArrayRef<Builtin::Info> ARMTargetInfo::getTargetBuiltin | +namespace CDE { | ||
- return llvm::ArrayRef(BuiltinInfo, | +#define GET_CDE_BUILTIN_ | ||
- clang::ARM::LastTSBuiltin - Builtin::FirstTSBuiltin); | +#include "clang/Basic/arm_cde_builtins | ||
+#undef GET_CDE_BUILTIN_ | |||
+ | |||
+static constexpr std::array<Builtin::Info, NumCDEBuiltins> BuiltinInfos = { | |||
+#define GET_CDE_BUILTIN_ | |||
+#include "clang/Basic/arm_cde_builtins | |||
+#undef GET_CDE_BUILTIN_ | |||
+}; | |||
+} // namespace CDE | |||
+} // namespace | |||
+ | |||
+static constexpr llvm::StringTable BuiltinStrings = | |||
+ CLANG_BUILTIN_ST | |||
+#define BUILTIN CLANG_BUILTIN_ST | |||
+#define TARGET_BUILTIN CLANG_TARGET_BUI | |||
+#define TARGET_HEADER_BU | |||
+#include "clang/Basic/BuiltinsARM.def" | |||
+ ; // namespace clang | |||
+ | |||
+static constexpr auto BuiltinInfos = Builtin::MakeInfos<NumARMBuiltins>({ | |||
+#define BUILTIN CLANG_BUILTIN_EN | |||
+#define LANGBUILTIN CLANG_LANGBUILTI | |||
+#define LIBBUILTIN CLANG_LIBBUILTIN | |||
+#define TARGET_BUILTIN CLANG_TARGET_BUI | |||
+#define TARGET_HEADER_BU | |||
+#include "clang/Basic/BuiltinsARM.def" | |||
+}); | |||
+ | |||
+llvm::SmallVector<Builtin::InfosShard> | |||
+ARMTargetInfo::getTargetBuiltin | |||
+ return { | |||
+ {&NEON::BuiltinStrings, NEON::BuiltinInfos, "__builtin_neon_"}, | |||
+ {&NEON::FP16::BuiltinStrings, NEON::FP16::BuiltinInfos, | |||
+ "__builtin_neon_"}, | |||
+ {&MVE::BuiltinStrings, MVE::BuiltinInfos, "__builtin_arm_mv | |||
+ {&CDE::BuiltinStrings, CDE::BuiltinInfos, "__builtin_arm_cd | |||
+ {&BuiltinStrings, BuiltinInfos}, | |||
+ }; | |||
} | } | ||
bool ARMTargetInfo::isCLZForZeroUnde | bool ARMTargetInfo::isCLZForZeroUnde |
@@ -155,6 +155,7 @@ public: | |||
bool isBranchProtecti | bool isBranchProtecti | ||
bool validateBranchPr | bool validateBranchPr | ||
BranchProtection | BranchProtection | ||
+ const LangOptions &LO, | |||
StringRef &Err) const override; | StringRef &Err) const override; | ||
// FIXME: This should be based on Arch attributes, not CPU names. | // FIXME: This should be based on Arch attributes, not CPU names. | ||
@@ -196,7 +197,7 @@ public: | |||
void getTargetDefines | void getTargetDefines | ||
MacroBuilder &Builder) const override; | MacroBuilder &Builder) const override; | ||
- | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override; | ||
bool isCLZForZeroUnde | bool isCLZForZeroUnde | ||
BuiltinVaListKin | BuiltinVaListKin |
@@ -63,7 +63,9 @@ public: | |||
void getTargetDefines | void getTargetDefines | ||
MacroBuilder &Builder) const override; | MacroBuilder &Builder) const override; | ||
- ArrayRef<Builtin::Info> getTargetBuiltin | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltin | ||
+ return {}; | |||
+ } | |||
bool allowsLargerPref | bool allowsLargerPref | ||
@@ -19,11 +19,19 @@ | |||
using namespace clang; | using namespace clang; | ||
using namespace clang::targets; | using namespace clang::targets; | ||
-static constexpr | +static constexpr int NumBuiltins = | ||
-#define BUILTIN(ID, TYPE, ATTRS) \ | + clang::BPF::LastTSBuiltin - Builtin::FirstTSBuiltin; | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + | ||
+#define GET_BUILTIN_STR_ | |||
+#include "clang/Basic/BuiltinsBPF.inc" | |||
+#undef GET_BUILTIN_STR_ | |||
+ | |||
+static constexpr Builtin::Info BuiltinInfos[] = { | |||
+#define GET_BUILTIN_INFO | |||
#include "clang/Basic/BuiltinsBPF.inc" | #include "clang/Basic/BuiltinsBPF.inc" | ||
+#undef GET_BUILTIN_INFO | |||
}; | }; | ||
+static_assert(std::size(BuiltinInfos) == NumBuiltins); | |||
void BPFTargetInfo::getTargetDefines | void BPFTargetInfo::getTargetDefines | ||
MacroBuilder &Builder) const { | MacroBuilder &Builder) const { | ||
@@ -81,9 +89,9 @@ void BPFTargetInfo::f | |||
Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames)); | Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames)); | ||
} | } | ||
-ArrayRef<Builtin::Info> BPFTargetInfo::getTargetBuiltin | +llvm::SmallVector<Builtin::InfosShard> | ||
- return llvm::ArrayRef(BuiltinInfo, | +BPFTargetInfo::getTargetBuiltin | ||
- clang::BPF::LastTSBuiltin - Builtin::FirstTSBuiltin); | + return {{&BuiltinStrings, BuiltinInfos}}; | ||
} | } | ||
bool BPFTargetInfo::handleTargetFeat | bool BPFTargetInfo::handleTargetFeat |
@@ -58,7 +58,7 @@ public: | |||
bool handleTargetFeat | bool handleTargetFeat | ||
DiagnosticsEngin | DiagnosticsEngin | ||
- | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override; | ||
std::string_view getClobbers() const override { return ""; } | std::string_view getClobbers() const override { return ""; } | ||
@@ -139,10 +139,6 @@ bool CSKYTargetInfo:: | |||
return true; | return true; | ||
} | } | ||
-ArrayRef<Builtin::Info> CSKYTargetInfo::getTargetBuiltin | |||
- return ArrayRef<Builtin::Info>(); | |||
-} | |||
- | |||
ArrayRef<const char *> CSKYTargetInfo::getGCCRegNames() const { | ArrayRef<const char *> CSKYTargetInfo::getGCCRegNames() const { | ||
static const char *const GCCRegNames[] = { | static const char *const GCCRegNames[] = { | ||
// Integer registers | // Integer registers |
@@ -73,7 +73,9 @@ public: | |||
unsigned getMinGlobalAlig | unsigned getMinGlobalAlig | ||
- | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override { | ||
+ return {}; | |||
+ } | |||
BuiltinVaListKin | BuiltinVaListKin | ||
return VoidPtrBuiltinVa | return VoidPtrBuiltinVa |
@@ -73,7 +73,9 @@ public: | |||
return Feature == "directx"; | return Feature == "directx"; | ||
} | } | ||
- ArrayRef<Builtin::Info> getTargetBuiltin | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltin | ||
+ return {}; | |||
+ } | |||
std::string_view getClobbers() const override { return ""; } | std::string_view getClobbers() const override { return ""; } | ||
@@ -204,15 +204,26 @@ ArrayRef<TargetI | |||
return llvm::ArrayRef(GCCRegAliases); | return llvm::ArrayRef(GCCRegAliases); | ||
} | } | ||
-static constexpr | +static constexpr int NumBuiltins = | ||
-#define BUILTIN(ID, TYPE, ATTRS) \ | + clang::Hexagon::LastTSBuiltin - Builtin::FirstTSBuiltin; | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + | ||
-#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ | +#define GET_BUILTIN_STR_ | ||
- {#ID, TYPE, ATTRS, nullptr, HEADER, ALL_LANGUAGES}, | +#include "clang/Basic/BuiltinsHexagon.inc" | ||
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ | +#undef GET_BUILTIN_STR_ | ||
- {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + | ||
+static constexpr Builtin::Info BuiltinInfos[] = { | |||
+#define GET_BUILTIN_INFO | |||
+#include "clang/Basic/BuiltinsHexagon.inc" | |||
+#undef GET_BUILTIN_INFO | |||
+}; | |||
+ | |||
+static constexpr Builtin::Info PrefixedBuiltinI | |||
+#define GET_BUILTIN_PREF | |||
#include "clang/Basic/BuiltinsHexagon.inc" | #include "clang/Basic/BuiltinsHexagon.inc" | ||
+#undef GET_BUILTIN_PREF | |||
}; | }; | ||
+static_assert((std::size(BuiltinInfos) + std::size(PrefixedBuiltinI | |||
+ NumBuiltins); | |||
bool HexagonTargetInf | bool HexagonTargetInf | ||
std::string VS = "hvxv" + HVXVersion; | std::string VS = "hvxv" + HVXVersion; | ||
@@ -271,7 +282,8 @@ void HexagonTargetInf | |||
Values.push_back(Suffix.Name); | Values.push_back(Suffix.Name); | ||
} | } | ||
-ArrayRef<Builtin::Info> HexagonTargetInf | +llvm::SmallVector<Builtin::InfosShard> | ||
- return llvm::ArrayRef(BuiltinInfo, clang::Hexagon::LastTSBuiltin - | +HexagonTargetInf | ||
- Builtin::FirstTSBuiltin); | + return {{&BuiltinStrings, BuiltinInfos}, | ||
+ {&BuiltinStrings, PrefixedBuiltinI | |||
} | } |
@@ -66,7 +66,7 @@ public: | |||
BoolWidth = BoolAlign = 8; | BoolWidth = BoolAlign = 8; | ||
} | } | ||
- | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override; | ||
bool validateAsmConst | bool validateAsmConst | ||
TargetInfo::ConstraintInfo &Info) const override { | TargetInfo::ConstraintInfo &Info) const override { |
@@ -78,7 +78,9 @@ public: | |||
return TargetInfo::VoidPtrBuiltinVa | return TargetInfo::VoidPtrBuiltinVa | ||
} | } | ||
- ArrayRef<Builtin::Info> getTargetBuiltin | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltin | ||
+ return {}; | |||
+ } | |||
bool validateAsmConst | bool validateAsmConst | ||
TargetInfo::ConstraintInfo &info) const override { | TargetInfo::ConstraintInfo &info) const override { |
@@ -273,13 +273,55 @@ void LoongArchTargetI | |||
Builder.defineMacro("__GCC_HAVE_SYNC_ | Builder.defineMacro("__GCC_HAVE_SYNC_ | ||
} | } | ||
-static constexpr | +static constexpr int NumBaseBuiltins = | ||
-#define BUILTIN(ID, TYPE, ATTRS) \ | + LoongArch::FirstLSXBuiltin - Builtin::FirstTSBuiltin; | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | +static constexpr int NumLSXBuiltins = | ||
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ | + LoongArch::FirstLASXBuiltin | ||
- {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | +static constexpr int NumLASXBuiltins = | ||
-#include "clang/Basic/BuiltinsLoongArc | + LoongArch::LastTSBuiltin - LoongArch::FirstLASXBuiltin | ||
-}; | +static constexpr int NumBuiltins = | ||
+ LoongArch::LastTSBuiltin - Builtin::FirstTSBuiltin; | |||
+static_assert(NumBuiltins == | |||
+ (NumBaseBuiltins + NumLSXBuiltins + NumLASXBuiltins)); | |||
+ | |||
+static constexpr llvm::StringTable BuiltinBaseStrin | |||
+ CLANG_BUILTIN_ST | |||
+#define TARGET_BUILTIN CLANG_TARGET_BUI | |||
+#include "clang/Basic/BuiltinsLoongArc | |||
+#undef TARGET_BUILTIN | |||
+ ; | |||
+ | |||
+static constexpr auto BuiltinBaseInfos | |||
+#define TARGET_BUILTIN CLANG_TARGET_BUI | |||
+#include "clang/Basic/BuiltinsLoongArc | |||
+#undef TARGET_BUILTIN | |||
+}); | |||
+ | |||
+static constexpr llvm::StringTable BuiltinLSXString | |||
+ CLANG_BUILTIN_ST | |||
+#define TARGET_BUILTIN CLANG_TARGET_BUI | |||
+#include "clang/Basic/BuiltinsLoongArc | |||
+#undef TARGET_BUILTIN | |||
+ ; | |||
+ | |||
+static constexpr auto BuiltinLSXInfos = Builtin::MakeInfos<NumLSXBuiltins>({ | |||
+#define TARGET_BUILTIN CLANG_TARGET_BUI | |||
+#include "clang/Basic/BuiltinsLoongArc | |||
+#undef TARGET_BUILTIN | |||
+}); | |||
+ | |||
+static constexpr llvm::StringTable BuiltinLASXStrin | |||
+ CLANG_BUILTIN_ST | |||
+#define TARGET_BUILTIN CLANG_TARGET_BUI | |||
+#include "clang/Basic/BuiltinsLoongArc | |||
+#undef TARGET_BUILTIN | |||
+ ; | |||
+ | |||
+static constexpr auto BuiltinLASXInfos | |||
+#define TARGET_BUILTIN CLANG_TARGET_BUI | |||
+#include "clang/Basic/BuiltinsLoongArc | |||
+#undef TARGET_BUILTIN | |||
+}); | |||
bool LoongArchTargetI | bool LoongArchTargetI | ||
llvm::StringMap<bool> &Features, DiagnosticsEngin | llvm::StringMap<bool> &Features, DiagnosticsEngin | ||
@@ -306,9 +348,13 @@ bool LoongArchTargetI | |||
.Default(false); | .Default(false); | ||
} | } | ||
-ArrayRef<Builtin::Info> LoongArchTargetI | +llvm::SmallVector<Builtin::InfosShard> | ||
- return llvm::ArrayRef(BuiltinInfo, clang::LoongArch::LastTSBuiltin - | +LoongArchTargetI | ||
- Builtin::FirstTSBuiltin); | + return { | ||
+ {&BuiltinBaseStrin | |||
+ {&BuiltinLSXString | |||
+ {&BuiltinLASXStrin | |||
+ }; | |||
} | } | ||
bool LoongArchTargetI | bool LoongArchTargetI |
@@ -72,7 +72,7 @@ public: | |||
void getTargetDefines | void getTargetDefines | ||
MacroBuilder &Builder) const override; | MacroBuilder &Builder) const override; | ||
- | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override; | ||
BuiltinVaListKin | BuiltinVaListKin | ||
return TargetInfo::VoidPtrBuiltinVa | return TargetInfo::VoidPtrBuiltinVa |
@@ -115,7 +115,8 @@ void M68kTargetInfo:: | |||
Builder.defineMacro("__HAVE_68881__"); | Builder.defineMacro("__HAVE_68881__"); | ||
} | } | ||
-ArrayRef<Builtin::Info> M68kTargetInfo::getTargetBuiltin | +llvm::SmallVector<Builtin::InfosShard> | ||
+M68kTargetInfo::getTargetBuiltin | |||
// FIXME: Implement. | // FIXME: Implement. | ||
return {}; | return {}; | ||
} | } |
@@ -44,7 +44,7 @@ public: | |||
void getTargetDefines | void getTargetDefines | ||
MacroBuilder &Builder) const override; | MacroBuilder &Builder) const override; | ||
- | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override; | ||
bool hasFeature(StringRef Feature) const override; | bool hasFeature(StringRef Feature) const override; | ||
ArrayRef<const char *> getGCCRegNames() const override; | ArrayRef<const char *> getGCCRegNames() const override; | ||
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases | ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases |
@@ -50,7 +50,7 @@ public: | |||
void getTargetDefines | void getTargetDefines | ||
MacroBuilder &Builder) const override; | MacroBuilder &Builder) const override; | ||
- | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override { | ||
// FIXME: Implement. | // FIXME: Implement. | ||
return {}; | return {}; | ||
} | } |
@@ -20,13 +20,20 @@ | |||
using namespace clang; | using namespace clang; | ||
using namespace clang::targets; | using namespace clang::targets; | ||
-static constexpr | +static constexpr int NumBuiltins = | ||
-#define BUILTIN(ID, TYPE, ATTRS) \ | + clang::Mips::LastTSBuiltin - Builtin::FirstTSBuiltin; | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + | ||
-#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ | +static constexpr llvm::StringTable BuiltinStrings = | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, ALL_LANGUAGES}, | + CLANG_BUILTIN_ST | ||
+#define BUILTIN CLANG_BUILTIN_ST | |||
+#include "clang/Basic/BuiltinsMips.def" | |||
+ ; | |||
+ | |||
+static constexpr auto BuiltinInfos = Builtin::MakeInfos<NumBuiltins>({ | |||
+#define BUILTIN CLANG_BUILTIN_EN | |||
+#define LIBBUILTIN CLANG_LIBBUILTIN | |||
#include "clang/Basic/BuiltinsMips.def" | #include "clang/Basic/BuiltinsMips.def" | ||
-}; | +}); | ||
bool MipsTargetInfo::processorSupport | bool MipsTargetInfo::processorSupport | ||
return llvm::StringSwitch<bool>(CPU) | return llvm::StringSwitch<bool>(CPU) | ||
@@ -223,9 +230,9 @@ bool MipsTargetInfo:: | |||
.Default(false); | .Default(false); | ||
} | } | ||
-ArrayRef<Builtin::Info> MipsTargetInfo::getTargetBuiltin | +llvm::SmallVector<Builtin::InfosShard> | ||
- return llvm::ArrayRef(BuiltinInfo, | +MipsTargetInfo::getTargetBuiltin | ||
- clang::Mips::LastTSBuiltin - Builtin::FirstTSBuiltin); | + return {{&BuiltinStrings, BuiltinInfos}}; | ||
} | } | ||
unsigned MipsTargetInfo::getUnwindWordWid | unsigned MipsTargetInfo::getUnwindWordWid |
@@ -198,7 +198,7 @@ public: | |||
void getTargetDefines | void getTargetDefines | ||
MacroBuilder &Builder) const override; | MacroBuilder &Builder) const override; | ||
- | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override; | ||
bool hasFeature(StringRef Feature) const override; | bool hasFeature(StringRef Feature) const override; | ||
@@ -20,11 +20,19 @@ | |||
using namespace clang; | using namespace clang; | ||
using namespace clang::targets; | using namespace clang::targets; | ||
-static constexpr | +static constexpr int NumBuiltins = | ||
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ | + clang::NVPTX::LastTSBuiltin - Builtin::FirstTSBuiltin; | ||
- {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + | ||
+#define GET_BUILTIN_STR_ | |||
+#include "clang/Basic/BuiltinsNVPTX.inc" | |||
+#undef GET_BUILTIN_STR_ | |||
+ | |||
+static constexpr Builtin::Info BuiltinInfos[] = { | |||
+#define GET_BUILTIN_INFO | |||
#include "clang/Basic/BuiltinsNVPTX.inc" | #include "clang/Basic/BuiltinsNVPTX.inc" | ||
+#undef GET_BUILTIN_INFO | |||
}; | }; | ||
+static_assert(std::size(BuiltinInfos) == NumBuiltins); | |||
const char *const NVPTXTargetInfo::GCCRegNames[] = {"r0"}; | const char *const NVPTXTargetInfo::GCCRegNames[] = {"r0"}; | ||
@@ -62,12 +70,13 @@ NVPTXTargetInfo: | |||
HasFloat16 = true; | HasFloat16 = true; | ||
if (TargetPointerWid | if (TargetPointerWid | ||
- resetDataLayout("e-p:32:32-i64:64-i128:128-v16:16-v32:32-n16:32:64"); | |||
- else if (Opts.NVPTXUseShortPoi | |||
resetDataLayout( | resetDataLayout( | ||
- "e- | + "e-p:32:32-p6:32:32-i64:64-i128:128-v16:16-v32:32-n16:32:64"); | ||
+ else if (Opts.NVPTXUseShortPoi | |||
+ resetDataLayout("e-p3:32:32-p4:32:32-p5:32:32-p6:32:32-i64:64-i128:128-v16:" | |||
+ "16-v32:32-n16:32:64"); | |||
else | else | ||
- resetDataLayout("e-i64:64-i128:128-v16:16-v32:32-n16:32:64"); | + resetDataLayout("e-p6:32:32-i64:64-i128:128-v16:16-v32:32-n16:32:64"); | ||
// If possible, get a TargetInfo for our host triple, so we can match its | // If possible, get a TargetInfo for our host triple, so we can match its | ||
// types. | // types. | ||
@@ -294,7 +303,7 @@ void NVPTXTargetInfo: | |||
} | } | ||
} | } | ||
-ArrayRef<Builtin::Info> NVPTXTargetInfo::getTargetBuiltin | +llvm::SmallVector<Builtin::InfosShard> | ||
- return llvm::ArrayRef(BuiltinInfo, | +NVPTXTargetInfo::getTargetBuiltin | ||
- clang::NVPTX::LastTSBuiltin - Builtin::FirstTSBuiltin); | + return {{&BuiltinStrings, BuiltinInfos}}; | ||
} | } |
@@ -75,7 +75,7 @@ public: | |||
void getTargetDefines | void getTargetDefines | ||
MacroBuilder &Builder) const override; | MacroBuilder &Builder) const override; | ||
- | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override; | ||
bool useFP16Conversio | bool useFP16Conversio | ||
@@ -52,7 +52,9 @@ public: | |||
return Feature == "pnacl"; | return Feature == "pnacl"; | ||
} | } | ||
- ArrayRef<Builtin::Info> getTargetBuiltin | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltin | ||
+ return {}; | |||
+ } | |||
BuiltinVaListKin | BuiltinVaListKin | ||
return TargetInfo::PNaClABIBuiltinV | return TargetInfo::PNaClABIBuiltinV |
@@ -19,15 +19,22 @@ | |||
using namespace clang; | using namespace clang; | ||
using namespace clang::targets; | using namespace clang::targets; | ||
-static constexpr | +static constexpr int NumBuiltins = | ||
-#define BUILTIN(ID, TYPE, ATTRS) \ | + clang::PPC::LastTSBuiltin - Builtin::FirstTSBuiltin; | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + | ||
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ | +static constexpr llvm::StringTable BuiltinStrings = | ||
- {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + CLANG_BUILTIN_ST | ||
-#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ | +#define BUILTIN CLANG_BUILTIN_ST | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, ALL_LANGUAGES}, | +#define TARGET_BUILTIN CLANG_TARGET_BUI | ||
#include "clang/Basic/BuiltinsPPC.def" | #include "clang/Basic/BuiltinsPPC.def" | ||
-}; | + ; | ||
+ | |||
+static constexpr auto BuiltinInfos = Builtin::MakeInfos<NumBuiltins>({ | |||
+#define BUILTIN CLANG_BUILTIN_EN | |||
+#define TARGET_BUILTIN CLANG_TARGET_BUI | |||
+#define LIBBUILTIN CLANG_LIBBUILTIN | |||
+#include "clang/Basic/BuiltinsPPC.def" | |||
+}); | |||
/// handleTargetFeat | /// handleTargetFeat | ||
/// configured set of features. | /// configured set of features. | ||
@@ -927,9 +934,9 @@ void PPCTargetInfo::a | |||
MaxAtomicInlineW | MaxAtomicInlineW | ||
} | } | ||
-ArrayRef<Builtin::Info> PPCTargetInfo::getTargetBuiltin | +llvm::SmallVector<Builtin::InfosShard> | ||
- return llvm::ArrayRef(BuiltinInfo, | +PPCTargetInfo::getTargetBuiltin | ||
- clang::PPC::LastTSBuiltin - Builtin::FirstTSBuiltin); | + return {{&BuiltinStrings, BuiltinInfos}}; | ||
} | } | ||
bool PPCTargetInfo::validateCpuSuppo | bool PPCTargetInfo::validateCpuSuppo |
@@ -187,7 +187,7 @@ public: | |||
StringRef getABI() const override { return ABI; } | StringRef getABI() const override { return ABI; } | ||
- | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override; | ||
bool isCLZForZeroUnde | bool isCLZForZeroUnde | ||
@@ -240,22 +240,61 @@ void RISCVTargetInfo: | |||
} | } | ||
} | } | ||
-static constexpr | +static constexpr int NumRVVBuiltins = | ||
-#define BUILTIN(ID, TYPE, ATTRS) \ | + RISCVVector::FirstSiFiveBuilt | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | +static constexpr int NumRVVSiFiveBuil | ||
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ | + RISCVVector::FirstTSBuiltin - RISCVVector::FirstSiFiveBuilt | ||
- {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | +static constexpr int NumRISCVBuiltins | ||
-#include "clang/Basic/BuiltinsRISCVVec | + RISCV::LastTSBuiltin - RISCVVector::FirstTSBuiltin; | ||
-#define BUILTIN(ID, TYPE, ATTRS) \ | +static constexpr int NumBuiltins = | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + RISCV::LastTSBuiltin - Builtin::FirstTSBuiltin; | ||
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ | +static_assert(NumBuiltins == | ||
- {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + (NumRVVBuiltins + NumRVVSiFiveBuil | ||
-#include "clang/Basic/BuiltinsRISCV.inc" | + | ||
+namespace RVV { | |||
+#define GET_RISCVV_BUILT | |||
+#include "clang/Basic/riscv_vector_bui | |||
+#undef GET_RISCVV_BUILT | |||
+static_assert(BuiltinStrings.size() < 100'000); | |||
+ | |||
+static constexpr std::array<Builtin::Info, NumRVVBuiltins> BuiltinInfos = { | |||
+#define GET_RISCVV_BUILT | |||
+#include "clang/Basic/riscv_vector_bui | |||
+#undef GET_RISCVV_BUILT | |||
+}; | |||
+} // namespace RVV | |||
+ | |||
+namespace RVVSiFive { | |||
+#define GET_RISCVV_BUILT | |||
+#include "clang/Basic/riscv_sifive_vec | |||
+#undef GET_RISCVV_BUILT | |||
+ | |||
+static constexpr std::array<Builtin::Info, NumRVVSiFiveBuil | |||
+ { | |||
+#define GET_RISCVV_BUILT | |||
+#include "clang/Basic/riscv_sifive_vec | |||
+#undef GET_RISCVV_BUILT | |||
}; | }; | ||
+} // namespace RVVSiFive | |||
+ | |||
+#define GET_BUILTIN_STR_ | |||
+#include "clang/Basic/BuiltinsRISCV.inc" | |||
+#undef GET_BUILTIN_STR_ | |||
-ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltin | +static constexpr Builtin::Info BuiltinInfos[] = { | ||
- return llvm::ArrayRef(BuiltinInfo, | +#define GET_BUILTIN_INFO | ||
- clang::RISCV::LastTSBuiltin - Builtin::FirstTSBuiltin); | +#include "clang/Basic/BuiltinsRISCV.inc" | ||
+#undef GET_BUILTIN_INFO | |||
+}; | |||
+static_assert(std::size(BuiltinInfos) == NumRISCVBuiltins | |||
+ | |||
+llvm::SmallVector<Builtin::InfosShard> | |||
+RISCVTargetInfo::getTargetBuiltin | |||
+ return { | |||
+ {&RVV::BuiltinStrings, RVV::BuiltinInfos, "__builtin_rvv_"}, | |||
+ {&RVVSiFive::BuiltinStrings, RVVSiFive::BuiltinInfos, "__builtin_rvv_"}, | |||
+ {&BuiltinStrings, BuiltinInfos}, | |||
+ }; | |||
} | } | ||
bool RISCVTargetInfo::initFeatureMap( | bool RISCVTargetInfo::initFeatureMap( |
@@ -62,7 +62,7 @@ public: | |||
void getTargetDefines | void getTargetDefines | ||
MacroBuilder &Builder) const override; | MacroBuilder &Builder) const override; | ||
- | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override; | ||
BuiltinVaListKin | BuiltinVaListKin | ||
return TargetInfo::VoidPtrBuiltinVa | return TargetInfo::VoidPtrBuiltinVa |
@@ -20,15 +20,23 @@ | |||
using namespace clang; | using namespace clang; | ||
using namespace clang::targets; | using namespace clang::targets; | ||
-static constexpr | +static constexpr int NumBuiltins = | ||
-#define BUILTIN(ID, TYPE, ATTRS) \ | + clang::SPIRV::LastTSBuiltin - Builtin::FirstTSBuiltin; | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + | ||
+#define GET_BUILTIN_STR_ | |||
+#include "clang/Basic/BuiltinsSPIRV.inc" | |||
+#undef GET_BUILTIN_STR_ | |||
+ | |||
+static constexpr Builtin::Info BuiltinInfos[] = { | |||
+#define GET_BUILTIN_INFO | |||
#include "clang/Basic/BuiltinsSPIRV.inc" | #include "clang/Basic/BuiltinsSPIRV.inc" | ||
+#undef GET_BUILTIN_INFO | |||
}; | }; | ||
+static_assert(std::size(BuiltinInfos) == NumBuiltins); | |||
-ArrayRef<Builtin::Info> SPIRVTargetInfo::getTargetBuiltin | +llvm::SmallVector<Builtin::InfosShard> | ||
- return llvm::ArrayRef(BuiltinInfo, | +SPIRVTargetInfo::getTargetBuiltin | ||
- clang::SPIRV::LastTSBuiltin - Builtin::FirstTSBuiltin); | + return {{&BuiltinStrings, BuiltinInfos}}; | ||
} | } | ||
void SPIRTargetInfo::getTargetDefines | void SPIRTargetInfo::getTargetDefines | ||
@@ -94,7 +102,8 @@ SPIRV64AMDGCNTar | |||
return AMDGPUTI.convertConstrain | return AMDGPUTI.convertConstrain | ||
} | } | ||
-ArrayRef<Builtin::Info> SPIRV64AMDGCNTar | +llvm::SmallVector<Builtin::InfosShard> | ||
+SPIRV64AMDGCNTar | |||
return AMDGPUTI.getTargetBuiltin | return AMDGPUTI.getTargetBuiltin | ||
} | } | ||
@@ -161,7 +161,9 @@ public: | |||
// memcpy as per section 3 of the SPIR spec. | // memcpy as per section 3 of the SPIR spec. | ||
bool useFP16Conversio | bool useFP16Conversio | ||
- ArrayRef<Builtin::Info> getTargetBuiltin | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltin | ||
+ return {}; | |||
+ } | |||
std::string_view getClobbers() const override { return ""; } | std::string_view getClobbers() const override { return ""; } | ||
@@ -315,7 +317,9 @@ public: | |||
resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-" | resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-" | ||
"v256:256-v512:512-v1024:1024-n8:16:32:64-G1"); | "v256:256-v512:512-v1024:1024-n8:16:32:64-G1"); | ||
} | } | ||
- ArrayRef<Builtin::Info> getTargetBuiltin | + | ||
+ llvm::SmallVector<Builtin::InfosShard> getTargetBuiltin | |||
+ | |||
void getTargetDefines | void getTargetDefines | ||
MacroBuilder &Builder) const override; | MacroBuilder &Builder) const override; | ||
}; | }; | ||
@@ -410,7 +414,7 @@ public: | |||
std::string convertConstrain | std::string convertConstrain | ||
- | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override; | ||
void getTargetDefines | void getTargetDefines | ||
MacroBuilder &Builder) const override; | MacroBuilder &Builder) const override; |
@@ -48,7 +48,7 @@ public: | |||
bool hasFeature(StringRef Feature) const override; | bool hasFeature(StringRef Feature) const override; | ||
- | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override { | ||
// FIXME: Implement! | // FIXME: Implement! | ||
return {}; | return {}; | ||
} | } |
@@ -20,13 +20,21 @@ | |||
using namespace clang; | using namespace clang; | ||
using namespace clang::targets; | using namespace clang::targets; | ||
-static constexpr | +static constexpr int NumBuiltins = | ||
-#define BUILTIN(ID, TYPE, ATTRS) \ | + clang::SystemZ::LastTSBuiltin - Builtin::FirstTSBuiltin; | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + | ||
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ | +static constexpr llvm::StringTable BuiltinStrings = | ||
- {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + CLANG_BUILTIN_ST | ||
+#define BUILTIN CLANG_BUILTIN_ST | |||
+#define TARGET_BUILTIN CLANG_TARGET_BUI | |||
#include "clang/Basic/BuiltinsSystemZ.def" | #include "clang/Basic/BuiltinsSystemZ.def" | ||
-}; | + ; | ||
+ | |||
+static constexpr auto BuiltinInfos = Builtin::MakeInfos<NumBuiltins>({ | |||
+#define BUILTIN CLANG_BUILTIN_EN | |||
+#define TARGET_BUILTIN CLANG_TARGET_BUI | |||
+#include "clang/Basic/BuiltinsSystemZ.def" | |||
+}); | |||
const char *const SystemZTargetInf | const char *const SystemZTargetInf | ||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", | "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", | ||
@@ -172,7 +180,7 @@ void SystemZTargetInf | |||
Builder.defineMacro("__VEC__", "10305"); | Builder.defineMacro("__VEC__", "10305"); | ||
} | } | ||
-ArrayRef<Builtin::Info> SystemZTargetInf | +llvm::SmallVector<Builtin::InfosShard> | ||
- return llvm::ArrayRef(BuiltinInfo, clang::SystemZ::LastTSBuiltin - | +SystemZTargetInf | ||
- Builtin::FirstTSBuiltin); | + return {{&BuiltinStrings, BuiltinInfos}}; | ||
} | } |
@@ -100,7 +100,7 @@ public: | |||
void getTargetDefines | void getTargetDefines | ||
MacroBuilder &Builder) const override; | MacroBuilder &Builder) const override; | ||
- | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override; | ||
ArrayRef<const char *> getGCCRegNames() const override; | ArrayRef<const char *> getGCCRegNames() const override; | ||
@@ -96,7 +96,9 @@ public: | |||
bool hasFeature(StringRef Feature) const override { return Feature == "tce"; } | bool hasFeature(StringRef Feature) const override { return Feature == "tce"; } | ||
- ArrayRef<Builtin::Info> getTargetBuiltin | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltin | ||
+ return {}; | |||
+ } | |||
std::string_view getClobbers() const override { return ""; } | std::string_view getClobbers() const override { return ""; } | ||
@@ -18,11 +18,19 @@ | |||
using namespace clang; | using namespace clang; | ||
using namespace clang::targets; | using namespace clang::targets; | ||
-static constexpr | +static constexpr int NumBuiltins = | ||
-#define BUILTIN(ID, TYPE, ATTRS) \ | + clang::VE::LastTSBuiltin - Builtin::FirstTSBuiltin; | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + | ||
+static constexpr llvm::StringTable BuiltinStrings = | |||
+ CLANG_BUILTIN_ST | |||
+#define BUILTIN CLANG_BUILTIN_ST | |||
+#include "clang/Basic/BuiltinsVE.def" | |||
+ ; | |||
+ | |||
+static constexpr auto BuiltinInfos = Builtin::MakeInfos<NumBuiltins>({ | |||
+#define BUILTIN CLANG_BUILTIN_EN | |||
#include "clang/Basic/BuiltinsVE.def" | #include "clang/Basic/BuiltinsVE.def" | ||
-}; | +}); | ||
void VETargetInfo::getTargetDefines | void VETargetInfo::getTargetDefines | ||
MacroBuilder &Builder) const { | MacroBuilder &Builder) const { | ||
@@ -39,7 +47,6 @@ void VETargetInfo::ge | |||
Builder.defineMacro("__GCC_HAVE_SYNC_ | Builder.defineMacro("__GCC_HAVE_SYNC_ | ||
} | } | ||
- | +llvm::SmallVector<Builtin::InfosShard> VETargetInfo::getTargetBuiltins() const { | ||
- return llvm::ArrayRef(BuiltinInfo, | + return {{&BuiltinStrings, BuiltinInfos}}; | ||
- clang::VE::LastTSBuiltin - Builtin::FirstTSBuiltin); | |||
} | } |
@@ -55,7 +55,7 @@ public: | |||
bool hasSjLjLowering() const override { return true; } | bool hasSjLjLowering() const override { return true; } | ||
- | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override; | ||
BuiltinVaListKin | BuiltinVaListKin | ||
return TargetInfo::VoidPtrBuiltinVa | return TargetInfo::VoidPtrBuiltinVa |
@@ -20,15 +20,22 @@ | |||
using namespace clang; | using namespace clang; | ||
using namespace clang::targets; | using namespace clang::targets; | ||
-static constexpr | +static constexpr int NumBuiltins = | ||
-#define BUILTIN(ID, TYPE, ATTRS) \ | + clang::WebAssembly::LastTSBuiltin - Builtin::FirstTSBuiltin; | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + | ||
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ | +static constexpr llvm::StringTable BuiltinStrings = | ||
- {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + CLANG_BUILTIN_ST | ||
-#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ | +#define BUILTIN CLANG_BUILTIN_ST | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, ALL_LANGUAGES}, | +#define TARGET_BUILTIN CLANG_TARGET_BUI | ||
+#include "clang/Basic/BuiltinsWebAssem | |||
+ ; | |||
+ | |||
+static constexpr auto BuiltinInfos = Builtin::MakeInfos<NumBuiltins>({ | |||
+#define BUILTIN CLANG_BUILTIN_EN | |||
+#define TARGET_BUILTIN CLANG_TARGET_BUI | |||
+#define LIBBUILTIN CLANG_LIBBUILTIN | |||
#include "clang/Basic/BuiltinsWebAssem | #include "clang/Basic/BuiltinsWebAssem | ||
-}; | +}); | ||
static constexpr llvm::StringLiteral ValidCPUNames[] = { | static constexpr llvm::StringLiteral ValidCPUNames[] = { | ||
{"mvp"}, {"bleeding-edge"}, {"generic"}, {"lime1"}}; | {"mvp"}, {"bleeding-edge"}, {"generic"}, {"lime1"}}; | ||
@@ -360,9 +367,9 @@ bool WebAssemblyTarge | |||
return true; | return true; | ||
} | } | ||
-ArrayRef<Builtin::Info> WebAssemblyTarge | +llvm::SmallVector<Builtin::InfosShard> | ||
- return llvm::ArrayRef(BuiltinInfo, clang::WebAssembly::LastTSBuiltin - | +WebAssemblyTarge | ||
- Builtin::FirstTSBuiltin); | + return {{&BuiltinStrings, BuiltinInfos}}; | ||
} | } | ||
void WebAssemblyTarge | void WebAssemblyTarge |
@@ -121,7 +121,7 @@ private: | |||
bool setCPU(const std::string &Name) final { return isValidCPUName(Name); } | bool setCPU(const std::string &Name) final { return isValidCPUName(Name); } | ||
- | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const final; | ||
BuiltinVaListKin | BuiltinVaListKin | ||
return VoidPtrBuiltinVa | return VoidPtrBuiltinVa |
@@ -23,23 +23,53 @@ | |||
namespace clang { | namespace clang { | ||
namespace targets { | namespace targets { | ||
-static constexpr Builtin::Info BuiltinInfoX86[] = { | +// The x86-32 builtins are a subset and prefix of the x86-64 builtins. | ||
-#define BUILTIN(ID, TYPE, ATTRS) \ | +static constexpr int NumX86Builtins = | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + X86::LastX86CommonBui | ||
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ | +static constexpr int NumX86_64Builtin | ||
- {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + X86::LastTSBuiltin - X86::FirstX86_64Built | ||
-#define TARGET_HEADER_BU | +static constexpr int NumBuiltins = X86::LastTSBuiltin - Builtin::FirstTSBuiltin; | ||
- {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::HEADER, LANGS}, | +static_assert(NumBuiltins == (NumX86Builtins + NumX86_64Builtin | ||
+ | |||
+namespace X86 { | |||
+#define GET_BUILTIN_STR_ | |||
#include "clang/Basic/BuiltinsX86.inc" | #include "clang/Basic/BuiltinsX86.inc" | ||
+#undef GET_BUILTIN_STR_ | |||
-#define BUILTIN(ID, TYPE, ATTRS) \ | +static constexpr Builtin::Info BuiltinInfos[] = { | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | +#define GET_BUILTIN_INFO | ||
-#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ | +#include "clang/Basic/BuiltinsX86.inc" | ||
- {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | +#undef GET_BUILTIN_INFO | ||
-#define TARGET_HEADER_BU | +}; | ||
- {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::HEADER, LANGS}, | + | ||
+static constexpr Builtin::Info PrefixedBuiltinI | |||
+#define GET_BUILTIN_PREF | |||
+#include "clang/Basic/BuiltinsX86.inc" | |||
+#undef GET_BUILTIN_PREF | |||
+}; | |||
+static_assert((std::size(BuiltinInfos) + std::size(PrefixedBuiltinI | |||
+ NumX86Builtins); | |||
+} // namespace X86 | |||
+ | |||
+namespace X86_64 { | |||
+#define GET_BUILTIN_STR_ | |||
#include "clang/Basic/BuiltinsX86_64.inc" | #include "clang/Basic/BuiltinsX86_64.inc" | ||
+#undef GET_BUILTIN_STR_ | |||
+ | |||
+static constexpr Builtin::Info BuiltinInfos[] = { | |||
+#define GET_BUILTIN_INFO | |||
+#include "clang/Basic/BuiltinsX86_64.inc" | |||
+#undef GET_BUILTIN_INFO | |||
+}; | |||
+ | |||
+static constexpr Builtin::Info PrefixedBuiltinI | |||
+#define GET_BUILTIN_PREF | |||
+#include "clang/Basic/BuiltinsX86_64.inc" | |||
+#undef GET_BUILTIN_PREF | |||
}; | }; | ||
+static_assert((std::size(BuiltinInfos) + std::size(PrefixedBuiltinI | |||
+ NumX86_64Builtin | |||
+} // namespace X86_64 | |||
static const char *const GCCRegNames[] = { | static const char *const GCCRegNames[] = { | ||
"ax", "dx", "cx", "bx", "si", "di", "bp", "sp", | "ax", "dx", "cx", "bx", "si", "di", "bp", "sp", | ||
@@ -1856,12 +1886,21 @@ ArrayRef<TargetI | |||
return llvm::ArrayRef(AddlRegNames); | return llvm::ArrayRef(AddlRegNames); | ||
} | } | ||
-ArrayRef<Builtin::Info> X86_32TargetInfo | +llvm::SmallVector<Builtin::InfosShard> | ||
- return llvm::ArrayRef(BuiltinInfoX86, clang::X86::LastX86CommonBui | +X86_32TargetInfo | ||
- Builtin::FirstTSBuiltin + 1); | + return { | ||
+ {&X86::BuiltinStrings, X86::BuiltinInfos}, | |||
+ {&X86::BuiltinStrings, X86::PrefixedBuiltinI | |||
+ }; | |||
} | } | ||
-ArrayRef<Builtin::Info> X86_64TargetInfo | +llvm::SmallVector<Builtin::InfosShard> | ||
- return llvm::ArrayRef(BuiltinInfoX86, | +X86_64TargetInfo | ||
- X86::LastTSBuiltin - Builtin::FirstTSBuiltin); | + return { | ||
+ {&X86::BuiltinStrings, X86::BuiltinInfos}, | |||
+ {&X86::BuiltinStrings, X86::PrefixedBuiltinI | |||
+ {&X86_64::BuiltinStrings, X86_64::BuiltinInfos}, | |||
+ {&X86_64::BuiltinStrings, X86_64::PrefixedBuiltinI | |||
+ "__builtin_ia32_"}, | |||
+ }; | |||
} | } |
@@ -509,7 +509,7 @@ public: | |||
MaxAtomicInlineW | MaxAtomicInlineW | ||
} | } | ||
- | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override; | ||
bool hasBitIntType() const override { return true; } | bool hasBitIntType() const override { return true; } | ||
size_t getMaxBitIntWidt | size_t getMaxBitIntWidt | ||
@@ -821,7 +821,7 @@ public: | |||
MaxAtomicInlineW | MaxAtomicInlineW | ||
} | } | ||
- | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override; | ||
bool hasBitIntType() const override { return true; } | bool hasBitIntType() const override { return true; } | ||
size_t getMaxBitIntWidt | size_t getMaxBitIntWidt |
@@ -18,13 +18,20 @@ | |||
using namespace clang; | using namespace clang; | ||
using namespace clang::targets; | using namespace clang::targets; | ||
-static constexpr | +static constexpr int NumBuiltins = | ||
-#define BUILTIN(ID, TYPE, ATTRS) \ | + XCore::LastTSBuiltin - Builtin::FirstTSBuiltin; | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES}, | + | ||
-#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ | +static constexpr llvm::StringTable BuiltinStrings = | ||
- {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, ALL_LANGUAGES}, | + CLANG_BUILTIN_ST | ||
+#define BUILTIN CLANG_BUILTIN_ST | |||
+#include "clang/Basic/BuiltinsXCore.def" | |||
+ ; | |||
+ | |||
+static constexpr auto BuiltinInfos = Builtin::MakeInfos<NumBuiltins>({ | |||
+#define BUILTIN CLANG_BUILTIN_EN | |||
+#define LIBBUILTIN CLANG_LIBBUILTIN | |||
#include "clang/Basic/BuiltinsXCore.def" | #include "clang/Basic/BuiltinsXCore.def" | ||
-}; | +}); | ||
void XCoreTargetInfo::getTargetDefines | void XCoreTargetInfo::getTargetDefines | ||
MacroBuilder &Builder) const { | MacroBuilder &Builder) const { | ||
@@ -32,7 +39,7 @@ void XCoreTargetInfo: | |||
Builder.defineMacro("__XS1B__"); | Builder.defineMacro("__XS1B__"); | ||
} | } | ||
-ArrayRef<Builtin::Info> XCoreTargetInfo::getTargetBuiltin | +llvm::SmallVector<Builtin::InfosShard> | ||
- return llvm::ArrayRef(BuiltinInfo, | +XCoreTargetInfo::getTargetBuiltin | ||
- clang::XCore::LastTSBuiltin - Builtin::FirstTSBuiltin); | + return {{&BuiltinStrings, BuiltinInfos}}; | ||
} | } |
@@ -43,7 +43,7 @@ public: | |||
void getTargetDefines | void getTargetDefines | ||
MacroBuilder &Builder) const override; | MacroBuilder &Builder) const override; | ||
- | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override; | ||
BuiltinVaListKin | BuiltinVaListKin | ||
return TargetInfo::VoidPtrBuiltinVa | return TargetInfo::VoidPtrBuiltinVa |
@@ -56,8 +56,8 @@ public: | |||
void getTargetDefines | void getTargetDefines | ||
MacroBuilder &Builder) const override; | MacroBuilder &Builder) const override; | ||
- | + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override { | ||
- return | + return {}; | ||
} | } | ||
BuiltinVaListKin | BuiltinVaListKin |
@@ -73,16 +73,6 @@ void clang::ProcessWa | |||
else | else | ||
Diags.setExtensionHand | Diags.setExtensionHand | ||
- if (!Opts.DiagnosticSuppre | |||
- if (auto FileContents = | |||
- VFS.getBufferForFile | |||
- Diags.setDiagSuppressi | |||
- } else if (ReportDiags) { | |||
- Diags.Report(diag::err_drv_no_such_ | |||
- << Opts.DiagnosticSuppre | |||
- } | |||
- } | |||
- | |||
SmallVector<diag::kind, 10> _Diags; | SmallVector<diag::kind, 10> _Diags; | ||
const IntrusiveRefCntP | const IntrusiveRefCntP | ||
Diags.getDiagnosticIDs | Diags.getDiagnosticIDs | ||
@@ -237,4 +227,17 @@ void clang::ProcessWa | |||
} | } | ||
} | } | ||
} | } | ||
+ | |||
+ // Process suppression mappings file after processing other warning flags | |||
+ // (like -Wno-unknown-warning-option) as we can emit extra warnings during | |||
+ // processing. | |||
+ if (!Opts.DiagnosticSuppre | |||
+ if (auto FileContents = | |||
+ VFS.getBufferForFile | |||
+ Diags.setDiagSuppressi | |||
+ } else if (ReportDiags) { | |||
+ Diags.Report(diag::err_drv_no_such_ | |||
+ << Opts.DiagnosticSuppre | |||
+ } | |||
+ } | |||
} | } |
@@ -3,9 +3,15 @@ set(LLVM_LINK_CO | |||
Support | Support | ||
) | ) | ||
+get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIB | |||
+ | |||
add_clang_librar | add_clang_librar | ||
LowerToLLVM.cpp | LowerToLLVM.cpp | ||
LINK_LIBS | LINK_LIBS | ||
MLIRIR | MLIRIR | ||
+ ${dialect_libs} | |||
+ MLIRCIR | |||
+ MLIRBuiltinToLLV | |||
+ MLIRLLVMToLLVMIR | |||
) | ) |
@@ -10,9 +10,23 @@ | |||
// | // | ||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||
-#include | +#include "LowerToLLVM.h" | ||
+#include "mlir/Conversion/LLVMCommon/TypeConverter.h" | |||
+#include "mlir/Dialect/DLTI/DLTI.h" | |||
+#include "mlir/Dialect/Func/IR/FuncOps.h" | |||
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h" | |||
+#include "mlir/IR/BuiltinDialect.h" | |||
#include "mlir/IR/BuiltinOps.h" | #include "mlir/IR/BuiltinOps.h" | ||
+#include "mlir/Pass/Pass.h" | |||
+#include "mlir/Pass/PassManager.h" | |||
+#include "mlir/Target/LLVMIR/Dialect/Builtin/BuiltinToLLVMIRT | |||
+#include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTran | |||
+#include "mlir/Target/LLVMIR/Export.h" | |||
+#include "mlir/Transforms/DialectConversio | |||
+#include "clang/CIR/Dialect/IR/CIRAttrVisitor.h" | |||
+#include "clang/CIR/Dialect/IR/CIRDialect.h" | |||
+#include "clang/CIR/MissingFeatures.h" | |||
#include "llvm/IR/Module.h" | #include "llvm/IR/Module.h" | ||
#include "llvm/Support/TimeProfiler.h" | #include "llvm/Support/TimeProfiler.h" | ||
@@ -22,16 +36,299 @@ using namespace llvm; | |||
namespace cir { | namespace cir { | ||
namespace direct { | namespace direct { | ||
+class CIRAttrToValue : public CirAttrVisitor<CIRAttrToValue, mlir::Value> { | |||
[diff truncated] |