diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6adae58832e191..0b2e4e1be86d86 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -64,8 +64,8 @@ clang/test/AST/Interp/ @tbaederr /mlir/Dialect/*/Transforms/Bufferize.cpp @matthias-springer # Linalg Dialect in MLIR. -/mlir/include/mlir/Dialect/Linalg/* @dcaballe @nicolasvasilache @rengolin -/mlir/lib/Dialect/Linalg/* @dcaballe @nicolasvasilache @rengolin +/mlir/include/mlir/Dialect/Linalg @dcaballe @nicolasvasilache @rengolin +/mlir/lib/Dialect/Linalg @dcaballe @nicolasvasilache @rengolin /mlir/lib/Dialect/Linalg/Transforms/DecomposeLinalgOps.cpp @MaheshRavishankar @nicolasvasilache /mlir/lib/Dialect/Linalg/Transforms/DropUnitDims.cpp @MaheshRavishankar @nicolasvasilache /mlir/lib/Dialect/Linalg/Transforms/ElementwiseOpFusion.cpp @MaheshRavishankar @nicolasvasilache @@ -85,8 +85,8 @@ clang/test/AST/Interp/ @tbaederr /mlir/**/*VectorToSCF* @banach-space @dcaballe @matthias-springer @nicolasvasilache /mlir/**/*VectorToLLVM* @banach-space @dcaballe @nicolasvasilache /mlir/**/*X86Vector* @aartbik @dcaballe @nicolasvasilache -/mlir/include/mlir/Dialect/Vector/* @dcaballe @nicolasvasilache -/mlir/lib/Dialect/Vector/* @dcaballe @nicolasvasilache +/mlir/include/mlir/Dialect/Vector @dcaballe @nicolasvasilache +/mlir/lib/Dialect/Vector @dcaballe @nicolasvasilache /mlir/lib/Dialect/Vector/Transforms/* @hanhanW @nicolasvasilache /mlir/lib/Dialect/Vector/Transforms/VectorEmulateNarrowType.cpp @MaheshRavishankar @nicolasvasilache /mlir/**/*EmulateNarrowType* @dcaballe @hanhanW @@ -120,6 +120,9 @@ clang/test/AST/Interp/ @tbaederr /mlir/**/LLVMIR/**/BasicPtxBuilderInterface* @grypp /mlir/**/NVVM* @grypp +# MLIR Index Dialect +/mlir/**/Index* @mogball + # MLIR Python Bindings /mlir/test/python/ @ftynse @makslevental @stellaraccident /mlir/python/ @ftynse @makslevental @stellaraccident @@ -141,3 +144,8 @@ clang/test/AST/Interp/ @tbaederr # ExtractAPI /clang/**/ExtractAPI @daniel-grumberg + +# DWARFLinker, dwarfutil, dsymutil +/llvm/**/DWARFLinker/ @JDevlieghere +/llvm/**/dsymutil/ @JDevlieghere +/llvm/**/llvm-dwarfutil/ @JDevlieghere diff --git a/.github/workflows/issue-write.yml b/.github/workflows/issue-write.yml index e003be006c4e15..616b323ad5fac3 100644 --- a/.github/workflows/issue-write.yml +++ b/.github/workflows/issue-write.yml @@ -5,6 +5,7 @@ on: workflows: - "Check code formatting" - "Check for private emails used in PRs" + - "PR Request Release Note" types: - completed @@ -92,7 +93,11 @@ jobs: var pr_number = 0; gql_result.repository.ref.associatedPullRequests.nodes.forEach((pr) => { - if (pr.baseRepository.owner.login = context.repo.owner && pr.state == 'OPEN') { + + // The largest PR number is the one we care about. The only way + // to have more than one associated pull requests is if all the + // old pull requests are in the closed state. + if (pr.baseRepository.owner.login = context.repo.owner && pr.number > pr_number) { pr_number = pr.number; } }); diff --git a/.github/workflows/pr-request-release-note.yml b/.github/workflows/pr-request-release-note.yml index 5e48ce7aee2e2b..2fa501dda16bb3 100644 --- a/.github/workflows/pr-request-release-note.yml +++ b/.github/workflows/pr-request-release-note.yml @@ -2,7 +2,6 @@ name: PR Request Release Note permissions: contents: read - pull-requests: write on: pull_request: @@ -41,3 +40,10 @@ jobs: --token "$GITHUB_TOKEN" \ request-release-note \ --pr-number ${{ github.event.pull_request.number}} + + - uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 #v4.3.0 + if: always() + with: + name: workflow-args + path: | + comments diff --git a/bolt/docs/CommandLineArgumentReference.md b/bolt/docs/CommandLineArgumentReference.md index 49e226513028f8..00d472c5789168 100644 --- a/bolt/docs/CommandLineArgumentReference.md +++ b/bolt/docs/CommandLineArgumentReference.md @@ -56,6 +56,14 @@ Allow processing of stripped binaries +- `--alt-inst-feature-size=` + + Size of feature field in .altinstructions + +- `--alt-inst-has-padlen` + + Specify that .altinstructions has padlen field + - `--asm-dump[=]` Dump function into assembly @@ -78,6 +86,16 @@ in the input is decoded and re-encoded. If the resulting bytes do not match the input, a warning message is printed. +- `--comp-dir-override=` + + Overrides DW_AT_comp_dir, and provides an alterantive base location, which is + used with DW_AT_dwo_name to construct a path to *.dwo files. + +- `--create-debug-names-section` + + Creates .debug_names section, if the input binary doesn't have it already, for + DWARF5 CU/TUs. + - `--cu-processing-batch-size=` Specifies the size of batches for processing CUs. Higher number has better @@ -93,7 +111,7 @@ - `--debug-skeleton-cu` - Prints out offsetrs for abbrev and debu_info of Skeleton CUs that get patched. + Prints out offsets for abbrev and debug_info of Skeleton CUs that get patched. - `--deterministic-debuginfo` @@ -104,6 +122,10 @@ Add basic block instructions as tool tips on nodes +- `--dump-alt-instructions` + + Dump Linux alternative instructions info + - `--dump-cg=` Dump callgraph to the given file @@ -117,10 +139,34 @@ Dump function CFGs to graphviz format after each stage;enable '-print-loops' for color-coded blocks +- `--dump-linux-exceptions` + + Dump Linux kernel exception table + - `--dump-orc` Dump raw ORC unwind information (sorted) +- `--dump-para-sites` + + Dump Linux kernel paravitual patch sites + +- `--dump-pci-fixups` + + Dump Linux kernel PCI fixup table + +- `--dump-smp-locks` + + Dump Linux kernel SMP locks + +- `--dump-static-calls` + + Dump Linux kernel static calls + +- `--dump-static-keys` + + Dump Linux kernel static keys jump table + - `--dwarf-output-path=` Path to where .dwo files or dwp file will be written out to. @@ -205,6 +251,18 @@ Skip processing of cold functions +- `--log-file=` + + Redirect journaling to a file instead of stdout/stderr + +- `--long-jump-labels` + + Always use long jumps/nops for Linux kernel static keys + +- `--match-profile-with-function-hash` + + Match profile with function hash + - `--max-data-relocations=` Maximum number of data relocations to process @@ -274,6 +332,10 @@ Number of tasks to be created per thread +- `--terminal-trap` + + Assume that execution stops at trap instruction + - `--thread-count=` Number of threads @@ -618,10 +680,6 @@ threshold means fewer functions to process. E.g threshold of 90 means only top 10 percent of functions with profile will be processed. -- `--mcf-use-rarcs` - - In MCF, consider the possibility of cancelling flow to balance edges - - `--memcpy1-spec=` List of functions with call sites for which to specialize memcpy() for size 1 @@ -710,7 +768,7 @@ - `none`: do not reorder functions - `exec-count`: order by execution count - `hfsort`: use hfsort algorithm - - `hfsort+`: use hfsort+ algorithm + - `hfsort+`: use cache-directed sort - `cdsort`: use cache-directed sort - `pettis-hansen`: use Pettis-Hansen algorithm - `random`: reorder functions randomly @@ -804,8 +862,8 @@ - `--stale-matching-min-matched-block=` - Minimum percent of exact match block for a function to be considered for - profile inference. + Percentage threshold of matched basic blocks at which stale profile inference + is executed. - `--stale-threshold=` @@ -853,6 +911,10 @@ Only apply branch boundary alignment in hot code +- `--x86-strip-redundant-address-size` + + Remove redundant Address-Size override prefix + ### BOLT options in relocation mode: - `--align-macro-fusion=` @@ -1039,6 +1101,10 @@ Print clusters +- `--print-estimate-edge-counts` + + Print function after edge counts are set for no-LBR profile + - `--print-finalized` Print function after CFG is finalized @@ -1071,6 +1137,10 @@ Print functions after inlining optimization +- `--print-large-functions` + + Print functions that could not be overwritten due to excessive size + - `--print-longjmp` Print functions after longjmp pass @@ -1166,4 +1236,4 @@ - `--print-options` - Print non-default options after command line parsing + Print non-default options after command line parsing \ No newline at end of file diff --git a/bolt/docs/OptimizingLinux.md b/bolt/docs/OptimizingLinux.md new file mode 100644 index 00000000000000..1fffcf22529068 --- /dev/null +++ b/bolt/docs/OptimizingLinux.md @@ -0,0 +1,120 @@ +# Optimizing Linux Kernel with BOLT + + +## Introduction + +Many Linux applications spend a significant amount of their execution time in the kernel. Thus, when we consider code optimization for system performance, it is essential to improve the CPU utilization not only in the user-space applications and libraries but also in the kernel. BOLT has demonstrated double-digit gains while being applied to user-space programs. This guide shows how to apply BOLT to the x86-64 Linux kernel and enhance your system's performance. In our experiments, BOLT boosted database TPS by 2 percent when applied to the kernel compiled with the highest level optimizations, including PGO and LTO. The database spent ~40% of the time in the kernel and was quite sensitive to kernel performance. + +BOLT optimizes code layout based on a low-level execution profile collected with the Linux `perf` tool. The best quality profile should include branch history, such as Intel's last branch records (LBR). BOLT runs on a linked binary and reorders the code while combining frequently executed blocks of instructions in a manner best suited for the hardware. Other than branch instructions, most of the code is left unchanged. Additionally, BOLT updates all metadata associated with the modified code, including DWARF debug information and Linux ORC unwind information. + +While BOLT optimizations are not specific to the Linux kernel, certain quirks distinguish the kernel from user-level applications. + +BOLT has been successfully applied to and tested with several flavors of the x86-64 Linux kernel. + + +## QuickStart Guide + +BOLT operates on a statically-linked kernel executable, a.k.a. `vmlinux` binary. However, most Linux distributions use a `vmlinuz` compressed image for system booting. To use BOLT on the kernel, you must either repackage `vmlinuz` after BOLT optimizations or add steps for running BOLT into the kernel build and rebuild `vmlinuz`. Uncompressing `vmlinuz` and repackaging it with a new `vmlinux` binary falls beyond the scope of this guide, and at some point, we may add the capability to run BOLT directly on `vmlinuz`. Meanwhile, this guide focuses on steps for integrating BOLT into the kernel build process. + + +### Building the Kernel + +After downloading the kernel sources and configuration for your distribution, you should be able to build `vmlinuz` using the `make bzImage` command. Ideally, the kernel should binary match the kernel on the system you are about to optimize (the target system). The binary matching part is critical as BOLT performs profile matching and optimizations at the binary level. We recommend installing a freshly built kernel on the target system to avoid any discrepancies. + +Note that the kernel build will produce several artifacts besides bzImage. The most important of them is the uncompressed `vmlinux` binary, which will be used in the next steps. Make sure to save this file. + +Build and target systems should have a `perf` tool installed for collecting and processing profiles. If your build system differs from the target, make sure `perf` versions are compatible. The build system should also have the latest BOLT binary and tools (`llvm-bolt`, `perf2bolt`). + +Once the target system boots with the freshly-built kernel, start your workload, such as a database benchmark. While the system is under load, collect the kernel profile using perf: + + +```bash +$ sudo perf record -a -e cycles -j any,k -F 5000 -- sleep 600 +``` + + +Convert `perf` profile into a format suitable for BOLT passing the `vmlinux` binary to `perf2bolt`: + + +```bash +$ sudo chwon $USER perf.data +$ perf2bolt -p perf.data -o perf.fdata vmlinux +``` + + +Under a high load, `perf.data` should be several gigabytes in size and you should expect the converted `perf.fdata` not to exceed 100 MB. + +Two changes are required for the kernel build. The first one is optional but highly recommended. It introduces a BOLT-reserved space into `vmlinux` code section: + + +```diff +--- a/arch/x86/kernel/vmlinux.lds.S ++++ b/arch/x86/kernel/vmlinux.lds.S +@@ -139,6 +139,11 @@ SECTIONS + STATIC_CALL_TEXT + *(.gnu.warning) + ++ /* Allocate space for BOLT */ ++ __bolt_reserved_start = .; ++ . += 2048 * 1024; ++ __bolt_reserved_end = .; ++ + #ifdef CONFIG_RETPOLINE + __indirect_thunk_start = .; + *(.text.__x86.*) +``` + + +The second patch adds a step that runs BOLT on `vmlinux` binary: + + +```diff +--- a/scripts/link-vmlinux.sh ++++ b/scripts/link-vmlinux.sh +@@ -340,5 +340,13 @@ if is_enabled CONFIG_KALLSYMS; then + fi + fi + ++# Apply BOLT ++BOLT=llvm-bolt ++BOLT_PROFILE=perf.fdata ++BOLT_OPTS="--dyno-stats --eliminate-unreachable=0 --reorder-blocks=ext-tsp --simplify-conditional-tail-calls=0 --skip-funcs=__entry_text_start,irq_entries_start --split-functions" ++mv vmlinux vmlinux.pre-bolt ++echo BOLTing vmlinux ++${BOLT} vmlinux.pre-bolt -o vmlinux --data ${BOLT_PROFILE} ${BOLT_OPTS} ++ + # For fixdep + echo "vmlinux: $0" > .vmlinux.d +``` + + +If you skipped the first step or are running BOLT on a pre-built `vmlinux` binary, drop the `--split-functions` option. + + +## Performance Expectations + +By improving the code layout, BOLT can boost the kernel's performance by up to 5% by reducing instruction cache misses and branch mispredictions. When measuring total system performance, you should scale this number accordingly based on the time your application spends in the kernel (excluding I/O time). + + +## Profile Quality + +The timing and duration of the profiling may have a significant effect on the performance of the BOLTed kernel. If you don't know your workload well, it's recommended that you profile for the whole duration of the benchmark run. As longer times will result in larger `perf.data` files, you can lower the profiling frequency by providing a smaller value of `-F` flag. E.g., to record the kernel profile for half an hour, use the following command: + + +```bash +$ sudo perf record -a -e cycles -j any,k -F 1000 -- sleep 1800 +``` + + + +## BOLT Disassembly + +BOLT annotates the disassembly with control-flow information and attaches Linux-specific metadata to the code. To view annotated disassembly, run: + + +```bash +$ llvm-bolt vmlinux -o /dev/null --print-cfg +``` + + +If you want to limit the disassembly to a set of functions, add `--print-only=,,...`, where a function name is specified using regular expressions. diff --git a/bolt/include/bolt/Core/BinaryFunction.h b/bolt/include/bolt/Core/BinaryFunction.h index 3c641581e247a8..1048e50cd80582 100644 --- a/bolt/include/bolt/Core/BinaryFunction.h +++ b/bolt/include/bolt/Core/BinaryFunction.h @@ -930,6 +930,10 @@ class BinaryFunction { return const_cast(this)->getInstructionAtOffset(Offset); } + /// When the function is in disassembled state, return an instruction that + /// contains the \p Offset. + MCInst *getInstructionContainingOffset(uint64_t Offset); + std::optional disassembleInstructionAtOffset(uint64_t Offset) const; /// Return offset for the first instruction. If there is data at the diff --git a/bolt/include/bolt/Passes/BinaryFunctionCallGraph.h b/bolt/include/bolt/Core/BinaryFunctionCallGraph.h similarity index 95% rename from bolt/include/bolt/Passes/BinaryFunctionCallGraph.h rename to bolt/include/bolt/Core/BinaryFunctionCallGraph.h index 52e17db4f50ce4..4ff5b1b94c5e5c 100644 --- a/bolt/include/bolt/Passes/BinaryFunctionCallGraph.h +++ b/bolt/include/bolt/Core/BinaryFunctionCallGraph.h @@ -1,4 +1,4 @@ -//===- bolt/Passes/CallGraph.h ----------------------------------*- C++ -*-===// +//===- bolt/Core/CallGraph.h ----------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -9,7 +9,7 @@ #ifndef BOLT_PASSES_BINARY_FUNCTION_CALLGRAPH_H #define BOLT_PASSES_BINARY_FUNCTION_CALLGRAPH_H -#include "bolt/Passes/CallGraph.h" +#include "bolt/Core/CallGraph.h" #include #include #include diff --git a/bolt/include/bolt/Passes/CallGraph.h b/bolt/include/bolt/Core/CallGraph.h similarity index 98% rename from bolt/include/bolt/Passes/CallGraph.h rename to bolt/include/bolt/Core/CallGraph.h index bdbc50bb78e87d..2fc18e61afcaaa 100644 --- a/bolt/include/bolt/Passes/CallGraph.h +++ b/bolt/include/bolt/Core/CallGraph.h @@ -1,4 +1,4 @@ -//===- bolt/Passes/CallGraph.h ----------------------------------*- C++ -*-===// +//===- bolt/Core/CallGraph.h ----------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/bolt/include/bolt/Passes/CallGraphWalker.h b/bolt/include/bolt/Core/CallGraphWalker.h similarity index 95% rename from bolt/include/bolt/Passes/CallGraphWalker.h rename to bolt/include/bolt/Core/CallGraphWalker.h index ac45644be362f2..b0a73aee143691 100644 --- a/bolt/include/bolt/Passes/CallGraphWalker.h +++ b/bolt/include/bolt/Core/CallGraphWalker.h @@ -1,4 +1,4 @@ -//===- bolt/Passes/CallGraphWalker.h ----------------------------*- C++ -*-===// +//===- bolt/Core/CallGraphWalker.h ----------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h index 765372aa9e402f..83f4d4c649fd81 100644 --- a/bolt/include/bolt/Core/MCPlusBuilder.h +++ b/bolt/include/bolt/Core/MCPlusBuilder.h @@ -439,7 +439,20 @@ class MCPlusBuilder { } /// Check whether this conditional branch can be reversed - virtual bool isReversibleBranch(const MCInst &Inst) const { return true; } + virtual bool isReversibleBranch(const MCInst &Inst) const { + assert(!isUnsupportedInstruction(Inst) && isConditionalBranch(Inst) && + "Instruction is not known conditional branch"); + + if (isDynamicBranch(Inst)) + return false; + return true; + } + + /// Return true if this instruction inhibits analysis of the containing + /// function. + virtual bool isUnsupportedInstruction(const MCInst &Inst) const { + return false; + } /// Return true of the instruction is of pseudo kind. virtual bool isPseudo(const MCInst &Inst) const { diff --git a/bolt/include/bolt/Passes/HFSort.h b/bolt/include/bolt/Passes/HFSort.h index 3787187733d072..2a35760329bb8e 100644 --- a/bolt/include/bolt/Passes/HFSort.h +++ b/bolt/include/bolt/Passes/HFSort.h @@ -19,7 +19,7 @@ #ifndef BOLT_PASSES_HFSORT_H #define BOLT_PASSES_HFSORT_H -#include "bolt/Passes/CallGraph.h" +#include "bolt/Core/CallGraph.h" #include #include diff --git a/bolt/include/bolt/Passes/RegReAssign.h b/bolt/include/bolt/Passes/RegReAssign.h index c50e32ff46e293..a7554a12151042 100644 --- a/bolt/include/bolt/Passes/RegReAssign.h +++ b/bolt/include/bolt/Passes/RegReAssign.h @@ -9,7 +9,7 @@ #ifndef BOLT_PASSES_REGREASSIGN_H #define BOLT_PASSES_REGREASSIGN_H -#include "bolt/Passes/BinaryFunctionCallGraph.h" +#include "bolt/Core/BinaryFunctionCallGraph.h" #include "bolt/Passes/BinaryPasses.h" #include "bolt/Passes/RegAnalysis.h" diff --git a/bolt/include/bolt/Passes/ReorderFunctions.h b/bolt/include/bolt/Passes/ReorderFunctions.h index 4c88142c588714..7da32324bc9333 100644 --- a/bolt/include/bolt/Passes/ReorderFunctions.h +++ b/bolt/include/bolt/Passes/ReorderFunctions.h @@ -9,7 +9,7 @@ #ifndef BOLT_PASSES_REORDER_FUNCTIONS_H #define BOLT_PASSES_REORDER_FUNCTIONS_H -#include "bolt/Passes/BinaryFunctionCallGraph.h" +#include "bolt/Core/BinaryFunctionCallGraph.h" #include "bolt/Passes/BinaryPasses.h" namespace llvm { diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp index c608ff40c6d9c3..f8530c424b8e9b 100644 --- a/bolt/lib/Core/BinaryFunction.cpp +++ b/bolt/lib/Core/BinaryFunction.cpp @@ -543,7 +543,7 @@ void BinaryFunction::print(raw_ostream &OS, std::string Annotation) { else OS << "\n"; } - if (BB->getCFIState() >= 0) + if (hasCFI()) OS << " CFI State : " << BB->getCFIState() << '\n'; if (opts::EnableBAT) { OS << " Input offset: 0x" << Twine::utohexstr(BB->getInputOffset()) @@ -611,7 +611,7 @@ void BinaryFunction::print(raw_ostream &OS, std::string Annotation) { } // In CFG_Finalized state we can miscalculate CFI state at exit. - if (CurrentState == State::CFG) { + if (CurrentState == State::CFG && hasCFI()) { const int32_t CFIStateAtExit = BB->getCFIStateAtExit(); if (CFIStateAtExit >= 0) OS << " CFI State: " << CFIStateAtExit << '\n'; @@ -1276,6 +1276,10 @@ Error BinaryFunction::disassemble() { } } + bool IsUnsupported = BC.MIB->isUnsupportedInstruction(Instruction); + if (IsUnsupported) + setIgnored(); + if (MIB->isBranch(Instruction) || MIB->isCall(Instruction)) { uint64_t TargetAddress = 0; if (MIB->evaluateBranch(Instruction, AbsoluteInstrAddr, Size, @@ -1289,12 +1293,10 @@ Error BinaryFunction::disassemble() { const bool IsCondBranch = MIB->isConditionalBranch(Instruction); MCSymbol *TargetSymbol = nullptr; - if (!BC.MIB->isReversibleBranch(Instruction)) { - setIgnored(); - if (BinaryFunction *TargetFunc = + if (IsUnsupported) + if (auto *TargetFunc = BC.getBinaryFunctionContainingAddress(TargetAddress)) TargetFunc->setIgnored(); - } if (IsCall && containsAddress(TargetAddress)) { if (TargetAddress == getAddress()) { @@ -4472,6 +4474,18 @@ MCInst *BinaryFunction::getInstructionAtOffset(uint64_t Offset) { } } +MCInst *BinaryFunction::getInstructionContainingOffset(uint64_t Offset) { + assert(CurrentState == State::Disassembled && "Wrong function state"); + + if (Offset > Size) + return nullptr; + + auto II = Instructions.upper_bound(Offset); + assert(II != Instructions.begin() && "First instruction not at offset 0"); + --II; + return &II->second; +} + void BinaryFunction::printLoopInfo(raw_ostream &OS) const { if (!opts::shouldPrint(*this)) return; diff --git a/bolt/lib/Passes/BinaryFunctionCallGraph.cpp b/bolt/lib/Core/BinaryFunctionCallGraph.cpp similarity index 98% rename from bolt/lib/Passes/BinaryFunctionCallGraph.cpp rename to bolt/lib/Core/BinaryFunctionCallGraph.cpp index bbcc9751c0cbe6..b4b7897aa426ae 100644 --- a/bolt/lib/Passes/BinaryFunctionCallGraph.cpp +++ b/bolt/lib/Core/BinaryFunctionCallGraph.cpp @@ -1,4 +1,4 @@ -//===- bolt/Passes/BinaryFunctionCallGraph.cpp ----------------------------===// +//===- bolt/Core/BinaryFunctionCallGraph.cpp ----------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -#include "bolt/Passes/BinaryFunctionCallGraph.h" +#include "bolt/Core/BinaryFunctionCallGraph.h" #include "bolt/Core/BinaryContext.h" #include "bolt/Core/BinaryFunction.h" #include "llvm/Support/CommandLine.h" diff --git a/bolt/lib/Core/CMakeLists.txt b/bolt/lib/Core/CMakeLists.txt index 873cf67a56291f..bb58667066fd88 100644 --- a/bolt/lib/Core/CMakeLists.txt +++ b/bolt/lib/Core/CMakeLists.txt @@ -17,8 +17,11 @@ add_llvm_library(LLVMBOLTCore BinaryData.cpp BinaryEmitter.cpp BinaryFunction.cpp + BinaryFunctionCallGraph.cpp BinaryFunctionProfile.cpp BinarySection.cpp + CallGraph.cpp + CallGraphWalker.cpp DebugData.cpp DebugNames.cpp DIEBuilder.cpp diff --git a/bolt/lib/Passes/CallGraph.cpp b/bolt/lib/Core/CallGraph.cpp similarity index 92% rename from bolt/lib/Passes/CallGraph.cpp rename to bolt/lib/Core/CallGraph.cpp index ee2ec26f3e50d8..f1d52737bf5560 100644 --- a/bolt/lib/Passes/CallGraph.cpp +++ b/bolt/lib/Core/CallGraph.cpp @@ -1,4 +1,4 @@ -//===- bolt/Passes/CallGraph.cpp ------------------------------------------===// +//===- bolt/Core/CallGraph.cpp ------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -10,16 +10,16 @@ // //===----------------------------------------------------------------------===// -#include "bolt/Passes/CallGraph.h" +#include "bolt/Core/CallGraph.h" #define DEBUG_TYPE "callgraph" #if defined(__x86_64__) && !defined(_MSC_VER) -# if (!defined USE_SSECRC) -# define USE_SSECRC -# endif +#if (!defined USE_SSECRC) +#define USE_SSECRC +#endif #else -# undef USE_SSECRC +#undef USE_SSECRC #endif static LLVM_ATTRIBUTE_UNUSED inline size_t hash_int64_fallback(int64_t k) { @@ -50,7 +50,7 @@ static inline size_t hash_int64_pair(int64_t k1, int64_t k2) { // crc32 is commutative, so we need to perturb k1 so that (k1, k2) hashes // differently from (k2, k1). k1 += k1; - __asm("crc32q %1, %0\n" : "+r" (k1) : "rm"(k2)); + __asm("crc32q %1, %0\n" : "+r"(k1) : "rm"(k2)); return k1; #else return (hash_int64(k1) << 1) ^ hash_int64(k2); @@ -118,5 +118,5 @@ void CallGraph::adjustArcWeights() { } } -} -} +} // namespace bolt +} // namespace llvm diff --git a/bolt/lib/Passes/CallGraphWalker.cpp b/bolt/lib/Core/CallGraphWalker.cpp similarity index 90% rename from bolt/lib/Passes/CallGraphWalker.cpp rename to bolt/lib/Core/CallGraphWalker.cpp index 53fb1cb4d98c99..cbfa178d8e0687 100644 --- a/bolt/lib/Passes/CallGraphWalker.cpp +++ b/bolt/lib/Core/CallGraphWalker.cpp @@ -1,4 +1,4 @@ -//===- bolt/Passes/CallGraphWalker.cpp ------------------------------------===// +//===- bolt/Core/CallGraphWalker.cpp ------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -10,8 +10,8 @@ // //===----------------------------------------------------------------------===// -#include "bolt/Passes/CallGraphWalker.h" -#include "bolt/Passes/BinaryFunctionCallGraph.h" +#include "bolt/Core/CallGraphWalker.h" +#include "bolt/Core/BinaryFunctionCallGraph.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Timer.h" #include diff --git a/bolt/lib/Passes/CMakeLists.txt b/bolt/lib/Passes/CMakeLists.txt index 04057a895d6662..407d8b03f73977 100644 --- a/bolt/lib/Passes/CMakeLists.txt +++ b/bolt/lib/Passes/CMakeLists.txt @@ -4,11 +4,8 @@ add_llvm_library(LLVMBOLTPasses AllocCombiner.cpp AsmDump.cpp BinaryPasses.cpp - BinaryFunctionCallGraph.cpp CMOVConversion.cpp CacheMetrics.cpp - CallGraph.cpp - CallGraphWalker.cpp DataflowAnalysis.cpp DataflowInfoManager.cpp FrameAnalysis.cpp diff --git a/bolt/lib/Passes/FrameAnalysis.cpp b/bolt/lib/Passes/FrameAnalysis.cpp index 4ebfd8f158f7f5..e027fc0403cd9f 100644 --- a/bolt/lib/Passes/FrameAnalysis.cpp +++ b/bolt/lib/Passes/FrameAnalysis.cpp @@ -11,8 +11,8 @@ //===----------------------------------------------------------------------===// #include "bolt/Passes/FrameAnalysis.h" +#include "bolt/Core/CallGraphWalker.h" #include "bolt/Core/ParallelUtilities.h" -#include "bolt/Passes/CallGraphWalker.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/Support/Timer.h" #include diff --git a/bolt/lib/Passes/FrameOptimizer.cpp b/bolt/lib/Passes/FrameOptimizer.cpp index 8461225e1819c1..1c0f9555f9eb9b 100644 --- a/bolt/lib/Passes/FrameOptimizer.cpp +++ b/bolt/lib/Passes/FrameOptimizer.cpp @@ -11,8 +11,8 @@ //===----------------------------------------------------------------------===// #include "bolt/Passes/FrameOptimizer.h" +#include "bolt/Core/BinaryFunctionCallGraph.h" #include "bolt/Core/ParallelUtilities.h" -#include "bolt/Passes/BinaryFunctionCallGraph.h" #include "bolt/Passes/DataflowInfoManager.h" #include "bolt/Passes/ShrinkWrapping.h" #include "bolt/Passes/StackAvailableExpressions.h" diff --git a/bolt/lib/Passes/IndirectCallPromotion.cpp b/bolt/lib/Passes/IndirectCallPromotion.cpp index 55eede641fd2f7..a73eb867b37775 100644 --- a/bolt/lib/Passes/IndirectCallPromotion.cpp +++ b/bolt/lib/Passes/IndirectCallPromotion.cpp @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// #include "bolt/Passes/IndirectCallPromotion.h" -#include "bolt/Passes/BinaryFunctionCallGraph.h" +#include "bolt/Core/BinaryFunctionCallGraph.h" #include "bolt/Passes/DataflowInfoManager.h" #include "bolt/Passes/Inliner.h" #include "llvm/ADT/STLExtras.h" diff --git a/bolt/lib/Passes/Instrumentation.cpp b/bolt/lib/Passes/Instrumentation.cpp index 14f506f9ca9689..e824a42d826964 100644 --- a/bolt/lib/Passes/Instrumentation.cpp +++ b/bolt/lib/Passes/Instrumentation.cpp @@ -479,8 +479,7 @@ void Instrumentation::instrumentFunction(BinaryFunction &Function, HasJumpTable = true; else if (BC.MIB->isUnconditionalBranch(Inst)) HasUnconditionalBranch = true; - else if ((!BC.MIB->isCall(Inst) && !BC.MIB->isConditionalBranch(Inst)) || - !BC.MIB->isReversibleBranch(Inst)) + else if (!(BC.MIB->isCall(Inst) || BC.MIB->isConditionalBranch(Inst))) continue; const uint32_t FromOffset = *BC.MIB->getOffset(Inst); diff --git a/bolt/lib/Passes/JTFootprintReduction.cpp b/bolt/lib/Passes/JTFootprintReduction.cpp index fd291f96004d93..71bdbba950df14 100644 --- a/bolt/lib/Passes/JTFootprintReduction.cpp +++ b/bolt/lib/Passes/JTFootprintReduction.cpp @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// #include "bolt/Passes/JTFootprintReduction.h" -#include "bolt/Passes/BinaryFunctionCallGraph.h" +#include "bolt/Core/BinaryFunctionCallGraph.h" #include "bolt/Passes/DataflowInfoManager.h" #include "llvm/Support/CommandLine.h" diff --git a/bolt/lib/Passes/RegAnalysis.cpp b/bolt/lib/Passes/RegAnalysis.cpp index 9054385c20b59b..66ca6800b1a5fa 100644 --- a/bolt/lib/Passes/RegAnalysis.cpp +++ b/bolt/lib/Passes/RegAnalysis.cpp @@ -12,7 +12,7 @@ #include "bolt/Passes/RegAnalysis.h" #include "bolt/Core/BinaryFunction.h" -#include "bolt/Passes/CallGraphWalker.h" +#include "bolt/Core/CallGraphWalker.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/Support/CommandLine.h" diff --git a/bolt/lib/Passes/RegReAssign.cpp b/bolt/lib/Passes/RegReAssign.cpp index 0becfb4a06a38c..60349f18b11d39 100644 --- a/bolt/lib/Passes/RegReAssign.cpp +++ b/bolt/lib/Passes/RegReAssign.cpp @@ -11,8 +11,8 @@ //===----------------------------------------------------------------------===// #include "bolt/Passes/RegReAssign.h" +#include "bolt/Core/BinaryFunctionCallGraph.h" #include "bolt/Core/MCPlus.h" -#include "bolt/Passes/BinaryFunctionCallGraph.h" #include "bolt/Passes/DataflowAnalysis.h" #include "bolt/Passes/DataflowInfoManager.h" #include "bolt/Utils/Utils.h" diff --git a/bolt/lib/Passes/StokeInfo.cpp b/bolt/lib/Passes/StokeInfo.cpp index 499cac4217099c..dd033508d200c1 100644 --- a/bolt/lib/Passes/StokeInfo.cpp +++ b/bolt/lib/Passes/StokeInfo.cpp @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// #include "bolt/Passes/StokeInfo.h" -#include "bolt/Passes/BinaryFunctionCallGraph.h" +#include "bolt/Core/BinaryFunctionCallGraph.h" #include "bolt/Passes/DataflowInfoManager.h" #include "llvm/Support/CommandLine.h" diff --git a/bolt/lib/Profile/YAMLProfileReader.cpp b/bolt/lib/Profile/YAMLProfileReader.cpp index f25f59201f1cd9..554def697fa21c 100644 --- a/bolt/lib/Profile/YAMLProfileReader.cpp +++ b/bolt/lib/Profile/YAMLProfileReader.cpp @@ -22,12 +22,18 @@ namespace opts { extern cl::opt Verbosity; extern cl::OptionCategory BoltOptCategory; extern cl::opt InferStaleProfile; +extern cl::opt Lite; static llvm::cl::opt IgnoreHash("profile-ignore-hash", cl::desc("ignore hash while reading function profile"), cl::Hidden, cl::cat(BoltOptCategory)); +llvm::cl::opt + MatchProfileWithFunctionHash("match-profile-with-function-hash", + cl::desc("Match profile with function hash"), + cl::Hidden, cl::cat(BoltOptCategory)); + llvm::cl::opt ProfileUseDFS("profile-use-dfs", cl::desc("use DFS order for YAML profile"), cl::Hidden, cl::cat(BoltOptCategory)); @@ -329,6 +335,8 @@ Error YAMLProfileReader::preprocessProfile(BinaryContext &BC) { } bool YAMLProfileReader::mayHaveProfileData(const BinaryFunction &BF) { + if (opts::MatchProfileWithFunctionHash) + return true; for (StringRef Name : BF.getNames()) if (ProfileFunctionNames.contains(Name)) return true; @@ -363,9 +371,24 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) { return Profile.Hash == static_cast(BF.getHash()); }; - // We have to do 2 passes since LTO introduces an ambiguity in function - // names. The first pass assigns profiles that match 100% by name and - // by hash. The second pass allows name ambiguity for LTO private functions. + uint64_t MatchedWithExactName = 0; + uint64_t MatchedWithHash = 0; + uint64_t MatchedWithLTOCommonName = 0; + + // Computes hash for binary functions. + if (opts::MatchProfileWithFunctionHash) { + for (auto &[_, BF] : BC.getBinaryFunctions()) { + BF.computeHash(YamlBP.Header.IsDFSOrder, YamlBP.Header.HashFunction); + } + } else if (!opts::IgnoreHash) { + for (BinaryFunction *BF : ProfileBFs) { + if (!BF) + continue; + BF->computeHash(YamlBP.Header.IsDFSOrder, YamlBP.Header.HashFunction); + } + } + + // This first pass assigns profiles that match 100% by name and by hash. for (auto [YamlBF, BF] : llvm::zip_equal(YamlBP.Functions, ProfileBFs)) { if (!BF) continue; @@ -374,15 +397,35 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) { // the profile. Function.setExecutionCount(BinaryFunction::COUNT_NO_PROFILE); - // Recompute hash once per function. - if (!opts::IgnoreHash) - Function.computeHash(YamlBP.Header.IsDFSOrder, - YamlBP.Header.HashFunction); - - if (profileMatches(YamlBF, Function)) + if (profileMatches(YamlBF, Function)) { matchProfileToFunction(YamlBF, Function); + ++MatchedWithExactName; + } } + // Iterates through profiled functions to match the first binary function with + // the same exact hash. Serves to match identical, renamed functions. + // Collisions are possible where multiple functions share the same exact hash. + if (opts::MatchProfileWithFunctionHash) { + DenseMap StrictHashToBF; + StrictHashToBF.reserve(BC.getBinaryFunctions().size()); + + for (auto &[_, BF] : BC.getBinaryFunctions()) + StrictHashToBF[BF.getHash()] = &BF; + + for (yaml::bolt::BinaryFunctionProfile &YamlBF : YamlBP.Functions) { + if (YamlBF.Used) + continue; + auto It = StrictHashToBF.find(YamlBF.Hash); + if (It != StrictHashToBF.end() && !ProfiledFunctions.count(It->second)) { + BinaryFunction *BF = It->second; + matchProfileToFunction(YamlBF, *BF); + ++MatchedWithHash; + } + } + } + + // This second pass allows name ambiguity for LTO private functions. for (const auto &[CommonName, LTOProfiles] : LTOCommonNameMap) { if (!LTOCommonNameFunctionMap.contains(CommonName)) continue; @@ -396,6 +439,7 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) { for (BinaryFunction *BF : Functions) { if (!ProfiledFunctions.count(BF) && profileMatches(*YamlBF, *BF)) { matchProfileToFunction(*YamlBF, *BF); + ++MatchedWithLTOCommonName; return true; } } @@ -407,8 +451,10 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) { // partially. if (!ProfileMatched && LTOProfiles.size() == 1 && Functions.size() == 1 && !LTOProfiles.front()->Used && - !ProfiledFunctions.count(*Functions.begin())) + !ProfiledFunctions.count(*Functions.begin())) { matchProfileToFunction(*LTOProfiles.front(), **Functions.begin()); + ++MatchedWithLTOCommonName; + } } for (auto [YamlBF, BF] : llvm::zip_equal(YamlBP.Functions, ProfileBFs)) @@ -420,6 +466,15 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) { errs() << "BOLT-WARNING: profile ignored for function " << YamlBF.Name << '\n'; + if (opts::Verbosity >= 1) { + outs() << "BOLT-INFO: matched " << MatchedWithExactName + << " functions with identical names\n"; + outs() << "BOLT-INFO: matched " << MatchedWithHash + << " functions with hash\n"; + outs() << "BOLT-INFO: matched " << MatchedWithLTOCommonName + << " functions with matching LTO common names\n"; + } + // Set for parseFunctionProfile(). NormalizeByInsnCount = usesEvent("cycles") || usesEvent("instructions"); NormalizeByCalls = usesEvent("branches"); @@ -439,6 +494,12 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) { BC.setNumUnusedProfiledObjects(NumUnused); + if (opts::Lite && opts::MatchProfileWithFunctionHash) { + for (BinaryFunction *BF : BC.getAllBinaryFunctions()) + if (!BF->hasProfile()) + BF->setIgnored(); + } + return Error::success(); } diff --git a/bolt/lib/Rewrite/LinuxKernelRewriter.cpp b/bolt/lib/Rewrite/LinuxKernelRewriter.cpp index aa18e79f73b9d2..03b414b71caca7 100644 --- a/bolt/lib/Rewrite/LinuxKernelRewriter.cpp +++ b/bolt/lib/Rewrite/LinuxKernelRewriter.cpp @@ -295,9 +295,6 @@ class LinuxKernelRewriter final : public MetadataRewriter { if (Error E = processSMPLocks()) return E; - if (Error E = readORCTables()) - return E; - if (Error E = readStaticCalls()) return E; @@ -313,6 +310,11 @@ class LinuxKernelRewriter final : public MetadataRewriter { if (Error E = readAltInstructions()) return E; + // Some ORC entries could be linked to alternative instruction + // sequences. Hence, we read ORC after .altinstructions. + if (Error E = readORCTables()) + return E; + if (Error E = readPCIFixupTable()) return E; @@ -563,11 +565,28 @@ Error LinuxKernelRewriter::readORCTables() { if (!BF->hasInstructions()) continue; - MCInst *Inst = BF->getInstructionAtOffset(IP - BF->getAddress()); - if (!Inst) + const uint64_t Offset = IP - BF->getAddress(); + MCInst *Inst = BF->getInstructionAtOffset(Offset); + if (!Inst) { + // Check if there is an alternative instruction(s) at this IP. Multiple + // alternative instructions can take a place of a single original + // instruction and each alternative can have a separate ORC entry. + // Since ORC table is shared between all alternative sequences, there's + // a requirement that only one (out of many) sequences can have an + // instruction from the ORC table to avoid ambiguities/conflicts. + // + // For now, we have limited support for alternatives. I.e. we still print + // functions with them, but will not change the code in the output binary. + // As such, we can ignore alternative ORC entries. They will be preserved + // in the binary, but will not get printed in the instruction stream. + Inst = BF->getInstructionContainingOffset(Offset); + if (Inst || BC.MIB->hasAnnotation(*Inst, "AltInst")) + continue; + return createStringError( errc::executable_format_error, "no instruction at address 0x%" PRIx64 " in .orc_unwind_ip", IP); + } // Some addresses will have two entries associated with them. The first // one being a "weak" section terminator. Since we ignore the terminator, @@ -1440,7 +1459,7 @@ Error LinuxKernelRewriter::tryReadAltInstructions(uint32_t AltInstFeatureSize, AltBF->setIgnored(); } - if (!BF || !BC.shouldEmit(*BF)) + if (!BF || !BF->hasInstructions()) continue; if (OrgInstAddress + OrgSize > BF->getAddress() + BF->getSize()) diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index 1a3a8af21d81b6..c118f2c3ccd65c 100644 --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -82,6 +82,7 @@ extern cl::opt Hugify; extern cl::opt Instrument; extern cl::opt JumpTables; extern cl::opt KeepNops; +extern cl::opt Lite; extern cl::list ReorderData; extern cl::opt ReorderFunctions; extern cl::opt TerminalTrap; @@ -140,9 +141,6 @@ KeepTmp("keep-tmp", cl::Hidden, cl::cat(BoltCategory)); -cl::opt Lite("lite", cl::desc("skip processing of cold functions"), - cl::cat(BoltCategory)); - static cl::opt LiteThresholdPct("lite-threshold-pct", cl::desc("threshold (in percent) for selecting functions to process in lite " diff --git a/bolt/lib/Target/X86/X86MCPlusBuilder.cpp b/bolt/lib/Target/X86/X86MCPlusBuilder.cpp index 515c9a94c58cd4..5bd77958934f92 100644 --- a/bolt/lib/Target/X86/X86MCPlusBuilder.cpp +++ b/bolt/lib/Target/X86/X86MCPlusBuilder.cpp @@ -328,19 +328,19 @@ class X86MCPlusBuilder : public MCPlusBuilder { return false; } - bool isReversibleBranch(const MCInst &Inst) const override { - if (isDynamicBranch(Inst)) - return false; - + bool isUnsupportedInstruction(const MCInst &Inst) const override { switch (Inst.getOpcode()) { default: - return true; + return false; + case X86::LOOP: case X86::LOOPE: case X86::LOOPNE: case X86::JECXZ: case X86::JRCXZ: - return false; + // These have a short displacement, and therefore (often) break after + // basic block relayout. + return true; } } @@ -1879,11 +1879,9 @@ class X86MCPlusBuilder : public MCPlusBuilder { continue; } - // Handle conditional branches and ignore indirect branches - if (isReversibleBranch(*I) && getCondCode(*I) == X86::COND_INVALID) { - // Indirect branch + // Ignore indirect branches + if (getCondCode(*I) == X86::COND_INVALID) return false; - } if (CondBranch == nullptr) { const MCSymbol *TargetBB = getTargetSymbol(*I); diff --git a/bolt/lib/Utils/CommandLineOpts.cpp b/bolt/lib/Utils/CommandLineOpts.cpp index 41c89bc8aeba4e..b9bc79f408a6b2 100644 --- a/bolt/lib/Utils/CommandLineOpts.cpp +++ b/bolt/lib/Utils/CommandLineOpts.cpp @@ -128,6 +128,9 @@ cl::opt cl::desc("instrument code to generate accurate profile data"), cl::cat(BoltOptCategory)); +cl::opt Lite("lite", cl::desc("skip processing of cold functions"), + cl::cat(BoltCategory)); + cl::opt OutputFilename("o", cl::desc(""), diff --git a/bolt/test/X86/hashing-based-function-matching.test b/bolt/test/X86/hashing-based-function-matching.test new file mode 100644 index 00000000000000..41c991b4612ece --- /dev/null +++ b/bolt/test/X86/hashing-based-function-matching.test @@ -0,0 +1,63 @@ +## Tests function matching in YAMLProfileReader by function hash. + +# REQUIRES: system-linux +# RUN: split-file %s %t +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %t/main.s -o %t.o +# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q -nostdlib +# RUN: llvm-bolt %t.exe -o %t.out --data %t/yaml -v=2 \ +# RUN: --print-cfg --match-profile-with-function-hash --profile-ignore-hash=0 2>&1 | FileCheck %s + +# CHECK: BOLT-INFO: matched 1 functions with hash + +#--- main.s +.globl main +.type main, @function +main: + .cfi_startproc +.LBB00: + pushq %rbp + movq %rsp, %rbp + subq $16, %rsp + testq %rax, %rax + js .LBB03 +.LBB01: + jne .LBB04 +.LBB02: + nop +.LBB03: + xorl %eax, %eax + addq $16, %rsp + popq %rbp + retq +.LBB04: + xorl %eax, %eax + addq $16, %rsp + popq %rbp + retq +## For relocations against .text + .reloc 0, R_X86_64_NONE + .cfi_endproc + .size main, .-main + +#--- yaml +--- +header: + profile-version: 1 + binary-name: 'hashing-based-function-matching.s.tmp.exe' + binary-build-id: '' + profile-flags: [ lbr ] + profile-origin: branch profile reader + profile-events: '' + dfs-order: false + hash-func: xxh3 +functions: + - name: main2 + fid: 0 + hash: 0x6E7F15254DE2478 + exec: 1 + nblocks: 6 + blocks: + - bid: 1 + insns: 1 + succ: [ { bid: 3, cnt: 1} ] +... diff --git a/bolt/test/X86/issue20.s b/bolt/test/X86/issue20.s index 99a4f2ea2ac998..9645eaf2e62234 100644 --- a/bolt/test/X86/issue20.s +++ b/bolt/test/X86/issue20.s @@ -13,7 +13,6 @@ # CHECK-NOT: BOLT-INFO: UCE removed {{.*}} blocks and {{.*}} bytes of code # CHECK: Binary Function "main" # CHECK: .LFT{{.*}} (2 instructions, align : 1) -# CHECK-NEXT: CFI State : 0 # CHECK-NEXT: 00000004: andq # CHECK-NEXT: 00000008: jmpq # CHECK-NEXT: Successors: .Ltmp{{.*}}, .Ltmp{{.*}}, .Ltmp{{.*}}, .Ltmp{{.*}} diff --git a/bolt/test/X86/issue20.test b/bolt/test/X86/issue20.test index dcb1ce5ab1567f..09f9c36cc9e3dc 100644 --- a/bolt/test/X86/issue20.test +++ b/bolt/test/X86/issue20.test @@ -9,7 +9,6 @@ CHECK-NOT: BOLT-INFO: UCE removed {{.*}} blocks and {{.*}}| bytes of code CHECK: Binary Function "main" CHECK: .LFT0 (2 instructions, align : 1) -CHECK-NEXT: CFI State : 0 CHECK-NEXT: 00000004: andq CHECK-NEXT: 00000008: jmpq CHECK-NEXT: Successors: .Ltmp1, .Ltmp2, .Ltmp3, .Ltmp4 diff --git a/bolt/test/X86/linux-alt-instruction.s b/bolt/test/X86/linux-alt-instruction.s index dc1b12a277785b..fe3abbfc2b4c93 100644 --- a/bolt/test/X86/linux-alt-instruction.s +++ b/bolt/test/X86/linux-alt-instruction.s @@ -38,7 +38,7 @@ # RUN: llvm-bolt %t.exe --print-cfg -o %t.fs4.out | FileCheck %s # CHECK: BOLT-INFO: Linux kernel binary detected -# CHECK: BOLT-INFO: parsed 2 alternative instruction entries +# CHECK: BOLT-INFO: parsed 3 alternative instruction entries .text .globl _start @@ -50,10 +50,12 @@ _start: # CHECK: rdtsc # CHECK-SAME: AltInst: 1 # CHECK-SAME: AltInst2: 2 +# CHECK-SAME: AltInst3: 3 nop # CHECK-NEXT: nop # CHECK-SAME: AltInst: 1 # CHECK-SAME: AltInst2: 2 +# CHECK-SAME: AltInst3: 3 nop nop .L1: @@ -66,6 +68,9 @@ _start: rdtsc .A1: rdtscp +.A2: + pushf + pop %rax .Ae: ## Alternative instruction info. @@ -92,11 +97,51 @@ _start: .word 0x3b # feature flags .endif .byte .L1 - .L0 # org size - .byte .Ae - .A1 # alt size + .byte .A2 - .A1 # alt size .ifdef PADLEN .byte 0 .endif + .long .L0 - . # org instruction + .long .A2 - . # alt instruction +.ifdef FEATURE_SIZE_4 + .long 0x110 # feature flags +.else + .word 0x110 # feature flags +.endif + .byte .L1 - .L0 # org size + .byte .Ae - .A2 # alt size +.ifdef PADLEN + .byte 0 +.endif + +## ORC unwind for "pushf; pop %rax" alternative sequence. + .section .orc_unwind,"a",@progbits + .align 4 + .section .orc_unwind_ip,"a",@progbits + .align 4 + + .section .orc_unwind + .2byte 8 + .2byte 0 + .2byte 0x205 + .section .orc_unwind_ip + .long _start - . + + .section .orc_unwind + .2byte 16 + .2byte 0 + .2byte 0x205 + .section .orc_unwind_ip + .long .L0 + 1 - . + + .section .orc_unwind + .2byte 8 + .2byte 0 + .2byte 0x205 + .section .orc_unwind_ip + .long .L0 + 2 - . + ## Fake Linux Kernel sections. .section __ksymtab,"a",@progbits .section __ksymtab_gpl,"a",@progbits diff --git a/bolt/test/X86/sctc-bug4.test b/bolt/test/X86/sctc-bug4.test index 21a602b6729ae3..e192a238a4d0c9 100644 --- a/bolt/test/X86/sctc-bug4.test +++ b/bolt/test/X86/sctc-bug4.test @@ -6,24 +6,19 @@ RUN: llvm-bolt %t -o %t.null --enable-bat \ RUN: -funcs=test_func -print-sctc -sequential-disassembly 2>&1 | FileCheck %s CHECK: .Ltmp2 (3 instructions, align : 1) -CHECK-NEXT: CFI State : 0 CHECK-NEXT: Input offset: 0x24 CHECK-NEXT: Predecessors: .LFT1 CHECK-NEXT: 00000024: cmpq $0x20, %rsi CHECK-NEXT: 00000028: ja dummy # TAILCALL # Offset: 53 # CTCTakenCount: 0 CHECK-NEXT: 0000002a: jmp .Ltmp4 CHECK-NEXT: Successors: .Ltmp4 -CHECK-NEXT: CFI State: 0 CHECK: .Ltmp1 (2 instructions, align : 1) -CHECK-NEXT: CFI State : 0 CHECK-NEXT: Input offset: 0x2c CHECK-NEXT: Predecessors: .LFT0 CHECK-NEXT: 0000002c: xorq %r11, %rax CHECK-NEXT: 0000002f: retq -CHECK-NEXT: CFI State: 0 CHECK: .Ltmp4 (4 instructions, align : 1) -CHECK-NEXT: CFI State : 0 CHECK-NEXT: Input offset: 0x3a CHECK-NEXT: Predecessors: .Ltmp2 diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp index c0faf5f7e8fd9b..b5da17564c2e01 100644 --- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp +++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp @@ -55,7 +55,7 @@ class HTMLTag { operator TagType() const { return Value; } operator bool() = delete; - bool IsSelfClosing() const; + bool isSelfClosing() const; llvm::SmallString<16> ToString() const; private: @@ -71,7 +71,7 @@ struct HTMLNode { HTMLNode(NodeType Type) : Type(Type) {} virtual ~HTMLNode() = default; - virtual void Render(llvm::raw_ostream &OS, int IndentationLevel) = 0; + virtual void render(llvm::raw_ostream &OS, int IndentationLevel) = 0; NodeType Type; // Type of node }; @@ -80,7 +80,7 @@ struct TextNode : public HTMLNode { : HTMLNode(NodeType::NODE_TEXT), Text(Text.str()) {} std::string Text; // Content of node - void Render(llvm::raw_ostream &OS, int IndentationLevel) override; + void render(llvm::raw_ostream &OS, int IndentationLevel) override; }; struct TagNode : public HTMLNode { @@ -94,17 +94,17 @@ struct TagNode : public HTMLNode { std::vector> Attributes; // List of key-value attributes for tag - void Render(llvm::raw_ostream &OS, int IndentationLevel) override; + void render(llvm::raw_ostream &OS, int IndentationLevel) override; }; constexpr const char *kDoctypeDecl = ""; struct HTMLFile { std::vector> Children; // List of child nodes - void Render(llvm::raw_ostream &OS) { + void render(llvm::raw_ostream &OS) { OS << kDoctypeDecl << "\n"; for (const auto &C : Children) { - C->Render(OS, 0); + C->render(OS, 0); OS << "\n"; } } @@ -112,7 +112,7 @@ struct HTMLFile { } // namespace -bool HTMLTag::IsSelfClosing() const { +bool HTMLTag::isSelfClosing() const { switch (Value) { case HTMLTag::TAG_META: case HTMLTag::TAG_LINK: @@ -177,12 +177,12 @@ llvm::SmallString<16> HTMLTag::ToString() const { llvm_unreachable("Unhandled HTMLTag::TagType"); } -void TextNode::Render(llvm::raw_ostream &OS, int IndentationLevel) { +void TextNode::render(llvm::raw_ostream &OS, int IndentationLevel) { OS.indent(IndentationLevel * 2); printHTMLEscaped(Text, OS); } -void TagNode::Render(llvm::raw_ostream &OS, int IndentationLevel) { +void TagNode::render(llvm::raw_ostream &OS, int IndentationLevel) { // Children nodes are rendered in the same line if all of them are text nodes bool InlineChildren = true; for (const auto &C : Children) @@ -194,7 +194,7 @@ void TagNode::Render(llvm::raw_ostream &OS, int IndentationLevel) { OS << "<" << Tag.ToString(); for (const auto &A : Attributes) OS << " " << A.first << "=\"" << A.second << "\""; - if (Tag.IsSelfClosing()) { + if (Tag.isSelfClosing()) { OS << "/>"; return; } @@ -205,7 +205,7 @@ void TagNode::Render(llvm::raw_ostream &OS, int IndentationLevel) { for (const auto &C : Children) { int ChildrenIndentation = InlineChildren || !NewLineRendered ? 0 : IndentationLevel + 1; - C->Render(OS, ChildrenIndentation); + C->render(OS, ChildrenIndentation); if (!InlineChildren && (C == Children.back() || (C->Type != NodeType::NODE_TEXT || (&C + 1)->get()->Type != NodeType::NODE_TEXT))) { @@ -221,7 +221,7 @@ void TagNode::Render(llvm::raw_ostream &OS, int IndentationLevel) { template ::value>> -static void AppendVector(std::vector &&New, +static void appendVector(std::vector &&New, std::vector &Original) { std::move(New.begin(), New.end(), std::back_inserter(Original)); } @@ -289,9 +289,18 @@ genStylesheetsHTML(StringRef InfoPath, const ClangDocContext &CDCtx) { static std::vector> genJsScriptsHTML(StringRef InfoPath, const ClangDocContext &CDCtx) { std::vector> Out; + + // index_json.js is part of every generated HTML file + SmallString<128> IndexJSONPath = computeRelativePath("", InfoPath); + auto IndexJSONNode = std::make_unique(HTMLTag::TAG_SCRIPT); + llvm::sys::path::append(IndexJSONPath, "index_json.js"); + llvm::sys::path::native(IndexJSONPath, llvm::sys::path::Style::posix); + IndexJSONNode->Attributes.emplace_back("src", std::string(IndexJSONPath)); + Out.emplace_back(std::move(IndexJSONNode)); + for (const auto &FilePath : CDCtx.JsScripts) { - auto ScriptNode = std::make_unique(HTMLTag::TAG_SCRIPT); SmallString<128> ScriptPath = computeRelativePath("", InfoPath); + auto ScriptNode = std::make_unique(HTMLTag::TAG_SCRIPT); llvm::sys::path::append(ScriptPath, llvm::sys::path::filename(FilePath)); // Paths in HTML must be in posix-style llvm::sys::path::native(ScriptPath, llvm::sys::path::Style::posix); @@ -313,8 +322,7 @@ genReference(const Reference &Type, StringRef CurrentDirectory, if (Type.Path.empty()) { if (!JumpToSection) return std::make_unique(Type.Name); - else - return genLink(Type.Name, "#" + *JumpToSection); + return genLink(Type.Name, "#" + *JumpToSection); } llvm::SmallString<64> Path = Type.getRelativeFilePath(CurrentDirectory); llvm::sys::path::append(Path, Type.getFileBaseName() + ".html"); @@ -357,7 +365,7 @@ genEnumsBlock(const std::vector &Enums, auto &DivBody = Out.back(); for (const auto &E : Enums) { std::vector> Nodes = genHTML(E, CDCtx); - AppendVector(std::move(Nodes), DivBody->Children); + appendVector(std::move(Nodes), DivBody->Children); } return Out; } @@ -388,7 +396,7 @@ genFunctionsBlock(const std::vector &Functions, for (const auto &F : Functions) { std::vector> Nodes = genHTML(F, CDCtx, ParentInfoDir); - AppendVector(std::move(Nodes), DivBody->Children); + appendVector(std::move(Nodes), DivBody->Children); } return Out; } @@ -478,10 +486,10 @@ genFileHeadNodes(StringRef Title, StringRef InfoPath, Out.emplace_back(std::make_unique(HTMLTag::TAG_TITLE, Title)); std::vector> StylesheetsNodes = genStylesheetsHTML(InfoPath, CDCtx); - AppendVector(std::move(StylesheetsNodes), Out); + appendVector(std::move(StylesheetsNodes), Out); std::vector> JsNodes = genJsScriptsHTML(InfoPath, CDCtx); - AppendVector(std::move(JsNodes), Out); + appendVector(std::move(JsNodes), Out); return Out; } @@ -513,7 +521,7 @@ static std::unique_ptr genInfoFileMainNode( MainContentNode->Attributes.emplace_back("id", "main-content"); MainContentNode->Attributes.emplace_back( "class", "col-xs-12 col-sm-9 col-md-8 main-content"); - AppendVector(std::move(MainContentInnerNodes), MainContentNode->Children); + appendVector(std::move(MainContentInnerNodes), MainContentNode->Children); auto RightSidebarNode = std::make_unique(HTMLTag::TAG_DIV); RightSidebarNode->Attributes.emplace_back("id", "sidebar-right"); @@ -521,7 +529,7 @@ static std::unique_ptr genInfoFileMainNode( "class", "col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right"); std::vector> InfoIndexHTML = genHTML(InfoIndex, InfoPath, true); - AppendVector(std::move(InfoIndexHTML), RightSidebarNode->Children); + appendVector(std::move(InfoIndexHTML), RightSidebarNode->Children); MainNode->Children.emplace_back(std::move(LeftSidebarNode)); MainNode->Children.emplace_back(std::move(MainContentNode)); @@ -555,7 +563,7 @@ genInfoFile(StringRef Title, StringRef InfoPath, genInfoFileMainNode(InfoPath, MainContentNodes, InfoIndex); std::unique_ptr FooterNode = genFileFooterNode(); - AppendVector(std::move(HeadNodes), F.Children); + appendVector(std::move(HeadNodes), F.Children); F.Children.emplace_back(std::move(HeaderNode)); F.Children.emplace_back(std::move(MainNode)); F.Children.emplace_back(std::move(FooterNode)); @@ -594,7 +602,7 @@ genHTML(const Index &Index, StringRef InfoPath, bool IsOutermostList) { for (const auto &C : Index.Children) { auto LiBody = std::make_unique(HTMLTag::TAG_LI); std::vector> Nodes = genHTML(C, InfoPath, false); - AppendVector(std::move(Nodes), LiBody->Children); + appendVector(std::move(Nodes), LiBody->Children); UlBody->Children.emplace_back(std::move(LiBody)); } return Out; @@ -609,7 +617,9 @@ static std::unique_ptr genHTML(const CommentInfo &I) { FullComment->Children.emplace_back(std::move(Node)); } return std::move(FullComment); - } else if (I.Kind == "ParagraphComment") { + } + + if (I.Kind == "ParagraphComment") { auto ParagraphComment = std::make_unique(HTMLTag::TAG_P); for (const auto &Child : I.Children) { std::unique_ptr Node = genHTML(*Child); @@ -619,7 +629,9 @@ static std::unique_ptr genHTML(const CommentInfo &I) { if (ParagraphComment->Children.empty()) return nullptr; return std::move(ParagraphComment); - } else if (I.Kind == "TextComment") { + } + + if (I.Kind == "TextComment") { if (I.Text == "") return nullptr; return std::make_unique(I.Text); @@ -639,11 +651,7 @@ static std::unique_ptr genHTML(const std::vector &C) { static std::vector> genHTML(const EnumInfo &I, const ClangDocContext &CDCtx) { std::vector> Out; - std::string EnumType; - if (I.Scoped) - EnumType = "enum class "; - else - EnumType = "enum "; + std::string EnumType = I.Scoped ? "enum class " : "enum "; Out.emplace_back( std::make_unique(HTMLTag::TAG_H3, EnumType + I.Name)); @@ -737,17 +745,17 @@ genHTML(const NamespaceInfo &I, Index &InfoIndex, const ClangDocContext &CDCtx, std::vector> ChildNamespaces = genReferencesBlock(I.Children.Namespaces, "Namespaces", BasePath); - AppendVector(std::move(ChildNamespaces), Out); + appendVector(std::move(ChildNamespaces), Out); std::vector> ChildRecords = genReferencesBlock(I.Children.Records, "Records", BasePath); - AppendVector(std::move(ChildRecords), Out); + appendVector(std::move(ChildRecords), Out); std::vector> ChildFunctions = genFunctionsBlock(I.Children.Functions, CDCtx, BasePath); - AppendVector(std::move(ChildFunctions), Out); + appendVector(std::move(ChildFunctions), Out); std::vector> ChildEnums = genEnumsBlock(I.Children.Enums, CDCtx); - AppendVector(std::move(ChildEnums), Out); + appendVector(std::move(ChildEnums), Out); if (!I.Children.Namespaces.empty()) InfoIndex.Children.emplace_back("Namespaces", "Namespaces"); @@ -791,29 +799,29 @@ genHTML(const RecordInfo &I, Index &InfoIndex, const ClangDocContext &CDCtx, auto &PBody = Out.back(); PBody->Children.emplace_back(std::make_unique("Inherits from ")); if (Parents.empty()) - AppendVector(std::move(VParents), PBody->Children); + appendVector(std::move(VParents), PBody->Children); else if (VParents.empty()) - AppendVector(std::move(Parents), PBody->Children); + appendVector(std::move(Parents), PBody->Children); else { - AppendVector(std::move(Parents), PBody->Children); + appendVector(std::move(Parents), PBody->Children); PBody->Children.emplace_back(std::make_unique(", ")); - AppendVector(std::move(VParents), PBody->Children); + appendVector(std::move(VParents), PBody->Children); } } std::vector> Members = genRecordMembersBlock(I.Members, I.Path); - AppendVector(std::move(Members), Out); + appendVector(std::move(Members), Out); std::vector> ChildRecords = genReferencesBlock(I.Children.Records, "Records", I.Path); - AppendVector(std::move(ChildRecords), Out); + appendVector(std::move(ChildRecords), Out); std::vector> ChildFunctions = genFunctionsBlock(I.Children.Functions, CDCtx, I.Path); - AppendVector(std::move(ChildFunctions), Out); + appendVector(std::move(ChildFunctions), Out); std::vector> ChildEnums = genEnumsBlock(I.Children.Enums, CDCtx); - AppendVector(std::move(ChildEnums), Out); + appendVector(std::move(ChildEnums), Out); if (!I.Members.empty()) InfoIndex.Children.emplace_back("Members", "Members"); @@ -936,7 +944,7 @@ llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS, HTMLFile F = genInfoFile(InfoTitle, I->getRelativeFilePath(""), MainContentNodes, InfoIndex, CDCtx); - F.Render(OS); + F.render(OS); return llvm::Error::success(); } @@ -959,7 +967,7 @@ static std::string getRefType(InfoType IT) { llvm_unreachable("Unknown InfoType"); } -static llvm::Error SerializeIndex(ClangDocContext &CDCtx) { +static llvm::Error serializeIndex(ClangDocContext &CDCtx) { std::error_code OK; std::error_code FileErr; llvm::SmallString<128> FilePath; @@ -985,9 +993,9 @@ static llvm::Error SerializeIndex(ClangDocContext &CDCtx) { }); }); }; - OS << "var JsonIndex = `\n"; + OS << "async function LoadIndex() {\nreturn"; IndexToJSON(CDCtx.Idx); - OS << "`;\n"; + OS << ";\n}"; return llvm::Error::success(); } @@ -1009,7 +1017,7 @@ static std::unique_ptr genIndexFileMainNode() { return MainNode; } -static llvm::Error GenIndex(const ClangDocContext &CDCtx) { +static llvm::Error genIndex(const ClangDocContext &CDCtx) { std::error_code FileErr, OK; llvm::SmallString<128> IndexPath; llvm::sys::path::native(CDCtx.OutDirectory, IndexPath); @@ -1029,17 +1037,17 @@ static llvm::Error GenIndex(const ClangDocContext &CDCtx) { std::unique_ptr MainNode = genIndexFileMainNode(); std::unique_ptr FooterNode = genFileFooterNode(); - AppendVector(std::move(HeadNodes), F.Children); + appendVector(std::move(HeadNodes), F.Children); F.Children.emplace_back(std::move(HeaderNode)); F.Children.emplace_back(std::move(MainNode)); F.Children.emplace_back(std::move(FooterNode)); - F.Render(IndexOS); + F.render(IndexOS); return llvm::Error::success(); } -static llvm::Error CopyFile(StringRef FilePath, StringRef OutDirectory) { +static llvm::Error copyFile(StringRef FilePath, StringRef OutDirectory) { llvm::SmallString<128> PathWrite; llvm::sys::path::native(OutDirectory, PathWrite); llvm::sys::path::append(PathWrite, llvm::sys::path::filename(FilePath)); @@ -1057,20 +1065,20 @@ static llvm::Error CopyFile(StringRef FilePath, StringRef OutDirectory) { } llvm::Error HTMLGenerator::createResources(ClangDocContext &CDCtx) { - auto Err = SerializeIndex(CDCtx); + auto Err = serializeIndex(CDCtx); if (Err) return Err; - Err = GenIndex(CDCtx); + Err = genIndex(CDCtx); if (Err) return Err; for (const auto &FilePath : CDCtx.UserStylesheets) { - Err = CopyFile(FilePath, CDCtx.OutDirectory); + Err = copyFile(FilePath, CDCtx.OutDirectory); if (Err) return Err; } - for (const auto &FilePath : CDCtx.FilesToCopy) { - Err = CopyFile(FilePath, CDCtx.OutDirectory); + for (const auto &FilePath : CDCtx.JsScripts) { + Err = copyFile(FilePath, CDCtx.OutDirectory); if (Err) return Err; } diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp index 2afff2929cf79c..d08afbb9621890 100644 --- a/clang-tools-extra/clang-doc/Representation.cpp +++ b/clang-tools-extra/clang-doc/Representation.cpp @@ -368,11 +368,9 @@ ClangDocContext::ClangDocContext(tooling::ExecutionContext *ECtx, StringRef ProjectName, bool PublicOnly, StringRef OutDirectory, StringRef SourceRoot, StringRef RepositoryUrl, - std::vector UserStylesheets, - std::vector JsScripts) + std::vector UserStylesheets) : ECtx(ECtx), ProjectName(ProjectName), PublicOnly(PublicOnly), - OutDirectory(OutDirectory), UserStylesheets(UserStylesheets), - JsScripts(JsScripts) { + OutDirectory(OutDirectory), UserStylesheets(UserStylesheets) { llvm::SmallString<128> SourceRootDir(SourceRoot); if (SourceRoot.empty()) // If no SourceRoot was provided the current path is used as the default diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h index a6b144eb7fa2a2..d70c279f7a2bdc 100644 --- a/clang-tools-extra/clang-doc/Representation.h +++ b/clang-tools-extra/clang-doc/Representation.h @@ -482,8 +482,7 @@ struct ClangDocContext { ClangDocContext(tooling::ExecutionContext *ECtx, StringRef ProjectName, bool PublicOnly, StringRef OutDirectory, StringRef SourceRoot, StringRef RepositoryUrl, - std::vector UserStylesheets, - std::vector JsScripts); + std::vector UserStylesheets); tooling::ExecutionContext *ECtx; std::string ProjectName; // Name of project clang-doc is documenting. bool PublicOnly; // Indicates if only public declarations are documented. @@ -498,8 +497,6 @@ struct ClangDocContext { std::vector UserStylesheets; // JavaScript files that will be imported in allHTML file. std::vector JsScripts; - // Other files that should be copied to OutDirectory, besides UserStylesheets. - std::vector FilesToCopy; Index Idx; }; diff --git a/clang-tools-extra/clang-doc/assets/index.js b/clang-tools-extra/clang-doc/assets/index.js index a5ac90f2e06e78..49818763a43935 100644 --- a/clang-tools-extra/clang-doc/assets/index.js +++ b/clang-tools-extra/clang-doc/assets/index.js @@ -80,8 +80,8 @@ function createIndex(Index) { // Runs after DOM loads document.addEventListener("DOMContentLoaded", function() { - // JsonIndex is a variable from another file that contains the index - // in JSON format - var Index = JSON.parse(JsonIndex); - createIndex(Index); + // LoadIndex is an asynchronous function that will be generated clang-doc. + // It ensures that the function call will not block as soon the page loads, + // since the index object are often huge and can contain thousands of lines. + LoadIndex().then((Index) => { createIndex(Index); }); }); diff --git a/clang-tools-extra/clang-doc/tool/CMakeLists.txt b/clang-tools-extra/clang-doc/tool/CMakeLists.txt index 4944251245c6bc..e93a5728d6b6b0 100644 --- a/clang-tools-extra/clang-doc/tool/CMakeLists.txt +++ b/clang-tools-extra/clang-doc/tool/CMakeLists.txt @@ -25,7 +25,7 @@ set(assets ) set(asset_dir "${CMAKE_CURRENT_SOURCE_DIR}/../assets") -set(resource_dir "${CMAKE_BINARY_DIR}/share/clang") +set(resource_dir "${CMAKE_BINARY_DIR}/share/clang-doc") set(out_files) function(copy_files_to_dst src_dir dst_dir file) @@ -42,7 +42,7 @@ endfunction(copy_files_to_dst) foreach(f ${assets}) install(FILES ${asset_dir}/${f} - DESTINATION "${CMAKE_INSTALL_DATADIR}/clang" + DESTINATION "${CMAKE_INSTALL_DATADIR}/clang-doc" COMPONENT clang-doc) copy_files_to_dst(${asset_dir} ${resource_dir} ${f}) endforeach(f) diff --git a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp index 5517522d7967dc..6198a6e0cdcc32 100644 --- a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp +++ b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp @@ -81,6 +81,12 @@ static llvm::cl::list UserStylesheets( llvm::cl::desc("CSS stylesheets to extend the default styles."), llvm::cl::cat(ClangDocCategory)); +static llvm::cl::opt UserAssetPath( + "asset", + llvm::cl::desc("User supplied asset path to " + "override the default css and js files for html output"), + llvm::cl::cat(ClangDocCategory)); + static llvm::cl::opt SourceRoot("source-root", llvm::cl::desc(R"( Directory where processed files are stored. Links to definition locations will only be @@ -127,16 +133,84 @@ std::string getFormatString() { // GetMainExecutable (since some platforms don't support taking the // address of main, and some platforms can't implement GetMainExecutable // without being given the address of a function in the main executable). -std::string GetExecutablePath(const char *Argv0, void *MainAddr) { +std::string getExecutablePath(const char *Argv0, void *MainAddr) { return llvm::sys::fs::getMainExecutable(Argv0, MainAddr); } +llvm::Error getAssetFiles(clang::doc::ClangDocContext &CDCtx) { + using DirIt = llvm::sys::fs::directory_iterator; + std::error_code FileErr; + llvm::SmallString<128> FilePath(UserAssetPath); + for (DirIt DirStart = DirIt(UserAssetPath, FileErr), + DirEnd; + !FileErr && DirStart != DirEnd; DirStart.increment(FileErr)) { + FilePath = DirStart->path(); + if (llvm::sys::fs::is_regular_file(FilePath)) { + if (llvm::sys::path::extension(FilePath) == ".css") + CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(), + std::string(FilePath)); + else if (llvm::sys::path::extension(FilePath) == ".js") + CDCtx.JsScripts.emplace_back(FilePath.str()); + } + } + if (FileErr) + return llvm::createFileError(FilePath, FileErr); + return llvm::Error::success(); +} + +llvm::Error getDefaultAssetFiles(const char *Argv0, + clang::doc::ClangDocContext &CDCtx) { + void *MainAddr = (void *)(intptr_t)getExecutablePath; + std::string ClangDocPath = getExecutablePath(Argv0, MainAddr); + llvm::SmallString<128> NativeClangDocPath; + llvm::sys::path::native(ClangDocPath, NativeClangDocPath); + + llvm::SmallString<128> AssetsPath; + AssetsPath = llvm::sys::path::parent_path(NativeClangDocPath); + llvm::sys::path::append(AssetsPath, "..", "share", "clang-doc"); + llvm::SmallString<128> DefaultStylesheet; + llvm::sys::path::native(AssetsPath, DefaultStylesheet); + llvm::sys::path::append(DefaultStylesheet, + "clang-doc-default-stylesheet.css"); + llvm::SmallString<128> IndexJS; + llvm::sys::path::native(AssetsPath, IndexJS); + llvm::sys::path::append(IndexJS, "index.js"); + + if (!llvm::sys::fs::is_regular_file(IndexJS)) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "default index.js file missing at " + + IndexJS + "\n"); + + if (!llvm::sys::fs::is_regular_file(DefaultStylesheet)) + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "default clang-doc-default-stylesheet.css file missing at " + + DefaultStylesheet + "\n"); + + CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(), + std::string(DefaultStylesheet)); + CDCtx.JsScripts.emplace_back(IndexJS.str()); + + return llvm::Error::success(); +} + +llvm::Error getHtmlAssetFiles(const char *Argv0, + clang::doc::ClangDocContext &CDCtx) { + if (!UserAssetPath.empty() && + !llvm::sys::fs::is_directory(std::string(UserAssetPath))) + llvm::outs() << "Asset path supply is not a directory: " << UserAssetPath + << " falling back to default\n"; + if (llvm::sys::fs::is_directory(std::string(UserAssetPath))) + return getAssetFiles(CDCtx); + return getDefaultAssetFiles(Argv0, CDCtx); +} + int main(int argc, const char **argv) { llvm::sys::PrintStackTraceOnErrorSignal(argv[0]); std::error_code OK; const char *Overview = - R"(Generates documentation from source code and comments. + R"(Generates documentation from source code and comments. Example usage for files without flags (default): @@ -178,27 +252,14 @@ Example usage for a project using a compile commands database: OutDirectory, SourceRoot, RepositoryUrl, - {UserStylesheets.begin(), UserStylesheets.end()}, - {"index.js", "index_json.js"}}; + {UserStylesheets.begin(), UserStylesheets.end()} + }; if (Format == "html") { - void *MainAddr = (void *)(intptr_t)GetExecutablePath; - std::string ClangDocPath = GetExecutablePath(argv[0], MainAddr); - llvm::SmallString<128> NativeClangDocPath; - llvm::sys::path::native(ClangDocPath, NativeClangDocPath); - llvm::SmallString<128> AssetsPath; - AssetsPath = llvm::sys::path::parent_path(NativeClangDocPath); - llvm::sys::path::append(AssetsPath, "..", "share", "clang"); - llvm::SmallString<128> DefaultStylesheet; - llvm::sys::path::native(AssetsPath, DefaultStylesheet); - llvm::sys::path::append(DefaultStylesheet, - "clang-doc-default-stylesheet.css"); - llvm::SmallString<128> IndexJS; - llvm::sys::path::native(AssetsPath, IndexJS); - llvm::sys::path::append(IndexJS, "index.js"); - CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(), - std::string(DefaultStylesheet)); - CDCtx.FilesToCopy.emplace_back(IndexJS.str()); + if (auto Err = getHtmlAssetFiles(argv[0], CDCtx)) { + llvm::errs() << toString(std::move(Err)) << "\n"; + return 1; + } } // Mapping phase diff --git a/clang-tools-extra/clang-tidy/misc/UseInternalLinkageCheck.cpp b/clang-tools-extra/clang-tidy/misc/UseInternalLinkageCheck.cpp index 70d0281df28fad..44ccc2bc906a5b 100644 --- a/clang-tools-extra/clang-tidy/misc/UseInternalLinkageCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/UseInternalLinkageCheck.cpp @@ -18,6 +18,26 @@ using namespace clang::ast_matchers; +namespace clang::tidy { + +template <> +struct OptionEnumMapping { + static llvm::ArrayRef< + std::pair> + getEnumMapping() { + static constexpr std::pair + Mapping[] = { + {misc::UseInternalLinkageCheck::FixModeKind::None, "None"}, + {misc::UseInternalLinkageCheck::FixModeKind::UseStatic, + "UseStatic"}, + }; + return {Mapping}; + } +}; + +} // namespace clang::tidy + namespace clang::tidy::misc { namespace { @@ -57,6 +77,16 @@ AST_POLYMORPHIC_MATCHER(isExternStorageClass, } // namespace +UseInternalLinkageCheck::UseInternalLinkageCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + HeaderFileExtensions(Context->getHeaderFileExtensions()), + FixMode(Options.get("FixMode", FixModeKind::UseStatic)) {} + +void UseInternalLinkageCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "FixMode", FixMode); +} + void UseInternalLinkageCheck::registerMatchers(MatchFinder *Finder) { auto Common = allOf(isFirstDecl(), isAllRedeclsInMainFile(HeaderFileExtensions), @@ -82,11 +112,21 @@ static constexpr StringRef Message = void UseInternalLinkageCheck::check(const MatchFinder::MatchResult &Result) { if (const auto *FD = Result.Nodes.getNodeAs("fn")) { - diag(FD->getLocation(), Message) << "function" << FD; + DiagnosticBuilder DB = diag(FD->getLocation(), Message) << "function" << FD; + SourceLocation FixLoc = FD->getTypeSpecStartLoc(); + if (FixLoc.isInvalid() || FixLoc.isMacroID()) + return; + if (FixMode == FixModeKind::UseStatic) + DB << FixItHint::CreateInsertion(FixLoc, "static "); return; } if (const auto *VD = Result.Nodes.getNodeAs("var")) { - diag(VD->getLocation(), Message) << "variable" << VD; + DiagnosticBuilder DB = diag(VD->getLocation(), Message) << "variable" << VD; + SourceLocation FixLoc = VD->getTypeSpecStartLoc(); + if (FixLoc.isInvalid() || FixLoc.isMacroID()) + return; + if (FixMode == FixModeKind::UseStatic) + DB << FixItHint::CreateInsertion(FixLoc, "static "); return; } llvm_unreachable(""); diff --git a/clang-tools-extra/clang-tidy/misc/UseInternalLinkageCheck.h b/clang-tools-extra/clang-tidy/misc/UseInternalLinkageCheck.h index a3c1c339659036..0d6c3e43aa9457 100644 --- a/clang-tools-extra/clang-tidy/misc/UseInternalLinkageCheck.h +++ b/clang-tools-extra/clang-tidy/misc/UseInternalLinkageCheck.h @@ -20,17 +20,22 @@ namespace clang::tidy::misc { /// http://clang.llvm.org/extra/clang-tidy/checks/misc/use-internal-linkage.html class UseInternalLinkageCheck : public ClangTidyCheck { public: - UseInternalLinkageCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context), - HeaderFileExtensions(Context->getHeaderFileExtensions()) {} + UseInternalLinkageCheck(StringRef Name, ClangTidyContext *Context); void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; std::optional getCheckTraversalKind() const override { return TK_IgnoreUnlessSpelledInSource; } + enum class FixModeKind { + None, + UseStatic, + }; + private: FileExtensionsSet HeaderFileExtensions; + FixModeKind FixMode; }; } // namespace clang::tidy::misc diff --git a/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.cpp b/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.cpp index fd4730d9c8b9c8..499c88ef5d4e49 100644 --- a/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.cpp @@ -9,6 +9,7 @@ #include "SimplifyBooleanExprCheck.h" #include "clang/AST/Expr.h" #include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/DiagnosticIDs.h" #include "clang/Lex/Lexer.h" #include "llvm/Support/SaveAndRestore.h" @@ -702,7 +703,8 @@ bool SimplifyBooleanExprCheck::canBeBypassed(const Stmt *S) const { return IgnoreMacros && S->getBeginLoc().isMacroID(); } -void SimplifyBooleanExprCheck::issueDiag(const ASTContext &Context, +/// @brief return true when replacement created. +bool SimplifyBooleanExprCheck::issueDiag(const ASTContext &Context, SourceLocation Loc, StringRef Description, SourceRange ReplacementRange, @@ -712,8 +714,10 @@ void SimplifyBooleanExprCheck::issueDiag(const ASTContext &Context, Context.getSourceManager(), getLangOpts()); DiagnosticBuilder Diag = diag(Loc, Description); - if (!containsDiscardedTokens(Context, CharRange)) + const bool HasReplacement = !containsDiscardedTokens(Context, CharRange); + if (HasReplacement) Diag << FixItHint::CreateReplacement(CharRange, Replacement); + return HasReplacement; } void SimplifyBooleanExprCheck::replaceWithThenStatement( @@ -751,8 +755,18 @@ void SimplifyBooleanExprCheck::replaceWithReturnCondition( replacementExpression(Context, Negated, If->getCond()); std::string Replacement = ("return " + Condition + Terminator).str(); SourceLocation Start = BoolLiteral->getBeginLoc(); - issueDiag(Context, Start, SimplifyConditionalReturnDiagnostic, - If->getSourceRange(), Replacement); + + const bool HasReplacement = + issueDiag(Context, Start, SimplifyConditionalReturnDiagnostic, + If->getSourceRange(), Replacement); + + if (!HasReplacement) { + const SourceRange ConditionRange = If->getCond()->getSourceRange(); + if (ConditionRange.isValid()) + diag(ConditionRange.getBegin(), "conditions that can be simplified", + DiagnosticIDs::Note) + << ConditionRange; + } } void SimplifyBooleanExprCheck::replaceCompoundReturnWithCondition( @@ -760,9 +774,23 @@ void SimplifyBooleanExprCheck::replaceCompoundReturnWithCondition( const IfStmt *If, const Expr *ThenReturn) { const std::string Replacement = "return " + replacementExpression(Context, Negated, If->getCond()); - issueDiag(Context, ThenReturn->getBeginLoc(), - SimplifyConditionalReturnDiagnostic, - SourceRange(If->getBeginLoc(), Ret->getEndLoc()), Replacement); + + const bool HasReplacement = issueDiag( + Context, ThenReturn->getBeginLoc(), SimplifyConditionalReturnDiagnostic, + SourceRange(If->getBeginLoc(), Ret->getEndLoc()), Replacement); + + if (!HasReplacement) { + const SourceRange ConditionRange = If->getCond()->getSourceRange(); + if (ConditionRange.isValid()) + diag(ConditionRange.getBegin(), "conditions that can be simplified", + DiagnosticIDs::Note) + << ConditionRange; + const SourceRange ReturnRange = Ret->getSourceRange(); + if (ReturnRange.isValid()) + diag(ReturnRange.getBegin(), "return statement that can be simplified", + DiagnosticIDs::Note) + << ReturnRange; + } } void SimplifyBooleanExprCheck::replaceWithAssignment(const ASTContext &Context, diff --git a/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.h b/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.h index 63c3caa01e01a7..2ea69687984086 100644 --- a/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.h +++ b/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.h @@ -60,7 +60,7 @@ class SimplifyBooleanExprCheck : public ClangTidyCheck { const BinaryOperator *Inner, bool TryOfferFix, const Stmt *Parent, const ParenExpr *Parens); - void issueDiag(const ASTContext &Context, SourceLocation Loc, + bool issueDiag(const ASTContext &Context, SourceLocation Loc, StringRef Description, SourceRange ReplacementRange, StringRef Replacement); diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp index 7388f20ef288eb..d42dafa8ffc362 100644 --- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp +++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp @@ -325,6 +325,14 @@ option is recognized. )"), cl::init(false), cl::cat(ClangTidyCategory)); +static cl::opt AllowNoChecks("allow-no-checks", desc(R"( +Allow empty enabled checks. This suppresses +the "no checks enabled" error when disabling +all of the checks. +)"), + cl::init(false), + cl::cat(ClangTidyCategory)); + namespace clang::tidy { static void printStats(const ClangTidyStats &Stats) { @@ -598,7 +606,7 @@ int clangTidyMain(int argc, const char **argv) { } if (ListChecks) { - if (EnabledChecks.empty()) { + if (EnabledChecks.empty() && !AllowNoChecks) { llvm::errs() << "No checks enabled.\n"; return 1; } @@ -652,6 +660,10 @@ int clangTidyMain(int argc, const char **argv) { } if (EnabledChecks.empty()) { + if (AllowNoChecks) { + llvm::outs() << "No checks enabled.\n"; + return 0; + } llvm::errs() << "Error: no checks enabled.\n"; llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true); return 1; diff --git a/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py b/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py index b048460abf2fca..62cb4297c50f75 100755 --- a/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py +++ b/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py @@ -229,6 +229,11 @@ def main(): default=[], help="Load the specified plugin in clang-tidy.", ) + parser.add_argument( + "-allow-no-checks", + action="store_true", + help="Allow empty enabled checks.", + ) clang_tidy_args = [] argv = sys.argv[1:] @@ -327,6 +332,8 @@ def main(): common_clang_tidy_args.append("-p=%s" % args.build_path) if args.use_color: common_clang_tidy_args.append("--use-color") + if args.allow_no_checks: + common_clang_tidy_args.append("--allow-no-checks") for arg in args.extra_arg: common_clang_tidy_args.append("-extra-arg=%s" % arg) for arg in args.extra_arg_before: diff --git a/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py b/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py index 4dd20bec81d3be..0dc35ad5873629 100755 --- a/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py +++ b/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py @@ -107,6 +107,7 @@ def get_tidy_invocation( plugins, warnings_as_errors, exclude_header_filter, + allow_no_checks, ): """Gets a command line for clang-tidy.""" start = [clang_tidy_binary] @@ -147,6 +148,8 @@ def get_tidy_invocation( start.append("-load=" + plugin) if warnings_as_errors: start.append("--warnings-as-errors=" + warnings_as_errors) + if allow_no_checks: + start.append("--allow-no-checks") start.append(f) return start @@ -232,6 +235,7 @@ def run_tidy(args, clang_tidy_binary, tmpdir, build_path, queue, lock, failed_fi args.plugins, args.warnings_as_errors, args.exclude_header_filter, + args.allow_no_checks, ) proc = subprocess.Popen( @@ -261,20 +265,20 @@ def main(): parser.add_argument( "-allow-enabling-alpha-checkers", action="store_true", - help="allow alpha checkers from clang-analyzer.", + help="Allow alpha checkers from clang-analyzer.", ) parser.add_argument( - "-clang-tidy-binary", metavar="PATH", help="path to clang-tidy binary" + "-clang-tidy-binary", metavar="PATH", help="Path to clang-tidy binary." ) parser.add_argument( "-clang-apply-replacements-binary", metavar="PATH", - help="path to clang-apply-replacements binary", + help="Path to clang-apply-replacements binary.", ) parser.add_argument( "-checks", default=None, - help="checks filter, when not specified, use clang-tidy default", + help="Checks filter, when not specified, use clang-tidy default.", ) config_group = parser.add_mutually_exclusive_group() config_group.add_argument( @@ -307,7 +311,7 @@ def main(): parser.add_argument( "-header-filter", default=None, - help="regular expression matching the names of the " + help="Regular expression matching the names of the " "headers to output diagnostics from. Diagnostics from " "the main file of each translation unit are always " "displayed.", @@ -347,19 +351,22 @@ def main(): "-j", type=int, default=0, - help="number of tidy instances to be run in parallel.", + help="Number of tidy instances to be run in parallel.", ) parser.add_argument( - "files", nargs="*", default=[".*"], help="files to be processed (regex on path)" + "files", + nargs="*", + default=[".*"], + help="Files to be processed (regex on path).", ) - parser.add_argument("-fix", action="store_true", help="apply fix-its") + parser.add_argument("-fix", action="store_true", help="apply fix-its.") parser.add_argument( - "-format", action="store_true", help="Reformat code after applying fixes" + "-format", action="store_true", help="Reformat code after applying fixes." ) parser.add_argument( "-style", default="file", - help="The style of reformat code after applying fixes", + help="The style of reformat code after applying fixes.", ) parser.add_argument( "-use-color", @@ -388,7 +395,7 @@ def main(): help="Additional argument to prepend to the compiler command line.", ) parser.add_argument( - "-quiet", action="store_true", help="Run clang-tidy in quiet mode" + "-quiet", action="store_true", help="Run clang-tidy in quiet mode." ) parser.add_argument( "-load", @@ -400,7 +407,12 @@ def main(): parser.add_argument( "-warnings-as-errors", default=None, - help="Upgrades warnings to errors. Same format as '-checks'", + help="Upgrades warnings to errors. Same format as '-checks'.", + ) + parser.add_argument( + "-allow-no-checks", + action="store_true", + help="Allow empty enabled checks.", ) args = parser.parse_args() @@ -463,6 +475,7 @@ def main(): args.plugins, args.warnings_as_errors, args.exclude_header_filter, + args.allow_no_checks, ) invocation.append("-list-checks") invocation.append("-") diff --git a/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp b/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp index a6062ccf42230b..106feb7fb41720 100644 --- a/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp +++ b/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp @@ -296,7 +296,7 @@ AST_MATCHER_P(DeclRefExpr, doesNotMutateObject, int, Indirections) { return false; } const auto *const Method = - dyn_cast(OpCall->getDirectCallee()); + dyn_cast_or_null(OpCall->getDirectCallee()); if (Method == nullptr) { // This is not a member operator. Typically, a friend operator. These diff --git a/clang-tools-extra/clangd/Format.cpp b/clang-tools-extra/clangd/Format.cpp index 272a34d4ed7972..fc56a1c8c50304 100644 --- a/clang-tools-extra/clangd/Format.cpp +++ b/clang-tools-extra/clangd/Format.cpp @@ -281,7 +281,7 @@ formatIncremental(llvm::StringRef OriginalCode, unsigned OriginalCursor, // Never *remove* lines in response to pressing enter! This annoys users. if (InsertedText == "\n") { Style.MaxEmptyLinesToKeep = 1000; - Style.KeepEmptyLinesAtTheStartOfBlocks = true; + Style.KeepEmptyLines.AtStartOfBlock = true; } // Compute the code we want to format: diff --git a/clang-tools-extra/clangd/index/remote/Client.h b/clang-tools-extra/clangd/index/remote/Client.h index ff5348bd23279e..9004012f066ae2 100644 --- a/clang-tools-extra/clangd/index/remote/Client.h +++ b/clang-tools-extra/clangd/index/remote/Client.h @@ -12,8 +12,11 @@ #include "index/Index.h" #include "llvm/ADT/StringRef.h" +#include + namespace clang { namespace clangd { + namespace remote { /// Returns an SymbolIndex client that passes requests to remote index located diff --git a/clang-tools-extra/clangd/support/Trace.cpp b/clang-tools-extra/clangd/support/Trace.cpp index 419c2eee99ec84..7c6490f2e92fb2 100644 --- a/clang-tools-extra/clangd/support/Trace.cpp +++ b/clang-tools-extra/clangd/support/Trace.cpp @@ -159,8 +159,8 @@ class JSONTracer : public EventTracer { Out.object([&] { Out.attribute("pid", 0); Out.attribute("ph", Phase); - for (const auto &KV : Event) - Out.attribute(KV.first, KV.second); + for (const auto *KV : llvm::json::sortedElements(Event)) + Out.attribute(KV->first, KV->second); }); } diff --git a/clang-tools-extra/clangd/test/trace.test b/clang-tools-extra/clangd/test/trace.test index cb6a226b496a4b..56f2d6333f1de0 100644 --- a/clang-tools-extra/clangd/test/trace.test +++ b/clang-tools-extra/clangd/test/trace.test @@ -8,17 +8,17 @@ # CHECK: "traceEvents": [ # CHECK: { # CHECK: "ph": "X", -# CHECK: "name": "BuildPreamble", # CHECK: "args": { # CHECK: "File": "{{.*(/|\\)}}foo.c" # CHECK: }, +# CHECK: "name": "BuildPreamble", # CHECK: } # CHECK: { # CHECK: "ph": "X", -# CHECK: "name": "BuildAST", # CHECK: "args": { # CHECK: "File": "{{.*(/|\\)}}foo.c" # CHECK: }, +# CHECK: "name": "BuildAST", # CHECK: } # CHECK: ] # CHECK: } diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 16fdc20eafd62e..d968100cd57a76 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -125,6 +125,9 @@ Improvements to clang-tidy - Added argument `--exclude-header-filter` and config option `ExcludeHeaderFilterRegex` to exclude headers from analysis via a RegEx. +- Added argument `--allow-no-checks` to suppress "no checks enabled" error + when disabling all of the checks by `--checks='-*'`. + New checks ^^^^^^^^^^ @@ -398,7 +401,7 @@ Changes in existing checks analyzed, so the check now handles the common patterns `const auto e = (*vector_ptr)[i]` and `const auto e = vector_ptr->at(i);`. Calls to mutable function where there exists a `const` overload are also - handled. + handled. Fix crash in the case of a non-member operator call. - Improved :doc:`readability-avoid-return-with-void-value ` check by adding @@ -452,7 +455,8 @@ Changes in existing checks - Improved :doc:`readability-simplify-boolean-expr ` check to avoid to emit - warning for macro when IgnoreMacro option is enabled. + warning for macro when IgnoreMacro option is enabled and improve messages + when auto-fix does not work. - Improved :doc:`readability-static-definition-in-anonymous-namespace ` diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc/use-internal-linkage.rst b/clang-tools-extra/docs/clang-tidy/checks/misc/use-internal-linkage.rst index e8e43a1fb3d632..7147af9a7919bc 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/misc/use-internal-linkage.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/misc/use-internal-linkage.rst @@ -25,3 +25,16 @@ Example: } // already declared as extern extern int v2; + +Options +------- + +.. option:: FixMode + + Selects what kind of a fix the check should provide. The default is `UseStatic`. + + ``None`` + Don't fix automatically. + + ``UseStatic`` + Add ``static`` for internal linkage variable and function. diff --git a/clang-tools-extra/docs/clang-tidy/index.rst b/clang-tools-extra/docs/clang-tidy/index.rst index 9ccacefa3c2c59..c8fc34c61caeb5 100644 --- a/clang-tools-extra/docs/clang-tidy/index.rst +++ b/clang-tools-extra/docs/clang-tidy/index.rst @@ -240,6 +240,9 @@ An overview of all the command-line options: This option's value is appended to the value of the 'WarningsAsErrors' option in .clang-tidy file, if any. + --allow-no-checks - Allow empty enabled checks. This suppresses + the "no checks enabled" error when disabling + all of the checks. -p is used to read a compile command database. diff --git a/clang-tools-extra/test/clang-doc/Inputs/basic-project/src/Calculator.cpp b/clang-tools-extra/test/clang-doc/Inputs/basic-project/src/Calculator.cpp index df1778c3b9d55f..64f31dbf13d871 100644 --- a/clang-tools-extra/test/clang-doc/Inputs/basic-project/src/Calculator.cpp +++ b/clang-tools-extra/test/clang-doc/Inputs/basic-project/src/Calculator.cpp @@ -1,5 +1,4 @@ #include "Calculator.h" -#include int Calculator::add(int a, int b) { return a + b; @@ -14,8 +13,5 @@ int Calculator::multiply(int a, int b) { } double Calculator::divide(int a, int b) { - if (b == 0) { - throw std::invalid_argument("Division by zero"); - } return static_cast(a) / b; } diff --git a/clang-tools-extra/test/clang-doc/Inputs/test-assets/test.css b/clang-tools-extra/test/clang-doc/Inputs/test-assets/test.css new file mode 100644 index 00000000000000..5c5532659be5e0 --- /dev/null +++ b/clang-tools-extra/test/clang-doc/Inputs/test-assets/test.css @@ -0,0 +1,3 @@ +body { + padding: 0; +} \ No newline at end of file diff --git a/clang-tools-extra/test/clang-doc/Inputs/test-assets/test.js b/clang-tools-extra/test/clang-doc/Inputs/test-assets/test.js new file mode 100644 index 00000000000000..06f320c59b9b0f --- /dev/null +++ b/clang-tools-extra/test/clang-doc/Inputs/test-assets/test.js @@ -0,0 +1 @@ +console.log("Hello, world!"); \ No newline at end of file diff --git a/clang-tools-extra/test/clang-doc/assets.cpp b/clang-tools-extra/test/clang-doc/assets.cpp new file mode 100644 index 00000000000000..d5a2d20e92240b --- /dev/null +++ b/clang-tools-extra/test/clang-doc/assets.cpp @@ -0,0 +1,22 @@ +// RUN: rm -rf %t && mkdir %t +// RUN: clang-doc --format=html --output=%t --asset=%S/Inputs/test-assets --executor=standalone %s +// RUN: FileCheck %s -input-file=%t/index.html -check-prefix=INDEX +// RUN: FileCheck %s -input-file=%t/test.css -check-prefix=CSS +// RUN: FileCheck %s -input-file=%t/test.js -check-prefix=JS + +// INDEX: +// INDEX-NEXT: +// INDEX-NEXT: Index +// INDEX-NEXT: +// INDEX-NEXT: +// INDEX-NEXT: +// INDEX-NEXT:
+// INDEX-NEXT:
+// INDEX-NEXT: +// INDEX-NEXT:
+ +// CSS: body { +// CSS-NEXT: padding: 0; +// CSS-NEXT: } + +// JS: console.log("Hello, world!"); \ No newline at end of file diff --git a/clang-tools-extra/test/clang-doc/basic-project.test b/clang-tools-extra/test/clang-doc/basic-project.test index 0898acaea3a33e..bab5f8e1761bc6 100644 --- a/clang-tools-extra/test/clang-doc/basic-project.test +++ b/clang-tools-extra/test/clang-doc/basic-project.test @@ -7,8 +7,8 @@ // RUN: FileCheck %s -input-file=%t/docs/GlobalNamespace/Rectangle.html -check-prefix=HTML-RECTANGLE // RUN: FileCheck %s -input-file=%t/docs/GlobalNamespace/Circle.html -check-prefix=HTML-CIRCLE -// JSON-INDEX: var JsonIndex = ` -// JSON-INDEX-NEXT: { +// JSON-INDEX: async function LoadIndex() { +// JSON-INDEX-NEXT: return{ // JSON-INDEX-NEXT: "USR": "{{([0-9A-F]{40})}}", // JSON-INDEX-NEXT: "Name": "", // JSON-INDEX-NEXT: "RefType": "default", @@ -51,14 +51,15 @@ // JSON-INDEX-NEXT: ] // JSON-INDEX-NEXT: } // JSON-INDEX-NEXT: ] -// JSON-INDEX-NEXT: }`; +// JSON-INDEX-NEXT: }; +// JSON-INDEX-NEXT: } // HTML-SHAPE: // HTML-SHAPE-NEXT: // HTML-SHAPE-NEXT: class Shape // HTML-SHAPE-NEXT: -// HTML-SHAPE-NEXT: -// HTML-SHAPE-NEXT: +// HTML-SHAPE-NEXT: +// HTML-SHAPE-NEXT: // HTML-SHAPE-NEXT:
// HTML-SHAPE-NEXT:
// HTML-SHAPE-NEXT: @@ -122,8 +123,8 @@ // HTML-CALC-NEXT: // HTML-CALC-NEXT: class Calculator // HTML-CALC-NEXT: -// HTML-CALC-NEXT: // HTML-CALC-NEXT: +// HTML-CALC-NEXT: // HTML-CALC-NEXT:
// HTML-CALC-NEXT:
// HTML-CALC-NEXT: @@ -139,25 +140,25 @@ // HTML-CALC-NEXT:
// HTML-CALC-NEXT:

add

// HTML-CALC-NEXT:

public int add(int a, int b)

-// HTML-CALC-NEXT:

Defined at line 4 of file {{.*}}Calculator.cpp

+// HTML-CALC-NEXT:

Defined at line 3 of file {{.*}}Calculator.cpp

// HTML-CALC-NEXT:
// HTML-CALC-NEXT:
// HTML-CALC-NEXT:
// HTML-CALC-NEXT:

subtract

// HTML-CALC-NEXT:

public int subtract(int a, int b)

-// HTML-CALC-NEXT:

Defined at line 8 of file {{.*}}Calculator.cpp

+// HTML-CALC-NEXT:

Defined at line 7 of file {{.*}}Calculator.cpp

// HTML-CALC-NEXT:
// HTML-CALC-NEXT:
// HTML-CALC-NEXT:
// HTML-CALC-NEXT:

multiply

// HTML-CALC-NEXT:

public int multiply(int a, int b)

-// HTML-CALC-NEXT:

Defined at line 12 of file {{.*}}Calculator.cpp

+// HTML-CALC-NEXT:

Defined at line 11 of file {{.*}}Calculator.cpp

// HTML-CALC-NEXT:
// HTML-CALC-NEXT:
// HTML-CALC-NEXT:
// HTML-CALC-NEXT:

divide

// HTML-CALC-NEXT:

public double divide(int a, int b)

-// HTML-CALC-NEXT:

Defined at line 16 of file {{.*}}Calculator.cpp

+// HTML-CALC-NEXT:

Defined at line 15 of file {{.*}}Calculator.cpp

// HTML-CALC-NEXT:
// HTML-CALC-NEXT:
// HTML-CALC-NEXT:
@@ -200,8 +201,8 @@ // HTML-RECTANGLE-NEXT: // HTML-RECTANGLE-NEXT: class Rectangle // HTML-RECTANGLE-NEXT: -// HTML-RECTANGLE-NEXT: // HTML-RECTANGLE-NEXT: +// HTML-RECTANGLE-NEXT: // HTML-RECTANGLE-NEXT:
// HTML-RECTANGLE-NEXT:
// HTML-RECTANGLE-NEXT: @@ -281,8 +282,8 @@ // HTML-CIRCLE-NEXT: // HTML-CIRCLE-NEXT: class Circle // HTML-CIRCLE-NEXT: -// HTML-CIRCLE-NEXT: // HTML-CIRCLE-NEXT: +// HTML-CIRCLE-NEXT: // HTML-CIRCLE-NEXT:
// HTML-CIRCLE-NEXT:
// HTML-CIRCLE-NEXT: diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/use-internal-linkage-fix-mode-none.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/use-internal-linkage-fix-mode-none.cpp new file mode 100644 index 00000000000000..3f2f5897bf7183 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/use-internal-linkage-fix-mode-none.cpp @@ -0,0 +1,10 @@ +// RUN: %check_clang_tidy %s misc-use-internal-linkage %t -- \ +// RUN: -config="{CheckOptions: {misc-use-internal-linkage.FixMode: 'None'}}" -- -I%S/Inputs/use-internal-linkage + +void func() {} +// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'func' +// CHECK-FIXES-NOT: static void func() {} + +int global; +// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: variable 'global' +// CHECK-FIXES-NOT: static int global; diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/use-internal-linkage-func.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/use-internal-linkage-func.cpp index c6c513fe0b0c06..9c91389542b03d 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/misc/use-internal-linkage-func.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/use-internal-linkage-func.cpp @@ -1,16 +1,21 @@ // RUN: %check_clang_tidy %s misc-use-internal-linkage %t -- -- -I%S/Inputs/use-internal-linkage +// RUN: %check_clang_tidy %s misc-use-internal-linkage %t -- \ +// RUN: -config="{CheckOptions: {misc-use-internal-linkage.FixMode: 'UseStatic'}}" -- -I%S/Inputs/use-internal-linkage #include "func.h" void func() {} // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'func' +// CHECK-FIXES: static void func() {} template void func_template() {} // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'func_template' +// CHECK-FIXES: static void func_template() {} void func_cpp_inc(); // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'func_cpp_inc' +// CHECK-FIXES: static void func_cpp_inc(); #include "func_cpp.inc" diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/use-internal-linkage-var.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/use-internal-linkage-var.cpp index bd5ef5431de6cc..01b8d28e612301 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/misc/use-internal-linkage-var.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/use-internal-linkage-var.cpp @@ -1,13 +1,17 @@ // RUN: %check_clang_tidy %s misc-use-internal-linkage %t -- -- -I%S/Inputs/use-internal-linkage +// RUN: %check_clang_tidy %s misc-use-internal-linkage %t -- \ +// RUN: -config="{CheckOptions: {misc-use-internal-linkage.FixMode: 'UseStatic'}}" -- -I%S/Inputs/use-internal-linkage #include "var.h" int global; // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: variable 'global' +// CHECK-FIXES: static int global; template T global_template; // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: variable 'global_template' +// CHECK-FIXES: static T global_template; int gloabl_header; diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-copy-initialization.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-copy-initialization.cpp index f259552dc8f1d8..d02bb98cf583cb 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-copy-initialization.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-copy-initialization.cpp @@ -906,3 +906,12 @@ void negativeNonConstMemberExpr() { } } + +bool operator==(ExpensiveToCopyType, ExpensiveToCopyType); + +template bool OperatorWithNoDirectCallee(T t) { + ExpensiveToCopyType a1; + ExpensiveToCopyType a2 = a1; + return a1 == t; +} + diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/simplify-boolean-expr.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/simplify-boolean-expr.cpp index c14438aa938019..bad1055a019045 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/simplify-boolean-expr.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/simplify-boolean-expr.cpp @@ -353,6 +353,23 @@ bool conditional_return_statements(int i) { // CHECK-FIXES: {{^}} return i == 0;{{$}} // CHECK-FIXES-NEXT: {{^}$}} +bool conditional_return_statements_no_fix_1(int i) { + if (i == 0) return true; + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: {{.*}} in conditional return statement + // CHECK-MESSAGES: :[[@LINE-2]]:7: note: conditions that can be simplified + // comment + return false; + // CHECK-MESSAGES: :[[@LINE-1]]:3: note: return statement that can be simplified +} + +bool conditional_return_statements_no_fix_2(int i) { + if (i == 0) return true; + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: {{.*}} in conditional return statement + // CHECK-MESSAGES: :[[@LINE-2]]:7: note: conditions that can be simplified + // comment + else return false; +} + bool conditional_return_statements_then_expr(int i, int j) { if (i == j) return (i == 0); else return false; } diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/allow-no-checks.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/allow-no-checks.cpp new file mode 100644 index 00000000000000..a1f059b92384d0 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/infrastructure/allow-no-checks.cpp @@ -0,0 +1,4 @@ +// RUN: not clang-tidy %s -checks='-*' +// RUN: clang-tidy %s -checks='-*' --allow-no-checks | FileCheck --match-full-lines %s + +// CHECK: No checks enabled. diff --git a/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp index 9aabb1ed30e426..e4a7340318b934 100644 --- a/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp +++ b/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp @@ -30,7 +30,7 @@ ClangDocContext getClangDocContext(std::vector UserStylesheets = {}, StringRef RepositoryUrl = "") { ClangDocContext CDCtx{ - {}, "test-project", {}, {}, {}, RepositoryUrl, UserStylesheets, {}}; + {}, "test-project", {}, {}, {}, RepositoryUrl, UserStylesheets}; CDCtx.UserStylesheets.insert( CDCtx.UserStylesheets.begin(), "../share/clang/clang-doc-default-stylesheet.css"); @@ -66,6 +66,7 @@ TEST(HTMLGeneratorTest, emitNamespaceHTML) { namespace Namespace +
test-project
@@ -176,6 +177,7 @@ TEST(HTMLGeneratorTest, emitRecordHTML) { class r +
test-project
@@ -290,6 +292,7 @@ TEST(HTMLGeneratorTest, emitFunctionHTML) { +
test-project
@@ -337,6 +340,7 @@ TEST(HTMLGeneratorTest, emitEnumHTML) { +
test-project
@@ -422,6 +426,7 @@ TEST(HTMLGeneratorTest, emitCommentHTML) { +
test-project
diff --git a/clang/cmake/caches/Fuchsia-stage2.cmake b/clang/cmake/caches/Fuchsia-stage2.cmake index a573ec54732101..9892b5d58e719b 100644 --- a/clang/cmake/caches/Fuchsia-stage2.cmake +++ b/clang/cmake/caches/Fuchsia-stage2.cmake @@ -321,7 +321,7 @@ foreach(target armv6m-unknown-eabi;armv7m-unknown-eabi;armv8m-unknown-eabi) set(RUNTIMES_${target}_CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "") set(RUNTIMES_${target}_CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY CACHE STRING "") foreach(lang C;CXX;ASM) - set(RUNTIMES_${target}_CMAKE_${lang}_FLAGS "--target=${target} -mthumb" CACHE STRING "") + set(RUNTIMES_${target}_CMAKE_${lang}_FLAGS "--target=${target} -mthumb -Wno-atomic-alignment" CACHE STRING "") endforeach() foreach(type SHARED;MODULE;EXE) set(RUNTIMES_${target}_CMAKE_${type}_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "") diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index bb00c20922d361..080cba90c4a8bf 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -4443,23 +4443,51 @@ the configuration (without a prefix: ``Auto``). false: import {VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying,} from "some/module.js" +.. _KeepEmptyLines: + +**KeepEmptyLines** (``KeepEmptyLinesStyle``) :versionbadge:`clang-format 19` :ref:`¶ ` + Which empty lines are kept. See ``MaxEmptyLinesToKeep`` for how many + consecutive empty lines are kept. + + Nested configuration flags: + + Options regarding which empty lines are kept. + + For example, the config below will remove empty lines at start of the + file, end of the file, and start of blocks. + + + .. code-block:: c++ + + KeepEmptyLines: + AtEndOfFile: false + AtStartOfBlock: false + AtStartOfFile: false + + * ``bool AtEndOfFile`` Keep empty lines at end of file. + + * ``bool AtStartOfBlock`` Keep empty lines at start of a block. + + .. code-block:: c++ + + true: false: + if (foo) { vs. if (foo) { + bar(); + bar(); } + } + + * ``bool AtStartOfFile`` Keep empty lines at start of file. + + .. _KeepEmptyLinesAtEOF: **KeepEmptyLinesAtEOF** (``Boolean``) :versionbadge:`clang-format 17` :ref:`¶ ` - Keep empty lines (up to ``MaxEmptyLinesToKeep``) at end of file. + This option is deprecated. See ``AtEndOfFile`` of ``KeepEmptyLines``. .. _KeepEmptyLinesAtTheStartOfBlocks: **KeepEmptyLinesAtTheStartOfBlocks** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - If true, the empty line at the start of blocks is kept. - - .. code-block:: c++ - - true: false: - if (foo) { vs. if (foo) { - bar(); - bar(); } - } + This option is deprecated. See ``AtStartOfBlock`` of ``KeepEmptyLines``. .. _LambdaBodyIndentation: diff --git a/clang/docs/HIPSupport.rst b/clang/docs/HIPSupport.rst index 5ba84c2f670556..e26297c7af97ac 100644 --- a/clang/docs/HIPSupport.rst +++ b/clang/docs/HIPSupport.rst @@ -284,3 +284,48 @@ Example Usage Base* basePtr = &obj; basePtr->virtualFunction(); // Allowed since obj is constructed in device code } + +SPIR-V Support on HIPAMD ToolChain +================================== + +The HIPAMD ToolChain supports targetting +`AMDGCN Flavoured SPIR-V `_. +The support for SPIR-V in the ROCm and HIPAMD ToolChain is under active +development. + +Compilation Process +------------------- + +When compiling HIP programs with the intent of utilizing SPIR-V, the process +diverges from the traditional compilation flow: + +Using ``--offload-arch=amdgcnspirv`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- **Target Triple**: The ``--offload-arch=amdgcnspirv`` flag instructs the + compiler to use the target triple ``spirv64-amd-amdhsa``. This approach does + generates generic AMDGCN SPIR-V which retains architecture specific elements + without hardcoding them, thus allowing for optimal target specific code to be + generated at run time, when the concrete target is known. + +- **LLVM IR Translation**: The program is compiled to LLVM Intermediate + Representation (IR), which is subsequently translated into SPIR-V. In the + future, this translation step will be replaced by direct SPIR-V emission via + the SPIR-V Back-end. + +- **Clang Offload Bundler**: The resulting SPIR-V is embedded in the Clang + offload bundler with the bundle ID ``hip-spirv64-amd-amdhsa--amdgcnspirv``. + +Mixed with Normal ``--offload-arch`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +**Mixing ``amdgcnspirv`` and concrete ``gfx###`` targets via ``--offload-arch`` +is not currently supported; this limitation is temporary and will be removed in +a future release** + +Architecture Specific Macros +---------------------------- + +None of the architecture specific :doc:`AMDGPU macros ` are +defined when targeting SPIR-V. An alternative, more flexible mechanism to enable +doing per target / per feature code selection will be added in the future. diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index df80588b3fe035..d9439d49a2e299 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -3483,6 +3483,60 @@ Query for this feature with ``__has_builtin(__builtin_trap)``. ``__builtin_arm_trap`` is lowered to the ``llvm.aarch64.break`` builtin, and then to ``brk #payload``. +``__builtin_verbose_trap`` +-------------------------- + +``__builtin_verbose_trap`` causes the program to stop its execution abnormally +and shows a human-readable description of the reason for the termination when a +debugger is attached or in a symbolicated crash log. + +**Syntax**: + +.. code-block:: c++ + + __builtin_verbose_trap(const char *category, const char *reason) + +**Description** + +``__builtin_verbose_trap`` is lowered to the ` ``llvm.trap`` `_ builtin. +Additionally, clang emits debugging information that represents an artificial +inline frame whose name encodes the category and reason strings passed to the builtin, +prefixed by a "magic" prefix. + +For example, consider the following code: + +.. code-block:: c++ + + void foo(int* p) { + if (p == nullptr) + __builtin_verbose_trap("check null", "Argument must not be null!"); + } + +The debugging information would look as if it were produced for the following code: + +.. code-block:: c++ + + __attribute__((always_inline)) + inline void "__clang_trap_msg$check null$Argument must not be null!"() { + __builtin_trap(); + } + + void foo(int* p) { + if (p == nullptr) + "__clang_trap_msg$check null$Argument must not be null!"(); + } + +However, the generated code would not actually contain a call to the artificial +function — it only exists in the debugging information. + +Query for this feature with ``__has_builtin(__builtin_verbose_trap)``. Note that +users need to enable debug information to enable this feature. A call to this +builtin is equivalent to a call to ``__builtin_trap`` if debug information isn't +enabled. + +The optimizer can merge calls to trap with different messages, which degrades +the debugging experience. + ``__builtin_allow_runtime_check`` --------------------------------- @@ -5345,7 +5399,7 @@ The ``#pragma clang section`` directive obeys the following rules: * The pragma clang section is enabled automatically, without need of any flags. -* This feature is only defined to work sensibly for ELF targets. +* This feature is only defined to work sensibly for ELF and Mach-O targets. * If section name is specified through _attribute_((section("myname"))), then the attribute name gains precedence. @@ -5368,16 +5422,85 @@ The ``#pragma comment(lib, ...)`` directive is supported on all ELF targets. The second parameter is the library name (without the traditional Unix prefix of ``lib``). This allows you to provide an implicit link of dependent libraries. -Evaluating Object Size Dynamically -================================== +Evaluating Object Size +====================== + +Clang supports the builtins ``__builtin_object_size`` and +``__builtin_dynamic_object_size``. The semantics are compatible with GCC's +builtins of the same names, but the details are slightly different. + +.. code-block:: c -Clang supports the builtin ``__builtin_dynamic_object_size``, the semantics are -the same as GCC's ``__builtin_object_size`` (which Clang also supports), but -``__builtin_dynamic_object_size`` can evaluate the object's size at runtime. -``__builtin_dynamic_object_size`` is meant to be used as a drop-in replacement -for ``__builtin_object_size`` in libraries that support it. + size_t __builtin_[dynamic_]object_size(const void *ptr, int type) + +Returns the number of accessible bytes ``n`` past ``ptr``. The value returned +depends on ``type``, which is required to be an integer constant between 0 and +3: + +* If ``type & 2 == 0``, the least ``n`` is returned such that accesses to + ``(const char*)ptr + n`` and beyond are known to be out of bounds. This is + ``(size_t)-1`` if no better bound is known. +* If ``type & 2 == 2``, the greatest ``n`` is returned such that accesses to + ``(const char*)ptr + i`` are known to be in bounds, for 0 <= ``i`` < ``n``. + This is ``(size_t)0`` if no better bound is known. + +.. code-block:: c + + char small[10], large[100]; + bool cond; + // Returns 100: writes of more than 100 bytes are known to be out of bounds. + int n100 = __builtin_object_size(cond ? small : large, 0); + // Returns 10: writes of 10 or fewer bytes are known to be in bounds. + int n10 = __builtin_object_size(cond ? small : large, 2); + +* If ``type & 1 == 0``, pointers are considered to be in bounds if they point + into the same storage as ``ptr`` -- that is, the same stack object, global + variable, or heap allocation. +* If ``type & 1 == 1``, pointers are considered to be in bounds if they point + to the same subobject that ``ptr`` points to. If ``ptr`` points to an array + element, other elements of the same array, but not of enclosing arrays, are + considered in bounds. + +.. code-block:: c + + struct X { char a, b, c; } x; + static_assert(__builtin_object_size(&x, 0) == 3); + static_assert(__builtin_object_size(&x.b, 0) == 2); + static_assert(__builtin_object_size(&x.b, 1) == 1); + +.. code-block:: c -For instance, here is a program that ``__builtin_dynamic_object_size`` will make + char a[10][10][10]; + static_assert(__builtin_object_size(&a, 1) == 1000); + static_assert(__builtin_object_size(&a[1], 1) == 900); + static_assert(__builtin_object_size(&a[1][1], 1) == 90); + static_assert(__builtin_object_size(&a[1][1][1], 1) == 9); + +The values returned by this builtin are a best effort conservative approximation +of the correct answers. When ``type & 2 == 0``, the true value is less than or +equal to the value returned by the builtin, and when ``type & 2 == 1``, the true +value is greater than or equal to the value returned by the builtin. + +For ``__builtin_object_size``, the value is determined entirely at compile time. +With optimization enabled, better results will be produced, especially when the +call to ``__builtin_object_size`` is in a different function from the formation +of the pointer. Unlike in GCC, enabling optimization in Clang does not allow +more information about subobjects to be determined, so the ``type & 1 == 1`` +case will often give imprecise results when used across a function call boundary +even when optimization is enabled. + +`The pass_object_size and pass_dynamic_object_size attributes `_ +can be used to invisibly pass the object size for a pointer parameter alongside +the pointer in a function call. This allows more precise object sizes to be +determined both when building without optimizations and in the ``type & 1 == 1`` +case. + +For ``__builtin_dynamic_object_size``, the result is not limited to being a +compile time constant. Instead, a small amount of runtime evaluation is +permitted to determine the size of the object, in order to give a more precise +result. ``__builtin_dynamic_object_size`` is meant to be used as a drop-in +replacement for ``__builtin_object_size`` in libraries that support it. For +instance, here is a program that ``__builtin_dynamic_object_size`` will make safer: .. code-block:: c diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 9c8f8c4a4fbafe..c720e47dbe35b7 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -71,6 +71,11 @@ C++ Specific Potentially Breaking Changes To fix this, update libstdc++ to version 14.1.1 or greater. +- Clang now emits errors when Thread Safety Analysis trylock attributes are + applied to functions or methods with incompatible return values, such as + constructors, destructors, and void-returning functions. This only affects the + ``TRY_ACQUIRE`` and ``TRY_ACQUIRE_SHARED`` attributes (and any synonyms). + ABI Changes in This Version --------------------------- - Fixed Microsoft name mangling of implicitly defined variables used for thread @@ -95,17 +100,22 @@ ABI Changes in This Version - Fixed Microsoft calling convention when returning classes that have a deleted copy assignment operator. Such a class should be returned indirectly. +- Removed the global alias that was pointing to AArch64 Function Multiversioning + ifuncs. Its purpose was to preserve backwards compatibility when the ".ifunc" + suffix got removed from the name mangling. The alias interacts badly with + GlobalOpt (see the issue #96197). + - Fixed Microsoft name mangling for auto non-type template arguments of pointer type for MSVC 1920+. This change resolves incompatibilities with code compiled by MSVC 1920+ but will introduce incompatibilities with code compiled by earlier versions of Clang unless such code is built with the compiler option `-fms-compatibility-version=19.14` to imitate the MSVC 1914 mangling behavior. - AST Dumping Potentially Breaking Changes ---------------------------------------- - The text ast-dumper has improved printing of TemplateArguments. +- The text decl-dumper prints template parameters' trailing requires expressions now. Clang Frontend Potentially Breaking Changes ------------------------------------------- @@ -511,6 +521,11 @@ Attribute Changes in Clang }; +- Introduced new function type attributes ``[[clang::nonblocking]]``, ``[[clang::nonallocating]]``, + ``[[clang::blocking]]``, and ``[[clang::allocating]]``, with GNU-style variants as well. + The attributes declare constraints about a function's behavior pertaining to blocking and + heap memory allocation. + Improvements to Clang's diagnostics ----------------------------------- - Clang now applies syntax highlighting to the code snippets it @@ -720,11 +735,19 @@ Bug Fixes in This Version - Fixed `static_cast` to array of unknown bound. Fixes (#GH62863). +- Clang's Thread Safety Analysis now evaluates trylock success arguments of enum + types rather than silently defaulting to false. This fixes a class of false + negatives where the analysis failed to detect unchecked access to guarded + data. + Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Fix crash when atomic builtins are called with pointer to zero-size struct (#GH90330) +- Clang now allows pointee types of atomic builtin arguments to be complete template types + that was not instantiated elsewhere. + Bug Fixes to Attribute Support ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -915,6 +938,7 @@ Bug Fixes to C++ Support - Fix an assertion failure caused by parsing a lambda used as a default argument for the value of a forward-declared class. (#GH93512). - Fixed a bug in access checking inside return-type-requirement of compound requirements. (#GH93788). +- Fixed an assertion failure about invalid conversion when calling lambda. (#GH96205). Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1091,6 +1115,8 @@ clang-format - Adds ``AllowShortCaseExpressionOnASingleLine`` option. - Adds ``AlignCaseArrows`` suboption to ``AlignConsecutiveShortCaseStatements``. - Adds ``LeftWithLastLine`` suboption to ``AlignEscapedNewlines``. +- Adds ``KeepEmptyLines`` option to deprecate ``KeepEmptyLinesAtEOF`` + and ``KeepEmptyLinesAtTheStartOfBlocks``. libclang -------- diff --git a/clang/docs/ThreadSafetyAnalysis.rst b/clang/docs/ThreadSafetyAnalysis.rst index dcde0c706c7045..1513719caa464b 100644 --- a/clang/docs/ThreadSafetyAnalysis.rst +++ b/clang/docs/ThreadSafetyAnalysis.rst @@ -420,10 +420,17 @@ TRY_ACQUIRE(, ...), TRY_ACQUIRE_SHARED(, ...) *Previously:* ``EXCLUSIVE_TRYLOCK_FUNCTION``, ``SHARED_TRYLOCK_FUNCTION`` These are attributes on a function or method that tries to acquire the given -capability, and returns a boolean value indicating success or failure. -The first argument must be ``true`` or ``false``, to specify which return value -indicates success, and the remaining arguments are interpreted in the same way -as ``ACQUIRE``. See :ref:`mutexheader`, below, for example uses. +capability, and returns a boolean, integer, or pointer value indicating success +or failure. + +The attribute's first argument defines whether a zero or non-zero return value +indicates success. Syntactically, it accepts ``NULL`` or ``nullptr``, ``bool`` +and ``int`` literals, as well as enumerator values. *The analysis only cares +whether this success value is zero or non-zero.* This leads to some subtle +consequences, discussed in the next section. + +The remaining arguments are interpreted in the same way as ``ACQUIRE``. See +:ref:`mutexheader`, below, for example uses. Because the analysis doesn't support conditional locking, a capability is treated as acquired after the first branch on the return value of a try-acquire @@ -445,6 +452,44 @@ function. } } +Subtle Consequences of Non-Boolean Success Values +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The trylock attributes accept non-boolean expressions for the success value, but +the analysis only cares whether the value is zero or non-zero. + +Suppose you define an enum with two non-zero enumerators: ``LockAcquired = 1`` +and ``LockNotAcquired = 2``. If your trylock function returns ``LockAcquired`` +on success and ``LockNotAcquired`` on failure, the analysis may fail to detect +access to guarded data without holding the mutex because they are both non-zero. + +.. code-block:: c++ + + // *** Beware: this code demonstrates incorrect usage. *** + + enum TrylockResult { LockAcquired = 1, LockNotAcquired = 2 }; + + class CAPABILITY("mutex") Mutex { + public: + TrylockResult TryLock() TRY_ACQUIRE(LockAcquired); + }; + + Mutex mu; + int a GUARDED_BY(mu); + + void foo() { + if (mu.TryLock()) { // This branch satisfies the analysis, but permits + // unguarded access to `a`! + a = 0; + mu.Unlock(); + } + } + +It's also possible to return a pointer from the trylock function. Similarly, all +that matters is whether the success value is zero or non-zero. For instance, a +success value of `true` means the function returns a non-null pointer on +success. + ASSERT_CAPABILITY(...) and ASSERT_SHARED_CAPABILITY(...) -------------------------------------------------------- diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index b8d5f372bdf619..42c097d973d532 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -420,21 +420,56 @@ around, such as ``std::string_view``. cplusplus.Move (C++) """""""""""""""""""" -Method calls on a moved-from object and copying a moved-from object will be reported. - +Find use-after-move bugs in C++. This includes method calls on moved-from +objects, assignment of a moved-from object, and repeated move of a moved-from +object. .. code-block:: cpp - struct A { + struct A { void foo() {} }; - void f() { + void f1() { A a; A b = std::move(a); // note: 'a' became 'moved-from' here a.foo(); // warn: method call on a 'moved-from' object 'a' } + void f2() { + A a; + A b = std::move(a); + A c(std::move(a)); // warn: move of an already moved-from object + } + + void f3() { + A a; + A b = std::move(a); + b = a; // warn: copy of moved-from object + } + +The checker option ``WarnOn`` controls on what objects the use-after-move is +checked: + +* The most strict value is ``KnownsOnly``, in this mode only objects are + checked whose type is known to be move-unsafe. These include most STL objects + (but excluding move-safe ones) and smart pointers. +* With option value ``KnownsAndLocals`` local variables (of any type) are + additionally checked. The idea behind this is that local variables are + usually not tempting to be re-used so an use after move is more likely a bug + than with member variables. +* With option value ``All`` any use-after move condition is checked on all + kinds of variables, excluding global variables and known move-safe cases. + +Default value is ``KnownsAndLocals``. + +Calls of methods named ``empty()`` or ``isEmpty()`` are allowed on moved-from +objects because these methods are considered as move-safe. Functions called +``reset()``, ``destroy()``, ``clear()``, ``assign``, ``resize``, ``shrink`` are +treated as state-reset functions and are allowed on moved-from objects, these +make the object valid again. This applies to any type of object (not only STL +ones). + .. _cplusplus-NewDelete: cplusplus.NewDelete (C++) diff --git a/clang/examples/LLVMPrintFunctionNames/LLVMPrintFunctionNames.cpp b/clang/examples/LLVMPrintFunctionNames/LLVMPrintFunctionNames.cpp index 6cb87e4b5e19c4..79a315d5a4ee27 100644 --- a/clang/examples/LLVMPrintFunctionNames/LLVMPrintFunctionNames.cpp +++ b/clang/examples/LLVMPrintFunctionNames/LLVMPrintFunctionNames.cpp @@ -18,6 +18,7 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendPluginRegistry.h" #include "clang/Sema/Sema.h" +#include "llvm/IR/Module.h" #include "llvm/IR/PassManager.h" #include "llvm/Passes/OptimizationLevel.h" #include "llvm/Passes/PassBuilder.h" diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index de86cb5e9d7fcf..a99f2dc6eb3f2b 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -37,6 +37,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Support/TypeSize.h" #include @@ -467,6 +468,14 @@ class ASTContext : public RefCountedBase { /// This is the top-level (C++20) Named module we are building. Module *CurrentCXXNamedModule = nullptr; + /// Help structures to decide whether two `const Module *` belongs + /// to the same conceptual module to avoid the expensive to string comparison + /// if possible. + /// + /// Not serialized intentionally. + llvm::StringMap PrimaryModuleNameMap; + llvm::DenseMap SameModuleLookupSet; + static constexpr unsigned ConstantArrayTypesLog2InitSize = 8; static constexpr unsigned GeneralTypesLog2InitSize = 9; static constexpr unsigned FunctionProtoTypesLog2InitSize = 12; @@ -1073,6 +1082,12 @@ class ASTContext : public RefCountedBase { /// Get module under construction, nullptr if this is not a C++20 module. Module *getCurrentNamedModule() const { return CurrentCXXNamedModule; } + /// If the two module \p M1 and \p M2 are in the same module. + /// + /// FIXME: The signature may be confusing since `clang::Module` means to + /// a module fragment or a module unit but not a C++20 module. + bool isInSameModule(const Module *M1, const Module *M2); + TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl->getMostRecentDecl(); } @@ -1263,6 +1278,11 @@ class ASTContext : public RefCountedBase { /// space. QualType removeAddrSpaceQualType(QualType T) const; + /// Return the "other" discriminator used for the pointer auth schema used for + /// vtable pointers in instances of the requested type. + uint16_t + getPointerAuthVTablePointerDiscriminator(const CXXRecordDecl *RD); + /// Apply Objective-C protocol qualifiers to the given type. /// \param allowOnPointerType specifies if we can apply protocol /// qualifiers on ObjCObjectPointerType. It can be set to true when @@ -3424,12 +3444,21 @@ OPT_LIST(V) /// Whether a C++ static variable or CUDA/HIP kernel should be externalized. bool shouldExternalize(const Decl *D) const; + /// Resolve the root record to be used to derive the vtable pointer + /// authentication policy for the specified record. + const CXXRecordDecl * + baseForVTableAuthentication(const CXXRecordDecl *ThisClass); + bool useAbbreviatedThunkName(GlobalDecl VirtualMethodDecl, + StringRef MangledName); + StringRef getCUIDHash() const; private: /// All OMPTraitInfo objects live in this collection, one per /// `pragma omp [begin] declare variant` directive. SmallVector, 4> OMPTraitInfoVector; + + llvm::DenseMap> ThunksToBeAbbreviated; }; /// Insertion operator for diagnostics. diff --git a/clang/include/clang/AST/AbstractBasicReader.h b/clang/include/clang/AST/AbstractBasicReader.h index ab036f1d445acc..4b627c65e276bb 100644 --- a/clang/include/clang/AST/AbstractBasicReader.h +++ b/clang/include/clang/AST/AbstractBasicReader.h @@ -244,6 +244,15 @@ class DataStreamBasicReader : public BasicReaderBase { return FunctionProtoType::ExtParameterInfo::getFromOpaqueValue(value); } + FunctionEffect readFunctionEffect() { + uint32_t value = asImpl().readUInt32(); + return FunctionEffect::fromOpaqueInt32(value); + } + + EffectConditionExpr readEffectConditionExpr() { + return EffectConditionExpr{asImpl().readExprRef()}; + } + NestedNameSpecifier *readNestedNameSpecifier() { auto &ctx = getASTContext(); diff --git a/clang/include/clang/AST/AbstractBasicWriter.h b/clang/include/clang/AST/AbstractBasicWriter.h index 8e42fcaad1d388..b941add8bde889 100644 --- a/clang/include/clang/AST/AbstractBasicWriter.h +++ b/clang/include/clang/AST/AbstractBasicWriter.h @@ -222,6 +222,14 @@ class DataStreamBasicWriter : public BasicWriterBase { asImpl().writeUInt32(epi.getOpaqueValue()); } + void writeFunctionEffect(FunctionEffect E) { + asImpl().writeUInt32(E.toOpaqueInt32()); + } + + void writeEffectConditionExpr(EffectConditionExpr CE) { + asImpl().writeExprRef(CE.getCondition()); + } + void writeNestedNameSpecifier(NestedNameSpecifier *NNS) { // Nested name specifiers usually aren't too long. I think that 8 would // typically accommodate the vast majority. diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 7fd80b90d10337..5957f14098363e 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -3042,6 +3042,16 @@ class FunctionDecl : public DeclaratorDecl, /// computed and stored. unsigned getODRHash() const; + FunctionEffectsRef getFunctionEffects() const { + // Effects may differ between declarations, but they should be propagated + // from old to new on any redeclaration, so it suffices to look at + // getMostRecentDecl(). + if (const auto *FPT = + getMostRecentDecl()->getType()->getAs()) + return FPT->getFunctionEffects(); + return {}; + } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { @@ -4670,6 +4680,13 @@ class BlockDecl : public Decl, public DeclContext { SourceRange getSourceRange() const override LLVM_READONLY; + FunctionEffectsRef getFunctionEffects() const { + if (const TypeSourceInfo *TSI = getSignatureAsWritten()) + if (const auto *FPT = TSI->getType()->getAs()) + return FPT->getFunctionEffects(); + return {}; + } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == Block; } diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 3310f57acc6835..45dac82e540776 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -835,10 +835,7 @@ class alignas(8) Decl { /// Get the module that owns this declaration for linkage purposes. /// There only ever is such a standard C++ module. - /// - /// \param IgnoreLinkage Ignore the linkage of the entity; assume that - /// all declarations in a global module fragment are unowned. - Module *getOwningModuleForLinkage(bool IgnoreLinkage = false) const; + Module *getOwningModuleForLinkage() const; /// Determine whether this declaration is definitely visible to name lookup, /// independent of whether the owning module is visible. diff --git a/clang/include/clang/AST/DeclID.h b/clang/include/clang/AST/DeclID.h index e8f4860e13f1f8..e5e27389fac60d 100644 --- a/clang/include/clang/AST/DeclID.h +++ b/clang/include/clang/AST/DeclID.h @@ -197,6 +197,8 @@ class LocalDeclID : public DeclIDBase { static LocalDeclID get(ASTReader &Reader, serialization::ModuleFile &MF, DeclID ID); + static LocalDeclID get(ASTReader &Reader, serialization::ModuleFile &MF, + unsigned ModuleFileIndex, unsigned LocalDeclID); LocalDeclID &operator++() { ++ID; @@ -259,11 +261,7 @@ template <> struct DenseMapInfo { } static unsigned getHashValue(const GlobalDeclID &Key) { - // Our default hash algorithm for 64 bits integer may not be very good. - // In GlobalDeclID's case, it is pretty common that the lower 32 bits can - // be same. - // FIXME: Remove this when we fix the underlying issue. - return llvm::hash_value(Key.getRawValue()); + return DenseMapInfo::getHashValue(Key.getRawValue()); } static bool isEqual(const GlobalDeclID &L, const GlobalDeclID &R) { diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 3bc8cae4d8c86c..a8add9d1337c6b 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -384,7 +384,7 @@ class Expr : public ValueStmt { bool isRValue() const { return Kind >= CL_XValue; } bool isModifiable() const { return getModifiable() == CM_Modifiable; } - /// Create a simple, modifiably lvalue + /// Create a simple, modifiable lvalue static Classification makeSimpleLValue() { return Classification(CL_LValue, CM_Modifiable); } @@ -787,6 +787,11 @@ class Expr : public ValueStmt { const Expr *PtrExpression, ASTContext &Ctx, EvalResult &Status) const; + /// If the current Expr can be evaluated to a pointer to a null-terminated + /// constant string, return the constant string (without the terminating + /// null). + std::optional tryEvaluateString(ASTContext &Ctx) const; + /// Enumeration used to describe the kind of Null pointer constant /// returned from \c isNullPointerConstant(). enum NullPointerConstantKind { @@ -1287,7 +1292,7 @@ class DeclRefExpr final DeclRefExpr(const ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, - bool RefersToEnlosingVariableOrCapture, + bool RefersToEnclosingVariableOrCapture, const DeclarationNameInfo &NameInfo, NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs, QualType T, ExprValueKind VK, NonOdrUseReason NOUR); @@ -1653,14 +1658,14 @@ class FloatingLiteral : public Expr, private APFloatStorage { } /// Get a raw enumeration value representing the floating-point semantics of - /// this literal (32-bit IEEE, x87, ...), suitable for serialisation. + /// this literal (32-bit IEEE, x87, ...), suitable for serialization. llvm::APFloatBase::Semantics getRawSemantics() const { return static_cast( FloatingLiteralBits.Semantics); } /// Set the raw enumeration value representing the floating-point semantics of - /// this literal (32-bit IEEE, x87, ...), suitable for serialisation. + /// this literal (32-bit IEEE, x87, ...), suitable for serialization. void setRawSemantics(llvm::APFloatBase::Semantics Sem) { FloatingLiteralBits.Semantics = Sem; } @@ -2125,7 +2130,7 @@ class SYCLUniqueStableNameExpr final : public Expr { static std::string ComputeName(ASTContext &Context, QualType Ty); }; -/// ParenExpr - This represents a parethesized expression, e.g. "(1)". This +/// ParenExpr - This represents a parenthesized expression, e.g. "(1)". This /// AST node is only formed if full location information is requested. class ParenExpr : public Expr { SourceLocation L, R; @@ -2241,7 +2246,7 @@ class UnaryOperator final bool canOverflow() const { return UnaryOperatorBits.CanOverflow; } void setCanOverflow(bool C) { UnaryOperatorBits.CanOverflow = C; } - /// Get the FP contractability status of this operator. Only meaningful for + /// Get the FP contractibility status of this operator. Only meaningful for /// operations on floating point types. bool isFPContractableWithinStatement(const LangOptions &LO) const { return getFPFeaturesInEffect(LO).allowFPContractWithinStatement(); @@ -4049,7 +4054,7 @@ class BinaryOperator : public Expr { return FPOptionsOverride(); } - /// Get the FP contractability status of this operator. Only meaningful for + /// Get the FP contractibility status of this operator. Only meaningful for /// operations on floating point types. bool isFPContractableWithinStatement(const LangOptions &LO) const { return getFPFeaturesInEffect(LO).allowFPContractWithinStatement(); @@ -4290,7 +4295,7 @@ class BinaryConditionalOperator : public AbstractConditionalOperator { } /// getFalseExpr - Return the subexpression which will be - /// evaluated if the condnition evaluates to false; this is + /// evaluated if the condition evaluates to false; this is /// defined in terms of the opaque value. Expr *getFalseExpr() const { return cast(SubExprs[RHS]); @@ -5998,7 +6003,7 @@ class GenericSelectionExpr final // if *It1 and *It2 are bound to the same objects. // An alternative design approach was discussed during review; // store an Association object inside the iterator, and return a reference - // to it when dereferenced. This idea was discarded beacuse of nasty + // to it when dereferenced. This idea was discarded because of nasty // lifetime issues: // AssociationIterator It = ...; // const Association &Assoc = *It++; // Oops, Assoc is dangling. diff --git a/clang/include/clang/AST/GlobalDecl.h b/clang/include/clang/AST/GlobalDecl.h index 88abba28c991d3..386693cabb1fbb 100644 --- a/clang/include/clang/AST/GlobalDecl.h +++ b/clang/include/clang/AST/GlobalDecl.h @@ -145,6 +145,10 @@ class GlobalDecl { LHS.MultiVersionIndex == RHS.MultiVersionIndex; } + bool operator!=(const GlobalDecl &Other) const { + return !(*this == Other); + } + void *getAsOpaquePtr() const { return Value.getOpaqueValue(); } explicit operator bool() const { return getAsOpaquePtr(); } diff --git a/clang/include/clang/AST/Mangle.h b/clang/include/clang/AST/Mangle.h index e586b0cec43dfd..d5f6c0f6cc67df 100644 --- a/clang/include/clang/AST/Mangle.h +++ b/clang/include/clang/AST/Mangle.h @@ -130,15 +130,15 @@ class MangleContext { // FIXME: consider replacing raw_ostream & with something like SmallString &. void mangleName(GlobalDecl GD, raw_ostream &); virtual void mangleCXXName(GlobalDecl GD, raw_ostream &) = 0; - virtual void mangleThunk(const CXXMethodDecl *MD, - const ThunkInfo &Thunk, - raw_ostream &) = 0; + virtual void mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk, + bool ElideOverrideInfo, raw_ostream &) = 0; virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, - const ThisAdjustment &ThisAdjustment, - raw_ostream &) = 0; + const ThunkInfo &Thunk, + bool ElideOverrideInfo, raw_ostream &) = 0; virtual void mangleReferenceTemporary(const VarDecl *D, unsigned ManglingNumber, raw_ostream &) = 0; + virtual void mangleCXXVTable(const CXXRecordDecl *RD, raw_ostream &) = 0; virtual void mangleCXXRTTI(QualType T, raw_ostream &) = 0; virtual void mangleCXXRTTIName(QualType T, raw_ostream &, bool NormalizeIntegers = false) = 0; @@ -192,7 +192,6 @@ class ItaniumMangleContext : public MangleContext { bool IsAux = false) : MangleContext(C, D, MK_Itanium, IsAux) {} - virtual void mangleCXXVTable(const CXXRecordDecl *RD, raw_ostream &) = 0; virtual void mangleCXXVTT(const CXXRecordDecl *RD, raw_ostream &) = 0; virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset, const CXXRecordDecl *Type, diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td index 6df1d93a7ba2eb..5f7d6195187623 100644 --- a/clang/include/clang/AST/PropertiesBase.td +++ b/clang/include/clang/AST/PropertiesBase.td @@ -117,6 +117,8 @@ def ExtParameterInfo : PropertyType<"FunctionProtoType::ExtParameterInfo">; def FixedPointSemantics : PropertyType<"llvm::FixedPointSemantics"> { let PassByReference = 1; } +def FunctionEffect : PropertyType<"FunctionEffect">; +def EffectConditionExpr : PropertyType<"EffectConditionExpr">; def Identifier : RefPropertyType<"IdentifierInfo"> { let ConstWhenWriting = 1; } def LValuePathEntry : PropertyType<"APValue::LValuePathEntry">; def LValuePathSerializationHelper : diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 61246479188e95..62836ec5c63125 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -118,6 +118,7 @@ class EnumDecl; class Expr; class ExtQualsTypeCommonBase; class FunctionDecl; +class FunctionEffectSet; class IdentifierInfo; class NamedDecl; class ObjCInterfaceDecl; @@ -131,6 +132,7 @@ class TemplateArgument; class TemplateArgumentListInfo; class TemplateArgumentLoc; class TemplateTypeParmDecl; +template class TreeTransform; class TypedefNameDecl; class UnresolvedUsingTypenameDecl; class UsingShadowDecl; @@ -4524,8 +4526,13 @@ class FunctionType : public Type { LLVM_PREFERRED_TYPE(bool) unsigned HasArmTypeAttributes : 1; + LLVM_PREFERRED_TYPE(bool) + unsigned EffectsHaveConditions : 1; + unsigned NumFunctionEffects : 4; + FunctionTypeExtraBitfields() - : NumExceptionType(0), HasArmTypeAttributes(false) {} + : NumExceptionType(0), HasArmTypeAttributes(false), + EffectsHaveConditions(false), NumFunctionEffects(0) {} }; /// The AArch64 SME ACLE (Arm C/C++ Language Extensions) define a number @@ -4658,6 +4665,296 @@ class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode { } }; +// ------------------------------------------------------------------------------ + +/// Represents an abstract function effect, using just an enumeration describing +/// its kind. +class FunctionEffect { +public: + /// Identifies the particular effect. + enum class Kind : uint8_t { + None = 0, + NonBlocking = 1, + NonAllocating = 2, + Blocking = 3, + Allocating = 4 + }; + + /// Flags describing some behaviors of the effect. + using Flags = unsigned; + enum FlagBit : Flags { + // Can verification inspect callees' implementations? (e.g. nonblocking: + // yes, tcb+types: no). This also implies the need for 2nd-pass + // verification. + FE_InferrableOnCallees = 0x1, + + // Language constructs which effects can diagnose as disallowed. + FE_ExcludeThrow = 0x2, + FE_ExcludeCatch = 0x4, + FE_ExcludeObjCMessageSend = 0x8, + FE_ExcludeStaticLocalVars = 0x10, + FE_ExcludeThreadLocalVars = 0x20 + }; + +private: + LLVM_PREFERRED_TYPE(Kind) + unsigned FKind : 3; + + // Expansion: for hypothetical TCB+types, there could be one Kind for TCB, + // then ~16(?) bits "SubKind" to map to a specific named TCB. SubKind would + // be considered for uniqueness. + +public: + FunctionEffect() : FKind(unsigned(Kind::None)) {} + + explicit FunctionEffect(Kind K) : FKind(unsigned(K)) {} + + /// The kind of the effect. + Kind kind() const { return Kind(FKind); } + + /// Return the opposite kind, for effects which have opposites. + Kind oppositeKind() const; + + /// For serialization. + uint32_t toOpaqueInt32() const { return FKind; } + static FunctionEffect fromOpaqueInt32(uint32_t Value) { + return FunctionEffect(Kind(Value)); + } + + /// Flags describing some behaviors of the effect. + Flags flags() const { + switch (kind()) { + case Kind::NonBlocking: + return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch | + FE_ExcludeObjCMessageSend | FE_ExcludeStaticLocalVars | + FE_ExcludeThreadLocalVars; + case Kind::NonAllocating: + // Same as NonBlocking, except without FE_ExcludeStaticLocalVars. + return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch | + FE_ExcludeObjCMessageSend | FE_ExcludeThreadLocalVars; + case Kind::Blocking: + case Kind::Allocating: + return 0; + case Kind::None: + break; + } + llvm_unreachable("unknown effect kind"); + } + + /// The description printed in diagnostics, e.g. 'nonblocking'. + StringRef name() const; + + /// Return true if the effect is allowed to be inferred on the callee, + /// which is either a FunctionDecl or BlockDecl. + /// Example: This allows nonblocking(false) to prevent inference for the + /// function. + bool canInferOnFunction(const Decl &Callee) const; + + // Return false for success. When true is returned for a direct call, then the + // FE_InferrableOnCallees flag may trigger inference rather than an immediate + // diagnostic. Caller should be assumed to have the effect (it may not have it + // explicitly when inferring). + bool shouldDiagnoseFunctionCall(bool Direct, + ArrayRef CalleeFX) const; + + friend bool operator==(const FunctionEffect &LHS, const FunctionEffect &RHS) { + return LHS.FKind == RHS.FKind; + } + friend bool operator!=(const FunctionEffect &LHS, const FunctionEffect &RHS) { + return !(LHS == RHS); + } + friend bool operator<(const FunctionEffect &LHS, const FunctionEffect &RHS) { + return LHS.FKind < RHS.FKind; + } +}; + +/// Wrap a function effect's condition expression in another struct so +/// that FunctionProtoType's TrailingObjects can treat it separately. +class EffectConditionExpr { + Expr *Cond = nullptr; // if null, unconditional. + +public: + EffectConditionExpr() = default; + EffectConditionExpr(Expr *E) : Cond(E) {} + + Expr *getCondition() const { return Cond; } + + bool operator==(const EffectConditionExpr &RHS) const { + return Cond == RHS.Cond; + } +}; + +/// A FunctionEffect plus a potential boolean expression determining whether +/// the effect is declared (e.g. nonblocking(expr)). Generally the condition +/// expression when present, is dependent. +struct FunctionEffectWithCondition { + FunctionEffect Effect; + EffectConditionExpr Cond; + + FunctionEffectWithCondition() = default; + FunctionEffectWithCondition(const FunctionEffect &E, + const EffectConditionExpr &C) + : Effect(E), Cond(C) {} + + /// Return a textual description of the effect, and its condition, if any. + std::string description() const; +}; + +/// Support iteration in parallel through a pair of FunctionEffect and +/// EffectConditionExpr containers. +template class FunctionEffectIterator { + friend Container; + + const Container *Outer = nullptr; + size_t Idx = 0; + +public: + FunctionEffectIterator(); + FunctionEffectIterator(const Container &O, size_t I) : Outer(&O), Idx(I) {} + bool operator==(const FunctionEffectIterator &Other) const { + return Idx == Other.Idx; + } + bool operator!=(const FunctionEffectIterator &Other) const { + return Idx != Other.Idx; + } + + FunctionEffectIterator operator++() { + ++Idx; + return *this; + } + + FunctionEffectWithCondition operator*() const { + assert(Outer != nullptr && "invalid FunctionEffectIterator"); + bool HasConds = !Outer->Conditions.empty(); + return FunctionEffectWithCondition{Outer->Effects[Idx], + HasConds ? Outer->Conditions[Idx] + : EffectConditionExpr()}; + } +}; + +/// An immutable set of FunctionEffects and possibly conditions attached to +/// them. The effects and conditions reside in memory not managed by this object +/// (typically, trailing objects in FunctionProtoType, or borrowed references +/// from a FunctionEffectSet). +/// +/// Invariants: +/// - there is never more than one instance of any given effect. +/// - the array of conditions is either empty or has the same size as the +/// array of effects. +/// - some conditions may be null expressions; each condition pertains to +/// the effect at the same array index. +/// +/// Also, if there are any conditions, at least one of those expressions will be +/// dependent, but this is only asserted in the constructor of +/// FunctionProtoType. +/// +/// See also FunctionEffectSet, in Sema, which provides a mutable set. +class FunctionEffectsRef { + // Restrict classes which can call the private constructor -- these friends + // all maintain the required invariants. FunctionEffectSet is generally the + // only way in which the arrays are created; FunctionProtoType will not + // reorder them. + friend FunctionProtoType; + friend FunctionEffectSet; + + ArrayRef Effects; + ArrayRef Conditions; + + // The arrays are expected to have been sorted by the caller, with the + // effects in order. The conditions array must be empty or the same size + // as the effects array, since the conditions are associated with the effects + // at the same array indices. + FunctionEffectsRef(ArrayRef FX, + ArrayRef Conds) + : Effects(FX), Conditions(Conds) {} + +public: + /// Extract the effects from a Type if it is a function, block, or member + /// function pointer, or a reference or pointer to one. + static FunctionEffectsRef get(QualType QT); + + /// Asserts invariants. + static FunctionEffectsRef create(ArrayRef FX, + ArrayRef Conds); + + FunctionEffectsRef() = default; + + bool empty() const { return Effects.empty(); } + size_t size() const { return Effects.size(); } + + ArrayRef effects() const { return Effects; } + ArrayRef conditions() const { return Conditions; } + + using iterator = FunctionEffectIterator; + friend iterator; + iterator begin() const { return iterator(*this, 0); } + iterator end() const { return iterator(*this, size()); } + + friend bool operator==(const FunctionEffectsRef &LHS, + const FunctionEffectsRef &RHS) { + return LHS.Effects == RHS.Effects && LHS.Conditions == RHS.Conditions; + } + friend bool operator!=(const FunctionEffectsRef &LHS, + const FunctionEffectsRef &RHS) { + return !(LHS == RHS); + } + + void Profile(llvm::FoldingSetNodeID &ID) const; + void dump(llvm::raw_ostream &OS) const; +}; + +/// A mutable set of FunctionEffects and possibly conditions attached to them. +/// Used to compare and merge effects on declarations. +/// +/// Has the same invariants as FunctionEffectsRef. +class FunctionEffectSet { + SmallVector Effects; + SmallVector Conditions; + +public: + FunctionEffectSet() = default; + + explicit FunctionEffectSet(const FunctionEffectsRef &FX) + : Effects(FX.effects()), Conditions(FX.conditions()) {} + + bool empty() const { return Effects.empty(); } + size_t size() const { return Effects.size(); } + + using iterator = FunctionEffectIterator; + friend iterator; + iterator begin() const { return iterator(*this, 0); } + iterator end() const { return iterator(*this, size()); } + + operator FunctionEffectsRef() const { return {Effects, Conditions}; } + + void dump(llvm::raw_ostream &OS) const; + + // Mutators + + // On insertion, a conflict occurs when attempting to insert an + // effect which is opposite an effect already in the set, or attempting + // to insert an effect which is already in the set but with a condition + // which is not identical. + struct Conflict { + FunctionEffectWithCondition Kept; + FunctionEffectWithCondition Rejected; + }; + using Conflicts = SmallVector; + + // Returns true for success (obviating a check of Errs.empty()). + bool insert(const FunctionEffectWithCondition &NewEC, Conflicts &Errs); + + // Returns true for success (obviating a check of Errs.empty()). + bool insert(const FunctionEffectsRef &Set, Conflicts &Errs); + + // Set operations + + static FunctionEffectSet getUnion(FunctionEffectsRef LHS, + FunctionEffectsRef RHS, Conflicts &Errs); + static FunctionEffectSet getIntersection(FunctionEffectsRef LHS, + FunctionEffectsRef RHS); +}; + /// Represents a prototype with parameter type info, e.g. /// 'int foo(int)' or 'int foo(void)'. 'void' is represented as having no /// parameters, not as having a single void parameter. Such a type can have @@ -4672,7 +4969,8 @@ class FunctionProtoType final FunctionProtoType, QualType, SourceLocation, FunctionType::FunctionTypeExtraBitfields, FunctionType::FunctionTypeArmAttributes, FunctionType::ExceptionType, - Expr *, FunctionDecl *, FunctionType::ExtParameterInfo, Qualifiers> { + Expr *, FunctionDecl *, FunctionType::ExtParameterInfo, + FunctionEffect, EffectConditionExpr, Qualifiers> { friend class ASTContext; // ASTContext creates these. friend TrailingObjects; @@ -4703,9 +5001,15 @@ class FunctionProtoType final // an ExtParameterInfo for each of the parameters. Present if and // only if hasExtParameterInfos() is true. // + // * Optionally, an array of getNumFunctionEffects() FunctionEffect. + // Present only when getNumFunctionEffects() > 0 + // + // * Optionally, an array of getNumFunctionEffects() EffectConditionExpr. + // Present only when getNumFunctionEffectConditions() > 0. + // // * Optionally a Qualifiers object to represent extra qualifiers that can't - // be represented by FunctionTypeBitfields.FastTypeQuals. Present if and only - // if hasExtQualifiers() is true. + // be represented by FunctionTypeBitfields.FastTypeQuals. Present if and + // only if hasExtQualifiers() is true. // // The optional FunctionTypeExtraBitfields has to be before the data // related to the exception specification since it contains the number @@ -4761,6 +5065,7 @@ class FunctionProtoType final ExceptionSpecInfo ExceptionSpec; const ExtParameterInfo *ExtParameterInfos = nullptr; SourceLocation EllipsisLoc; + FunctionEffectsRef FunctionEffects; ExtProtoInfo() : Variadic(false), HasTrailingReturn(false), @@ -4778,7 +5083,8 @@ class FunctionProtoType final bool requiresFunctionProtoTypeExtraBitfields() const { return ExceptionSpec.Type == EST_Dynamic || - requiresFunctionProtoTypeArmAttributes(); + requiresFunctionProtoTypeArmAttributes() || + !FunctionEffects.empty(); } bool requiresFunctionProtoTypeArmAttributes() const { @@ -4826,6 +5132,14 @@ class FunctionProtoType final return hasExtParameterInfos() ? getNumParams() : 0; } + unsigned numTrailingObjects(OverloadToken) const { + return getNumFunctionEffects(); + } + + unsigned numTrailingObjects(OverloadToken) const { + return getNumFunctionEffectConditions(); + } + /// Determine whether there are any argument types that /// contain an unexpanded parameter pack. static bool containsAnyUnexpandedParameterPack(const QualType *ArgArray, @@ -4927,6 +5241,7 @@ class FunctionProtoType final EPI.RefQualifier = getRefQualifier(); EPI.ExtParameterInfos = getExtParameterInfosOrNull(); EPI.AArch64SMEAttributes = getAArch64SMEAttributes(); + EPI.FunctionEffects = getFunctionEffects(); return EPI; } @@ -5138,6 +5453,62 @@ class FunctionProtoType final return false; } + unsigned getNumFunctionEffects() const { + return hasExtraBitfields() + ? getTrailingObjects() + ->NumFunctionEffects + : 0; + } + + // For serialization. + ArrayRef getFunctionEffectsWithoutConditions() const { + if (hasExtraBitfields()) { + const auto *Bitfields = getTrailingObjects(); + if (Bitfields->NumFunctionEffects > 0) + return {getTrailingObjects(), + Bitfields->NumFunctionEffects}; + } + return {}; + } + + unsigned getNumFunctionEffectConditions() const { + if (hasExtraBitfields()) { + const auto *Bitfields = getTrailingObjects(); + if (Bitfields->EffectsHaveConditions) + return Bitfields->NumFunctionEffects; + } + return 0; + } + + // For serialization. + ArrayRef getFunctionEffectConditions() const { + if (hasExtraBitfields()) { + const auto *Bitfields = getTrailingObjects(); + if (Bitfields->EffectsHaveConditions) + return {getTrailingObjects(), + Bitfields->NumFunctionEffects}; + } + return {}; + } + + // Combines effects with their conditions. + FunctionEffectsRef getFunctionEffects() const { + if (hasExtraBitfields()) { + const auto *Bitfields = getTrailingObjects(); + if (Bitfields->NumFunctionEffects > 0) { + const size_t NumConds = Bitfields->EffectsHaveConditions + ? Bitfields->NumFunctionEffects + : 0; + return FunctionEffectsRef( + {getTrailingObjects(), + Bitfields->NumFunctionEffects}, + {NumConds ? getTrailingObjects() : nullptr, + NumConds}); + } + } + return {}; + } + bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td index aba14b222a03ac..7d4353c2773a30 100644 --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -352,6 +352,12 @@ let Class = FunctionProtoType in { def : Property<"AArch64SMEAttributes", UInt32> { let Read = [{ node->getAArch64SMEAttributes() }]; } + def : Property<"functionEffects", Array> { + let Read = [{ node->getFunctionEffectsWithoutConditions() }]; + } + def : Property<"functionEffectConds", Array> { + let Read = [{ node->getFunctionEffectConditions() }]; + } def : Creator<[{ auto extInfo = FunctionType::ExtInfo(noReturn, hasRegParm, regParm, @@ -368,6 +374,7 @@ let Class = FunctionProtoType in { epi.ExtParameterInfos = extParameterInfo.empty() ? nullptr : extParameterInfo.data(); epi.AArch64SMEAttributes = AArch64SMEAttributes; + epi.FunctionEffects = FunctionEffectsRef::create(functionEffects, functionEffectConds); return ctx.getFunctionType(returnType, parameters, epi); }]>; } diff --git a/clang/include/clang/AST/VTableBuilder.h b/clang/include/clang/AST/VTableBuilder.h index fbf6c041a1ec11..a5de41dbc22f14 100644 --- a/clang/include/clang/AST/VTableBuilder.h +++ b/clang/include/clang/AST/VTableBuilder.h @@ -361,6 +361,10 @@ class VTableContextBase { }; class ItaniumVTableContext : public VTableContextBase { +public: + typedef llvm::DenseMap + OriginalMethodMapTy; + private: /// Contains the index (relative to the vtable address point) @@ -384,6 +388,10 @@ class ItaniumVTableContext : public VTableContextBase { VirtualBaseClassOffsetOffsetsMapTy; VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets; + /// Map from a virtual method to the nearest method in the primary base class + /// chain that it overrides. + OriginalMethodMapTy OriginalMethodMap; + void computeVTableRelatedInformation(const CXXRecordDecl *RD) override; public: @@ -425,6 +433,27 @@ class ItaniumVTableContext : public VTableContextBase { CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, const CXXRecordDecl *VBase); + /// Return the method that added the v-table slot that will be used to call + /// the given method. + /// + /// In the Itanium ABI, where overrides always cause methods to be added to + /// the primary v-table if they're not already there, this will be the first + /// declaration in the primary base class chain for which the return type + /// adjustment is trivial. + GlobalDecl findOriginalMethod(GlobalDecl GD); + + const CXXMethodDecl *findOriginalMethodInMap(const CXXMethodDecl *MD) const; + + void setOriginalMethod(const CXXMethodDecl *Key, const CXXMethodDecl *Val) { + OriginalMethodMap[Key] = Val; + } + + /// This method is reserved for the implementation and shouldn't be used + /// directly. + const OriginalMethodMapTy &getOriginalMethodMap() { + return OriginalMethodMap; + } + static bool classof(const VTableContextBase *VT) { return !VT->isMicrosoft(); } diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index c8e2015c8e66ae..452cd1810f6539 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -686,6 +686,10 @@ class Attr { bit PragmaAttributeSupport; // Set to true if this attribute accepts parameter pack expansion expressions. bit AcceptsExprPack = 0; + // To support multiple enum parameters to an attribute without breaking + // our existing general parsing we need to have a separate flag that + // opts an attribute into strict parsing of attribute parameters + bit StrictEnumParameters = 0; // Lists language options, one of which is required to be true for the // attribute to be applicable. If empty, no language options are required. list LangOpts = []; @@ -1461,6 +1465,28 @@ def CXX11NoReturn : InheritableAttr { let Documentation = [CXX11NoReturnDocs]; } +def NonBlocking : TypeAttr { + let Spellings = [Clang<"nonblocking">]; + let Args = [ExprArgument<"Cond", /*optional*/1>]; + let Documentation = [NonBlockingDocs]; +} + +def NonAllocating : TypeAttr { + let Spellings = [Clang<"nonallocating">]; + let Args = [ExprArgument<"Cond", /*optional*/1>]; + let Documentation = [NonAllocatingDocs]; +} + +def Blocking : TypeAttr { + let Spellings = [Clang<"blocking">]; + let Documentation = [BlockingDocs]; +} + +def Allocating : TypeAttr { + let Spellings = [Clang<"allocating">]; + let Documentation = [AllocatingDocs]; +} + // Similar to CUDA, OpenCL attributes do not receive a [[]] spelling because // the specification does not expose them with one currently. def OpenCLKernel : InheritableAttr { @@ -4554,6 +4580,31 @@ def NoRandomizeLayout : InheritableAttr { } def : MutualExclusions<[RandomizeLayout, NoRandomizeLayout]>; +def VTablePointerAuthentication : InheritableAttr { + let Spellings = [Clang<"ptrauth_vtable_pointer">]; + let Subjects = SubjectList<[CXXRecord]>; + let Documentation = [Undocumented]; + let StrictEnumParameters = 1; + let Args = [EnumArgument<"Key", "VPtrAuthKeyType", /*is_string=*/ true, + ["default_key", "no_authentication", "process_dependent", + "process_independent"], + ["DefaultKey", "NoKey", "ProcessDependent", + "ProcessIndependent"]>, + EnumArgument<"AddressDiscrimination", "AddressDiscriminationMode", + /*is_string=*/ true, + ["default_address_discrimination", "no_address_discrimination", + "address_discrimination"], + ["DefaultAddressDiscrimination", "NoAddressDiscrimination", + "AddressDiscrimination"]>, + EnumArgument<"ExtraDiscrimination", "ExtraDiscrimination", + /*is_string=*/ true, + ["default_extra_discrimination", "no_extra_discrimination", + "type_discrimination", "custom_discrimination"], + ["DefaultExtraDiscrimination", "NoExtraDiscrimination", + "TypeDiscrimination", "CustomDiscrimination"]>, + IntArgument<"CustomDiscriminationValue", 1>]; +} + def FunctionReturnThunks : InheritableAttr, TargetSpecificAttr { let Spellings = [GCC<"function_return">]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 70d5dfa8aaf868..ab4bd003541fa4 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -5672,9 +5672,10 @@ may be changed in the future. be used to pass function arguments. Floating-point registers (XMMs/YMMs) still follow the C calling convention. - On AArch64, only LR and FP are preserved by the callee. - Registers X19-X28, X0-X7, and X9-X15 are used to pass function arguments. - X8, X16-X18, SIMD and floating-point registers follow the AAPCS calling - convention. + Registers X20-X28, X0-X7, and X9-X14 are used to pass function arguments. + X8, X16-X19, SIMD and floating-point registers follow the AAPCS calling + convention. X15 is not available for argument passing on Windows, but is + used to pass arguments on other platforms. }]; } @@ -6584,7 +6585,8 @@ like pointers to an object of type ``T``: private: int *valuePointer; public: - int *getInt() { return &valuePointer; } + IntPointer(const IntOwner&); + int *getInt() { return valuePointer; } }; The argument ``T`` is optional and is ignored. @@ -6600,12 +6602,8 @@ When the Owner's lifetime ends, it will consider the Pointer to be dangling. .. code-block:: c++ int f() { - IntPointer P; - if (true) { - IntOwner O(7); - P = IntPointer(O); // P "points into" O - } // P is dangling - return P.get(); // error: Using a dangling Pointer. + IntPointer P(IntOwner{}); // P "points into" a temporary IntOwner object + P.getInt(); // P is dangling } }]; @@ -8106,3 +8104,72 @@ Attribute used by `clspv`_ (OpenCL-C to Vulkan SPIR-V compiler) to identify func .. _`libclc`: https://libclc.llvm.org }]; } + +def DocCatNonBlockingNonAllocating : DocumentationCategory<"Performance Constraint Attributes"> { + let Content = [{ +The ``nonblocking``, ``blocking``, ``nonallocating`` and ``allocating`` attributes can be attached +to function types, including blocks, C++ lambdas, and member functions. The attributes declare +constraints about a function's behavior pertaining to blocking and heap memory allocation. + +There are several rules for function types with these attributes, enforced with +compiler warnings: + +- When assigning or otherwise converting to a function pointer of ``nonblocking`` or + ``nonallocating`` type, the source must also be a function or function pointer of + that type, unless it is a null pointer, i.e. the attributes should not be "spoofed". Conversions + that remove the attributes are transparent and valid. + +- An override of a ``nonblocking`` or ``nonallocating`` virtual method must also be declared + with that same attribute (or a stronger one.) An overriding method may add an attribute. + +- A redeclaration of a ``nonblocking`` or ``nonallocating`` function must also be declared with + the same attribute (or a stronger one). A redeclaration may add an attribute. + +The warnings are controlled by ``-Wfunction-effects``, which is enabled by default. + +In a future commit, the compiler will diagnose function calls from ``nonblocking`` and ``nonallocating`` +functions to other functions which lack the appropriate attribute. + }]; +} + +def NonBlockingDocs : Documentation { + let Category = DocCatNonBlockingNonAllocating; + let Heading = "nonblocking"; + let Content = [{ +Declares that a function or function type either does or does not block in any way, according +to the optional, compile-time constant boolean argument, which defaults to true. When the argument +is false, the attribute is equivalent to ``blocking``. + +For the purposes of diagnostics, ``nonblocking`` is considered to include the +``nonallocating`` guarantee and is therefore a "stronger" constraint or attribute. + }]; +} + +def NonAllocatingDocs : Documentation { + let Category = DocCatNonBlockingNonAllocating; + let Heading = "nonallocating"; + let Content = [{ +Declares that a function or function type either does or does not allocate heap memory, according +to the optional, compile-time constant boolean argument, which defaults to true. When the argument +is false, the attribute is equivalent to ``allocating``. + }]; +} + +def BlockingDocs : Documentation { + let Category = DocCatNonBlockingNonAllocating; + let Heading = "blocking"; + let Content = [{ +Declares that a function potentially blocks, and prevents any potential inference of ``nonblocking`` +by the compiler. + }]; +} + +def AllocatingDocs : Documentation { + let Category = DocCatNonBlockingNonAllocating; + let Heading = "allocating"; + let Content = [{ +Declares that a function potentially allocates heap memory, and prevents any potential inference +of ``nonallocating`` by the compiler. + }]; +} + diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index c8f6104a7f1a7a..f5b15cf90d1f83 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -1152,6 +1152,12 @@ def Trap : Builtin { let Prototype = "void()"; } +def VerboseTrap : Builtin { + let Spellings = ["__builtin_verbose_trap"]; + let Attributes = [NoThrow, NoReturn]; + let Prototype = "void(char const*, char const*)"; +} + def Debugtrap : Builtin { let Spellings = ["__builtin_debugtrap"]; let Attributes = [NoThrow]; diff --git a/clang/include/clang/Basic/BuiltinsAMDGPU.def b/clang/include/clang/Basic/BuiltinsAMDGPU.def index a73e63355cfd73..56bba448e12a42 100644 --- a/clang/include/clang/Basic/BuiltinsAMDGPU.def +++ b/clang/include/clang/Basic/BuiltinsAMDGPU.def @@ -149,6 +149,12 @@ BUILTIN(__builtin_amdgcn_mqsad_pk_u16_u8, "WUiWUiUiWUi", "nc") BUILTIN(__builtin_amdgcn_mqsad_u32_u8, "V4UiWUiUiV4Ui", "nc") BUILTIN(__builtin_amdgcn_make_buffer_rsrc, "Qbv*sii", "nc") +BUILTIN(__builtin_amdgcn_raw_buffer_store_b8, "vcQbiiIi", "n") +BUILTIN(__builtin_amdgcn_raw_buffer_store_b16, "vsQbiiIi", "n") +BUILTIN(__builtin_amdgcn_raw_buffer_store_b32, "viQbiiIi", "n") +BUILTIN(__builtin_amdgcn_raw_buffer_store_b64, "vV2iQbiiIi", "n") +BUILTIN(__builtin_amdgcn_raw_buffer_store_b96, "vV3iQbiiIi", "n") +BUILTIN(__builtin_amdgcn_raw_buffer_store_b128, "vV4iQbiiIi", "n") //===----------------------------------------------------------------------===// // Ballot builtins. diff --git a/clang/include/clang/Basic/Cuda.h b/clang/include/clang/Basic/Cuda.h index 0d5e38e825aa78..83699f8897f663 100644 --- a/clang/include/clang/Basic/Cuda.h +++ b/clang/include/clang/Basic/Cuda.h @@ -52,7 +52,7 @@ const char *CudaVersionToString(CudaVersion V); // Input is "Major.Minor" CudaVersion CudaStringToVersion(const llvm::Twine &S); -enum class CudaArch { +enum class OffloadArch { UNUSED, UNKNOWN, // TODO: Deprecate and remove GPU architectures older than sm_52. @@ -128,12 +128,13 @@ enum class CudaArch { GFX12_GENERIC, GFX1200, GFX1201, + AMDGCNSPIRV, Generic, // A processor model named 'generic' if the target backend defines a // public one. LAST, - CudaDefault = CudaArch::SM_52, - HIPDefault = CudaArch::GFX906, + CudaDefault = OffloadArch::SM_52, + HIPDefault = OffloadArch::GFX906, }; enum class CUDAFunctionTarget { @@ -144,26 +145,26 @@ enum class CUDAFunctionTarget { InvalidTarget }; -static inline bool IsNVIDIAGpuArch(CudaArch A) { - return A >= CudaArch::SM_20 && A < CudaArch::GFX600; +static inline bool IsNVIDIAOffloadArch(OffloadArch A) { + return A >= OffloadArch::SM_20 && A < OffloadArch::GFX600; } -static inline bool IsAMDGpuArch(CudaArch A) { +static inline bool IsAMDOffloadArch(OffloadArch A) { // Generic processor model is for testing only. - return A >= CudaArch::GFX600 && A < CudaArch::Generic; + return A >= OffloadArch::GFX600 && A < OffloadArch::Generic; } -const char *CudaArchToString(CudaArch A); -const char *CudaArchToVirtualArchString(CudaArch A); +const char *OffloadArchToString(OffloadArch A); +const char *OffloadArchToVirtualArchString(OffloadArch A); // The input should have the form "sm_20". -CudaArch StringToCudaArch(llvm::StringRef S); +OffloadArch StringToOffloadArch(llvm::StringRef S); -/// Get the earliest CudaVersion that supports the given CudaArch. -CudaVersion MinVersionForCudaArch(CudaArch A); +/// Get the earliest CudaVersion that supports the given OffloadArch. +CudaVersion MinVersionForOffloadArch(OffloadArch A); -/// Get the latest CudaVersion that supports the given CudaArch. -CudaVersion MaxVersionForCudaArch(CudaArch A); +/// Get the latest CudaVersion that supports the given OffloadArch. +CudaVersion MaxVersionForOffloadArch(OffloadArch A); // Various SDK-dependent features that affect CUDA compilation enum class CudaFeature { diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 9b37d4bd3205bf..de99cb46d3145a 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1527,6 +1527,10 @@ def ReadOnlyPlacementChecks : DiagGroup<"read-only-types">; def UnsafeBufferUsageInContainer : DiagGroup<"unsafe-buffer-usage-in-container">; def UnsafeBufferUsage : DiagGroup<"unsafe-buffer-usage", [UnsafeBufferUsageInContainer]>; +// Warnings and notes related to the function effects system underlying +// the nonblocking and nonallocating attributes. +def FunctionEffects : DiagGroup<"function-effects">; + // Warnings and notes InstallAPI verification. def InstallAPIViolation : DiagGroup<"installapi-violation">; @@ -1535,3 +1539,7 @@ def BitIntExtension : DiagGroup<"bit-int-extension">; // Warnings about misuse of ExtractAPI options. def ExtractAPIMisuse : DiagGroup<"extractapi-misuse">; + +// Warnings about using the non-standard extension having an explicit specialization +// with a storage class specifier. +def ExplicitSpecializationStorageClass : DiagGroup<"explicit-specialization-storage-class">; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index d8c3fee7841f43..1160b0f7a7a5a9 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1508,6 +1508,8 @@ def err_omp_unexpected_append_op : Error< "unexpected operation specified in 'append_args' clause, expected 'interop'">; def err_omp_unexpected_execution_modifier : Error< "unexpected 'execution' modifier in non-executable context">; +def err_omp_unknown_adjust_args_op : Error< + "incorrect adjust_args type, expected 'need_device_ptr' or 'nothing'">; def err_omp_declare_variant_wrong_clause : Error< "expected %select{'match'|'match', 'adjust_args', or 'append_args'}0 clause " "on 'omp declare variant' directive">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 25a87078a57093..5dc36c594bcb7c 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -940,6 +940,13 @@ def warn_ptrauth_auth_null_pointer : def err_ptrauth_string_not_literal : Error< "argument must be a string literal%select{| of char type}0">; +def note_ptrauth_virtual_function_pointer_incomplete_arg_ret : + Note<"cannot take an address of a virtual member function if its return or " + "argument types are incomplete">; +def note_ptrauth_virtual_function_incomplete_arg_ret_type : + Note<"%0 is incomplete">; + + /// main() // static main() is not an error in C, just in C++. def warn_static_main : Warning<"'main' should not be declared static">, @@ -3246,6 +3253,9 @@ def warn_unsupported_target_attribute def err_attribute_unsupported : Error<"%0 attribute is not supported on targets missing %1;" " specify an appropriate -march= or -mcpu=">; +def err_attribute_unsupported_m_profile + : Error<"on M-profile architectures %0 attribute is not supported on targets missing %1;" + " specify an appropriate -march= or -mcpu=">; def err_duplicate_target_attribute : Error<"%select{unsupported|duplicate|unknown}0%select{| CPU|" " tune CPU}1 '%2' in the '%select{target|target_clones|target_version}3' " @@ -3272,11 +3282,23 @@ def warn_aligned_attr_underaligned : Warning, def err_attribute_sizeless_type : Error< "%0 attribute cannot be applied to sizeless type %1">; def err_attribute_argument_n_type : Error< - "%0 attribute requires parameter %1 to be %select{int or bool|an integer " - "constant|a string|an identifier|a constant expression|a builtin function}2">; + "%0 attribute requires parameter %1 to be %select{" + "int or bool" + "|an integer constant" + "|a string" + "|an identifier" + "|a constant expression" + "|a builtin function" + "|nullptr or a bool, int, or enum literal}2">; def err_attribute_argument_type : Error< - "%0 attribute requires %select{int or bool|an integer " - "constant|a string|an identifier}1">; + "%0 attribute requires %select{" + "int or bool" + "|an integer constant" + "|a string" + "|an identifier" + "|a constant expression" + "|a builtin function" + "|a pointer or a bool, int, or enum literal}1">; def err_attribute_argument_out_of_range : Error< "%0 attribute requires integer constant between %1 and %2 inclusive">; def err_init_priority_object_attr : Error< @@ -3728,7 +3750,8 @@ def warn_attribute_wrong_decl_type : Warning< "|types and namespaces" "|variables, functions and classes" "|kernel functions" - "|non-K&R-style functions}2">, + "|non-K&R-style functions" + "|functions that return bool, integer, or a pointer type}2">, InGroup; def err_attribute_wrong_decl_type : Error; def warn_type_attribute_wrong_type : Warning< @@ -5366,7 +5389,7 @@ def err_not_class_template_specialization : Error< "cannot specialize a %select{dependent template|template template " "parameter}0">; def ext_explicit_specialization_storage_class : ExtWarn< - "explicit specialization cannot have a storage class">; + "explicit specialization cannot have a storage class">, InGroup; def err_dependent_function_template_spec_no_match : Error< "no candidate function template was found for dependent" " %select{member|friend}0 function template specialization">; @@ -6075,6 +6098,9 @@ def err_thread_thread_different_kind : Error< def err_mismatched_owning_module : Error< "declaration of %0 in %select{the global module|module %2}1 follows " "declaration in %select{the global module|module %4}3">; +def err_multiple_decl_in_different_modules : Error< + "declaration %0 attached to named module '%1' can't be attached to " + "other modules">; def err_redefinition_different_type : Error< "redefinition of %0 with a different type%diff{: $ vs $|}1,2">; def err_redefinition_different_kind : Error< @@ -8937,6 +8963,8 @@ def err_expected_callable_argument : Error< "expected a callable expression as %ordinal0 argument to %1, found %2">; def note_building_builtin_dump_struct_call : Note< "in call to printing function with arguments '(%0)' while dumping struct">; +def err_builtin_verbose_trap_arg : Error< + "argument to __builtin_verbose_trap must %select{be a pointer to a constant string|not contain $}0">; def err_atomic_load_store_uses_lib : Error< "atomic %select{load|store}0 requires runtime support that is not " @@ -10881,6 +10909,23 @@ def warn_imp_cast_drops_unaligned : Warning< "implicit cast from type %0 to type %1 drops __unaligned qualifier">, InGroup>; +// Function effects +// spoofing nonblocking/nonallocating +def warn_invalid_add_func_effects : Warning< + "attribute '%0' should not be added via type conversion">, + InGroup; +def warn_mismatched_func_effect_override : Warning< + "attribute '%0' on overriding function does not match base declaration">, + InGroup; +def warn_mismatched_func_effect_redeclaration : Warning< + "attribute '%0' on function does not match previous declaration">, + InGroup; +def warn_conflicting_func_effects : Warning< + "effects conflict when merging declarations; kept '%0', discarded '%1'">, + InGroup; +def err_func_with_effects_no_prototype : Error< + "'%0' function must have a prototype">; + } // end of sema category let CategoryName = "API Notes Issue" in { @@ -11072,7 +11117,7 @@ def err_omp_loop_variable_type : Error< def err_omp_loop_incr_not_compatible : Error< "increment expression must cause %0 to %select{decrease|increase}1 " "on each iteration of OpenMP for loop">; -def note_omp_loop_cond_requres_compatible_incr : Note< +def note_omp_loop_cond_requires_compatible_incr : Note< "loop step is expected to be %select{negative|positive}0 due to this condition">; def err_omp_loop_diff_cxx : Error< "could not calculate number of iterations calling 'operator-' with " @@ -11135,16 +11180,12 @@ def err_omp_several_directives_in_region : Error< def note_omp_previous_directive : Note< "previous '%0' directive used here">; def err_omp_sections_not_compound_stmt : Error< - "the statement for '#pragma omp sections' must be a compound statement">; -def err_omp_parallel_sections_not_compound_stmt : Error< - "the statement for '#pragma omp parallel sections' must be a compound statement">; + "the statement for '#pragma omp %0' must be a compound statement">; def err_omp_orphaned_section_directive : Error< "%select{orphaned 'omp section' directives are prohibited, it|'omp section' directive}0" " must be closely nested to a sections region%select{|, not a %1 region}0">; def err_omp_sections_substmt_not_section : Error< - "statement in 'omp sections' directive must be enclosed into a section region">; -def err_omp_parallel_sections_substmt_not_section : Error< - "statement in 'omp parallel sections' directive must be enclosed into a section region">; + "statement in 'omp %0' directive must be enclosed into a section region">; def err_omp_parallel_reduction_in_task_firstprivate : Error< "argument of a reduction clause of a %0 construct must not appear in a firstprivate clause on a task construct">; def err_omp_atomic_read_not_expression_statement : Error< @@ -12182,6 +12223,30 @@ def warn_cuda_maxclusterrank_sm_90 : Warning< "maxclusterrank requires sm_90 or higher, CUDA arch provided: %0, ignoring " "%1 attribute">, InGroup; +// VTable pointer authentication errors +def err_non_polymorphic_vtable_pointer_auth : Error< + "cannot set vtable pointer authentication on monomorphic type %0">; +def err_incomplete_type_vtable_pointer_auth : Error< + "cannot set vtable pointer authentication on an incomplete type %0">; +def err_non_top_level_vtable_pointer_auth : Error< + "cannot set vtable pointer authentication on %0 which is a subclass of polymorphic type %1">; +def err_duplicated_vtable_pointer_auth : Error< + "multiple vtable pointer authentication policies on %0">; +def err_invalid_authentication_key : Error< + "invalid authentication key %0">; +def err_invalid_address_discrimination : Error< + "invalid address discrimination mode %0">; +def err_invalid_extra_discrimination : Error< + "invalid extra discrimination selection %0">; +def err_invalid_custom_discrimination : Error< + "invalid custom discrimination">; +def err_missing_custom_discrimination : Error< + "missing custom discrimination">; +def err_no_default_vtable_pointer_auth : Error< + "cannot specify a default vtable pointer authentication " + "%select{key|address discrimination mode|discriminator}0 with no default set" +>; + def err_bit_int_bad_size : Error<"%select{signed|unsigned}0 _BitInt must " "have a bit size of at least %select{2|1}0">; def err_bit_int_max_size : Error<"%select{signed|unsigned}0 _BitInt of bit " diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 75e88afbd97050..91f1c2f2e6239e 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -575,6 +575,10 @@ class LangOptions : public LangOptionsBase { // implementation on real-world examples. std::string OpenACCMacroOverride; + // Indicates if the wasm-opt binary must be ignored in the case of a + // WebAssembly target. + bool NoWasmOpt = false; + LangOptions(); /// Set language defaults for the given input language and diff --git a/clang/include/clang/Basic/OpenMPKinds.h b/clang/include/clang/Basic/OpenMPKinds.h index d127498774c7fa..29a852d6665111 100644 --- a/clang/include/clang/Basic/OpenMPKinds.h +++ b/clang/include/clang/Basic/OpenMPKinds.h @@ -368,6 +368,14 @@ bool needsTaskBasedThreadLimit(OpenMPDirectiveKind DKind); /// is restricted only to memory order clauses of "OMPC_acquire", /// "OMPC_relaxed" and "OMPC_seq_cst". bool checkFailClauseParameter(OpenMPClauseKind FailClauseParameter); + +/// Checks if the specified directive is considered as "executable". This +/// combines the OpenMP categories of "executable" and "subsidiary", plus +/// any other directives that should be treated as executable. +/// \param DKind Specified directive. +/// \return true - if the above condition is met for this directive +/// otherwise - false. +bool isOpenMPExecutableDirective(OpenMPDirectiveKind DKind); } #endif diff --git a/clang/include/clang/Basic/PointerAuthOptions.h b/clang/include/clang/Basic/PointerAuthOptions.h index aaad4a2b2b5ae6..197d63642ca6d2 100644 --- a/clang/include/clang/Basic/PointerAuthOptions.h +++ b/clang/include/clang/Basic/PointerAuthOptions.h @@ -47,6 +47,12 @@ class PointerAuthSchema { /// No additional discrimination. None, + /// Include a hash of the entity's type. + Type, + + /// Include a hash of the entity's identity. + Decl, + /// Discriminate using a constant value. Constant, }; @@ -150,6 +156,25 @@ class PointerAuthSchema { struct PointerAuthOptions { /// The ABI for C function pointers. PointerAuthSchema FunctionPointers; + + /// The ABI for C++ virtual table pointers (the pointer to the table + /// itself) as installed in an actual class instance. + PointerAuthSchema CXXVTablePointers; + + /// TypeInfo has external ABI requirements and is emitted without + /// actually having parsed the libcxx definition, so we can't simply + /// perform a look up. The settings for this should match the exact + /// specification in type_info.h + PointerAuthSchema CXXTypeInfoVTablePointer; + + /// The ABI for C++ virtual table pointers as installed in a VTT. + PointerAuthSchema CXXVTTVTablePointers; + + /// The ABI for most C++ virtual function pointers, i.e. v-table entries. + PointerAuthSchema CXXVirtualFunctionPointers; + + /// The ABI for variadic C++ virtual function pointers. + PointerAuthSchema CXXVirtualVariadicFunctionPointers; }; } // end namespace clang diff --git a/clang/include/clang/Basic/SourceManager.h b/clang/include/clang/Basic/SourceManager.h index d2e2e914327f2b..d3ccc7ef81c079 100644 --- a/clang/include/clang/Basic/SourceManager.h +++ b/clang/include/clang/Basic/SourceManager.h @@ -1981,6 +1981,7 @@ class SourceManager : public RefCountedBase { SourceLocation SpellLoc, SourceLocation ExpansionLoc, unsigned ExpansionLength) const; + void updateSlocUsageStats() const; }; /// Comparison function object. diff --git a/clang/include/clang/Basic/TargetCXXABI.h b/clang/include/clang/Basic/TargetCXXABI.h index c113a6a048ad44..d204452afbf4b3 100644 --- a/clang/include/clang/Basic/TargetCXXABI.h +++ b/clang/include/clang/Basic/TargetCXXABI.h @@ -116,7 +116,7 @@ class TargetCXXABI { return T.isKnownWindowsMSVCEnvironment(); } llvm_unreachable("invalid CXXABI kind"); - }; + } /// Does this ABI generally fall into the Itanium family of ABIs? bool isItaniumFamily() const { diff --git a/clang/include/clang/Basic/Thunk.h b/clang/include/clang/Basic/Thunk.h index 0247e279408f08..8ff7603e0094d7 100644 --- a/clang/include/clang/Basic/Thunk.h +++ b/clang/include/clang/Basic/Thunk.h @@ -21,6 +21,7 @@ namespace clang { class CXXMethodDecl; +class Type; /// A return adjustment. struct ReturnAdjustment { @@ -162,20 +163,24 @@ struct ThunkInfo { /// Holds a pointer to the overridden method this thunk is for, /// if needed by the ABI to distinguish different thunks with equal - /// adjustments. Otherwise, null. + /// adjustments. + /// In the Itanium ABI, this field can hold the method that created the + /// vtable entry for this thunk. + /// Otherwise, null. /// CAUTION: In the unlikely event you need to sort ThunkInfos, consider using /// an ABI-specific comparator. const CXXMethodDecl *Method; + const Type *ThisType; - ThunkInfo() : Method(nullptr) {} + ThunkInfo() : Method(nullptr), ThisType(nullptr) {} ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return, - const CXXMethodDecl *Method = nullptr) - : This(This), Return(Return), Method(Method) {} + const Type *ThisT, const CXXMethodDecl *Method = nullptr) + : This(This), Return(Return), Method(Method), ThisType(ThisT) {} friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) { return LHS.This == RHS.This && LHS.Return == RHS.Return && - LHS.Method == RHS.Method; + LHS.Method == RHS.Method && LHS.ThisType == RHS.ThisType; } bool isEmpty() const { diff --git a/clang/include/clang/Basic/arm_sme.td b/clang/include/clang/Basic/arm_sme.td index 564a58e4eb6709..ce211f97d1c968 100644 --- a/clang/include/clang/Basic/arm_sme.td +++ b/clang/include/clang/Basic/arm_sme.td @@ -15,11 +15,13 @@ include "arm_sve_sme_incl.td" +let SVETargetGuard = InvalidMode in { + //////////////////////////////////////////////////////////////////////////////// // Loads multiclass ZALoad ch> { - let TargetGuard = "sme" in { + let SMETargetGuard = "sme" in { def NAME # _H : MInst<"svld1_hor_" # n_suffix, "vimPQ", t, [IsLoad, IsOverloadNone, IsStreaming, IsInOutZA], MemEltTyDefault, i_prefix # "_horiz", ch>; @@ -44,7 +46,7 @@ defm SVLD1_ZA32 : ZALoad<"za32", "i", "aarch64_sme_ld1w", [ImmCheck<0, ImmCheck0 defm SVLD1_ZA64 : ZALoad<"za64", "l", "aarch64_sme_ld1d", [ImmCheck<0, ImmCheck0_7>]>; defm SVLD1_ZA128 : ZALoad<"za128", "q", "aarch64_sme_ld1q", [ImmCheck<0, ImmCheck0_15>]>; -let TargetGuard = "sme" in { +let SMETargetGuard = "sme" in { def SVLDR_VNUM_ZA : MInst<"svldr_vnum_za", "vmQl", "", [IsOverloadNone, IsStreamingCompatible, IsInOutZA], MemEltTyDefault, "aarch64_sme_ldr">; @@ -58,7 +60,7 @@ def SVLDR_ZA : MInst<"svldr_za", "vmQ", "", // Stores multiclass ZAStore ch> { - let TargetGuard = "sme" in { + let SMETargetGuard = "sme" in { def NAME # _H : MInst<"svst1_hor_" # n_suffix, "vimP%", t, [IsStore, IsOverloadNone, IsStreaming, IsInZA], MemEltTyDefault, i_prefix # "_horiz", ch>; @@ -83,7 +85,7 @@ defm SVST1_ZA32 : ZAStore<"za32", "i", "aarch64_sme_st1w", [ImmCheck<0, ImmCheck defm SVST1_ZA64 : ZAStore<"za64", "l", "aarch64_sme_st1d", [ImmCheck<0, ImmCheck0_7>]>; defm SVST1_ZA128 : ZAStore<"za128", "q", "aarch64_sme_st1q", [ImmCheck<0, ImmCheck0_15>]>; -let TargetGuard = "sme" in { +let SMETargetGuard = "sme" in { def SVSTR_VNUM_ZA : MInst<"svstr_vnum_za", "vm%l", "", [IsOverloadNone, IsStreamingCompatible, IsInZA], MemEltTyDefault, "aarch64_sme_str">; @@ -97,7 +99,7 @@ def SVSTR_ZA : MInst<"svstr_za", "vm%", "", // Read horizontal/vertical ZA slices multiclass ZARead ch> { - let TargetGuard = "sme" in { + let SMETargetGuard = "sme" in { def NAME # _H : SInst<"svread_hor_" # n_suffix # "[_{d}]", "ddPim", t, MergeOp1, i_prefix # "_horiz", [IsReadZA, IsStreaming, IsInZA], ch>; @@ -118,7 +120,7 @@ defm SVREAD_ZA128 : ZARead<"za128", "csilUcUsUiUlhbfd", "aarch64_sme_readq", [Im // Write horizontal/vertical ZA slices multiclass ZAWrite ch> { - let TargetGuard = "sme" in { + let SMETargetGuard = "sme" in { def NAME # _H : SInst<"svwrite_hor_" # n_suffix # "[_{d}]", "vimPd", t, MergeOp1, i_prefix # "_horiz", [IsWriteZA, IsStreaming, IsInOutZA], ch>; @@ -138,7 +140,7 @@ defm SVWRITE_ZA128 : ZAWrite<"za128", "csilUcUsUiUlhbfd", "aarch64_sme_writeq", //////////////////////////////////////////////////////////////////////////////// // SME - Zero -let TargetGuard = "sme" in { +let SMETargetGuard = "sme" in { def SVZERO_MASK_ZA : SInst<"svzero_mask_za", "vi", "", MergeNone, "aarch64_sme_zero", [IsOverloadNone, IsStreamingCompatible, IsInOutZA], [ImmCheck<0, ImmCheck0_255>]>; @@ -146,7 +148,7 @@ let TargetGuard = "sme" in { [IsOverloadNone, IsStreamingCompatible, IsOutZA]>; } -let TargetGuard = "sme2p1" in { +let SMETargetGuard = "sme2p1" in { def SVZERO_ZA64_VG1x2 : SInst<"svzero_za64_vg1x2", "vm", "", MergeNone, "aarch64_sme_zero_za64_vg1x2", [IsOverloadNone, IsStreaming, IsInOutZA]>; def SVZERO_ZA64_VG1x4 : SInst<"svzero_za64_vg1x4", "vm", "", MergeNone, "aarch64_sme_zero_za64_vg1x4", @@ -169,7 +171,7 @@ let TargetGuard = "sme2p1" in { // SME - Counting elements in a streaming vector multiclass ZACount { - let TargetGuard = "sme" in { + let SMETargetGuard = "sme" in { def NAME : SInst<"sv" # n_suffix, "nv", "", MergeNone, "aarch64_sme_" # n_suffix, [IsOverloadNone, IsStreamingCompatible]>; @@ -185,13 +187,13 @@ defm SVCNTSD : ZACount<"cntsd">; // SME - ADDHA/ADDVA multiclass ZAAdd { - let TargetGuard = "sme" in { + let SMETargetGuard = "sme" in { def NAME # _ZA32: SInst<"sv" # n_suffix # "_za32[_{d}]", "viPPd", "iUi", MergeOp1, "aarch64_sme_" # n_suffix, [IsStreaming, IsInOutZA], [ImmCheck<0, ImmCheck0_3>]>; } - let TargetGuard = "sme-i16i64" in { + let SMETargetGuard = "sme-i16i64" in { def NAME # _ZA64: SInst<"sv" # n_suffix # "_za64[_{d}]", "viPPd", "lUl", MergeOp1, "aarch64_sme_" # n_suffix, [IsStreaming, IsInOutZA], [ImmCheck<0, ImmCheck0_7>]>; @@ -205,7 +207,7 @@ defm SVADDVA : ZAAdd<"addva">; // SME - SMOPA, SMOPS, UMOPA, UMOPS multiclass ZAIntOuterProd { - let TargetGuard = "sme" in { + let SMETargetGuard = "sme" in { def NAME # _ZA32_B: SInst<"sv" # n_suffix2 # "_za32[_{d}]", "viPPdd", !cond(!eq(n_suffix1, "s") : "", true: "U") # "c", MergeOp1, "aarch64_sme_" # n_suffix1 # n_suffix2 # "_wide", @@ -213,7 +215,7 @@ multiclass ZAIntOuterProd { [ImmCheck<0, ImmCheck0_3>]>; } - let TargetGuard = "sme-i16i64" in { + let SMETargetGuard = "sme-i16i64" in { def NAME # _ZA64_H: SInst<"sv" # n_suffix2 # "_za64[_{d}]", "viPPdd", !cond(!eq(n_suffix1, "s") : "", true: "U") # "s", MergeOp1, "aarch64_sme_" # n_suffix1 # n_suffix2 # "_wide", @@ -231,7 +233,7 @@ defm SVUMOPS : ZAIntOuterProd<"u", "mops">; // SME - SUMOPA, SUMOPS, USMOPA, USMOPS multiclass ZAIntOuterProdMixedSigns { - let TargetGuard = "sme" in { + let SMETargetGuard = "sme" in { def NAME # _ZA32_B: SInst<"sv" # n_suffix1 # n_suffix2 # "_za32[_{d}]", "viPPd" # !cond(!eq(n_suffix1, "su") : "u", true: "x"), !cond(!eq(n_suffix1, "su") : "", true: "U") # "c", @@ -240,7 +242,7 @@ multiclass ZAIntOuterProdMixedSigns { [ImmCheck<0, ImmCheck0_3>]>; } - let TargetGuard = "sme-i16i64" in { + let SMETargetGuard = "sme-i16i64" in { def NAME # _ZA64_H: SInst<"sv" # n_suffix1 # n_suffix2 # "_za64[_{d}]", "viPPd" # !cond(!eq(n_suffix1, "su") : "u", true: "x"), !cond(!eq(n_suffix1, "su") : "", true: "U") # "s", @@ -259,7 +261,7 @@ defm SVUSMOPS : ZAIntOuterProdMixedSigns<"us", "mops">; // SME - FMOPA, FMOPS multiclass ZAFPOuterProd { - let TargetGuard = "sme" in { + let SMETargetGuard = "sme" in { def NAME # _ZA32_B: SInst<"sv" # n_suffix # "_za32[_{d}]", "viPPdd", "h", MergeOp1, "aarch64_sme_" # n_suffix # "_wide", [IsStreaming, IsInOutZA], @@ -276,7 +278,7 @@ multiclass ZAFPOuterProd { [ImmCheck<0, ImmCheck0_3>]>; } - let TargetGuard = "sme-f64f64" in { + let SMETargetGuard = "sme-f64f64" in { def NAME # _ZA64_D: SInst<"sv" # n_suffix # "_za64[_{d}]", "viPPdd", "d", MergeOp1, "aarch64_sme_" # n_suffix, [IsStreaming, IsInOutZA], @@ -291,7 +293,7 @@ defm SVMOPS : ZAFPOuterProd<"mops">; // SME2 - ADD, SUB multiclass ZAAddSub { - let TargetGuard = "sme2" in { + let SMETargetGuard = "sme2" in { def NAME # _WRITE_SINGLE_ZA32_VG1X2_I32 : Inst<"sv" # n_suffix # "_write[_single]_za32[_{d}]_vg1x2", "vm2d", "iUi", MergeNone, "aarch64_sme_" # n_suffix # "_write_single_za_vg1x2", [IsStreaming, IsInOutZA], []>; def NAME # _WRITE_SINGLE_ZA32_VG1X4_I32 : Inst<"sv" # n_suffix # "_write[_single]_za32[_{d}]_vg1x4", "vm4d", "iUi", MergeNone, "aarch64_sme_" # n_suffix # "_write_single_za_vg1x4", [IsStreaming, IsInOutZA], []>; @@ -302,7 +304,7 @@ multiclass ZAAddSub { def NAME # _ZA32_VG1X4_I32 : Inst<"sv" # n_suffix # "_za32[_{d}]_vg1x4", "vm4", "iUif", MergeNone, "aarch64_sme_" # n_suffix # "_za32_vg1x4", [IsStreaming, IsInOutZA], []>; } - let TargetGuard = "sme2,sme-i16i64" in { + let SMETargetGuard = "sme2,sme-i16i64" in { def NAME # _WRITE_SINGLE_ZA64_VG1X2_I64 : Inst<"sv" # n_suffix # "_write[_single]_za64[_{d}]_vg1x2", "vm2d", "lUl", MergeNone, "aarch64_sme_" # n_suffix # "_write_single_za_vg1x2", [IsStreaming, IsInOutZA], []>; def NAME # _WRITE_SINGLE_ZA64_VG1X4_I64 : Inst<"sv" # n_suffix # "_write[_single]_za64[_{d}]_vg1x4", "vm4d", "lUl", MergeNone, "aarch64_sme_" # n_suffix # "_write_single_za_vg1x4", [IsStreaming, IsInOutZA], []>; @@ -313,17 +315,17 @@ multiclass ZAAddSub { def NAME # _ZA64_VG1X4_I64 : Inst<"sv" # n_suffix # "_za64[_{d}]_vg1x4", "vm4", "lUl", MergeNone, "aarch64_sme_" # n_suffix # "_za64_vg1x4", [IsStreaming, IsInOutZA], []>; } - let TargetGuard = "sme2,sme-f64f64" in { + let SMETargetGuard = "sme2,sme-f64f64" in { def NAME # _ZA64_VG1X2_F64 : Inst<"sv" # n_suffix # "_za64[_{d}]_vg1x2", "vm2", "d", MergeNone, "aarch64_sme_" # n_suffix # "_za64_vg1x2", [IsStreaming, IsInOutZA], []>; def NAME # _ZA64_VG1X4_F64 : Inst<"sv" # n_suffix # "_za64[_{d}]_vg1x4", "vm4", "d", MergeNone, "aarch64_sme_" # n_suffix # "_za64_vg1x4", [IsStreaming, IsInOutZA], []>; } - let TargetGuard = "sme-f16f16|sme-f8f16" in { + let SMETargetGuard = "sme-f16f16|sme-f8f16" in { def NAME # _ZA16_VG1X2_F16 : Inst<"sv" # n_suffix # "_za16[_{d}]_vg1x2", "vm2", "h", MergeNone, "aarch64_sme_" # n_suffix # "_za16_vg1x2", [IsStreaming, IsInOutZA], []>; def NAME # _ZA16_VG1X4_F16 : Inst<"sv" # n_suffix # "_za16[_{d}]_vg1x4", "vm4", "h", MergeNone, "aarch64_sme_" # n_suffix # "_za16_vg1x4", [IsStreaming, IsInOutZA], []>; } - let TargetGuard = "sme2,b16b16" in { + let SMETargetGuard = "sme2,b16b16" in { def NAME # _ZA16_VG1X2_BF16 : Inst<"sv" # n_suffix # "_za16[_{d}]_vg1x2", "vm2", "b", MergeNone, "aarch64_sme_" # n_suffix # "_za16_vg1x2", [IsStreaming, IsInOutZA], []>; def NAME # _ZA16_VG1X4_BF16 : Inst<"sv" # n_suffix # "_za16[_{d}]_vg1x4", "vm4", "b", MergeNone, "aarch64_sme_" # n_suffix # "_za16_vg1x4", [IsStreaming, IsInOutZA], []>; } @@ -347,7 +349,7 @@ multiclass ZAWrite_VG checks> { def NAME # _VG1x4 : Inst<"svwrite_" # n # "[_{d}]_vg1x4", "vm4", t, MergeNone, i # "_vg1x4", [IsInOutZA, IsStreaming], []>; } -let TargetGuard = "sme2" in { +let SMETargetGuard = "sme2" in { defm SVWRITE_ZA8 : ZAWrite_VG<"za8", "cUc", "aarch64_sme_write", [ImmCheck<0, ImmCheck0_0>]>; defm SVWRITE_ZA16 : ZAWrite_VG<"za16", "sUshb", "aarch64_sme_write", [ImmCheck<0, ImmCheck0_1>]>; defm SVWRITE_ZA32 : ZAWrite_VG<"za32", "iUif", "aarch64_sme_write", [ImmCheck<0, ImmCheck0_3>]>; @@ -363,7 +365,7 @@ multiclass ZARead_VG checks> { def NAME # _VG1x4 : Inst<"svread_" # n # "_{d}_vg1x4", "4m", t, MergeNone, i # "_vg1x4", [IsInZA, IsStreaming], []>; } -let TargetGuard = "sme2" in { +let SMETargetGuard = "sme2" in { defm SVREAD_ZA8 : ZARead_VG<"za8", "cUc", "aarch64_sme_read", [ImmCheck<0, ImmCheck0_0>]>; defm SVREAD_ZA16 : ZARead_VG<"za16", "sUshb", "aarch64_sme_read", [ImmCheck<0, ImmCheck0_1>]>; defm SVREAD_ZA32 : ZARead_VG<"za32", "iUif", "aarch64_sme_read", [ImmCheck<0, ImmCheck0_3>]>; @@ -374,7 +376,7 @@ let TargetGuard = "sme2" in { // Outer product and accumulate/subtract // -let TargetGuard = "sme2" in { +let SMETargetGuard = "sme2" in { def SVSMOPA : Inst<"svmopa_za32[_{d}]_m", "viPPdd", "s", MergeNone, "aarch64_sme_smopa_za32", [IsInOutZA, IsStreaming], [ImmCheck<0, ImmCheck0_3>]>; def SVUSMOPA : Inst<"svmopa_za32[_{d}]_m", "viPPdd", "Us", MergeNone, "aarch64_sme_umopa_za32", [IsInOutZA, IsStreaming], [ImmCheck<0, ImmCheck0_3>]>; @@ -434,7 +436,7 @@ let TargetGuard = "sme2" in { def SVDOT_LANE_ZA32_VG1x4_F16 : Inst<"svdot_lane_za32[_{d}]_vg1x4", "vm4di", "bh", MergeNone, "aarch64_sme_fdot_lane_za32_vg1x4", [IsStreaming, IsInOutZA], [ImmCheck<3, ImmCheck0_3>]>; } -let TargetGuard = "sme2,sme-i16i64" in { +let SMETargetGuard = "sme2,sme-i16i64" in { def SVVDOT_LANE_ZA64_VG1x4_S : Inst<"svvdot_lane_za64[_{d}]_vg1x4", "vm4di", "s", MergeNone, "aarch64_sme_svdot_lane_za64_vg1x4", [IsStreaming, IsInOutZA], [ImmCheck<3, ImmCheck0_1>]>; def SVVDOT_LANE_ZA64_VG1x4_U : Inst<"svvdot_lane_za64[_{d}]_vg1x4", "vm4di", "Us", MergeNone, "aarch64_sme_uvdot_lane_za64_vg1x4", [IsStreaming, IsInOutZA], [ImmCheck<3, ImmCheck0_1>]>; @@ -453,7 +455,7 @@ let TargetGuard = "sme2,sme-i16i64" in { } // FMLA/FMLS -let TargetGuard = "sme2" in { +let SMETargetGuard = "sme2" in { def SVMLA_MULTI_VG1x2_F32 : Inst<"svmla_za32[_{d}]_vg1x2", "vm22", "f", MergeNone, "aarch64_sme_fmla_vg1x2", [IsStreaming, IsInOutZA], []>; def SVMLA_MULTI_VG1x4_F32 : Inst<"svmla_za32[_{d}]_vg1x4", "vm44", "f", MergeNone, "aarch64_sme_fmla_vg1x4", [IsStreaming, IsInOutZA], []>; def SVMLS_MULTI_VG1x2_F32 : Inst<"svmls_za32[_{d}]_vg1x2", "vm22", "f", MergeNone, "aarch64_sme_fmls_vg1x2", [IsStreaming, IsInOutZA], []>; @@ -470,7 +472,7 @@ let TargetGuard = "sme2" in { def SVMLS_LANE_VG1x4_F32 : Inst<"svmls_lane_za32[_{d}]_vg1x4", "vm4di", "f", MergeNone, "aarch64_sme_fmls_lane_vg1x4", [IsStreaming, IsInOutZA], [ImmCheck<3, ImmCheck0_3>]>; } -let TargetGuard = "sme2,sme-f64f64" in { +let SMETargetGuard = "sme2,sme-f64f64" in { def SVMLA_MULTI_VG1x2_F64 : Inst<"svmla_za64[_{d}]_vg1x2", "vm22", "d", MergeNone, "aarch64_sme_fmla_vg1x2", [IsStreaming, IsInOutZA], []>; def SVMLA_MULTI_VG1x4_F64 : Inst<"svmla_za64[_{d}]_vg1x4", "vm44", "d", MergeNone, "aarch64_sme_fmla_vg1x4", [IsStreaming, IsInOutZA], []>; def SVMLS_MULTI_VG1x2_F64 : Inst<"svmls_za64[_{d}]_vg1x2", "vm22", "d", MergeNone, "aarch64_sme_fmls_vg1x2", [IsStreaming, IsInOutZA], []>; @@ -487,7 +489,7 @@ let TargetGuard = "sme2,sme-f64f64" in { def SVMLS_LANE_VG1x4_F64 : Inst<"svmls_lane_za64[_{d}]_vg1x4", "vm4di", "d", MergeNone, "aarch64_sme_fmls_lane_vg1x4", [IsStreaming, IsInOutZA], [ImmCheck<3, ImmCheck0_1>]>; } -let TargetGuard = "sme-f16f16" in { +let SMETargetGuard = "sme-f16f16" in { def SVMLA_MULTI_VG1x2_F16 : Inst<"svmla_za16[_f16]_vg1x2", "vm22", "h", MergeNone, "aarch64_sme_fmla_vg1x2", [IsStreaming, IsInOutZA], []>; def SVMLA_MULTI_VG1x4_F16 : Inst<"svmla_za16[_f16]_vg1x4", "vm44", "h", MergeNone, "aarch64_sme_fmla_vg1x4", [IsStreaming, IsInOutZA], []>; def SVMLS_MULTI_VG1x2_F16 : Inst<"svmls_za16[_f16]_vg1x2", "vm22", "h", MergeNone, "aarch64_sme_fmls_vg1x2", [IsStreaming, IsInOutZA], []>; @@ -504,7 +506,7 @@ let TargetGuard = "sme-f16f16" in { def SVMLS_LANE_VG1x4_F16 : Inst<"svmls_lane_za16[_f16]_vg1x4", "vm4di", "h", MergeNone, "aarch64_sme_fmls_lane_vg1x4", [IsStreaming, IsInOutZA], [ImmCheck<3, ImmCheck0_7>]>; } -let TargetGuard = "sme2,b16b16" in { +let SMETargetGuard = "sme2,b16b16" in { def SVMLA_MULTI_VG1x2_BF16 : Inst<"svmla_za16[_bf16]_vg1x2", "vm22", "b", MergeNone, "aarch64_sme_fmla_vg1x2", [IsStreaming, IsInOutZA], []>; def SVMLA_MULTI_VG1x4_BF16 : Inst<"svmla_za16[_bf16]_vg1x4", "vm44", "b", MergeNone, "aarch64_sme_fmla_vg1x4", [IsStreaming, IsInOutZA], []>; def SVMLS_MULTI_VG1x2_BF16 : Inst<"svmls_za16[_bf16]_vg1x2", "vm22", "b", MergeNone, "aarch64_sme_fmls_vg1x2", [IsStreaming, IsInOutZA], []>; @@ -523,7 +525,7 @@ let TargetGuard = "sme2,b16b16" in { // FMLAL/FMLSL/UMLAL/SMLAL // SMLALL/UMLALL/USMLALL/SUMLALL -let TargetGuard = "sme2" in { +let SMETargetGuard = "sme2" in { // MULTI MLAL def SVMLAL_MULTI_VG2x2_F16 : Inst<"svmla_za32[_{d}]_vg2x2", "vm22", "bh", MergeNone, "aarch64_sme_fmlal_vg2x2", [IsStreaming, IsInOutZA], []>; def SVMLAL_MULTI_VG2x4_F16 : Inst<"svmla_za32[_{d}]_vg2x4", "vm44", "bh", MergeNone, "aarch64_sme_fmlal_vg2x4", [IsStreaming, IsInOutZA], []>; @@ -653,7 +655,7 @@ let TargetGuard = "sme2" in { def SVUSMLALL_LANE_VG4x4 : Inst<"svusmla_lane_za32[_{d}]_vg4x4", "vm4xi", "Uc", MergeNone, "aarch64_sme_usmla_za32_lane_vg4x4", [IsStreaming, IsInOutZA], [ImmCheck<3, ImmCheck0_15>]>; } -let TargetGuard = "sme2,sme-i16i64" in { +let SMETargetGuard = "sme2,sme-i16i64" in { // MULTI MLAL def SVMLAL_MULTI_VG4x2_S16 : Inst<"svmla_za64[_{d}]_vg4x2", "vm22", "s", MergeNone, "aarch64_sme_smla_za64_vg4x2", [IsStreaming, IsInOutZA], []>; def SVMLAL_MULTI_VG4x2_U16 : Inst<"svmla_za64[_{d}]_vg4x2", "vm22", "Us", MergeNone, "aarch64_sme_umla_za64_vg4x2", [IsStreaming, IsInOutZA], []>; @@ -702,7 +704,7 @@ let TargetGuard = "sme2,sme-i16i64" in { // // Spill and fill of ZT0 // -let TargetGuard = "sme2" in { +let SMETargetGuard = "sme2" in { def SVLDR_ZT : Inst<"svldr_zt", "viQ", "", MergeNone, "aarch64_sme_ldr_zt", [IsOverloadNone, IsStreamingCompatible, IsInOutZT0], [ImmCheck<0, ImmCheck0_0>]>; def SVSTR_ZT : Inst<"svstr_zt", "vi%", "", MergeNone, "aarch64_sme_str_zt", [IsOverloadNone, IsStreamingCompatible, IsInZT0], [ImmCheck<0, ImmCheck0_0>]>; } @@ -710,14 +712,14 @@ let TargetGuard = "sme2" in { // // Zero ZT0 // -let TargetGuard = "sme2" in { +let SMETargetGuard = "sme2" in { def SVZERO_ZT : Inst<"svzero_zt", "vi", "", MergeNone, "aarch64_sme_zero_zt", [IsOverloadNone, IsStreamingCompatible, IsOutZT0], [ImmCheck<0, ImmCheck0_0>]>; } // // lookup table expand four contiguous registers // -let TargetGuard = "sme2" in { +let SMETargetGuard = "sme2" in { def SVLUTI2_LANE_ZT_X4 : Inst<"svluti2_lane_zt_{d}_x4", "4.di[i", "cUcsUsiUibhf", MergeNone, "aarch64_sme_luti2_lane_zt_x4", [IsStreaming, IsInZT0], [ImmCheck<0, ImmCheck0_0>, ImmCheck<2, ImmCheck0_3>]>; def SVLUTI4_LANE_ZT_X4 : Inst<"svluti4_lane_zt_{d}_x4", "4.di[i", "sUsiUibhf", MergeNone, "aarch64_sme_luti4_lane_zt_x4", [IsStreaming, IsInZT0], [ImmCheck<0, ImmCheck0_0>, ImmCheck<2, ImmCheck0_1>]>; } @@ -725,7 +727,7 @@ let TargetGuard = "sme2" in { // // lookup table expand one register // -let TargetGuard = "sme2" in { +let SMETargetGuard = "sme2" in { def SVLUTI2_LANE_ZT : Inst<"svluti2_lane_zt_{d}", "di[i", "cUcsUsiUibhf", 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", "cUcsUsiUibhf", MergeNone, "aarch64_sme_luti4_lane_zt", [IsStreaming, IsInZT0], [ImmCheck<0, ImmCheck0_0>, ImmCheck<2, ImmCheck0_7>]>; } @@ -733,14 +735,14 @@ let TargetGuard = "sme2" in { // // lookup table expand two contiguous registers // -let TargetGuard = "sme2" in { +let SMETargetGuard = "sme2" in { def SVLUTI2_LANE_ZT_X2 : Inst<"svluti2_lane_zt_{d}_x2", "2.di[i", "cUcsUsiUibhf", 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", "cUcsUsiUibhf", MergeNone, "aarch64_sme_luti4_lane_zt_x2", [IsStreaming, IsInZT0], [ImmCheck<0, ImmCheck0_0>, ImmCheck<2, ImmCheck0_3>]>; } //////////////////////////////////////////////////////////////////////////////// // SME2p1 - FMOPA, FMOPS (non-widening) -let TargetGuard = "sme2,b16b16" in { +let SMETargetGuard = "sme2,b16b16" in { def SVMOPA_BF16_NW : SInst<"svmopa_za16[_bf16]_m", "viPPdd", "b", MergeNone, "aarch64_sme_mopa", [IsStreaming, IsInOutZA], @@ -751,7 +753,7 @@ let TargetGuard = "sme2,b16b16" in { [ImmCheck<0, ImmCheck0_1>]>; } -let TargetGuard = "sme-f16f16" in { +let SMETargetGuard = "sme-f16f16" in { def SVMOPA_F16_NW : SInst<"svmopa_za16[_f16]_m", "viPPdd", "h", MergeNone, "aarch64_sme_mopa", [IsStreaming, IsInOutZA], @@ -761,3 +763,46 @@ let TargetGuard = "sme-f16f16" in { [IsStreaming, IsInOutZA], [ImmCheck<0, ImmCheck0_1>]>; } + + +multiclass ZAReadz ch> { + let SMETargetGuard = "sme2p1" in { + def NAME # _H : SInst<"svreadz_hor_" # n_suffix # "_{d}_vg" # vg_num, vg_num # "im", t, + MergeNone, i_prefix # "_horiz_x" # vg_num, + [IsStreaming, IsInOutZA], ch>; + + def NAME # _V : SInst<"svreadz_ver_" # n_suffix # "_{d}_vg" # vg_num, vg_num # "im", t, + MergeNone, i_prefix # "_vert_x" #vg_num, + [IsStreaming, IsInOutZA], ch>; + } +} + +defm SVREADZ_ZA8_X2 : ZAReadz<"za8", "2", "cUc", "aarch64_sme_readz", [ImmCheck<0, ImmCheck0_0>]>; +defm SVREADZ_ZA16_X2 : ZAReadz<"za16", "2", "sUshb", "aarch64_sme_readz", [ImmCheck<0, ImmCheck0_1>]>; +defm SVREADZ_ZA32_X2 : ZAReadz<"za32", "2", "iUif", "aarch64_sme_readz", [ImmCheck<0, ImmCheck0_3>]>; +defm SVREADZ_ZA64_X2 : ZAReadz<"za64", "2", "lUld", "aarch64_sme_readz", [ImmCheck<0, ImmCheck0_7>]>; + +defm SVREADZ_ZA8_X4 : ZAReadz<"za8", "4", "cUc", "aarch64_sme_readz", [ImmCheck<0, ImmCheck0_0>]>; +defm SVREADZ_ZA16_X4 : ZAReadz<"za16", "4", "sUshb", "aarch64_sme_readz", [ImmCheck<0, ImmCheck0_1>]>; +defm SVREADZ_ZA32_X4 : ZAReadz<"za32", "4", "iUif", "aarch64_sme_readz", [ImmCheck<0, ImmCheck0_3>]>; +defm SVREADZ_ZA64_X4 : ZAReadz<"za64", "4", "lUld", "aarch64_sme_readz", [ImmCheck<0, ImmCheck0_7>]>; + + +multiclass ZAReadzSingle ch> { + let SMETargetGuard = "sme2p1" in { + def NAME # _H : SInst<"svreadz_hor_" # n_suffix # "_{d}", "dim", t, + MergeNone, i_prefix # "_horiz", + [IsStreaming, IsInOutZA], ch>; + + def NAME # _V : SInst<"svreadz_ver_" # n_suffix # "_{d}", "dim", t, + MergeNone, i_prefix # "_vert", + [IsStreaming, IsInOutZA], ch>; + } +} + +defm SVREADZ_ZA8 : ZAReadzSingle<"za8", "cUc", "aarch64_sme_readz", [ImmCheck<0, ImmCheck0_0>]>; +defm SVREADZ_ZA16 : ZAReadzSingle<"za16", "sUshb", "aarch64_sme_readz", [ImmCheck<0, ImmCheck0_1>]>; +defm SVREADZ_ZA32 : ZAReadzSingle<"za32", "iUif", "aarch64_sme_readz", [ImmCheck<0, ImmCheck0_3>]>; +defm SVREADZ_ZA64 : ZAReadzSingle<"za64", "lUld", "aarch64_sme_readz", [ImmCheck<0, ImmCheck0_7>]>; +defm SVREADZ_ZA128 : ZAReadzSingle<"za128", "csilUcUiUsUlbhfd", "aarch64_sme_readz_q", [ImmCheck<0, ImmCheck0_15>]>; +} // let SVETargetGuard = InvalidMode diff --git a/clang/include/clang/Basic/arm_sve.td b/clang/include/clang/Basic/arm_sve.td index 4a3f92520ba74f..94c093d8911562 100644 --- a/clang/include/clang/Basic/arm_sve.td +++ b/clang/include/clang/Basic/arm_sve.td @@ -27,7 +27,7 @@ def SVLD1UH : MInst<"svld1uh_{d}", "dPX", "ilUiUl", [IsLoad, IsZExtRetu def SVLD1SW : MInst<"svld1sw_{d}", "dPU", "lUl", [IsLoad, VerifyRuntimeMode], MemEltTyInt32, "aarch64_sve_ld1">; def SVLD1UW : MInst<"svld1uw_{d}", "dPY", "lUl", [IsLoad, IsZExtReturn, VerifyRuntimeMode], MemEltTyInt32, "aarch64_sve_ld1">; -let TargetGuard = "(sve|sme),bf16" in { +let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in { def SVLD1_BF : MInst<"svld1[_{2}]", "dPc", "b", [IsLoad, VerifyRuntimeMode], MemEltTyDefault, "aarch64_sve_ld1">; def SVLD1_VNUM_BF : MInst<"svld1_vnum[_{2}]", "dPcl", "b", [IsLoad, VerifyRuntimeMode], MemEltTyDefault, "aarch64_sve_ld1">; } @@ -41,7 +41,7 @@ def SVLD1UH_VNUM : MInst<"svld1uh_vnum_{d}", "dPXl", "ilUiUl", [IsLoad, def SVLD1SW_VNUM : MInst<"svld1sw_vnum_{d}", "dPUl", "lUl", [IsLoad, VerifyRuntimeMode], MemEltTyInt32, "aarch64_sve_ld1">; def SVLD1UW_VNUM : MInst<"svld1uw_vnum_{d}", "dPYl", "lUl", [IsLoad, IsZExtReturn, VerifyRuntimeMode], MemEltTyInt32, "aarch64_sve_ld1">; -let TargetGuard = "sve" in { +let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in { // Load one vector (vector base) def SVLD1_GATHER_BASES_U : MInst<"svld1_gather[_{2}base]_{d}", "dPu", "ilUiUlfd", [IsGatherLoad], MemEltTyDefault, "aarch64_sve_ld1_gather_scalar_offset">; def SVLD1SB_GATHER_BASES_U : MInst<"svld1sb_gather[_{2}base]_{d}", "dPu", "ilUiUl", [IsGatherLoad], MemEltTyInt8, "aarch64_sve_ld1_gather_scalar_offset">; @@ -137,14 +137,14 @@ def SVLDFF1SH_VNUM : MInst<"svldff1sh_vnum_{d}", "dPTl", "ilUiUl", [IsL def SVLDFF1UH_VNUM : MInst<"svldff1uh_vnum_{d}", "dPXl", "ilUiUl", [IsLoad, IsZExtReturn], MemEltTyInt16, "aarch64_sve_ldff1">; def SVLDFF1SW_VNUM : MInst<"svldff1sw_vnum_{d}", "dPUl", "lUl", [IsLoad], MemEltTyInt32, "aarch64_sve_ldff1">; def SVLDFF1UW_VNUM : MInst<"svldff1uw_vnum_{d}", "dPYl", "lUl", [IsLoad, IsZExtReturn], MemEltTyInt32, "aarch64_sve_ldff1">; -} // let TargetGuard = "sve" +} // let SVETargetGuard = "sve", SMETargetGuard = InvalidMode -let TargetGuard = "sve,bf16" in { +let SVETargetGuard = "sve,bf16", SMETargetGuard = InvalidMode in { def SVLDFF1_BF : MInst<"svldff1[_{2}]", "dPc", "b", [IsLoad], MemEltTyDefault, "aarch64_sve_ldff1">; def SVLDFF1_VNUM_BF : MInst<"svldff1_vnum[_{2}]", "dPcl", "b", [IsLoad], MemEltTyDefault, "aarch64_sve_ldff1">; } -let TargetGuard = "sve" in { +let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in { // First-faulting load one vector (vector base) def SVLDFF1_GATHER_BASES_U : MInst<"svldff1_gather[_{2}base]_{d}", "dPu", "ilUiUlfd", [IsGatherLoad], MemEltTyDefault, "aarch64_sve_ldff1_gather_scalar_offset">; def SVLDFF1SB_GATHER_BASES_U : MInst<"svldff1sb_gather[_{2}base]_{d}", "dPu", "ilUiUl", [IsGatherLoad], MemEltTyInt8, "aarch64_sve_ldff1_gather_scalar_offset">; @@ -239,9 +239,9 @@ def SVLDNF1SH_VNUM : MInst<"svldnf1sh_vnum_{d}", "dPTl", "ilUiUl", [IsL def SVLDNF1UH_VNUM : MInst<"svldnf1uh_vnum_{d}", "dPXl", "ilUiUl", [IsLoad, IsZExtReturn], MemEltTyInt16, "aarch64_sve_ldnf1">; def SVLDNF1SW_VNUM : MInst<"svldnf1sw_vnum_{d}", "dPUl", "lUl", [IsLoad], MemEltTyInt32, "aarch64_sve_ldnf1">; def SVLDNF1UW_VNUM : MInst<"svldnf1uw_vnum_{d}", "dPYl", "lUl", [IsLoad, IsZExtReturn], MemEltTyInt32, "aarch64_sve_ldnf1">; -} // let TargetGuard = "sve" +} // let SVETargetGuard = "sve", SMETargetGuard = InvalidMode -let TargetGuard = "sve,bf16" in { +let SVETargetGuard = "sve,bf16", SMETargetGuard = InvalidMode in { def SVLDNF1_BF : MInst<"svldnf1[_{2}]", "dPc", "b", [IsLoad], MemEltTyDefault, "aarch64_sve_ldnf1">; def SVLDNF1_VNUM_BF : MInst<"svldnf1_vnum[_{2}]", "dPcl", "b", [IsLoad], MemEltTyDefault, "aarch64_sve_ldnf1">; } @@ -252,7 +252,7 @@ def SVLDNT1 : MInst<"svldnt1[_{2}]", "dPc", "csilUcUsUiUlhfd", [IsLoad, VerifyRu // Load one vector, unextended load, non-temporal (scalar base, VL displacement) def SVLDNT1_VNUM : MInst<"svldnt1_vnum[_{2}]", "dPcl", "csilUcUsUiUlhfd", [IsLoad, VerifyRuntimeMode], MemEltTyDefault, "aarch64_sve_ldnt1">; -let TargetGuard = "(sve|sme),bf16" in { +let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in { def SVLDNT1_BF : MInst<"svldnt1[_{2}]", "dPc", "b", [IsLoad, VerifyRuntimeMode], MemEltTyDefault, "aarch64_sve_ldnt1">; def SVLDNT1_VNUM_BF : MInst<"svldnt1_vnum[_{2}]", "dPcl", "b", [IsLoad, VerifyRuntimeMode], MemEltTyDefault, "aarch64_sve_ldnt1">; } @@ -260,13 +260,13 @@ let TargetGuard = "(sve|sme),bf16" in { // Load one quadword and replicate (scalar base) def SVLD1RQ : SInst<"svld1rq[_{2}]", "dPc", "csilUcUsUiUlhfd", MergeNone, "aarch64_sve_ld1rq", [VerifyRuntimeMode]>; -let TargetGuard = "(sve|sme),bf16" in { +let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in { def SVLD1RQ_BF : SInst<"svld1rq[_{2}]", "dPc", "b", MergeNone, "aarch64_sve_ld1rq", [VerifyRuntimeMode]>; } multiclass StructLoad { def : SInst; - let TargetGuard = "(sve|sme),bf16" in { + let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in { def: SInst; } } @@ -282,18 +282,18 @@ defm SVLD3_VNUM : StructLoad<"svld3_vnum[_{2}]", "3Pcl", "aarch64_sve_ld3_sret"> defm SVLD4_VNUM : StructLoad<"svld4_vnum[_{2}]", "4Pcl", "aarch64_sve_ld4_sret">; // Load one octoword and replicate (scalar base) -let TargetGuard = "sve,f64mm" in { +let SVETargetGuard = "sve,f64mm", SMETargetGuard = InvalidMode in { def SVLD1RO : SInst<"svld1ro[_{2}]", "dPc", "csilUcUsUiUlhfd", MergeNone, "aarch64_sve_ld1ro">; } -let TargetGuard = "sve,f64mm,bf16" in { +let SVETargetGuard = "sve,f64mm,bf16", SMETargetGuard = InvalidMode in { def SVLD1RO_BF16 : SInst<"svld1ro[_{2}]", "dPc", "b", MergeNone, "aarch64_sve_ld1ro">; } -let TargetGuard = "sve,bf16" in { +let SVETargetGuard = "sve,bf16", SMETargetGuard = InvalidMode in { def SVBFMMLA : SInst<"svbfmmla[_{0}]", "MMdd", "b", MergeNone, "aarch64_sve_bfmmla", [IsOverloadNone]>; } -let TargetGuard = "(sve|sme),bf16" in { +let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in { def SVBFDOT : SInst<"svbfdot[_{0}]", "MMdd", "b", MergeNone, "aarch64_sve_bfdot", [IsOverloadNone, VerifyRuntimeMode]>; def SVBFMLALB : SInst<"svbfmlalb[_{0}]", "MMdd", "b", MergeNone, "aarch64_sve_bfmlalb", [IsOverloadNone, VerifyRuntimeMode]>; def SVBFMLALT : SInst<"svbfmlalt[_{0}]", "MMdd", "b", MergeNone, "aarch64_sve_bfmlalt", [IsOverloadNone, VerifyRuntimeMode]>; @@ -303,9 +303,9 @@ let TargetGuard = "(sve|sme),bf16" in { def SVBFDOT_LANE : SInst<"svbfdot_lane[_{0}]", "MMddi", "b", MergeNone, "aarch64_sve_bfdot_lane_v2", [IsOverloadNone, VerifyRuntimeMode], [ImmCheck<3, ImmCheck0_3>]>; def SVBFMLALB_LANE : SInst<"svbfmlalb_lane[_{0}]", "MMddi", "b", MergeNone, "aarch64_sve_bfmlalb_lane_v2", [IsOverloadNone, VerifyRuntimeMode], [ImmCheck<3, ImmCheck0_7>]>; def SVBFMLALT_LANE : SInst<"svbfmlalt_lane[_{0}]", "MMddi", "b", MergeNone, "aarch64_sve_bfmlalt_lane_v2", [IsOverloadNone, VerifyRuntimeMode], [ImmCheck<3, ImmCheck0_7>]>; -} // let TargetGuard = "(sve|sme),bf16" +} // let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" -let TargetGuard = "sve2p1" in { +let SVETargetGuard = "sve2p1", SMETargetGuard = InvalidMode in { // Contiguous zero-extending load to quadword (single vector). def SVLD1UWQ : MInst<"svld1uwq[_{d}]", "dPc", "iUif", [IsLoad], MemEltTyInt32, "aarch64_sve_ld1uwq">; def SVLD1UWQ_VNUM : MInst<"svld1uwq_vnum[_{d}]", "dPcl", "iUif", [IsLoad], MemEltTyInt32, "aarch64_sve_ld1uwq">; @@ -358,12 +358,12 @@ def SVST1H_VNUM_U : MInst<"svst1h_vnum[_{d}]", "vPFld", "UiUl", [IsSt def SVST1W_VNUM_S : MInst<"svst1w_vnum[_{d}]", "vPCld", "l", [IsStore, VerifyRuntimeMode], MemEltTyInt32, "aarch64_sve_st1">; def SVST1W_VNUM_U : MInst<"svst1w_vnum[_{d}]", "vPGld", "Ul", [IsStore, VerifyRuntimeMode], MemEltTyInt32, "aarch64_sve_st1">; -let TargetGuard = "(sve|sme),bf16" in { +let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in { def SVST1_BF : MInst<"svst1[_{d}]", "vPpd", "b", [IsStore, VerifyRuntimeMode], MemEltTyDefault, "aarch64_sve_st1">; def SVST1_VNUM_BF : MInst<"svst1_vnum[_{d}]", "vPpld", "b", [IsStore, VerifyRuntimeMode], MemEltTyDefault, "aarch64_sve_st1">; } -let TargetGuard = "sve" in { +let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in { // Store one vector (vector base) def SVST1_SCATTER_BASES_U : MInst<"svst1_scatter[_{2}base_{d}]", "vPud", "ilUiUlfd", [IsScatterStore], MemEltTyDefault, "aarch64_sve_st1_scatter_scalar_offset">; def SVST1B_SCATTER_BASES_U : MInst<"svst1b_scatter[_{2}base_{d}]", "vPud", "ilUiUl", [IsScatterStore], MemEltTyInt8, "aarch64_sve_st1_scatter_scalar_offset">; @@ -432,11 +432,11 @@ def SVST1H_SCATTER_32B_INDICES_UU : MInst<"svst1h_scatter_[{3}]index[_{d}]", "vP def SVST1_SCATTER_INDEX_S : MInst<"svst1_scatter[_{2}base]_index[_{d}]", "vPuld", "ilUiUlfd", [IsScatterStore], MemEltTyDefault, "aarch64_sve_st1_scatter_scalar_offset">; def SVST1H_SCATTER_INDEX_S : MInst<"svst1h_scatter[_{2}base]_index[_{d}]", "vPuld", "ilUiUl", [IsScatterStore], MemEltTyInt16, "aarch64_sve_st1_scatter_scalar_offset">; def SVST1W_SCATTER_INDEX_S : MInst<"svst1w_scatter[_{2}base]_index[_{d}]", "vPuld", "lUl", [IsScatterStore], MemEltTyInt32, "aarch64_sve_st1_scatter_scalar_offset">; -} // let TargetGuard = "sve" +} // let SVETargetGuard = "sve" multiclass StructStore { def : SInst; - let TargetGuard = "(sve|sme),bf16" in { + let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in { def: SInst; } } @@ -456,12 +456,12 @@ def SVSTNT1 : MInst<"svstnt1[_{d}]", "vPpd", "csilUcUsUiUlhfd", [IsStore, Verify // Store one vector, with no truncation, non-temporal (scalar base, VL displacement) def SVSTNT1_VNUM : MInst<"svstnt1_vnum[_{d}]", "vPpld", "csilUcUsUiUlhfd", [IsStore, VerifyRuntimeMode], MemEltTyDefault, "aarch64_sve_stnt1">; -let TargetGuard = "(sve|sme),bf16" in { +let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in { def SVSTNT1_BF : MInst<"svstnt1[_{d}]", "vPpd", "b", [IsStore, VerifyRuntimeMode], MemEltTyDefault, "aarch64_sve_stnt1">; def SVSTNT1_VNUM_BF : MInst<"svstnt1_vnum[_{d}]", "vPpld", "b", [IsStore, VerifyRuntimeMode], MemEltTyDefault, "aarch64_sve_stnt1">; } -let TargetGuard = "sve2p1" in { +let SVETargetGuard = "sve2p1", SMETargetGuard = InvalidMode in { // Contiguous truncating store from quadword (single vector). def SVST1UWQ : MInst<"svst1wq[_{d}]", "vPcd", "iUif", [IsStore], MemEltTyInt32, "aarch64_sve_st1wq">; def SVST1UWQ_VNUM : MInst<"svst1wq_vnum[_{d}]", "vPcld", "iUif", [IsStore], MemEltTyInt32, "aarch64_sve_st1wq">; @@ -508,7 +508,7 @@ def SVPRFH_VNUM : MInst<"svprfh_vnum", "vPQlJ", "s", [IsPrefetch, VerifyRuntimeM def SVPRFW_VNUM : MInst<"svprfw_vnum", "vPQlJ", "i", [IsPrefetch, VerifyRuntimeMode], MemEltTyInt32, "aarch64_sve_prf">; def SVPRFD_VNUM : MInst<"svprfd_vnum", "vPQlJ", "l", [IsPrefetch, VerifyRuntimeMode], MemEltTyInt64, "aarch64_sve_prf">; -let TargetGuard = "sve" in { +let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in { // Prefetch (Vector bases) def SVPRFB_GATHER_BASES : MInst<"svprfb_gather[_{2}base]", "vPdJ", "UiUl", [IsGatherPrefetch], MemEltTyInt8, "aarch64_sve_prfb_gather_scalar_offset">; def SVPRFH_GATHER_BASES : MInst<"svprfh_gather[_{2}base]", "vPdJ", "UiUl", [IsGatherPrefetch], MemEltTyInt16, "aarch64_sve_prfh_gather_scalar_offset">; @@ -541,24 +541,24 @@ def SVPRFB_GATHER_BASES_OFFSET : MInst<"svprfb_gather[_{2}base]_offset", "vPdlJ" def SVPRFH_GATHER_BASES_OFFSET : MInst<"svprfh_gather[_{2}base]_index", "vPdlJ", "UiUl", [IsGatherPrefetch], MemEltTyInt16, "aarch64_sve_prfh_gather_scalar_offset">; def SVPRFW_GATHER_BASES_OFFSET : MInst<"svprfw_gather[_{2}base]_index", "vPdlJ", "UiUl", [IsGatherPrefetch], MemEltTyInt32, "aarch64_sve_prfw_gather_scalar_offset">; def SVPRFD_GATHER_BASES_OFFSET : MInst<"svprfd_gather[_{2}base]_index", "vPdlJ", "UiUl", [IsGatherPrefetch], MemEltTyInt64, "aarch64_sve_prfd_gather_scalar_offset">; -} // let TargetGuard = "sve" +} // let SVETargetGuard = "sve" //////////////////////////////////////////////////////////////////////////////// // Address calculations -let TargetGuard = "sve" in { +let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in { def SVADRB : SInst<"svadrb[_{0}base]_[{2}]offset", "uud", "ilUiUl", MergeNone, "aarch64_sve_adrb">; def SVADRH : SInst<"svadrh[_{0}base]_[{2}]index", "uud", "ilUiUl", MergeNone, "aarch64_sve_adrh">; def SVADRW : SInst<"svadrw[_{0}base]_[{2}]index", "uud", "ilUiUl", MergeNone, "aarch64_sve_adrw">; def SVADRD : SInst<"svadrd[_{0}base]_[{2}]index", "uud", "ilUiUl", MergeNone, "aarch64_sve_adrd">; -} // let TargetGuard = "sve" +} // let SVETargetGuard = "sve" //////////////////////////////////////////////////////////////////////////////// // Scalar to vector def SVDUPQ_8 : SInst<"svdupq[_n]_{d}", "dssssssssssssssss", "cUc", MergeNone, "", [VerifyRuntimeMode]>; def SVDUPQ_16 : SInst<"svdupq[_n]_{d}", "dssssssss", "sUsh", MergeNone, "", [VerifyRuntimeMode]>; -let TargetGuard = "(sve|sme),bf16" in { +let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in { def SVDUPQ_BF16 : SInst<"svdupq[_n]_{d}", "dssssssss", "b", MergeNone, "", [VerifyRuntimeMode]>; } def SVDUPQ_32 : SInst<"svdupq[_n]_{d}", "dssss", "iUif", MergeNone, "", [VerifyRuntimeMode]>; @@ -566,7 +566,7 @@ def SVDUPQ_64 : SInst<"svdupq[_n]_{d}", "dss", "lUld", MergeNone, "", [VerifyRu multiclass svdup_base { def NAME : SInst; - let TargetGuard = "(sve|sme),bf16" in { + let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in { def _BF16: SInst; } } @@ -657,9 +657,7 @@ def SVDOT_LANE_U : SInst<"svdot_lane[_{d}]", "ddqqi", "UiUl", MergeNone, "aarc //////////////////////////////////////////////////////////////////////////////// // Logical operations -let TargetGuard = "sve|sme" in { // FIXME: Make this the default for most operations. defm SVAND : SInstZPZZ<"svand", "csilUcUsUiUl", "aarch64_sve_and", "aarch64_sve_and_u">; -} defm SVBIC : SInstZPZZ<"svbic", "csilUcUsUiUl", "aarch64_sve_bic", "aarch64_sve_bic_u">; defm SVEOR : SInstZPZZ<"sveor", "csilUcUsUiUl", "aarch64_sve_eor", "aarch64_sve_eor_u">; defm SVORR : SInstZPZZ<"svorr", "csilUcUsUiUl", "aarch64_sve_orr", "aarch64_sve_orr_u">; @@ -697,7 +695,7 @@ def SVASRD_X : SInst<"svasrd[_n_{d}]", "dPdi", "csil", MergeAny, "aa def SVASRD_Z : SInst<"svasrd[_n_{d}]", "dPdi", "csil", MergeZero, "aarch64_sve_asrd", [VerifyRuntimeMode], [ImmCheck<2, ImmCheckShiftRight, 1>]>; def SVINSR : SInst<"svinsr[_n_{d}]", "dds", "csilUcUsUiUlhfd", MergeNone, "aarch64_sve_insr", [VerifyRuntimeMode]>; -let TargetGuard = "(sve|sme),bf16" in { +let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in { def SVINSR_BF16 : SInst<"svinsr[_n_{d}]", "dds", "b", MergeNone, "aarch64_sve_insr", [VerifyRuntimeMode]>; } @@ -786,7 +784,7 @@ defm SVCLS : SInstCLS<"svcls", "csil", "aarch64_sve_cls", [VerifyRunt defm SVCLZ : SInstCLS<"svclz", "csilUcUsUiUl", "aarch64_sve_clz", [VerifyRuntimeMode]>; defm SVCNT : SInstCLS<"svcnt", "csilUcUsUiUlhfd", "aarch64_sve_cnt", [VerifyRuntimeMode]>; -let TargetGuard = "(sve|sme),bf16" in { +let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in { defm SVCNT_BF16 : SInstCLS<"svcnt", "b", "aarch64_sve_cnt", [VerifyRuntimeMode]>; } @@ -815,9 +813,7 @@ defm SVABS_F : SInstZPZ<"svabs", "hfd", "aarch64_sve_fabs">; defm SVNEG_F : SInstZPZ<"svneg", "hfd", "aarch64_sve_fneg">; defm SVABD_F : SInstZPZZ<"svabd", "hfd", "aarch64_sve_fabd", "aarch64_sve_fabd_u">; -let TargetGuard = "sve|sme" in { // FIXME: Make this the default for most operations. defm SVADD_F : SInstZPZZ<"svadd", "hfd", "aarch64_sve_fadd", "aarch64_sve_fadd_u">; -} defm SVDIV_F : SInstZPZZ<"svdiv", "hfd", "aarch64_sve_fdiv", "aarch64_sve_fdiv_u">; defm SVDIVR_F : SInstZPZZ<"svdivr", "hfd", "aarch64_sve_fdivr", "aarch64_sve_fdiv_u", [ReverseMergeAnyBinOp]>; defm SVMAX_F : SInstZPZZ<"svmax", "hfd", "aarch64_sve_fmax", "aarch64_sve_fmax_u">; @@ -839,7 +835,7 @@ defm SVRINTX : SInstZPZ<"svrintx", "hfd", "aarch64_sve_frintx">; defm SVRINTZ : SInstZPZ<"svrintz", "hfd", "aarch64_sve_frintz">; defm SVSQRT : SInstZPZ<"svsqrt", "hfd", "aarch64_sve_fsqrt">; -let TargetGuard = "sve" in { +let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in { def SVEXPA : SInst<"svexpa[_{d}]", "du", "hfd", MergeNone, "aarch64_sve_fexpa_x">; def SVTMAD : SInst<"svtmad[_{d}]", "dddi", "hfd", MergeNone, "aarch64_sve_ftmad_x", [], [ImmCheck<2, ImmCheck0_7>]>; def SVTSMUL : SInst<"svtsmul[_{d}]", "ddu", "hfd", MergeNone, "aarch64_sve_ftsmul_x">; @@ -947,7 +943,7 @@ defm SVFCVTZS_S64_F16 : SInstCvtMXZ<"svcvt_s64[_f16]", "ddPO", "dPO", "l", "aar defm SVFCVTZS_S32_F32 : SInstCvtMXZ<"svcvt_s32[_f32]", "ddPM", "dPM", "i", "aarch64_sve_fcvtzs", [IsOverloadCvt]>; defm SVFCVTZS_S64_F32 : SInstCvtMXZ<"svcvt_s64[_f32]", "ddPM", "dPM", "l", "aarch64_sve_fcvtzs_i64f32">; -let TargetGuard = "(sve|sme),bf16" in { +let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in { defm SVCVT_BF16_F32 : SInstCvtMXZ<"svcvt_bf16[_f32]", "ddPM", "dPM", "b", "aarch64_sve_fcvt_bf16f32">; def SVCVTNT_BF16_F32 : SInst<"svcvtnt_bf16[_f32]", "ddPM", "b", MergeOp1, "aarch64_sve_fcvtnt_bf16f32", [IsOverloadNone, VerifyRuntimeMode]>; } @@ -1007,7 +1003,7 @@ defm SVFCVT_F32_F64 : SInstCvtMXZ<"svcvt_f32[_f64]", "MMPd", "MPd", "d", "aarc defm SVFCVT_F64_F16 : SInstCvtMXZ<"svcvt_f64[_f16]", "ddPO", "dPO", "d", "aarch64_sve_fcvt_f64f16">; defm SVFCVT_F64_F32 : SInstCvtMXZ<"svcvt_f64[_f32]", "ddPM", "dPM", "d", "aarch64_sve_fcvt_f64f32">; -let TargetGuard = "sve2|sme" in { +let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { defm SVCVTLT_F32 : SInstCvtMX<"svcvtlt_f32[_f16]", "ddPh", "dPh", "f", "aarch64_sve_fcvtlt_f32f16">; defm SVCVTLT_F64 : SInstCvtMX<"svcvtlt_f64[_f32]", "ddPh", "dPh", "d", "aarch64_sve_fcvtlt_f64f32">; @@ -1027,7 +1023,7 @@ def SVCVTXNT_F32 : SInst<"svcvtxnt_f32[_f64]", "MMPd", "d", MergeOp1, "aarch6 multiclass SVEPerm { def : SInst; - let TargetGuard = "(sve|sme),bf16" in { + let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in { def: SInst; } } @@ -1037,7 +1033,7 @@ defm SVCLASTA_N : SVEPerm<"svclasta[_n_{d}]", "sPsd", "aarch64_sve_clasta_n">; defm SVCLASTB : SVEPerm<"svclastb[_{d}]", "dPdd", "aarch64_sve_clastb">; defm SVCLASTB_N : SVEPerm<"svclastb[_n_{d}]", "sPsd", "aarch64_sve_clastb_n">; -let TargetGuard = "sve" in { +let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in { def SVCOMPACT : SInst<"svcompact[_{d}]", "dPd", "ilUiUlfd", MergeNone, "aarch64_sve_compact">; } @@ -1046,13 +1042,13 @@ def SVCOMPACT : SInst<"svcompact[_{d}]", "dPd", "ilUiUlfd", MergeNo // instruction such as DUP (indexed) if the lane index fits the range of the // instruction's immediate. def SVDUP_LANE : SInst<"svdup_lane[_{d}]", "ddL", "csilUcUsUiUlhfd", MergeNone, "aarch64_sve_tbl", [VerifyRuntimeMode]>; -let TargetGuard = "(sve|sme),bf16" in { +let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in { def SVDUP_LANE_BF16 : SInst<"svdup_lane[_{d}]", "ddL", "b", MergeNone, "aarch64_sve_tbl", [VerifyRuntimeMode]>; } def SVDUPQ_LANE : SInst<"svdupq_lane[_{d}]", "ddn", "csilUcUsUiUlhfd", MergeNone, "aarch64_sve_dupq_lane", [VerifyRuntimeMode]>; -let TargetGuard = "(sve|sme),bf16" in { +let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in { def SVDUPQ_LANE_BF16 : SInst<"svdupq_lane[_{d}]", "ddn", "b", MergeNone, "aarch64_sve_dupq_lane", [VerifyRuntimeMode]>; } def SVEXT : SInst<"svext[_{d}]", "dddi", "csilUcUsUiUlhfd", MergeNone, "aarch64_sve_ext", [VerifyRuntimeMode], [ImmCheck<2, ImmCheckExtract, 1>]>; @@ -1063,7 +1059,7 @@ def SVSEL : SInst<"svsel[_{d}]", "dPdd", "csilUcUsUiUlhfd", MergeNo def SVSPLICE : SInst<"svsplice[_{d}]", "dPdd", "csilUcUsUiUlhfd", MergeNone, "aarch64_sve_splice", [VerifyRuntimeMode]>; def SVTBL : SInst<"svtbl[_{d}]", "ddu", "csilUcUsUiUlhfd", MergeNone, "aarch64_sve_tbl", [VerifyRuntimeMode]>; -let TargetGuard = "(sve|sme),bf16" in { +let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in { def SVTBL_BF16 : SInst<"svtbl[_{d}]", "ddu", "b", MergeNone, "aarch64_sve_tbl", [VerifyRuntimeMode]>; } @@ -1078,7 +1074,7 @@ def SVUZP2 : SInst<"svuzp2[_{d}]", "ddd", "csilUcUsUiUlhfd", MergeNo def SVZIP1 : SInst<"svzip1[_{d}]", "ddd", "csilUcUsUiUlhfd", MergeNone, "aarch64_sve_zip1", [VerifyRuntimeMode]>; def SVZIP2 : SInst<"svzip2[_{d}]", "ddd", "csilUcUsUiUlhfd", MergeNone, "aarch64_sve_zip2", [VerifyRuntimeMode]>; -let TargetGuard = "(sve|sme),bf16" in { +let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in { def SVEXT_BF16 : SInst<"svext[_{d}]", "dddi", "b", MergeNone, "aarch64_sve_ext", [VerifyRuntimeMode], [ImmCheck<2, ImmCheckExtract, 1>]>; def SVREV_BF16 : SInst<"svrev[_{d}]", "dd", "b", MergeNone, "aarch64_sve_rev", [VerifyRuntimeMode]>; def SVSEL_BF16 : SInst<"svsel[_{d}]", "dPdd", "b", MergeNone, "aarch64_sve_sel", [VerifyRuntimeMode]>; @@ -1127,11 +1123,8 @@ def SVZIP2_B64 : SInst<"svzip2_b64", "PPP", "Pc", MergeNone, "aarch64_sve_zip // Predicate creation def SVPFALSE : SInst<"svpfalse[_b]", "Pv", "", MergeNone, "", [IsOverloadNone, VerifyRuntimeMode]>; - -let TargetGuard = "sve|sme" in { // FIXME: Make this the default for most operations. def SVPTRUE_PAT : SInst<"svptrue_pat_{d}", "PI", "PcPsPiPl", MergeNone, "aarch64_sve_ptrue", [VerifyRuntimeMode]>; def SVPTRUE : SInst<"svptrue_{d}", "Pv", "PcPsPiPl", MergeNone, "aarch64_sve_ptrue", [IsAppendSVALL, VerifyRuntimeMode]>; -} def SVDUPQ_B8 : SInst<"svdupq[_n]_{d}", "Pssssssssssssssss", "Pc", MergeNone, "", [VerifyRuntimeMode]>; def SVDUPQ_B16 : SInst<"svdupq[_n]_{d}", "Pssssssss", "Ps", MergeNone, "", [VerifyRuntimeMode]>; @@ -1143,9 +1136,7 @@ def SVDUP_N_B : SInst<"svdup[_n]_{d}", "Ps", "PcPsPiPl", MergeNone, "", [V //////////////////////////////////////////////////////////////////////////////// // Predicate operations -let TargetGuard = "sve|sme" in { // FIXME: Make this the default for most operations. def SVAND_B_Z : SInst<"svand[_b]_z", "PPPP", "Pc", MergeNone, "aarch64_sve_and_z", [VerifyRuntimeMode]>; -} def SVBIC_B_Z : SInst<"svbic[_b]_z", "PPPP", "Pc", MergeNone, "aarch64_sve_bic_z", [VerifyRuntimeMode]>; def SVEOR_B_Z : SInst<"sveor[_b]_z", "PPPP", "Pc", MergeNone, "aarch64_sve_eor_z", [VerifyRuntimeMode]>; def SVMOV_B_Z : SInst<"svmov[_b]_z", "PPP", "Pc", MergeNone, "", [VerifyRuntimeMode]>; // Uses custom expansion @@ -1176,7 +1167,7 @@ def SVPTEST_LAST : SInst<"svptest_last", "sPP", "Pc", MergeNone, "aarch64_sve_ //////////////////////////////////////////////////////////////////////////////// // FFR manipulation -let TargetGuard = "sve" in { +let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in { def SVRDFFR : SInst<"svrdffr", "Pv", "Pc", MergeNone, "", [IsOverloadNone]>; def SVRDFFR_Z : SInst<"svrdffr_z", "PP", "Pc", MergeNone, "", [IsOverloadNone]>; def SVSETFFR : SInst<"svsetffr", "vv", "", MergeNone, "", [IsOverloadNone]>; @@ -1199,7 +1190,7 @@ def SVCNTD : SInst<"svcntd", "nv", "", MergeNone, "aarch64_sve_cntd", [IsAppendS def SVCNTP : SInst<"svcntp_{d}", "nPP", "PcPsPiPl", MergeNone, "aarch64_sve_cntp", [VerifyRuntimeMode]>; def SVLEN : SInst<"svlen[_{d}]", "nd", "csilUcUsUiUlhfd", MergeNone, "", [VerifyRuntimeMode]>; -let TargetGuard = "(sve|sme),bf16" in { +let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in { def SVLEN_BF16 : SInst<"svlen[_{d}]", "nd", "b", MergeNone, "", [VerifyRuntimeMode]>; } @@ -1265,13 +1256,13 @@ def SVQINCP_N_S64 : SInst<"svqincp[_n_s64]_{d}", "llP", "PcPsPiPl", MergeNone, " def SVQINCP_N_U32 : SInst<"svqincp[_n_u32]_{d}", "mmP", "PcPsPiPl", MergeNone, "aarch64_sve_uqincp_n32", [VerifyRuntimeMode]>; def SVQINCP_N_U64 : SInst<"svqincp[_n_u64]_{d}", "nnP", "PcPsPiPl", MergeNone, "aarch64_sve_uqincp_n64", [VerifyRuntimeMode]>; -let TargetGuard = "sve,i8mm" in { +let SVETargetGuard = "sve,i8mm", SMETargetGuard = InvalidMode in { def SVMLLA_S32 : SInst<"svmmla[_s32]", "ddqq","i", MergeNone, "aarch64_sve_smmla">; def SVMLLA_U32 : SInst<"svmmla[_u32]", "ddqq","Ui", MergeNone, "aarch64_sve_ummla">; def SVUSMLLA_S32 : SInst<"svusmmla[_s32]", "ddbq","i", MergeNone, "aarch64_sve_usmmla">; } -let TargetGuard = "(sve|sme),i8mm" in { +let SVETargetGuard = "sve,i8mm", SMETargetGuard = "sme,i8mm"in { def SVUSDOT_S : SInst<"svusdot[_s32]", "ddbq", "i", MergeNone, "aarch64_sve_usdot", [VerifyRuntimeMode]>; def SVUSDOT_N_S : SInst<"svusdot[_n_s32]", "ddbr", "i", MergeNone, "aarch64_sve_usdot", [VerifyRuntimeMode]>; def SVSUDOT_S : SInst<"svsudot[_s32]", "ddqb", "i", MergeNone, "aarch64_sve_usdot", [ReverseUSDOT, VerifyRuntimeMode]>; @@ -1281,11 +1272,11 @@ def SVUSDOT_LANE_S : SInst<"svusdot_lane[_s32]", "ddbqi", "i", MergeNone, "a def SVSUDOT_LANE_S : SInst<"svsudot_lane[_s32]", "ddqbi", "i", MergeNone, "aarch64_sve_sudot_lane", [VerifyRuntimeMode], [ImmCheck<3, ImmCheckLaneIndexDot, 2>]>; } -let TargetGuard = "sve,f32mm" in { +let SVETargetGuard = "sve,f32mm", SMETargetGuard = InvalidMode in { def SVMLLA_F32 : SInst<"svmmla[_f32]", "dddd","f", MergeNone, "aarch64_sve_fmmla">; } -let TargetGuard = "sve,f64mm" in { +let SVETargetGuard = "sve,f64mm", SMETargetGuard = InvalidMode in { def SVMLLA_F64 : SInst<"svmmla[_f64]", "dddd","d", MergeNone, "aarch64_sve_fmmla">; def SVTRN1Q : SInst<"svtrn1q[_{d}]", "ddd", "csilUcUsUiUlhfd", MergeNone, "aarch64_sve_trn1q">; def SVTRN2Q : SInst<"svtrn2q[_{d}]", "ddd", "csilUcUsUiUlhfd", MergeNone, "aarch64_sve_trn2q">; @@ -1295,7 +1286,7 @@ def SVZIP1Q : SInst<"svzip1q[_{d}]", "ddd", "csilUcUsUiUlhfd", MergeNo def SVZIP2Q : SInst<"svzip2q[_{d}]", "ddd", "csilUcUsUiUlhfd", MergeNone, "aarch64_sve_zip2q">; } -let TargetGuard = "sve,bf16,f64mm" in { +let SVETargetGuard = "sve,bf16,f64mm", SMETargetGuard = InvalidMode in { def SVTRN1Q_BF16 : SInst<"svtrn1q[_{d}]", "ddd", "b", MergeNone, "aarch64_sve_trn1q">; def SVTRN2Q_BF16 : SInst<"svtrn2q[_{d}]", "ddd", "b", MergeNone, "aarch64_sve_trn2q">; def SVUZP1Q_BF16 : SInst<"svuzp1q[_{d}]", "ddd", "b", MergeNone, "aarch64_sve_uzp1q">; @@ -1306,7 +1297,6 @@ def SVZIP2Q_BF16 : SInst<"svzip2q[_{d}]", "ddd", "b", MergeNone, "aarc //////////////////////////////////////////////////////////////////////////////// // Vector creation -let TargetGuard = "sve|sme" in { // FIXME: Make this the default for most operations. def SVUNDEF_1 : SInst<"svundef_{d}", "dv", "csilUcUsUiUlhfd", MergeNone, "", [IsUndef, VerifyRuntimeMode]>; def SVUNDEF_2 : SInst<"svundef2_{d}", "2v", "csilUcUsUiUlhfd", MergeNone, "", [IsUndef, VerifyRuntimeMode]>; def SVUNDEF_3 : SInst<"svundef3_{d}", "3v", "csilUcUsUiUlhfd", MergeNone, "", [IsUndef, VerifyRuntimeMode]>; @@ -1315,9 +1305,8 @@ def SVUNDEF_4 : SInst<"svundef4_{d}", "4v", "csilUcUsUiUlhfd", MergeNone, "", [I def SVCREATE_2 : SInst<"svcreate2[_{d}]", "2dd", "csilUcUsUiUlhfd", MergeNone, "", [IsTupleCreate, VerifyRuntimeMode]>; def SVCREATE_3 : SInst<"svcreate3[_{d}]", "3ddd", "csilUcUsUiUlhfd", MergeNone, "", [IsTupleCreate, VerifyRuntimeMode]>; def SVCREATE_4 : SInst<"svcreate4[_{d}]", "4dddd", "csilUcUsUiUlhfd", MergeNone, "", [IsTupleCreate, VerifyRuntimeMode]>; -} -let TargetGuard = "(sve|sme),bf16" in { +let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in { def SVUNDEF_1_BF16 : SInst<"svundef_{d}", "dv", "b", MergeNone, "", [IsUndef, VerifyRuntimeMode]>; def SVUNDEF_2_BF16 : SInst<"svundef2_{d}", "2v", "b", MergeNone, "", [IsUndef, VerifyRuntimeMode]>; def SVUNDEF_3_BF16 : SInst<"svundef3_{d}", "3v", "b", MergeNone, "", [IsUndef, VerifyRuntimeMode]>; @@ -1328,14 +1317,13 @@ def SVCREATE_3_BF16 : SInst<"svcreate3[_{d}]", "3ddd", "b", MergeNone, "", [IsT def SVCREATE_4_BF16 : SInst<"svcreate4[_{d}]", "4dddd", "b", MergeNone, "", [IsTupleCreate, VerifyRuntimeMode]>; } -let TargetGuard = "sve2p1|sme2" in { +let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in { def SVCREATE_2_B : SInst<"svcreate2[_b]", "2dd", "Pc", MergeNone, "", [IsTupleCreate, VerifyRuntimeMode]>; def SVCREATE_4_B : SInst<"svcreate4[_b]", "4dddd", "Pc", MergeNone, "", [IsTupleCreate, VerifyRuntimeMode]>; } //////////////////////////////////////////////////////////////////////////////// // Vector insertion and extraction -let TargetGuard = "sve|sme" in { // FIXME: Make this the default for most operations. def SVGET_2 : SInst<"svget2[_{d}]", "d2i", "csilUcUsUiUlhfd", MergeNone, "", [IsTupleGet, VerifyRuntimeMode], [ImmCheck<1, ImmCheck0_1>]>; def SVGET_3 : SInst<"svget3[_{d}]", "d3i", "csilUcUsUiUlhfd", MergeNone, "", [IsTupleGet, VerifyRuntimeMode], [ImmCheck<1, ImmCheck0_2>]>; def SVGET_4 : SInst<"svget4[_{d}]", "d4i", "csilUcUsUiUlhfd", MergeNone, "", [IsTupleGet, VerifyRuntimeMode], [ImmCheck<1, ImmCheck0_3>]>; @@ -1343,9 +1331,8 @@ def SVGET_4 : SInst<"svget4[_{d}]", "d4i", "csilUcUsUiUlhfd", MergeNone, "", [Is def SVSET_2 : SInst<"svset2[_{d}]", "22id", "csilUcUsUiUlhfd", MergeNone, "", [IsTupleSet, VerifyRuntimeMode], [ImmCheck<1, ImmCheck0_1>]>; def SVSET_3 : SInst<"svset3[_{d}]", "33id", "csilUcUsUiUlhfd", MergeNone, "", [IsTupleSet, VerifyRuntimeMode], [ImmCheck<1, ImmCheck0_2>]>; def SVSET_4 : SInst<"svset4[_{d}]", "44id", "csilUcUsUiUlhfd", MergeNone, "", [IsTupleSet, VerifyRuntimeMode], [ImmCheck<1, ImmCheck0_3>]>; -} -let TargetGuard = "(sve|sme),bf16" in { +let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in { def SVGET_2_BF16 : SInst<"svget2[_{d}]", "d2i", "b", MergeNone, "", [IsTupleGet, VerifyRuntimeMode], [ImmCheck<1, ImmCheck0_1>]>; def SVGET_3_BF16 : SInst<"svget3[_{d}]", "d3i", "b", MergeNone, "", [IsTupleGet, VerifyRuntimeMode], [ImmCheck<1, ImmCheck0_2>]>; def SVGET_4_BF16 : SInst<"svget4[_{d}]", "d4i", "b", MergeNone, "", [IsTupleGet, VerifyRuntimeMode], [ImmCheck<1, ImmCheck0_3>]>; @@ -1355,7 +1342,7 @@ def SVSET_3_BF16 : SInst<"svset3[_{d}]", "33id", "b", MergeNone, "", [IsTupleSet def SVSET_4_BF16 : SInst<"svset4[_{d}]", "44id", "b", MergeNone, "", [IsTupleSet, VerifyRuntimeMode], [ImmCheck<1, ImmCheck0_3>]>; } -let TargetGuard = "sve2p1|sme2" in { +let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in { def SVGET_2_B : SInst<"svget2[_b]", "d2i", "Pc", MergeNone, "", [IsTupleGet, VerifyRuntimeMode], [ImmCheck<1, ImmCheck0_1>]>; def SVGET_4_B : SInst<"svget4[_b]", "d4i", "Pc", MergeNone, "", [IsTupleGet, VerifyRuntimeMode], [ImmCheck<1, ImmCheck0_3>]>; @@ -1363,13 +1350,13 @@ let TargetGuard = "sve2p1|sme2" in { def SVSET_4_B : SInst<"svset4[_b]", "44id", "Pc", MergeNone, "", [IsTupleSet, VerifyRuntimeMode], [ImmCheck<1, ImmCheck0_3>]>; } -let TargetGuard = "sve2p1|sme2" in { +let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in { def SVUNDEF_2_B: Inst<"svundef2_b", "2", "Pc", MergeNone, "", [IsUndef, VerifyRuntimeMode], []>; def SVUNDEF_4_B: Inst<"svundef4_b", "4", "Pc", MergeNone, "", [IsUndef, VerifyRuntimeMode], []>; } //////////////////////////////////////////////////////////////////////////////// // SVE2 WhileGE/GT -let TargetGuard = "sve2|sme" in { +let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { def SVWHILEGE_S32 : SInst<"svwhilege_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilege", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; def SVWHILEGE_S64 : SInst<"svwhilege_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilege", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; def SVWHILEGT_S32 : SInst<"svwhilegt_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilegt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; @@ -1380,7 +1367,7 @@ def SVWHILEHS_U32 : SInst<"svwhilege_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNon def SVWHILEHS_U64 : SInst<"svwhilege_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>; } -let TargetGuard = "sve2p1|sme2" in { +let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in { def SVWHILEGE_S64_X2 : SInst<"svwhilege_{d}[_{1}]_x2", "2ll", "PcPsPiPl", MergeNone, "aarch64_sve_whilege_x2", [VerifyRuntimeMode]>; def SVWHILEGT_S64_X2 : SInst<"svwhilegt_{d}[_{1}]_x2", "2ll", "PcPsPiPl", MergeNone, "aarch64_sve_whilegt_x2", [VerifyRuntimeMode]>; def SVWHILEHI_U64_X2 : SInst<"svwhilegt_{d}[_{1}]_x2", "2nn", "PcPsPiPl", MergeNone, "aarch64_sve_whilehi_x2", [VerifyRuntimeMode]>; @@ -1395,7 +1382,7 @@ let TargetGuard = "sve2p1|sme2" in { //////////////////////////////////////////////////////////////////////////////// // SVE2 - Uniform DSP operations -let TargetGuard = "sve2|sme" in { +let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { defm SVQADD_S : SInstZPZZ<"svqadd", "csli", "aarch64_sve_sqadd", "aarch64_sve_sqadd">; defm SVQADD_U : SInstZPZZ<"svqadd", "UcUsUiUl", "aarch64_sve_uqadd", "aarch64_sve_uqadd">; defm SVHADD_S : SInstZPZZ<"svhadd", "csli", "aarch64_sve_shadd", "aarch64_sve_shadd">; @@ -1430,7 +1417,7 @@ multiclass SInstZPZxZ; } -let TargetGuard = "sve2|sme" in { +let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { defm SVQRSHL_S : SInstZPZxZ<"svqrshl", "csil", "dPdx", "dPdK", "aarch64_sve_sqrshl", [VerifyRuntimeMode]>; defm SVQRSHL_U : SInstZPZxZ<"svqrshl", "UcUsUiUl", "dPdx", "dPdK", "aarch64_sve_uqrshl", [VerifyRuntimeMode]>; defm SVQSHL_S : SInstZPZxZ<"svqshl", "csil", "dPdx", "dPdK", "aarch64_sve_sqshl", [VerifyRuntimeMode]>; @@ -1484,7 +1471,7 @@ multiclass SInstPairwise; } -let TargetGuard = "sve2|sme" in { +let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { defm SVADDP : SInstPairwise<"svaddp", "csliUcUsUiUl", "aarch64_sve_addp", [VerifyRuntimeMode]>; defm SVADDP_F : SInstPairwise<"svaddp", "hfd", "aarch64_sve_faddp", [VerifyRuntimeMode]>; defm SVMAXNMP : SInstPairwise<"svmaxnmp", "hfd", "aarch64_sve_fmaxnmp", [VerifyRuntimeMode]>; @@ -1500,7 +1487,7 @@ defm SVMINP_U : SInstPairwise<"svminp", "UcUsUiUl", "aarch64_sve_uminp", [ //////////////////////////////////////////////////////////////////////////////// // SVE2 - Widening pairwise arithmetic -let TargetGuard = "sve2|sme" in { +let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { def SVADALP_S_M : SInst<"svadalp[_{d}]", "dPdh", "sil", MergeOp1, "aarch64_sve_sadalp", [VerifyRuntimeMode]>; def SVADALP_S_X : SInst<"svadalp[_{d}]", "dPdh", "sil", MergeAny, "aarch64_sve_sadalp", [VerifyRuntimeMode]>; def SVADALP_S_Z : SInst<"svadalp[_{d}]", "dPdh", "sil", MergeZero, "aarch64_sve_sadalp", [VerifyRuntimeMode]>; @@ -1514,7 +1501,7 @@ def SVADALP_U_Z : SInst<"svadalp[_{d}]", "dPdh", "UsUiUl", MergeZero, "aarch64_s // SVE2 - Bitwise ternary logical instructions // -let TargetGuard = "sve2|sme" in { +let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { def SVBCAX : SInst<"svbcax[_{d}]", "dddd", "csilUcUsUiUl", MergeNone, "aarch64_sve_bcax", [VerifyRuntimeMode]>; def SVBSL : SInst<"svbsl[_{d}]", "dddd", "csilUcUsUiUl", MergeNone, "aarch64_sve_bsl", [VerifyRuntimeMode]>; def SVBSL1N : SInst<"svbsl1n[_{d}]", "dddd", "csilUcUsUiUl", MergeNone, "aarch64_sve_bsl1n", [VerifyRuntimeMode]>; @@ -1534,7 +1521,7 @@ def SVXAR_N : SInst<"svxar[_n_{d}]", "dddi", "csilUcUsUiUl", MergeNone, "aar //////////////////////////////////////////////////////////////////////////////// // SVE2 - Large integer arithmetic -let TargetGuard = "sve2|sme" in { +let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { def SVADCLB : SInst<"svadclb[_{d}]", "dddd", "UiUl", MergeNone, "aarch64_sve_adclb", [VerifyRuntimeMode]>; def SVADCLT : SInst<"svadclt[_{d}]", "dddd", "UiUl", MergeNone, "aarch64_sve_adclt", [VerifyRuntimeMode]>; def SVSBCLB : SInst<"svsbclb[_{d}]", "dddd", "UiUl", MergeNone, "aarch64_sve_sbclb", [VerifyRuntimeMode]>; @@ -1549,7 +1536,7 @@ def SVSBCLT_N : SInst<"svsbclt[_n_{d}]", "ddda", "UiUl", MergeNone, "aarch64_sve //////////////////////////////////////////////////////////////////////////////// // SVE2 - Multiplication by indexed elements -let TargetGuard = "sve2|sme" in { +let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { def SVMLA_LANE_2 : SInst<"svmla_lane[_{d}]", "ddddi", "silUsUiUl", MergeNone, "aarch64_sve_mla_lane", [VerifyRuntimeMode], [ImmCheck<3, ImmCheckLaneIndex, 2>]>; def SVMLS_LANE_2 : SInst<"svmls_lane[_{d}]", "ddddi", "silUsUiUl", MergeNone, "aarch64_sve_mls_lane", [VerifyRuntimeMode], [ImmCheck<3, ImmCheckLaneIndex, 2>]>; def SVMUL_LANE_2 : SInst<"svmul_lane[_{d}]", "dddi", "silUsUiUl", MergeNone, "aarch64_sve_mul_lane", [VerifyRuntimeMode], [ImmCheck<2, ImmCheckLaneIndex, 1>]>; @@ -1557,7 +1544,7 @@ def SVMUL_LANE_2 : SInst<"svmul_lane[_{d}]", "dddi", "silUsUiUl", MergeNone, "a //////////////////////////////////////////////////////////////////////////////// // SVE2 - Uniform complex integer arithmetic -let TargetGuard = "sve2|sme" in { +let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { def SVCADD : SInst<"svcadd[_{d}]", "dddi", "csilUcUsUiUl", MergeNone, "aarch64_sve_cadd_x", [VerifyRuntimeMode], [ImmCheck<2, ImmCheckComplexRot90_270>]>; def SVSQCADD : SInst<"svqcadd[_{d}]", "dddi", "csil", MergeNone, "aarch64_sve_sqcadd_x", [VerifyRuntimeMode], [ImmCheck<2, ImmCheckComplexRot90_270>]>; def SVCMLA : SInst<"svcmla[_{d}]", "ddddi", "csilUcUsUiUl", MergeNone, "aarch64_sve_cmla_x", [VerifyRuntimeMode], [ImmCheck<3, ImmCheckComplexRotAll90>]>; @@ -1586,7 +1573,7 @@ multiclass SInstWideDSPWide { def _N : SInst; } -let TargetGuard = "sve2|sme" in { +let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { defm SVABALB_S : SInstWideDSPAcc<"svabalb", "sil", "aarch64_sve_sabalb">; defm SVABALB_U : SInstWideDSPAcc<"svabalb", "UsUiUl", "aarch64_sve_uabalb">; defm SVABALT_S : SInstWideDSPAcc<"svabalt", "sil", "aarch64_sve_sabalt">; @@ -1665,7 +1652,7 @@ def SVQDMULLT_LANE : SInst<"svqdmullt_lane[_{d}]", "dhhi", "il", MergeNone, " //////////////////////////////////////////////////////////////////////////////// // SVE2 - Narrowing DSP operations -let TargetGuard = "sve2|sme" in { +let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { def SVADDHNB : SInst<"svaddhnb[_{d}]", "hdd", "silUsUiUl", MergeNone, "aarch64_sve_addhnb", [VerifyRuntimeMode]>; def SVADDHNT : SInst<"svaddhnt[_{d}]", "hhdd", "silUsUiUl", MergeNone, "aarch64_sve_addhnt", [VerifyRuntimeMode]>; def SVRADDHNB : SInst<"svraddhnb[_{d}]", "hdd", "silUsUiUl", MergeNone, "aarch64_sve_raddhnb", [VerifyRuntimeMode]>; @@ -1705,7 +1692,7 @@ def SVQRSHRNT_U : SInst<"svqrshrnt[_n_{d}]", "hhdi", "UsUiUl", MergeNone, " //////////////////////////////////////////////////////////////////////////////// // SVE2 - Unary narrowing operations -let TargetGuard = "sve2|sme" in { +let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { def SVQXTNB_S : SInst<"svqxtnb[_{d}]", "hd", "sil", MergeNone, "aarch64_sve_sqxtnb", [VerifyRuntimeMode]>; def SVQXTNB_U : SInst<"svqxtnb[_{d}]", "hd", "UsUiUl", MergeNone, "aarch64_sve_uqxtnb", [VerifyRuntimeMode]>; def SVQXTUNB_S : SInst<"svqxtunb[_{d}]", "ed", "sil", MergeNone, "aarch64_sve_sqxtunb", [VerifyRuntimeMode]>; @@ -1718,7 +1705,7 @@ def SVQXTUNT_S : SInst<"svqxtunt[_{d}]", "eed", "sil", MergeNone, "aarch64_s //////////////////////////////////////////////////////////////////////////////// // SVE2 - Widening complex integer arithmetic -let TargetGuard = "sve2|sme" in { +let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { defm SVADDLBT : SInstWideDSPLong<"svaddlbt", "sil", "aarch64_sve_saddlbt">; defm SVSUBLBT : SInstWideDSPLong<"svsublbt", "sil", "aarch64_sve_ssublbt">; defm SVSUBLTB : SInstWideDSPLong<"svsubltb", "sil", "aarch64_sve_ssubltb">; @@ -1729,7 +1716,7 @@ defm SVQDMLSLBT : SInstWideDSPAcc<"svqdmlslbt", "sil", "aarch64_sve_sqdmlslbt">; //////////////////////////////////////////////////////////////////////////////// // SVE2 - Non-temporal gather/scatter -let TargetGuard = "sve2" in { +let SVETargetGuard = "sve2", SMETargetGuard = InvalidMode in { // Non-temporal gather load one vector (vector base) def SVLDNT1_GATHER_BASES_U : MInst<"svldnt1_gather[_{2}base]_{0}", "dPu", "ilUiUlfd", [IsGatherLoad], MemEltTyDefault, "aarch64_sve_ldnt1_gather_scalar_offset">; def SVLDNT1SB_GATHER_BASES_U : MInst<"svldnt1sb_gather[_{2}base]_{0}", "dPu", "ilUiUl", [IsGatherLoad], MemEltTyInt8, "aarch64_sve_ldnt1_gather_scalar_offset">; @@ -1852,7 +1839,7 @@ def SVSTNT1W_SCATTER_INDEX_S : MInst<"svstnt1w_scatter[_{2}base]_index[_{d}]", " //////////////////////////////////////////////////////////////////////////////// // SVE2 - Polynomial arithmetic -let TargetGuard = "sve2|sme" in { +let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { def SVEORBT : SInst<"sveorbt[_{d}]", "dddd", "csilUcUsUiUl", MergeNone, "aarch64_sve_eorbt", [VerifyRuntimeMode]>; def SVEORBT_N : SInst<"sveorbt[_n_{d}]", "ddda", "csilUcUsUiUl", MergeNone, "aarch64_sve_eorbt", [VerifyRuntimeMode]>; def SVEORTB : SInst<"sveortb[_{d}]", "dddd", "csilUcUsUiUl", MergeNone, "aarch64_sve_eortb", [VerifyRuntimeMode]>; @@ -1872,7 +1859,7 @@ def SVPMULLT_PAIR_N : SInst<"svpmullt_pair[_n_{d}]", "dda", "UcUi", Mer //////////////////////////////////////////////////////////////////////////////// // SVE2 - Complex integer dot product -let TargetGuard = "sve2|sme" in { +let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { def SVCDOT : SInst<"svcdot[_{d}]", "ddqqi", "il", MergeNone, "aarch64_sve_cdot", [VerifyRuntimeMode], [ImmCheck<3, ImmCheckComplexRotAll90>]>; def SVCDOT_LANE : SInst<"svcdot_lane[_{d}]", "ddqqii", "il", MergeNone, "aarch64_sve_cdot_lane", [VerifyRuntimeMode], [ImmCheck<4, ImmCheckComplexRotAll90>, ImmCheck<3, ImmCheckLaneIndexDot, 2>]>; @@ -1881,7 +1868,7 @@ def SVCDOT_LANE : SInst<"svcdot_lane[_{d}]", "ddqqii", "il", MergeNone, "aarch //////////////////////////////////////////////////////////////////////////////// // SVE2 - Floating-point widening multiply-accumulate -let TargetGuard = "sve2|sme" in { +let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { def SVMLALB_F : SInst<"svmlalb[_{d}]", "ddhh", "f", MergeNone, "aarch64_sve_fmlalb", [VerifyRuntimeMode]>; def SVMLALB_F_N : SInst<"svmlalb[_n_{d}]", "ddhR", "f", MergeNone, "aarch64_sve_fmlalb", [VerifyRuntimeMode]>; def SVMLALB_F_LANE : SInst<"svmlalb_lane[_{d}]", "ddhhi", "f", MergeNone, "aarch64_sve_fmlalb_lane", [VerifyRuntimeMode], [ImmCheck<3, ImmCheckLaneIndex, 2>]>; @@ -1899,7 +1886,7 @@ def SVMLSLT_F_LANE : SInst<"svmlslt_lane[_{d}]", "ddhhi", "f", MergeNone, "aar //////////////////////////////////////////////////////////////////////////////// // SVE2 - Floating-point integer binary logarithm -let TargetGuard = "sve2|sme" in { +let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { def SVLOGB_M : SInst<"svlogb[_{d}]", "xxPd", "hfd", MergeOp1, "aarch64_sve_flogb", [VerifyRuntimeMode]>; def SVLOGB_X : SInst<"svlogb[_{d}]", "xPd", "hfd", MergeAnyExp, "aarch64_sve_flogb", [VerifyRuntimeMode]>; def SVLOGB_Z : SInst<"svlogb[_{d}]", "xPd", "hfd", MergeZeroExp, "aarch64_sve_flogb", [VerifyRuntimeMode]>; @@ -1908,7 +1895,7 @@ def SVLOGB_Z : SInst<"svlogb[_{d}]", "xPd", "hfd", MergeZeroExp, "aarch64_sve_ //////////////////////////////////////////////////////////////////////////////// // SVE2 - Vector Histogram count -let TargetGuard = "sve2" in { +let SVETargetGuard = "sve2", SMETargetGuard = InvalidMode in { def SVHISTCNT : SInst<"svhistcnt[_{d}]_z", "uPdd", "ilUiUl", MergeNone, "aarch64_sve_histcnt">; def SVHISTSEG : SInst<"svhistseg[_{d}]", "udd", "cUc", MergeNone, "aarch64_sve_histseg">; } @@ -1916,14 +1903,14 @@ def SVHISTSEG : SInst<"svhistseg[_{d}]", "udd", "cUc", MergeNone, "aarch6 //////////////////////////////////////////////////////////////////////////////// // SVE2 - Character match -let TargetGuard = "sve2" in { +let SVETargetGuard = "sve2", SMETargetGuard = InvalidMode in { def SVMATCH : SInst<"svmatch[_{d}]", "PPdd", "csUcUs", MergeNone, "aarch64_sve_match">; def SVNMATCH : SInst<"svnmatch[_{d}]", "PPdd", "csUcUs", MergeNone, "aarch64_sve_nmatch">; } //////////////////////////////////////////////////////////////////////////////// // SVE2 - Contiguous conflict detection -let TargetGuard = "sve2|sme" in { +let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { def SVWHILERW_B : SInst<"svwhilerw[_{1}]", "Pcc", "cUc", MergeNone, "aarch64_sve_whilerw_b", [IsOverloadWhileRW, VerifyRuntimeMode]>; def SVWHILERW_H : SInst<"svwhilerw[_{1}]", "Pcc", "sUsh", MergeNone, "aarch64_sve_whilerw_h", [IsOverloadWhileRW, VerifyRuntimeMode]>; def SVWHILERW_S : SInst<"svwhilerw[_{1}]", "Pcc", "iUif", MergeNone, "aarch64_sve_whilerw_s", [IsOverloadWhileRW, VerifyRuntimeMode]>; @@ -1935,19 +1922,19 @@ def SVWHILEWR_S : SInst<"svwhilewr[_{1}]", "Pcc", "iUif", MergeNone, "aarch64_sv def SVWHILEWR_D : SInst<"svwhilewr[_{1}]", "Pcc", "lUld", MergeNone, "aarch64_sve_whilewr_d", [IsOverloadWhileRW, VerifyRuntimeMode]>; } -let TargetGuard = "(sve2|sme),bf16" in { +let SVETargetGuard = "sve2,bf16", SMETargetGuard = "sme,bf16" in { def SVWHILERW_H_BF16 : SInst<"svwhilerw[_{1}]", "Pcc", "b", MergeNone, "aarch64_sve_whilerw_h", [IsOverloadWhileRW, VerifyRuntimeMode]>; def SVWHILEWR_H_BF16 : SInst<"svwhilewr[_{1}]", "Pcc", "b", MergeNone, "aarch64_sve_whilewr_h", [IsOverloadWhileRW, VerifyRuntimeMode]>; } //////////////////////////////////////////////////////////////////////////////// // SVE2 - Extended table lookup/permute -let TargetGuard = "sve2|sme" in { +let SVETargetGuard = "sve2", SMETargetGuard = "sme" in { def SVTBL2 : SInst<"svtbl2[_{d}]", "d2u", "csilUcUsUiUlhfd", MergeNone, "", [VerifyRuntimeMode]>; def SVTBX : SInst<"svtbx[_{d}]", "dddu", "csilUcUsUiUlhfd", MergeNone, "aarch64_sve_tbx", [VerifyRuntimeMode]>; } -let TargetGuard = "(sve2|sme),bf16" in { +let SVETargetGuard = "sve2,bf16", SMETargetGuard = "sme,bf16" in { def SVTBL2_BF16 : SInst<"svtbl2[_{d}]", "d2u", "b", MergeNone, "", [VerifyRuntimeMode]>; def SVTBX_BF16 : SInst<"svtbx[_{d}]", "dddu", "b", MergeNone, "aarch64_sve_tbx", [VerifyRuntimeMode]>; } @@ -1955,7 +1942,7 @@ def SVTBX_BF16 : SInst<"svtbx[_{d}]", "dddu", "b", MergeNone, "aarch64_sve_tbx //////////////////////////////////////////////////////////////////////////////// // SVE2 - Optional -let TargetGuard = "sve2-aes" in { +let SVETargetGuard = "sve2-aes", SMETargetGuard = InvalidMode in { def SVAESD : SInst<"svaesd[_{d}]", "ddd", "Uc", MergeNone, "aarch64_sve_aesd", [IsOverloadNone]>; def SVAESIMC : SInst<"svaesimc[_{d}]", "dd", "Uc", MergeNone, "aarch64_sve_aesimc", [IsOverloadNone]>; def SVAESE : SInst<"svaese[_{d}]", "ddd", "Uc", MergeNone, "aarch64_sve_aese", [IsOverloadNone]>; @@ -1968,16 +1955,16 @@ def SVPMULLT_PAIR_U64 : SInst<"svpmullt_pair[_{d}]", "ddd", "Ul", MergeNone, def SVPMULLT_PAIR_N_U64 : SInst<"svpmullt_pair[_n_{d}]", "dda", "Ul", MergeNone, "aarch64_sve_pmullt_pair">; } -let TargetGuard = "sve2-sha3" in { +let SVETargetGuard = "sve2-sha3", SMETargetGuard = InvalidMode in { // FIXME: valid from sme2p1. def SVRAX1 : SInst<"svrax1[_{d}]", "ddd", "lUl", MergeNone, "aarch64_sve_rax1", [IsOverloadNone]>; } -let TargetGuard = "sve2-sm4" in { +let SVETargetGuard = "sve2-sm4", SMETargetGuard = InvalidMode in { def SVSM4E : SInst<"svsm4e[_{d}]", "ddd", "Ui", MergeNone, "aarch64_sve_sm4e", [IsOverloadNone]>; def SVSM4EKEY : SInst<"svsm4ekey[_{d}]", "ddd", "Ui", MergeNone, "aarch64_sve_sm4ekey", [IsOverloadNone]>; } -let TargetGuard = "sve2-bitperm" in { +let SVETargetGuard = "sve2-bitperm", SMETargetGuard = InvalidMode in { def SVBDEP : SInst<"svbdep[_{d}]", "ddd", "UcUsUiUl", MergeNone, "aarch64_sve_bdep_x">; def SVBDEP_N : SInst<"svbdep[_n_{d}]", "dda", "UcUsUiUl", MergeNone, "aarch64_sve_bdep_x">; def SVBEXT : SInst<"svbext[_{d}]", "ddd", "UcUsUiUl", MergeNone, "aarch64_sve_bext_x">; @@ -1986,7 +1973,7 @@ def SVBGRP : SInst<"svbgrp[_{d}]", "ddd", "UcUsUiUl", MergeNone, "aarch64_sv def SVBGRP_N : SInst<"svbgrp[_n_{d}]", "dda", "UcUsUiUl", MergeNone, "aarch64_sve_bgrp_x">; } -let TargetGuard = "sve2p1|sme" in { +let SVETargetGuard = "sve2p1", SMETargetGuard = "sme" in { def SVPSEL_B : SInst<"svpsel_lane_b8", "PPPm", "Pc", MergeNone, "", [VerifyRuntimeMode], []>; def SVPSEL_H : SInst<"svpsel_lane_b16", "PPPm", "Ps", MergeNone, "", [VerifyRuntimeMode], []>; def SVPSEL_S : SInst<"svpsel_lane_b32", "PPPm", "Pi", MergeNone, "", [VerifyRuntimeMode], []>; @@ -1994,7 +1981,7 @@ def SVPSEL_D : SInst<"svpsel_lane_b64", "PPPm", "Pl", MergeNone, "", [VerifyRunt } // Standalone sve2.1 builtins -let TargetGuard = "sve2p1" in { +let SVETargetGuard = "sve2p1", SMETargetGuard = InvalidMode in { def SVORQV : SInst<"svorqv[_{d}]", "{Pd", "csilUcUsUiUl", MergeNone, "aarch64_sve_orqv", [IsReductionQV]>; def SVEORQV : SInst<"sveorqv[_{d}]", "{Pd", "csilUcUsUiUl", MergeNone, "aarch64_sve_eorqv", [IsReductionQV]>; def SVADDQV : SInst<"svaddqv[_{d}]", "{Pd", "csilUcUsUiUl", MergeNone, "aarch64_sve_addqv", [IsReductionQV]>; @@ -2011,7 +1998,7 @@ def SVFMAXQV : SInst<"svmaxqv[_{d}]", "{Pd", "hfd", MergeNone, "aarch64_sve_ def SVFMINQV : SInst<"svminqv[_{d}]", "{Pd", "hfd", MergeNone, "aarch64_sve_fminqv", [IsReductionQV]>; } -let TargetGuard = "sve2p1|sme2" in { +let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in { def SVPEXT_SINGLE : SInst<"svpext_lane_{d}", "P}i", "QcQsQiQl", MergeNone, "aarch64_sve_pext", [VerifyRuntimeMode], [ImmCheck<1, ImmCheck0_3>]>; def SVPEXT_X2 : SInst<"svpext_lane_{d}_x2", "2.P}i", "QcQsQiQl", MergeNone, "aarch64_sve_pext_x2", [VerifyRuntimeMode], [ImmCheck<1, ImmCheck0_1>]>; @@ -2050,7 +2037,7 @@ multiclass MultiVecLoad { def SV # NAME # D_VNUM_X4 : MInst<"sv" # i # "_vnum" # "[_{2}]_x4", "4}cl", "lUld", [IsStructLoad, VerifyRuntimeMode], MemEltTyDefault, "aarch64_sve_" # i # "_pn_x4">; } -let TargetGuard = "sve2p1|sme2" in { +let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in { defm LD1 : MultiVecLoad<"ld1">; defm LDNT1 : MultiVecLoad<"ldnt1">; } @@ -2075,12 +2062,12 @@ multiclass MultiVecStore { def SV # NAME # D_VNUM_X4 : MInst<"sv" # i # "_vnum" # "[_{2}_x4]", "v}pl4", "lUld", [IsStructStore, VerifyRuntimeMode], MemEltTyDefault, "aarch64_sve_" # i # "_pn_x4">; } -let TargetGuard = "sve2p1|sme2" in { +let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in { defm ST1 : MultiVecStore<"st1">; defm STNT1 : MultiVecStore<"stnt1">; } -let TargetGuard = "sve2p1|sme2" in { +let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in { def SVDOT_X2_S : SInst<"svdot[_{d}_{2}]", "ddhh", "i", MergeNone, "aarch64_sve_sdot_x2", [VerifyRuntimeMode], []>; def SVDOT_X2_U : SInst<"svdot[_{d}_{2}]", "ddhh", "Ui", MergeNone, "aarch64_sve_udot_x2", [VerifyRuntimeMode], []>; def SVDOT_X2_F : SInst<"svdot[_{d}_{2}]", "ddhh", "f", MergeNone, "aarch64_sve_fdot_x2", [VerifyRuntimeMode], []>; @@ -2089,14 +2076,14 @@ def SVDOT_LANE_X2_U : SInst<"svdot_lane[_{d}_{2}]", "ddhhi", "Ui", MergeNone, "a def SVDOT_LANE_X2_F : SInst<"svdot_lane[_{d}_{2}]", "ddhhi", "f", MergeNone, "aarch64_sve_fdot_lane_x2", [VerifyRuntimeMode], [ImmCheck<3, ImmCheck0_3>]>; } -let TargetGuard = "sve2p1|sme" in { +let SVETargetGuard = "sve2p1", SMETargetGuard = "sme" in { def SVSCLAMP : SInst<"svclamp[_{d}]", "dddd", "csil", MergeNone, "aarch64_sve_sclamp", [VerifyRuntimeMode], []>; def SVUCLAMP : SInst<"svclamp[_{d}]", "dddd", "UcUsUiUl", MergeNone, "aarch64_sve_uclamp", [VerifyRuntimeMode], []>; defm SVREVD : SInstZPZ<"svrevd", "csilUcUsUiUlbhfd", "aarch64_sve_revd">; } -let TargetGuard = "sve2p1|sme2" in { +let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in { def SVPTRUE_COUNT : SInst<"svptrue_{d}", "}v", "QcQsQiQl", MergeNone, "aarch64_sve_ptrue_{d}", [IsOverloadNone, VerifyRuntimeMode], []>; def SVPFALSE_COUNT_ALIAS : SInst<"svpfalse_c", "}v", "", MergeNone, "", [IsOverloadNone, VerifyRuntimeMode]>; @@ -2105,7 +2092,7 @@ let TargetGuard = "sve2p1|sme2" in { def SVCNTP_COUNT : SInst<"svcntp_{d}", "n}i", "QcQsQiQl", MergeNone, "aarch64_sve_cntp_{d}", [IsOverloadNone, VerifyRuntimeMode], [ImmCheck<1, ImmCheck2_4_Mul2>]>; } -let TargetGuard = "(sve2|sme2),b16b16" in { +let SVETargetGuard = "sve2,b16b16", SMETargetGuard = "sme2,b16b16" in { defm SVMUL_BF : SInstZPZZ<"svmul", "b", "aarch64_sve_fmul", "aarch64_sve_fmul_u", [VerifyRuntimeMode]>; defm SVADD_BF : SInstZPZZ<"svadd", "b", "aarch64_sve_fadd", "aarch64_sve_fadd_u", [VerifyRuntimeMode]>; defm SVSUB_BF : SInstZPZZ<"svsub", "b", "aarch64_sve_fsub", "aarch64_sve_fsub_u", [VerifyRuntimeMode]>; @@ -2132,7 +2119,7 @@ multiclass MinMaxIntr { def SVF # NAME : SInst<"sv" # i # "[" # zm # "_{d}_" # mul # "]", t, "bhfd", MergeNone, "aarch64_sve_f" # i # zm # "_" # mul, [IsStreaming], []>; } -let TargetGuard = "sme2" in { +let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in { // == SMAX / UMAX / FMAX == defm MAX_SINGLE_X2 : MinMaxIntr<"max", "_single", "x2", "22d">; defm MAX_MULTI_X2 : MinMaxIntr<"max", "", "x2", "222">; @@ -2154,13 +2141,13 @@ multiclass SInstMinMaxByVector { def NAME # _X4 : SInst<"sv" # name # "nm[_{d}_x4]", "444", "bhfd", MergeNone, "aarch64_sve_f" # name # "nm_x4", [IsStreaming], []>; } -let TargetGuard = "sme2" in { +let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in { // == FMINNM / FMAXNM == defm SVMINNM : SInstMinMaxByVector<"min">; defm SVMAXNM : SInstMinMaxByVector<"max">; } -let TargetGuard = "sme2" in { +let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in { // FRINTA / FRINTM / FRINTN / FRINTP def SVRINTA_X2 : SInst<"svrinta[_{d}_x2]", "22", "f", MergeNone, "aarch64_sve_frinta_x2", [IsStreaming], []>; def SVRINTA_X4 : SInst<"svrinta[_{d}_x4]", "44", "f", MergeNone, "aarch64_sve_frinta_x4", [IsStreaming], []>; @@ -2175,7 +2162,7 @@ let TargetGuard = "sme2" in { def SVRINTP_X4 : SInst<"svrintp[_{d}_x4]", "44", "f", MergeNone, "aarch64_sve_frintp_x4", [IsStreaming], []>; } -let TargetGuard = "sme2" in { +let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in { def SVSCLAMP_X2 : SInst<"svclamp[_single_{d}_x2]", "22dd", "csil", MergeNone, "aarch64_sve_sclamp_single_x2", [IsStreaming], []>; def SVUCLAMP_X2 : SInst<"svclamp[_single_{d}_x2]", "22dd", "UcUsUiUl", MergeNone, "aarch64_sve_uclamp_single_x2", [IsStreaming], []>; def SVFCLAMP_X2 : SInst<"svclamp[_single_{d}_x2]", "22dd", "hfd", MergeNone, "aarch64_sve_fclamp_single_x2", [IsStreaming], []>; @@ -2185,12 +2172,12 @@ let TargetGuard = "sme2" in { def SVFCLAMP_X4 : SInst<"svclamp[_single_{d}_x4]", "44dd", "hfd", MergeNone, "aarch64_sve_fclamp_single_x4", [IsStreaming], []>; } -let TargetGuard = "sme2,b16b16"in { +let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2,b16b16"in { def SVBFCLAMP_X2 : SInst<"svclamp[_single_{d}_x2]", "22dd", "b", MergeNone, "aarch64_sve_bfclamp_single_x2", [IsStreaming], []>; def SVBFCLAMP_X4 : SInst<"svclamp[_single_{d}_x4]", "44dd", "b", MergeNone, "aarch64_sve_bfclamp_single_x4", [IsStreaming], []>; } -let TargetGuard = "sme2" in { +let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in { // == ADD (vectors) == def SVADD_SINGLE_X2 : SInst<"svadd[_single_{d}_x2]", "22d", "cUcsUsiUilUl", MergeNone, "aarch64_sve_add_single_x2", [IsStreaming], []>; def SVADD_SINGLE_X4 : SInst<"svadd[_single_{d}_x4]", "44d", "cUcsUsiUilUl", MergeNone, "aarch64_sve_add_single_x4", [IsStreaming], []>; @@ -2232,7 +2219,7 @@ let TargetGuard = "sme2" in { def SVSQDMULH_X4 : SInst<"svqdmulh[_{d}_x4]", "444", "csil", MergeNone, "aarch64_sve_sqdmulh_vgx4", [IsStreaming], []>; } -let TargetGuard = "sve2p1|sme2" in { +let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in { def REINTERPRET_SVBOOL_TO_SVCOUNT : Inst<"svreinterpret[_c]", "}P", "Pc", MergeNone, "", [VerifyRuntimeMode], []>; def REINTERPRET_SVCOUNT_TO_SVBOOL : Inst<"svreinterpret[_b]", "P}", "Pc", MergeNone, "", [VerifyRuntimeMode], []>; @@ -2244,7 +2231,7 @@ let TargetGuard = "sve2p1|sme2" in { def SVSQRSHRUN_X2 : SInst<"svqrshrun[_n]_{0}[_{d}_x2]", "e2i", "i", MergeNone, "aarch64_sve_sqrshrun_x2", [VerifyRuntimeMode], [ImmCheck<1, ImmCheck1_16>]>; } -let TargetGuard = "sve2p1" in { +let SVETargetGuard = "sve2p1", SMETargetGuard = InvalidMode in { // ZIPQ1, ZIPQ2, UZPQ1, UZPQ2 def SVZIPQ1 : SInst<"svzipq1[_{d}]", "ddd", "cUcsUsiUilUlbhfd", MergeNone, "aarch64_sve_zipq1", [], []>; def SVZIPQ2 : SInst<"svzipq2[_{d}]", "ddd", "cUcsUsiUilUlbhfd", MergeNone, "aarch64_sve_zipq2", [], []>; @@ -2278,7 +2265,7 @@ let TargetGuard = "sve2p1" in { defm SVPMOV_TO_VEC_LANE_D : PMOV_TO_VEC<"svpmov", "lUl", "aarch64_sve_pmov_to_vector_lane" ,[], ImmCheck1_7>; } -let TargetGuard = "sve2p1|sme2p1" in { +let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2p1" in { // DUPQ def SVDUP_LANEQ_B : SInst<"svdup_laneq[_{d}]", "ddi", "cUc", MergeNone, "aarch64_sve_dup_laneq", [VerifyRuntimeMode], [ImmCheck<1, ImmCheck0_15>]>; def SVDUP_LANEQ_H : SInst<"svdup_laneq[_{d}]", "ddi", "sUsh", MergeNone, "aarch64_sve_dup_laneq", [VerifyRuntimeMode], [ImmCheck<1, ImmCheck0_7>]>; @@ -2286,14 +2273,14 @@ let TargetGuard = "sve2p1|sme2p1" in { def SVDUP_LANEQ_D : SInst<"svdup_laneq[_{d}]", "ddi", "lUld", MergeNone, "aarch64_sve_dup_laneq", [VerifyRuntimeMode], [ImmCheck<1, ImmCheck0_1>]>; } -let TargetGuard = "(sve2p1|sme2p1),bf16" in { +let SVETargetGuard = "sve2p1,bf16", SMETargetGuard = "sme2p1,bf16" in { def SVDUP_LANEQ_BF16 : SInst<"svdup_laneq[_{d}]", "ddi", "b", MergeNone, "aarch64_sve_dup_laneq", [VerifyRuntimeMode], [ImmCheck<1, ImmCheck0_7>]>; } // // Multi-vector convert to/from floating-point. // -let TargetGuard = "sme2" in { +let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in { def SVCVT_F16_X2 : SInst<"svcvt_f16[_f32_x2]", "e2", "f", MergeNone, "aarch64_sve_fcvt_x2", [IsStreaming],[]>; def SVCVT_BF16_X2 : SInst<"svcvt_bf16[_f32_x2]", "$2", "f", MergeNone, "aarch64_sve_bfcvt_x2", [IsOverloadNone, IsStreaming],[]>; @@ -2308,14 +2295,14 @@ let TargetGuard = "sme2" in { def SVCVT_S32_F32_X4 : SInst<"svcvt_{d}[_f32_x4]", "4.d4.M", "i", MergeNone, "aarch64_sve_fcvtzs_x4", [IsStreaming, IsOverloadWhileOrMultiVecCvt], []>; } -let TargetGuard = "sme-f16f16" in { +let SVETargetGuard = InvalidMode, SMETargetGuard = "sme-f16f16" in { def SVCVT_F32_X2 : SInst<"svcvt_{d}[_f16_x2]", "2h", "f", MergeNone, "aarch64_sve_fcvt_widen_x2", [ IsStreaming],[]>; } // // Multi-vector floating-point convert from single-precision to interleaved half-precision/BFloat16 // -let TargetGuard = "sme2" in { +let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in { def SVCVTN_F16_X2 : SInst<"svcvtn_f16[_f32_x2]", "e2", "f", MergeNone, "aarch64_sve_fcvtn_x2", [IsStreaming],[]>; def SVCVTN_BF16_X2 : SInst<"svcvtn_bf16[_f32_x2]", "$2", "f", MergeNone, "aarch64_sve_bfcvtn_x2", [IsOverloadNone, IsStreaming],[]>; } @@ -2323,14 +2310,14 @@ let TargetGuard = "sme2" in { // //Multi-vector floating-point convert from half-precision to deinterleaved single-precision. // -let TargetGuard = "sme-f16f16" in { +let SVETargetGuard = InvalidMode, SMETargetGuard = "sme-f16f16" in { def SVCVTL_F32_X2 : SInst<"svcvtl_f32[_f16_x2]", "2h", "f", MergeNone, "aarch64_sve_fcvtl_widen_x2", [ IsStreaming],[]>; } // // Multi-vector saturating extract narrow // -let TargetGuard = "sme2" in { +let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in { def SVQCVT_S16_S32_X2 : SInst<"svqcvt_s16[_{d}_x2]", "h2.d", "i", MergeNone, "aarch64_sve_sqcvt_x2", [IsStreaming], []>; def SVQCVT_U16_U32_X2 : SInst<"svqcvt_u16[_{d}_x2]", "e2.d", "Ui", MergeNone, "aarch64_sve_uqcvt_x2", [IsStreaming], []>; def SVQCVT_U16_S32_X2 : SInst<"svqcvt_u16[_{d}_x2]", "e2.d", "i", MergeNone, "aarch64_sve_sqcvtu_x2", [IsStreaming], []>; @@ -2347,13 +2334,13 @@ let TargetGuard = "sme2" in { // // Multi-vector saturating extract narrow and interleave // -let TargetGuard = "sme2|sve2p1" in { +let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in { def SVQCVTN_S16_S32_X2 : SInst<"svqcvtn_s16[_{d}_x2]", "h2.d", "i", MergeNone, "aarch64_sve_sqcvtn_x2", [VerifyRuntimeMode], []>; def SVQCVTN_U16_U32_X2 : SInst<"svqcvtn_u16[_{d}_x2]", "e2.d", "Ui", MergeNone, "aarch64_sve_uqcvtn_x2", [VerifyRuntimeMode], []>; def SVQCVTN_U16_S32_X2 : SInst<"svqcvtn_u16[_{d}_x2]", "e2.d", "i", MergeNone, "aarch64_sve_sqcvtun_x2", [VerifyRuntimeMode], []>; } -let TargetGuard = "sme2" in { +let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in { def SVQCVTN_S8_S32_X4 : SInst<"svqcvtn_s8[_{d}_x4]", "q4.d", "i", MergeNone, "aarch64_sve_sqcvtn_x4", [IsStreaming], []>; def SVQCVTN_U8_U32_X4 : SInst<"svqcvtn_u8[_{d}_x4]", "b4.d", "Ui", MergeNone, "aarch64_sve_uqcvtn_x4", [IsStreaming], []>; def SVQCVTN_U8_S32_X4 : SInst<"svqcvtn_u8[_{d}_x4]", "b4.d", "i", MergeNone, "aarch64_sve_sqcvtun_x4", [IsStreaming], []>; @@ -2367,7 +2354,7 @@ let TargetGuard = "sme2" in { // Multi-vector zip/unzip // -let TargetGuard = "sme2" in { +let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in { def SVZIP_X2 : SInst<"svzip[_{d}_x2]", "22", "cUcsUsiUilUlbhfd", MergeNone, "aarch64_sve_zip_x2", [IsStreaming], []>; def SVZIPQ_X2 : SInst<"svzipq[_{d}_x2]", "22", "cUcsUsiUilUlbhfd", MergeNone, "aarch64_sve_zipq_x2", [IsStreaming], []>; def SVZIP_X4 : SInst<"svzip[_{d}_x4]", "44", "cUcsUsiUilUlbhfd", MergeNone, "aarch64_sve_zip_x4", [IsStreaming], []>; @@ -2383,14 +2370,14 @@ let TargetGuard = "sme2" in { // Multi-vector unpack // -let TargetGuard = "sme2" in { +let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in { def SVSUNPK_X2 : SInst<"svunpk_{d}[_{1}_x2]", "2h", "sil", MergeNone, "aarch64_sve_sunpk_x2", [IsStreaming], []>; def SVUUNPK_X2 : SInst<"svunpk_{d}[_{1}_x2]", "2h", "UsUiUl", MergeNone, "aarch64_sve_uunpk_x2", [IsStreaming], []>; def SVSUNPK_X4 : SInst<"svunpk_{d}[_{3}_x4]", "42.h", "sil", MergeNone, "aarch64_sve_sunpk_x4", [IsStreaming], []>; def SVUUNPK_X4 : SInst<"svunpk_{d}[_{3}_x4]", "42.h", "UsUiUl", MergeNone, "aarch64_sve_uunpk_x4", [IsStreaming], []>; } -let TargetGuard = "sve2p1|sme2" in { +let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in { // == BFloat16 multiply-subtract == def SVBFMLSLB : SInst<"svbfmlslb[_{d}]", "dd$$", "f", MergeNone, "aarch64_sve_bfmlslb", [IsOverloadNone, VerifyRuntimeMode], []>; def SVBFMLSLT : SInst<"svbfmlslt[_{d}]", "dd$$", "f", MergeNone, "aarch64_sve_bfmlslt", [IsOverloadNone, VerifyRuntimeMode], []>; diff --git a/clang/include/clang/Basic/arm_sve_sme_incl.td b/clang/include/clang/Basic/arm_sve_sme_incl.td index 707f445858067d..6ec357825a132a 100644 --- a/clang/include/clang/Basic/arm_sve_sme_incl.td +++ b/clang/include/clang/Basic/arm_sve_sme_incl.td @@ -267,12 +267,15 @@ class ImmCheck { ImmCheckType Kind = kind; } +defvar InvalidMode = ""; + class Inst ft, list ch, MemEltType met = MemEltTyDefault> { string Name = n; string Prototype = p; string Types = t; - string TargetGuard = "sve|sme"; + string SVETargetGuard = "sve"; + string SMETargetGuard = "sme"; int Merge = mt.Value; string MergeSuffix = mt.Suffix; string LLVMIntrinsic = i; diff --git a/clang/include/clang/CodeGen/CodeGenABITypes.h b/clang/include/clang/CodeGen/CodeGenABITypes.h index fda0855dc86837..d4822dc160082b 100644 --- a/clang/include/clang/CodeGen/CodeGenABITypes.h +++ b/clang/include/clang/CodeGen/CodeGenABITypes.h @@ -42,6 +42,7 @@ class CXXConstructorDecl; class CXXDestructorDecl; class CXXRecordDecl; class CXXMethodDecl; +class GlobalDecl; class ObjCMethodDecl; class ObjCProtocolDecl; @@ -104,6 +105,9 @@ llvm::Type *convertTypeForMemory(CodeGenModule &CGM, QualType T); unsigned getLLVMFieldNumber(CodeGenModule &CGM, const RecordDecl *RD, const FieldDecl *FD); +/// Return a declaration discriminator for the given global decl. +uint16_t getPointerAuthDeclDiscriminator(CodeGenModule &CGM, GlobalDecl GD); + /// Given the language and code-generation options that Clang was configured /// with, set the default LLVM IR attributes for a function definition. /// The attributes set here are mostly global target-configuration and diff --git a/clang/include/clang/CodeGen/ConstantInitBuilder.h b/clang/include/clang/CodeGen/ConstantInitBuilder.h index 498acfd3801318..28d4764b6d60b0 100644 --- a/clang/include/clang/CodeGen/ConstantInitBuilder.h +++ b/clang/include/clang/CodeGen/ConstantInitBuilder.h @@ -25,8 +25,11 @@ #include namespace clang { -namespace CodeGen { +class GlobalDecl; +class PointerAuthSchema; +class QualType; +namespace CodeGen { class CodeGenModule; /// A convenience builder class for complex constant initializers, @@ -199,6 +202,11 @@ class ConstantAggregateBuilderBase { add(llvm::ConstantInt::get(intTy, value, isSigned)); } + /// Add a signed pointer using the given pointer authentication schema. + void addSignedPointer(llvm::Constant *Pointer, + const PointerAuthSchema &Schema, GlobalDecl CalleeDecl, + QualType CalleeType); + /// Add a null pointer of a specific type. void addNullPointer(llvm::PointerType *ptrTy) { add(llvm::ConstantPointerNull::get(ptrTy)); diff --git a/clang/include/clang/CodeGen/ModuleBuilder.h b/clang/include/clang/CodeGen/ModuleBuilder.h index edacd82bf899db..59b9840d02e086 100644 --- a/clang/include/clang/CodeGen/ModuleBuilder.h +++ b/clang/include/clang/CodeGen/ModuleBuilder.h @@ -15,6 +15,7 @@ #include "clang/AST/ASTConsumer.h" #include "clang/Basic/LLVM.h" +#include "llvm/ADT/StringRef.h" namespace llvm { class Constant; @@ -27,6 +28,9 @@ namespace llvm { } } +// Prefix of the name of the artificial inline frame. +inline constexpr llvm::StringRef ClangTrapPrefix = "__clang_trap_msg"; + namespace clang { class CodeGenOptions; class CoverageSourceInfo; diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h index 084c3ffe69ae86..cc1538372d5f8d 100644 --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -747,9 +747,6 @@ class Driver { /// option. void setDriverMode(StringRef DriverModeValue); - /// Set the resource directory, depending on which driver is being used. - void setResourceDirectory(); - /// Parse the \p Args list for LTO options and record the type of LTO /// compilation based on which -f(no-)?lto(=.*)? option occurs last. void setLTOMode(const llvm::opt::ArgList &Args); diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index bbf860aa491e1d..1c2b8cfeef6ce6 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -5713,6 +5713,11 @@ def print_supported_extensions : Flag<["-", "--"], "print-supported-extensions"> Visibility<[ClangOption, CC1Option, CLOption]>, HelpText<"Print supported -march extensions (RISC-V, AArch64 and ARM only)">, MarshallingInfoFlag>; +def print_enabled_extensions : Flag<["-", "--"], "print-enabled-extensions">, + Visibility<[ClangOption, CC1Option, CLOption]>, + HelpText<"Print the extensions enabled by the given target and -march/-mcpu options." + " (AArch64 only)">, + MarshallingInfoFlag>; def : Flag<["-"], "mcpu=help">, Alias; def : Flag<["-"], "mtune=help">, Alias; def time : Flag<["-"], "time">, @@ -6314,12 +6319,12 @@ def mno_gather : Flag<["-"], "mno-gather">, Group, def mno_scatter : Flag<["-"], "mno-scatter">, Group, HelpText<"Disable generation of scatter instructions in auto-vectorization(x86 only)">; def mapx_features_EQ : CommaJoined<["-"], "mapx-features=">, Group, - HelpText<"Enable features of APX">, Values<"egpr,push2pop2,ppx,ndd,ccmp,nf,cf">; + HelpText<"Enable features of APX">, Values<"egpr,push2pop2,ppx,ndd,ccmp,nf,cf,zu">; def mno_apx_features_EQ : CommaJoined<["-"], "mno-apx-features=">, Group, - HelpText<"Disable features of APX">, Values<"egpr,push2pop2,ppx,ndd,ccmp,nf,cf">; + HelpText<"Disable features of APX">, Values<"egpr,push2pop2,ppx,ndd,ccmp,nf,cf,zu">; // For stability, we only add a feature to -mapxf after it passes the validation of llvm-test-suite && cpu2017 on Intel SDE. -def mapxf : Flag<["-"], "mapxf">, Alias, AliasArgs<["egpr","push2pop2","ppx","ndd","ccmp","nf"]>; -def mno_apxf : Flag<["-"], "mno-apxf">, Alias, AliasArgs<["egpr","push2pop2","ppx","ndd","ccmp","nf"]>; +def mapxf : Flag<["-"], "mapxf">, Alias, AliasArgs<["egpr","push2pop2","ppx","ndd","ccmp","nf","cf"]>; +def mno_apxf : Flag<["-"], "mno-apxf">, Alias, AliasArgs<["egpr","push2pop2","ppx","ndd","ccmp","nf","cf"]>; def mapx_inline_asm_use_gpr32 : Flag<["-"], "mapx-inline-asm-use-gpr32">, Group, HelpText<"Enable use of GPR32 in inline assembly for APX">; } // let Flags = [TargetSpecific] @@ -8597,6 +8602,8 @@ def : Separate<["-"], "Xmicrosoft-windows-sdk-root">, Alias<_SLASH_winsdkdir>; def : Separate<["-"], "Xmicrosoft-windows-sdk-version">, Alias<_SLASH_winsdkversion>; +def : Separate<["-"], "Xmicrosoft-windows-sys-root">, + Alias<_SLASH_winsysroot>; // Ignored: @@ -8768,3 +8775,11 @@ def spirv : DXCFlag<"spirv">, def fspv_target_env_EQ : Joined<["-"], "fspv-target-env=">, Group, HelpText<"Specify the target environment">, Values<"vulkan1.2, vulkan1.3">; +def no_wasm_opt : Flag<["--"], "no-wasm-opt">, + Group, + HelpText<"Disable the wasm-opt optimizer">, + MarshallingInfoFlag>; +def wasm_opt : Flag<["--"], "wasm-opt">, + Group, + HelpText<"Enable the wasm-opt optimizer (default)">, + MarshallingInfoNegativeFlag>; diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 7d257be10af42c..efc2e450b723fa 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -3095,20 +3095,49 @@ struct FormatStyle { bool JavaScriptWrapImports; // clang-format on - /// Keep empty lines (up to ``MaxEmptyLinesToKeep``) at end of file. - /// \version 17 - bool KeepEmptyLinesAtEOF; - - /// If true, the empty line at the start of blocks is kept. + /// Options regarding which empty lines are kept. + /// + /// For example, the config below will remove empty lines at start of the + /// file, end of the file, and start of blocks. + /// /// \code - /// true: false: - /// if (foo) { vs. if (foo) { - /// bar(); - /// bar(); } - /// } + /// KeepEmptyLines: + /// AtEndOfFile: false + /// AtStartOfBlock: false + /// AtStartOfFile: false /// \endcode + struct KeepEmptyLinesStyle { + /// Keep empty lines at end of file. + bool AtEndOfFile; + /// Keep empty lines at start of a block. + /// \code + /// true: false: + /// if (foo) { vs. if (foo) { + /// bar(); + /// bar(); } + /// } + /// \endcode + bool AtStartOfBlock; + /// Keep empty lines at start of file. + bool AtStartOfFile; + bool operator==(const KeepEmptyLinesStyle &R) const { + return AtEndOfFile == R.AtEndOfFile && + AtStartOfBlock == R.AtStartOfBlock && + AtStartOfFile == R.AtStartOfFile; + } + }; + /// Which empty lines are kept. See ``MaxEmptyLinesToKeep`` for how many + /// consecutive empty lines are kept. + /// \version 19 + KeepEmptyLinesStyle KeepEmptyLines; + + /// This option is deprecated. See ``AtEndOfFile`` of ``KeepEmptyLines``. + /// \version 17 + // bool KeepEmptyLinesAtEOF; + + /// This option is deprecated. See ``AtStartOfBlock`` of ``KeepEmptyLines``. /// \version 3.7 - bool KeepEmptyLinesAtTheStartOfBlocks; + // bool KeepEmptyLinesAtTheStartOfBlocks; /// Indentation logic for lambda bodies. enum LambdaBodyIndentationKind : int8_t { @@ -5033,10 +5062,7 @@ struct FormatStyle { JavaImportGroups == R.JavaImportGroups && JavaScriptQuotes == R.JavaScriptQuotes && JavaScriptWrapImports == R.JavaScriptWrapImports && - KeepEmptyLinesAtEOF == R.KeepEmptyLinesAtEOF && - KeepEmptyLinesAtTheStartOfBlocks == - R.KeepEmptyLinesAtTheStartOfBlocks && - Language == R.Language && + KeepEmptyLines == R.KeepEmptyLines && Language == R.Language && LambdaBodyIndentation == R.LambdaBodyIndentation && LineEnding == R.LineEnding && MacroBlockBegin == R.MacroBlockBegin && MacroBlockEnd == R.MacroBlockEnd && Macros == R.Macros && diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h index ebb8e9e59c6b64..5e5034fe01eb54 100644 --- a/clang/include/clang/Frontend/FrontendOptions.h +++ b/clang/include/clang/Frontend/FrontendOptions.h @@ -306,6 +306,10 @@ class FrontendOptions { LLVM_PREFERRED_TYPE(bool) unsigned PrintSupportedExtensions : 1; + /// Print the extensions enabled for the current target. + LLVM_PREFERRED_TYPE(bool) + unsigned PrintEnabledExtensions : 1; + /// Show the -version text. LLVM_PREFERRED_TYPE(bool) unsigned ShowVersion : 1; diff --git a/clang/include/clang/InstallAPI/Visitor.h b/clang/include/clang/InstallAPI/Visitor.h index 9ac948ded3e332..3680ee566ca875 100644 --- a/clang/include/clang/InstallAPI/Visitor.h +++ b/clang/include/clang/InstallAPI/Visitor.h @@ -60,8 +60,8 @@ class InstallAPIVisitor final : public ASTConsumer, std::string getMangledName(const NamedDecl *D) const; std::string getBackendMangledName(llvm::Twine Name) const; std::string getMangledCXXVTableName(const CXXRecordDecl *D) const; - std::string getMangledCXXThunk(const GlobalDecl &D, - const ThunkInfo &Thunk) const; + std::string getMangledCXXThunk(const GlobalDecl &D, const ThunkInfo &Thunk, + bool ElideOverrideInfo) const; std::string getMangledCXXRTTI(const CXXRecordDecl *D) const; std::string getMangledCXXRTTIName(const CXXRecordDecl *D) const; std::string getMangledCtorDtor(const CXXMethodDecl *D, int Type) const; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 95c0655f9a2145..6880fa4bb0b03a 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3017,11 +3017,12 @@ class Parser : public CodeCompletionHandler { const IdentifierInfo *EnclosingScope = nullptr); void MaybeParseHLSLAnnotations(Declarator &D, - SourceLocation *EndLoc = nullptr) { + SourceLocation *EndLoc = nullptr, + bool CouldBeBitField = false) { assert(getLangOpts().HLSL && "MaybeParseHLSLAnnotations is for HLSL only"); if (Tok.is(tok::colon)) { ParsedAttributes Attrs(AttrFactory); - ParseHLSLAnnotations(Attrs, EndLoc); + ParseHLSLAnnotations(Attrs, EndLoc, CouldBeBitField); D.takeAttributes(Attrs); } } @@ -3029,12 +3030,13 @@ class Parser : public CodeCompletionHandler { void MaybeParseHLSLAnnotations(ParsedAttributes &Attrs, SourceLocation *EndLoc = nullptr) { assert(getLangOpts().HLSL && "MaybeParseHLSLAnnotations is for HLSL only"); - if (getLangOpts().HLSL && Tok.is(tok::colon)) + if (Tok.is(tok::colon)) ParseHLSLAnnotations(Attrs, EndLoc); } void ParseHLSLAnnotations(ParsedAttributes &Attrs, - SourceLocation *EndLoc = nullptr); + SourceLocation *EndLoc = nullptr, + bool CouldBeBitField = false); Decl *ParseHLSLBuffer(SourceLocation &DeclEnd); void MaybeParseMicrosoftAttributes(ParsedAttributes &Attrs) { @@ -3511,6 +3513,19 @@ class Parser : public CodeCompletionHandler { /// metadirective and therefore ends on the closing paren. StmtResult ParseOpenMPDeclarativeOrExecutableDirective( ParsedStmtContext StmtCtx, bool ReadDirectiveWithinMetadirective = false); + + /// Parses executable directive. + /// + /// \param StmtCtx The context in which we're parsing the directive. + /// \param DKind The kind of the executable directive. + /// \param Loc Source location of the beginning of the directive. + /// \param ReadDirectiveWithinMetadirective true if directive is within a + /// metadirective and therefore ends on the closing paren. + StmtResult + ParseOpenMPExecutableDirective(ParsedStmtContext StmtCtx, + OpenMPDirectiveKind DKind, SourceLocation Loc, + bool ReadDirectiveWithinMetadirective); + /// Parses clause of kind \a CKind for directive of a kind \a Kind. /// /// \param DKind Kind of current directive. diff --git a/clang/include/clang/Sema/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h index 22cbd0d90ee432..65d73f6cd44f6e 100644 --- a/clang/include/clang/Sema/ParsedAttr.h +++ b/clang/include/clang/Sema/ParsedAttr.h @@ -1083,6 +1083,7 @@ enum AttributeArgumentNType { AANT_ArgumentIdentifier, AANT_ArgumentConstantExpr, AANT_ArgumentBuiltinFunction, + AANT_ArgumentNullptrOrBoolIntOrEnumLiteral, }; /// These constants match the enumerated choices of @@ -1101,6 +1102,7 @@ enum AttributeDeclKind { ExpectedFunctionVariableOrClass, ExpectedKernelFunction, ExpectedFunctionWithProtoType, + ExpectedFunctionReturningPointerBoolIntOrEnum, }; inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index e43e5f465361d5..ef4fc47567a7c4 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -473,6 +473,63 @@ enum class TagUseKind { Friend // Friend declaration: 'friend struct foo;' }; +/// Used with attributes/effects with a boolean condition, e.g. `nonblocking`. +enum class FunctionEffectMode : uint8_t { + None, // effect is not present. + False, // effect(false). + True, // effect(true). + Dependent // effect(expr) where expr is dependent. +}; + +struct FunctionEffectDiff { + enum class Kind { Added, Removed, ConditionMismatch }; + + FunctionEffect::Kind EffectKind; + Kind DiffKind; + FunctionEffectWithCondition Old; // invalid when Added. + FunctionEffectWithCondition New; // invalid when Removed. + + StringRef effectName() const { + if (Old.Effect.kind() != FunctionEffect::Kind::None) + return Old.Effect.name(); + return New.Effect.name(); + } + + /// Describes the result of effects differing between a base class's virtual + /// method and an overriding method in a subclass. + enum class OverrideResult { + NoAction, + Warn, + Merge // Merge missing effect from base to derived. + }; + + /// Return true if adding or removing the effect as part of a type conversion + /// should generate a diagnostic. + bool shouldDiagnoseConversion(QualType SrcType, + const FunctionEffectsRef &SrcFX, + QualType DstType, + const FunctionEffectsRef &DstFX) const; + + /// Return true if adding or removing the effect in a redeclaration should + /// generate a diagnostic. + bool shouldDiagnoseRedeclaration(const FunctionDecl &OldFunction, + const FunctionEffectsRef &OldFX, + const FunctionDecl &NewFunction, + const FunctionEffectsRef &NewFX) const; + + /// Return true if adding or removing the effect in a C++ virtual method + /// override should generate a diagnostic. + OverrideResult shouldDiagnoseMethodOverride( + const CXXMethodDecl &OldMethod, const FunctionEffectsRef &OldFX, + const CXXMethodDecl &NewMethod, const FunctionEffectsRef &NewFX) const; +}; + +struct FunctionEffectDifferences : public SmallVector { + /// Caller should short-circuit by checking for equality first. + FunctionEffectDifferences(const FunctionEffectsRef &Old, + const FunctionEffectsRef &New); +}; + /// Sema - This implements semantic analysis and AST building for C. /// \nosubgrouping class Sema final : public SemaBase { @@ -783,6 +840,28 @@ class Sema final : public SemaBase { /// Warn when implicitly casting 0 to nullptr. void diagnoseZeroToNullptrConversion(CastKind Kind, const Expr *E); + // ----- function effects --- + + /// Warn when implicitly changing function effects. + void diagnoseFunctionEffectConversion(QualType DstType, QualType SrcType, + SourceLocation Loc); + + /// Warn and return true if adding an effect to a set would create a conflict. + bool diagnoseConflictingFunctionEffect(const FunctionEffectsRef &FX, + const FunctionEffectWithCondition &EC, + SourceLocation NewAttrLoc); + + void + diagnoseFunctionEffectMergeConflicts(const FunctionEffectSet::Conflicts &Errs, + SourceLocation NewLoc, + SourceLocation OldLoc); + + /// Try to parse the conditional expression attached to an effect attribute + /// (e.g. 'nonblocking'). (c.f. Sema::ActOnNoexceptSpec). Return an empty + /// optional on error. + std::optional + ActOnEffectExpression(Expr *CondExpr, StringRef AttributeName); + bool makeUnavailableInSystemHeader(SourceLocation loc, UnavailableAttr::ImplicitReason reason); @@ -2035,8 +2114,6 @@ class Sema final : public SemaBase { bool FormatStringHasSArg(const StringLiteral *FExpr); - static bool GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx); - void CheckFloatComparison(SourceLocation Loc, Expr *LHS, Expr *RHS, BinaryOperatorKind Opcode); @@ -2149,8 +2226,6 @@ class Sema final : public SemaBase { bool BuiltinVectorMath(CallExpr *TheCall, QualType &Res); bool BuiltinVectorToScalarMath(CallExpr *TheCall); - bool CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); - void checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, const Expr *ThisArg, ArrayRef Args, bool IsMemberFunction, SourceLocation Loc, SourceRange Range, @@ -2180,6 +2255,14 @@ class Sema final : public SemaBase { bool ValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum); + void CheckImplicitConversion(Expr *E, QualType T, SourceLocation CC, + bool *ICContext = nullptr, + bool IsListInit = false); + + bool BuiltinElementwiseTernaryMath(CallExpr *TheCall, + bool CheckForFloatArgs = true); + bool PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall); + private: void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, const ArraySubscriptExpr *ASE = nullptr, @@ -2227,9 +2310,6 @@ class Sema final : public SemaBase { AtomicExpr::AtomicOp Op); bool BuiltinElementwiseMath(CallExpr *TheCall); - bool BuiltinElementwiseTernaryMath(CallExpr *TheCall, - bool CheckForFloatArgs = true); - bool PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall); bool PrepareBuiltinReduceMathOneArgCall(CallExpr *TheCall); bool BuiltinNonDeterministicValue(CallExpr *TheCall); @@ -4487,6 +4567,10 @@ class Sema final : public SemaBase { /// conditions that are needed for the attribute to have an effect. void checkIllFormedTrivialABIStruct(CXXRecordDecl &RD); + /// Check that VTable Pointer authentication is only being set on the first + /// first instantiation of the vtable + void checkIncorrectVTablePointerAuthenticationAttribute(CXXRecordDecl &RD); + void ActOnFinishCXXMemberSpecification(Scope *S, SourceLocation RLoc, Decl *TagDecl, SourceLocation LBrac, SourceLocation RBrac, @@ -4612,7 +4696,7 @@ class Sema final : public SemaBase { std::string getAmbiguousPathsDisplayString(CXXBasePaths &Paths); - bool CheckOverridingFunctionAttributes(const CXXMethodDecl *New, + bool CheckOverridingFunctionAttributes(CXXMethodDecl *New, const CXXMethodDecl *Old); /// CheckOverridingFunctionReturnType - Checks whether the return types are diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index 0e41a72e444ef4..4d6958a1be3e5b 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -58,6 +58,8 @@ class SemaHLSL : public SemaBase { void handleShaderAttr(Decl *D, const ParsedAttr &AL); void handleResourceBindingAttr(Decl *D, const ParsedAttr &AL); void handleParamModifierAttr(Decl *D, const ParsedAttr &AL); + + bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); }; } // namespace clang diff --git a/clang/include/clang/Sema/SemaObjC.h b/clang/include/clang/Sema/SemaObjC.h index bb8887691ce5d3..07c3c1a06be160 100644 --- a/clang/include/clang/Sema/SemaObjC.h +++ b/clang/include/clang/Sema/SemaObjC.h @@ -158,6 +158,27 @@ class SemaObjC : public SemaBase { IdentifierInfo *getNSErrorIdent(); + bool GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx); + + /// Diagnose use of %s directive in an NSString which is being passed + /// as formatting string to formatting method. + void DiagnoseCStringFormatDirectiveInCFAPI(const NamedDecl *FDecl, + Expr **Args, unsigned NumArgs); + + bool isSignedCharBool(QualType Ty); + + void adornBoolConversionDiagWithTernaryFixit( + Expr *SourceExpr, const Sema::SemaDiagnosticBuilder &Builder); + + /// Check an Objective-C dictionary literal being converted to the given + /// target type. + void checkDictionaryLiteral(QualType TargetType, + ObjCDictionaryLiteral *DictionaryLiteral); + + /// Check an Objective-C array literal being converted to the given + /// target type. + void checkArrayLiteral(QualType TargetType, ObjCArrayLiteral *ArrayLiteral); + private: IdentifierInfo *Ident_NSError = nullptr; diff --git a/clang/include/clang/Sema/SemaOpenCL.h b/clang/include/clang/Sema/SemaOpenCL.h index 0d80c4b4c0b561..7d6b4b0dec09c2 100644 --- a/clang/include/clang/Sema/SemaOpenCL.h +++ b/clang/include/clang/Sema/SemaOpenCL.h @@ -28,6 +28,78 @@ class SemaOpenCL : public SemaBase { // Handles intel_reqd_sub_group_size. void handleSubGroupSize(Decl *D, const ParsedAttr &AL); + + // Performs semantic analysis for the read/write_pipe call. + // \param S Reference to the semantic analyzer. + // \param Call A pointer to the builtin call. + // \return True if a semantic error has been found, false otherwise. + bool checkBuiltinRWPipe(CallExpr *Call); + + // Performs a semantic analysis on the {work_group_/sub_group_ + // /_}reserve_{read/write}_pipe + // \param S Reference to the semantic analyzer. + // \param Call The call to the builtin function to be analyzed. + // \return True if a semantic error was found, false otherwise. + bool checkBuiltinReserveRWPipe(CallExpr *Call); + + bool checkSubgroupExt(CallExpr *Call); + + // Performs a semantic analysis on {work_group_/sub_group_ + // /_}commit_{read/write}_pipe + // \param S Reference to the semantic analyzer. + // \param Call The call to the builtin function to be analyzed. + // \return True if a semantic error was found, false otherwise. + bool checkBuiltinCommitRWPipe(CallExpr *Call); + + // Performs a semantic analysis on the call to built-in Pipe + // Query Functions. + // \param S Reference to the semantic analyzer. + // \param Call The call to the builtin function to be analyzed. + // \return True if a semantic error was found, false otherwise. + bool checkBuiltinPipePackets(CallExpr *Call); + + // OpenCL v2.0 s6.13.9 - Address space qualifier functions. + // Performs semantic analysis for the to_global/local/private call. + // \param S Reference to the semantic analyzer. + // \param BuiltinID ID of the builtin function. + // \param Call A pointer to the builtin call. + // \return True if a semantic error has been found, false otherwise. + bool checkBuiltinToAddr(unsigned BuiltinID, CallExpr *Call); + + /// OpenCL C v2.0, s6.13.17 - Enqueue kernel function contains four different + /// overload formats specified in Table 6.13.17.1. + /// int enqueue_kernel(queue_t queue, + /// kernel_enqueue_flags_t flags, + /// const ndrange_t ndrange, + /// void (^block)(void)) + /// int enqueue_kernel(queue_t queue, + /// kernel_enqueue_flags_t flags, + /// const ndrange_t ndrange, + /// uint num_events_in_wait_list, + /// clk_event_t *event_wait_list, + /// clk_event_t *event_ret, + /// void (^block)(void)) + /// int enqueue_kernel(queue_t queue, + /// kernel_enqueue_flags_t flags, + /// const ndrange_t ndrange, + /// void (^block)(local void*, ...), + /// uint size0, ...) + /// int enqueue_kernel(queue_t queue, + /// kernel_enqueue_flags_t flags, + /// const ndrange_t ndrange, + /// uint num_events_in_wait_list, + /// clk_event_t *event_wait_list, + /// clk_event_t *event_ret, + /// void (^block)(local void*, ...), + /// uint size0, ...) + bool checkBuiltinEnqueueKernel(CallExpr *TheCall); + + /// OpenCL C v2.0, s6.13.17.6 - Check the argument to the + /// get_kernel_work_group_size + /// and get_kernel_preferred_work_group_size_multiple builtin functions. + bool checkBuiltinKernelWorkGroupSize(CallExpr *TheCall); + + bool checkBuiltinNDRangeAndBlock(CallExpr *TheCall); }; } // namespace clang diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index 429c334a0b24b2..6e224a4e098ad2 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -686,22 +686,11 @@ def MoveChecker: Checker<"Move">, CheckerOptions<[ CmdLineOption ]>, diff --git a/clang/include/clang/Tooling/Transformer/RangeSelector.h b/clang/include/clang/Tooling/Transformer/RangeSelector.h index 1e288043f0a8e5..462a9da8f10ebb 100644 --- a/clang/include/clang/Tooling/Transformer/RangeSelector.h +++ b/clang/include/clang/Tooling/Transformer/RangeSelector.h @@ -86,6 +86,11 @@ RangeSelector name(std::string ID); // source between the call's parentheses). RangeSelector callArgs(std::string ID); +// Given a \c CXXConstructExpr (bound to \p ID), selects the +// arguments' source text. Depending on the syntactic form of the construct, +// this is the range between parentheses or braces. +RangeSelector constructExprArgs(std::string ID); + // Given a \c CompoundStmt (bound to \p ID), selects the source of the // statements (all source between the braces). RangeSelector statements(std::string ID); diff --git a/clang/include/module.modulemap b/clang/include/module.modulemap index acd960c9c932ac..00ecd47d35b623 100644 --- a/clang/include/module.modulemap +++ b/clang/include/module.modulemap @@ -37,19 +37,20 @@ module Clang_Basic { umbrella "clang/Basic" textual header "clang/Basic/AArch64SVEACLETypes.def" + textual header "clang/Basic/AMDGPUTypes.def" + textual header "clang/Basic/BuiltinHeaders.def" textual header "clang/Basic/BuiltinsAArch64.def" - textual header "clang/Basic/BuiltinsAMDGPU.def" textual header "clang/Basic/BuiltinsAArch64NeonSVEBridge.def" textual header "clang/Basic/BuiltinsAArch64NeonSVEBridge_cg.def" + textual header "clang/Basic/BuiltinsAMDGPU.def" textual header "clang/Basic/BuiltinsARM.def" - textual header "clang/Basic/BuiltinHeaders.def" textual header "clang/Basic/BuiltinsHexagon.def" textual header "clang/Basic/BuiltinsHexagonDep.def" textual header "clang/Basic/BuiltinsHexagonMapCustomDep.def" textual header "clang/Basic/BuiltinsLoongArch.def" textual header "clang/Basic/BuiltinsLoongArchBase.def" - textual header "clang/Basic/BuiltinsLoongArchLSX.def" textual header "clang/Basic/BuiltinsLoongArchLASX.def" + textual header "clang/Basic/BuiltinsLoongArchLSX.def" textual header "clang/Basic/BuiltinsMips.def" textual header "clang/Basic/BuiltinsNEON.def" textual header "clang/Basic/BuiltinsNVPTX.def" @@ -67,13 +68,14 @@ module Clang_Basic { textual header "clang/Basic/CodeGenOptions.def" textual header "clang/Basic/DebugOptions.def" textual header "clang/Basic/DiagnosticOptions.def" - textual header "clang/Basic/Features.def" textual header "clang/Basic/FPOptions.def" - textual header "clang/Basic/MSP430Target.def" + textual header "clang/Basic/Features.def" textual header "clang/Basic/LangOptions.def" + textual header "clang/Basic/MSP430Target.def" + textual header "clang/Basic/OpenACCClauses.def" + textual header "clang/Basic/OpenCLExtensionTypes.def" textual header "clang/Basic/OpenCLExtensions.def" textual header "clang/Basic/OpenCLImageTypes.def" - textual header "clang/Basic/OpenCLExtensionTypes.def" textual header "clang/Basic/OpenMPKinds.def" textual header "clang/Basic/OperatorKinds.def" textual header "clang/Basic/PPCTypes.def" @@ -81,8 +83,8 @@ module Clang_Basic { textual header "clang/Basic/Sanitizers.def" textual header "clang/Basic/TargetCXXABI.def" textual header "clang/Basic/TargetOSMacros.def" - textual header "clang/Basic/TransformTypeTraits.def" textual header "clang/Basic/TokenKinds.def" + textual header "clang/Basic/TransformTypeTraits.def" textual header "clang/Basic/WebAssemblyReferenceTypes.def" module * { export * } diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index fca200988fea19..84deaf5429df75 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -86,6 +86,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MD5.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/SipHash.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TargetParser/AArch64TargetParser.h" #include "llvm/TargetParser/Triple.h" @@ -1110,6 +1111,31 @@ void ASTContext::setCurrentNamedModule(Module *M) { CurrentCXXNamedModule = M; } +bool ASTContext::isInSameModule(const Module *M1, const Module *M2) { + if (!M1 != !M2) + return false; + + /// Get the representative module for M. The representative module is the + /// first module unit for a specific primary module name. So that the module + /// units have the same representative module belongs to the same module. + /// + /// The process is helpful to reduce the expensive string operations. + auto GetRepresentativeModule = [this](const Module *M) { + auto Iter = SameModuleLookupSet.find(M); + if (Iter != SameModuleLookupSet.end()) + return Iter->second; + + const Module *RepresentativeModule = + PrimaryModuleNameMap.try_emplace(M->getPrimaryModuleInterfaceName(), M) + .first->second; + SameModuleLookupSet[M] = RepresentativeModule; + return RepresentativeModule; + }; + + assert(M1 && "Shouldn't call `isInSameModule` if both M1 and M2 are none."); + return GetRepresentativeModule(M1) == GetRepresentativeModule(M2); +} + ExternCContextDecl *ASTContext::getExternCContextDecl() const { if (!ExternCContext) ExternCContext = ExternCContextDecl::Create(*this, getTranslationUnitDecl()); @@ -3103,6 +3129,17 @@ QualType ASTContext::removeAddrSpaceQualType(QualType T) const { return QualType(TypeNode, Quals.getFastQualifiers()); } +uint16_t +ASTContext::getPointerAuthVTablePointerDiscriminator(const CXXRecordDecl *RD) { + assert(RD->isPolymorphic() && + "Attempted to get vtable pointer discriminator on a monomorphic type"); + std::unique_ptr MC(createMangleContext()); + SmallString<256> Str; + llvm::raw_svector_ostream Out(Str); + MC->mangleCXXVTable(RD, Out); + return llvm::getPointerAuthStableSipHash(Str); +} + QualType ASTContext::getObjCGCQualType(QualType T, Qualifiers::GC GCAttr) const { QualType CanT = getCanonicalType(T); @@ -4576,11 +4613,13 @@ QualType ASTContext::getFunctionTypeInternal( size_t Size = FunctionProtoType::totalSizeToAlloc< QualType, SourceLocation, FunctionType::FunctionTypeExtraBitfields, FunctionType::FunctionTypeArmAttributes, FunctionType::ExceptionType, - Expr *, FunctionDecl *, FunctionProtoType::ExtParameterInfo, Qualifiers>( + Expr *, FunctionDecl *, FunctionProtoType::ExtParameterInfo, + FunctionEffect, EffectConditionExpr, Qualifiers>( NumArgs, EPI.Variadic, EPI.requiresFunctionProtoTypeExtraBitfields(), EPI.requiresFunctionProtoTypeArmAttributes(), ESH.NumExceptionType, ESH.NumExprPtr, ESH.NumFunctionDeclPtr, - EPI.ExtParameterInfos ? NumArgs : 0, + EPI.ExtParameterInfos ? NumArgs : 0, EPI.FunctionEffects.size(), + EPI.FunctionEffects.conditions().size(), EPI.TypeQuals.hasNonFastQualifiers() ? 1 : 0); auto *FTP = (FunctionProtoType *)Allocate(Size, alignof(FunctionProtoType)); @@ -10525,6 +10564,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, FunctionType::ExtInfo einfo = lbaseInfo.withNoReturn(NoReturn); + std::optional MergedFX; + if (lproto && rproto) { // two C99 style function prototypes assert((AllowCXX || (!lproto->hasExceptionSpec() && !rproto->hasExceptionSpec())) && @@ -10540,6 +10581,25 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, if (lproto->getMethodQuals() != rproto->getMethodQuals()) return {}; + // Function effects are handled similarly to noreturn, see above. + FunctionEffectsRef LHSFX = lproto->getFunctionEffects(); + FunctionEffectsRef RHSFX = rproto->getFunctionEffects(); + if (LHSFX != RHSFX) { + if (IsConditionalOperator) + MergedFX = FunctionEffectSet::getIntersection(LHSFX, RHSFX); + else { + FunctionEffectSet::Conflicts Errs; + MergedFX = FunctionEffectSet::getUnion(LHSFX, RHSFX, Errs); + // Here we're discarding a possible error due to conflicts in the effect + // sets. But we're not in a context where we can report it. The + // operation does however guarantee maintenance of invariants. + } + if (*MergedFX != LHSFX) + allLTypes = false; + if (*MergedFX != RHSFX) + allRTypes = false; + } + SmallVector newParamInfos; bool canUseLeft, canUseRight; if (!mergeExtParameterInfo(lproto, rproto, canUseLeft, canUseRight, @@ -10583,6 +10643,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, EPI.ExtInfo = einfo; EPI.ExtParameterInfos = newParamInfos.empty() ? nullptr : newParamInfos.data(); + if (MergedFX) + EPI.FunctionEffects = *MergedFX; return getFunctionType(retType, types, EPI); } @@ -10620,6 +10682,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, FunctionProtoType::ExtProtoInfo EPI = proto->getExtProtoInfo(); EPI.ExtInfo = einfo; + if (MergedFX) + EPI.FunctionEffects = *MergedFX; return getFunctionType(retType, proto->getParamTypes(), EPI); } @@ -13842,3 +13906,74 @@ StringRef ASTContext::getCUIDHash() const { CUIDHash = llvm::utohexstr(llvm::MD5Hash(LangOpts.CUID), /*LowerCase=*/true); return CUIDHash; } + +const CXXRecordDecl * +ASTContext::baseForVTableAuthentication(const CXXRecordDecl *ThisClass) { + assert(ThisClass); + assert(ThisClass->isPolymorphic()); + const CXXRecordDecl *PrimaryBase = ThisClass; + while (1) { + assert(PrimaryBase); + assert(PrimaryBase->isPolymorphic()); + auto &Layout = getASTRecordLayout(PrimaryBase); + auto Base = Layout.getPrimaryBase(); + if (!Base || Base == PrimaryBase || !Base->isPolymorphic()) + break; + PrimaryBase = Base; + } + return PrimaryBase; +} + +bool ASTContext::useAbbreviatedThunkName(GlobalDecl VirtualMethodDecl, + StringRef MangledName) { + auto *Method = cast(VirtualMethodDecl.getDecl()); + assert(Method->isVirtual()); + bool DefaultIncludesPointerAuth = + LangOpts.PointerAuthCalls || LangOpts.PointerAuthIntrinsics; + + if (!DefaultIncludesPointerAuth) + return true; + + auto Existing = ThunksToBeAbbreviated.find(VirtualMethodDecl); + if (Existing != ThunksToBeAbbreviated.end()) + return Existing->second.contains(MangledName.str()); + + std::unique_ptr Mangler(createMangleContext()); + llvm::StringMap> Thunks; + auto VtableContext = getVTableContext(); + if (const auto *ThunkInfos = VtableContext->getThunkInfo(VirtualMethodDecl)) { + auto *Destructor = dyn_cast(Method); + for (const auto &Thunk : *ThunkInfos) { + SmallString<256> ElidedName; + llvm::raw_svector_ostream ElidedNameStream(ElidedName); + if (Destructor) + Mangler->mangleCXXDtorThunk(Destructor, VirtualMethodDecl.getDtorType(), + Thunk, /* elideOverrideInfo */ true, + ElidedNameStream); + else + Mangler->mangleThunk(Method, Thunk, /* elideOverrideInfo */ true, + ElidedNameStream); + SmallString<256> MangledName; + llvm::raw_svector_ostream mangledNameStream(MangledName); + if (Destructor) + Mangler->mangleCXXDtorThunk(Destructor, VirtualMethodDecl.getDtorType(), + Thunk, /* elideOverrideInfo */ false, + mangledNameStream); + else + Mangler->mangleThunk(Method, Thunk, /* elideOverrideInfo */ false, + mangledNameStream); + + if (Thunks.find(ElidedName) == Thunks.end()) + Thunks[ElidedName] = {}; + Thunks[ElidedName].push_back(std::string(MangledName)); + } + } + llvm::StringSet<> SimplifiedThunkNames; + for (auto &ThunkList : Thunks) { + llvm::sort(ThunkList.second); + SimplifiedThunkNames.insert(ThunkList.second[0]); + } + bool Result = SimplifiedThunkNames.contains(MangledName); + ThunksToBeAbbreviated[VirtualMethodDecl] = std::move(SimplifiedThunkNames); + return Result; +} diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp index f0603880c32dde..864d0393f9a78e 100644 --- a/clang/lib/AST/ASTDumper.cpp +++ b/clang/lib/AST/ASTDumper.cpp @@ -342,8 +342,7 @@ LLVM_DUMP_METHOD void APValue::dump() const { LLVM_DUMP_METHOD void APValue::dump(raw_ostream &OS, const ASTContext &Context) const { - ASTDumper Dumper(llvm::errs(), Context, - Context.getDiagnostics().getShowColors()); + ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors()); Dumper.Visit(*this, /*Ty=*/Context.getPointerType(Context.CharTy)); } diff --git a/clang/lib/AST/CMakeLists.txt b/clang/lib/AST/CMakeLists.txt index 0328666d59b1fc..ceaad8d3c5a865 100644 --- a/clang/lib/AST/CMakeLists.txt +++ b/clang/lib/AST/CMakeLists.txt @@ -65,8 +65,7 @@ add_clang_library(clangAST FormatString.cpp InheritViz.cpp Interp/ByteCodeEmitter.cpp - Interp/ByteCodeExprGen.cpp - Interp/ByteCodeStmtGen.cpp + Interp/Compiler.cpp Interp/Context.cpp Interp/Descriptor.cpp Interp/Disasm.cpp diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 9d0a835a12c458..16ed6d88d1cb1e 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1614,7 +1614,7 @@ LinkageInfo LinkageComputer::getDeclLinkageAndVisibility(const NamedDecl *D) { : CK); } -Module *Decl::getOwningModuleForLinkage(bool IgnoreLinkage) const { +Module *Decl::getOwningModuleForLinkage() const { if (isa(this)) // Namespaces never have module linkage. It is the entities within them // that [may] do. @@ -1637,24 +1637,9 @@ Module *Decl::getOwningModuleForLinkage(bool IgnoreLinkage) const { case Module::ModuleHeaderUnit: case Module::ExplicitGlobalModuleFragment: - case Module::ImplicitGlobalModuleFragment: { - // External linkage declarations in the global module have no owning module - // for linkage purposes. But internal linkage declarations in the global - // module fragment of a particular module are owned by that module for - // linkage purposes. - // FIXME: p1815 removes the need for this distinction -- there are no - // internal linkage declarations that need to be referred to from outside - // this TU. - if (IgnoreLinkage) - return nullptr; - bool InternalLinkage; - if (auto *ND = dyn_cast(this)) - InternalLinkage = !ND->hasExternalFormalLinkage(); - else - InternalLinkage = isInAnonymousNamespace(); - return InternalLinkage ? M->Kind == Module::ModuleHeaderUnit ? M : M->Parent - : nullptr; - } + case Module::ImplicitGlobalModuleFragment: + // The global module shouldn't change the linkage. + return nullptr; case Module::PrivateModuleFragment: // The private module fragment is part of its containing module for linkage diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 0cf4e64f83b8df..26773a69ab9acf 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -1187,6 +1187,13 @@ void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params, } Out << '>'; + + if (const Expr *RequiresClause = Params->getRequiresClause()) { + Out << " requires "; + RequiresClause->printPretty(Out, nullptr, Policy, Indentation, "\n", + &Context); + } + if (!OmitTemplateKW) Out << ' '; } diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index fe4b9a569ab874..374a3acf7aa26f 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -1885,7 +1885,8 @@ static bool EvaluateAtomic(const Expr *E, const LValue *This, APValue &Result, EvalInfo &Info); static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result); static bool EvaluateBuiltinStrLen(const Expr *E, uint64_t &Result, - EvalInfo &Info); + EvalInfo &Info, + std::string *StringResult = nullptr); /// Evaluate an integer or fixed point expression into an APResult. static bool EvaluateFixedPointOrInteger(const Expr *E, APFixedPoint &Result, @@ -17009,7 +17010,7 @@ bool Expr::tryEvaluateObjectSize(uint64_t &Result, ASTContext &Ctx, } static bool EvaluateBuiltinStrLen(const Expr *E, uint64_t &Result, - EvalInfo &Info) { + EvalInfo &Info, std::string *StringResult) { if (!E->getType()->hasPointerRepresentation() || !E->isPRValue()) return false; @@ -17036,6 +17037,8 @@ static bool EvaluateBuiltinStrLen(const Expr *E, uint64_t &Result, Str = Str.substr(0, Pos); Result = Str.size(); + if (StringResult) + *StringResult = Str; return true; } @@ -17051,12 +17054,24 @@ static bool EvaluateBuiltinStrLen(const Expr *E, uint64_t &Result, if (!Char.getInt()) { Result = Strlen; return true; - } + } else if (StringResult) + StringResult->push_back(Char.getInt().getExtValue()); if (!HandleLValueArrayAdjustment(Info, E, String, CharTy, 1)) return false; } } +std::optional Expr::tryEvaluateString(ASTContext &Ctx) const { + Expr::EvalStatus Status; + EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantFold); + uint64_t Result; + std::string StringResult; + + if (EvaluateBuiltinStrLen(this, Result, Info, &StringResult)) + return StringResult; + return {}; +} + bool Expr::EvaluateCharRangeAsString(std::string &Result, const Expr *SizeExpression, const Expr *PtrExpression, ASTContext &Ctx, diff --git a/clang/lib/AST/Interp/ByteCodeEmitter.h b/clang/lib/AST/Interp/ByteCodeEmitter.h index d797a0ab4a1c9d..9a329e969f339c 100644 --- a/clang/lib/AST/Interp/ByteCodeEmitter.h +++ b/clang/lib/AST/Interp/ByteCodeEmitter.h @@ -54,6 +54,9 @@ class ByteCodeEmitter { bool jump(const LabelTy &Label); bool fallthrough(const LabelTy &Label); + /// We're always emitting bytecode. + bool isActive() const { return true; } + /// Callback for local registration. Local createLocal(Descriptor *D); diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp deleted file mode 100644 index 0618ec1aa8f584..00000000000000 --- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp +++ /dev/null @@ -1,734 +0,0 @@ -//===--- ByteCodeStmtGen.cpp - Code generator for expressions ---*- 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 -// -//===----------------------------------------------------------------------===// - -#include "ByteCodeStmtGen.h" -#include "ByteCodeEmitter.h" -#include "Context.h" -#include "Function.h" -#include "PrimType.h" - -using namespace clang; -using namespace clang::interp; - -namespace clang { -namespace interp { - -/// Scope managing label targets. -template class LabelScope { -public: - virtual ~LabelScope() { } - -protected: - LabelScope(ByteCodeStmtGen *Ctx) : Ctx(Ctx) {} - /// ByteCodeStmtGen instance. - ByteCodeStmtGen *Ctx; -}; - -/// Sets the context for break/continue statements. -template class LoopScope final : public LabelScope { -public: - using LabelTy = typename ByteCodeStmtGen::LabelTy; - using OptLabelTy = typename ByteCodeStmtGen::OptLabelTy; - - LoopScope(ByteCodeStmtGen *Ctx, LabelTy BreakLabel, - LabelTy ContinueLabel) - : LabelScope(Ctx), OldBreakLabel(Ctx->BreakLabel), - OldContinueLabel(Ctx->ContinueLabel) { - this->Ctx->BreakLabel = BreakLabel; - this->Ctx->ContinueLabel = ContinueLabel; - } - - ~LoopScope() { - this->Ctx->BreakLabel = OldBreakLabel; - this->Ctx->ContinueLabel = OldContinueLabel; - } - -private: - OptLabelTy OldBreakLabel; - OptLabelTy OldContinueLabel; -}; - -// Sets the context for a switch scope, mapping labels. -template class SwitchScope final : public LabelScope { -public: - using LabelTy = typename ByteCodeStmtGen::LabelTy; - using OptLabelTy = typename ByteCodeStmtGen::OptLabelTy; - using CaseMap = typename ByteCodeStmtGen::CaseMap; - - SwitchScope(ByteCodeStmtGen *Ctx, CaseMap &&CaseLabels, - LabelTy BreakLabel, OptLabelTy DefaultLabel) - : LabelScope(Ctx), OldBreakLabel(Ctx->BreakLabel), - OldDefaultLabel(this->Ctx->DefaultLabel), - OldCaseLabels(std::move(this->Ctx->CaseLabels)) { - this->Ctx->BreakLabel = BreakLabel; - this->Ctx->DefaultLabel = DefaultLabel; - this->Ctx->CaseLabels = std::move(CaseLabels); - } - - ~SwitchScope() { - this->Ctx->BreakLabel = OldBreakLabel; - this->Ctx->DefaultLabel = OldDefaultLabel; - this->Ctx->CaseLabels = std::move(OldCaseLabels); - } - -private: - OptLabelTy OldBreakLabel; - OptLabelTy OldDefaultLabel; - CaseMap OldCaseLabels; -}; - -} // namespace interp -} // namespace clang - -template -bool ByteCodeStmtGen::emitLambdaStaticInvokerBody( - const CXXMethodDecl *MD) { - assert(MD->isLambdaStaticInvoker()); - assert(MD->hasBody()); - assert(cast(MD->getBody())->body_empty()); - - const CXXRecordDecl *ClosureClass = MD->getParent(); - const CXXMethodDecl *LambdaCallOp = ClosureClass->getLambdaCallOperator(); - assert(ClosureClass->captures_begin() == ClosureClass->captures_end()); - const Function *Func = this->getFunction(LambdaCallOp); - if (!Func) - return false; - assert(Func->hasThisPointer()); - assert(Func->getNumParams() == (MD->getNumParams() + 1 + Func->hasRVO())); - - if (Func->hasRVO()) { - if (!this->emitRVOPtr(MD)) - return false; - } - - // The lambda call operator needs an instance pointer, but we don't have - // one here, and we don't need one either because the lambda cannot have - // any captures, as verified above. Emit a null pointer. This is then - // special-cased when interpreting to not emit any misleading diagnostics. - if (!this->emitNullPtr(nullptr, MD)) - return false; - - // Forward all arguments from the static invoker to the lambda call operator. - for (const ParmVarDecl *PVD : MD->parameters()) { - auto It = this->Params.find(PVD); - assert(It != this->Params.end()); - - // We do the lvalue-to-rvalue conversion manually here, so no need - // to care about references. - PrimType ParamType = this->classify(PVD->getType()).value_or(PT_Ptr); - if (!this->emitGetParam(ParamType, It->second.Offset, MD)) - return false; - } - - if (!this->emitCall(Func, 0, LambdaCallOp)) - return false; - - this->emitCleanup(); - if (ReturnType) - return this->emitRet(*ReturnType, MD); - - // Nothing to do, since we emitted the RVO pointer above. - return this->emitRetVoid(MD); -} - -template -bool ByteCodeStmtGen::visitFunc(const FunctionDecl *F) { - // Classify the return type. - ReturnType = this->classify(F->getReturnType()); - - auto emitFieldInitializer = [&](const Record::Field *F, unsigned FieldOffset, - const Expr *InitExpr) -> bool { - // We don't know what to do with these, so just return false. - if (InitExpr->getType().isNull()) - return false; - - if (std::optional T = this->classify(InitExpr)) { - if (!this->visit(InitExpr)) - return false; - - if (F->isBitField()) - return this->emitInitThisBitField(*T, F, FieldOffset, InitExpr); - return this->emitInitThisField(*T, FieldOffset, InitExpr); - } - - // Non-primitive case. Get a pointer to the field-to-initialize - // on the stack and call visitInitialzer() for it. - InitLinkScope FieldScope(this, InitLink::Field(F->Offset)); - if (!this->emitGetPtrThisField(FieldOffset, InitExpr)) - return false; - - if (!this->visitInitializer(InitExpr)) - return false; - - return this->emitPopPtr(InitExpr); - }; - - // Emit custom code if this is a lambda static invoker. - if (const auto *MD = dyn_cast(F); - MD && MD->isLambdaStaticInvoker()) - return this->emitLambdaStaticInvokerBody(MD); - - // Constructor. Set up field initializers. - if (const auto *Ctor = dyn_cast(F)) { - const RecordDecl *RD = Ctor->getParent(); - const Record *R = this->getRecord(RD); - if (!R) - return false; - - InitLinkScope InitScope(this, InitLink::This()); - for (const auto *Init : Ctor->inits()) { - // Scope needed for the initializers. - BlockScope Scope(this); - - const Expr *InitExpr = Init->getInit(); - if (const FieldDecl *Member = Init->getMember()) { - const Record::Field *F = R->getField(Member); - - if (!emitFieldInitializer(F, F->Offset, InitExpr)) - return false; - } else if (const Type *Base = Init->getBaseClass()) { - const auto *BaseDecl = Base->getAsCXXRecordDecl(); - assert(BaseDecl); - - if (Init->isBaseVirtual()) { - assert(R->getVirtualBase(BaseDecl)); - if (!this->emitGetPtrThisVirtBase(BaseDecl, InitExpr)) - return false; - - } else { - // Base class initializer. - // Get This Base and call initializer on it. - const Record::Base *B = R->getBase(BaseDecl); - assert(B); - if (!this->emitGetPtrThisBase(B->Offset, InitExpr)) - return false; - } - - if (!this->visitInitializer(InitExpr)) - return false; - if (!this->emitFinishInitPop(InitExpr)) - return false; - } else if (const IndirectFieldDecl *IFD = Init->getIndirectMember()) { - assert(IFD->getChainingSize() >= 2); - - unsigned NestedFieldOffset = 0; - const Record::Field *NestedField = nullptr; - for (const NamedDecl *ND : IFD->chain()) { - const auto *FD = cast(ND); - const Record *FieldRecord = - this->P.getOrCreateRecord(FD->getParent()); - assert(FieldRecord); - - NestedField = FieldRecord->getField(FD); - assert(NestedField); - - NestedFieldOffset += NestedField->Offset; - } - assert(NestedField); - - if (!emitFieldInitializer(NestedField, NestedFieldOffset, InitExpr)) - return false; - } else { - assert(Init->isDelegatingInitializer()); - if (!this->emitThis(InitExpr)) - return false; - if (!this->visitInitializer(Init->getInit())) - return false; - if (!this->emitPopPtr(InitExpr)) - return false; - } - } - } - - if (const auto *Body = F->getBody()) - if (!visitStmt(Body)) - return false; - - // Emit a guard return to protect against a code path missing one. - if (F->getReturnType()->isVoidType()) - return this->emitRetVoid(SourceInfo{}); - else - return this->emitNoRet(SourceInfo{}); -} - -template -bool ByteCodeStmtGen::visitStmt(const Stmt *S) { - switch (S->getStmtClass()) { - case Stmt::CompoundStmtClass: - return visitCompoundStmt(cast(S)); - case Stmt::DeclStmtClass: - return visitDeclStmt(cast(S)); - case Stmt::ReturnStmtClass: - return visitReturnStmt(cast(S)); - case Stmt::IfStmtClass: - return visitIfStmt(cast(S)); - case Stmt::WhileStmtClass: - return visitWhileStmt(cast(S)); - case Stmt::DoStmtClass: - return visitDoStmt(cast(S)); - case Stmt::ForStmtClass: - return visitForStmt(cast(S)); - case Stmt::CXXForRangeStmtClass: - return visitCXXForRangeStmt(cast(S)); - case Stmt::BreakStmtClass: - return visitBreakStmt(cast(S)); - case Stmt::ContinueStmtClass: - return visitContinueStmt(cast(S)); - case Stmt::SwitchStmtClass: - return visitSwitchStmt(cast(S)); - case Stmt::CaseStmtClass: - return visitCaseStmt(cast(S)); - case Stmt::DefaultStmtClass: - return visitDefaultStmt(cast(S)); - case Stmt::AttributedStmtClass: - return visitAttributedStmt(cast(S)); - case Stmt::CXXTryStmtClass: - return visitCXXTryStmt(cast(S)); - case Stmt::NullStmtClass: - return true; - // Always invalid statements. - case Stmt::GCCAsmStmtClass: - case Stmt::MSAsmStmtClass: - case Stmt::GotoStmtClass: - return this->emitInvalid(S); - case Stmt::LabelStmtClass: - return this->visitStmt(cast(S)->getSubStmt()); - default: { - if (auto *Exp = dyn_cast(S)) - return this->discard(Exp); - return false; - } - } -} - -/// Visits the given statment without creating a variable -/// scope for it in case it is a compound statement. -template -bool ByteCodeStmtGen::visitLoopBody(const Stmt *S) { - if (isa(S)) - return true; - - if (const auto *CS = dyn_cast(S)) { - for (auto *InnerStmt : CS->body()) - if (!visitStmt(InnerStmt)) - return false; - return true; - } - - return this->visitStmt(S); -} - -template -bool ByteCodeStmtGen::visitCompoundStmt( - const CompoundStmt *CompoundStmt) { - BlockScope Scope(this); - for (auto *InnerStmt : CompoundStmt->body()) - if (!visitStmt(InnerStmt)) - return false; - return true; -} - -template -bool ByteCodeStmtGen::visitDeclStmt(const DeclStmt *DS) { - for (auto *D : DS->decls()) { - if (isa(D)) - continue; - - const auto *VD = dyn_cast(D); - if (!VD) - return false; - if (!this->visitVarDecl(VD)) - return false; - } - - return true; -} - -template -bool ByteCodeStmtGen::visitReturnStmt(const ReturnStmt *RS) { - if (const Expr *RE = RS->getRetValue()) { - ExprScope RetScope(this); - if (ReturnType) { - // Primitive types are simply returned. - if (!this->visit(RE)) - return false; - this->emitCleanup(); - return this->emitRet(*ReturnType, RS); - } else if (RE->getType()->isVoidType()) { - if (!this->visit(RE)) - return false; - } else { - // RVO - construct the value in the return location. - if (!this->emitRVOPtr(RE)) - return false; - if (!this->visitInitializer(RE)) - return false; - if (!this->emitPopPtr(RE)) - return false; - - this->emitCleanup(); - return this->emitRetVoid(RS); - } - } - - // Void return. - this->emitCleanup(); - return this->emitRetVoid(RS); -} - -template -bool ByteCodeStmtGen::visitIfStmt(const IfStmt *IS) { - BlockScope IfScope(this); - - if (IS->isNonNegatedConsteval()) - return visitStmt(IS->getThen()); - if (IS->isNegatedConsteval()) - return IS->getElse() ? visitStmt(IS->getElse()) : true; - - if (auto *CondInit = IS->getInit()) - if (!visitStmt(CondInit)) - return false; - - if (const DeclStmt *CondDecl = IS->getConditionVariableDeclStmt()) - if (!visitDeclStmt(CondDecl)) - return false; - - if (!this->visitBool(IS->getCond())) - return false; - - if (const Stmt *Else = IS->getElse()) { - LabelTy LabelElse = this->getLabel(); - LabelTy LabelEnd = this->getLabel(); - if (!this->jumpFalse(LabelElse)) - return false; - if (!visitStmt(IS->getThen())) - return false; - if (!this->jump(LabelEnd)) - return false; - this->emitLabel(LabelElse); - if (!visitStmt(Else)) - return false; - this->emitLabel(LabelEnd); - } else { - LabelTy LabelEnd = this->getLabel(); - if (!this->jumpFalse(LabelEnd)) - return false; - if (!visitStmt(IS->getThen())) - return false; - this->emitLabel(LabelEnd); - } - - return true; -} - -template -bool ByteCodeStmtGen::visitWhileStmt(const WhileStmt *S) { - const Expr *Cond = S->getCond(); - const Stmt *Body = S->getBody(); - - LabelTy CondLabel = this->getLabel(); // Label before the condition. - LabelTy EndLabel = this->getLabel(); // Label after the loop. - LoopScope LS(this, EndLabel, CondLabel); - - this->emitLabel(CondLabel); - - if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt()) - if (!visitDeclStmt(CondDecl)) - return false; - - if (!this->visitBool(Cond)) - return false; - if (!this->jumpFalse(EndLabel)) - return false; - - LocalScope Scope(this); - { - DestructorScope DS(Scope); - if (!this->visitLoopBody(Body)) - return false; - } - - if (!this->jump(CondLabel)) - return false; - this->emitLabel(EndLabel); - - return true; -} - -template -bool ByteCodeStmtGen::visitDoStmt(const DoStmt *S) { - const Expr *Cond = S->getCond(); - const Stmt *Body = S->getBody(); - - LabelTy StartLabel = this->getLabel(); - LabelTy EndLabel = this->getLabel(); - LabelTy CondLabel = this->getLabel(); - LoopScope LS(this, EndLabel, CondLabel); - LocalScope Scope(this); - - this->emitLabel(StartLabel); - { - DestructorScope DS(Scope); - - if (!this->visitLoopBody(Body)) - return false; - this->emitLabel(CondLabel); - if (!this->visitBool(Cond)) - return false; - } - if (!this->jumpTrue(StartLabel)) - return false; - - this->emitLabel(EndLabel); - return true; -} - -template -bool ByteCodeStmtGen::visitForStmt(const ForStmt *S) { - // for (Init; Cond; Inc) { Body } - const Stmt *Init = S->getInit(); - const Expr *Cond = S->getCond(); - const Expr *Inc = S->getInc(); - const Stmt *Body = S->getBody(); - - LabelTy EndLabel = this->getLabel(); - LabelTy CondLabel = this->getLabel(); - LabelTy IncLabel = this->getLabel(); - LoopScope LS(this, EndLabel, IncLabel); - LocalScope Scope(this); - - if (Init && !this->visitStmt(Init)) - return false; - this->emitLabel(CondLabel); - - if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt()) - if (!visitDeclStmt(CondDecl)) - return false; - if (Cond) { - if (!this->visitBool(Cond)) - return false; - if (!this->jumpFalse(EndLabel)) - return false; - } - - { - DestructorScope DS(Scope); - - if (Body && !this->visitLoopBody(Body)) - return false; - this->emitLabel(IncLabel); - if (Inc && !this->discard(Inc)) - return false; - } - - if (!this->jump(CondLabel)) - return false; - this->emitLabel(EndLabel); - return true; -} - -template -bool ByteCodeStmtGen::visitCXXForRangeStmt(const CXXForRangeStmt *S) { - const Stmt *Init = S->getInit(); - const Expr *Cond = S->getCond(); - const Expr *Inc = S->getInc(); - const Stmt *Body = S->getBody(); - const Stmt *BeginStmt = S->getBeginStmt(); - const Stmt *RangeStmt = S->getRangeStmt(); - const Stmt *EndStmt = S->getEndStmt(); - const VarDecl *LoopVar = S->getLoopVariable(); - - LabelTy EndLabel = this->getLabel(); - LabelTy CondLabel = this->getLabel(); - LabelTy IncLabel = this->getLabel(); - LoopScope LS(this, EndLabel, IncLabel); - - // Emit declarations needed in the loop. - if (Init && !this->visitStmt(Init)) - return false; - if (!this->visitStmt(RangeStmt)) - return false; - if (!this->visitStmt(BeginStmt)) - return false; - if (!this->visitStmt(EndStmt)) - return false; - - // Now the condition as well as the loop variable assignment. - this->emitLabel(CondLabel); - if (!this->visitBool(Cond)) - return false; - if (!this->jumpFalse(EndLabel)) - return false; - - if (!this->visitVarDecl(LoopVar)) - return false; - - // Body. - LocalScope Scope(this); - { - DestructorScope DS(Scope); - - if (!this->visitLoopBody(Body)) - return false; - this->emitLabel(IncLabel); - if (!this->discard(Inc)) - return false; - } - if (!this->jump(CondLabel)) - return false; - - this->emitLabel(EndLabel); - return true; -} - -template -bool ByteCodeStmtGen::visitBreakStmt(const BreakStmt *S) { - if (!BreakLabel) - return false; - - this->VarScope->emitDestructors(); - return this->jump(*BreakLabel); -} - -template -bool ByteCodeStmtGen::visitContinueStmt(const ContinueStmt *S) { - if (!ContinueLabel) - return false; - - this->VarScope->emitDestructors(); - return this->jump(*ContinueLabel); -} - -template -bool ByteCodeStmtGen::visitSwitchStmt(const SwitchStmt *S) { - const Expr *Cond = S->getCond(); - - LabelTy EndLabel = this->getLabel(); - OptLabelTy DefaultLabel = std::nullopt; - - if (const auto *CondInit = S->getInit()) - if (!visitStmt(CondInit)) - return false; - - if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt()) - if (!visitDeclStmt(CondDecl)) - return false; - - // Initialize condition variable. - PrimType CondT = this->classifyPrim(Cond->getType()); - unsigned CondVar = this->allocateLocalPrimitive(Cond, CondT, true, false); - if (!this->visit(Cond)) - return false; - if (!this->emitSetLocal(CondT, CondVar, S)) - return false; - - CaseMap CaseLabels; - // Create labels and comparison ops for all case statements. - for (const SwitchCase *SC = S->getSwitchCaseList(); SC; - SC = SC->getNextSwitchCase()) { - if (const auto *CS = dyn_cast(SC)) { - // FIXME: Implement ranges. - if (CS->caseStmtIsGNURange()) - return false; - CaseLabels[SC] = this->getLabel(); - - const Expr *Value = CS->getLHS(); - PrimType ValueT = this->classifyPrim(Value->getType()); - - // Compare the case statement's value to the switch condition. - if (!this->emitGetLocal(CondT, CondVar, CS)) - return false; - if (!this->visit(Value)) - return false; - - // Compare and jump to the case label. - if (!this->emitEQ(ValueT, S)) - return false; - if (!this->jumpTrue(CaseLabels[CS])) - return false; - } else { - assert(!DefaultLabel); - DefaultLabel = this->getLabel(); - } - } - - // If none of the conditions above were true, fall through to the default - // statement or jump after the switch statement. - if (DefaultLabel) { - if (!this->jump(*DefaultLabel)) - return false; - } else { - if (!this->jump(EndLabel)) - return false; - } - - SwitchScope SS(this, std::move(CaseLabels), EndLabel, DefaultLabel); - if (!this->visitStmt(S->getBody())) - return false; - this->emitLabel(EndLabel); - return true; -} - -template -bool ByteCodeStmtGen::visitCaseStmt(const CaseStmt *S) { - this->emitLabel(CaseLabels[S]); - return this->visitStmt(S->getSubStmt()); -} - -template -bool ByteCodeStmtGen::visitDefaultStmt(const DefaultStmt *S) { - this->emitLabel(*DefaultLabel); - return this->visitStmt(S->getSubStmt()); -} - -template -bool ByteCodeStmtGen::visitAttributedStmt(const AttributedStmt *S) { - - if (this->Ctx.getLangOpts().CXXAssumptions && - !this->Ctx.getLangOpts().MSVCCompat) { - for (const Attr *A : S->getAttrs()) { - auto *AA = dyn_cast(A); - if (!AA) - continue; - - assert(isa(S->getSubStmt())); - - const Expr *Assumption = AA->getAssumption(); - if (Assumption->isValueDependent()) - return false; - - if (Assumption->HasSideEffects(this->Ctx.getASTContext())) - continue; - - // Evaluate assumption. - if (!this->visitBool(Assumption)) - return false; - - if (!this->emitAssume(Assumption)) - return false; - } - } - - // Ignore other attributes. - return this->visitStmt(S->getSubStmt()); -} - -template -bool ByteCodeStmtGen::visitCXXTryStmt(const CXXTryStmt *S) { - // Ignore all handlers. - return this->visitStmt(S->getTryBlock()); -} - -namespace clang { -namespace interp { - -template class ByteCodeStmtGen; - -} // namespace interp -} // namespace clang diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.h b/clang/lib/AST/Interp/ByteCodeStmtGen.h deleted file mode 100644 index d7e6e5042c2740..00000000000000 --- a/clang/lib/AST/Interp/ByteCodeStmtGen.h +++ /dev/null @@ -1,91 +0,0 @@ -//===--- ByteCodeStmtGen.h - Code generator for expressions -----*- 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 -// -//===----------------------------------------------------------------------===// -// -// Defines the constexpr bytecode compiler. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_AST_INTERP_BYTECODESTMTGEN_H -#define LLVM_CLANG_AST_INTERP_BYTECODESTMTGEN_H - -#include "ByteCodeEmitter.h" -#include "ByteCodeExprGen.h" -#include "EvalEmitter.h" -#include "PrimType.h" -#include "clang/AST/StmtVisitor.h" - -namespace clang { -namespace interp { - -template class LoopScope; -template class SwitchScope; -template class LabelScope; - -/// Compilation context for statements. -template -class ByteCodeStmtGen final : public ByteCodeExprGen { - using LabelTy = typename Emitter::LabelTy; - using AddrTy = typename Emitter::AddrTy; - using OptLabelTy = std::optional; - using CaseMap = llvm::DenseMap; - -public: - template - ByteCodeStmtGen(Tys&&... Args) - : ByteCodeExprGen(std::forward(Args)...) {} - -protected: - bool visitFunc(const FunctionDecl *F) override; - -private: - friend class LabelScope; - friend class LoopScope; - friend class SwitchScope; - - // Statement visitors. - bool visitStmt(const Stmt *S); - bool visitCompoundStmt(const CompoundStmt *S); - bool visitLoopBody(const Stmt *S); - bool visitDeclStmt(const DeclStmt *DS); - bool visitReturnStmt(const ReturnStmt *RS); - bool visitIfStmt(const IfStmt *IS); - bool visitWhileStmt(const WhileStmt *S); - bool visitDoStmt(const DoStmt *S); - bool visitForStmt(const ForStmt *S); - bool visitCXXForRangeStmt(const CXXForRangeStmt *S); - bool visitBreakStmt(const BreakStmt *S); - bool visitContinueStmt(const ContinueStmt *S); - bool visitSwitchStmt(const SwitchStmt *S); - bool visitCaseStmt(const CaseStmt *S); - bool visitDefaultStmt(const DefaultStmt *S); - bool visitAttributedStmt(const AttributedStmt *S); - bool visitCXXTryStmt(const CXXTryStmt *S); - - bool emitLambdaStaticInvokerBody(const CXXMethodDecl *MD); - - /// Type of the expression returned by the function. - std::optional ReturnType; - - /// Switch case mapping. - CaseMap CaseLabels; - - /// Point to break to. - OptLabelTy BreakLabel; - /// Point to continue to. - OptLabelTy ContinueLabel; - /// Default case label. - OptLabelTy DefaultLabel; -}; - -extern template class ByteCodeStmtGen; -extern template class ByteCodeExprGen; - -} // namespace interp -} // namespace clang - -#endif diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/Compiler.cpp similarity index 79% rename from clang/lib/AST/Interp/ByteCodeExprGen.cpp rename to clang/lib/AST/Interp/Compiler.cpp index 72c569f56a7887..424f4f84a01673 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -1,4 +1,4 @@ -//===--- ByteCodeExprGen.cpp - Code generator for expressions ---*- C++ -*-===// +//===--- Compiler.cpp - Code generator for expressions ---*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,9 +6,8 @@ // //===----------------------------------------------------------------------===// -#include "ByteCodeExprGen.h" +#include "Compiler.h" #include "ByteCodeEmitter.h" -#include "ByteCodeStmtGen.h" #include "Context.h" #include "Floating.h" #include "Function.h" @@ -28,7 +27,7 @@ namespace interp { /// Scope used to handle temporaries in toplevel variable declarations. template class DeclScope final : public VariableScope { public: - DeclScope(ByteCodeExprGen *Ctx, const ValueDecl *VD) + DeclScope(Compiler *Ctx, const ValueDecl *VD) : VariableScope(Ctx, nullptr), Scope(Ctx->P, VD), OldGlobalDecl(Ctx->GlobalDecl), OldInitializingDecl(Ctx->InitializingDecl) { @@ -37,6 +36,10 @@ template class DeclScope final : public VariableScope { Ctx->InitStack.push_back(InitLink::Decl(VD)); } + void addExtended(const Scope::Local &Local) override { + return this->addLocal(Local); + } + ~DeclScope() { this->Ctx->GlobalDecl = OldGlobalDecl; this->Ctx->InitializingDecl = OldInitializingDecl; @@ -53,7 +56,7 @@ template class DeclScope final : public VariableScope { template class OptionScope final { public: /// Root constructor, compiling or discarding primitives. - OptionScope(ByteCodeExprGen *Ctx, bool NewDiscardResult, + OptionScope(Compiler *Ctx, bool NewDiscardResult, bool NewInitializing) : Ctx(Ctx), OldDiscardResult(Ctx->DiscardResult), OldInitializing(Ctx->Initializing) { @@ -68,14 +71,14 @@ template class OptionScope final { private: /// Parent context. - ByteCodeExprGen *Ctx; + Compiler *Ctx; /// Old discard flag to restore. bool OldDiscardResult; bool OldInitializing; }; template -bool InitLink::emit(ByteCodeExprGen *Ctx, const Expr *E) const { +bool InitLink::emit(Compiler *Ctx, const Expr *E) const { switch (Kind) { case K_This: return Ctx->emitThis(E); @@ -88,11 +91,74 @@ bool InitLink::emit(ByteCodeExprGen *Ctx, const Expr *E) const { return true; } +/// Scope managing label targets. +template class LabelScope { +public: + virtual ~LabelScope() {} + +protected: + LabelScope(Compiler *Ctx) : Ctx(Ctx) {} + /// Compiler instance. + Compiler *Ctx; +}; + +/// Sets the context for break/continue statements. +template class LoopScope final : public LabelScope { +public: + using LabelTy = typename Compiler::LabelTy; + using OptLabelTy = typename Compiler::OptLabelTy; + + LoopScope(Compiler *Ctx, LabelTy BreakLabel, LabelTy ContinueLabel) + : LabelScope(Ctx), OldBreakLabel(Ctx->BreakLabel), + OldContinueLabel(Ctx->ContinueLabel) { + this->Ctx->BreakLabel = BreakLabel; + this->Ctx->ContinueLabel = ContinueLabel; + } + + ~LoopScope() { + this->Ctx->BreakLabel = OldBreakLabel; + this->Ctx->ContinueLabel = OldContinueLabel; + } + +private: + OptLabelTy OldBreakLabel; + OptLabelTy OldContinueLabel; +}; + +// Sets the context for a switch scope, mapping labels. +template class SwitchScope final : public LabelScope { +public: + using LabelTy = typename Compiler::LabelTy; + using OptLabelTy = typename Compiler::OptLabelTy; + using CaseMap = typename Compiler::CaseMap; + + SwitchScope(Compiler *Ctx, CaseMap &&CaseLabels, LabelTy BreakLabel, + OptLabelTy DefaultLabel) + : LabelScope(Ctx), OldBreakLabel(Ctx->BreakLabel), + OldDefaultLabel(this->Ctx->DefaultLabel), + OldCaseLabels(std::move(this->Ctx->CaseLabels)) { + this->Ctx->BreakLabel = BreakLabel; + this->Ctx->DefaultLabel = DefaultLabel; + this->Ctx->CaseLabels = std::move(CaseLabels); + } + + ~SwitchScope() { + this->Ctx->BreakLabel = OldBreakLabel; + this->Ctx->DefaultLabel = OldDefaultLabel; + this->Ctx->CaseLabels = std::move(OldCaseLabels); + } + +private: + OptLabelTy OldBreakLabel; + OptLabelTy OldDefaultLabel; + CaseMap OldCaseLabels; +}; + } // namespace interp } // namespace clang template -bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { +bool Compiler::VisitCastExpr(const CastExpr *CE) { const Expr *SubExpr = CE->getSubExpr(); switch (CE->getCastKind()) { @@ -546,7 +612,7 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { } template -bool ByteCodeExprGen::VisitIntegerLiteral(const IntegerLiteral *LE) { +bool Compiler::VisitIntegerLiteral(const IntegerLiteral *LE) { if (DiscardResult) return true; @@ -554,7 +620,7 @@ bool ByteCodeExprGen::VisitIntegerLiteral(const IntegerLiteral *LE) { } template -bool ByteCodeExprGen::VisitFloatingLiteral(const FloatingLiteral *E) { +bool Compiler::VisitFloatingLiteral(const FloatingLiteral *E) { if (DiscardResult) return true; @@ -562,8 +628,7 @@ bool ByteCodeExprGen::VisitFloatingLiteral(const FloatingLiteral *E) { } template -bool ByteCodeExprGen::VisitImaginaryLiteral( - const ImaginaryLiteral *E) { +bool Compiler::VisitImaginaryLiteral(const ImaginaryLiteral *E) { assert(E->getType()->isAnyComplexType()); if (DiscardResult) return true; @@ -587,12 +652,12 @@ bool ByteCodeExprGen::VisitImaginaryLiteral( } template -bool ByteCodeExprGen::VisitParenExpr(const ParenExpr *E) { +bool Compiler::VisitParenExpr(const ParenExpr *E) { return this->delegate(E->getSubExpr()); } template -bool ByteCodeExprGen::VisitBinaryOperator(const BinaryOperator *BO) { +bool Compiler::VisitBinaryOperator(const BinaryOperator *BO) { // Need short-circuiting for these. if (BO->isLogicalOp()) return this->VisitLogicalBinOp(BO); @@ -764,7 +829,7 @@ bool ByteCodeExprGen::VisitBinaryOperator(const BinaryOperator *BO) { /// Perform addition/subtraction of a pointer and an integer or /// subtraction of two pointers. template -bool ByteCodeExprGen::VisitPointerArithBinOp(const BinaryOperator *E) { +bool Compiler::VisitPointerArithBinOp(const BinaryOperator *E) { BinaryOperatorKind Op = E->getOpcode(); const Expr *LHS = E->getLHS(); const Expr *RHS = E->getRHS(); @@ -812,7 +877,7 @@ bool ByteCodeExprGen::VisitPointerArithBinOp(const BinaryOperator *E) { } template -bool ByteCodeExprGen::VisitLogicalBinOp(const BinaryOperator *E) { +bool Compiler::VisitLogicalBinOp(const BinaryOperator *E) { assert(E->isLogicalOp()); BinaryOperatorKind Op = E->getOpcode(); const Expr *LHS = E->getLHS(); @@ -873,7 +938,7 @@ bool ByteCodeExprGen::VisitLogicalBinOp(const BinaryOperator *E) { } template -bool ByteCodeExprGen::VisitComplexBinOp(const BinaryOperator *E) { +bool Compiler::VisitComplexBinOp(const BinaryOperator *E) { // Prepare storage for result. if (!Initializing) { std::optional LocalIndex = allocateLocal(E); @@ -1101,7 +1166,8 @@ bool ByteCodeExprGen::VisitComplexBinOp(const BinaryOperator *E) { } template -bool ByteCodeExprGen::VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) { +bool Compiler::VisitImplicitValueInitExpr( + const ImplicitValueInitExpr *E) { QualType QT = E->getType(); if (std::optional T = classify(QT)) @@ -1184,8 +1250,7 @@ bool ByteCodeExprGen::VisitImplicitValueInitExpr(const ImplicitValueIni } template -bool ByteCodeExprGen::VisitArraySubscriptExpr( - const ArraySubscriptExpr *E) { +bool Compiler::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { const Expr *Base = E->getBase(); const Expr *Index = E->getIdx(); @@ -1205,9 +1270,8 @@ bool ByteCodeExprGen::VisitArraySubscriptExpr( } template -bool ByteCodeExprGen::visitInitList(ArrayRef Inits, - const Expr *ArrayFiller, - const Expr *E) { +bool Compiler::visitInitList(ArrayRef Inits, + const Expr *ArrayFiller, const Expr *E) { if (E->getType()->isVoidType()) return this->emitInvalid(E); @@ -1234,7 +1298,7 @@ bool ByteCodeExprGen::visitInitList(ArrayRef Inits, const Record *R = getRecord(E->getType()); if (Inits.size() == 1 && E->getType() == Inits[0]->getType()) - return this->visitInitializer(Inits[0]); + return this->delegate(Inits[0]); auto initPrimitiveField = [=](const Record::Field *FieldToInit, const Expr *Init, PrimType T) -> bool { @@ -1329,22 +1393,8 @@ bool ByteCodeExprGen::visitInitList(ArrayRef Inits, } if (T->isArrayType()) { - // Prepare composite return value. - if (!Initializing) { - if (GlobalDecl) { - std::optional GlobalIndex = P.createGlobal(E); - if (!GlobalIndex) - return false; - if (!this->emitGetPtrGlobal(*GlobalIndex, E)) - return false; - } else { - std::optional LocalIndex = allocateLocal(E); - if (!LocalIndex) - return false; - if (!this->emitGetPtrLocal(*LocalIndex, E)) - return false; - } - } + if (Inits.size() == 1 && E->getType() == Inits[0]->getType()) + return this->delegate(Inits[0]); unsigned ElementIndex = 0; for (const Expr *Init : Inits) { @@ -1433,7 +1483,8 @@ bool ByteCodeExprGen::visitInitList(ArrayRef Inits, // If the initializer is of vector type itself, we have to deconstruct // that and initialize all the target fields from the initializer fields. if (const auto *InitVecT = Init->getType()->getAs()) { - if (!this->emitCopyArray(ElemT, 0, InitIndex, InitVecT->getNumElements(), E)) + if (!this->emitCopyArray(ElemT, 0, InitIndex, + InitVecT->getNumElements(), E)) return false; InitIndex += InitVecT->getNumElements(); } else { @@ -1461,8 +1512,8 @@ bool ByteCodeExprGen::visitInitList(ArrayRef Inits, /// Pointer to the array(not the element!) must be on the stack when calling /// this. template -bool ByteCodeExprGen::visitArrayElemInit(unsigned ElemIndex, - const Expr *Init) { +bool Compiler::visitArrayElemInit(unsigned ElemIndex, + const Expr *Init) { if (std::optional T = classify(Init->getType())) { // Visit the primitive element like normal. if (!this->visit(Init)) @@ -1482,24 +1533,24 @@ bool ByteCodeExprGen::visitArrayElemInit(unsigned ElemIndex, } template -bool ByteCodeExprGen::VisitInitListExpr(const InitListExpr *E) { +bool Compiler::VisitInitListExpr(const InitListExpr *E) { return this->visitInitList(E->inits(), E->getArrayFiller(), E); } template -bool ByteCodeExprGen::VisitCXXParenListInitExpr( +bool Compiler::VisitCXXParenListInitExpr( const CXXParenListInitExpr *E) { return this->visitInitList(E->getInitExprs(), E->getArrayFiller(), E); } template -bool ByteCodeExprGen::VisitSubstNonTypeTemplateParmExpr( +bool Compiler::VisitSubstNonTypeTemplateParmExpr( const SubstNonTypeTemplateParmExpr *E) { return this->delegate(E->getReplacement()); } template -bool ByteCodeExprGen::VisitConstantExpr(const ConstantExpr *E) { +bool Compiler::VisitConstantExpr(const ConstantExpr *E) { std::optional T = classify(E->getType()); if (T && E->hasAPValueResult()) { // Try to emit the APValue directly, without visiting the subexpr. @@ -1515,7 +1566,7 @@ bool ByteCodeExprGen::VisitConstantExpr(const ConstantExpr *E) { } template -bool ByteCodeExprGen::VisitEmbedExpr(const EmbedExpr *E) { +bool Compiler::VisitEmbedExpr(const EmbedExpr *E) { auto It = E->begin(); return this->visit(*It); } @@ -1544,7 +1595,7 @@ static CharUnits AlignOfType(QualType T, const ASTContext &ASTCtx, } template -bool ByteCodeExprGen::VisitUnaryExprOrTypeTraitExpr( +bool Compiler::VisitUnaryExprOrTypeTraitExpr( const UnaryExprOrTypeTraitExpr *E) { UnaryExprOrTypeTrait Kind = E->getKind(); const ASTContext &ASTCtx = Ctx.getASTContext(); @@ -1636,7 +1687,7 @@ bool ByteCodeExprGen::VisitUnaryExprOrTypeTraitExpr( } template -bool ByteCodeExprGen::VisitMemberExpr(const MemberExpr *E) { +bool Compiler::VisitMemberExpr(const MemberExpr *E) { // 'Base.Member' const Expr *Base = E->getBase(); const ValueDecl *Member = E->getMemberDecl(); @@ -1688,8 +1739,7 @@ bool ByteCodeExprGen::VisitMemberExpr(const MemberExpr *E) { } template -bool ByteCodeExprGen::VisitArrayInitIndexExpr( - const ArrayInitIndexExpr *E) { +bool Compiler::VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E) { // ArrayIndex might not be set if a ArrayInitIndexExpr is being evaluated // stand-alone, e.g. via EvaluateAsInt(). if (!ArrayIndex) @@ -1698,8 +1748,7 @@ bool ByteCodeExprGen::VisitArrayInitIndexExpr( } template -bool ByteCodeExprGen::VisitArrayInitLoopExpr( - const ArrayInitLoopExpr *E) { +bool Compiler::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) { assert(Initializing); assert(!DiscardResult); @@ -1727,7 +1776,7 @@ bool ByteCodeExprGen::VisitArrayInitLoopExpr( } template -bool ByteCodeExprGen::VisitOpaqueValueExpr(const OpaqueValueExpr *E) { +bool Compiler::VisitOpaqueValueExpr(const OpaqueValueExpr *E) { const Expr *SourceExpr = E->getSourceExpr(); if (!SourceExpr) return false; @@ -1763,7 +1812,7 @@ bool ByteCodeExprGen::VisitOpaqueValueExpr(const OpaqueValueExpr *E) { } template -bool ByteCodeExprGen::VisitAbstractConditionalOperator( +bool Compiler::VisitAbstractConditionalOperator( const AbstractConditionalOperator *E) { const Expr *Condition = E->getCond(); const Expr *TrueExpr = E->getTrueExpr(); @@ -1795,7 +1844,7 @@ bool ByteCodeExprGen::VisitAbstractConditionalOperator( } template -bool ByteCodeExprGen::VisitStringLiteral(const StringLiteral *E) { +bool Compiler::VisitStringLiteral(const StringLiteral *E) { if (DiscardResult) return true; @@ -1852,13 +1901,12 @@ bool ByteCodeExprGen::VisitStringLiteral(const StringLiteral *E) { } template -bool ByteCodeExprGen::VisitObjCStringLiteral( - const ObjCStringLiteral *E) { +bool Compiler::VisitObjCStringLiteral(const ObjCStringLiteral *E) { return this->delegate(E->getString()); } template -bool ByteCodeExprGen::VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { +bool Compiler::VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { auto &A = Ctx.getASTContext(); std::string Str; A.getObjCEncodingForType(E->getEncodedType(), Str); @@ -1869,7 +1917,7 @@ bool ByteCodeExprGen::VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { } template -bool ByteCodeExprGen::VisitSYCLUniqueStableNameExpr( +bool Compiler::VisitSYCLUniqueStableNameExpr( const SYCLUniqueStableNameExpr *E) { if (DiscardResult) return true; @@ -1893,15 +1941,14 @@ bool ByteCodeExprGen::VisitSYCLUniqueStableNameExpr( } template -bool ByteCodeExprGen::VisitCharacterLiteral( - const CharacterLiteral *E) { +bool Compiler::VisitCharacterLiteral(const CharacterLiteral *E) { if (DiscardResult) return true; return this->emitConst(E->getValue(), E); } template -bool ByteCodeExprGen::VisitFloatCompoundAssignOperator( +bool Compiler::VisitFloatCompoundAssignOperator( const CompoundAssignOperator *E) { const Expr *LHS = E->getLHS(); @@ -1975,7 +2022,7 @@ bool ByteCodeExprGen::VisitFloatCompoundAssignOperator( } template -bool ByteCodeExprGen::VisitPointerCompoundAssignOperator( +bool Compiler::VisitPointerCompoundAssignOperator( const CompoundAssignOperator *E) { BinaryOperatorKind Op = E->getOpcode(); const Expr *LHS = E->getLHS(); @@ -2012,7 +2059,7 @@ bool ByteCodeExprGen::VisitPointerCompoundAssignOperator( } template -bool ByteCodeExprGen::VisitCompoundAssignOperator( +bool Compiler::VisitCompoundAssignOperator( const CompoundAssignOperator *E) { const Expr *LHS = E->getLHS(); @@ -2133,8 +2180,7 @@ bool ByteCodeExprGen::VisitCompoundAssignOperator( } template -bool ByteCodeExprGen::VisitExprWithCleanups( - const ExprWithCleanups *E) { +bool Compiler::VisitExprWithCleanups(const ExprWithCleanups *E) { ExprScope ES(this); const Expr *SubExpr = E->getSubExpr(); @@ -2144,13 +2190,13 @@ bool ByteCodeExprGen::VisitExprWithCleanups( } template -bool ByteCodeExprGen::VisitMaterializeTemporaryExpr( +bool Compiler::VisitMaterializeTemporaryExpr( const MaterializeTemporaryExpr *E) { const Expr *SubExpr = E->getSubExpr(); if (Initializing) { // We already have a value, just initialize that. - return this->visitInitializer(SubExpr); + return this->delegate(SubExpr); } // If we don't end up using the materialized temporary anyway, don't // bother creating it. @@ -2216,14 +2262,13 @@ bool ByteCodeExprGen::VisitMaterializeTemporaryExpr( } template -bool ByteCodeExprGen::VisitCXXBindTemporaryExpr( +bool Compiler::VisitCXXBindTemporaryExpr( const CXXBindTemporaryExpr *E) { return this->delegate(E->getSubExpr()); } template -bool ByteCodeExprGen::VisitCompoundLiteralExpr( - const CompoundLiteralExpr *E) { +bool Compiler::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { const Expr *Init = E->getInitializer(); if (Initializing) { // We already have a value, just initialize that. @@ -2288,7 +2333,7 @@ bool ByteCodeExprGen::VisitCompoundLiteralExpr( } template -bool ByteCodeExprGen::VisitTypeTraitExpr(const TypeTraitExpr *E) { +bool Compiler::VisitTypeTraitExpr(const TypeTraitExpr *E) { if (DiscardResult) return true; if (E->getType()->isBooleanType()) @@ -2297,15 +2342,14 @@ bool ByteCodeExprGen::VisitTypeTraitExpr(const TypeTraitExpr *E) { } template -bool ByteCodeExprGen::VisitArrayTypeTraitExpr( - const ArrayTypeTraitExpr *E) { +bool Compiler::VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) { if (DiscardResult) return true; return this->emitConst(E->getValue(), E); } template -bool ByteCodeExprGen::VisitLambdaExpr(const LambdaExpr *E) { +bool Compiler::VisitLambdaExpr(const LambdaExpr *E) { if (DiscardResult) return true; @@ -2344,7 +2388,7 @@ bool ByteCodeExprGen::VisitLambdaExpr(const LambdaExpr *E) { } template -bool ByteCodeExprGen::VisitPredefinedExpr(const PredefinedExpr *E) { +bool Compiler::VisitPredefinedExpr(const PredefinedExpr *E) { if (DiscardResult) return true; @@ -2352,7 +2396,7 @@ bool ByteCodeExprGen::VisitPredefinedExpr(const PredefinedExpr *E) { } template -bool ByteCodeExprGen::VisitCXXThrowExpr(const CXXThrowExpr *E) { +bool Compiler::VisitCXXThrowExpr(const CXXThrowExpr *E) { if (E->getSubExpr() && !this->discard(E->getSubExpr())) return false; @@ -2360,7 +2404,7 @@ bool ByteCodeExprGen::VisitCXXThrowExpr(const CXXThrowExpr *E) { } template -bool ByteCodeExprGen::VisitCXXReinterpretCastExpr( +bool Compiler::VisitCXXReinterpretCastExpr( const CXXReinterpretCastExpr *E) { if (!this->discard(E->getSubExpr())) return false; @@ -2369,7 +2413,7 @@ bool ByteCodeExprGen::VisitCXXReinterpretCastExpr( } template -bool ByteCodeExprGen::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) { +bool Compiler::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) { assert(E->getType()->isBooleanType()); if (DiscardResult) @@ -2378,8 +2422,7 @@ bool ByteCodeExprGen::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) { } template -bool ByteCodeExprGen::VisitCXXConstructExpr( - const CXXConstructExpr *E) { +bool Compiler::VisitCXXConstructExpr(const CXXConstructExpr *E) { QualType T = E->getType(); assert(!classify(T)); @@ -2491,7 +2534,7 @@ bool ByteCodeExprGen::VisitCXXConstructExpr( } template -bool ByteCodeExprGen::VisitSourceLocExpr(const SourceLocExpr *E) { +bool Compiler::VisitSourceLocExpr(const SourceLocExpr *E) { if (DiscardResult) return true; @@ -2547,7 +2590,7 @@ bool ByteCodeExprGen::VisitSourceLocExpr(const SourceLocExpr *E) { } template -bool ByteCodeExprGen::VisitOffsetOfExpr(const OffsetOfExpr *E) { +bool Compiler::VisitOffsetOfExpr(const OffsetOfExpr *E) { unsigned N = E->getNumComponents(); if (N == 0) return false; @@ -2582,7 +2625,7 @@ bool ByteCodeExprGen::VisitOffsetOfExpr(const OffsetOfExpr *E) { } template -bool ByteCodeExprGen::VisitCXXScalarValueInitExpr( +bool Compiler::VisitCXXScalarValueInitExpr( const CXXScalarValueInitExpr *E) { QualType Ty = E->getType(); @@ -2641,24 +2684,23 @@ bool ByteCodeExprGen::VisitCXXScalarValueInitExpr( } template -bool ByteCodeExprGen::VisitSizeOfPackExpr(const SizeOfPackExpr *E) { +bool Compiler::VisitSizeOfPackExpr(const SizeOfPackExpr *E) { return this->emitConst(E->getPackLength(), E); } template -bool ByteCodeExprGen::VisitGenericSelectionExpr( +bool Compiler::VisitGenericSelectionExpr( const GenericSelectionExpr *E) { return this->delegate(E->getResultExpr()); } template -bool ByteCodeExprGen::VisitChooseExpr(const ChooseExpr *E) { +bool Compiler::VisitChooseExpr(const ChooseExpr *E) { return this->delegate(E->getChosenSubExpr()); } template -bool ByteCodeExprGen::VisitObjCBoolLiteralExpr( - const ObjCBoolLiteralExpr *E) { +bool Compiler::VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *E) { if (DiscardResult) return true; @@ -2666,7 +2708,7 @@ bool ByteCodeExprGen::VisitObjCBoolLiteralExpr( } template -bool ByteCodeExprGen::VisitCXXInheritedCtorInitExpr( +bool Compiler::VisitCXXInheritedCtorInitExpr( const CXXInheritedCtorInitExpr *E) { const CXXConstructorDecl *Ctor = E->getConstructor(); assert(!Ctor->isTrivial() && @@ -2697,19 +2739,29 @@ bool ByteCodeExprGen::VisitCXXInheritedCtorInitExpr( } template -bool ByteCodeExprGen::VisitExpressionTraitExpr( - const ExpressionTraitExpr *E) { +bool Compiler::VisitExpressionTraitExpr(const ExpressionTraitExpr *E) { assert(Ctx.getLangOpts().CPlusPlus); return this->emitConstBool(E->getValue(), E); } template -bool ByteCodeExprGen::VisitCXXUuidofExpr(const CXXUuidofExpr *E) { +bool Compiler::VisitCXXUuidofExpr(const CXXUuidofExpr *E) { if (DiscardResult) return true; assert(!Initializing); - std::optional GlobalIndex = P.getOrCreateGlobal(E->getGuidDecl()); + const MSGuidDecl *GuidDecl = E->getGuidDecl(); + const RecordDecl *RD = GuidDecl->getType()->getAsRecordDecl(); + assert(RD); + // If the definiton of the result type is incomplete, just return a dummy. + // If (and when) that is read from, we will fail, but not now. + if (!RD->isCompleteDefinition()) { + if (std::optional I = P.getOrCreateDummy(GuidDecl)) + return this->emitGetPtrGlobal(*I, E); + return false; + } + + std::optional GlobalIndex = P.getOrCreateGlobal(GuidDecl); if (!GlobalIndex) return false; if (!this->emitGetPtrGlobal(*GlobalIndex, E)) @@ -2717,7 +2769,7 @@ bool ByteCodeExprGen::VisitCXXUuidofExpr(const CXXUuidofExpr *E) { assert(this->getRecord(E->getType())); - const APValue &V = E->getGuidDecl()->getAsAPValue(); + const APValue &V = GuidDecl->getAsAPValue(); if (V.getKind() == APValue::None) return true; @@ -2730,7 +2782,7 @@ bool ByteCodeExprGen::VisitCXXUuidofExpr(const CXXUuidofExpr *E) { } template -bool ByteCodeExprGen::VisitRequiresExpr(const RequiresExpr *E) { +bool Compiler::VisitRequiresExpr(const RequiresExpr *E) { assert(classifyPrim(E->getType()) == PT_Bool); if (DiscardResult) return true; @@ -2738,7 +2790,7 @@ bool ByteCodeExprGen::VisitRequiresExpr(const RequiresExpr *E) { } template -bool ByteCodeExprGen::VisitConceptSpecializationExpr( +bool Compiler::VisitConceptSpecializationExpr( const ConceptSpecializationExpr *E) { assert(classifyPrim(E->getType()) == PT_Bool); if (DiscardResult) @@ -2747,14 +2799,13 @@ bool ByteCodeExprGen::VisitConceptSpecializationExpr( } template -bool ByteCodeExprGen::VisitCXXRewrittenBinaryOperator( +bool Compiler::VisitCXXRewrittenBinaryOperator( const CXXRewrittenBinaryOperator *E) { return this->delegate(E->getSemanticForm()); } template -bool ByteCodeExprGen::VisitPseudoObjectExpr( - const PseudoObjectExpr *E) { +bool Compiler::VisitPseudoObjectExpr(const PseudoObjectExpr *E) { for (const Expr *SemE : E->semantics()) { if (auto *OVE = dyn_cast(SemE)) { @@ -2778,18 +2829,17 @@ bool ByteCodeExprGen::VisitPseudoObjectExpr( } template -bool ByteCodeExprGen::VisitPackIndexingExpr( - const PackIndexingExpr *E) { +bool Compiler::VisitPackIndexingExpr(const PackIndexingExpr *E) { return this->delegate(E->getSelectedExpr()); } template -bool ByteCodeExprGen::VisitRecoveryExpr(const RecoveryExpr *E) { +bool Compiler::VisitRecoveryExpr(const RecoveryExpr *E) { return this->emitError(E); } template -bool ByteCodeExprGen::VisitAddrLabelExpr(const AddrLabelExpr *E) { +bool Compiler::VisitAddrLabelExpr(const AddrLabelExpr *E) { assert(E->getType()->isVoidPointerType()); unsigned Offset = allocateLocalPrimitive( @@ -2799,8 +2849,7 @@ bool ByteCodeExprGen::VisitAddrLabelExpr(const AddrLabelExpr *E) { } template -bool ByteCodeExprGen::VisitConvertVectorExpr( - const ConvertVectorExpr *E) { +bool Compiler::VisitConvertVectorExpr(const ConvertVectorExpr *E) { assert(Initializing); const auto *VT = E->getType()->castAs(); QualType ElemType = VT->getElementType(); @@ -2832,8 +2881,7 @@ bool ByteCodeExprGen::VisitConvertVectorExpr( } template -bool ByteCodeExprGen::VisitShuffleVectorExpr( - const ShuffleVectorExpr *E) { +bool Compiler::VisitShuffleVectorExpr(const ShuffleVectorExpr *E) { assert(Initializing); assert(E->getNumSubExprs() > 2); @@ -2875,7 +2923,7 @@ bool ByteCodeExprGen::VisitShuffleVectorExpr( } template -bool ByteCodeExprGen::VisitExtVectorElementExpr( +bool Compiler::VisitExtVectorElementExpr( const ExtVectorElementExpr *E) { const Expr *Base = E->getBase(); assert( @@ -2937,28 +2985,89 @@ bool ByteCodeExprGen::VisitExtVectorElementExpr( } template -bool ByteCodeExprGen::VisitObjCBoxedExpr(const ObjCBoxedExpr *E) { +bool Compiler::VisitObjCBoxedExpr(const ObjCBoxedExpr *E) { if (!E->isExpressibleAsConstantInitializer()) return this->emitInvalid(E); return this->delegate(E->getSubExpr()); } -template bool ByteCodeExprGen::discard(const Expr *E) { +template +bool Compiler::VisitCXXStdInitializerListExpr( + const CXXStdInitializerListExpr *E) { + const Expr *SubExpr = E->getSubExpr(); + const ConstantArrayType *ArrayType = + Ctx.getASTContext().getAsConstantArrayType(SubExpr->getType()); + const Record *R = getRecord(E->getType()); + assert(Initializing); + assert(SubExpr->isGLValue()); + + if (!this->visit(SubExpr)) + return false; + if (!this->emitInitFieldPtr(R->getField(0u)->Offset, E)) + return false; + + PrimType SecondFieldT = classifyPrim(R->getField(1u)->Decl->getType()); + if (isIntegralType(SecondFieldT)) { + if (!this->emitConst(static_cast(ArrayType->getSize()), + SecondFieldT, E)) + return false; + return this->emitInitField(SecondFieldT, R->getField(1u)->Offset, E); + } + assert(SecondFieldT == PT_Ptr); + + if (!this->emitGetFieldPtr(R->getField(0u)->Offset, E)) + return false; + if (!this->emitConst(static_cast(ArrayType->getSize()), PT_Uint64, E)) + return false; + if (!this->emitArrayElemPtrPop(PT_Uint64, E)) + return false; + return this->emitInitFieldPtr(R->getField(1u)->Offset, E); +} + +template +bool Compiler::VisitStmtExpr(const StmtExpr *E) { + BlockScope BS(this); + + const CompoundStmt *CS = E->getSubStmt(); + const Stmt *Result = CS->getStmtExprResult(); + for (const Stmt *S : CS->body()) { + if (S != Result) { + if (!this->visitStmt(S)) + return false; + continue; + } + + assert(S == Result); + // This better produces a value (i.e. is an expression). + if (const Expr *ResultExpr = dyn_cast(S)) { + if (DiscardResult) + return this->discard(ResultExpr); + return this->delegate(ResultExpr); + } + return false; + } + + return true; +} + +template bool Compiler::discard(const Expr *E) { OptionScope Scope(this, /*NewDiscardResult=*/true, /*NewInitializing=*/false); return this->Visit(E); } -template -bool ByteCodeExprGen::delegate(const Expr *E) { +template bool Compiler::delegate(const Expr *E) { + if (E->containsErrors()) + return this->emitError(E); + // We're basically doing: // OptionScope Scope(this, DicardResult, Initializing); // but that's unnecessary of course. return this->Visit(E); } -template bool ByteCodeExprGen::visit(const Expr *E) { +template bool Compiler::visit(const Expr *E) { if (E->getType().isNull()) return false; @@ -2985,7 +3094,7 @@ template bool ByteCodeExprGen::visit(const Expr *E) { } template -bool ByteCodeExprGen::visitInitializer(const Expr *E) { +bool Compiler::visitInitializer(const Expr *E) { assert(!classify(E->getType())); if (E->containsErrors()) @@ -2996,8 +3105,7 @@ bool ByteCodeExprGen::visitInitializer(const Expr *E) { return this->Visit(E); } -template -bool ByteCodeExprGen::visitBool(const Expr *E) { +template bool Compiler::visitBool(const Expr *E) { std::optional T = classify(E->getType()); if (!T) { // Convert complex values to bool. @@ -3031,8 +3139,8 @@ bool ByteCodeExprGen::visitBool(const Expr *E) { } template -bool ByteCodeExprGen::visitZeroInitializer(PrimType T, QualType QT, - const Expr *E) { +bool Compiler::visitZeroInitializer(PrimType T, QualType QT, + const Expr *E) { switch (T) { case PT_Bool: return this->emitZeroBool(E); @@ -3070,8 +3178,8 @@ bool ByteCodeExprGen::visitZeroInitializer(PrimType T, QualType QT, } template -bool ByteCodeExprGen::visitZeroRecordInitializer(const Record *R, - const Expr *E) { +bool Compiler::visitZeroRecordInitializer(const Record *R, + const Expr *E) { assert(E); assert(R); // Fields @@ -3139,7 +3247,7 @@ bool ByteCodeExprGen::visitZeroRecordInitializer(const Record *R, template template -bool ByteCodeExprGen::emitConst(T Value, PrimType Ty, const Expr *E) { +bool Compiler::emitConst(T Value, PrimType Ty, const Expr *E) { switch (Ty) { case PT_Sint8: return this->emitConstSint8(Value, E); @@ -3173,13 +3281,13 @@ bool ByteCodeExprGen::emitConst(T Value, PrimType Ty, const Expr *E) { template template -bool ByteCodeExprGen::emitConst(T Value, const Expr *E) { +bool Compiler::emitConst(T Value, const Expr *E) { return this->emitConst(Value, classifyPrim(E->getType()), E); } template -bool ByteCodeExprGen::emitConst(const APSInt &Value, PrimType Ty, - const Expr *E) { +bool Compiler::emitConst(const APSInt &Value, PrimType Ty, + const Expr *E) { if (Ty == PT_IntAPS) return this->emitConstIntAPS(Value, E); if (Ty == PT_IntAP) @@ -3191,15 +3299,14 @@ bool ByteCodeExprGen::emitConst(const APSInt &Value, PrimType Ty, } template -bool ByteCodeExprGen::emitConst(const APSInt &Value, const Expr *E) { +bool Compiler::emitConst(const APSInt &Value, const Expr *E) { return this->emitConst(Value, classifyPrim(E->getType()), E); } template -unsigned ByteCodeExprGen::allocateLocalPrimitive(DeclTy &&Src, - PrimType Ty, - bool IsConst, - bool IsExtended) { +unsigned Compiler::allocateLocalPrimitive(DeclTy &&Src, PrimType Ty, + bool IsConst, + bool IsExtended) { // Make sure we don't accidentally register the same decl twice. if (const auto *VD = dyn_cast_if_present(Src.dyn_cast())) { @@ -3222,10 +3329,9 @@ unsigned ByteCodeExprGen::allocateLocalPrimitive(DeclTy &&Src, template std::optional -ByteCodeExprGen::allocateLocal(DeclTy &&Src, - const ValueDecl *ExtendingDecl) { +Compiler::allocateLocal(DeclTy &&Src, const ValueDecl *ExtendingDecl) { // Make sure we don't accidentally register the same decl twice. - if ([[maybe_unused]] const auto *VD = + if ([[maybe_unused]] const auto *VD = dyn_cast_if_present(Src.dyn_cast())) { assert(!P.getGlobal(VD)); assert(!Locals.contains(VD)); @@ -3264,31 +3370,29 @@ ByteCodeExprGen::allocateLocal(DeclTy &&Src, } template -const RecordType *ByteCodeExprGen::getRecordTy(QualType Ty) { +const RecordType *Compiler::getRecordTy(QualType Ty) { if (const PointerType *PT = dyn_cast(Ty)) return PT->getPointeeType()->getAs(); return Ty->getAs(); } -template -Record *ByteCodeExprGen::getRecord(QualType Ty) { +template Record *Compiler::getRecord(QualType Ty) { if (const auto *RecordTy = getRecordTy(Ty)) return getRecord(RecordTy->getDecl()); return nullptr; } template -Record *ByteCodeExprGen::getRecord(const RecordDecl *RD) { +Record *Compiler::getRecord(const RecordDecl *RD) { return P.getOrCreateRecord(RD); } template -const Function *ByteCodeExprGen::getFunction(const FunctionDecl *FD) { +const Function *Compiler::getFunction(const FunctionDecl *FD) { return Ctx.getOrCreateFunction(FD); } -template -bool ByteCodeExprGen::visitExpr(const Expr *E) { +template bool Compiler::visitExpr(const Expr *E) { ExprScope RootScope(this); // Void expressions. if (E->getType()->isVoidType()) { @@ -3330,8 +3434,7 @@ bool ByteCodeExprGen::visitExpr(const Expr *E) { /// We get here from evaluateAsInitializer(). /// We need to evaluate the initializer and return its value. template -bool ByteCodeExprGen::visitDecl(const VarDecl *VD, - bool ConstantContext) { +bool Compiler::visitDecl(const VarDecl *VD, bool ConstantContext) { assert(!VD->isInvalidDecl() && "Trying to constant evaluate an invalid decl"); std::optional VarT = classify(VD->getType()); @@ -3404,11 +3507,16 @@ bool ByteCodeExprGen::visitDecl(const VarDecl *VD, } template -bool ByteCodeExprGen::visitVarDecl(const VarDecl *VD) { +VarCreationState Compiler::visitVarDecl(const VarDecl *VD) { // We don't know what to do with these, so just return false. if (VD->getType().isNull()) return false; + // This case is EvalEmitter-only. If we won't create any instructions for the + // initializer anyway, don't bother creating the variable in the first place. + if (!this->isActive()) + return VarCreationState::NotCreated(); + const Expr *Init = VD->getInit(); std::optional VarT = classify(VD->getType()); @@ -3467,8 +3575,8 @@ bool ByteCodeExprGen::visitVarDecl(const VarDecl *VD) { } template -bool ByteCodeExprGen::visitAPValue(const APValue &Val, - PrimType ValType, const Expr *E) { +bool Compiler::visitAPValue(const APValue &Val, PrimType ValType, + const Expr *E) { assert(!DiscardResult); if (Val.isInt()) return this->emitConst(Val.getInt(), ValType, E); @@ -3494,8 +3602,8 @@ bool ByteCodeExprGen::visitAPValue(const APValue &Val, } template -bool ByteCodeExprGen::visitAPValueInitializer(const APValue &Val, - const Expr *E) { +bool Compiler::visitAPValueInitializer(const APValue &Val, + const Expr *E) { if (Val.isStruct()) { const Record *R = this->getRecord(E->getType()); @@ -3557,7 +3665,7 @@ bool ByteCodeExprGen::visitAPValueInitializer(const APValue &Val, } template -bool ByteCodeExprGen::VisitBuiltinCallExpr(const CallExpr *E) { +bool Compiler::VisitBuiltinCallExpr(const CallExpr *E) { const Function *Func = getFunction(E->getDirectCallee()); if (!Func) return false; @@ -3567,9 +3675,16 @@ bool ByteCodeExprGen::VisitBuiltinCallExpr(const CallExpr *E) { unsigned Builtin = E->getBuiltinCallee(); if (Builtin == Builtin::BI__builtin___CFStringMakeConstantString || Builtin == Builtin::BI__builtin___NSStringMakeConstantString || + Builtin == Builtin::BI__builtin_ptrauth_sign_constant || Builtin == Builtin::BI__builtin_function_start) { - if (std::optional GlobalOffset = P.createGlobal(E)) - return this->emitGetPtrGlobal(*GlobalOffset, E); + if (std::optional GlobalOffset = P.createGlobal(E)) { + if (!this->emitGetPtrGlobal(*GlobalOffset, E)) + return false; + + if (PrimType PT = classifyPrim(E); PT != PT_Ptr && isPtrType(PT)) + return this->emitDecayPtr(PT_Ptr, PT, E); + return true; + } return false; } @@ -3605,7 +3720,7 @@ bool ByteCodeExprGen::VisitBuiltinCallExpr(const CallExpr *E) { } template -bool ByteCodeExprGen::VisitCallExpr(const CallExpr *E) { +bool Compiler::VisitCallExpr(const CallExpr *E) { if (E->getBuiltinCallee()) return VisitBuiltinCallExpr(E); @@ -3765,8 +3880,7 @@ bool ByteCodeExprGen::VisitCallExpr(const CallExpr *E) { } template -bool ByteCodeExprGen::VisitCXXDefaultInitExpr( - const CXXDefaultInitExpr *E) { +bool Compiler::VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) { SourceLocScope SLS(this, E); bool Old = InitStackActive; @@ -3777,8 +3891,7 @@ bool ByteCodeExprGen::VisitCXXDefaultInitExpr( } template -bool ByteCodeExprGen::VisitCXXDefaultArgExpr( - const CXXDefaultArgExpr *E) { +bool Compiler::VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) { SourceLocScope SLS(this, E); const Expr *SubExpr = E->getExpr(); @@ -3790,8 +3903,7 @@ bool ByteCodeExprGen::VisitCXXDefaultArgExpr( } template -bool ByteCodeExprGen::VisitCXXBoolLiteralExpr( - const CXXBoolLiteralExpr *E) { +bool Compiler::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) { if (DiscardResult) return true; @@ -3799,7 +3911,7 @@ bool ByteCodeExprGen::VisitCXXBoolLiteralExpr( } template -bool ByteCodeExprGen::VisitCXXNullPtrLiteralExpr( +bool Compiler::VisitCXXNullPtrLiteralExpr( const CXXNullPtrLiteralExpr *E) { if (DiscardResult) return true; @@ -3808,7 +3920,7 @@ bool ByteCodeExprGen::VisitCXXNullPtrLiteralExpr( } template -bool ByteCodeExprGen::VisitGNUNullExpr(const GNUNullExpr *E) { +bool Compiler::VisitGNUNullExpr(const GNUNullExpr *E) { if (DiscardResult) return true; @@ -3819,7 +3931,7 @@ bool ByteCodeExprGen::VisitGNUNullExpr(const GNUNullExpr *E) { } template -bool ByteCodeExprGen::VisitCXXThisExpr(const CXXThisExpr *E) { +bool Compiler::VisitCXXThisExpr(const CXXThisExpr *E) { if (DiscardResult) return true; @@ -3843,8 +3955,640 @@ bool ByteCodeExprGen::VisitCXXThisExpr(const CXXThisExpr *E) { return this->emitThis(E); } +template bool Compiler::visitStmt(const Stmt *S) { + switch (S->getStmtClass()) { + case Stmt::CompoundStmtClass: + return visitCompoundStmt(cast(S)); + case Stmt::DeclStmtClass: + return visitDeclStmt(cast(S)); + case Stmt::ReturnStmtClass: + return visitReturnStmt(cast(S)); + case Stmt::IfStmtClass: + return visitIfStmt(cast(S)); + case Stmt::WhileStmtClass: + return visitWhileStmt(cast(S)); + case Stmt::DoStmtClass: + return visitDoStmt(cast(S)); + case Stmt::ForStmtClass: + return visitForStmt(cast(S)); + case Stmt::CXXForRangeStmtClass: + return visitCXXForRangeStmt(cast(S)); + case Stmt::BreakStmtClass: + return visitBreakStmt(cast(S)); + case Stmt::ContinueStmtClass: + return visitContinueStmt(cast(S)); + case Stmt::SwitchStmtClass: + return visitSwitchStmt(cast(S)); + case Stmt::CaseStmtClass: + return visitCaseStmt(cast(S)); + case Stmt::DefaultStmtClass: + return visitDefaultStmt(cast(S)); + case Stmt::AttributedStmtClass: + return visitAttributedStmt(cast(S)); + case Stmt::CXXTryStmtClass: + return visitCXXTryStmt(cast(S)); + case Stmt::NullStmtClass: + return true; + // Always invalid statements. + case Stmt::GCCAsmStmtClass: + case Stmt::MSAsmStmtClass: + case Stmt::GotoStmtClass: + return this->emitInvalid(S); + case Stmt::LabelStmtClass: + return this->visitStmt(cast(S)->getSubStmt()); + default: { + if (const auto *E = dyn_cast(S)) + return this->discard(E); + return false; + } + } +} + +/// Visits the given statment without creating a variable +/// scope for it in case it is a compound statement. +template bool Compiler::visitLoopBody(const Stmt *S) { + if (isa(S)) + return true; + + if (const auto *CS = dyn_cast(S)) { + for (auto *InnerStmt : CS->body()) + if (!visitStmt(InnerStmt)) + return false; + return true; + } + + return this->visitStmt(S); +} + +template +bool Compiler::visitCompoundStmt(const CompoundStmt *S) { + BlockScope Scope(this); + for (auto *InnerStmt : S->body()) + if (!visitStmt(InnerStmt)) + return false; + return true; +} + +template +bool Compiler::visitDeclStmt(const DeclStmt *DS) { + for (auto *D : DS->decls()) { + if (isa(D)) + continue; + + const auto *VD = dyn_cast(D); + if (!VD) + return false; + if (!this->visitVarDecl(VD)) + return false; + } + + return true; +} + +template +bool Compiler::visitReturnStmt(const ReturnStmt *RS) { + if (const Expr *RE = RS->getRetValue()) { + ExprScope RetScope(this); + if (ReturnType) { + // Primitive types are simply returned. + if (!this->visit(RE)) + return false; + this->emitCleanup(); + return this->emitRet(*ReturnType, RS); + } else if (RE->getType()->isVoidType()) { + if (!this->visit(RE)) + return false; + } else { + // RVO - construct the value in the return location. + if (!this->emitRVOPtr(RE)) + return false; + if (!this->visitInitializer(RE)) + return false; + if (!this->emitPopPtr(RE)) + return false; + + this->emitCleanup(); + return this->emitRetVoid(RS); + } + } + + // Void return. + this->emitCleanup(); + return this->emitRetVoid(RS); +} + +template bool Compiler::visitIfStmt(const IfStmt *IS) { + BlockScope IfScope(this); + + if (IS->isNonNegatedConsteval()) + return visitStmt(IS->getThen()); + if (IS->isNegatedConsteval()) + return IS->getElse() ? visitStmt(IS->getElse()) : true; + + if (auto *CondInit = IS->getInit()) + if (!visitStmt(CondInit)) + return false; + + if (const DeclStmt *CondDecl = IS->getConditionVariableDeclStmt()) + if (!visitDeclStmt(CondDecl)) + return false; + + if (!this->visitBool(IS->getCond())) + return false; + + if (const Stmt *Else = IS->getElse()) { + LabelTy LabelElse = this->getLabel(); + LabelTy LabelEnd = this->getLabel(); + if (!this->jumpFalse(LabelElse)) + return false; + if (!visitStmt(IS->getThen())) + return false; + if (!this->jump(LabelEnd)) + return false; + this->emitLabel(LabelElse); + if (!visitStmt(Else)) + return false; + this->emitLabel(LabelEnd); + } else { + LabelTy LabelEnd = this->getLabel(); + if (!this->jumpFalse(LabelEnd)) + return false; + if (!visitStmt(IS->getThen())) + return false; + this->emitLabel(LabelEnd); + } + + return true; +} + +template +bool Compiler::visitWhileStmt(const WhileStmt *S) { + const Expr *Cond = S->getCond(); + const Stmt *Body = S->getBody(); + + LabelTy CondLabel = this->getLabel(); // Label before the condition. + LabelTy EndLabel = this->getLabel(); // Label after the loop. + LoopScope LS(this, EndLabel, CondLabel); + + this->emitLabel(CondLabel); + + if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt()) + if (!visitDeclStmt(CondDecl)) + return false; + + if (!this->visitBool(Cond)) + return false; + if (!this->jumpFalse(EndLabel)) + return false; + + LocalScope Scope(this); + { + DestructorScope DS(Scope); + if (!this->visitLoopBody(Body)) + return false; + } + + if (!this->jump(CondLabel)) + return false; + this->emitLabel(EndLabel); + + return true; +} + +template bool Compiler::visitDoStmt(const DoStmt *S) { + const Expr *Cond = S->getCond(); + const Stmt *Body = S->getBody(); + + LabelTy StartLabel = this->getLabel(); + LabelTy EndLabel = this->getLabel(); + LabelTy CondLabel = this->getLabel(); + LoopScope LS(this, EndLabel, CondLabel); + LocalScope Scope(this); + + this->emitLabel(StartLabel); + { + DestructorScope DS(Scope); + + if (!this->visitLoopBody(Body)) + return false; + this->emitLabel(CondLabel); + if (!this->visitBool(Cond)) + return false; + } + if (!this->jumpTrue(StartLabel)) + return false; + + this->emitLabel(EndLabel); + return true; +} + +template +bool Compiler::visitForStmt(const ForStmt *S) { + // for (Init; Cond; Inc) { Body } + const Stmt *Init = S->getInit(); + const Expr *Cond = S->getCond(); + const Expr *Inc = S->getInc(); + const Stmt *Body = S->getBody(); + + LabelTy EndLabel = this->getLabel(); + LabelTy CondLabel = this->getLabel(); + LabelTy IncLabel = this->getLabel(); + LoopScope LS(this, EndLabel, IncLabel); + LocalScope Scope(this); + + if (Init && !this->visitStmt(Init)) + return false; + this->emitLabel(CondLabel); + + if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt()) + if (!visitDeclStmt(CondDecl)) + return false; + + if (Cond) { + if (!this->visitBool(Cond)) + return false; + if (!this->jumpFalse(EndLabel)) + return false; + } + + { + DestructorScope DS(Scope); + + if (Body && !this->visitLoopBody(Body)) + return false; + this->emitLabel(IncLabel); + if (Inc && !this->discard(Inc)) + return false; + } + + if (!this->jump(CondLabel)) + return false; + this->emitLabel(EndLabel); + return true; +} + +template +bool Compiler::visitCXXForRangeStmt(const CXXForRangeStmt *S) { + const Stmt *Init = S->getInit(); + const Expr *Cond = S->getCond(); + const Expr *Inc = S->getInc(); + const Stmt *Body = S->getBody(); + const Stmt *BeginStmt = S->getBeginStmt(); + const Stmt *RangeStmt = S->getRangeStmt(); + const Stmt *EndStmt = S->getEndStmt(); + const VarDecl *LoopVar = S->getLoopVariable(); + + LabelTy EndLabel = this->getLabel(); + LabelTy CondLabel = this->getLabel(); + LabelTy IncLabel = this->getLabel(); + LoopScope LS(this, EndLabel, IncLabel); + + // Emit declarations needed in the loop. + if (Init && !this->visitStmt(Init)) + return false; + if (!this->visitStmt(RangeStmt)) + return false; + if (!this->visitStmt(BeginStmt)) + return false; + if (!this->visitStmt(EndStmt)) + return false; + + // Now the condition as well as the loop variable assignment. + this->emitLabel(CondLabel); + if (!this->visitBool(Cond)) + return false; + if (!this->jumpFalse(EndLabel)) + return false; + + if (!this->visitVarDecl(LoopVar)) + return false; + + // Body. + LocalScope Scope(this); + { + DestructorScope DS(Scope); + + if (!this->visitLoopBody(Body)) + return false; + this->emitLabel(IncLabel); + if (!this->discard(Inc)) + return false; + } + if (!this->jump(CondLabel)) + return false; + + this->emitLabel(EndLabel); + return true; +} + +template +bool Compiler::visitBreakStmt(const BreakStmt *S) { + if (!BreakLabel) + return false; + + this->VarScope->emitDestructors(); + return this->jump(*BreakLabel); +} + +template +bool Compiler::visitContinueStmt(const ContinueStmt *S) { + if (!ContinueLabel) + return false; + + this->VarScope->emitDestructors(); + return this->jump(*ContinueLabel); +} + +template +bool Compiler::visitSwitchStmt(const SwitchStmt *S) { + const Expr *Cond = S->getCond(); + PrimType CondT = this->classifyPrim(Cond->getType()); + + LabelTy EndLabel = this->getLabel(); + OptLabelTy DefaultLabel = std::nullopt; + unsigned CondVar = this->allocateLocalPrimitive(Cond, CondT, true, false); + + if (const auto *CondInit = S->getInit()) + if (!visitStmt(CondInit)) + return false; + + if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt()) + if (!visitDeclStmt(CondDecl)) + return false; + + // Initialize condition variable. + if (!this->visit(Cond)) + return false; + if (!this->emitSetLocal(CondT, CondVar, S)) + return false; + + CaseMap CaseLabels; + // Create labels and comparison ops for all case statements. + for (const SwitchCase *SC = S->getSwitchCaseList(); SC; + SC = SC->getNextSwitchCase()) { + if (const auto *CS = dyn_cast(SC)) { + // FIXME: Implement ranges. + if (CS->caseStmtIsGNURange()) + return false; + CaseLabels[SC] = this->getLabel(); + + const Expr *Value = CS->getLHS(); + PrimType ValueT = this->classifyPrim(Value->getType()); + + // Compare the case statement's value to the switch condition. + if (!this->emitGetLocal(CondT, CondVar, CS)) + return false; + if (!this->visit(Value)) + return false; + + // Compare and jump to the case label. + if (!this->emitEQ(ValueT, S)) + return false; + if (!this->jumpTrue(CaseLabels[CS])) + return false; + } else { + assert(!DefaultLabel); + DefaultLabel = this->getLabel(); + } + } + + // If none of the conditions above were true, fall through to the default + // statement or jump after the switch statement. + if (DefaultLabel) { + if (!this->jump(*DefaultLabel)) + return false; + } else { + if (!this->jump(EndLabel)) + return false; + } + + SwitchScope SS(this, std::move(CaseLabels), EndLabel, DefaultLabel); + if (!this->visitStmt(S->getBody())) + return false; + this->emitLabel(EndLabel); + return true; +} + template -bool ByteCodeExprGen::VisitUnaryOperator(const UnaryOperator *E) { +bool Compiler::visitCaseStmt(const CaseStmt *S) { + this->emitLabel(CaseLabels[S]); + return this->visitStmt(S->getSubStmt()); +} + +template +bool Compiler::visitDefaultStmt(const DefaultStmt *S) { + this->emitLabel(*DefaultLabel); + return this->visitStmt(S->getSubStmt()); +} + +template +bool Compiler::visitAttributedStmt(const AttributedStmt *S) { + if (this->Ctx.getLangOpts().CXXAssumptions && + !this->Ctx.getLangOpts().MSVCCompat) { + for (const Attr *A : S->getAttrs()) { + auto *AA = dyn_cast(A); + if (!AA) + continue; + + assert(isa(S->getSubStmt())); + + const Expr *Assumption = AA->getAssumption(); + if (Assumption->isValueDependent()) + return false; + + if (Assumption->HasSideEffects(this->Ctx.getASTContext())) + continue; + + // Evaluate assumption. + if (!this->visitBool(Assumption)) + return false; + + if (!this->emitAssume(Assumption)) + return false; + } + } + + // Ignore other attributes. + return this->visitStmt(S->getSubStmt()); +} + +template +bool Compiler::visitCXXTryStmt(const CXXTryStmt *S) { + // Ignore all handlers. + return this->visitStmt(S->getTryBlock()); +} + +template +bool Compiler::emitLambdaStaticInvokerBody(const CXXMethodDecl *MD) { + assert(MD->isLambdaStaticInvoker()); + assert(MD->hasBody()); + assert(cast(MD->getBody())->body_empty()); + + const CXXRecordDecl *ClosureClass = MD->getParent(); + const CXXMethodDecl *LambdaCallOp = ClosureClass->getLambdaCallOperator(); + assert(ClosureClass->captures_begin() == ClosureClass->captures_end()); + const Function *Func = this->getFunction(LambdaCallOp); + if (!Func) + return false; + assert(Func->hasThisPointer()); + assert(Func->getNumParams() == (MD->getNumParams() + 1 + Func->hasRVO())); + + if (Func->hasRVO()) { + if (!this->emitRVOPtr(MD)) + return false; + } + + // The lambda call operator needs an instance pointer, but we don't have + // one here, and we don't need one either because the lambda cannot have + // any captures, as verified above. Emit a null pointer. This is then + // special-cased when interpreting to not emit any misleading diagnostics. + if (!this->emitNullPtr(nullptr, MD)) + return false; + + // Forward all arguments from the static invoker to the lambda call operator. + for (const ParmVarDecl *PVD : MD->parameters()) { + auto It = this->Params.find(PVD); + assert(It != this->Params.end()); + + // We do the lvalue-to-rvalue conversion manually here, so no need + // to care about references. + PrimType ParamType = this->classify(PVD->getType()).value_or(PT_Ptr); + if (!this->emitGetParam(ParamType, It->second.Offset, MD)) + return false; + } + + if (!this->emitCall(Func, 0, LambdaCallOp)) + return false; + + this->emitCleanup(); + if (ReturnType) + return this->emitRet(*ReturnType, MD); + + // Nothing to do, since we emitted the RVO pointer above. + return this->emitRetVoid(MD); +} + +template +bool Compiler::visitFunc(const FunctionDecl *F) { + // Classify the return type. + ReturnType = this->classify(F->getReturnType()); + + auto emitFieldInitializer = [&](const Record::Field *F, unsigned FieldOffset, + const Expr *InitExpr) -> bool { + // We don't know what to do with these, so just return false. + if (InitExpr->getType().isNull()) + return false; + + if (std::optional T = this->classify(InitExpr)) { + if (!this->visit(InitExpr)) + return false; + + if (F->isBitField()) + return this->emitInitThisBitField(*T, F, FieldOffset, InitExpr); + return this->emitInitThisField(*T, FieldOffset, InitExpr); + } + // Non-primitive case. Get a pointer to the field-to-initialize + // on the stack and call visitInitialzer() for it. + InitLinkScope FieldScope(this, InitLink::Field(F->Offset)); + if (!this->emitGetPtrThisField(FieldOffset, InitExpr)) + return false; + + if (!this->visitInitializer(InitExpr)) + return false; + + return this->emitPopPtr(InitExpr); + }; + + // Emit custom code if this is a lambda static invoker. + if (const auto *MD = dyn_cast(F); + MD && MD->isLambdaStaticInvoker()) + return this->emitLambdaStaticInvokerBody(MD); + + // Constructor. Set up field initializers. + if (const auto *Ctor = dyn_cast(F)) { + const RecordDecl *RD = Ctor->getParent(); + const Record *R = this->getRecord(RD); + if (!R) + return false; + + InitLinkScope InitScope(this, InitLink::This()); + for (const auto *Init : Ctor->inits()) { + // Scope needed for the initializers. + BlockScope Scope(this); + + const Expr *InitExpr = Init->getInit(); + if (const FieldDecl *Member = Init->getMember()) { + const Record::Field *F = R->getField(Member); + + if (!emitFieldInitializer(F, F->Offset, InitExpr)) + return false; + } else if (const Type *Base = Init->getBaseClass()) { + const auto *BaseDecl = Base->getAsCXXRecordDecl(); + assert(BaseDecl); + + if (Init->isBaseVirtual()) { + assert(R->getVirtualBase(BaseDecl)); + if (!this->emitGetPtrThisVirtBase(BaseDecl, InitExpr)) + return false; + + } else { + // Base class initializer. + // Get This Base and call initializer on it. + const Record::Base *B = R->getBase(BaseDecl); + assert(B); + if (!this->emitGetPtrThisBase(B->Offset, InitExpr)) + return false; + } + + if (!this->visitInitializer(InitExpr)) + return false; + if (!this->emitFinishInitPop(InitExpr)) + return false; + } else if (const IndirectFieldDecl *IFD = Init->getIndirectMember()) { + assert(IFD->getChainingSize() >= 2); + + unsigned NestedFieldOffset = 0; + const Record::Field *NestedField = nullptr; + for (const NamedDecl *ND : IFD->chain()) { + const auto *FD = cast(ND); + const Record *FieldRecord = + this->P.getOrCreateRecord(FD->getParent()); + assert(FieldRecord); + + NestedField = FieldRecord->getField(FD); + assert(NestedField); + + NestedFieldOffset += NestedField->Offset; + } + assert(NestedField); + + if (!emitFieldInitializer(NestedField, NestedFieldOffset, InitExpr)) + return false; + } else { + assert(Init->isDelegatingInitializer()); + if (!this->emitThis(InitExpr)) + return false; + if (!this->visitInitializer(Init->getInit())) + return false; + if (!this->emitPopPtr(InitExpr)) + return false; + } + } + } + + if (const auto *Body = F->getBody()) + if (!visitStmt(Body)) + return false; + + // Emit a guard return to protect against a code path missing one. + if (F->getReturnType()->isVoidType()) + return this->emitRetVoid(SourceInfo{}); + return this->emitNoRet(SourceInfo{}); +} + +template +bool Compiler::VisitUnaryOperator(const UnaryOperator *E) { const Expr *SubExpr = E->getSubExpr(); if (SubExpr->getType()->isAnyComplexType()) return this->VisitComplexUnaryOperator(E); @@ -4004,7 +4748,7 @@ bool ByteCodeExprGen::VisitUnaryOperator(const UnaryOperator *E) { if (!this->visit(SubExpr)) return false; return DiscardResult ? this->emitPop(*T, E) : this->emitNeg(*T, E); - case UO_Plus: // +x + case UO_Plus: // +x if (!this->visit(SubExpr)) // noop return false; return DiscardResult ? this->emitPop(*T, E) : true; @@ -4016,11 +4760,11 @@ bool ByteCodeExprGen::VisitUnaryOperator(const UnaryOperator *E) { } // We should already have a pointer when we get here. return this->delegate(SubExpr); - case UO_Deref: // *x + case UO_Deref: // *x if (DiscardResult) return this->discard(SubExpr); return this->visit(SubExpr); - case UO_Not: // ~x + case UO_Not: // ~x if (!this->visit(SubExpr)) return false; return DiscardResult ? this->emitPop(*T, E) : this->emitComp(*T, E); @@ -4043,8 +4787,7 @@ bool ByteCodeExprGen::VisitUnaryOperator(const UnaryOperator *E) { } template -bool ByteCodeExprGen::VisitComplexUnaryOperator( - const UnaryOperator *E) { +bool Compiler::VisitComplexUnaryOperator(const UnaryOperator *E) { const Expr *SubExpr = E->getSubExpr(); assert(SubExpr->getType()->isAnyComplexType()); @@ -4151,7 +4894,7 @@ bool ByteCodeExprGen::VisitComplexUnaryOperator( } template -bool ByteCodeExprGen::visitDeclRef(const ValueDecl *D, const Expr *E) { +bool Compiler::visitDeclRef(const ValueDecl *D, const Expr *E) { if (DiscardResult) return true; @@ -4189,8 +4932,11 @@ bool ByteCodeExprGen::visitDeclRef(const ValueDecl *D, const Expr *E) { return this->emitGetLocal(PT_Ptr, Offset, E); return this->emitGetPtrLocal(Offset, E); } else if (auto GlobalIndex = P.getGlobal(D)) { - if (IsReference) - return this->emitGetGlobal(classifyPrim(E), *GlobalIndex, E); + if (IsReference) { + if (!Ctx.getLangOpts().CPlusPlus11) + return this->emitGetGlobal(classifyPrim(E), *GlobalIndex, E); + return this->emitGetGlobalUnchecked(classifyPrim(E), *GlobalIndex, E); + } return this->emitGetPtrGlobal(*GlobalIndex, E); } else if (const auto *PVD = dyn_cast(D)) { @@ -4237,7 +4983,10 @@ bool ByteCodeExprGen::visitDeclRef(const ValueDecl *D, const Expr *E) { if ((VD->hasGlobalStorage() || VD->isLocalVarDecl() || VD->isStaticDataMember()) && typeShouldBeVisited(VD->getType())) { - if (!this->visitVarDecl(VD)) + auto VarState = this->visitVarDecl(VD); + if (VarState.notCreated()) + return true; + if (!VarState) return false; // Retry. return this->visitDeclRef(VD, E); @@ -4247,7 +4996,10 @@ bool ByteCodeExprGen::visitDeclRef(const ValueDecl *D, const Expr *E) { if (const auto *VD = dyn_cast(D); VD && VD->getAnyInitializer() && VD->getType().isConstant(Ctx.getASTContext()) && !VD->isWeak()) { - if (!this->visitVarDecl(VD)) + auto VarState = this->visitVarDecl(VD); + if (VarState.notCreated()) + return true; + if (!VarState) return false; // Retry. return this->visitDeclRef(VD, E); @@ -4274,21 +5026,19 @@ bool ByteCodeExprGen::visitDeclRef(const ValueDecl *D, const Expr *E) { } template -bool ByteCodeExprGen::VisitDeclRefExpr(const DeclRefExpr *E) { +bool Compiler::VisitDeclRefExpr(const DeclRefExpr *E) { const auto *D = E->getDecl(); return this->visitDeclRef(D, E); } -template -void ByteCodeExprGen::emitCleanup() { +template void Compiler::emitCleanup() { for (VariableScope *C = VarScope; C; C = C->getParent()) C->emitDestruction(); } template -unsigned -ByteCodeExprGen::collectBaseOffset(const QualType BaseType, - const QualType DerivedType) { +unsigned Compiler::collectBaseOffset(const QualType BaseType, + const QualType DerivedType) { const auto extractRecordDecl = [](QualType Ty) -> const CXXRecordDecl * { if (const auto *PT = dyn_cast(Ty)) return PT->getPointeeType()->getAsCXXRecordDecl(); @@ -4302,8 +5052,8 @@ ByteCodeExprGen::collectBaseOffset(const QualType BaseType, /// Emit casts from a PrimType to another PrimType. template -bool ByteCodeExprGen::emitPrimCast(PrimType FromT, PrimType ToT, - QualType ToQT, const Expr *E) { +bool Compiler::emitPrimCast(PrimType FromT, PrimType ToT, + QualType ToQT, const Expr *E) { if (FromT == PT_Float) { // Floating to floating. @@ -4345,7 +5095,7 @@ bool ByteCodeExprGen::emitPrimCast(PrimType FromT, PrimType ToT, /// Emits __real(SubExpr) template -bool ByteCodeExprGen::emitComplexReal(const Expr *SubExpr) { +bool Compiler::emitComplexReal(const Expr *SubExpr) { assert(SubExpr->getType()->isAnyComplexType()); if (DiscardResult) @@ -4365,7 +5115,7 @@ bool ByteCodeExprGen::emitComplexReal(const Expr *SubExpr) { } template -bool ByteCodeExprGen::emitComplexBoolCast(const Expr *E) { +bool Compiler::emitComplexBoolCast(const Expr *E) { assert(!DiscardResult); PrimType ElemT = classifyComplexElementType(E->getType()); // We emit the expression (__real(E) != 0 || __imag(E) != 0) @@ -4411,9 +5161,8 @@ bool ByteCodeExprGen::emitComplexBoolCast(const Expr *E) { } template -bool ByteCodeExprGen::emitComplexComparison(const Expr *LHS, - const Expr *RHS, - const BinaryOperator *E) { +bool Compiler::emitComplexComparison(const Expr *LHS, const Expr *RHS, + const BinaryOperator *E) { assert(E->isComparisonOp()); assert(!Initializing); assert(!DiscardResult); @@ -4510,7 +5259,7 @@ bool ByteCodeExprGen::emitComplexComparison(const Expr *LHS, /// on the stack. /// Emit destruction of record types (or arrays of record types). template -bool ByteCodeExprGen::emitRecordDestruction(const Record *R) { +bool Compiler::emitRecordDestruction(const Record *R) { assert(R); // First, destroy all fields. for (const Record::Field &Field : llvm::reverse(R->fields())) { @@ -4558,7 +5307,7 @@ bool ByteCodeExprGen::emitRecordDestruction(const Record *R) { /// on the stack. /// Emit destruction of record types (or arrays of record types). template -bool ByteCodeExprGen::emitDestruction(const Descriptor *Desc) { +bool Compiler::emitDestruction(const Descriptor *Desc) { assert(Desc); assert(!Desc->isPrimitive()); assert(!Desc->isPrimitiveArray()); @@ -4601,8 +5350,8 @@ bool ByteCodeExprGen::emitDestruction(const Descriptor *Desc) { namespace clang { namespace interp { -template class ByteCodeExprGen; -template class ByteCodeExprGen; +template class Compiler; +template class Compiler; } // namespace interp } // namespace clang diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/Compiler.h similarity index 84% rename from clang/lib/AST/Interp/ByteCodeExprGen.h rename to clang/lib/AST/Interp/Compiler.h index eef8cae6e38cd8..d188ce2200664f 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/Compiler.h @@ -1,4 +1,4 @@ -//===--- ByteCodeExprGen.h - Code generator for expressions -----*- C++ -*-===// +//===--- Compiler.h - Code generator for expressions -----*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -36,8 +36,11 @@ template class InitLinkScope; template class OptionScope; template class ArrayIndexScope; template class SourceLocScope; +template class LoopScope; +template class LabelScope; +template class SwitchScope; -template class ByteCodeExprGen; +template class Compiler; struct InitLink { public: enum { @@ -60,7 +63,7 @@ struct InitLink { InitLink(uint8_t Kind) : Kind(Kind) {} template - bool emit(ByteCodeExprGen *Ctx, const Expr *E) const; + bool emit(Compiler *Ctx, const Expr *E) const; private: uint32_t Kind; @@ -70,14 +73,28 @@ struct InitLink { }; }; +/// State encapsulating if a the variable creation has been successful, +/// unsuccessful, or no variable has been created at all. +struct VarCreationState { + std::optional S = std::nullopt; + VarCreationState() = default; + VarCreationState(bool b) : S(b) {} + static VarCreationState NotCreated() { return VarCreationState(); } + + operator bool() const { return S && *S; } + bool notCreated() const { return !S; } +}; + /// Compilation context for expressions. template -class ByteCodeExprGen : public ConstStmtVisitor, bool>, - public Emitter { +class Compiler : public ConstStmtVisitor, bool>, + public Emitter { protected: // Aliases for types defined in the emitter. using LabelTy = typename Emitter::LabelTy; using AddrTy = typename Emitter::AddrTy; + using OptLabelTy = std::optional; + using CaseMap = llvm::DenseMap; /// Current compilation context. Context &Ctx; @@ -87,10 +104,10 @@ class ByteCodeExprGen : public ConstStmtVisitor, bool>, public: /// Initializes the compiler and the backend emitter. template - ByteCodeExprGen(Context &Ctx, Program &P, Tys &&... Args) + Compiler(Context &Ctx, Program &P, Tys &&...Args) : Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {} - // Expression visitors - result returned on interp stack. + // Expressions. bool VisitCastExpr(const CastExpr *E); bool VisitIntegerLiteral(const IntegerLiteral *E); bool VisitFloatingLiteral(const FloatingLiteral *E); @@ -165,10 +182,32 @@ class ByteCodeExprGen : public ConstStmtVisitor, bool>, bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E); bool VisitExtVectorElementExpr(const ExtVectorElementExpr *E); bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E); + bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E); + bool VisitStmtExpr(const StmtExpr *E); + + // Statements. + bool visitCompoundStmt(const CompoundStmt *S); + bool visitLoopBody(const Stmt *S); + bool visitDeclStmt(const DeclStmt *DS); + bool visitReturnStmt(const ReturnStmt *RS); + bool visitIfStmt(const IfStmt *IS); + bool visitWhileStmt(const WhileStmt *S); + bool visitDoStmt(const DoStmt *S); + bool visitForStmt(const ForStmt *S); + bool visitCXXForRangeStmt(const CXXForRangeStmt *S); + bool visitBreakStmt(const BreakStmt *S); + bool visitContinueStmt(const ContinueStmt *S); + bool visitSwitchStmt(const SwitchStmt *S); + bool visitCaseStmt(const CaseStmt *S); + bool visitDefaultStmt(const DefaultStmt *S); + bool visitAttributedStmt(const AttributedStmt *S); + bool visitCXXTryStmt(const CXXTryStmt *S); protected: + bool visitStmt(const Stmt *S); bool visitExpr(const Expr *E) override; bool visitDecl(const VarDecl *VD, bool ConstantContext) override; + bool visitFunc(const FunctionDecl *F) override; protected: /// Emits scope cleanup instructions. @@ -181,8 +220,8 @@ class ByteCodeExprGen : public ConstStmtVisitor, bool>, Record *getRecord(QualType Ty); Record *getRecord(const RecordDecl *RD); - // Returns a function for the given FunctionDecl. - // If the function does not exist yet, it is compiled. + /// Returns a function for the given FunctionDecl. + /// If the function does not exist yet, it is compiled. const Function *getFunction(const FunctionDecl *FD); std::optional classify(const Expr *E) const { @@ -220,9 +259,8 @@ class ByteCodeExprGen : public ConstStmtVisitor, bool>, /// Just pass evaluation on to \p E. This leaves all the parsing flags /// intact. bool delegate(const Expr *E); - /// Creates and initializes a variable from the given decl. - bool visitVarDecl(const VarDecl *VD); + VarCreationState visitVarDecl(const VarDecl *VD); /// Visit an APValue. bool visitAPValue(const APValue &Val, PrimType ValType, const Expr *E); bool visitAPValueInitializer(const APValue &Val, const Expr *E); @@ -293,6 +331,9 @@ class ByteCodeExprGen : public ConstStmtVisitor, bool>, friend class ArrayIndexScope; friend class SourceLocScope; friend struct InitLink; + friend class LoopScope; + friend class LabelScope; + friend class SwitchScope; /// Emits a zero initializer. bool visitZeroInitializer(PrimType T, QualType QT, const Expr *E); @@ -336,6 +377,7 @@ class ByteCodeExprGen : public ConstStmtVisitor, bool>, bool emitDestruction(const Descriptor *Desc); unsigned collectBaseOffset(const QualType BaseType, const QualType DerivedType); + bool emitLambdaStaticInvokerBody(const CXXMethodDecl *MD); protected: /// Variable to storage mapping. @@ -366,15 +408,28 @@ class ByteCodeExprGen : public ConstStmtVisitor, bool>, /// Flag indicating if we're initializing a global variable. bool GlobalDecl = false; + + /// Type of the expression returned by the function. + std::optional ReturnType; + + /// Switch case mapping. + CaseMap CaseLabels; + + /// Point to break to. + OptLabelTy BreakLabel; + /// Point to continue to. + OptLabelTy ContinueLabel; + /// Default case label. + OptLabelTy DefaultLabel; }; -extern template class ByteCodeExprGen; -extern template class ByteCodeExprGen; +extern template class Compiler; +extern template class Compiler; /// Scope chain managing the variable lifetimes. template class VariableScope { public: - VariableScope(ByteCodeExprGen *Ctx, const ValueDecl *VD) + VariableScope(Compiler *Ctx, const ValueDecl *VD) : Ctx(Ctx), Parent(Ctx->VarScope), ValDecl(VD) { Ctx->VarScope = this; } @@ -421,8 +476,8 @@ template class VariableScope { VariableScope *getParent() const { return Parent; } protected: - /// ByteCodeExprGen instance. - ByteCodeExprGen *Ctx; + /// Compiler instance. + Compiler *Ctx; /// Link to the parent scope. VariableScope *Parent; const ValueDecl *ValDecl = nullptr; @@ -431,8 +486,7 @@ template class VariableScope { /// Generic scope for local variables. template class LocalScope : public VariableScope { public: - LocalScope(ByteCodeExprGen *Ctx) - : VariableScope(Ctx, nullptr) {} + LocalScope(Compiler *Ctx) : VariableScope(Ctx, nullptr) {} /// Emit a Destroy op for this scope. ~LocalScope() override { @@ -526,8 +580,7 @@ template class DestructorScope final { /// variables are automatically emitted when the AutoScope is destroyed. template class AutoScope : public LocalScope { public: - AutoScope(ByteCodeExprGen *Ctx) - : LocalScope(Ctx), DS(*this) {} + AutoScope(Compiler *Ctx) : LocalScope(Ctx), DS(*this) {} private: DestructorScope DS; @@ -536,7 +589,7 @@ template class AutoScope : public LocalScope { /// Scope for storage declared in a compound statement. template class BlockScope final : public AutoScope { public: - BlockScope(ByteCodeExprGen *Ctx) : AutoScope(Ctx) {} + BlockScope(Compiler *Ctx) : AutoScope(Ctx) {} void addExtended(const Scope::Local &Local) override { // If we to this point, just add the variable as a normal local @@ -548,12 +601,12 @@ template class BlockScope final : public AutoScope { template class ExprScope final : public AutoScope { public: - ExprScope(ByteCodeExprGen *Ctx) : AutoScope(Ctx) {} + ExprScope(Compiler *Ctx) : AutoScope(Ctx) {} }; template class ArrayIndexScope final { public: - ArrayIndexScope(ByteCodeExprGen *Ctx, uint64_t Index) : Ctx(Ctx) { + ArrayIndexScope(Compiler *Ctx, uint64_t Index) : Ctx(Ctx) { OldArrayIndex = Ctx->ArrayIndex; Ctx->ArrayIndex = Index; } @@ -561,14 +614,13 @@ template class ArrayIndexScope final { ~ArrayIndexScope() { Ctx->ArrayIndex = OldArrayIndex; } private: - ByteCodeExprGen *Ctx; + Compiler *Ctx; std::optional OldArrayIndex; }; template class SourceLocScope final { public: - SourceLocScope(ByteCodeExprGen *Ctx, const Expr *DefaultExpr) - : Ctx(Ctx) { + SourceLocScope(Compiler *Ctx, const Expr *DefaultExpr) : Ctx(Ctx) { assert(DefaultExpr); // We only switch if the current SourceLocDefaultExpr is null. if (!Ctx->SourceLocDefaultExpr) { @@ -583,20 +635,20 @@ template class SourceLocScope final { } private: - ByteCodeExprGen *Ctx; + Compiler *Ctx; bool Enabled = false; }; template class InitLinkScope final { public: - InitLinkScope(ByteCodeExprGen *Ctx, InitLink &&Link) : Ctx(Ctx) { + InitLinkScope(Compiler *Ctx, InitLink &&Link) : Ctx(Ctx) { Ctx->InitStack.push_back(std::move(Link)); } ~InitLinkScope() { this->Ctx->InitStack.pop_back(); } private: - ByteCodeExprGen *Ctx; + Compiler *Ctx; }; } // namespace interp diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp index 98d1837204ebc4..913e8d514282ad 100644 --- a/clang/lib/AST/Interp/Context.cpp +++ b/clang/lib/AST/Interp/Context.cpp @@ -8,8 +8,7 @@ #include "Context.h" #include "ByteCodeEmitter.h" -#include "ByteCodeExprGen.h" -#include "ByteCodeStmtGen.h" +#include "Compiler.h" #include "EvalEmitter.h" #include "Interp.h" #include "InterpFrame.h" @@ -30,7 +29,7 @@ bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) { assert(Stk.empty()); Function *Func = P->getFunction(FD); if (!Func || !Func->hasBody()) - Func = ByteCodeStmtGen(*this, *P).compileFunc(FD); + Func = Compiler(*this, *P).compileFunc(FD); APValue DummyResult; if (!Run(Parent, Func, DummyResult)) @@ -40,8 +39,9 @@ bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) { } bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) { + ++EvalID; bool Recursing = !Stk.empty(); - ByteCodeExprGen C(*this, *P, Parent, Stk); + Compiler C(*this, *P, Parent, Stk); auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/E->isGLValue()); @@ -66,8 +66,9 @@ bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) { } bool Context::evaluate(State &Parent, const Expr *E, APValue &Result) { + ++EvalID; bool Recursing = !Stk.empty(); - ByteCodeExprGen C(*this, *P, Parent, Stk); + Compiler C(*this, *P, Parent, Stk); auto Res = C.interpretExpr(E); if (Res.isInvalid()) { @@ -91,8 +92,9 @@ bool Context::evaluate(State &Parent, const Expr *E, APValue &Result) { bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD, APValue &Result) { + ++EvalID; bool Recursing = !Stk.empty(); - ByteCodeExprGen C(*this, *P, Parent, Stk); + Compiler C(*this, *P, Parent, Stk); bool CheckGlobalInitialized = shouldBeGloballyIndexed(VD) && @@ -261,7 +263,7 @@ const Function *Context::getOrCreateFunction(const FunctionDecl *FD) { return Func; if (!Func || WasNotDefined) { - if (auto F = ByteCodeStmtGen(*this, *P).compileFunc(FD)) + if (auto F = Compiler(*this, *P).compileFunc(FD)) Func = F; } diff --git a/clang/lib/AST/Interp/Context.h b/clang/lib/AST/Interp/Context.h index c78dc9a2a471eb..b8ea4ad6b3b447 100644 --- a/clang/lib/AST/Interp/Context.h +++ b/clang/lib/AST/Interp/Context.h @@ -109,6 +109,8 @@ class Context final { const Record *getRecord(const RecordDecl *D) const; + unsigned getEvalID() const { return EvalID; } + private: /// Runs a function. bool Run(State &Parent, const Function *Func, APValue &Result); @@ -119,6 +121,8 @@ class Context final { InterpStack Stk; /// Constexpr program. std::unique_ptr P; + /// ID identifying an evaluation. + unsigned EvalID = 0; }; } // namespace interp diff --git a/clang/lib/AST/Interp/Descriptor.cpp b/clang/lib/AST/Interp/Descriptor.cpp index fcb778f7aeab0e..afafae088aca0c 100644 --- a/clang/lib/AST/Interp/Descriptor.cpp +++ b/clang/lib/AST/Interp/Descriptor.cpp @@ -64,7 +64,14 @@ static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D) { template static void moveArrayTy(Block *, const std::byte *Src, std::byte *Dst, const Descriptor *D) { - // FIXME: Need to copy the InitMap? + // FIXME: Get rid of the const_cast. + InitMapPtr &SrcIMP = + *reinterpret_cast(const_cast(Src)); + if (SrcIMP) { + // We only ever invoke the moveFunc when moving block contents to a + // DeadBlock. DeadBlocks don't need InitMaps, so we destroy them here. + SrcIMP = std::nullopt; + } Src += sizeof(InitMapPtr); Dst += sizeof(InitMapPtr); for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) { @@ -348,11 +355,11 @@ Descriptor::Descriptor(const DeclTy &D) } QualType Descriptor::getType() const { - if (auto *E = asExpr()) + if (const auto *E = asExpr()) return E->getType(); - if (auto *D = asValueDecl()) + if (const auto *D = asValueDecl()) return D->getType(); - if (auto *T = dyn_cast(asDecl())) + if (const auto *T = dyn_cast(asDecl())) return QualType(T->getTypeForDecl(), 0); llvm_unreachable("Invalid descriptor type"); } diff --git a/clang/lib/AST/Interp/Disasm.cpp b/clang/lib/AST/Interp/Disasm.cpp index 0ab84d159c58b7..d946a10c22dc3f 100644 --- a/clang/lib/AST/Interp/Disasm.cpp +++ b/clang/lib/AST/Interp/Disasm.cpp @@ -25,6 +25,7 @@ #include "Program.h" #include "clang/AST/ASTDumperUtils.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/ExprCXX.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Format.h" @@ -154,6 +155,32 @@ LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const { OS << (GP.isInitialized() ? "initialized " : "uninitialized "); } Desc->dump(OS); + + if (GP.isInitialized() && Desc->IsTemporary) { + if (const auto *MTE = + dyn_cast_if_present(Desc->asExpr()); + MTE && MTE->getLifetimeExtendedTemporaryDecl()) { + if (const APValue *V = + MTE->getLifetimeExtendedTemporaryDecl()->getValue()) { + OS << " (global temporary value: "; + { + ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_MAGENTA, true}); + std::string VStr; + llvm::raw_string_ostream SS(VStr); + V->dump(SS, Ctx.getASTContext()); + + for (unsigned I = 0; I != VStr.size(); ++I) { + if (VStr[I] == '\n') + VStr[I] = ' '; + } + VStr.pop_back(); // Remove the newline (or now space) at the end. + OS << VStr; + } + OS << ')'; + } + } + } + OS << "\n"; if (GP.isInitialized() && Desc->isPrimitive() && !Desc->isDummy()) { OS << " "; @@ -191,7 +218,7 @@ LLVM_DUMP_METHOD void Descriptor::dump(llvm::raw_ostream &OS) const { if (const auto *ND = dyn_cast_if_present(asDecl())) ND->printQualifiedName(OS); else if (asExpr()) - OS << "expr (TODO)"; + OS << "Expr " << (const void *)asExpr(); } // Print a few interesting bits about the descriptor. diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp index 77ff901634a462..d17151416b44bd 100644 --- a/clang/lib/AST/Interp/EvalEmitter.cpp +++ b/clang/lib/AST/Interp/EvalEmitter.cpp @@ -56,6 +56,7 @@ EvaluationResult EvalEmitter::interpretExpr(const Expr *E, EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD, bool CheckFullyInitialized) { this->CheckFullyInitialized = CheckFullyInitialized; + S.EvaluatingDecl = VD; if (const Expr *Init = VD->getAnyInitializer()) { QualType T = VD->getType(); @@ -69,6 +70,8 @@ EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD, if (!this->visitDecl(VD, S.inConstantContext()) && EvalResult.empty()) EvalResult.setInvalid(); + S.EvaluatingDecl = nullptr; + updateGlobalTemporaries(); return std::move(this->EvalResult); } @@ -81,7 +84,7 @@ EvalEmitter::LabelTy EvalEmitter::getLabel() { return NextLabel++; } Scope::Local EvalEmitter::createLocal(Descriptor *D) { // Allocate memory for a local. auto Memory = std::make_unique(sizeof(Block) + D->getAllocSize()); - auto *B = new (Memory.get()) Block(D, /*isStatic=*/false); + auto *B = new (Memory.get()) Block(Ctx.getEvalID(), D, /*isStatic=*/false); B->invokeCtor(); // Initialize local variable inline descriptor. @@ -148,6 +151,11 @@ template <> bool EvalEmitter::emitRet(const SourceInfo &Info) { // Implicitly convert lvalue to rvalue, if requested. if (ConvertResultToRValue) { + // Never allow reading from a non-const pointer, unless the memory + // has been created in this evaluation. + if (!Ptr.isConst() && Ptr.block()->getEvalID() != Ctx.getEvalID()) + return false; + if (std::optional V = Ptr.toRValue(Ctx)) { EvalResult.setValue(*V); } else { @@ -235,6 +243,28 @@ bool EvalEmitter::emitDestroy(uint32_t I, const SourceInfo &Info) { return true; } +/// Global temporaries (LifetimeExtendedTemporary) carry their value +/// around as an APValue, which codegen accesses. +/// We set their value once when creating them, but we don't update it +/// afterwards when code changes it later. +/// This is what we do here. +void EvalEmitter::updateGlobalTemporaries() { + for (const auto &[E, Temp] : S.SeenGlobalTemporaries) { + if (std::optional GlobalIndex = P.getGlobal(E)) { + const Pointer &Ptr = P.getPtrGlobal(*GlobalIndex); + APValue *Cached = Temp->getOrCreateValue(true); + + if (std::optional T = Ctx.classify(E->getType())) { + TYPE_SWITCH(*T, { *Cached = Ptr.deref().toAPValue(); }); + } else { + if (std::optional APV = Ptr.toRValue(Ctx)) + *Cached = *APV; + } + } + } + S.SeenGlobalTemporaries.clear(); +} + //===----------------------------------------------------------------------===// // Opcode evaluators //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/Interp/EvalEmitter.h b/clang/lib/AST/Interp/EvalEmitter.h index 68accbc5214c27..d1e125cae95944 100644 --- a/clang/lib/AST/Interp/EvalEmitter.h +++ b/clang/lib/AST/Interp/EvalEmitter.h @@ -56,6 +56,7 @@ class EvalEmitter : public SourceMapper { /// Methods implemented by the compiler. virtual bool visitExpr(const Expr *E) = 0; virtual bool visitDecl(const VarDecl *VD, bool ConstantContext) = 0; + virtual bool visitFunc(const FunctionDecl *F) = 0; /// Emits jumps. bool jumpTrue(const LabelTy &Label); @@ -63,6 +64,10 @@ class EvalEmitter : public SourceMapper { bool jump(const LabelTy &Label); bool fallthrough(const LabelTy &Label); + /// Since expressions can only jump forward, predicated execution is + /// used to deal with if-else statements. + bool isActive() const { return CurrentLabel == ActiveLabel; } + /// Callback for registering a local. Local createLocal(Descriptor *D); @@ -104,6 +109,8 @@ class EvalEmitter : public SourceMapper { return reinterpret_cast(It->second.get()); } + void updateGlobalTemporaries(); + // The emitter always tracks the current instruction and sets OpPC to a token // value which is mapped to the location of the opcode being evaluated. CodePtr OpPC; @@ -117,10 +124,6 @@ class EvalEmitter : public SourceMapper { /// Active block which should be executed. LabelTy ActiveLabel = 0; - /// Since expressions can only jump forward, predicated execution is - /// used to deal with if-else statements. - bool isActive() const { return CurrentLabel == ActiveLabel; } - protected: #define GET_EVAL_PROTO #include "Opcodes.inc" diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 49015b1dd63d33..0411fcad88ad0a 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -322,7 +322,7 @@ bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { }; if (const auto *D = Desc->asVarDecl(); - D && D->hasGlobalStorage() && !IsConstType(D)) { + D && D->hasGlobalStorage() && D != S.EvaluatingDecl && !IsConstType(D)) { diagnoseNonConstVariable(S, OpPC, D); return S.inConstantContext(); } @@ -341,7 +341,9 @@ bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, if (!Ptr.isZero()) return true; const SourceInfo &Loc = S.Current->getSource(OpPC); - S.FFDiag(Loc, diag::note_constexpr_null_subobject) << CSK; + S.FFDiag(Loc, diag::note_constexpr_null_subobject) + << CSK << S.Current->getRange(OpPC); + return false; } @@ -350,7 +352,8 @@ bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, if (!Ptr.isOnePastEnd()) return true; const SourceInfo &Loc = S.Current->getSource(OpPC); - S.FFDiag(Loc, diag::note_constexpr_access_past_end) << AK; + S.FFDiag(Loc, diag::note_constexpr_access_past_end) + << AK << S.Current->getRange(OpPC); return false; } @@ -359,7 +362,8 @@ bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, if (!Ptr.isElementPastEnd()) return true; const SourceInfo &Loc = S.Current->getSource(OpPC); - S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) << CSK; + S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) + << CSK << S.Current->getRange(OpPC); return false; } @@ -369,7 +373,8 @@ bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, return true; const SourceInfo &Loc = S.Current->getSource(OpPC); - S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) << CSK; + S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) + << CSK << S.Current->getRange(OpPC); return false; } @@ -395,7 +400,7 @@ bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { assert(Ptr.isLive() && "Pointer is not live"); - if (!Ptr.isConst()) + if (!Ptr.isConst() || Ptr.isMutable()) return true; // The This pointer is writable in constructors and destructors, @@ -417,9 +422,14 @@ bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { assert(Ptr.isLive() && "Pointer is not live"); - if (!Ptr.isMutable()) { + if (!Ptr.isMutable()) + return true; + + // In C++14 onwards, it is permitted to read a mutable member whose + // lifetime began within the evaluation. + if (S.getLangOpts().CPlusPlus14 && + Ptr.block()->getEvalID() == S.Ctx.getEvalID()) return true; - } const SourceInfo &Loc = S.Current->getSource(OpPC); const FieldDecl *Field = Ptr.getField(); @@ -471,23 +481,24 @@ bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { return false; } -bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { - if (!CheckLive(S, OpPC, Ptr, AK_Read)) +bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, + AccessKinds AK) { + if (!CheckLive(S, OpPC, Ptr, AK)) return false; if (!CheckConstant(S, OpPC, Ptr)) return false; - if (!CheckDummy(S, OpPC, Ptr, AK_Read)) + if (!CheckDummy(S, OpPC, Ptr, AK)) return false; if (!CheckExtern(S, OpPC, Ptr)) return false; - if (!CheckRange(S, OpPC, Ptr, AK_Read)) + if (!CheckRange(S, OpPC, Ptr, AK)) return false; - if (!CheckActive(S, OpPC, Ptr, AK_Read)) + if (!CheckActive(S, OpPC, Ptr, AK)) return false; - if (!CheckInitialized(S, OpPC, Ptr, AK_Read)) + if (!CheckInitialized(S, OpPC, Ptr, AK)) return false; - if (!CheckTemporary(S, OpPC, Ptr, AK_Read)) + if (!CheckTemporary(S, OpPC, Ptr, AK)) return false; if (!CheckMutable(S, OpPC, Ptr)) return false; diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 916d268aa4f095..866593b9af094a 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -92,7 +92,8 @@ bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc); bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr); /// Checks if a value can be loaded from a block. -bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr); +bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, + AccessKinds AK = AK_Read); bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK); @@ -724,9 +725,7 @@ bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { template ::T> bool Inc(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.pop(); - if (!CheckDummy(S, OpPC, Ptr, AK_Increment)) - return false; - if (!CheckInitialized(S, OpPC, Ptr, AK_Increment)) + if (!CheckLoad(S, OpPC, Ptr, AK_Increment)) return false; return IncDecHelper(S, OpPC, Ptr); @@ -738,9 +737,7 @@ bool Inc(InterpState &S, CodePtr OpPC) { template ::T> bool IncPop(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.pop(); - if (!CheckDummy(S, OpPC, Ptr, AK_Increment)) - return false; - if (!CheckInitialized(S, OpPC, Ptr, AK_Increment)) + if (!CheckLoad(S, OpPC, Ptr, AK_Increment)) return false; return IncDecHelper(S, OpPC, Ptr); @@ -753,9 +750,7 @@ bool IncPop(InterpState &S, CodePtr OpPC) { template ::T> bool Dec(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.pop(); - if (!CheckDummy(S, OpPC, Ptr, AK_Decrement)) - return false; - if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement)) + if (!CheckLoad(S, OpPC, Ptr, AK_Decrement)) return false; return IncDecHelper(S, OpPC, Ptr); @@ -767,9 +762,7 @@ bool Dec(InterpState &S, CodePtr OpPC) { template ::T> bool DecPop(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.pop(); - if (!CheckDummy(S, OpPC, Ptr, AK_Decrement)) - return false; - if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement)) + if (!CheckLoad(S, OpPC, Ptr, AK_Decrement)) return false; return IncDecHelper(S, OpPC, Ptr); @@ -797,9 +790,7 @@ bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr, inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { const Pointer &Ptr = S.Stk.pop(); - if (Ptr.isDummy()) - return false; - if (!CheckInitialized(S, OpPC, Ptr, AK_Increment)) + if (!CheckLoad(S, OpPC, Ptr, AK_Increment)) return false; return IncDecFloatHelper(S, OpPC, Ptr, RM); @@ -807,9 +798,7 @@ inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { inline bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { const Pointer &Ptr = S.Stk.pop(); - if (Ptr.isDummy()) - return false; - if (!CheckInitialized(S, OpPC, Ptr, AK_Increment)) + if (!CheckLoad(S, OpPC, Ptr, AK_Increment)) return false; return IncDecFloatHelper(S, OpPC, Ptr, RM); @@ -817,11 +806,7 @@ inline bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { inline bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { const Pointer &Ptr = S.Stk.pop(); - - if (Ptr.isDummy()) - return false; - - if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement)) + if (!CheckLoad(S, OpPC, Ptr, AK_Decrement)) return false; return IncDecFloatHelper(S, OpPC, Ptr, RM); @@ -829,10 +814,7 @@ inline bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { inline bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { const Pointer &Ptr = S.Stk.pop(); - - if (Ptr.isDummy()) - return false; - if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement)) + if (!CheckLoad(S, OpPC, Ptr, AK_Decrement)) return false; return IncDecFloatHelper(S, OpPC, Ptr, RM); @@ -1255,7 +1237,10 @@ bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { /// Same as GetGlobal, but without the checks. template ::T> bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) { - auto *B = S.P.getGlobal(I); + const Pointer &Ptr = S.P.getPtrGlobal(I); + if (!Ptr.isInitialized()) + return false; + const Block *B = S.P.getGlobal(I); S.Stk.push(B->deref()); return true; } @@ -1280,16 +1265,20 @@ bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { template ::T> bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I, const LifetimeExtendedTemporaryDecl *Temp) { - assert(Temp); + const Pointer &Ptr = S.P.getGlobal(I); + const T Value = S.Stk.peek(); APValue APV = Value.toAPValue(); APValue *Cached = Temp->getOrCreateValue(true); *Cached = APV; - const Pointer &P = S.P.getGlobal(I); - P.deref() = S.Stk.pop(); - P.initialize(); + assert(Ptr.getDeclDesc()->asExpr()); + + S.SeenGlobalTemporaries.push_back( + std::make_pair(Ptr.getDeclDesc()->asExpr(), Temp)); + Ptr.deref() = S.Stk.pop(); + Ptr.initialize(); return true; } @@ -1302,6 +1291,9 @@ inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC, const Pointer &P = S.Stk.peek(); APValue *Cached = Temp->getOrCreateValue(true); + S.SeenGlobalTemporaries.push_back( + std::make_pair(P.getDeclDesc()->asExpr(), Temp)); + if (std::optional APV = P.toRValue(S.getCtx())) { *Cached = *APV; return true; diff --git a/clang/lib/AST/Interp/InterpBlock.cpp b/clang/lib/AST/Interp/InterpBlock.cpp index 9b33d1b778fb2c..c34ea7634b4a90 100644 --- a/clang/lib/AST/Interp/InterpBlock.cpp +++ b/clang/lib/AST/Interp/InterpBlock.cpp @@ -92,7 +92,8 @@ bool Block::hasPointer(const Pointer *P) const { #endif DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk) - : Root(Root), B(Blk->Desc, Blk->IsStatic, Blk->IsExtern, /*isDead=*/true) { + : Root(Root), + B(~0u, Blk->Desc, Blk->IsStatic, Blk->IsExtern, /*isDead=*/true) { // Add the block to the chain of dead blocks. if (Root) Root->Prev = this; diff --git a/clang/lib/AST/Interp/InterpBlock.h b/clang/lib/AST/Interp/InterpBlock.h index 2bb195648a9a91..1f25de35896303 100644 --- a/clang/lib/AST/Interp/InterpBlock.h +++ b/clang/lib/AST/Interp/InterpBlock.h @@ -49,17 +49,19 @@ enum PrimType : unsigned; class Block final { public: /// Creates a new block. - Block(const std::optional &DeclID, const Descriptor *Desc, - bool IsStatic = false, bool IsExtern = false) - : DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern), Desc(Desc) { - assert(Desc); - } - - Block(const Descriptor *Desc, bool IsStatic = false, bool IsExtern = false) - : DeclID((unsigned)-1), IsStatic(IsStatic), IsExtern(IsExtern), + Block(unsigned EvalID, const std::optional &DeclID, + const Descriptor *Desc, bool IsStatic = false, bool IsExtern = false) + : EvalID(EvalID), DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern), Desc(Desc) { - assert(Desc); - } + assert(Desc); + } + + Block(unsigned EvalID, const Descriptor *Desc, bool IsStatic = false, + bool IsExtern = false) + : EvalID(EvalID), DeclID((unsigned)-1), IsStatic(IsStatic), + IsExtern(IsExtern), Desc(Desc) { + assert(Desc); + } /// Returns the block's descriptor. const Descriptor *getDescriptor() const { return Desc; } @@ -75,7 +77,11 @@ class Block final { unsigned getSize() const { return Desc->getAllocSize(); } /// Returns the declaration ID. std::optional getDeclID() const { return DeclID; } + /// Returns whether the data of this block has been initialized via + /// invoking the Ctor func. bool isInitialized() const { return IsInitialized; } + /// The Evaluation ID this block was created in. + unsigned getEvalID() const { return EvalID; } /// Returns a pointer to the stored data. /// You are allowed to read Desc->getSize() bytes from this address. @@ -130,8 +136,10 @@ class Block final { friend class DeadBlock; friend class InterpState; - Block(const Descriptor *Desc, bool IsExtern, bool IsStatic, bool IsDead) - : IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true), Desc(Desc) { + Block(unsigned EvalID, const Descriptor *Desc, bool IsExtern, bool IsStatic, + bool IsDead) + : EvalID(EvalID), IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true), + Desc(Desc) { assert(Desc); } @@ -146,6 +154,7 @@ class Block final { bool hasPointer(const Pointer *P) const; #endif + const unsigned EvalID = ~0u; /// Start of the chain of pointers. Pointer *Pointers = nullptr; /// Unique identifier of the declaration. diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp index af8841c8b4ef8a..98928b3c22d7c6 100644 --- a/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -13,6 +13,7 @@ #include "clang/AST/RecordLayout.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/Support/SipHash.h" namespace clang { namespace interp { @@ -608,8 +609,8 @@ static bool interp__builtin_addressof(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *Func, const CallExpr *Call) { - PrimType PtrT = - S.getContext().classify(Call->getArg(0)->getType()).value_or(PT_Ptr); + assert(Call->getArg(0)->isLValue()); + PrimType PtrT = S.getContext().classify(Call->getArg(0)).value_or(PT_Ptr); if (PtrT == PT_FnPtr) { const FunctionPointer &Arg = S.Stk.peek(); @@ -1100,6 +1101,18 @@ static bool interp__builtin_os_log_format_buffer_size(InterpState &S, return true; } +static bool interp__builtin_ptrauth_string_discriminator( + InterpState &S, CodePtr OpPC, const InterpFrame *Frame, + const Function *Func, const CallExpr *Call) { + const auto &Ptr = S.Stk.peek(); + assert(Ptr.getFieldDesc()->isPrimitiveArray()); + + StringRef R(&Ptr.deref(), Ptr.getFieldDesc()->getNumElems() - 1); + uint64_t Result = getPointerAuthStableSipHash(R); + pushInteger(S, Result, Call->getType()); + return true; +} + bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *Call) { const InterpFrame *Frame = S.Current; @@ -1424,6 +1437,11 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, return false; break; + case Builtin::BI__builtin_ptrauth_string_discriminator: + if (!interp__builtin_ptrauth_string_discriminator(S, OpPC, Frame, F, Call)) + return false; + break; + default: S.FFDiag(S.Current->getLocation(OpPC), diag::note_invalid_subexpr_in_const_expr) diff --git a/clang/lib/AST/Interp/InterpFrame.cpp b/clang/lib/AST/Interp/InterpFrame.cpp index 54ccf9034c7a7d..b33f74dfe99f1c 100644 --- a/clang/lib/AST/Interp/InterpFrame.cpp +++ b/clang/lib/AST/Interp/InterpFrame.cpp @@ -37,7 +37,8 @@ InterpFrame::InterpFrame(InterpState &S, const Function *Func, Locals = std::make_unique(FrameSize); for (auto &Scope : Func->scopes()) { for (auto &Local : Scope.locals()) { - Block *B = new (localBlock(Local.Offset)) Block(Local.Desc); + Block *B = + new (localBlock(Local.Offset)) Block(S.Ctx.getEvalID(), Local.Desc); B->invokeCtor(); new (localInlineDesc(Local.Offset)) InlineDescriptor(Local.Desc); } @@ -220,7 +221,7 @@ Pointer InterpFrame::getParamPointer(unsigned Off) { const auto &Desc = Func->getParamDescriptor(Off); size_t BlockSize = sizeof(Block) + Desc.second->getAllocSize(); auto Memory = std::make_unique(BlockSize); - auto *B = new (Memory.get()) Block(Desc.second); + auto *B = new (Memory.get()) Block(S.Ctx.getEvalID(), Desc.second); // Copy the initial value. TYPE_SWITCH(Desc.first, new (B->data()) T(stackRef(Off))); diff --git a/clang/lib/AST/Interp/InterpState.h b/clang/lib/AST/Interp/InterpState.h index 0938a723a76d09..138e1d7ac95d5d 100644 --- a/clang/lib/AST/Interp/InterpState.h +++ b/clang/lib/AST/Interp/InterpState.h @@ -121,6 +121,12 @@ class InterpState final : public State, public SourceMapper { InterpFrame *Current = nullptr; /// Source location of the evaluating expression SourceLocation EvalLocation; + /// Declaration we're initializing/evaluting, if any. + const VarDecl *EvaluatingDecl = nullptr; + + llvm::SmallVector< + std::pair> + SeenGlobalTemporaries; }; } // namespace interp diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp index d77cd8943c4966..4070d0c54225da 100644 --- a/clang/lib/AST/Interp/Pointer.cpp +++ b/clang/lib/AST/Interp/Pointer.cpp @@ -347,7 +347,7 @@ std::optional Pointer::toRValue(const Context &Ctx) const { Ty = AT->getValueType(); // Invalid pointers. - if (Ptr.isDummy() || !Ptr.isLive() || + if (Ptr.isDummy() || !Ptr.isLive() || !Ptr.isBlockPointer() || (!Ptr.isUnknownSizeArray() && Ptr.isOnePastEnd())) return false; diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h index 609367a462b006..5faec75cc3ec51 100644 --- a/clang/lib/AST/Interp/Pointer.h +++ b/clang/lib/AST/Interp/Pointer.h @@ -513,6 +513,8 @@ class Pointer { unsigned getByteOffset() const { if (isIntegralPointer()) return asIntPointer().Value + Offset; + if (isOnePastEnd()) + return PastEndMark; return Offset; } @@ -551,6 +553,9 @@ class Pointer { if (!asBlockPointer().Pointee) return false; + if (isUnknownSizeArray()) + return false; + return isElementPastEnd() || (getSize() == getOffset() && !isZeroSizeArray()); } diff --git a/clang/lib/AST/Interp/Program.cpp b/clang/lib/AST/Interp/Program.cpp index 7b1f719779e904..d3864d23925c0e 100644 --- a/clang/lib/AST/Interp/Program.cpp +++ b/clang/lib/AST/Interp/Program.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "Program.h" -#include "ByteCodeStmtGen.h" #include "Context.h" #include "Function.h" #include "Integral.h" @@ -64,7 +63,7 @@ unsigned Program::createGlobalString(const StringLiteral *S) { // The byte length does not include the null terminator. unsigned I = Globals.size(); unsigned Sz = Desc->getAllocSize(); - auto *G = new (Allocator, Sz) Global(Desc, /*isStatic=*/true, + auto *G = new (Allocator, Sz) Global(Ctx.getEvalID(), Desc, /*isStatic=*/true, /*isExtern=*/false); G->block()->invokeCtor(); @@ -127,6 +126,12 @@ std::optional Program::getGlobal(const ValueDecl *VD) { return std::nullopt; } +std::optional Program::getGlobal(const Expr *E) { + if (auto It = GlobalIndices.find(E); It != GlobalIndices.end()) + return It->second; + return std::nullopt; +} + std::optional Program::getOrCreateGlobal(const ValueDecl *VD, const Expr *Init) { if (auto Idx = getGlobal(VD)) @@ -165,7 +170,8 @@ std::optional Program::getOrCreateDummy(const ValueDecl *VD) { unsigned I = Globals.size(); auto *G = new (Allocator, Desc->getAllocSize()) - Global(getCurrentDecl(), Desc, /*IsStatic=*/true, /*IsExtern=*/false); + Global(Ctx.getEvalID(), getCurrentDecl(), Desc, /*IsStatic=*/true, + /*IsExtern=*/false); G->block()->invokeCtor(); Globals.push_back(G); @@ -196,7 +202,14 @@ std::optional Program::createGlobal(const ValueDecl *VD, } std::optional Program::createGlobal(const Expr *E) { - return createGlobal(E, E->getType(), /*isStatic=*/true, /*isExtern=*/false); + if (auto Idx = getGlobal(E)) + return Idx; + if (auto Idx = createGlobal(E, E->getType(), /*isStatic=*/true, + /*isExtern=*/false)) { + GlobalIndices[E] = *Idx; + return *Idx; + } + return std::nullopt; } std::optional Program::createGlobal(const DeclTy &D, QualType Ty, @@ -219,7 +232,7 @@ std::optional Program::createGlobal(const DeclTy &D, QualType Ty, unsigned I = Globals.size(); auto *G = new (Allocator, Desc->getAllocSize()) - Global(getCurrentDecl(), Desc, IsStatic, IsExtern); + Global(Ctx.getEvalID(), getCurrentDecl(), Desc, IsStatic, IsExtern); G->block()->invokeCtor(); // Initialize InlineDescriptor fields. diff --git a/clang/lib/AST/Interp/Program.h b/clang/lib/AST/Interp/Program.h index ec7c0744b8856a..1cabc5212180f2 100644 --- a/clang/lib/AST/Interp/Program.h +++ b/clang/lib/AST/Interp/Program.h @@ -77,6 +77,7 @@ class Program final { /// Finds a global's index. std::optional getGlobal(const ValueDecl *VD); + std::optional getGlobal(const Expr *E); /// Returns or creates a global an creates an index to it. std::optional getOrCreateGlobal(const ValueDecl *VD, diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 2cac03ba163f92..5444dcf027fe2f 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -99,11 +99,10 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext { } void mangleCXXName(GlobalDecl GD, raw_ostream &) override; - void mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk, + void mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk, bool, raw_ostream &) override; void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, - const ThisAdjustment &ThisAdjustment, - raw_ostream &) override; + const ThunkInfo &Thunk, bool, raw_ostream &) override; void mangleReferenceTemporary(const VarDecl *D, unsigned ManglingNumber, raw_ostream &) override; void mangleCXXVTable(const CXXRecordDecl *RD, raw_ostream &) override; @@ -468,6 +467,7 @@ class CXXNameMangler { void mangleNameOrStandardSubstitution(const NamedDecl *ND); void mangleLambdaSig(const CXXRecordDecl *Lambda); void mangleModuleNamePrefix(StringRef Name, bool IsPartition = false); + void mangleVendorQualifier(StringRef Name); private: @@ -559,7 +559,6 @@ class CXXNameMangler { StringRef Prefix = ""); void mangleOperatorName(DeclarationName Name, unsigned Arity); void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); - void mangleVendorQualifier(StringRef qualifier); void mangleQualifiers(Qualifiers Quals, const DependentAddressSpaceType *DAST = nullptr); void mangleRefQualifier(RefQualifierKind RefQualifier); @@ -7044,8 +7043,78 @@ void ItaniumMangleContextImpl::mangleCXXDtorComdat(const CXXDestructorDecl *D, Mangler.mangle(GlobalDecl(D, Dtor_Comdat)); } +/// Mangles the pointer authentication override attribute for classes +/// that have explicit overrides for the vtable authentication schema. +/// +/// The override is mangled as a parameterized vendor extension as follows +/// +/// ::= U "__vtptrauth" I +/// +/// +/// +/// E +/// +/// The extra discriminator encodes the explicit value derived from the +/// override schema, e.g. if the override has specified type based +/// discrimination the encoded value will be the discriminator derived from the +/// type name. +static void mangleOverrideDiscrimination(CXXNameMangler &Mangler, + ASTContext &Context, + const ThunkInfo &Thunk) { + auto &LangOpts = Context.getLangOpts(); + const CXXRecordDecl *ThisRD = Thunk.ThisType->getPointeeCXXRecordDecl(); + const CXXRecordDecl *PtrauthClassRD = + Context.baseForVTableAuthentication(ThisRD); + unsigned TypedDiscriminator = + Context.getPointerAuthVTablePointerDiscriminator(ThisRD); + Mangler.mangleVendorQualifier("__vtptrauth"); + auto &ManglerStream = Mangler.getStream(); + ManglerStream << "I"; + if (const auto *ExplicitAuth = + PtrauthClassRD->getAttr()) { + ManglerStream << "Lj" << ExplicitAuth->getKey(); + + if (ExplicitAuth->getAddressDiscrimination() == + VTablePointerAuthenticationAttr::DefaultAddressDiscrimination) + ManglerStream << "Lb" << LangOpts.PointerAuthVTPtrAddressDiscrimination; + else + ManglerStream << "Lb" + << (ExplicitAuth->getAddressDiscrimination() == + VTablePointerAuthenticationAttr::AddressDiscrimination); + + switch (ExplicitAuth->getExtraDiscrimination()) { + case VTablePointerAuthenticationAttr::DefaultExtraDiscrimination: { + if (LangOpts.PointerAuthVTPtrTypeDiscrimination) + ManglerStream << "Lj" << TypedDiscriminator; + else + ManglerStream << "Lj" << 0; + break; + } + case VTablePointerAuthenticationAttr::TypeDiscrimination: + ManglerStream << "Lj" << TypedDiscriminator; + break; + case VTablePointerAuthenticationAttr::CustomDiscrimination: + ManglerStream << "Lj" << ExplicitAuth->getCustomDiscriminationValue(); + break; + case VTablePointerAuthenticationAttr::NoExtraDiscrimination: + ManglerStream << "Lj" << 0; + break; + } + } else { + ManglerStream << "Lj" + << (unsigned)VTablePointerAuthenticationAttr::DefaultKey; + ManglerStream << "Lb" << LangOpts.PointerAuthVTPtrAddressDiscrimination; + if (LangOpts.PointerAuthVTPtrTypeDiscrimination) + ManglerStream << "Lj" << TypedDiscriminator; + else + ManglerStream << "Lj" << 0; + } + ManglerStream << "E"; +} + void ItaniumMangleContextImpl::mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk, + bool ElideOverrideInfo, raw_ostream &Out) { // ::= T // # base is the nominal target function of thunk @@ -7071,21 +7140,28 @@ void ItaniumMangleContextImpl::mangleThunk(const CXXMethodDecl *MD, Thunk.Return.Virtual.Itanium.VBaseOffsetOffset); Mangler.mangleFunctionEncoding(MD); + if (!ElideOverrideInfo) + mangleOverrideDiscrimination(Mangler, getASTContext(), Thunk); } -void ItaniumMangleContextImpl::mangleCXXDtorThunk( - const CXXDestructorDecl *DD, CXXDtorType Type, - const ThisAdjustment &ThisAdjustment, raw_ostream &Out) { +void ItaniumMangleContextImpl::mangleCXXDtorThunk(const CXXDestructorDecl *DD, + CXXDtorType Type, + const ThunkInfo &Thunk, + bool ElideOverrideInfo, + raw_ostream &Out) { // ::= T // # base is the nominal target function of thunk CXXNameMangler Mangler(*this, Out, DD, Type); Mangler.getStream() << "_ZT"; + auto &ThisAdjustment = Thunk.This; // Mangle the 'this' pointer adjustment. Mangler.mangleCallOffset(ThisAdjustment.NonVirtual, ThisAdjustment.Virtual.Itanium.VCallOffsetOffset); Mangler.mangleFunctionEncoding(GlobalDecl(DD, Type)); + if (!ElideOverrideInfo) + mangleOverrideDiscrimination(Mangler, getASTContext(), Thunk); } /// Returns the mangled name for a guard variable for the passed in VarDecl. diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp index 4fbf0e3b42dbc8..75f6e2161a6338 100644 --- a/clang/lib/AST/Mangle.cpp +++ b/clang/lib/AST/Mangle.cpp @@ -513,10 +513,20 @@ class ASTNameGenerator::Implementation { } } else if (const auto *MD = dyn_cast_or_null(ND)) { Manglings.emplace_back(getName(ND)); - if (MD->isVirtual()) - if (const auto *TIV = Ctx.getVTableContext()->getThunkInfo(MD)) - for (const auto &T : *TIV) - Manglings.emplace_back(getMangledThunk(MD, T)); + if (MD->isVirtual()) { + if (const auto *TIV = Ctx.getVTableContext()->getThunkInfo(MD)) { + for (const auto &T : *TIV) { + std::string ThunkName; + std::string ContextualizedName = + getMangledThunk(MD, T, /* ElideOverrideInfo */ false); + if (Ctx.useAbbreviatedThunkName(MD, ContextualizedName)) + ThunkName = getMangledThunk(MD, T, /* ElideOverrideInfo */ true); + else + ThunkName = ContextualizedName; + Manglings.emplace_back(ThunkName); + } + } + } } return Manglings; @@ -569,11 +579,12 @@ class ASTNameGenerator::Implementation { return BOS.str(); } - std::string getMangledThunk(const CXXMethodDecl *MD, const ThunkInfo &T) { + std::string getMangledThunk(const CXXMethodDecl *MD, const ThunkInfo &T, + bool ElideOverrideInfo) { std::string FrontendBuf; llvm::raw_string_ostream FOS(FrontendBuf); - MC->mangleThunk(MD, T, FOS); + MC->mangleThunk(MD, T, ElideOverrideInfo, FOS); std::string BackendBuf; llvm::raw_string_ostream BOS(BackendBuf); diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index 3923d34274703d..7f1e9ab02ec261 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -159,9 +159,9 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext { const MethodVFTableLocation &ML, raw_ostream &Out) override; void mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk, - raw_ostream &) override; + bool ElideOverrideInfo, raw_ostream &) override; void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, - const ThisAdjustment &ThisAdjustment, + const ThunkInfo &Thunk, bool ElideOverrideInfo, raw_ostream &) override; void mangleCXXVFTable(const CXXRecordDecl *Derived, ArrayRef BasePath, @@ -169,6 +169,8 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext { void mangleCXXVBTable(const CXXRecordDecl *Derived, ArrayRef BasePath, raw_ostream &Out) override; + + void mangleCXXVTable(const CXXRecordDecl *, raw_ostream &) override; void mangleCXXVirtualDisplacementMap(const CXXRecordDecl *SrcRD, const CXXRecordDecl *DstRD, raw_ostream &Out) override; @@ -447,8 +449,8 @@ class MicrosoftCXXNameMangler { void mangleDecayedArrayType(const ArrayType *T); void mangleArrayType(const ArrayType *T); void mangleFunctionClass(const FunctionDecl *FD); - void mangleCallingConvention(CallingConv CC); - void mangleCallingConvention(const FunctionType *T); + void mangleCallingConvention(CallingConv CC, SourceRange Range); + void mangleCallingConvention(const FunctionType *T, SourceRange Range); void mangleIntegerLiteral(const llvm::APSInt &Number, const NonTypeTemplateParmDecl *PD = nullptr, QualType TemplateArgType = QualType()); @@ -888,7 +890,8 @@ void MicrosoftCXXNameMangler::mangleVirtualMemPtrThunk( Out << "$B"; mangleNumber(OffsetInVFTable); Out << 'A'; - mangleCallingConvention(MD->getType()->castAs()); + mangleCallingConvention(MD->getType()->castAs(), + MD->getSourceRange()); } void MicrosoftCXXNameMangler::mangleName(GlobalDecl GD) { @@ -2768,7 +2771,7 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T, mangleQualifiers(Quals, /*IsMember=*/false); } - mangleCallingConvention(CC); + mangleCallingConvention(CC, Range); // ::= // ::= @ # structors (they have no declared return type) @@ -2949,7 +2952,8 @@ void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) { Out << 'Y'; } } -void MicrosoftCXXNameMangler::mangleCallingConvention(CallingConv CC) { +void MicrosoftCXXNameMangler::mangleCallingConvention(CallingConv CC, + SourceRange Range) { // ::= A # __cdecl // ::= B # __export __cdecl // ::= C # __pascal @@ -2962,7 +2966,10 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(CallingConv CC) { // ::= J # __export __fastcall // ::= Q # __vectorcall // ::= S # __attribute__((__swiftcall__)) // Clang-only - // ::= T # __attribute__((__swiftasynccall__)) + // ::= W # __attribute__((__swiftasynccall__)) + // ::= U # __attribute__((__preserve_most__)) + // ::= V # __attribute__((__preserve_none__)) // + // Clang-only // // Clang-only // ::= w # __regcall // ::= x # __regcall4 @@ -2974,28 +2981,55 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(CallingConv CC) { switch (CC) { default: - llvm_unreachable("Unsupported CC for mangling"); + break; case CC_Win64: case CC_X86_64SysV: - case CC_C: Out << 'A'; break; - case CC_X86Pascal: Out << 'C'; break; - case CC_X86ThisCall: Out << 'E'; break; - case CC_X86StdCall: Out << 'G'; break; - case CC_X86FastCall: Out << 'I'; break; - case CC_X86VectorCall: Out << 'Q'; break; - case CC_Swift: Out << 'S'; break; - case CC_SwiftAsync: Out << 'W'; break; - case CC_PreserveMost: Out << 'U'; break; + case CC_C: + Out << 'A'; + return; + case CC_X86Pascal: + Out << 'C'; + return; + case CC_X86ThisCall: + Out << 'E'; + return; + case CC_X86StdCall: + Out << 'G'; + return; + case CC_X86FastCall: + Out << 'I'; + return; + case CC_X86VectorCall: + Out << 'Q'; + return; + case CC_Swift: + Out << 'S'; + return; + case CC_SwiftAsync: + Out << 'W'; + return; + case CC_PreserveMost: + Out << 'U'; + return; + case CC_PreserveNone: + Out << 'V'; + return; case CC_X86RegCall: if (getASTContext().getLangOpts().RegCall4) Out << "x"; else Out << "w"; - break; + return; } + + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID( + DiagnosticsEngine::Error, "cannot mangle this calling convention yet"); + Diags.Report(Range.getBegin(), DiagID) << Range; } -void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) { - mangleCallingConvention(T->getCallConv()); +void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T, + SourceRange Range) { + mangleCallingConvention(T->getCallConv(), Range); } void MicrosoftCXXNameMangler::mangleThrowSpecification( @@ -3715,6 +3749,7 @@ void MicrosoftMangleContextImpl::mangleVirtualMemPtrThunk( void MicrosoftMangleContextImpl::mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk, + bool /*ElideOverrideInfo*/, raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); @@ -3736,9 +3771,11 @@ void MicrosoftMangleContextImpl::mangleThunk(const CXXMethodDecl *MD, DeclForFPT->getType()->castAs(), MD); } -void MicrosoftMangleContextImpl::mangleCXXDtorThunk( - const CXXDestructorDecl *DD, CXXDtorType Type, - const ThisAdjustment &Adjustment, raw_ostream &Out) { +void MicrosoftMangleContextImpl::mangleCXXDtorThunk(const CXXDestructorDecl *DD, + CXXDtorType Type, + const ThunkInfo &Thunk, + bool /*ElideOverrideInfo*/, + raw_ostream &Out) { // FIXME: Actually, the dtor thunk should be emitted for vector deleting // dtors rather than scalar deleting dtors. Just use the vector deleting dtor // mangling manually until we support both deleting dtor types. @@ -3747,6 +3784,7 @@ void MicrosoftMangleContextImpl::mangleCXXDtorThunk( MicrosoftCXXNameMangler Mangler(*this, MHO, DD, Type); Mangler.getStream() << "??_E"; Mangler.mangleName(DD->getParent()); + auto &Adjustment = Thunk.This; mangleThunkThisAdjustment(DD->getAccess(), Adjustment, Mangler, MHO); Mangler.mangleFunctionType(DD->getType()->castAs(), DD); } @@ -3771,6 +3809,12 @@ void MicrosoftMangleContextImpl::mangleCXXVFTable( Mangler.getStream() << '@'; } +void MicrosoftMangleContextImpl::mangleCXXVTable(const CXXRecordDecl *Derived, + raw_ostream &Out) { + // TODO: Determine appropriate mangling for MSABI + mangleCXXVFTable(Derived, {}, Out); +} + void MicrosoftMangleContextImpl::mangleCXXVBTable( const CXXRecordDecl *Derived, ArrayRef BasePath, raw_ostream &Out) { diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp index d8519b2071e6da..c8792941a6bb64 100644 --- a/clang/lib/AST/StmtOpenMP.cpp +++ b/clang/lib/AST/StmtOpenMP.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// // -// This file implements the subclesses of Stmt class declared in StmtOpenMP.h +// This file implements the subclasses of Stmt class declared in StmtOpenMP.h // //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 656b733a13b0e9..d8b885870de3ac 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -3711,6 +3711,34 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef params, auto &EllipsisLoc = *getTrailingObjects(); EllipsisLoc = epi.EllipsisLoc; } + + if (!epi.FunctionEffects.empty()) { + auto &ExtraBits = *getTrailingObjects(); + size_t EffectsCount = epi.FunctionEffects.size(); + ExtraBits.NumFunctionEffects = EffectsCount; + assert(ExtraBits.NumFunctionEffects == EffectsCount && + "effect bitfield overflow"); + + ArrayRef SrcFX = epi.FunctionEffects.effects(); + auto *DestFX = getTrailingObjects(); + std::uninitialized_copy(SrcFX.begin(), SrcFX.end(), DestFX); + + ArrayRef SrcConds = epi.FunctionEffects.conditions(); + if (!SrcConds.empty()) { + ExtraBits.EffectsHaveConditions = true; + auto *DestConds = getTrailingObjects(); + std::uninitialized_copy(SrcConds.begin(), SrcConds.end(), DestConds); + assert(std::any_of(SrcConds.begin(), SrcConds.end(), + [](const EffectConditionExpr &EC) { + if (const Expr *E = EC.getCondition()) + return E->isTypeDependent() || + E->isValueDependent(); + return false; + }) && + "expected a dependent expression among the conditions"); + addDependence(TypeDependence::DependentInstantiation); + } + } } bool FunctionProtoType::hasDependentExceptionSpec() const { @@ -3794,6 +3822,7 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, // Finally we have a trailing return type flag (bool) // combined with AArch64 SME Attributes, to save space: // int + // combined with any FunctionEffects // // There is no ambiguity between the consumed arguments and an empty EH // spec because of the leading 'bool' which unambiguously indicates @@ -3829,6 +3858,8 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, epi.ExtInfo.Profile(ID); ID.AddInteger((epi.AArch64SMEAttributes << 1) | epi.HasTrailingReturn); + + epi.FunctionEffects.Profile(ID); } void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, @@ -5093,3 +5124,257 @@ void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { Profile(ID, Context, getDeducedType(), getKeyword(), isDependentType(), getTypeConstraintConcept(), getTypeConstraintArguments()); } + +FunctionEffect::Kind FunctionEffect::oppositeKind() const { + switch (kind()) { + case Kind::NonBlocking: + return Kind::Blocking; + case Kind::Blocking: + return Kind::NonBlocking; + case Kind::NonAllocating: + return Kind::Allocating; + case Kind::Allocating: + return Kind::NonAllocating; + case Kind::None: + return Kind::None; + } + llvm_unreachable("unknown effect kind"); +} + +StringRef FunctionEffect::name() const { + switch (kind()) { + case Kind::NonBlocking: + return "nonblocking"; + case Kind::NonAllocating: + return "nonallocating"; + case Kind::Blocking: + return "blocking"; + case Kind::Allocating: + return "allocating"; + case Kind::None: + return "(none)"; + } + llvm_unreachable("unknown effect kind"); +} + +bool FunctionEffect::canInferOnFunction(const Decl &Callee) const { + switch (kind()) { + case Kind::NonAllocating: + case Kind::NonBlocking: { + FunctionEffectsRef CalleeFX; + if (auto *FD = Callee.getAsFunction()) + CalleeFX = FD->getFunctionEffects(); + else if (auto *BD = dyn_cast(&Callee)) + CalleeFX = BD->getFunctionEffects(); + else + return false; + for (const FunctionEffectWithCondition &CalleeEC : CalleeFX) { + // nonblocking/nonallocating cannot call allocating. + if (CalleeEC.Effect.kind() == Kind::Allocating) + return false; + // nonblocking cannot call blocking. + if (kind() == Kind::NonBlocking && + CalleeEC.Effect.kind() == Kind::Blocking) + return false; + } + return true; + } + + case Kind::Allocating: + case Kind::Blocking: + return false; + + case Kind::None: + assert(0 && "canInferOnFunction with None"); + break; + } + llvm_unreachable("unknown effect kind"); +} + +bool FunctionEffect::shouldDiagnoseFunctionCall( + bool Direct, ArrayRef CalleeFX) const { + switch (kind()) { + case Kind::NonAllocating: + case Kind::NonBlocking: { + const Kind CallerKind = kind(); + for (const auto &Effect : CalleeFX) { + const Kind EK = Effect.kind(); + // Does callee have same or stronger constraint? + if (EK == CallerKind || + (CallerKind == Kind::NonAllocating && EK == Kind::NonBlocking)) { + return false; // no diagnostic + } + } + return true; // warning + } + case Kind::Allocating: + case Kind::Blocking: + return false; + case Kind::None: + assert(0 && "shouldDiagnoseFunctionCall with None"); + break; + } + llvm_unreachable("unknown effect kind"); +} + +// ===== + +void FunctionEffectsRef::Profile(llvm::FoldingSetNodeID &ID) const { + bool HasConds = !Conditions.empty(); + + ID.AddInteger(size() | (HasConds << 31u)); + for (unsigned Idx = 0, Count = Effects.size(); Idx != Count; ++Idx) { + ID.AddInteger(Effects[Idx].toOpaqueInt32()); + if (HasConds) + ID.AddPointer(Conditions[Idx].getCondition()); + } +} + +bool FunctionEffectSet::insert(const FunctionEffectWithCondition &NewEC, + Conflicts &Errs) { + FunctionEffect::Kind NewOppositeKind = NewEC.Effect.oppositeKind(); + Expr *NewCondition = NewEC.Cond.getCondition(); + + // The index at which insertion will take place; default is at end + // but we might find an earlier insertion point. + unsigned InsertIdx = Effects.size(); + unsigned Idx = 0; + for (const FunctionEffectWithCondition &EC : *this) { + // Note about effects with conditions: They are considered distinct from + // those without conditions; they are potentially unique, redundant, or + // in conflict, but we can't tell which until the condition is evaluated. + if (EC.Cond.getCondition() == nullptr && NewCondition == nullptr) { + if (EC.Effect.kind() == NewEC.Effect.kind()) { + // There is no condition, and the effect kind is already present, + // so just fail to insert the new one (creating a duplicate), + // and return success. + return true; + } + + if (EC.Effect.kind() == NewOppositeKind) { + Errs.push_back({EC, NewEC}); + return false; + } + } + + if (NewEC.Effect.kind() < EC.Effect.kind() && InsertIdx > Idx) + InsertIdx = Idx; + + ++Idx; + } + + if (NewCondition || !Conditions.empty()) { + if (Conditions.empty() && !Effects.empty()) + Conditions.resize(Effects.size()); + Conditions.insert(Conditions.begin() + InsertIdx, + NewEC.Cond.getCondition()); + } + Effects.insert(Effects.begin() + InsertIdx, NewEC.Effect); + return true; +} + +bool FunctionEffectSet::insert(const FunctionEffectsRef &Set, Conflicts &Errs) { + for (const auto &Item : Set) + insert(Item, Errs); + return Errs.empty(); +} + +FunctionEffectSet FunctionEffectSet::getIntersection(FunctionEffectsRef LHS, + FunctionEffectsRef RHS) { + FunctionEffectSet Result; + FunctionEffectSet::Conflicts Errs; + + // We could use std::set_intersection but that would require expanding the + // container interface to include push_back, making it available to clients + // who might fail to maintain invariants. + auto IterA = LHS.begin(), EndA = LHS.end(); + auto IterB = RHS.begin(), EndB = RHS.end(); + + auto FEWCLess = [](const FunctionEffectWithCondition &LHS, + const FunctionEffectWithCondition &RHS) { + return std::tuple(LHS.Effect, uintptr_t(LHS.Cond.getCondition())) < + std::tuple(RHS.Effect, uintptr_t(RHS.Cond.getCondition())); + }; + + while (IterA != EndA && IterB != EndB) { + FunctionEffectWithCondition A = *IterA; + FunctionEffectWithCondition B = *IterB; + if (FEWCLess(A, B)) + ++IterA; + else if (FEWCLess(B, A)) + ++IterB; + else { + Result.insert(A, Errs); + ++IterA; + ++IterB; + } + } + + // Insertion shouldn't be able to fail; that would mean both input + // sets contained conflicts. + assert(Errs.empty() && "conflict shouldn't be possible in getIntersection"); + + return Result; +} + +FunctionEffectSet FunctionEffectSet::getUnion(FunctionEffectsRef LHS, + FunctionEffectsRef RHS, + Conflicts &Errs) { + // Optimize for either of the two sets being empty (very common). + if (LHS.empty()) + return FunctionEffectSet(RHS); + + FunctionEffectSet Combined(LHS); + Combined.insert(RHS, Errs); + return Combined; +} + +LLVM_DUMP_METHOD void FunctionEffectsRef::dump(llvm::raw_ostream &OS) const { + OS << "Effects{"; + bool First = true; + for (const auto &CFE : *this) { + if (!First) + OS << ", "; + else + First = false; + OS << CFE.Effect.name(); + if (Expr *E = CFE.Cond.getCondition()) { + OS << '('; + E->dump(); + OS << ')'; + } + } + OS << "}"; +} + +LLVM_DUMP_METHOD void FunctionEffectSet::dump(llvm::raw_ostream &OS) const { + FunctionEffectsRef(*this).dump(OS); +} + +FunctionEffectsRef FunctionEffectsRef::get(QualType QT) { + while (true) { + QualType Pointee = QT->getPointeeType(); + if (Pointee.isNull()) + break; + QT = Pointee; + } + if (const auto *FPT = QT->getAs()) + return FPT->getFunctionEffects(); + return {}; +} + +FunctionEffectsRef +FunctionEffectsRef::create(ArrayRef FX, + ArrayRef Conds) { + assert(std::is_sorted(FX.begin(), FX.end()) && "effects should be sorted"); + assert((Conds.empty() || Conds.size() == FX.size()) && + "effects size should match conditions size"); + return FunctionEffectsRef(FX, Conds); +} + +std::string FunctionEffectWithCondition::description() const { + std::string Result(Effect.name().str()); + if (Cond.getCondition() != nullptr) + Result += "(expr)"; + return Result; +} diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 4add4d3af69a30..7c87fd587880ed 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1016,6 +1016,17 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T, } T->printExceptionSpecification(OS, Policy); + const FunctionEffectsRef FX = T->getFunctionEffects(); + for (const auto &CFE : FX) { + OS << " __attribute__((" << CFE.Effect.name(); + if (const Expr *E = CFE.Cond.getCondition()) { + OS << '('; + E->printPretty(OS, nullptr, Policy); + OS << ')'; + } + OS << "))"; + } + if (T->hasTrailingReturn()) { OS << " -> "; print(T->getReturnType(), OS, StringRef()); @@ -1946,6 +1957,10 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, case attr::ArmOut: case attr::ArmInOut: case attr::ArmPreserves: + case attr::NonBlocking: + case attr::NonAllocating: + case attr::Blocking: + case attr::Allocating: llvm_unreachable("This attribute should have been handled already"); case attr::NSReturnsRetained: diff --git a/clang/lib/AST/VTableBuilder.cpp b/clang/lib/AST/VTableBuilder.cpp index a956ca5b37acfe..e941c3bedb0a7e 100644 --- a/clang/lib/AST/VTableBuilder.cpp +++ b/clang/lib/AST/VTableBuilder.cpp @@ -1147,11 +1147,41 @@ void ItaniumVTableBuilder::ComputeThisAdjustments() { continue; // Add it. - VTableThunks[VTableIndex].This = ThisAdjustment; + auto SetThisAdjustmentThunk = [&](uint64_t Idx) { + // If a this pointer adjustment is required, record the method that + // created the vtable entry. MD is not necessarily the method that + // created the entry since derived classes overwrite base class + // information in MethodInfoMap, hence findOriginalMethodInMap is called + // here. + // + // For example, in the following class hierarchy, if MD = D1::m and + // Overrider = D2:m, the original method that created the entry is B0:m, + // which is what findOriginalMethodInMap(MD) returns: + // + // struct B0 { int a; virtual void m(); }; + // struct D0 : B0 { int a; void m() override; }; + // struct D1 : B0 { int a; void m() override; }; + // struct D2 : D0, D1 { int a; void m() override; }; + // + // We need to record the method because we cannot + // call findOriginalMethod to find the method that created the entry if + // the method in the entry requires adjustment. + // + // Do not set ThunkInfo::Method if Idx is already in VTableThunks. This + // can happen when covariant return adjustment is required too. + if (!VTableThunks.count(Idx)) { + const CXXMethodDecl *Method = VTables.findOriginalMethodInMap(MD); + VTableThunks[Idx].Method = Method; + VTableThunks[Idx].ThisType = Method->getThisType().getTypePtr(); + } + VTableThunks[Idx].This = ThisAdjustment; + }; + + SetThisAdjustmentThunk(VTableIndex); if (isa(MD)) { // Add an adjustment for the deleting destructor as well. - VTableThunks[VTableIndex + 1].This = ThisAdjustment; + SetThisAdjustmentThunk(VTableIndex + 1); } } @@ -1509,6 +1539,8 @@ void ItaniumVTableBuilder::AddMethods( FindNearestOverriddenMethod(MD, PrimaryBases)) { if (ComputeReturnAdjustmentBaseOffset(Context, MD, OverriddenMD).isEmpty()) { + VTables.setOriginalMethod(MD, OverriddenMD); + // Replace the method info of the overridden method with our own // method. assert(MethodInfoMap.count(OverriddenMD) && @@ -1547,7 +1579,8 @@ void ItaniumVTableBuilder::AddMethods( // This is a virtual thunk for the most derived class, add it. AddThunk(Overrider.Method, - ThunkInfo(ThisAdjustment, ReturnAdjustment)); + ThunkInfo(ThisAdjustment, ReturnAdjustment, + OverriddenMD->getThisType().getTypePtr())); } } @@ -1615,6 +1648,15 @@ void ItaniumVTableBuilder::AddMethods( ReturnAdjustment ReturnAdjustment = ComputeReturnAdjustment(ReturnAdjustmentOffset); + // If a return adjustment is required, record the method that created the + // vtable entry. We need to record the method because we cannot call + // findOriginalMethod to find the method that created the entry if the + // method in the entry requires adjustment. + if (!ReturnAdjustment.isEmpty()) { + VTableThunks[Components.size()].Method = MD; + VTableThunks[Components.size()].ThisType = MD->getThisType().getTypePtr(); + } + AddMethod(Overrider.Method, ReturnAdjustment); } } @@ -1890,11 +1932,31 @@ void ItaniumVTableBuilder::LayoutVTablesForVirtualBases( } } +static void printThunkMethod(const ThunkInfo &Info, raw_ostream &Out) { + if (!Info.Method) + return; + std::string Str = PredefinedExpr::ComputeName( + PredefinedIdentKind::PrettyFunctionNoVirtual, Info.Method); + Out << " method: " << Str; +} + /// dumpLayout - Dump the vtable layout. void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) { // FIXME: write more tests that actually use the dumpLayout output to prevent // ItaniumVTableBuilder regressions. + Out << "Original map\n"; + + for (const auto &P : VTables.getOriginalMethodMap()) { + std::string Str0 = + PredefinedExpr::ComputeName(PredefinedIdentKind::PrettyFunctionNoVirtual, + P.first); + std::string Str1 = + PredefinedExpr::ComputeName(PredefinedIdentKind::PrettyFunctionNoVirtual, + P.second); + Out << " " << Str0 << " -> " << Str1 << "\n"; + } + if (isBuildingConstructorVTable()) { Out << "Construction vtable for ('"; MostDerivedClass->printQualifiedName(Out); @@ -1978,6 +2040,7 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) { } Out << ']'; + printThunkMethod(Thunk, Out); } // If this function pointer has a 'this' pointer adjustment, dump it. @@ -1991,6 +2054,7 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) { } Out << ']'; + printThunkMethod(Thunk, Out); } } @@ -2027,6 +2091,7 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) { Out << ']'; } + printThunkMethod(Thunk, Out); } break; @@ -2125,7 +2190,6 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) { ThunkInfoVectorTy ThunksVector = Thunks[MD]; llvm::sort(ThunksVector, [](const ThunkInfo &LHS, const ThunkInfo &RHS) { - assert(LHS.Method == nullptr && RHS.Method == nullptr); return std::tie(LHS.This, LHS.Return) < std::tie(RHS.This, RHS.Return); }); @@ -2314,6 +2378,35 @@ ItaniumVTableContext::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, return I->second; } +GlobalDecl ItaniumVTableContext::findOriginalMethod(GlobalDecl GD) { + const auto *MD = cast(GD.getDecl()); + computeVTableRelatedInformation(MD->getParent()); + const CXXMethodDecl *OriginalMD = findOriginalMethodInMap(MD); + + if (const auto *DD = dyn_cast(OriginalMD)) + return GlobalDecl(DD, GD.getDtorType()); + return OriginalMD; +} + +const CXXMethodDecl * +ItaniumVTableContext::findOriginalMethodInMap(const CXXMethodDecl *MD) const { + // Traverse the chain of virtual methods until we find the method that added + // the v-table slot. + while (true) { + auto I = OriginalMethodMap.find(MD); + + // MD doesn't exist in OriginalMethodMap, so it must be the method we are + // looking for. + if (I == OriginalMethodMap.end()) + break; + + // Set MD to the overridden method. + MD = I->second; + } + + return MD; +} + static std::unique_ptr CreateVTableLayout(const ItaniumVTableBuilder &Builder) { SmallVector @@ -3094,9 +3187,9 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, ReturnAdjustmentOffset.VirtualBase); } } - + auto ThisType = (OverriddenMD ? OverriddenMD : MD)->getThisType().getTypePtr(); AddMethod(FinalOverriderMD, - ThunkInfo(ThisAdjustmentOffset, ReturnAdjustment, + ThunkInfo(ThisAdjustmentOffset, ReturnAdjustment, ThisType, ForceReturnAdjustmentMangling ? MD : nullptr)); } } diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index 8109ac6a781e73..3c896d373a211d 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -391,17 +391,22 @@ class TransferVisitor : public ConstStmtVisitor { } case UO_PreInc: case UO_PreDec: - // Propagate the storage location, but don't create a new value; to - // avoid generating unnecessary values, we leave it to the specific - // analysis to do this if desired. + // Propagate the storage location and clear out any value associated with + // it (to represent the fact that the value has definitely changed). + // To avoid generating unnecessary values, we leave it to the specific + // analysis to create a new value if desired. propagateStorageLocation(*S->getSubExpr(), *S, Env); + if (StorageLocation *Loc = Env.getStorageLocation(*S->getSubExpr())) + Env.clearValue(*Loc); break; case UO_PostInc: case UO_PostDec: - // Propagate the old value, but don't create a new value; to avoid - // generating unnecessary values, we leave it to the specific analysis - // to do this if desired. + // Propagate the old value, then clear out any value associated with the + // storage location (to represent the fact that the value has definitely + // changed). See above for rationale. propagateValue(*S->getSubExpr(), *S, Env); + if (StorageLocation *Loc = Env.getStorageLocation(*S->getSubExpr())) + Env.clearValue(*Loc); break; default: break; diff --git a/clang/lib/Analysis/ThreadSafety.cpp b/clang/lib/Analysis/ThreadSafety.cpp index e25b843c9bf83e..550c2a3ffe522f 100644 --- a/clang/lib/Analysis/ThreadSafety.cpp +++ b/clang/lib/Analysis/ThreadSafety.cpp @@ -37,6 +37,7 @@ #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" +#include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/ImmutableMap.h" @@ -1034,9 +1035,10 @@ class ThreadSafetyAnalyzer { template void getMutexIDs(CapExprSet &Mtxs, AttrType *Attr, const Expr *Exp, - const NamedDecl *D, - const CFGBlock *PredBlock, const CFGBlock *CurrBlock, - Expr *BrE, bool Neg); + const NamedDecl *D, const CFGBlock *PredBlock, + const CFGBlock *CurrBlock, + const ASTContext &TrylockAttrContext, + Expr *TrylockAttrSuccessValue, bool Neg); const CallExpr* getTrylockCallExpr(const Stmt *Cond, LocalVarContext C, bool &Negate); @@ -1359,17 +1361,18 @@ void ThreadSafetyAnalyzer::getMutexIDs(CapExprSet &Mtxs, AttrType *Attr, const Expr *Exp, const NamedDecl *D, const CFGBlock *PredBlock, const CFGBlock *CurrBlock, - Expr *BrE, bool Neg) { - // Find out which branch has the lock - bool branch = false; - if (const auto *BLE = dyn_cast_or_null(BrE)) - branch = BLE->getValue(); - else if (const auto *ILE = dyn_cast_or_null(BrE)) - branch = ILE->getValue().getBoolValue(); - - int branchnum = branch ? 0 : 1; - if (Neg) - branchnum = !branchnum; + const ASTContext &TrylockAttrContext, + Expr *TrylockAttrSuccess, + bool Neg) { + // Evaluate the trylock's success value as a boolean. + bool trylockSuccessValue = false; + if (!TrylockAttrSuccess->EvaluateAsBooleanCondition( + trylockSuccessValue, TrylockAttrContext, + /*InConstantContext=*/true)) { + llvm_unreachable("Trylock success value could not be evaluated."); + } + + const int branchnum = Neg ? !!trylockSuccessValue : !trylockSuccessValue; // If we've taken the trylock branch, then add the lock int i = 0; @@ -1390,8 +1393,15 @@ static bool getStaticBooleanValue(Expr *E, bool &TCond) { } else if (const auto *ILE = dyn_cast(E)) { TCond = ILE->getValue().getBoolValue(); return true; - } else if (auto *CE = dyn_cast(E)) + } else if (auto *CE = dyn_cast(E)) { return getStaticBooleanValue(CE->getSubExpr(), TCond); + } else if (auto *DRE = dyn_cast(E)) { + if (auto *ECD = dyn_cast(DRE->getDecl())) { + llvm::APSInt IV = ECD->getInitVal(); + TCond = IV.getBoolValue(); + return true; + } + } return false; } @@ -1497,27 +1507,27 @@ void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result, // If the condition is a call to a Trylock function, then grab the attributes for (const auto *Attr : FunDecl->attrs()) { switch (Attr->getKind()) { - case attr::TryAcquireCapability: { - auto *A = cast(Attr); - getMutexIDs(A->isShared() ? SharedLocksToAdd : ExclusiveLocksToAdd, A, - Exp, FunDecl, PredBlock, CurrBlock, A->getSuccessValue(), - Negate); - break; - }; - case attr::ExclusiveTrylockFunction: { - const auto *A = cast(Attr); - getMutexIDs(ExclusiveLocksToAdd, A, Exp, FunDecl, PredBlock, CurrBlock, - A->getSuccessValue(), Negate); - break; - } - case attr::SharedTrylockFunction: { - const auto *A = cast(Attr); - getMutexIDs(SharedLocksToAdd, A, Exp, FunDecl, PredBlock, CurrBlock, - A->getSuccessValue(), Negate); - break; - } - default: - break; + case attr::TryAcquireCapability: { + auto *A = cast(Attr); + getMutexIDs(A->isShared() ? SharedLocksToAdd : ExclusiveLocksToAdd, A, + Exp, FunDecl, PredBlock, CurrBlock, FunDecl->getASTContext(), + A->getSuccessValue(), Negate); + break; + }; + case attr::ExclusiveTrylockFunction: { + const auto *A = cast(Attr); + getMutexIDs(ExclusiveLocksToAdd, A, Exp, FunDecl, PredBlock, CurrBlock, + FunDecl->getASTContext(), A->getSuccessValue(), Negate); + break; + } + case attr::SharedTrylockFunction: { + const auto *A = cast(Attr); + getMutexIDs(SharedLocksToAdd, A, Exp, FunDecl, PredBlock, CurrBlock, + FunDecl->getASTContext(), A->getSuccessValue(), Negate); + break; + } + default: + break; } } diff --git a/clang/lib/Basic/Cuda.cpp b/clang/lib/Basic/Cuda.cpp index 1d96a929f95d85..faf3878f064d20 100644 --- a/clang/lib/Basic/Cuda.cpp +++ b/clang/lib/Basic/Cuda.cpp @@ -72,23 +72,21 @@ CudaVersion ToCudaVersion(llvm::VersionTuple Version) { } namespace { -struct CudaArchToStringMap { - CudaArch arch; +struct OffloadArchToStringMap { + OffloadArch arch; const char *arch_name; const char *virtual_arch_name; }; } // namespace -#define SM2(sm, ca) \ - { CudaArch::SM_##sm, "sm_" #sm, ca } +#define SM2(sm, ca) {OffloadArch::SM_##sm, "sm_" #sm, ca} #define SM(sm) SM2(sm, "compute_" #sm) -#define GFX(gpu) \ - { CudaArch::GFX##gpu, "gfx" #gpu, "compute_amdgcn" } -static const CudaArchToStringMap arch_names[] = { +#define GFX(gpu) {OffloadArch::GFX##gpu, "gfx" #gpu, "compute_amdgcn"} +static const OffloadArchToStringMap arch_names[] = { // clang-format off - {CudaArch::UNUSED, "", ""}, + {OffloadArch::UNUSED, "", ""}, SM2(20, "compute_20"), SM2(21, "compute_20"), // Fermi - SM(30), {CudaArch::SM_32_, "sm_32", "compute_32"}, SM(35), SM(37), // Kepler + SM(30), {OffloadArch::SM_32_, "sm_32", "compute_32"}, SM(35), SM(37), // Kepler SM(50), SM(52), SM(53), // Maxwell SM(60), SM(61), SM(62), // Pascal SM(70), SM(72), // Volta @@ -112,7 +110,7 @@ static const CudaArchToStringMap arch_names[] = { GFX(803), // gfx803 GFX(805), // gfx805 GFX(810), // gfx810 - {CudaArch::GFX9_GENERIC, "gfx9-generic", "compute_amdgcn"}, + {OffloadArch::GFX9_GENERIC, "gfx9-generic", "compute_amdgcn"}, GFX(900), // gfx900 GFX(902), // gfx902 GFX(904), // gfx903 @@ -124,12 +122,12 @@ static const CudaArchToStringMap arch_names[] = { GFX(940), // gfx940 GFX(941), // gfx941 GFX(942), // gfx942 - {CudaArch::GFX10_1_GENERIC, "gfx10-1-generic", "compute_amdgcn"}, + {OffloadArch::GFX10_1_GENERIC, "gfx10-1-generic", "compute_amdgcn"}, GFX(1010), // gfx1010 GFX(1011), // gfx1011 GFX(1012), // gfx1012 GFX(1013), // gfx1013 - {CudaArch::GFX10_3_GENERIC, "gfx10-3-generic", "compute_amdgcn"}, + {OffloadArch::GFX10_3_GENERIC, "gfx10-3-generic", "compute_amdgcn"}, GFX(1030), // gfx1030 GFX(1031), // gfx1031 GFX(1032), // gfx1032 @@ -137,7 +135,7 @@ static const CudaArchToStringMap arch_names[] = { GFX(1034), // gfx1034 GFX(1035), // gfx1035 GFX(1036), // gfx1036 - {CudaArch::GFX11_GENERIC, "gfx11-generic", "compute_amdgcn"}, + {OffloadArch::GFX11_GENERIC, "gfx11-generic", "compute_amdgcn"}, GFX(1100), // gfx1100 GFX(1101), // gfx1101 GFX(1102), // gfx1102 @@ -145,104 +143,105 @@ static const CudaArchToStringMap arch_names[] = { GFX(1150), // gfx1150 GFX(1151), // gfx1151 GFX(1152), // gfx1152 - {CudaArch::GFX12_GENERIC, "gfx12-generic", "compute_amdgcn"}, + {OffloadArch::GFX12_GENERIC, "gfx12-generic", "compute_amdgcn"}, GFX(1200), // gfx1200 GFX(1201), // gfx1201 - {CudaArch::Generic, "generic", ""}, + {OffloadArch::AMDGCNSPIRV, "amdgcnspirv", "compute_amdgcn"}, + {OffloadArch::Generic, "generic", ""}, // clang-format on }; #undef SM #undef SM2 #undef GFX -const char *CudaArchToString(CudaArch A) { +const char *OffloadArchToString(OffloadArch A) { auto result = std::find_if( std::begin(arch_names), std::end(arch_names), - [A](const CudaArchToStringMap &map) { return A == map.arch; }); + [A](const OffloadArchToStringMap &map) { return A == map.arch; }); if (result == std::end(arch_names)) return "unknown"; return result->arch_name; } -const char *CudaArchToVirtualArchString(CudaArch A) { +const char *OffloadArchToVirtualArchString(OffloadArch A) { auto result = std::find_if( std::begin(arch_names), std::end(arch_names), - [A](const CudaArchToStringMap &map) { return A == map.arch; }); + [A](const OffloadArchToStringMap &map) { return A == map.arch; }); if (result == std::end(arch_names)) return "unknown"; return result->virtual_arch_name; } -CudaArch StringToCudaArch(llvm::StringRef S) { +OffloadArch StringToOffloadArch(llvm::StringRef S) { auto result = std::find_if( std::begin(arch_names), std::end(arch_names), - [S](const CudaArchToStringMap &map) { return S == map.arch_name; }); + [S](const OffloadArchToStringMap &map) { return S == map.arch_name; }); if (result == std::end(arch_names)) - return CudaArch::UNKNOWN; + return OffloadArch::UNKNOWN; return result->arch; } -CudaVersion MinVersionForCudaArch(CudaArch A) { - if (A == CudaArch::UNKNOWN) +CudaVersion MinVersionForOffloadArch(OffloadArch A) { + if (A == OffloadArch::UNKNOWN) return CudaVersion::UNKNOWN; // AMD GPUs do not depend on CUDA versions. - if (IsAMDGpuArch(A)) + if (IsAMDOffloadArch(A)) return CudaVersion::CUDA_70; switch (A) { - case CudaArch::SM_20: - case CudaArch::SM_21: - case CudaArch::SM_30: - case CudaArch::SM_32_: - case CudaArch::SM_35: - case CudaArch::SM_37: - case CudaArch::SM_50: - case CudaArch::SM_52: - case CudaArch::SM_53: + case OffloadArch::SM_20: + case OffloadArch::SM_21: + case OffloadArch::SM_30: + case OffloadArch::SM_32_: + case OffloadArch::SM_35: + case OffloadArch::SM_37: + case OffloadArch::SM_50: + case OffloadArch::SM_52: + case OffloadArch::SM_53: return CudaVersion::CUDA_70; - case CudaArch::SM_60: - case CudaArch::SM_61: - case CudaArch::SM_62: + case OffloadArch::SM_60: + case OffloadArch::SM_61: + case OffloadArch::SM_62: return CudaVersion::CUDA_80; - case CudaArch::SM_70: + case OffloadArch::SM_70: return CudaVersion::CUDA_90; - case CudaArch::SM_72: + case OffloadArch::SM_72: return CudaVersion::CUDA_91; - case CudaArch::SM_75: + case OffloadArch::SM_75: return CudaVersion::CUDA_100; - case CudaArch::SM_80: + case OffloadArch::SM_80: return CudaVersion::CUDA_110; - case CudaArch::SM_86: + case OffloadArch::SM_86: return CudaVersion::CUDA_111; - case CudaArch::SM_87: + case OffloadArch::SM_87: return CudaVersion::CUDA_114; - case CudaArch::SM_89: - case CudaArch::SM_90: + case OffloadArch::SM_89: + case OffloadArch::SM_90: return CudaVersion::CUDA_118; - case CudaArch::SM_90a: + case OffloadArch::SM_90a: return CudaVersion::CUDA_120; default: llvm_unreachable("invalid enum"); } } -CudaVersion MaxVersionForCudaArch(CudaArch A) { +CudaVersion MaxVersionForOffloadArch(OffloadArch A) { // AMD GPUs do not depend on CUDA versions. - if (IsAMDGpuArch(A)) + if (IsAMDOffloadArch(A)) return CudaVersion::NEW; switch (A) { - case CudaArch::UNKNOWN: + case OffloadArch::UNKNOWN: return CudaVersion::UNKNOWN; - case CudaArch::SM_20: - case CudaArch::SM_21: + case OffloadArch::SM_20: + case OffloadArch::SM_21: return CudaVersion::CUDA_80; - case CudaArch::SM_30: - case CudaArch::SM_32_: + case OffloadArch::SM_30: + case OffloadArch::SM_32_: return CudaVersion::CUDA_102; - case CudaArch::SM_35: - case CudaArch::SM_37: + case OffloadArch::SM_35: + case OffloadArch::SM_37: return CudaVersion::CUDA_118; default: return CudaVersion::NEW; diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index b3e9affbb3e58a..7c8990880fae3b 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -702,6 +702,13 @@ bool clang::needsTaskBasedThreadLimit(OpenMPDirectiveKind DKind) { DKind == OMPD_target_parallel_loop; } +bool clang::isOpenMPExecutableDirective(OpenMPDirectiveKind DKind) { + if (DKind == OMPD_error) + return true; + Category Cat = getDirectiveCategory(DKind); + return Cat == Category::Executable || Cat == Category::Subsidiary; +} + void clang::getOpenMPCaptureRegions( SmallVectorImpl &CaptureRegions, OpenMPDirectiveKind DKind) { diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp index f0af1a3e3a38b5..533a9fe88a2150 100644 --- a/clang/lib/Basic/SourceManager.cpp +++ b/clang/lib/Basic/SourceManager.cpp @@ -20,6 +20,7 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Allocator.h" @@ -46,6 +47,13 @@ using namespace clang; using namespace SrcMgr; using llvm::MemoryBuffer; +#define DEBUG_TYPE "source-manager" + +// Reaching a limit of 2^31 results in a hard error. This metric allows to track +// if particular invocation of the compiler is close to it. +STATISTIC(MaxUsedSLocBytes, "Maximum number of bytes used by source locations " + "(both loaded and local)."); + //===----------------------------------------------------------------------===// // SourceManager Helper Classes //===----------------------------------------------------------------------===// @@ -466,6 +474,7 @@ SourceManager::AllocateLoadedSLocEntries(unsigned NumSLocEntries, SLocEntryLoaded.resize(LoadedSLocEntryTable.size()); SLocEntryOffsetLoaded.resize(LoadedSLocEntryTable.size()); CurrentLoadedOffset -= TotalSize; + updateSlocUsageStats(); int BaseID = -int(LoadedSLocEntryTable.size()) - 1; LoadedSLocEntryAllocBegin.push_back(FileID::get(BaseID)); return std::make_pair(BaseID, CurrentLoadedOffset); @@ -619,6 +628,7 @@ FileID SourceManager::createFileIDImpl(ContentCache &File, StringRef Filename, // We do a +1 here because we want a SourceLocation that means "the end of the // file", e.g. for the "no newline at the end of the file" diagnostic. NextLocalOffset += FileSize + 1; + updateSlocUsageStats(); // Set LastFileIDLookup to the newly created file. The next getFileID call is // almost guaranteed to be from that file. @@ -679,6 +689,7 @@ SourceManager::createExpansionLocImpl(const ExpansionInfo &Info, } // See createFileID for that +1. NextLocalOffset += Length + 1; + updateSlocUsageStats(); return SourceLocation::getMacroLoc(NextLocalOffset - (Length + 1)); } @@ -1843,6 +1854,12 @@ void SourceManager::associateFileChunkWithMacroArgExp( MacroArgsCache[EndOffs] = EndOffsMappedLoc; } +void SourceManager::updateSlocUsageStats() const { + SourceLocation::UIntTy UsedBytes = + NextLocalOffset + (MaxLoadedOffset - CurrentLoadedOffset); + MaxUsedSLocBytes.updateMax(UsedBytes); +} + /// If \arg Loc points inside a function macro argument, the returned /// location will be the macro location in which the argument was expanded. /// If a macro argument is used multiple times, the expanded location will diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index 31d8121b91d107..2692ddec26ff46 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -1536,6 +1536,7 @@ WindowsARM64TargetInfo::checkCallingConvention(CallingConv CC) const { case CC_OpenCLKernel: case CC_PreserveMost: case CC_PreserveAll: + case CC_PreserveNone: case CC_Swift: case CC_SwiftAsync: case CC_Win64: diff --git a/clang/lib/Basic/Targets/NVPTX.cpp b/clang/lib/Basic/Targets/NVPTX.cpp index ff7d2f1f92aa41..43b653dc52ce0d 100644 --- a/clang/lib/Basic/Targets/NVPTX.cpp +++ b/clang/lib/Basic/Targets/NVPTX.cpp @@ -59,7 +59,7 @@ NVPTXTargetInfo::NVPTXTargetInfo(const llvm::Triple &Triple, // Define available target features // These must be defined in sorted order! NoAsmVariants = true; - GPU = CudaArch::UNUSED; + GPU = OffloadArch::UNUSED; // PTX supports f16 as a fundamental type. HasLegalHalfType = true; @@ -175,116 +175,117 @@ void NVPTXTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__NVPTX__"); // Skip setting architecture dependent macros if undefined. - if (GPU == CudaArch::UNUSED && !HostTarget) + if (GPU == OffloadArch::UNUSED && !HostTarget) return; if (Opts.CUDAIsDevice || Opts.OpenMPIsTargetDevice || !HostTarget) { // Set __CUDA_ARCH__ for the GPU specified. std::string CUDAArchCode = [this] { switch (GPU) { - case CudaArch::GFX600: - case CudaArch::GFX601: - case CudaArch::GFX602: - case CudaArch::GFX700: - case CudaArch::GFX701: - case CudaArch::GFX702: - case CudaArch::GFX703: - case CudaArch::GFX704: - case CudaArch::GFX705: - case CudaArch::GFX801: - case CudaArch::GFX802: - case CudaArch::GFX803: - case CudaArch::GFX805: - case CudaArch::GFX810: - case CudaArch::GFX9_GENERIC: - case CudaArch::GFX900: - case CudaArch::GFX902: - case CudaArch::GFX904: - case CudaArch::GFX906: - case CudaArch::GFX908: - case CudaArch::GFX909: - case CudaArch::GFX90a: - case CudaArch::GFX90c: - case CudaArch::GFX940: - case CudaArch::GFX941: - case CudaArch::GFX942: - case CudaArch::GFX10_1_GENERIC: - case CudaArch::GFX1010: - case CudaArch::GFX1011: - case CudaArch::GFX1012: - case CudaArch::GFX1013: - case CudaArch::GFX10_3_GENERIC: - case CudaArch::GFX1030: - case CudaArch::GFX1031: - case CudaArch::GFX1032: - case CudaArch::GFX1033: - case CudaArch::GFX1034: - case CudaArch::GFX1035: - case CudaArch::GFX1036: - case CudaArch::GFX11_GENERIC: - case CudaArch::GFX1100: - case CudaArch::GFX1101: - case CudaArch::GFX1102: - case CudaArch::GFX1103: - case CudaArch::GFX1150: - case CudaArch::GFX1151: - case CudaArch::GFX1152: - case CudaArch::GFX12_GENERIC: - case CudaArch::GFX1200: - case CudaArch::GFX1201: - case CudaArch::Generic: - case CudaArch::LAST: + case OffloadArch::GFX600: + case OffloadArch::GFX601: + case OffloadArch::GFX602: + case OffloadArch::GFX700: + case OffloadArch::GFX701: + case OffloadArch::GFX702: + case OffloadArch::GFX703: + case OffloadArch::GFX704: + case OffloadArch::GFX705: + case OffloadArch::GFX801: + case OffloadArch::GFX802: + case OffloadArch::GFX803: + case OffloadArch::GFX805: + case OffloadArch::GFX810: + case OffloadArch::GFX9_GENERIC: + case OffloadArch::GFX900: + case OffloadArch::GFX902: + case OffloadArch::GFX904: + case OffloadArch::GFX906: + case OffloadArch::GFX908: + case OffloadArch::GFX909: + case OffloadArch::GFX90a: + case OffloadArch::GFX90c: + case OffloadArch::GFX940: + case OffloadArch::GFX941: + case OffloadArch::GFX942: + case OffloadArch::GFX10_1_GENERIC: + case OffloadArch::GFX1010: + case OffloadArch::GFX1011: + case OffloadArch::GFX1012: + case OffloadArch::GFX1013: + case OffloadArch::GFX10_3_GENERIC: + case OffloadArch::GFX1030: + case OffloadArch::GFX1031: + case OffloadArch::GFX1032: + case OffloadArch::GFX1033: + case OffloadArch::GFX1034: + case OffloadArch::GFX1035: + case OffloadArch::GFX1036: + case OffloadArch::GFX11_GENERIC: + case OffloadArch::GFX1100: + case OffloadArch::GFX1101: + case OffloadArch::GFX1102: + case OffloadArch::GFX1103: + case OffloadArch::GFX1150: + case OffloadArch::GFX1151: + case OffloadArch::GFX1152: + case OffloadArch::GFX12_GENERIC: + case OffloadArch::GFX1200: + case OffloadArch::GFX1201: + case OffloadArch::AMDGCNSPIRV: + case OffloadArch::Generic: + case OffloadArch::LAST: break; - case CudaArch::UNKNOWN: + case OffloadArch::UNKNOWN: assert(false && "No GPU arch when compiling CUDA device code."); return ""; - case CudaArch::UNUSED: - case CudaArch::SM_20: + case OffloadArch::UNUSED: + case OffloadArch::SM_20: return "200"; - case CudaArch::SM_21: + case OffloadArch::SM_21: return "210"; - case CudaArch::SM_30: + case OffloadArch::SM_30: return "300"; - case CudaArch::SM_32_: + case OffloadArch::SM_32_: return "320"; - case CudaArch::SM_35: + case OffloadArch::SM_35: return "350"; - case CudaArch::SM_37: + case OffloadArch::SM_37: return "370"; - case CudaArch::SM_50: + case OffloadArch::SM_50: return "500"; - case CudaArch::SM_52: + case OffloadArch::SM_52: return "520"; - case CudaArch::SM_53: + case OffloadArch::SM_53: return "530"; - case CudaArch::SM_60: + case OffloadArch::SM_60: return "600"; - case CudaArch::SM_61: + case OffloadArch::SM_61: return "610"; - case CudaArch::SM_62: + case OffloadArch::SM_62: return "620"; - case CudaArch::SM_70: + case OffloadArch::SM_70: return "700"; - case CudaArch::SM_72: + case OffloadArch::SM_72: return "720"; - case CudaArch::SM_75: + case OffloadArch::SM_75: return "750"; - case CudaArch::SM_80: + case OffloadArch::SM_80: return "800"; - case CudaArch::SM_86: + case OffloadArch::SM_86: return "860"; - case CudaArch::SM_87: + case OffloadArch::SM_87: return "870"; - case CudaArch::SM_89: + case OffloadArch::SM_89: return "890"; - case CudaArch::SM_90: - case CudaArch::SM_90a: + case OffloadArch::SM_90: + case OffloadArch::SM_90a: return "900"; } - llvm_unreachable("unhandled CudaArch"); + llvm_unreachable("unhandled OffloadArch"); }(); Builder.defineMacro("__CUDA_ARCH__", CUDAArchCode); - if (GPU == CudaArch::SM_90a) + if (GPU == OffloadArch::SM_90a) Builder.defineMacro("__CUDA_ARCH_FEAT_SM90_ALL", "1"); } } diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h index f476d49047c013..a5daf36cfac720 100644 --- a/clang/lib/Basic/Targets/NVPTX.h +++ b/clang/lib/Basic/Targets/NVPTX.h @@ -62,7 +62,7 @@ static const int NVPTXDWARFAddrSpaceMap[] = { class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public TargetInfo { static const char *const GCCRegNames[]; - CudaArch GPU; + OffloadArch GPU; uint32_t PTXVersion; std::unique_ptr HostTarget; @@ -79,8 +79,8 @@ class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public TargetInfo { initFeatureMap(llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const override { - if (GPU != CudaArch::UNUSED) - Features[CudaArchToString(GPU)] = true; + if (GPU != OffloadArch::UNUSED) + Features[OffloadArchToString(GPU)] = true; Features["ptx" + std::to_string(PTXVersion)] = true; return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } @@ -121,18 +121,18 @@ class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public TargetInfo { } bool isValidCPUName(StringRef Name) const override { - return StringToCudaArch(Name) != CudaArch::UNKNOWN; + return StringToOffloadArch(Name) != OffloadArch::UNKNOWN; } void fillValidCPUList(SmallVectorImpl &Values) const override { - for (int i = static_cast(CudaArch::SM_20); - i < static_cast(CudaArch::Generic); ++i) - Values.emplace_back(CudaArchToString(static_cast(i))); + for (int i = static_cast(OffloadArch::SM_20); + i < static_cast(OffloadArch::Generic); ++i) + Values.emplace_back(OffloadArchToString(static_cast(i))); } bool setCPU(const std::string &Name) override { - GPU = StringToCudaArch(Name); - return GPU != CudaArch::UNKNOWN; + GPU = StringToOffloadArch(Name); + return GPU != OffloadArch::UNKNOWN; } void setSupportedOpenCLOpts() override { @@ -183,7 +183,7 @@ class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public TargetInfo { bool hasBitIntType() const override { return true; } bool hasBFloat16Type() const override { return true; } - CudaArch getGPU() const { return GPU; } + OffloadArch getGPU() const { return GPU; } }; } // namespace targets } // namespace clang diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h index fc23c30c68523a..e4d6a02386da58 100644 --- a/clang/lib/Basic/Targets/PPC.h +++ b/clang/lib/Basic/Targets/PPC.h @@ -305,9 +305,11 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo { // asm statements) Info.setAllowsMemory(); break; - case 'R': // AIX TOC entry case 'a': // Address operand that is an indexed or indirect from a // register (`p' is preferable for asm statements) + // TODO: Add full support for this constraint + return false; + case 'R': // AIX TOC entry case 'S': // Constant suitable as a 64-bit mask operand case 'T': // Constant suitable as a 32-bit mask operand case 'U': // System V Release 4 small data area reference diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp index 036a655a4d073f..276d492955207a 100644 --- a/clang/lib/Basic/Targets/X86.cpp +++ b/clang/lib/Basic/Targets/X86.cpp @@ -455,6 +455,8 @@ bool X86TargetInfo::handleTargetFeatures(std::vector &Features, HasNF = true; } else if (Feature == "+cf") { HasCF = true; + } else if (Feature == "+zu") { + HasZU = true; } X86SSEEnum Level = llvm::StringSwitch(Feature) @@ -962,8 +964,10 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__NF__"); if (HasCF) Builder.defineMacro("__CF__"); + if (HasZU) + Builder.defineMacro("__ZU__"); // Condition here is aligned with the feature set of mapxf in Options.td - if (HasEGPR && HasPush2Pop2 && HasPPX && HasNDD && HasCCMP && HasNF) + if (HasEGPR && HasPush2Pop2 && HasPPX && HasNDD && HasCCMP && HasNF && HasCF) Builder.defineMacro("__APX_F__"); if (HasEGPR && HasInlineAsmUseGPR32) Builder.defineMacro("__APX_INLINE_ASM_USE_GPR32__"); @@ -1166,6 +1170,7 @@ bool X86TargetInfo::isValidFeatureName(StringRef Name) const { .Case("ccmp", true) .Case("nf", true) .Case("cf", true) + .Case("zu", true) .Default(false); } @@ -1286,6 +1291,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const { .Case("ccmp", HasCCMP) .Case("nf", HasNF) .Case("cf", HasCF) + .Case("zu", HasZU) .Default(false); } diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h index 9b2ae87adb2e74..5ce4953251bc34 100644 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -172,6 +172,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo { bool HasCCMP = false; bool HasNF = false; bool HasCF = false; + bool HasZU = false; bool HasInlineAsmUseGPR32 = false; protected: diff --git a/clang/lib/CodeGen/BackendConsumer.h b/clang/lib/CodeGen/BackendConsumer.h index 0fe9929dca2b33..a648bd314e5012 100644 --- a/clang/lib/CodeGen/BackendConsumer.h +++ b/clang/lib/CodeGen/BackendConsumer.h @@ -112,7 +112,7 @@ class BackendConsumer : public ASTConsumer { void HandleVTable(CXXRecordDecl *RD) override; // Links each entry in LinkModules into our module. Returns true on error. - bool LinkInModules(llvm::Module *M, bool ShouldLinkFiles = true); + bool LinkInModules(llvm::Module *M); /// Get the best possible source location to represent a diagnostic that /// may have associated debug info. diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index b09680086248d0..22b593e8f2b7a2 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -1035,7 +1035,7 @@ void EmitAssemblyHelper::RunOptimizationPipeline( // Link against bitcodes supplied via the -mlink-builtin-bitcode option if (CodeGenOpts.LinkBitcodePostopt) - MPM.addPass(LinkInModulesPass(BC, false)); + MPM.addPass(LinkInModulesPass(BC)); // Add a verifier pass if requested. We don't have to do this if the action // requires code generation because there will already be a verifier pass in diff --git a/clang/lib/CodeGen/CGBuilder.h b/clang/lib/CodeGen/CGBuilder.h index ed07476f4047f6..0bc4fda62979cd 100644 --- a/clang/lib/CodeGen/CGBuilder.h +++ b/clang/lib/CodeGen/CGBuilder.h @@ -62,7 +62,7 @@ class CGBuilderTy : public CGBuilderBaseTy { template Address createConstGEP2_32(Address Addr, unsigned Idx0, unsigned Idx1, const llvm::Twine &Name) { - const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout(); + const llvm::DataLayout &DL = BB->getDataLayout(); llvm::GetElementPtrInst *GEP; if (IsInBounds) GEP = cast(CreateConstInBoundsGEP2_32( @@ -218,7 +218,7 @@ class CGBuilderTy : public CGBuilderBaseTy { Address CreateStructGEP(Address Addr, unsigned Index, const llvm::Twine &Name = "") { llvm::StructType *ElTy = cast(Addr.getElementType()); - const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout(); + const llvm::DataLayout &DL = BB->getDataLayout(); const llvm::StructLayout *Layout = DL.getStructLayout(ElTy); auto Offset = CharUnits::fromQuantity(Layout->getElementOffset(Index)); @@ -240,7 +240,7 @@ class CGBuilderTy : public CGBuilderBaseTy { Address CreateConstArrayGEP(Address Addr, uint64_t Index, const llvm::Twine &Name = "") { llvm::ArrayType *ElTy = cast(Addr.getElementType()); - const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout(); + const llvm::DataLayout &DL = BB->getDataLayout(); CharUnits EltSize = CharUnits::fromQuantity(DL.getTypeAllocSize(ElTy->getElementType())); @@ -260,7 +260,7 @@ class CGBuilderTy : public CGBuilderBaseTy { Address CreateConstInBoundsGEP(Address Addr, uint64_t Index, const llvm::Twine &Name = "") { llvm::Type *ElTy = Addr.getElementType(); - const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout(); + const llvm::DataLayout &DL = BB->getDataLayout(); CharUnits EltSize = CharUnits::fromQuantity(DL.getTypeAllocSize(ElTy)); return Address( @@ -277,7 +277,7 @@ class CGBuilderTy : public CGBuilderBaseTy { Address CreateConstGEP(Address Addr, uint64_t Index, const llvm::Twine &Name = "") { llvm::Type *ElTy = Addr.getElementType(); - const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout(); + const llvm::DataLayout &DL = BB->getDataLayout(); CharUnits EltSize = CharUnits::fromQuantity(DL.getTypeAllocSize(ElTy)); return Address(CreateGEP(ElTy, Addr.getBasePointer(), getSize(Index), Name), @@ -290,7 +290,7 @@ class CGBuilderTy : public CGBuilderBaseTy { using CGBuilderBaseTy::CreateGEP; Address CreateGEP(CodeGenFunction &CGF, Address Addr, llvm::Value *Index, const llvm::Twine &Name = "") { - const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout(); + const llvm::DataLayout &DL = BB->getDataLayout(); CharUnits EltSize = CharUnits::fromQuantity(DL.getTypeAllocSize(Addr.getElementType())); @@ -412,7 +412,7 @@ class CGBuilderTy : public CGBuilderBaseTy { unsigned FieldIndex, llvm::MDNode *DbgInfo) { llvm::StructType *ElTy = cast(Addr.getElementType()); - const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout(); + const llvm::DataLayout &DL = BB->getDataLayout(); const llvm::StructLayout *Layout = DL.getStructLayout(ElTy); auto Offset = CharUnits::fromQuantity(Layout->getElementOffset(Index)); diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 6316e2b062692d..98c2f70664ec7a 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -3505,6 +3505,18 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_trap: EmitTrapCall(Intrinsic::trap); return RValue::get(nullptr); + case Builtin::BI__builtin_verbose_trap: { + llvm::DILocation *TrapLocation = Builder.getCurrentDebugLocation(); + if (getDebugInfo()) { + TrapLocation = getDebugInfo()->CreateTrapFailureMessageFor( + TrapLocation, *E->getArg(0)->tryEvaluateString(getContext()), + *E->getArg(1)->tryEvaluateString(getContext())); + } + ApplyDebugLocation ApplyTrapDI(*this, TrapLocation); + // Currently no attempt is made to prevent traps from being merged. + EmitTrapCall(Intrinsic::trap); + return RValue::get(nullptr); + } case Builtin::BI__debugbreak: EmitTrapCall(Intrinsic::debugtrap); return RValue::get(nullptr); @@ -18467,6 +18479,22 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, CGM.getIntrinsic(Intrinsic::amdgcn_update_dpp, Args[0]->getType()); return Builder.CreateCall(F, Args); } + case AMDGPU::BI__builtin_amdgcn_permlane16: + case AMDGPU::BI__builtin_amdgcn_permlanex16: + return emitBuiltinWithOneOverloadedType<6>( + *this, E, + BuiltinID == AMDGPU::BI__builtin_amdgcn_permlane16 + ? Intrinsic::amdgcn_permlane16 + : Intrinsic::amdgcn_permlanex16); + case AMDGPU::BI__builtin_amdgcn_permlane64: + return emitBuiltinWithOneOverloadedType<1>(*this, E, + Intrinsic::amdgcn_permlane64); + case AMDGPU::BI__builtin_amdgcn_readlane: + return emitBuiltinWithOneOverloadedType<2>(*this, E, + Intrinsic::amdgcn_readlane); + case AMDGPU::BI__builtin_amdgcn_readfirstlane: + return emitBuiltinWithOneOverloadedType<1>(*this, E, + Intrinsic::amdgcn_readfirstlane); case AMDGPU::BI__builtin_amdgcn_div_fixup: case AMDGPU::BI__builtin_amdgcn_div_fixupf: case AMDGPU::BI__builtin_amdgcn_div_fixuph: @@ -18604,28 +18632,6 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, Function *F = CGM.getIntrinsic(Intrin, { Src0->getType() }); return Builder.CreateCall(F, { Src0, Builder.getFalse() }); } - case AMDGPU::BI__builtin_amdgcn_ds_fminf: - case AMDGPU::BI__builtin_amdgcn_ds_fmaxf: { - Intrinsic::ID Intrin; - switch (BuiltinID) { - case AMDGPU::BI__builtin_amdgcn_ds_fminf: - Intrin = Intrinsic::amdgcn_ds_fmin; - break; - case AMDGPU::BI__builtin_amdgcn_ds_fmaxf: - Intrin = Intrinsic::amdgcn_ds_fmax; - break; - } - llvm::Value *Src0 = EmitScalarExpr(E->getArg(0)); - llvm::Value *Src1 = EmitScalarExpr(E->getArg(1)); - llvm::Value *Src2 = EmitScalarExpr(E->getArg(2)); - llvm::Value *Src3 = EmitScalarExpr(E->getArg(3)); - llvm::Value *Src4 = EmitScalarExpr(E->getArg(4)); - llvm::Function *F = CGM.getIntrinsic(Intrin, { Src1->getType() }); - llvm::FunctionType *FTy = F->getFunctionType(); - llvm::Type *PTy = FTy->getParamType(0); - Src0 = Builder.CreatePointerBitCastOrAddrSpaceCast(Src0, PTy); - return Builder.CreateCall(F, { Src0, Src1, Src2, Src3, Src4 }); - } case AMDGPU::BI__builtin_amdgcn_global_atomic_fadd_f64: case AMDGPU::BI__builtin_amdgcn_global_atomic_fadd_f32: case AMDGPU::BI__builtin_amdgcn_global_atomic_fadd_v2f16: @@ -19059,11 +19065,13 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, case AMDGPU::BI__builtin_amdgcn_atomic_inc64: case AMDGPU::BI__builtin_amdgcn_atomic_dec32: case AMDGPU::BI__builtin_amdgcn_atomic_dec64: - case AMDGPU::BI__builtin_amdgcn_ds_faddf: case AMDGPU::BI__builtin_amdgcn_ds_atomic_fadd_f64: case AMDGPU::BI__builtin_amdgcn_ds_atomic_fadd_f32: case AMDGPU::BI__builtin_amdgcn_ds_atomic_fadd_v2f16: - case AMDGPU::BI__builtin_amdgcn_ds_atomic_fadd_v2bf16: { + case AMDGPU::BI__builtin_amdgcn_ds_atomic_fadd_v2bf16: + case AMDGPU::BI__builtin_amdgcn_ds_faddf: + case AMDGPU::BI__builtin_amdgcn_ds_fminf: + case AMDGPU::BI__builtin_amdgcn_ds_fmaxf: { llvm::AtomicRMWInst::BinOp BinOp; switch (BuiltinID) { case AMDGPU::BI__builtin_amdgcn_atomic_inc32: @@ -19081,6 +19089,12 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, case AMDGPU::BI__builtin_amdgcn_ds_atomic_fadd_v2bf16: BinOp = llvm::AtomicRMWInst::FAdd; break; + case AMDGPU::BI__builtin_amdgcn_ds_fminf: + BinOp = llvm::AtomicRMWInst::FMin; + break; + case AMDGPU::BI__builtin_amdgcn_ds_fmaxf: + BinOp = llvm::AtomicRMWInst::FMax; + break; } Address Ptr = CheckAtomicAlignment(*this, E); @@ -19090,8 +19104,10 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, bool Volatile; - if (BuiltinID == AMDGPU::BI__builtin_amdgcn_ds_faddf) { - // __builtin_amdgcn_ds_faddf has an explicit volatile argument + if (BuiltinID == AMDGPU::BI__builtin_amdgcn_ds_faddf || + BuiltinID == AMDGPU::BI__builtin_amdgcn_ds_fminf || + BuiltinID == AMDGPU::BI__builtin_amdgcn_ds_fmaxf) { + // __builtin_amdgcn_ds_faddf/fminf/fmaxf has an explicit volatile argument Volatile = cast(EmitScalarExpr(E->getArg(4)))->getZExtValue(); } else { @@ -19105,7 +19121,7 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, ProcessOrderScopeAMDGCN(EmitScalarExpr(E->getArg(2)), EmitScalarExpr(E->getArg(3)), AO, SSID); } else { - // The ds_fadd_* builtins do not have syncscope/order arguments. + // The ds_atomic_fadd_* builtins do not have syncscope/order arguments. SSID = llvm::SyncScope::System; AO = AtomicOrdering::SequentiallyConsistent; @@ -19135,6 +19151,14 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, case AMDGPU::BI__builtin_amdgcn_make_buffer_rsrc: return emitBuiltinWithOneOverloadedType<4>( *this, E, Intrinsic::amdgcn_make_buffer_rsrc); + case AMDGPU::BI__builtin_amdgcn_raw_buffer_store_b8: + case AMDGPU::BI__builtin_amdgcn_raw_buffer_store_b16: + case AMDGPU::BI__builtin_amdgcn_raw_buffer_store_b32: + case AMDGPU::BI__builtin_amdgcn_raw_buffer_store_b64: + case AMDGPU::BI__builtin_amdgcn_raw_buffer_store_b96: + case AMDGPU::BI__builtin_amdgcn_raw_buffer_store_b128: + return emitBuiltinWithOneOverloadedType<5>( + *this, E, Intrinsic::amdgcn_raw_ptr_buffer_store); default: return nullptr; } diff --git a/clang/lib/CodeGen/CGCXX.cpp b/clang/lib/CodeGen/CGCXX.cpp index e95a735f92f74b..23ebbee19bf791 100644 --- a/clang/lib/CodeGen/CGCXX.cpp +++ b/clang/lib/CodeGen/CGCXX.cpp @@ -263,7 +263,16 @@ static CGCallee BuildAppleKextVirtualCall(CodeGenFunction &CGF, CGF.Builder.CreateConstInBoundsGEP1_64(Ty, VTable, VTableIndex, "vfnkxt"); llvm::Value *VFunc = CGF.Builder.CreateAlignedLoad( Ty, VFuncPtr, llvm::Align(CGF.PointerAlignInBytes)); - CGCallee Callee(GD, VFunc); + + CGPointerAuthInfo PointerAuth; + if (auto &Schema = + CGM.getCodeGenOpts().PointerAuth.CXXVirtualFunctionPointers) { + GlobalDecl OrigMD = + CGM.getItaniumVTableContext().findOriginalMethod(GD.getCanonicalDecl()); + PointerAuth = CGF.EmitPointerAuthInfo(Schema, VFuncPtr, OrigMD, QualType()); + } + + CGCallee Callee(GD, VFunc, PointerAuth); return Callee; } diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h index 104a20db8efaf2..7dcc539111996b 100644 --- a/clang/lib/CodeGen/CGCXXABI.h +++ b/clang/lib/CodeGen/CGCXXABI.h @@ -504,13 +504,15 @@ class CGCXXABI { virtual void setThunkLinkage(llvm::Function *Thunk, bool ForVTable, GlobalDecl GD, bool ReturnAdjustment) = 0; - virtual llvm::Value *performThisAdjustment(CodeGenFunction &CGF, - Address This, - const ThisAdjustment &TA) = 0; + virtual llvm::Value * + performThisAdjustment(CodeGenFunction &CGF, Address This, + const CXXRecordDecl *UnadjustedClass, + const ThunkInfo &TI) = 0; - virtual llvm::Value *performReturnAdjustment(CodeGenFunction &CGF, - Address Ret, - const ReturnAdjustment &RA) = 0; + virtual llvm::Value * + performReturnAdjustment(CodeGenFunction &CGF, Address Ret, + const CXXRecordDecl *UnadjustedClass, + const ReturnAdjustment &RA) = 0; virtual void EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV, QualType ResultType); diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 5a032bdbf93791..0a595bb998d261 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -2588,6 +2588,11 @@ void CodeGenFunction::InitializeVTablePointer(const VPtr &Vptr) { // the same addr space. Note that this might not be LLVM address space 0. VTableField = VTableField.withElementType(PtrTy); + if (auto AuthenticationInfo = CGM.getVTablePointerAuthInfo( + this, Vptr.Base.getBase(), VTableField.emitRawPointer(*this))) + VTableAddressPoint = + EmitPointerAuthSign(*AuthenticationInfo, VTableAddressPoint); + llvm::StoreInst *Store = Builder.CreateStore(VTableAddressPoint, VTableField); TBAAAccessInfo TBAAInfo = CGM.getTBAAVTablePtrAccessInfo(PtrTy); CGM.DecorateInstructionWithTBAA(Store, TBAAInfo); @@ -2681,12 +2686,35 @@ void CodeGenFunction::InitializeVTablePointers(const CXXRecordDecl *RD) { llvm::Value *CodeGenFunction::GetVTablePtr(Address This, llvm::Type *VTableTy, - const CXXRecordDecl *RD) { + const CXXRecordDecl *RD, + VTableAuthMode AuthMode) { Address VTablePtrSrc = This.withElementType(VTableTy); llvm::Instruction *VTable = Builder.CreateLoad(VTablePtrSrc, "vtable"); TBAAAccessInfo TBAAInfo = CGM.getTBAAVTablePtrAccessInfo(VTableTy); CGM.DecorateInstructionWithTBAA(VTable, TBAAInfo); + if (auto AuthenticationInfo = + CGM.getVTablePointerAuthInfo(this, RD, This.emitRawPointer(*this))) { + if (AuthMode != VTableAuthMode::UnsafeUbsanStrip) { + VTable = cast( + EmitPointerAuthAuth(*AuthenticationInfo, VTable)); + if (AuthMode == VTableAuthMode::MustTrap) { + // This is clearly suboptimal but until we have an ability + // to rely on the authentication intrinsic trapping and force + // an authentication to occur we don't really have a choice. + VTable = + cast(Builder.CreateBitCast(VTable, Int8PtrTy)); + Builder.CreateLoad(RawAddress(VTable, Int8Ty, CGM.getPointerAlign()), + /* IsVolatile */ true); + } + } else { + VTable = cast(EmitPointerAuthAuth( + CGPointerAuthInfo(0, PointerAuthenticationMode::Strip, false, false, + nullptr), + VTable)); + } + } + if (CGM.getCodeGenOpts().OptimizationLevel > 0 && CGM.getCodeGenOpts().StrictVTablePointers) CGM.DecorateInstructionWithInvariantGroup(VTable, RD); diff --git a/clang/lib/CodeGen/CGCoroutine.cpp b/clang/lib/CodeGen/CGCoroutine.cpp index b4c724422c14aa..a8a70186c2c5a1 100644 --- a/clang/lib/CodeGen/CGCoroutine.cpp +++ b/clang/lib/CodeGen/CGCoroutine.cpp @@ -103,7 +103,7 @@ static void createCoroData(CodeGenFunction &CGF, return; } - CurCoro.Data = std::unique_ptr(new CGCoroData); + CurCoro.Data = std::make_unique(); CurCoro.Data->CoroId = CoroId; CurCoro.Data->CoroIdExpr = CoroIdExpr; } diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index a072475ba77057..3d8a715b692de8 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -32,6 +32,7 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/Version.h" +#include "clang/CodeGen/ModuleBuilder.h" #include "clang/Frontend/FrontendOptions.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/ModuleMap.h" @@ -1731,6 +1732,28 @@ llvm::DIType *CGDebugInfo::createFieldType( offsetInBits, flags, debugType, Annotations); } +llvm::DISubprogram * +CGDebugInfo::createInlinedTrapSubprogram(StringRef FuncName, + llvm::DIFile *FileScope) { + // We are caching the subprogram because we don't want to duplicate + // subprograms with the same message. Note that `SPFlagDefinition` prevents + // subprograms from being uniqued. + llvm::DISubprogram *&SP = InlinedTrapFuncMap[FuncName]; + + if (!SP) { + llvm::DISubroutineType *DIFnTy = DBuilder.createSubroutineType(nullptr); + SP = DBuilder.createFunction( + /*Scope=*/FileScope, /*Name=*/FuncName, /*LinkageName=*/StringRef(), + /*File=*/FileScope, /*LineNo=*/0, /*Ty=*/DIFnTy, + /*ScopeLine=*/0, + /*Flags=*/llvm::DINode::FlagArtificial, + /*SPFlags=*/llvm::DISubprogram::SPFlagDefinition, + /*TParams=*/nullptr, /*ThrownTypes=*/nullptr, /*Annotations=*/nullptr); + } + + return SP; +} + void CGDebugInfo::CollectRecordLambdaFields( const CXXRecordDecl *CXXDecl, SmallVectorImpl &elements, llvm::DIType *RecordTy) { @@ -3527,6 +3550,23 @@ llvm::DIMacroFile *CGDebugInfo::CreateTempMacroFile(llvm::DIMacroFile *Parent, return DBuilder.createTempMacroFile(Parent, Line, FName); } +llvm::DILocation *CGDebugInfo::CreateTrapFailureMessageFor( + llvm::DebugLoc TrapLocation, StringRef Category, StringRef FailureMsg) { + // Create a debug location from `TrapLocation` that adds an artificial inline + // frame. + SmallString<64> FuncName(ClangTrapPrefix); + + FuncName += "$"; + FuncName += Category; + FuncName += "$"; + FuncName += FailureMsg; + + llvm::DISubprogram *TrapSP = + createInlinedTrapSubprogram(FuncName, TrapLocation->getFile()); + return llvm::DILocation::get(CGM.getLLVMContext(), /*Line=*/0, /*Column=*/0, + /*Scope=*/TrapSP, /*InlinedAt=*/TrapLocation); +} + static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) { Qualifiers Quals; do { diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index 2731c627d9dc37..a0c419cf1e208a 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -29,7 +29,9 @@ #include "llvm/IR/DebugInfo.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Support/Allocator.h" +#include #include +#include namespace llvm { class MDNode; @@ -346,6 +348,14 @@ class CGDebugInfo { const FieldDecl *BitFieldDecl, const llvm::DIDerivedType *BitFieldDI, llvm::ArrayRef PreviousFieldsDI, const RecordDecl *RD); + /// A cache that maps names of artificial inlined functions to subprograms. + llvm::StringMap InlinedTrapFuncMap; + + /// A function that returns the subprogram corresponding to the artificial + /// inlined function for traps. + llvm::DISubprogram *createInlinedTrapSubprogram(StringRef FuncName, + llvm::DIFile *FileScope); + /// Helpers for collecting fields of a record. /// @{ void CollectRecordLambdaFields(const CXXRecordDecl *CXXDecl, @@ -608,6 +618,18 @@ class CGDebugInfo { return CoroutineParameterMappings; } + /// Create a debug location from `TrapLocation` that adds an artificial inline + /// frame where the frame name is + /// + /// * `::` + /// + /// `` is "__clang_trap_msg". + /// + /// This is used to store failure reasons for traps. + llvm::DILocation *CreateTrapFailureMessageFor(llvm::DebugLoc TrapLocation, + StringRef Category, + StringRef FailureMsg); + private: /// Emit call to llvm.dbg.declare for a variable declaration. /// Returns a pointer to the DILocalVariable associated with the diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 4a213990d1e36e..90aa4c0745a8ab 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -1972,7 +1972,21 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) { } if (!constant) { - initializeWhatIsTechnicallyUninitialized(Loc); + if (trivialAutoVarInit != + LangOptions::TrivialAutoVarInitKind::Uninitialized) { + // At this point, we know D has an Init expression, but isn't a constant. + // - If D is not a scalar, auto-var-init conservatively (members may be + // left uninitialized by constructor Init expressions for example). + // - If D is a scalar, we only need to auto-var-init if there is a + // self-reference. Otherwise, the Init expression should be sufficient. + // It may be that the Init expression uses other uninitialized memory, + // but auto-var-init here would not help, as auto-init would get + // overwritten by Init. + if (!D.getType()->isScalarType() || capturedByInit || + isAccessedBy(D, Init)) { + initializeWhatIsTechnicallyUninitialized(Loc); + } + } LValue lv = MakeAddrLValue(Loc, type); lv.setNonGC(true); return EmitExprAsInit(Init, &D, lv, capturedByInit); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 534f46da748627..23e5deee325813 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -830,8 +830,14 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, // Load the vptr, and mix it with TypeHash. llvm::Value *TypeHash = llvm::ConstantInt::get(Int64Ty, xxh3_64bits(Out.str())); + + llvm::Type *VPtrTy = llvm::PointerType::get(IntPtrTy, 0); Address VPtrAddr(Ptr, IntPtrTy, getPointerAlign()); - llvm::Value *VPtrVal = Builder.CreateLoad(VPtrAddr); + llvm::Value *VPtrVal = GetVTablePtr(VPtrAddr, VPtrTy, + Ty->getAsCXXRecordDecl(), + VTableAuthMode::UnsafeUbsanStrip); + VPtrVal = Builder.CreateBitOrPointerCast(VPtrVal, IntPtrTy); + llvm::Value *Hash = emitHashMix(Builder, TypeHash, Builder.CreateZExt(VPtrVal, Int64Ty)); Hash = Builder.CreateTrunc(Hash, IntPtrTy); diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index dffb8ce83b6437..1fec587b5c4c7c 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -803,6 +803,13 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD, llvm::Constant *VTableAddressPoint = CGM.getCXXABI().getVTableAddressPoint(BaseSubobject(CD, Offset), VTableClass); + if (auto Authentication = + CGM.getVTablePointerAuthentication(VTableClass)) { + VTableAddressPoint = Emitter.tryEmitConstantSignedPointer( + VTableAddressPoint, *Authentication); + if (!VTableAddressPoint) + return false; + } if (!AppendBytes(Offset, VTableAddressPoint)) return false; } @@ -1647,7 +1654,7 @@ namespace { // messing around with llvm::Constant structures, which never itself // does anything that should be visible in compiler output. for (auto &entry : Locations) { - assert(entry.first->getParent() == nullptr && "not a placeholder!"); + assert(entry.first->getName() == "" && "not a placeholder!"); entry.first->replaceAllUsesWith(entry.second); entry.first->eraseFromParent(); } @@ -1811,6 +1818,43 @@ llvm::Constant *ConstantEmitter::tryEmitPrivateForMemory(const APValue &value, return (C ? emitForMemory(C, destType) : nullptr); } +/// Try to emit a constant signed pointer, given a raw pointer and the +/// destination ptrauth qualifier. +/// +/// This can fail if the qualifier needs address discrimination and the +/// emitter is in an abstract mode. +llvm::Constant * +ConstantEmitter::tryEmitConstantSignedPointer(llvm::Constant *UnsignedPointer, + PointerAuthQualifier Schema) { + assert(Schema && "applying trivial ptrauth schema"); + + if (Schema.hasKeyNone()) + return UnsignedPointer; + + unsigned Key = Schema.getKey(); + + // Create an address placeholder if we're using address discrimination. + llvm::GlobalValue *StorageAddress = nullptr; + if (Schema.isAddressDiscriminated()) { + // We can't do this if the emitter is in an abstract state. + if (isAbstract()) + return nullptr; + + StorageAddress = getCurrentAddrPrivate(); + } + + llvm::ConstantInt *Discriminator = + llvm::ConstantInt::get(CGM.IntPtrTy, Schema.getExtraDiscriminator()); + + llvm::Constant *SignedPointer = CGM.getConstantSignedPointer( + UnsignedPointer, Key, StorageAddress, Discriminator); + + if (Schema.isAddressDiscriminated()) + registerCurrentAddrPrivate(SignedPointer, StorageAddress); + + return SignedPointer; +} + llvm::Constant *ConstantEmitter::emitForMemory(CodeGenModule &CGM, llvm::Constant *C, QualType destType) { @@ -2041,10 +2085,10 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) { return ConstantLValue(C); }; - if (auto FD = dyn_cast(D)) + if (const auto *FD = dyn_cast(D)) return PtrAuthSign(CGM.getRawFunctionPointer(FD)); - if (auto VD = dyn_cast(D)) { + if (const auto *VD = dyn_cast(D)) { // We can never refer to a variable with local storage. if (!VD->hasLocalStorage()) { if (VD->isFileVarDecl() || VD->hasExternalStorage()) @@ -2057,13 +2101,13 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) { } } - if (auto *GD = dyn_cast(D)) + if (const auto *GD = dyn_cast(D)) return CGM.GetAddrOfMSGuidDecl(GD); - if (auto *GCD = dyn_cast(D)) + if (const auto *GCD = dyn_cast(D)) return CGM.GetAddrOfUnnamedGlobalConstantDecl(GCD); - if (auto *TPO = dyn_cast(D)) + if (const auto *TPO = dyn_cast(D)) return CGM.GetAddrOfTemplateParamObject(TPO); return nullptr; diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp index 6e9a1bacd9bf5f..f5bd4a141cc2d7 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp @@ -501,31 +501,6 @@ class CheckVarsEscapingDeclContext final }; } // anonymous namespace -/// Get the id of the warp in the block. -/// We assume that the warp size is 32, which is always the case -/// on the NVPTX device, to generate more efficient code. -static llvm::Value *getNVPTXWarpID(CodeGenFunction &CGF) { - CGBuilderTy &Bld = CGF.Builder; - unsigned LaneIDBits = - llvm::Log2_32(CGF.getTarget().getGridValue().GV_Warp_Size); - auto &RT = static_cast(CGF.CGM.getOpenMPRuntime()); - return Bld.CreateAShr(RT.getGPUThreadID(CGF), LaneIDBits, "nvptx_warp_id"); -} - -/// Get the id of the current lane in the Warp. -/// We assume that the warp size is 32, which is always the case -/// on the NVPTX device, to generate more efficient code. -static llvm::Value *getNVPTXLaneID(CodeGenFunction &CGF) { - CGBuilderTy &Bld = CGF.Builder; - unsigned LaneIDBits = - llvm::Log2_32(CGF.getTarget().getGridValue().GV_Warp_Size); - assert(LaneIDBits < 32 && "Invalid LaneIDBits size in NVPTX device."); - unsigned LaneIDMask = ~0u >> (32u - LaneIDBits); - auto &RT = static_cast(CGF.CGM.getOpenMPRuntime()); - return Bld.CreateAnd(RT.getGPUThreadID(CGF), Bld.getInt32(LaneIDMask), - "nvptx_lane_id"); -} - CGOpenMPRuntimeGPU::ExecutionMode CGOpenMPRuntimeGPU::getExecutionMode() const { return CurrentExecutionMode; @@ -1435,1133 +1410,6 @@ static llvm::Value *castValueToType(CodeGenFunction &CGF, llvm::Value *Val, TBAAAccessInfo()); } -/// This function creates calls to one of two shuffle functions to copy -/// variables between lanes in a warp. -static llvm::Value *createRuntimeShuffleFunction(CodeGenFunction &CGF, - llvm::Value *Elem, - QualType ElemType, - llvm::Value *Offset, - SourceLocation Loc) { - CodeGenModule &CGM = CGF.CGM; - CGBuilderTy &Bld = CGF.Builder; - CGOpenMPRuntimeGPU &RT = - *(static_cast(&CGM.getOpenMPRuntime())); - llvm::OpenMPIRBuilder &OMPBuilder = RT.getOMPBuilder(); - - CharUnits Size = CGF.getContext().getTypeSizeInChars(ElemType); - assert(Size.getQuantity() <= 8 && - "Unsupported bitwidth in shuffle instruction."); - - RuntimeFunction ShuffleFn = Size.getQuantity() <= 4 - ? OMPRTL___kmpc_shuffle_int32 - : OMPRTL___kmpc_shuffle_int64; - - // Cast all types to 32- or 64-bit values before calling shuffle routines. - QualType CastTy = CGF.getContext().getIntTypeForBitwidth( - Size.getQuantity() <= 4 ? 32 : 64, /*Signed=*/1); - llvm::Value *ElemCast = castValueToType(CGF, Elem, ElemType, CastTy, Loc); - llvm::Value *WarpSize = - Bld.CreateIntCast(RT.getGPUWarpSize(CGF), CGM.Int16Ty, /*isSigned=*/true); - - llvm::Value *ShuffledVal = CGF.EmitRuntimeCall( - OMPBuilder.getOrCreateRuntimeFunction(CGM.getModule(), ShuffleFn), - {ElemCast, Offset, WarpSize}); - - return castValueToType(CGF, ShuffledVal, CastTy, ElemType, Loc); -} - -static void shuffleAndStore(CodeGenFunction &CGF, Address SrcAddr, - Address DestAddr, QualType ElemType, - llvm::Value *Offset, SourceLocation Loc) { - CGBuilderTy &Bld = CGF.Builder; - - CharUnits Size = CGF.getContext().getTypeSizeInChars(ElemType); - // Create the loop over the big sized data. - // ptr = (void*)Elem; - // ptrEnd = (void*) Elem + 1; - // Step = 8; - // while (ptr + Step < ptrEnd) - // shuffle((int64_t)*ptr); - // Step = 4; - // while (ptr + Step < ptrEnd) - // shuffle((int32_t)*ptr); - // ... - Address ElemPtr = DestAddr; - Address Ptr = SrcAddr; - Address PtrEnd = Bld.CreatePointerBitCastOrAddrSpaceCast( - Bld.CreateConstGEP(SrcAddr, 1), CGF.VoidPtrTy, CGF.Int8Ty); - for (int IntSize = 8; IntSize >= 1; IntSize /= 2) { - if (Size < CharUnits::fromQuantity(IntSize)) - continue; - QualType IntType = CGF.getContext().getIntTypeForBitwidth( - CGF.getContext().toBits(CharUnits::fromQuantity(IntSize)), - /*Signed=*/1); - llvm::Type *IntTy = CGF.ConvertTypeForMem(IntType); - Ptr = Bld.CreatePointerBitCastOrAddrSpaceCast(Ptr, IntTy->getPointerTo(), - IntTy); - ElemPtr = Bld.CreatePointerBitCastOrAddrSpaceCast( - ElemPtr, IntTy->getPointerTo(), IntTy); - if (Size.getQuantity() / IntSize > 1) { - llvm::BasicBlock *PreCondBB = CGF.createBasicBlock(".shuffle.pre_cond"); - llvm::BasicBlock *ThenBB = CGF.createBasicBlock(".shuffle.then"); - llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".shuffle.exit"); - llvm::BasicBlock *CurrentBB = Bld.GetInsertBlock(); - CGF.EmitBlock(PreCondBB); - llvm::PHINode *PhiSrc = - Bld.CreatePHI(Ptr.getType(), /*NumReservedValues=*/2); - PhiSrc->addIncoming(Ptr.emitRawPointer(CGF), CurrentBB); - llvm::PHINode *PhiDest = - Bld.CreatePHI(ElemPtr.getType(), /*NumReservedValues=*/2); - PhiDest->addIncoming(ElemPtr.emitRawPointer(CGF), CurrentBB); - Ptr = Address(PhiSrc, Ptr.getElementType(), Ptr.getAlignment()); - ElemPtr = - Address(PhiDest, ElemPtr.getElementType(), ElemPtr.getAlignment()); - llvm::Value *PtrEndRaw = PtrEnd.emitRawPointer(CGF); - llvm::Value *PtrRaw = Ptr.emitRawPointer(CGF); - llvm::Value *PtrDiff = Bld.CreatePtrDiff( - CGF.Int8Ty, PtrEndRaw, - Bld.CreatePointerBitCastOrAddrSpaceCast(PtrRaw, CGF.VoidPtrTy)); - Bld.CreateCondBr(Bld.CreateICmpSGT(PtrDiff, Bld.getInt64(IntSize - 1)), - ThenBB, ExitBB); - CGF.EmitBlock(ThenBB); - llvm::Value *Res = createRuntimeShuffleFunction( - CGF, - CGF.EmitLoadOfScalar(Ptr, /*Volatile=*/false, IntType, Loc, - LValueBaseInfo(AlignmentSource::Type), - TBAAAccessInfo()), - IntType, Offset, Loc); - CGF.EmitStoreOfScalar(Res, ElemPtr, /*Volatile=*/false, IntType, - LValueBaseInfo(AlignmentSource::Type), - TBAAAccessInfo()); - Address LocalPtr = Bld.CreateConstGEP(Ptr, 1); - Address LocalElemPtr = Bld.CreateConstGEP(ElemPtr, 1); - PhiSrc->addIncoming(LocalPtr.emitRawPointer(CGF), ThenBB); - PhiDest->addIncoming(LocalElemPtr.emitRawPointer(CGF), ThenBB); - CGF.EmitBranch(PreCondBB); - CGF.EmitBlock(ExitBB); - } else { - llvm::Value *Res = createRuntimeShuffleFunction( - CGF, - CGF.EmitLoadOfScalar(Ptr, /*Volatile=*/false, IntType, Loc, - LValueBaseInfo(AlignmentSource::Type), - TBAAAccessInfo()), - IntType, Offset, Loc); - CGF.EmitStoreOfScalar(Res, ElemPtr, /*Volatile=*/false, IntType, - LValueBaseInfo(AlignmentSource::Type), - TBAAAccessInfo()); - Ptr = Bld.CreateConstGEP(Ptr, 1); - ElemPtr = Bld.CreateConstGEP(ElemPtr, 1); - } - Size = Size % IntSize; - } -} - -namespace { -enum CopyAction : unsigned { - // RemoteLaneToThread: Copy over a Reduce list from a remote lane in - // the warp using shuffle instructions. - RemoteLaneToThread, - // ThreadCopy: Make a copy of a Reduce list on the thread's stack. - ThreadCopy, -}; -} // namespace - -struct CopyOptionsTy { - llvm::Value *RemoteLaneOffset; - llvm::Value *ScratchpadIndex; - llvm::Value *ScratchpadWidth; -}; - -/// Emit instructions to copy a Reduce list, which contains partially -/// aggregated values, in the specified direction. -static void emitReductionListCopy( - CopyAction Action, CodeGenFunction &CGF, QualType ReductionArrayTy, - ArrayRef Privates, Address SrcBase, Address DestBase, - CopyOptionsTy CopyOptions = {nullptr, nullptr, nullptr}) { - - CodeGenModule &CGM = CGF.CGM; - ASTContext &C = CGM.getContext(); - CGBuilderTy &Bld = CGF.Builder; - - llvm::Value *RemoteLaneOffset = CopyOptions.RemoteLaneOffset; - - // Iterates, element-by-element, through the source Reduce list and - // make a copy. - unsigned Idx = 0; - for (const Expr *Private : Privates) { - Address SrcElementAddr = Address::invalid(); - Address DestElementAddr = Address::invalid(); - Address DestElementPtrAddr = Address::invalid(); - // Should we shuffle in an element from a remote lane? - bool ShuffleInElement = false; - // Set to true to update the pointer in the dest Reduce list to a - // newly created element. - bool UpdateDestListPtr = false; - QualType PrivatePtrType = C.getPointerType(Private->getType()); - llvm::Type *PrivateLlvmPtrType = CGF.ConvertType(PrivatePtrType); - - switch (Action) { - case RemoteLaneToThread: { - // Step 1.1: Get the address for the src element in the Reduce list. - Address SrcElementPtrAddr = Bld.CreateConstArrayGEP(SrcBase, Idx); - SrcElementAddr = CGF.EmitLoadOfPointer( - SrcElementPtrAddr.withElementType(PrivateLlvmPtrType), - PrivatePtrType->castAs()); - - // Step 1.2: Create a temporary to store the element in the destination - // Reduce list. - DestElementPtrAddr = Bld.CreateConstArrayGEP(DestBase, Idx); - DestElementAddr = - CGF.CreateMemTemp(Private->getType(), ".omp.reduction.element"); - ShuffleInElement = true; - UpdateDestListPtr = true; - break; - } - case ThreadCopy: { - // Step 1.1: Get the address for the src element in the Reduce list. - Address SrcElementPtrAddr = Bld.CreateConstArrayGEP(SrcBase, Idx); - SrcElementAddr = CGF.EmitLoadOfPointer( - SrcElementPtrAddr.withElementType(PrivateLlvmPtrType), - PrivatePtrType->castAs()); - - // Step 1.2: Get the address for dest element. The destination - // element has already been created on the thread's stack. - DestElementPtrAddr = Bld.CreateConstArrayGEP(DestBase, Idx); - DestElementAddr = CGF.EmitLoadOfPointer( - DestElementPtrAddr.withElementType(PrivateLlvmPtrType), - PrivatePtrType->castAs()); - break; - } - } - - // Regardless of src and dest of copy, we emit the load of src - // element as this is required in all directions - SrcElementAddr = SrcElementAddr.withElementType( - CGF.ConvertTypeForMem(Private->getType())); - DestElementAddr = - DestElementAddr.withElementType(SrcElementAddr.getElementType()); - - // Now that all active lanes have read the element in the - // Reduce list, shuffle over the value from the remote lane. - if (ShuffleInElement) { - shuffleAndStore(CGF, SrcElementAddr, DestElementAddr, Private->getType(), - RemoteLaneOffset, Private->getExprLoc()); - } else { - switch (CGF.getEvaluationKind(Private->getType())) { - case TEK_Scalar: { - llvm::Value *Elem = CGF.EmitLoadOfScalar( - SrcElementAddr, /*Volatile=*/false, Private->getType(), - Private->getExprLoc(), LValueBaseInfo(AlignmentSource::Type), - TBAAAccessInfo()); - // Store the source element value to the dest element address. - CGF.EmitStoreOfScalar( - Elem, DestElementAddr, /*Volatile=*/false, Private->getType(), - LValueBaseInfo(AlignmentSource::Type), TBAAAccessInfo()); - break; - } - case TEK_Complex: { - CodeGenFunction::ComplexPairTy Elem = CGF.EmitLoadOfComplex( - CGF.MakeAddrLValue(SrcElementAddr, Private->getType()), - Private->getExprLoc()); - CGF.EmitStoreOfComplex( - Elem, CGF.MakeAddrLValue(DestElementAddr, Private->getType()), - /*isInit=*/false); - break; - } - case TEK_Aggregate: - CGF.EmitAggregateCopy( - CGF.MakeAddrLValue(DestElementAddr, Private->getType()), - CGF.MakeAddrLValue(SrcElementAddr, Private->getType()), - Private->getType(), AggValueSlot::DoesNotOverlap); - break; - } - } - - // Step 3.1: Modify reference in dest Reduce list as needed. - // Modifying the reference in Reduce list to point to the newly - // created element. The element is live in the current function - // scope and that of functions it invokes (i.e., reduce_function). - // RemoteReduceData[i] = (void*)&RemoteElem - if (UpdateDestListPtr) { - CGF.EmitStoreOfScalar( - Bld.CreatePointerBitCastOrAddrSpaceCast( - DestElementAddr.emitRawPointer(CGF), CGF.VoidPtrTy), - DestElementPtrAddr, /*Volatile=*/false, C.VoidPtrTy); - } - - ++Idx; - } -} - -/// This function emits a helper that gathers Reduce lists from the first -/// lane of every active warp to lanes in the first warp. -/// -/// void inter_warp_copy_func(void* reduce_data, num_warps) -/// shared smem[warp_size]; -/// For all data entries D in reduce_data: -/// sync -/// If (I am the first lane in each warp) -/// Copy my local D to smem[warp_id] -/// sync -/// if (I am the first warp) -/// Copy smem[thread_id] to my local D -static llvm::Value *emitInterWarpCopyFunction(CodeGenModule &CGM, - ArrayRef Privates, - QualType ReductionArrayTy, - SourceLocation Loc) { - ASTContext &C = CGM.getContext(); - llvm::Module &M = CGM.getModule(); - - // ReduceList: thread local Reduce list. - // At the stage of the computation when this function is called, partially - // aggregated values reside in the first lane of every active warp. - ImplicitParamDecl ReduceListArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, - C.VoidPtrTy, ImplicitParamKind::Other); - // NumWarps: number of warps active in the parallel region. This could - // be smaller than 32 (max warps in a CTA) for partial block reduction. - ImplicitParamDecl NumWarpsArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, - C.getIntTypeForBitwidth(32, /* Signed */ true), - ImplicitParamKind::Other); - FunctionArgList Args; - Args.push_back(&ReduceListArg); - Args.push_back(&NumWarpsArg); - - const CGFunctionInfo &CGFI = - CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args); - auto *Fn = llvm::Function::Create(CGM.getTypes().GetFunctionType(CGFI), - llvm::GlobalValue::InternalLinkage, - "_omp_reduction_inter_warp_copy_func", &M); - CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, CGFI); - Fn->setDoesNotRecurse(); - CodeGenFunction CGF(CGM); - CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args, Loc, Loc); - - CGBuilderTy &Bld = CGF.Builder; - - // This array is used as a medium to transfer, one reduce element at a time, - // the data from the first lane of every warp to lanes in the first warp - // in order to perform the final step of a reduction in a parallel region - // (reduction across warps). The array is placed in NVPTX __shared__ memory - // for reduced latency, as well as to have a distinct copy for concurrently - // executing target regions. The array is declared with common linkage so - // as to be shared across compilation units. - StringRef TransferMediumName = - "__openmp_nvptx_data_transfer_temporary_storage"; - llvm::GlobalVariable *TransferMedium = - M.getGlobalVariable(TransferMediumName); - unsigned WarpSize = CGF.getTarget().getGridValue().GV_Warp_Size; - if (!TransferMedium) { - auto *Ty = llvm::ArrayType::get(CGM.Int32Ty, WarpSize); - unsigned SharedAddressSpace = C.getTargetAddressSpace(LangAS::cuda_shared); - TransferMedium = new llvm::GlobalVariable( - M, Ty, /*isConstant=*/false, llvm::GlobalVariable::WeakAnyLinkage, - llvm::UndefValue::get(Ty), TransferMediumName, - /*InsertBefore=*/nullptr, llvm::GlobalVariable::NotThreadLocal, - SharedAddressSpace); - CGM.addCompilerUsedGlobal(TransferMedium); - } - - auto &RT = static_cast(CGF.CGM.getOpenMPRuntime()); - // Get the CUDA thread id of the current OpenMP thread on the GPU. - llvm::Value *ThreadID = RT.getGPUThreadID(CGF); - // nvptx_lane_id = nvptx_id % warpsize - llvm::Value *LaneID = getNVPTXLaneID(CGF); - // nvptx_warp_id = nvptx_id / warpsize - llvm::Value *WarpID = getNVPTXWarpID(CGF); - - Address AddrReduceListArg = CGF.GetAddrOfLocalVar(&ReduceListArg); - llvm::Type *ElemTy = CGF.ConvertTypeForMem(ReductionArrayTy); - Address LocalReduceList( - Bld.CreatePointerBitCastOrAddrSpaceCast( - CGF.EmitLoadOfScalar( - AddrReduceListArg, /*Volatile=*/false, C.VoidPtrTy, Loc, - LValueBaseInfo(AlignmentSource::Type), TBAAAccessInfo()), - ElemTy->getPointerTo()), - ElemTy, CGF.getPointerAlign()); - - unsigned Idx = 0; - for (const Expr *Private : Privates) { - // - // Warp master copies reduce element to transfer medium in __shared__ - // memory. - // - unsigned RealTySize = - C.getTypeSizeInChars(Private->getType()) - .alignTo(C.getTypeAlignInChars(Private->getType())) - .getQuantity(); - for (unsigned TySize = 4; TySize > 0 && RealTySize > 0; TySize /=2) { - unsigned NumIters = RealTySize / TySize; - if (NumIters == 0) - continue; - QualType CType = C.getIntTypeForBitwidth( - C.toBits(CharUnits::fromQuantity(TySize)), /*Signed=*/1); - llvm::Type *CopyType = CGF.ConvertTypeForMem(CType); - CharUnits Align = CharUnits::fromQuantity(TySize); - llvm::Value *Cnt = nullptr; - Address CntAddr = Address::invalid(); - llvm::BasicBlock *PrecondBB = nullptr; - llvm::BasicBlock *ExitBB = nullptr; - if (NumIters > 1) { - CntAddr = CGF.CreateMemTemp(C.IntTy, ".cnt.addr"); - CGF.EmitStoreOfScalar(llvm::Constant::getNullValue(CGM.IntTy), CntAddr, - /*Volatile=*/false, C.IntTy); - PrecondBB = CGF.createBasicBlock("precond"); - ExitBB = CGF.createBasicBlock("exit"); - llvm::BasicBlock *BodyBB = CGF.createBasicBlock("body"); - // There is no need to emit line number for unconditional branch. - (void)ApplyDebugLocation::CreateEmpty(CGF); - CGF.EmitBlock(PrecondBB); - Cnt = CGF.EmitLoadOfScalar(CntAddr, /*Volatile=*/false, C.IntTy, Loc); - llvm::Value *Cmp = - Bld.CreateICmpULT(Cnt, llvm::ConstantInt::get(CGM.IntTy, NumIters)); - Bld.CreateCondBr(Cmp, BodyBB, ExitBB); - CGF.EmitBlock(BodyBB); - } - // kmpc_barrier. - CGM.getOpenMPRuntime().emitBarrierCall(CGF, Loc, OMPD_unknown, - /*EmitChecks=*/false, - /*ForceSimpleCall=*/true); - llvm::BasicBlock *ThenBB = CGF.createBasicBlock("then"); - llvm::BasicBlock *ElseBB = CGF.createBasicBlock("else"); - llvm::BasicBlock *MergeBB = CGF.createBasicBlock("ifcont"); - - // if (lane_id == 0) - llvm::Value *IsWarpMaster = Bld.CreateIsNull(LaneID, "warp_master"); - Bld.CreateCondBr(IsWarpMaster, ThenBB, ElseBB); - CGF.EmitBlock(ThenBB); - - // Reduce element = LocalReduceList[i] - Address ElemPtrPtrAddr = Bld.CreateConstArrayGEP(LocalReduceList, Idx); - llvm::Value *ElemPtrPtr = CGF.EmitLoadOfScalar( - ElemPtrPtrAddr, /*Volatile=*/false, C.VoidPtrTy, SourceLocation()); - // elemptr = ((CopyType*)(elemptrptr)) + I - Address ElemPtr(ElemPtrPtr, CopyType, Align); - if (NumIters > 1) - ElemPtr = Bld.CreateGEP(CGF, ElemPtr, Cnt); - - // Get pointer to location in transfer medium. - // MediumPtr = &medium[warp_id] - llvm::Value *MediumPtrVal = Bld.CreateInBoundsGEP( - TransferMedium->getValueType(), TransferMedium, - {llvm::Constant::getNullValue(CGM.Int64Ty), WarpID}); - // Casting to actual data type. - // MediumPtr = (CopyType*)MediumPtrAddr; - Address MediumPtr(MediumPtrVal, CopyType, Align); - - // elem = *elemptr - //*MediumPtr = elem - llvm::Value *Elem = CGF.EmitLoadOfScalar( - ElemPtr, /*Volatile=*/false, CType, Loc, - LValueBaseInfo(AlignmentSource::Type), TBAAAccessInfo()); - // Store the source element value to the dest element address. - CGF.EmitStoreOfScalar(Elem, MediumPtr, /*Volatile=*/true, CType, - LValueBaseInfo(AlignmentSource::Type), - TBAAAccessInfo()); - - Bld.CreateBr(MergeBB); - - CGF.EmitBlock(ElseBB); - Bld.CreateBr(MergeBB); - - CGF.EmitBlock(MergeBB); - - // kmpc_barrier. - CGM.getOpenMPRuntime().emitBarrierCall(CGF, Loc, OMPD_unknown, - /*EmitChecks=*/false, - /*ForceSimpleCall=*/true); - - // - // Warp 0 copies reduce element from transfer medium. - // - llvm::BasicBlock *W0ThenBB = CGF.createBasicBlock("then"); - llvm::BasicBlock *W0ElseBB = CGF.createBasicBlock("else"); - llvm::BasicBlock *W0MergeBB = CGF.createBasicBlock("ifcont"); - - Address AddrNumWarpsArg = CGF.GetAddrOfLocalVar(&NumWarpsArg); - llvm::Value *NumWarpsVal = CGF.EmitLoadOfScalar( - AddrNumWarpsArg, /*Volatile=*/false, C.IntTy, Loc); - - // Up to 32 threads in warp 0 are active. - llvm::Value *IsActiveThread = - Bld.CreateICmpULT(ThreadID, NumWarpsVal, "is_active_thread"); - Bld.CreateCondBr(IsActiveThread, W0ThenBB, W0ElseBB); - - CGF.EmitBlock(W0ThenBB); - - // SrcMediumPtr = &medium[tid] - llvm::Value *SrcMediumPtrVal = Bld.CreateInBoundsGEP( - TransferMedium->getValueType(), TransferMedium, - {llvm::Constant::getNullValue(CGM.Int64Ty), ThreadID}); - // SrcMediumVal = *SrcMediumPtr; - Address SrcMediumPtr(SrcMediumPtrVal, CopyType, Align); - - // TargetElemPtr = (CopyType*)(SrcDataAddr[i]) + I - Address TargetElemPtrPtr = Bld.CreateConstArrayGEP(LocalReduceList, Idx); - llvm::Value *TargetElemPtrVal = CGF.EmitLoadOfScalar( - TargetElemPtrPtr, /*Volatile=*/false, C.VoidPtrTy, Loc); - Address TargetElemPtr(TargetElemPtrVal, CopyType, Align); - if (NumIters > 1) - TargetElemPtr = Bld.CreateGEP(CGF, TargetElemPtr, Cnt); - - // *TargetElemPtr = SrcMediumVal; - llvm::Value *SrcMediumValue = - CGF.EmitLoadOfScalar(SrcMediumPtr, /*Volatile=*/true, CType, Loc); - CGF.EmitStoreOfScalar(SrcMediumValue, TargetElemPtr, /*Volatile=*/false, - CType); - Bld.CreateBr(W0MergeBB); - - CGF.EmitBlock(W0ElseBB); - Bld.CreateBr(W0MergeBB); - - CGF.EmitBlock(W0MergeBB); - - if (NumIters > 1) { - Cnt = Bld.CreateNSWAdd(Cnt, llvm::ConstantInt::get(CGM.IntTy, /*V=*/1)); - CGF.EmitStoreOfScalar(Cnt, CntAddr, /*Volatile=*/false, C.IntTy); - CGF.EmitBranch(PrecondBB); - (void)ApplyDebugLocation::CreateEmpty(CGF); - CGF.EmitBlock(ExitBB); - } - RealTySize %= TySize; - } - ++Idx; - } - - CGF.FinishFunction(); - return Fn; -} - -/// Emit a helper that reduces data across two OpenMP threads (lanes) -/// in the same warp. It uses shuffle instructions to copy over data from -/// a remote lane's stack. The reduction algorithm performed is specified -/// by the fourth parameter. -/// -/// Algorithm Versions. -/// Full Warp Reduce (argument value 0): -/// This algorithm assumes that all 32 lanes are active and gathers -/// data from these 32 lanes, producing a single resultant value. -/// Contiguous Partial Warp Reduce (argument value 1): -/// This algorithm assumes that only a *contiguous* subset of lanes -/// are active. This happens for the last warp in a parallel region -/// when the user specified num_threads is not an integer multiple of -/// 32. This contiguous subset always starts with the zeroth lane. -/// Partial Warp Reduce (argument value 2): -/// This algorithm gathers data from any number of lanes at any position. -/// All reduced values are stored in the lowest possible lane. The set -/// of problems every algorithm addresses is a super set of those -/// addressable by algorithms with a lower version number. Overhead -/// increases as algorithm version increases. -/// -/// Terminology -/// Reduce element: -/// Reduce element refers to the individual data field with primitive -/// data types to be combined and reduced across threads. -/// Reduce list: -/// Reduce list refers to a collection of local, thread-private -/// reduce elements. -/// Remote Reduce list: -/// Remote Reduce list refers to a collection of remote (relative to -/// the current thread) reduce elements. -/// -/// We distinguish between three states of threads that are important to -/// the implementation of this function. -/// Alive threads: -/// Threads in a warp executing the SIMT instruction, as distinguished from -/// threads that are inactive due to divergent control flow. -/// Active threads: -/// The minimal set of threads that has to be alive upon entry to this -/// function. The computation is correct iff active threads are alive. -/// Some threads are alive but they are not active because they do not -/// contribute to the computation in any useful manner. Turning them off -/// may introduce control flow overheads without any tangible benefits. -/// Effective threads: -/// In order to comply with the argument requirements of the shuffle -/// function, we must keep all lanes holding data alive. But at most -/// half of them perform value aggregation; we refer to this half of -/// threads as effective. The other half is simply handing off their -/// data. -/// -/// Procedure -/// Value shuffle: -/// In this step active threads transfer data from higher lane positions -/// in the warp to lower lane positions, creating Remote Reduce list. -/// Value aggregation: -/// In this step, effective threads combine their thread local Reduce list -/// with Remote Reduce list and store the result in the thread local -/// Reduce list. -/// Value copy: -/// In this step, we deal with the assumption made by algorithm 2 -/// (i.e. contiguity assumption). When we have an odd number of lanes -/// active, say 2k+1, only k threads will be effective and therefore k -/// new values will be produced. However, the Reduce list owned by the -/// (2k+1)th thread is ignored in the value aggregation. Therefore -/// we copy the Reduce list from the (2k+1)th lane to (k+1)th lane so -/// that the contiguity assumption still holds. -static llvm::Function *emitShuffleAndReduceFunction( - CodeGenModule &CGM, ArrayRef Privates, - QualType ReductionArrayTy, llvm::Function *ReduceFn, SourceLocation Loc) { - ASTContext &C = CGM.getContext(); - - // Thread local Reduce list used to host the values of data to be reduced. - ImplicitParamDecl ReduceListArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, - C.VoidPtrTy, ImplicitParamKind::Other); - // Current lane id; could be logical. - ImplicitParamDecl LaneIDArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, C.ShortTy, - ImplicitParamKind::Other); - // Offset of the remote source lane relative to the current lane. - ImplicitParamDecl RemoteLaneOffsetArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, - C.ShortTy, ImplicitParamKind::Other); - // Algorithm version. This is expected to be known at compile time. - ImplicitParamDecl AlgoVerArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, - C.ShortTy, ImplicitParamKind::Other); - FunctionArgList Args; - Args.push_back(&ReduceListArg); - Args.push_back(&LaneIDArg); - Args.push_back(&RemoteLaneOffsetArg); - Args.push_back(&AlgoVerArg); - - const CGFunctionInfo &CGFI = - CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args); - auto *Fn = llvm::Function::Create( - CGM.getTypes().GetFunctionType(CGFI), llvm::GlobalValue::InternalLinkage, - "_omp_reduction_shuffle_and_reduce_func", &CGM.getModule()); - CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, CGFI); - Fn->setDoesNotRecurse(); - - CodeGenFunction CGF(CGM); - CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args, Loc, Loc); - - CGBuilderTy &Bld = CGF.Builder; - - Address AddrReduceListArg = CGF.GetAddrOfLocalVar(&ReduceListArg); - llvm::Type *ElemTy = CGF.ConvertTypeForMem(ReductionArrayTy); - Address LocalReduceList( - Bld.CreatePointerBitCastOrAddrSpaceCast( - CGF.EmitLoadOfScalar(AddrReduceListArg, /*Volatile=*/false, - C.VoidPtrTy, SourceLocation()), - ElemTy->getPointerTo()), - ElemTy, CGF.getPointerAlign()); - - Address AddrLaneIDArg = CGF.GetAddrOfLocalVar(&LaneIDArg); - llvm::Value *LaneIDArgVal = CGF.EmitLoadOfScalar( - AddrLaneIDArg, /*Volatile=*/false, C.ShortTy, SourceLocation()); - - Address AddrRemoteLaneOffsetArg = CGF.GetAddrOfLocalVar(&RemoteLaneOffsetArg); - llvm::Value *RemoteLaneOffsetArgVal = CGF.EmitLoadOfScalar( - AddrRemoteLaneOffsetArg, /*Volatile=*/false, C.ShortTy, SourceLocation()); - - Address AddrAlgoVerArg = CGF.GetAddrOfLocalVar(&AlgoVerArg); - llvm::Value *AlgoVerArgVal = CGF.EmitLoadOfScalar( - AddrAlgoVerArg, /*Volatile=*/false, C.ShortTy, SourceLocation()); - - // Create a local thread-private variable to host the Reduce list - // from a remote lane. - Address RemoteReduceList = - CGF.CreateMemTemp(ReductionArrayTy, ".omp.reduction.remote_reduce_list"); - - // This loop iterates through the list of reduce elements and copies, - // element by element, from a remote lane in the warp to RemoteReduceList, - // hosted on the thread's stack. - emitReductionListCopy(RemoteLaneToThread, CGF, ReductionArrayTy, Privates, - LocalReduceList, RemoteReduceList, - {/*RemoteLaneOffset=*/RemoteLaneOffsetArgVal, - /*ScratchpadIndex=*/nullptr, - /*ScratchpadWidth=*/nullptr}); - - // The actions to be performed on the Remote Reduce list is dependent - // on the algorithm version. - // - // if (AlgoVer==0) || (AlgoVer==1 && (LaneId < Offset)) || (AlgoVer==2 && - // LaneId % 2 == 0 && Offset > 0): - // do the reduction value aggregation - // - // The thread local variable Reduce list is mutated in place to host the - // reduced data, which is the aggregated value produced from local and - // remote lanes. - // - // Note that AlgoVer is expected to be a constant integer known at compile - // time. - // When AlgoVer==0, the first conjunction evaluates to true, making - // the entire predicate true during compile time. - // When AlgoVer==1, the second conjunction has only the second part to be - // evaluated during runtime. Other conjunctions evaluates to false - // during compile time. - // When AlgoVer==2, the third conjunction has only the second part to be - // evaluated during runtime. Other conjunctions evaluates to false - // during compile time. - llvm::Value *CondAlgo0 = Bld.CreateIsNull(AlgoVerArgVal); - - llvm::Value *Algo1 = Bld.CreateICmpEQ(AlgoVerArgVal, Bld.getInt16(1)); - llvm::Value *CondAlgo1 = Bld.CreateAnd( - Algo1, Bld.CreateICmpULT(LaneIDArgVal, RemoteLaneOffsetArgVal)); - - llvm::Value *Algo2 = Bld.CreateICmpEQ(AlgoVerArgVal, Bld.getInt16(2)); - llvm::Value *CondAlgo2 = Bld.CreateAnd( - Algo2, Bld.CreateIsNull(Bld.CreateAnd(LaneIDArgVal, Bld.getInt16(1)))); - CondAlgo2 = Bld.CreateAnd( - CondAlgo2, Bld.CreateICmpSGT(RemoteLaneOffsetArgVal, Bld.getInt16(0))); - - llvm::Value *CondReduce = Bld.CreateOr(CondAlgo0, CondAlgo1); - CondReduce = Bld.CreateOr(CondReduce, CondAlgo2); - - llvm::BasicBlock *ThenBB = CGF.createBasicBlock("then"); - llvm::BasicBlock *ElseBB = CGF.createBasicBlock("else"); - llvm::BasicBlock *MergeBB = CGF.createBasicBlock("ifcont"); - Bld.CreateCondBr(CondReduce, ThenBB, ElseBB); - - CGF.EmitBlock(ThenBB); - // reduce_function(LocalReduceList, RemoteReduceList) - llvm::Value *LocalReduceListPtr = Bld.CreatePointerBitCastOrAddrSpaceCast( - LocalReduceList.emitRawPointer(CGF), CGF.VoidPtrTy); - llvm::Value *RemoteReduceListPtr = Bld.CreatePointerBitCastOrAddrSpaceCast( - RemoteReduceList.emitRawPointer(CGF), CGF.VoidPtrTy); - CGM.getOpenMPRuntime().emitOutlinedFunctionCall( - CGF, Loc, ReduceFn, {LocalReduceListPtr, RemoteReduceListPtr}); - Bld.CreateBr(MergeBB); - - CGF.EmitBlock(ElseBB); - Bld.CreateBr(MergeBB); - - CGF.EmitBlock(MergeBB); - - // if (AlgoVer==1 && (LaneId >= Offset)) copy Remote Reduce list to local - // Reduce list. - Algo1 = Bld.CreateICmpEQ(AlgoVerArgVal, Bld.getInt16(1)); - llvm::Value *CondCopy = Bld.CreateAnd( - Algo1, Bld.CreateICmpUGE(LaneIDArgVal, RemoteLaneOffsetArgVal)); - - llvm::BasicBlock *CpyThenBB = CGF.createBasicBlock("then"); - llvm::BasicBlock *CpyElseBB = CGF.createBasicBlock("else"); - llvm::BasicBlock *CpyMergeBB = CGF.createBasicBlock("ifcont"); - Bld.CreateCondBr(CondCopy, CpyThenBB, CpyElseBB); - - CGF.EmitBlock(CpyThenBB); - emitReductionListCopy(ThreadCopy, CGF, ReductionArrayTy, Privates, - RemoteReduceList, LocalReduceList); - Bld.CreateBr(CpyMergeBB); - - CGF.EmitBlock(CpyElseBB); - Bld.CreateBr(CpyMergeBB); - - CGF.EmitBlock(CpyMergeBB); - - CGF.FinishFunction(); - return Fn; -} - -/// This function emits a helper that copies all the reduction variables from -/// the team into the provided global buffer for the reduction variables. -/// -/// void list_to_global_copy_func(void *buffer, int Idx, void *reduce_data) -/// For all data entries D in reduce_data: -/// Copy local D to buffer.D[Idx] -static llvm::Value *emitListToGlobalCopyFunction( - CodeGenModule &CGM, ArrayRef Privates, - QualType ReductionArrayTy, SourceLocation Loc, - const RecordDecl *TeamReductionRec, - const llvm::SmallDenseMap - &VarFieldMap) { - ASTContext &C = CGM.getContext(); - - // Buffer: global reduction buffer. - ImplicitParamDecl BufferArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, - C.VoidPtrTy, ImplicitParamKind::Other); - // Idx: index of the buffer. - ImplicitParamDecl IdxArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, C.IntTy, - ImplicitParamKind::Other); - // ReduceList: thread local Reduce list. - ImplicitParamDecl ReduceListArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, - C.VoidPtrTy, ImplicitParamKind::Other); - FunctionArgList Args; - Args.push_back(&BufferArg); - Args.push_back(&IdxArg); - Args.push_back(&ReduceListArg); - - const CGFunctionInfo &CGFI = - CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args); - auto *Fn = llvm::Function::Create( - CGM.getTypes().GetFunctionType(CGFI), llvm::GlobalValue::InternalLinkage, - "_omp_reduction_list_to_global_copy_func", &CGM.getModule()); - CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, CGFI); - Fn->setDoesNotRecurse(); - CodeGenFunction CGF(CGM); - CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args, Loc, Loc); - - CGBuilderTy &Bld = CGF.Builder; - - Address AddrReduceListArg = CGF.GetAddrOfLocalVar(&ReduceListArg); - Address AddrBufferArg = CGF.GetAddrOfLocalVar(&BufferArg); - llvm::Type *ElemTy = CGF.ConvertTypeForMem(ReductionArrayTy); - Address LocalReduceList( - Bld.CreatePointerBitCastOrAddrSpaceCast( - CGF.EmitLoadOfScalar(AddrReduceListArg, /*Volatile=*/false, - C.VoidPtrTy, Loc), - ElemTy->getPointerTo()), - ElemTy, CGF.getPointerAlign()); - QualType StaticTy = C.getRecordType(TeamReductionRec); - llvm::Type *LLVMReductionsBufferTy = - CGM.getTypes().ConvertTypeForMem(StaticTy); - llvm::Value *BufferArrPtr = Bld.CreatePointerBitCastOrAddrSpaceCast( - CGF.EmitLoadOfScalar(AddrBufferArg, /*Volatile=*/false, C.VoidPtrTy, Loc), - LLVMReductionsBufferTy->getPointerTo()); - llvm::Value *Idxs[] = {CGF.EmitLoadOfScalar(CGF.GetAddrOfLocalVar(&IdxArg), - /*Volatile=*/false, C.IntTy, - Loc)}; - unsigned Idx = 0; - for (const Expr *Private : Privates) { - // Reduce element = LocalReduceList[i] - Address ElemPtrPtrAddr = Bld.CreateConstArrayGEP(LocalReduceList, Idx); - llvm::Value *ElemPtrPtr = CGF.EmitLoadOfScalar( - ElemPtrPtrAddr, /*Volatile=*/false, C.VoidPtrTy, SourceLocation()); - // elemptr = ((CopyType*)(elemptrptr)) + I - ElemTy = CGF.ConvertTypeForMem(Private->getType()); - ElemPtrPtr = Bld.CreatePointerBitCastOrAddrSpaceCast( - ElemPtrPtr, ElemTy->getPointerTo()); - Address ElemPtr = - Address(ElemPtrPtr, ElemTy, C.getTypeAlignInChars(Private->getType())); - const ValueDecl *VD = cast(Private)->getDecl(); - // Global = Buffer.VD[Idx]; - const FieldDecl *FD = VarFieldMap.lookup(VD); - llvm::Value *BufferPtr = - Bld.CreateInBoundsGEP(LLVMReductionsBufferTy, BufferArrPtr, Idxs); - LValue GlobLVal = CGF.EmitLValueForField( - CGF.MakeNaturalAlignRawAddrLValue(BufferPtr, StaticTy), FD); - Address GlobAddr = GlobLVal.getAddress(); - GlobLVal.setAddress(Address(GlobAddr.emitRawPointer(CGF), - CGF.ConvertTypeForMem(Private->getType()), - GlobAddr.getAlignment())); - switch (CGF.getEvaluationKind(Private->getType())) { - case TEK_Scalar: { - llvm::Value *V = CGF.EmitLoadOfScalar( - ElemPtr, /*Volatile=*/false, Private->getType(), Loc, - LValueBaseInfo(AlignmentSource::Type), TBAAAccessInfo()); - CGF.EmitStoreOfScalar(V, GlobLVal); - break; - } - case TEK_Complex: { - CodeGenFunction::ComplexPairTy V = CGF.EmitLoadOfComplex( - CGF.MakeAddrLValue(ElemPtr, Private->getType()), Loc); - CGF.EmitStoreOfComplex(V, GlobLVal, /*isInit=*/false); - break; - } - case TEK_Aggregate: - CGF.EmitAggregateCopy(GlobLVal, - CGF.MakeAddrLValue(ElemPtr, Private->getType()), - Private->getType(), AggValueSlot::DoesNotOverlap); - break; - } - ++Idx; - } - - CGF.FinishFunction(); - return Fn; -} - -/// This function emits a helper that reduces all the reduction variables from -/// the team into the provided global buffer for the reduction variables. -/// -/// void list_to_global_reduce_func(void *buffer, int Idx, void *reduce_data) -/// void *GlobPtrs[]; -/// GlobPtrs[0] = (void*)&buffer.D0[Idx]; -/// ... -/// GlobPtrs[N] = (void*)&buffer.DN[Idx]; -/// reduce_function(GlobPtrs, reduce_data); -static llvm::Value *emitListToGlobalReduceFunction( - CodeGenModule &CGM, ArrayRef Privates, - QualType ReductionArrayTy, SourceLocation Loc, - const RecordDecl *TeamReductionRec, - const llvm::SmallDenseMap - &VarFieldMap, - llvm::Function *ReduceFn) { - ASTContext &C = CGM.getContext(); - - // Buffer: global reduction buffer. - ImplicitParamDecl BufferArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, - C.VoidPtrTy, ImplicitParamKind::Other); - // Idx: index of the buffer. - ImplicitParamDecl IdxArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, C.IntTy, - ImplicitParamKind::Other); - // ReduceList: thread local Reduce list. - ImplicitParamDecl ReduceListArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, - C.VoidPtrTy, ImplicitParamKind::Other); - FunctionArgList Args; - Args.push_back(&BufferArg); - Args.push_back(&IdxArg); - Args.push_back(&ReduceListArg); - - const CGFunctionInfo &CGFI = - CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args); - auto *Fn = llvm::Function::Create( - CGM.getTypes().GetFunctionType(CGFI), llvm::GlobalValue::InternalLinkage, - "_omp_reduction_list_to_global_reduce_func", &CGM.getModule()); - CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, CGFI); - Fn->setDoesNotRecurse(); - CodeGenFunction CGF(CGM); - CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args, Loc, Loc); - - CGBuilderTy &Bld = CGF.Builder; - - Address AddrBufferArg = CGF.GetAddrOfLocalVar(&BufferArg); - QualType StaticTy = C.getRecordType(TeamReductionRec); - llvm::Type *LLVMReductionsBufferTy = - CGM.getTypes().ConvertTypeForMem(StaticTy); - llvm::Value *BufferArrPtr = Bld.CreatePointerBitCastOrAddrSpaceCast( - CGF.EmitLoadOfScalar(AddrBufferArg, /*Volatile=*/false, C.VoidPtrTy, Loc), - LLVMReductionsBufferTy->getPointerTo()); - - // 1. Build a list of reduction variables. - // void *RedList[] = {[0], ..., [-1]}; - RawAddress ReductionList = - CGF.CreateMemTemp(ReductionArrayTy, ".omp.reduction.red_list"); - auto IPriv = Privates.begin(); - llvm::Value *Idxs[] = {CGF.EmitLoadOfScalar(CGF.GetAddrOfLocalVar(&IdxArg), - /*Volatile=*/false, C.IntTy, - Loc)}; - unsigned Idx = 0; - for (unsigned I = 0, E = Privates.size(); I < E; ++I, ++IPriv, ++Idx) { - Address Elem = CGF.Builder.CreateConstArrayGEP(ReductionList, Idx); - // Global = Buffer.VD[Idx]; - const ValueDecl *VD = cast(*IPriv)->getDecl(); - const FieldDecl *FD = VarFieldMap.lookup(VD); - llvm::Value *BufferPtr = - Bld.CreateInBoundsGEP(LLVMReductionsBufferTy, BufferArrPtr, Idxs); - LValue GlobLVal = CGF.EmitLValueForField( - CGF.MakeNaturalAlignRawAddrLValue(BufferPtr, StaticTy), FD); - Address GlobAddr = GlobLVal.getAddress(); - CGF.EmitStoreOfScalar(GlobAddr.emitRawPointer(CGF), Elem, - /*Volatile=*/false, C.VoidPtrTy); - if ((*IPriv)->getType()->isVariablyModifiedType()) { - // Store array size. - ++Idx; - Elem = CGF.Builder.CreateConstArrayGEP(ReductionList, Idx); - llvm::Value *Size = CGF.Builder.CreateIntCast( - CGF.getVLASize( - CGF.getContext().getAsVariableArrayType((*IPriv)->getType())) - .NumElts, - CGF.SizeTy, /*isSigned=*/false); - CGF.Builder.CreateStore(CGF.Builder.CreateIntToPtr(Size, CGF.VoidPtrTy), - Elem); - } - } - - // Call reduce_function(GlobalReduceList, ReduceList) - llvm::Value *GlobalReduceList = ReductionList.getPointer(); - Address AddrReduceListArg = CGF.GetAddrOfLocalVar(&ReduceListArg); - llvm::Value *ReducedPtr = CGF.EmitLoadOfScalar( - AddrReduceListArg, /*Volatile=*/false, C.VoidPtrTy, Loc); - CGM.getOpenMPRuntime().emitOutlinedFunctionCall( - CGF, Loc, ReduceFn, {GlobalReduceList, ReducedPtr}); - CGF.FinishFunction(); - return Fn; -} - -/// This function emits a helper that copies all the reduction variables from -/// the team into the provided global buffer for the reduction variables. -/// -/// void list_to_global_copy_func(void *buffer, int Idx, void *reduce_data) -/// For all data entries D in reduce_data: -/// Copy buffer.D[Idx] to local D; -static llvm::Value *emitGlobalToListCopyFunction( - CodeGenModule &CGM, ArrayRef Privates, - QualType ReductionArrayTy, SourceLocation Loc, - const RecordDecl *TeamReductionRec, - const llvm::SmallDenseMap - &VarFieldMap) { - ASTContext &C = CGM.getContext(); - - // Buffer: global reduction buffer. - ImplicitParamDecl BufferArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, - C.VoidPtrTy, ImplicitParamKind::Other); - // Idx: index of the buffer. - ImplicitParamDecl IdxArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, C.IntTy, - ImplicitParamKind::Other); - // ReduceList: thread local Reduce list. - ImplicitParamDecl ReduceListArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, - C.VoidPtrTy, ImplicitParamKind::Other); - FunctionArgList Args; - Args.push_back(&BufferArg); - Args.push_back(&IdxArg); - Args.push_back(&ReduceListArg); - - const CGFunctionInfo &CGFI = - CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args); - auto *Fn = llvm::Function::Create( - CGM.getTypes().GetFunctionType(CGFI), llvm::GlobalValue::InternalLinkage, - "_omp_reduction_global_to_list_copy_func", &CGM.getModule()); - CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, CGFI); - Fn->setDoesNotRecurse(); - CodeGenFunction CGF(CGM); - CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args, Loc, Loc); - - CGBuilderTy &Bld = CGF.Builder; - - Address AddrReduceListArg = CGF.GetAddrOfLocalVar(&ReduceListArg); - Address AddrBufferArg = CGF.GetAddrOfLocalVar(&BufferArg); - llvm::Type *ElemTy = CGF.ConvertTypeForMem(ReductionArrayTy); - Address LocalReduceList( - Bld.CreatePointerBitCastOrAddrSpaceCast( - CGF.EmitLoadOfScalar(AddrReduceListArg, /*Volatile=*/false, - C.VoidPtrTy, Loc), - ElemTy->getPointerTo()), - ElemTy, CGF.getPointerAlign()); - QualType StaticTy = C.getRecordType(TeamReductionRec); - llvm::Type *LLVMReductionsBufferTy = - CGM.getTypes().ConvertTypeForMem(StaticTy); - llvm::Value *BufferArrPtr = Bld.CreatePointerBitCastOrAddrSpaceCast( - CGF.EmitLoadOfScalar(AddrBufferArg, /*Volatile=*/false, C.VoidPtrTy, Loc), - LLVMReductionsBufferTy->getPointerTo()); - - llvm::Value *Idxs[] = {CGF.EmitLoadOfScalar(CGF.GetAddrOfLocalVar(&IdxArg), - /*Volatile=*/false, C.IntTy, - Loc)}; - unsigned Idx = 0; - for (const Expr *Private : Privates) { - // Reduce element = LocalReduceList[i] - Address ElemPtrPtrAddr = Bld.CreateConstArrayGEP(LocalReduceList, Idx); - llvm::Value *ElemPtrPtr = CGF.EmitLoadOfScalar( - ElemPtrPtrAddr, /*Volatile=*/false, C.VoidPtrTy, SourceLocation()); - // elemptr = ((CopyType*)(elemptrptr)) + I - ElemTy = CGF.ConvertTypeForMem(Private->getType()); - ElemPtrPtr = Bld.CreatePointerBitCastOrAddrSpaceCast( - ElemPtrPtr, ElemTy->getPointerTo()); - Address ElemPtr = - Address(ElemPtrPtr, ElemTy, C.getTypeAlignInChars(Private->getType())); - const ValueDecl *VD = cast(Private)->getDecl(); - // Global = Buffer.VD[Idx]; - const FieldDecl *FD = VarFieldMap.lookup(VD); - llvm::Value *BufferPtr = - Bld.CreateInBoundsGEP(LLVMReductionsBufferTy, BufferArrPtr, Idxs); - LValue GlobLVal = CGF.EmitLValueForField( - CGF.MakeNaturalAlignRawAddrLValue(BufferPtr, StaticTy), FD); - Address GlobAddr = GlobLVal.getAddress(); - GlobLVal.setAddress(Address(GlobAddr.emitRawPointer(CGF), - CGF.ConvertTypeForMem(Private->getType()), - GlobAddr.getAlignment())); - switch (CGF.getEvaluationKind(Private->getType())) { - case TEK_Scalar: { - llvm::Value *V = CGF.EmitLoadOfScalar(GlobLVal, Loc); - CGF.EmitStoreOfScalar(V, ElemPtr, /*Volatile=*/false, Private->getType(), - LValueBaseInfo(AlignmentSource::Type), - TBAAAccessInfo()); - break; - } - case TEK_Complex: { - CodeGenFunction::ComplexPairTy V = CGF.EmitLoadOfComplex(GlobLVal, Loc); - CGF.EmitStoreOfComplex(V, CGF.MakeAddrLValue(ElemPtr, Private->getType()), - /*isInit=*/false); - break; - } - case TEK_Aggregate: - CGF.EmitAggregateCopy(CGF.MakeAddrLValue(ElemPtr, Private->getType()), - GlobLVal, Private->getType(), - AggValueSlot::DoesNotOverlap); - break; - } - ++Idx; - } - - CGF.FinishFunction(); - return Fn; -} - -/// This function emits a helper that reduces all the reduction variables from -/// the team into the provided global buffer for the reduction variables. -/// -/// void global_to_list_reduce_func(void *buffer, int Idx, void *reduce_data) -/// void *GlobPtrs[]; -/// GlobPtrs[0] = (void*)&buffer.D0[Idx]; -/// ... -/// GlobPtrs[N] = (void*)&buffer.DN[Idx]; -/// reduce_function(reduce_data, GlobPtrs); -static llvm::Value *emitGlobalToListReduceFunction( - CodeGenModule &CGM, ArrayRef Privates, - QualType ReductionArrayTy, SourceLocation Loc, - const RecordDecl *TeamReductionRec, - const llvm::SmallDenseMap - &VarFieldMap, - llvm::Function *ReduceFn) { - ASTContext &C = CGM.getContext(); - - // Buffer: global reduction buffer. - ImplicitParamDecl BufferArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, - C.VoidPtrTy, ImplicitParamKind::Other); - // Idx: index of the buffer. - ImplicitParamDecl IdxArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, C.IntTy, - ImplicitParamKind::Other); - // ReduceList: thread local Reduce list. - ImplicitParamDecl ReduceListArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, - C.VoidPtrTy, ImplicitParamKind::Other); - FunctionArgList Args; - Args.push_back(&BufferArg); - Args.push_back(&IdxArg); - Args.push_back(&ReduceListArg); - - const CGFunctionInfo &CGFI = - CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args); - auto *Fn = llvm::Function::Create( - CGM.getTypes().GetFunctionType(CGFI), llvm::GlobalValue::InternalLinkage, - "_omp_reduction_global_to_list_reduce_func", &CGM.getModule()); - CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, CGFI); - Fn->setDoesNotRecurse(); - CodeGenFunction CGF(CGM); - CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args, Loc, Loc); - - CGBuilderTy &Bld = CGF.Builder; - - Address AddrBufferArg = CGF.GetAddrOfLocalVar(&BufferArg); - QualType StaticTy = C.getRecordType(TeamReductionRec); - llvm::Type *LLVMReductionsBufferTy = - CGM.getTypes().ConvertTypeForMem(StaticTy); - llvm::Value *BufferArrPtr = Bld.CreatePointerBitCastOrAddrSpaceCast( - CGF.EmitLoadOfScalar(AddrBufferArg, /*Volatile=*/false, C.VoidPtrTy, Loc), - LLVMReductionsBufferTy->getPointerTo()); - - // 1. Build a list of reduction variables. - // void *RedList[] = {[0], ..., [-1]}; - Address ReductionList = - CGF.CreateMemTemp(ReductionArrayTy, ".omp.reduction.red_list"); - auto IPriv = Privates.begin(); - llvm::Value *Idxs[] = {CGF.EmitLoadOfScalar(CGF.GetAddrOfLocalVar(&IdxArg), - /*Volatile=*/false, C.IntTy, - Loc)}; - unsigned Idx = 0; - for (unsigned I = 0, E = Privates.size(); I < E; ++I, ++IPriv, ++Idx) { - Address Elem = CGF.Builder.CreateConstArrayGEP(ReductionList, Idx); - // Global = Buffer.VD[Idx]; - const ValueDecl *VD = cast(*IPriv)->getDecl(); - const FieldDecl *FD = VarFieldMap.lookup(VD); - llvm::Value *BufferPtr = - Bld.CreateInBoundsGEP(LLVMReductionsBufferTy, BufferArrPtr, Idxs); - LValue GlobLVal = CGF.EmitLValueForField( - CGF.MakeNaturalAlignRawAddrLValue(BufferPtr, StaticTy), FD); - Address GlobAddr = GlobLVal.getAddress(); - CGF.EmitStoreOfScalar(GlobAddr.emitRawPointer(CGF), Elem, - /*Volatile=*/false, C.VoidPtrTy); - if ((*IPriv)->getType()->isVariablyModifiedType()) { - // Store array size. - ++Idx; - Elem = CGF.Builder.CreateConstArrayGEP(ReductionList, Idx); - llvm::Value *Size = CGF.Builder.CreateIntCast( - CGF.getVLASize( - CGF.getContext().getAsVariableArrayType((*IPriv)->getType())) - .NumElts, - CGF.SizeTy, /*isSigned=*/false); - CGF.Builder.CreateStore(CGF.Builder.CreateIntToPtr(Size, CGF.VoidPtrTy), - Elem); - } - } - - // Call reduce_function(ReduceList, GlobalReduceList) - llvm::Value *GlobalReduceList = ReductionList.emitRawPointer(CGF); - Address AddrReduceListArg = CGF.GetAddrOfLocalVar(&ReduceListArg); - llvm::Value *ReducedPtr = CGF.EmitLoadOfScalar( - AddrReduceListArg, /*Volatile=*/false, C.VoidPtrTy, Loc); - CGM.getOpenMPRuntime().emitOutlinedFunctionCall( - CGF, Loc, ReduceFn, {ReducedPtr, GlobalReduceList}); - CGF.FinishFunction(); - return Fn; -} - /// /// Design of OpenMP reductions on the GPU /// @@ -2812,21 +1660,20 @@ void CGOpenMPRuntimeGPU::emitReduction( return; bool ParallelReduction = isOpenMPParallelDirective(Options.ReductionKind); -#ifndef NDEBUG + bool DistributeReduction = isOpenMPDistributeDirective(Options.ReductionKind); bool TeamsReduction = isOpenMPTeamsDirective(Options.ReductionKind); -#endif + + ASTContext &C = CGM.getContext(); if (Options.SimpleReduction) { assert(!TeamsReduction && !ParallelReduction && "Invalid reduction selection in emitReduction."); + (void)ParallelReduction; CGOpenMPRuntime::emitReduction(CGF, Loc, Privates, LHSExprs, RHSExprs, ReductionOps, Options); return; } - assert((TeamsReduction || ParallelReduction) && - "Invalid reduction selection in emitReduction."); - llvm::SmallDenseMap VarFieldMap; llvm::SmallVector PrivatesReductions(Privates.size()); int Cnt = 0; @@ -2834,145 +1681,84 @@ void CGOpenMPRuntimeGPU::emitReduction( PrivatesReductions[Cnt] = cast(DRE)->getDecl(); ++Cnt; } - - ASTContext &C = CGM.getContext(); const RecordDecl *ReductionRec = ::buildRecordForGlobalizedVars( CGM.getContext(), PrivatesReductions, std::nullopt, VarFieldMap, 1); - // Build res = __kmpc_reduce{_nowait}(, , sizeof(RedList), - // RedList, shuffle_reduce_func, interwarp_copy_func); - // or - // Build res = __kmpc_reduce_teams_nowait_simple(, , ); - llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc); - - llvm::Value *Res; - // 1. Build a list of reduction variables. - // void *RedList[] = {[0], ..., [-1]}; - auto Size = RHSExprs.size(); - for (const Expr *E : Privates) { - if (E->getType()->isVariablyModifiedType()) - // Reserve place for array size. - ++Size; - } - llvm::APInt ArraySize(/*unsigned int numBits=*/32, Size); - QualType ReductionArrayTy = C.getConstantArrayType( - C.VoidPtrTy, ArraySize, nullptr, ArraySizeModifier::Normal, - /*IndexTypeQuals=*/0); - Address ReductionList = - CGF.CreateMemTemp(ReductionArrayTy, ".omp.reduction.red_list"); - auto IPriv = Privates.begin(); - unsigned Idx = 0; - for (unsigned I = 0, E = RHSExprs.size(); I < E; ++I, ++IPriv, ++Idx) { - Address Elem = CGF.Builder.CreateConstArrayGEP(ReductionList, Idx); - CGF.Builder.CreateStore( - CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( - CGF.EmitLValue(RHSExprs[I]).getPointer(CGF), CGF.VoidPtrTy), - Elem); - if ((*IPriv)->getType()->isVariablyModifiedType()) { - // Store array size. - ++Idx; - Elem = CGF.Builder.CreateConstArrayGEP(ReductionList, Idx); - llvm::Value *Size = CGF.Builder.CreateIntCast( - CGF.getVLASize( - CGF.getContext().getAsVariableArrayType((*IPriv)->getType())) - .NumElts, - CGF.SizeTy, /*isSigned=*/false); - CGF.Builder.CreateStore(CGF.Builder.CreateIntToPtr(Size, CGF.VoidPtrTy), - Elem); - } - } - - llvm::Value *RL = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( - ReductionList.emitRawPointer(CGF), CGF.VoidPtrTy); - llvm::Function *ReductionFn = emitReductionFunction( - CGF.CurFn->getName(), Loc, CGF.ConvertTypeForMem(ReductionArrayTy), - Privates, LHSExprs, RHSExprs, ReductionOps); - llvm::Value *ReductionDataSize = - CGF.getTypeSize(C.getRecordType(ReductionRec)); - ReductionDataSize = - CGF.Builder.CreateSExtOrTrunc(ReductionDataSize, CGF.Int64Ty); - llvm::Function *ShuffleAndReduceFn = emitShuffleAndReduceFunction( - CGM, Privates, ReductionArrayTy, ReductionFn, Loc); - llvm::Value *InterWarpCopyFn = - emitInterWarpCopyFunction(CGM, Privates, ReductionArrayTy, Loc); - - if (ParallelReduction) { - llvm::Value *Args[] = {RTLoc, ReductionDataSize, RL, ShuffleAndReduceFn, - InterWarpCopyFn}; - - Res = CGF.EmitRuntimeCall( - OMPBuilder.getOrCreateRuntimeFunction( - CGM.getModule(), OMPRTL___kmpc_nvptx_parallel_reduce_nowait_v2), - Args); - } else { - assert(TeamsReduction && "expected teams reduction."); + if (TeamsReduction) TeamsReductions.push_back(ReductionRec); - auto *KernelTeamsReductionPtr = CGF.EmitRuntimeCall( - OMPBuilder.getOrCreateRuntimeFunction( - CGM.getModule(), OMPRTL___kmpc_reduction_get_fixed_buffer), - {}, "_openmp_teams_reductions_buffer_$_$ptr"); - llvm::Value *GlobalToBufferCpyFn = ::emitListToGlobalCopyFunction( - CGM, Privates, ReductionArrayTy, Loc, ReductionRec, VarFieldMap); - llvm::Value *GlobalToBufferRedFn = ::emitListToGlobalReduceFunction( - CGM, Privates, ReductionArrayTy, Loc, ReductionRec, VarFieldMap, - ReductionFn); - llvm::Value *BufferToGlobalCpyFn = ::emitGlobalToListCopyFunction( - CGM, Privates, ReductionArrayTy, Loc, ReductionRec, VarFieldMap); - llvm::Value *BufferToGlobalRedFn = ::emitGlobalToListReduceFunction( - CGM, Privates, ReductionArrayTy, Loc, ReductionRec, VarFieldMap, - ReductionFn); - llvm::Value *Args[] = { - RTLoc, - KernelTeamsReductionPtr, - CGF.Builder.getInt32(C.getLangOpts().OpenMPCUDAReductionBufNum), - ReductionDataSize, - RL, - ShuffleAndReduceFn, - InterWarpCopyFn, - GlobalToBufferCpyFn, - GlobalToBufferRedFn, - BufferToGlobalCpyFn, - BufferToGlobalRedFn}; - - Res = CGF.EmitRuntimeCall( - OMPBuilder.getOrCreateRuntimeFunction( - CGM.getModule(), OMPRTL___kmpc_nvptx_teams_reduce_nowait_v2), - Args); - } + // Source location for the ident struct + llvm::Value *RTLoc = emitUpdateLocation(CGF, Loc); - // 5. Build if (res == 1) - llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".omp.reduction.done"); - llvm::BasicBlock *ThenBB = CGF.createBasicBlock(".omp.reduction.then"); - llvm::Value *Cond = CGF.Builder.CreateICmpEQ( - Res, llvm::ConstantInt::get(CGM.Int32Ty, /*V=*/1)); - CGF.Builder.CreateCondBr(Cond, ThenBB, ExitBB); - - // 6. Build then branch: where we have reduced values in the master - // thread in each team. - // __kmpc_end_reduce{_nowait}(); - // break; - CGF.EmitBlock(ThenBB); - - // Add emission of __kmpc_end_reduce{_nowait}(); - auto &&CodeGen = [Privates, LHSExprs, RHSExprs, ReductionOps, - this](CodeGenFunction &CGF, PrePostActionTy &Action) { - auto IPriv = Privates.begin(); - auto ILHS = LHSExprs.begin(); - auto IRHS = RHSExprs.begin(); - for (const Expr *E : ReductionOps) { - emitSingleReductionCombiner(CGF, E, *IPriv, cast(*ILHS), - cast(*IRHS)); - ++IPriv; - ++ILHS; - ++IRHS; + using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy; + InsertPointTy AllocaIP(CGF.AllocaInsertPt->getParent(), + CGF.AllocaInsertPt->getIterator()); + InsertPointTy CodeGenIP(CGF.Builder.GetInsertBlock(), + CGF.Builder.GetInsertPoint()); + llvm::OpenMPIRBuilder::LocationDescription OmpLoc(CodeGenIP); + llvm::SmallVector ReductionInfos; + + CodeGenFunction::OMPPrivateScope Scope(CGF); + unsigned Idx = 0; + for (const Expr *Private : Privates) { + llvm::Type *ElementType; + llvm::Value *Variable; + llvm::Value *PrivateVariable; + llvm::OpenMPIRBuilder::ReductionGenAtomicCBTy AtomicReductionGen = nullptr; + ElementType = CGF.ConvertTypeForMem(Private->getType()); + const auto *RHSVar = + cast(cast(RHSExprs[Idx])->getDecl()); + PrivateVariable = CGF.GetAddrOfLocalVar(RHSVar).emitRawPointer(CGF); + const auto *LHSVar = + cast(cast(LHSExprs[Idx])->getDecl()); + Variable = CGF.GetAddrOfLocalVar(LHSVar).emitRawPointer(CGF); + llvm::OpenMPIRBuilder::EvalKind EvalKind; + switch (CGF.getEvaluationKind(Private->getType())) { + case TEK_Scalar: + EvalKind = llvm::OpenMPIRBuilder::EvalKind::Scalar; + break; + case TEK_Complex: + EvalKind = llvm::OpenMPIRBuilder::EvalKind::Complex; + break; + case TEK_Aggregate: + EvalKind = llvm::OpenMPIRBuilder::EvalKind::Aggregate; + break; } - }; - RegionCodeGenTy RCG(CodeGen); - RCG(CGF); - // There is no need to emit line number for unconditional branch. - (void)ApplyDebugLocation::CreateEmpty(CGF); - CGF.EmitBlock(ExitBB, /*IsFinished=*/true); + auto ReductionGen = [&](InsertPointTy CodeGenIP, unsigned I, + llvm::Value **LHSPtr, llvm::Value **RHSPtr, + llvm::Function *NewFunc) { + CGF.Builder.restoreIP(CodeGenIP); + auto *CurFn = CGF.CurFn; + CGF.CurFn = NewFunc; + + *LHSPtr = CGF.GetAddrOfLocalVar( + cast(cast(LHSExprs[I])->getDecl())) + .emitRawPointer(CGF); + *RHSPtr = CGF.GetAddrOfLocalVar( + cast(cast(RHSExprs[I])->getDecl())) + .emitRawPointer(CGF); + + emitSingleReductionCombiner(CGF, ReductionOps[I], Privates[I], + cast(LHSExprs[I]), + cast(RHSExprs[I])); + + CGF.CurFn = CurFn; + + return InsertPointTy(CGF.Builder.GetInsertBlock(), + CGF.Builder.GetInsertPoint()); + }; + ReductionInfos.emplace_back(llvm::OpenMPIRBuilder::ReductionInfo( + ElementType, Variable, PrivateVariable, EvalKind, + /*ReductionGen=*/nullptr, ReductionGen, AtomicReductionGen)); + Idx++; + } + + CGF.Builder.restoreIP(OMPBuilder.createReductionsGPU( + OmpLoc, AllocaIP, CodeGenIP, ReductionInfos, false, TeamsReduction, + DistributeReduction, llvm::OpenMPIRBuilder::ReductionGenCBKind::Clang, + CGF.getTarget().getGridValue(), C.getLangOpts().OpenMPCUDAReductionBufNum, + RTLoc)); + return; } const VarDecl * @@ -3441,112 +2227,112 @@ bool CGOpenMPRuntimeGPU::hasAllocateAttributeForGlobalVar(const VarDecl *VD, return false; } -// Get current CudaArch and ignore any unknown values -static CudaArch getCudaArch(CodeGenModule &CGM) { +// Get current OffloadArch and ignore any unknown values +static OffloadArch getOffloadArch(CodeGenModule &CGM) { if (!CGM.getTarget().hasFeature("ptx")) - return CudaArch::UNKNOWN; + return OffloadArch::UNKNOWN; for (const auto &Feature : CGM.getTarget().getTargetOpts().FeatureMap) { if (Feature.getValue()) { - CudaArch Arch = StringToCudaArch(Feature.getKey()); - if (Arch != CudaArch::UNKNOWN) + OffloadArch Arch = StringToOffloadArch(Feature.getKey()); + if (Arch != OffloadArch::UNKNOWN) return Arch; } } - return CudaArch::UNKNOWN; + return OffloadArch::UNKNOWN; } /// Check to see if target architecture supports unified addressing which is /// a restriction for OpenMP requires clause "unified_shared_memory". -void CGOpenMPRuntimeGPU::processRequiresDirective( - const OMPRequiresDecl *D) { +void CGOpenMPRuntimeGPU::processRequiresDirective(const OMPRequiresDecl *D) { for (const OMPClause *Clause : D->clauselists()) { if (Clause->getClauseKind() == OMPC_unified_shared_memory) { - CudaArch Arch = getCudaArch(CGM); + OffloadArch Arch = getOffloadArch(CGM); switch (Arch) { - case CudaArch::SM_20: - case CudaArch::SM_21: - case CudaArch::SM_30: - case CudaArch::SM_32_: - case CudaArch::SM_35: - case CudaArch::SM_37: - case CudaArch::SM_50: - case CudaArch::SM_52: - case CudaArch::SM_53: { + case OffloadArch::SM_20: + case OffloadArch::SM_21: + case OffloadArch::SM_30: + case OffloadArch::SM_32_: + case OffloadArch::SM_35: + case OffloadArch::SM_37: + case OffloadArch::SM_50: + case OffloadArch::SM_52: + case OffloadArch::SM_53: { SmallString<256> Buffer; llvm::raw_svector_ostream Out(Buffer); - Out << "Target architecture " << CudaArchToString(Arch) + Out << "Target architecture " << OffloadArchToString(Arch) << " does not support unified addressing"; CGM.Error(Clause->getBeginLoc(), Out.str()); return; } - case CudaArch::SM_60: - case CudaArch::SM_61: - case CudaArch::SM_62: - case CudaArch::SM_70: - case CudaArch::SM_72: - case CudaArch::SM_75: - case CudaArch::SM_80: - case CudaArch::SM_86: - case CudaArch::SM_87: - case CudaArch::SM_89: - case CudaArch::SM_90: - case CudaArch::SM_90a: - case CudaArch::GFX600: - case CudaArch::GFX601: - case CudaArch::GFX602: - case CudaArch::GFX700: - case CudaArch::GFX701: - case CudaArch::GFX702: - case CudaArch::GFX703: - case CudaArch::GFX704: - case CudaArch::GFX705: - case CudaArch::GFX801: - case CudaArch::GFX802: - case CudaArch::GFX803: - case CudaArch::GFX805: - case CudaArch::GFX810: - case CudaArch::GFX9_GENERIC: - case CudaArch::GFX900: - case CudaArch::GFX902: - case CudaArch::GFX904: - case CudaArch::GFX906: - case CudaArch::GFX908: - case CudaArch::GFX909: - case CudaArch::GFX90a: - case CudaArch::GFX90c: - case CudaArch::GFX940: - case CudaArch::GFX941: - case CudaArch::GFX942: - case CudaArch::GFX10_1_GENERIC: - case CudaArch::GFX1010: - case CudaArch::GFX1011: - case CudaArch::GFX1012: - case CudaArch::GFX1013: - case CudaArch::GFX10_3_GENERIC: - case CudaArch::GFX1030: - case CudaArch::GFX1031: - case CudaArch::GFX1032: - case CudaArch::GFX1033: - case CudaArch::GFX1034: - case CudaArch::GFX1035: - case CudaArch::GFX1036: - case CudaArch::GFX11_GENERIC: - case CudaArch::GFX1100: - case CudaArch::GFX1101: - case CudaArch::GFX1102: - case CudaArch::GFX1103: - case CudaArch::GFX1150: - case CudaArch::GFX1151: - case CudaArch::GFX1152: - case CudaArch::GFX12_GENERIC: - case CudaArch::GFX1200: - case CudaArch::GFX1201: - case CudaArch::Generic: - case CudaArch::UNUSED: - case CudaArch::UNKNOWN: + case OffloadArch::SM_60: + case OffloadArch::SM_61: + case OffloadArch::SM_62: + case OffloadArch::SM_70: + case OffloadArch::SM_72: + case OffloadArch::SM_75: + case OffloadArch::SM_80: + case OffloadArch::SM_86: + case OffloadArch::SM_87: + case OffloadArch::SM_89: + case OffloadArch::SM_90: + case OffloadArch::SM_90a: + case OffloadArch::GFX600: + case OffloadArch::GFX601: + case OffloadArch::GFX602: + case OffloadArch::GFX700: + case OffloadArch::GFX701: + case OffloadArch::GFX702: + case OffloadArch::GFX703: + case OffloadArch::GFX704: + case OffloadArch::GFX705: + case OffloadArch::GFX801: + case OffloadArch::GFX802: + case OffloadArch::GFX803: + case OffloadArch::GFX805: + case OffloadArch::GFX810: + case OffloadArch::GFX9_GENERIC: + case OffloadArch::GFX900: + case OffloadArch::GFX902: + case OffloadArch::GFX904: + case OffloadArch::GFX906: + case OffloadArch::GFX908: + case OffloadArch::GFX909: + case OffloadArch::GFX90a: + case OffloadArch::GFX90c: + case OffloadArch::GFX940: + case OffloadArch::GFX941: + case OffloadArch::GFX942: + case OffloadArch::GFX10_1_GENERIC: + case OffloadArch::GFX1010: + case OffloadArch::GFX1011: + case OffloadArch::GFX1012: + case OffloadArch::GFX1013: + case OffloadArch::GFX10_3_GENERIC: + case OffloadArch::GFX1030: + case OffloadArch::GFX1031: + case OffloadArch::GFX1032: + case OffloadArch::GFX1033: + case OffloadArch::GFX1034: + case OffloadArch::GFX1035: + case OffloadArch::GFX1036: + case OffloadArch::GFX11_GENERIC: + case OffloadArch::GFX1100: + case OffloadArch::GFX1101: + case OffloadArch::GFX1102: + case OffloadArch::GFX1103: + case OffloadArch::GFX1150: + case OffloadArch::GFX1151: + case OffloadArch::GFX1152: + case OffloadArch::GFX12_GENERIC: + case OffloadArch::GFX1200: + case OffloadArch::GFX1201: + case OffloadArch::AMDGCNSPIRV: + case OffloadArch::Generic: + case OffloadArch::UNUSED: + case OffloadArch::UNKNOWN: break; - case CudaArch::LAST: - llvm_unreachable("Unexpected Cuda arch."); + case OffloadArch::LAST: + llvm_unreachable("Unexpected GPU arch."); } } } @@ -3573,10 +2359,3 @@ llvm::Value *CGOpenMPRuntimeGPU::getGPUThreadID(CodeGenFunction &CGF) { CGM.getModule(), OMPRTL___kmpc_get_hardware_thread_id_in_block), Args); } - -llvm::Value *CGOpenMPRuntimeGPU::getGPUWarpSize(CodeGenFunction &CGF) { - ArrayRef Args{}; - return CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction( - CGM.getModule(), OMPRTL___kmpc_get_warp_size), - Args); -} diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h index 141436f26230dd..4d586ec972f8d6 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h +++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h @@ -150,9 +150,6 @@ class CGOpenMPRuntimeGPU : public CGOpenMPRuntime { CodeGenFunction &CGF, const std::pair &AddrSizePair) override; - /// Get the GPU warp size. - llvm::Value *getGPUWarpSize(CodeGenFunction &CGF); - /// Get the id of the current thread on the GPU. llvm::Value *getGPUThreadID(CodeGenFunction &CGF); diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp index f0819b04674898..673f6e60bfc317 100644 --- a/clang/lib/CodeGen/CGPointerAuth.cpp +++ b/clang/lib/CodeGen/CGPointerAuth.cpp @@ -11,12 +11,56 @@ // //===----------------------------------------------------------------------===// +#include "CodeGenFunction.h" #include "CodeGenModule.h" #include "clang/CodeGen/CodeGenABITypes.h" +#include "clang/CodeGen/ConstantInitBuilder.h" +#include "llvm/Support/SipHash.h" using namespace clang; using namespace CodeGen; +/// Given a pointer-authentication schema, return a concrete "other" +/// discriminator for it. +llvm::ConstantInt *CodeGenModule::getPointerAuthOtherDiscriminator( + const PointerAuthSchema &Schema, GlobalDecl Decl, QualType Type) { + switch (Schema.getOtherDiscrimination()) { + case PointerAuthSchema::Discrimination::None: + return nullptr; + + case PointerAuthSchema::Discrimination::Type: + llvm_unreachable("type discrimination not implemented yet"); + + case PointerAuthSchema::Discrimination::Decl: + assert(Decl.getDecl() && + "declaration not provided for decl-discriminated schema"); + return llvm::ConstantInt::get(IntPtrTy, + getPointerAuthDeclDiscriminator(Decl)); + + case PointerAuthSchema::Discrimination::Constant: + return llvm::ConstantInt::get(IntPtrTy, Schema.getConstantDiscrimination()); + } + llvm_unreachable("bad discrimination kind"); +} + +uint16_t CodeGen::getPointerAuthDeclDiscriminator(CodeGenModule &CGM, + GlobalDecl Declaration) { + return CGM.getPointerAuthDeclDiscriminator(Declaration); +} + +/// Return the "other" decl-specific discriminator for the given decl. +uint16_t +CodeGenModule::getPointerAuthDeclDiscriminator(GlobalDecl Declaration) { + uint16_t &EntityHash = PtrAuthDiscriminatorHashes[Declaration]; + + if (EntityHash == 0) { + StringRef Name = getMangledName(Declaration); + EntityHash = llvm::getPointerAuthStableSipHash(Name); + } + + return EntityHash; +} + /// Return the abstract pointer authentication schema for a pointer to the given /// function type. CGPointerAuthInfo CodeGenModule::getFunctionPointerAuthInfo(QualType T) { @@ -35,6 +79,41 @@ CGPointerAuthInfo CodeGenModule::getFunctionPointerAuthInfo(QualType T) { /*Discriminator=*/nullptr); } +llvm::Value * +CodeGenFunction::EmitPointerAuthBlendDiscriminator(llvm::Value *StorageAddress, + llvm::Value *Discriminator) { + StorageAddress = Builder.CreatePtrToInt(StorageAddress, IntPtrTy); + auto Intrinsic = CGM.getIntrinsic(llvm::Intrinsic::ptrauth_blend); + return Builder.CreateCall(Intrinsic, {StorageAddress, Discriminator}); +} + +/// Emit the concrete pointer authentication informaton for the +/// given authentication schema. +CGPointerAuthInfo CodeGenFunction::EmitPointerAuthInfo( + const PointerAuthSchema &Schema, llvm::Value *StorageAddress, + GlobalDecl SchemaDecl, QualType SchemaType) { + if (!Schema) + return CGPointerAuthInfo(); + + llvm::Value *Discriminator = + CGM.getPointerAuthOtherDiscriminator(Schema, SchemaDecl, SchemaType); + + if (Schema.isAddressDiscriminated()) { + assert(StorageAddress && + "address not provided for address-discriminated schema"); + + if (Discriminator) + Discriminator = + EmitPointerAuthBlendDiscriminator(StorageAddress, Discriminator); + else + Discriminator = Builder.CreatePtrToInt(StorageAddress, IntPtrTy); + } + + return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(), + Schema.isIsaPointer(), + Schema.authenticatesNullValues(), Discriminator); +} + llvm::Constant * CodeGenModule::getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key, llvm::Constant *StorageAddress, @@ -60,6 +139,29 @@ CodeGenModule::getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key, IntegerDiscriminator, AddressDiscriminator); } +/// Does a given PointerAuthScheme require us to sign a value +bool CodeGenModule::shouldSignPointer(const PointerAuthSchema &Schema) { + auto AuthenticationMode = Schema.getAuthenticationMode(); + return AuthenticationMode == PointerAuthenticationMode::SignAndStrip || + AuthenticationMode == PointerAuthenticationMode::SignAndAuth; +} + +/// Sign a constant pointer using the given scheme, producing a constant +/// with the same IR type. +llvm::Constant *CodeGenModule::getConstantSignedPointer( + llvm::Constant *Pointer, const PointerAuthSchema &Schema, + llvm::Constant *StorageAddress, GlobalDecl SchemaDecl, + QualType SchemaType) { + assert(shouldSignPointer(Schema)); + llvm::ConstantInt *OtherDiscriminator = + getPointerAuthOtherDiscriminator(Schema, SchemaDecl, SchemaType); + + return getConstantSignedPointer(Pointer, Schema.getKey(), StorageAddress, + OtherDiscriminator); +} + +/// If applicable, sign a given constant function pointer with the ABI rules for +/// functionType. llvm::Constant *CodeGenModule::getFunctionPointer(llvm::Constant *Pointer, QualType FunctionType) { assert(FunctionType->isFunctionType() || @@ -80,3 +182,113 @@ llvm::Constant *CodeGenModule::getFunctionPointer(GlobalDecl GD, QualType FuncType = FD->getType(); return getFunctionPointer(getRawFunctionPointer(GD, Ty), FuncType); } + +std::optional +CodeGenModule::computeVTPointerAuthentication(const CXXRecordDecl *ThisClass) { + auto DefaultAuthentication = getCodeGenOpts().PointerAuth.CXXVTablePointers; + if (!DefaultAuthentication) + return std::nullopt; + const CXXRecordDecl *PrimaryBase = + Context.baseForVTableAuthentication(ThisClass); + + unsigned Key = DefaultAuthentication.getKey(); + bool AddressDiscriminated = DefaultAuthentication.isAddressDiscriminated(); + auto DefaultDiscrimination = DefaultAuthentication.getOtherDiscrimination(); + unsigned TypeBasedDiscriminator = + Context.getPointerAuthVTablePointerDiscriminator(PrimaryBase); + unsigned Discriminator; + if (DefaultDiscrimination == PointerAuthSchema::Discrimination::Type) { + Discriminator = TypeBasedDiscriminator; + } else if (DefaultDiscrimination == + PointerAuthSchema::Discrimination::Constant) { + Discriminator = DefaultAuthentication.getConstantDiscrimination(); + } else { + assert(DefaultDiscrimination == PointerAuthSchema::Discrimination::None); + Discriminator = 0; + } + if (auto ExplicitAuthentication = + PrimaryBase->getAttr()) { + auto ExplicitAddressDiscrimination = + ExplicitAuthentication->getAddressDiscrimination(); + auto ExplicitDiscriminator = + ExplicitAuthentication->getExtraDiscrimination(); + + unsigned ExplicitKey = ExplicitAuthentication->getKey(); + if (ExplicitKey == VTablePointerAuthenticationAttr::NoKey) + return std::nullopt; + + if (ExplicitKey != VTablePointerAuthenticationAttr::DefaultKey) { + if (ExplicitKey == VTablePointerAuthenticationAttr::ProcessIndependent) + Key = (unsigned)PointerAuthSchema::ARM8_3Key::ASDA; + else { + assert(ExplicitKey == + VTablePointerAuthenticationAttr::ProcessDependent); + Key = (unsigned)PointerAuthSchema::ARM8_3Key::ASDB; + } + } + + if (ExplicitAddressDiscrimination != + VTablePointerAuthenticationAttr::DefaultAddressDiscrimination) + AddressDiscriminated = + ExplicitAddressDiscrimination == + VTablePointerAuthenticationAttr::AddressDiscrimination; + + if (ExplicitDiscriminator == + VTablePointerAuthenticationAttr::TypeDiscrimination) + Discriminator = TypeBasedDiscriminator; + else if (ExplicitDiscriminator == + VTablePointerAuthenticationAttr::CustomDiscrimination) + Discriminator = ExplicitAuthentication->getCustomDiscriminationValue(); + else if (ExplicitDiscriminator == + VTablePointerAuthenticationAttr::NoExtraDiscrimination) + Discriminator = 0; + } + return PointerAuthQualifier::Create(Key, AddressDiscriminated, Discriminator, + PointerAuthenticationMode::SignAndAuth, + /* IsIsaPointer */ false, + /* AuthenticatesNullValues */ false); +} + +std::optional +CodeGenModule::getVTablePointerAuthentication(const CXXRecordDecl *Record) { + if (!Record->getDefinition() || !Record->isPolymorphic()) + return std::nullopt; + + auto Existing = VTablePtrAuthInfos.find(Record); + std::optional Authentication; + if (Existing != VTablePtrAuthInfos.end()) { + Authentication = Existing->getSecond(); + } else { + Authentication = computeVTPointerAuthentication(Record); + VTablePtrAuthInfos.insert(std::make_pair(Record, Authentication)); + } + return Authentication; +} + +std::optional +CodeGenModule::getVTablePointerAuthInfo(CodeGenFunction *CGF, + const CXXRecordDecl *Record, + llvm::Value *StorageAddress) { + auto Authentication = getVTablePointerAuthentication(Record); + if (!Authentication) + return std::nullopt; + + llvm::Value *Discriminator = nullptr; + if (auto ExtraDiscriminator = Authentication->getExtraDiscriminator()) + Discriminator = llvm::ConstantInt::get(IntPtrTy, ExtraDiscriminator); + + if (Authentication->isAddressDiscriminated()) { + assert(StorageAddress && + "address not provided for address-discriminated schema"); + if (Discriminator) + Discriminator = + CGF->EmitPointerAuthBlendDiscriminator(StorageAddress, Discriminator); + else + Discriminator = CGF->Builder.CreatePtrToInt(StorageAddress, IntPtrTy); + } + + return CGPointerAuthInfo(Authentication->getKey(), + PointerAuthenticationMode::SignAndAuth, + /* IsIsaPointer */ false, + /* AuthenticatesNullValues */ false, Discriminator); +} diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index f73d32de7c4848..43cf4dc630cd77 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -193,7 +193,7 @@ class OMPLoopScope : public CodeGenFunction::RunCleanupsScope { if (PreInits) { // CompoundStmts and DeclStmts are used as lists of PreInit statements and // declarations. Since declarations must be visible in the the following - // that they initialize, unpack the ComboundStmt they are nested in. + // that they initialize, unpack the CompoundStmt they are nested in. SmallVector PreInitStmts; if (auto *PreInitCompound = dyn_cast(PreInits)) llvm::append_range(PreInitStmts, PreInitCompound->body()); @@ -1411,7 +1411,7 @@ void CodeGenFunction::EmitOMPReductionClauseInit( case OMPD_end_declare_variant: case OMPD_unknown: default: - llvm_unreachable("Enexpected directive with task reductions."); + llvm_unreachable("Unexpected directive with task reductions."); } const auto *VD = cast(cast(TaskRedRef)->getDecl()); @@ -1766,7 +1766,7 @@ void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) { using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy; - // The cleanup callback that finalizes all variabels at the given location, + // The cleanup callback that finalizes all variables at the given location, // thus calls destructors etc. auto FiniCB = [this](InsertPointTy IP) { OMPBuilderCBHelpers::FinalizeOMPRegion(*this, IP); @@ -6506,7 +6506,7 @@ static void emitOMPAtomicCompareExpr( } if (FailAO == llvm::AtomicOrdering::NotAtomic) { - // fail clause was not mentionend on the + // fail clause was not mentioned on the // "#pragma omp atomic compare" construct. CGF.Builder.restoreIP(OMPBuilder.createAtomicCompare( CGF.Builder, XOpVal, VOpVal, ROpVal, EVal, DVal, AO, Op, IsXBinopExpr, @@ -7920,7 +7920,7 @@ void CodeGenFunction::EmitOMPGenericLoopDirective( void CodeGenFunction::EmitOMPParallelGenericLoopDirective( const OMPLoopDirective &S) { - // Emit combined directive as if its consituent constructs are 'parallel' + // Emit combined directive as if its constituent constructs are 'parallel' // and 'for'. auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { Action.Enter(CGF); diff --git a/clang/lib/CodeGen/CGVTT.cpp b/clang/lib/CodeGen/CGVTT.cpp index 4cebb750c89e8f..20bd2c2fc2c642 100644 --- a/clang/lib/CodeGen/CGVTT.cpp +++ b/clang/lib/CodeGen/CGVTT.cpp @@ -90,6 +90,11 @@ CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT, llvm::Constant *Init = llvm::ConstantExpr::getGetElementPtr( VTable->getValueType(), VTable, Idxs, /*InBounds=*/true, InRange); + if (const auto &Schema = + CGM.getCodeGenOpts().PointerAuth.CXXVTTVTablePointers) + Init = CGM.getConstantSignedPointer(Init, Schema, nullptr, GlobalDecl(), + QualType()); + VTTComponents.push_back(Init); } diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp index 55c3032dc9332c..3e88cd73e8c1f4 100644 --- a/clang/lib/CodeGen/CGVTables.cpp +++ b/clang/lib/CodeGen/CGVTables.cpp @@ -95,7 +95,7 @@ static RValue PerformReturnAdjustment(CodeGenFunction &CGF, CGF, Address(ReturnValue, CGF.ConvertTypeForMem(ResultType->getPointeeType()), ClassAlign), - Thunk.Return); + ClassDecl, Thunk.Return); if (NullCheckValue) { CGF.Builder.CreateBr(AdjustEnd); @@ -219,8 +219,10 @@ CodeGenFunction::GenerateVarArgsThunk(llvm::Function *Fn, "Store of this should be in entry block?"); // Adjust "this", if necessary. Builder.SetInsertPoint(&*ThisStore); - llvm::Value *AdjustedThisPtr = - CGM.getCXXABI().performThisAdjustment(*this, ThisPtr, Thunk.This); + + const CXXRecordDecl *ThisValueClass = Thunk.ThisType->getPointeeCXXRecordDecl(); + llvm::Value *AdjustedThisPtr = CGM.getCXXABI().performThisAdjustment( + *this, ThisPtr, ThisValueClass, Thunk); AdjustedThisPtr = Builder.CreateBitCast(AdjustedThisPtr, ThisStore->getOperand(0)->getType()); ThisStore->setOperand(0, AdjustedThisPtr); @@ -307,10 +309,15 @@ void CodeGenFunction::EmitCallAndReturnForThunk(llvm::FunctionCallee Callee, const CXXMethodDecl *MD = cast(CurGD.getDecl()); // Adjust the 'this' pointer if necessary + const CXXRecordDecl *ThisValueClass = + MD->getThisType()->getPointeeCXXRecordDecl(); + if (Thunk) + ThisValueClass = Thunk->ThisType->getPointeeCXXRecordDecl(); + llvm::Value *AdjustedThisPtr = - Thunk ? CGM.getCXXABI().performThisAdjustment( - *this, LoadCXXThisAddress(), Thunk->This) - : LoadCXXThis(); + Thunk ? CGM.getCXXABI().performThisAdjustment(*this, LoadCXXThisAddress(), + ThisValueClass, *Thunk) + : LoadCXXThis(); // If perfect forwarding is required a variadic method, a method using // inalloca, or an unprototyped thunk, use musttail. Emit an error if this @@ -504,10 +511,22 @@ llvm::Constant *CodeGenVTables::maybeEmitThunk(GlobalDecl GD, SmallString<256> Name; MangleContext &MCtx = CGM.getCXXABI().getMangleContext(); llvm::raw_svector_ostream Out(Name); - if (const CXXDestructorDecl *DD = dyn_cast(MD)) - MCtx.mangleCXXDtorThunk(DD, GD.getDtorType(), TI.This, Out); - else - MCtx.mangleThunk(MD, TI, Out); + + if (const CXXDestructorDecl *DD = dyn_cast(MD)) { + MCtx.mangleCXXDtorThunk(DD, GD.getDtorType(), TI, + /* elideOverrideInfo */ false, Out); + } else + MCtx.mangleThunk(MD, TI, /* elideOverrideInfo */ false, Out); + + if (CGM.getContext().useAbbreviatedThunkName(GD, Name.str())) { + Name = ""; + if (const CXXDestructorDecl *DD = dyn_cast(MD)) + MCtx.mangleCXXDtorThunk(DD, GD.getDtorType(), TI, + /* elideOverrideInfo */ true, Out); + else + MCtx.mangleThunk(MD, TI, /* elideOverrideInfo */ true, Out); + } + llvm::Type *ThunkVTableTy = CGM.getTypes().GetFunctionTypeForVTable(GD); llvm::Constant *Thunk = CGM.GetAddrOfThunk(Name, ThunkVTableTy, GD); @@ -819,11 +838,17 @@ void CodeGenVTables::addVTableComponent(ConstantArrayBuilder &builder, nextVTableThunkIndex++; fnPtr = maybeEmitThunk(GD, thunkInfo, /*ForVTable=*/true); + if (CGM.getCodeGenOpts().PointerAuth.CXXVirtualFunctionPointers) { + assert(thunkInfo.Method && "Method not set"); + GD = GD.getWithDecl(thunkInfo.Method); + } // Otherwise we can use the method definition directly. } else { llvm::Type *fnTy = CGM.getTypes().GetFunctionTypeForVTable(GD); fnPtr = CGM.GetAddrOfFunction(GD, fnTy, /*ForVTable=*/true); + if (CGM.getCodeGenOpts().PointerAuth.CXXVirtualFunctionPointers) + GD = getItaniumVTableContext().findOriginalMethod(GD); } if (useRelativeLayout()) { @@ -841,6 +866,9 @@ void CodeGenVTables::addVTableComponent(ConstantArrayBuilder &builder, if (FnAS != GVAS) fnPtr = llvm::ConstantExpr::getAddrSpaceCast(fnPtr, CGM.GlobalsInt8PtrTy); + if (const auto &Schema = + CGM.getCodeGenOpts().PointerAuth.CXXVirtualFunctionPointers) + return builder.addSignedPointer(fnPtr, Schema, GD, QualType()); return builder.add(fnPtr); } } diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt index 8dd9d8b54c25fa..2a179deddcc314 100644 --- a/clang/lib/CodeGen/CMakeLists.txt +++ b/clang/lib/CodeGen/CMakeLists.txt @@ -39,6 +39,7 @@ set(LLVM_LINK_COMPONENTS # our goal is to disable the /Og flag while retaining the other optimizations from the /O1|/O2 set if(MSVC AND NOT CMAKE_CXX_COMPILER_ID MATCHES Clang AND MSVC_VERSION VERSION_GREATER_EQUAL 1932 + AND MSVC_VERSION VERSION_LESS 1939 AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64") string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE) diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index 6d3efdb5ffe34e..0b92c5318a5c23 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -226,16 +226,11 @@ void BackendConsumer::HandleInterestingDecl(DeclGroupRef D) { HandleTopLevelDecl(D); } -// Links each entry in LinkModules into our module. Returns true on error. -bool BackendConsumer::LinkInModules(llvm::Module *M, bool ShouldLinkFiles) { +// Links each entry in LinkModules into our module. Returns true on error. +bool BackendConsumer::LinkInModules(llvm::Module *M) { for (auto &LM : LinkModules) { assert(LM.Module && "LinkModule does not actually have a module"); - // If ShouldLinkFiles is not set, skip files added via the - // -mlink-bitcode-files, only linking -mlink-builtin-bitcode - if (!LM.Internalize && !ShouldLinkFiles) - continue; - if (LM.PropagateAttrs) for (Function &F : *LM.Module) { // Skip intrinsics. Keep consistent with how intrinsics are created @@ -299,6 +294,9 @@ void BackendConsumer::HandleTranslationUnit(ASTContext &C) { Ctx.setDiagnosticHandler(std::make_unique( CodeGenOpts, this)); + Ctx.setDefaultTargetCPU(TargetOpts.CPU); + Ctx.setDefaultTargetFeatures(llvm::join(TargetOpts.Features, ",")); + Expected> OptRecordFileOrErr = setupLLVMOptimizationRemarks( Ctx, CodeGenOpts.OptRecordFile, CodeGenOpts.OptRecordPasses, @@ -1205,6 +1203,9 @@ void CodeGenAction::ExecuteAction() { Ctx.setDiagnosticHandler( std::make_unique(CodeGenOpts, &Result)); + Ctx.setDefaultTargetCPU(TargetOpts.CPU); + Ctx.setDefaultTargetFeatures(llvm::join(TargetOpts.Features, ",")); + Expected> OptRecordFileOrErr = setupLLVMOptimizationRemarks( Ctx, CodeGenOpts.OptRecordFile, CodeGenOpts.OptRecordPasses, diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 650c5662539f9f..26deeca95d326c 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -3063,3 +3063,66 @@ void CodeGenFunction::EmitPointerAuthOperandBundle( llvm::Value *Args[] = {Key, Discriminator}; Bundles.emplace_back("ptrauth", Args); } + +static llvm::Value *EmitPointerAuthCommon(CodeGenFunction &CGF, + const CGPointerAuthInfo &PointerAuth, + llvm::Value *Pointer, + unsigned IntrinsicID) { + if (!PointerAuth) + return Pointer; + + auto Key = CGF.Builder.getInt32(PointerAuth.getKey()); + + llvm::Value *Discriminator = PointerAuth.getDiscriminator(); + if (!Discriminator) { + Discriminator = CGF.Builder.getSize(0); + } + + // Convert the pointer to intptr_t before signing it. + auto OrigType = Pointer->getType(); + Pointer = CGF.Builder.CreatePtrToInt(Pointer, CGF.IntPtrTy); + + // call i64 @llvm.ptrauth.sign.i64(i64 %pointer, i32 %key, i64 %discriminator) + auto Intrinsic = CGF.CGM.getIntrinsic(IntrinsicID); + Pointer = CGF.EmitRuntimeCall(Intrinsic, {Pointer, Key, Discriminator}); + + // Convert back to the original type. + Pointer = CGF.Builder.CreateIntToPtr(Pointer, OrigType); + return Pointer; +} + +llvm::Value * +CodeGenFunction::EmitPointerAuthSign(const CGPointerAuthInfo &PointerAuth, + llvm::Value *Pointer) { + if (!PointerAuth.shouldSign()) + return Pointer; + return EmitPointerAuthCommon(*this, PointerAuth, Pointer, + llvm::Intrinsic::ptrauth_sign); +} + +static llvm::Value *EmitStrip(CodeGenFunction &CGF, + const CGPointerAuthInfo &PointerAuth, + llvm::Value *Pointer) { + auto StripIntrinsic = CGF.CGM.getIntrinsic(llvm::Intrinsic::ptrauth_strip); + + auto Key = CGF.Builder.getInt32(PointerAuth.getKey()); + // Convert the pointer to intptr_t before signing it. + auto OrigType = Pointer->getType(); + Pointer = CGF.EmitRuntimeCall( + StripIntrinsic, {CGF.Builder.CreatePtrToInt(Pointer, CGF.IntPtrTy), Key}); + return CGF.Builder.CreateIntToPtr(Pointer, OrigType); +} + +llvm::Value * +CodeGenFunction::EmitPointerAuthAuth(const CGPointerAuthInfo &PointerAuth, + llvm::Value *Pointer) { + if (PointerAuth.shouldStrip()) { + return EmitStrip(*this, PointerAuth, Pointer); + } + if (!PointerAuth.shouldAuth()) { + return Pointer; + } + + return EmitPointerAuthCommon(*this, PointerAuth, Pointer, + llvm::Intrinsic::ptrauth_auth); +} diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index a9c497bde68717..13f12b5d878a6a 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -2453,10 +2453,20 @@ class CodeGenFunction : public CodeGenTypeCache { void InitializeVTablePointers(const CXXRecordDecl *ClassDecl); + // VTableTrapMode - whether we guarantee that loading the + // vtable is guaranteed to trap on authentication failure, + // even if the resulting vtable pointer is unused. + enum class VTableAuthMode { + Authenticate, + MustTrap, + UnsafeUbsanStrip // Should only be used for Vptr UBSan check + }; /// GetVTablePtr - Return the Value of the vtable pointer member pointed /// to by This. - llvm::Value *GetVTablePtr(Address This, llvm::Type *VTableTy, - const CXXRecordDecl *VTableClass); + llvm::Value * + GetVTablePtr(Address This, llvm::Type *VTableTy, + const CXXRecordDecl *VTableClass, + VTableAuthMode AuthMode = VTableAuthMode::Authenticate); enum CFITypeCheckKind { CFITCK_VCall, @@ -4417,6 +4427,19 @@ class CodeGenFunction : public CodeGenTypeCache { bool isPointerKnownNonNull(const Expr *E); + /// Create the discriminator from the storage address and the entity hash. + llvm::Value *EmitPointerAuthBlendDiscriminator(llvm::Value *StorageAddress, + llvm::Value *Discriminator); + CGPointerAuthInfo EmitPointerAuthInfo(const PointerAuthSchema &Schema, + llvm::Value *StorageAddress, + GlobalDecl SchemaDecl, + QualType SchemaType); + llvm::Value *EmitPointerAuthSign(QualType PointeeType, llvm::Value *Pointer); + llvm::Value *EmitPointerAuthSign(const CGPointerAuthInfo &Info, + llvm::Value *Pointer); + llvm::Value *EmitPointerAuthAuth(const CGPointerAuthInfo &Info, + llvm::Value *Pointer); + void EmitPointerAuthOperandBundle( const CGPointerAuthInfo &Info, SmallVectorImpl &Bundles); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index dd4a665ebc78b7..652f519d824880 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -907,7 +907,8 @@ void CodeGenModule::Release() { if (Context.getTargetInfo().getTriple().isWasm()) EmitMainVoidAlias(); - if (getTriple().isAMDGPU()) { + if (getTriple().isAMDGPU() || + (getTriple().isSPIRV() && getTriple().getVendor() == llvm::Triple::AMD)) { // Emit amdhsa_code_object_version module flag, which is code object version // times 100. if (getTarget().getTargetOpts().CodeObjectVersion != @@ -4259,8 +4260,8 @@ void CodeGenModule::emitMultiVersionFunctions() { llvm::Constant *ResolverConstant = GetOrCreateMultiVersionResolver(GD); if (auto *IFunc = dyn_cast(ResolverConstant)) { ResolverConstant = IFunc->getResolver(); - if (FD->isTargetClonesMultiVersion() || - FD->isTargetVersionMultiVersion()) { + if (FD->isTargetClonesMultiVersion() && + !getTarget().getTriple().isAArch64()) { std::string MangledName = getMangledNameImpl( *this, GD, FD, /*OmitMultiVersionMangling=*/true); if (!GetGlobalValue(MangledName + ".ifunc")) { diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 9913304757caa7..4796d421aaa699 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -435,7 +435,7 @@ class CodeGenModule : public CodeGenTypeCache { // Store deferred function annotations so they can be emitted at the end with // most up to date ValueDecl that will have all the inherited annotations. - llvm::DenseMap DeferredAnnotations; + llvm::MapVector DeferredAnnotations; /// Map used to get unique annotation strings. llvm::StringMap AnnotationStrings; @@ -609,6 +609,13 @@ class CodeGenModule : public CodeGenTypeCache { std::pair, const TopLevelStmtDecl *> GlobalTopLevelStmtBlockInFlight; + llvm::DenseMap PtrAuthDiscriminatorHashes; + + llvm::DenseMap> + VTablePtrAuthInfos; + std::optional + computeVTPointerAuthentication(const CXXRecordDecl *ThisClass); + public: CodeGenModule(ASTContext &C, IntrusiveRefCntPtr FS, const HeaderSearchOptions &headersearchopts, @@ -957,11 +964,33 @@ class CodeGenModule : public CodeGenTypeCache { CGPointerAuthInfo getFunctionPointerAuthInfo(QualType T); + bool shouldSignPointer(const PointerAuthSchema &Schema); + llvm::Constant *getConstantSignedPointer(llvm::Constant *Pointer, + const PointerAuthSchema &Schema, + llvm::Constant *StorageAddress, + GlobalDecl SchemaDecl, + QualType SchemaType); + llvm::Constant * getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key, llvm::Constant *StorageAddress, llvm::ConstantInt *OtherDiscriminator); + llvm::ConstantInt * + getPointerAuthOtherDiscriminator(const PointerAuthSchema &Schema, + GlobalDecl SchemaDecl, QualType SchemaType); + + uint16_t getPointerAuthDeclDiscriminator(GlobalDecl GD); + std::optional + getVTablePointerAuthInfo(CodeGenFunction *Context, + const CXXRecordDecl *Record, + llvm::Value *StorageAddress); + + std::optional + getVTablePointerAuthentication(const CXXRecordDecl *thisClass); + + CGPointerAuthInfo EmitPointerAuthInfo(const RecordDecl *RD); + // Return whether RTTI information should be emitted for this target. bool shouldEmitRTTI(bool ForEH = false) { return (ForEH || getLangOpts().RTTI) && !getLangOpts().CUDAIsDevice && diff --git a/clang/lib/CodeGen/ConstantEmitter.h b/clang/lib/CodeGen/ConstantEmitter.h index a55da0dcad7921..eff0a8d52891f0 100644 --- a/clang/lib/CodeGen/ConstantEmitter.h +++ b/clang/lib/CodeGen/ConstantEmitter.h @@ -113,6 +113,9 @@ class ConstantEmitter { llvm::Constant *tryEmitAbstract(const APValue &value, QualType T); llvm::Constant *tryEmitAbstractForMemory(const APValue &value, QualType T); + llvm::Constant *tryEmitConstantSignedPointer(llvm::Constant *Ptr, + PointerAuthQualifier Auth); + llvm::Constant *tryEmitConstantExpr(const ConstantExpr *CE); llvm::Constant *emitNullForMemory(QualType T) { diff --git a/clang/lib/CodeGen/ConstantInitBuilder.cpp b/clang/lib/CodeGen/ConstantInitBuilder.cpp index 3cf69f3b6415e4..549d5dd66b1230 100644 --- a/clang/lib/CodeGen/ConstantInitBuilder.cpp +++ b/clang/lib/CodeGen/ConstantInitBuilder.cpp @@ -296,3 +296,21 @@ ConstantAggregateBuilderBase::finishStruct(llvm::StructType *ty) { buffer.erase(buffer.begin() + Begin, buffer.end()); return constant; } + +/// Sign the given pointer and add it to the constant initializer +/// currently being built. +void ConstantAggregateBuilderBase::addSignedPointer( + llvm::Constant *Pointer, const PointerAuthSchema &Schema, + GlobalDecl CalleeDecl, QualType CalleeType) { + if (!Schema || !Builder.CGM.shouldSignPointer(Schema)) + return add(Pointer); + + llvm::Constant *StorageAddress = nullptr; + if (Schema.isAddressDiscriminated()) { + StorageAddress = getAddrOfCurrentPosition(Pointer->getType()); + } + + llvm::Constant *SignedPointer = Builder.CGM.getConstantSignedPointer( + Pointer, Schema, StorageAddress, CalleeDecl, CalleeType); + add(SignedPointer); +} diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 01a735c1437e1d..63e36e1b838936 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -23,6 +23,7 @@ #include "CGVTables.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" +#include "ConstantEmitter.h" #include "TargetInfo.h" #include "clang/AST/Attr.h" #include "clang/AST/Mangle.h" @@ -336,9 +337,11 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI { bool exportThunk() override { return true; } llvm::Value *performThisAdjustment(CodeGenFunction &CGF, Address This, - const ThisAdjustment &TA) override; + const CXXRecordDecl *UnadjustedThisClass, + const ThunkInfo &TI) override; llvm::Value *performReturnAdjustment(CodeGenFunction &CGF, Address Ret, + const CXXRecordDecl *UnadjustedRetClass, const ReturnAdjustment &RA) override; size_t getSrcArgforCopyCtor(const CXXConstructorDecl *, @@ -1477,10 +1480,22 @@ llvm::Value *ItaniumCXXABI::emitDynamicCastCall( computeOffsetHint(CGF.getContext(), SrcDecl, DestDecl).getQuantity()); // Emit the call to __dynamic_cast. - llvm::Value *Args[] = {ThisAddr.emitRawPointer(CGF), SrcRTTI, DestRTTI, - OffsetHint}; - llvm::Value *Value = - CGF.EmitNounwindRuntimeCall(getItaniumDynamicCastFn(CGF), Args); + llvm::Value *Value = ThisAddr.emitRawPointer(CGF); + if (CGM.getCodeGenOpts().PointerAuth.CXXVTablePointers) { + // We perform a no-op load of the vtable pointer here to force an + // authentication. In environments that do not support pointer + // authentication this is a an actual no-op that will be elided. When + // pointer authentication is supported and enforced on vtable pointers this + // load can trap. + llvm::Value *Vtable = + CGF.GetVTablePtr(ThisAddr, CGM.Int8PtrTy, SrcDecl, + CodeGenFunction::VTableAuthMode::MustTrap); + assert(Vtable); + (void)Vtable; + } + + llvm::Value *args[] = {Value, SrcRTTI, DestRTTI, OffsetHint}; + Value = CGF.EmitNounwindRuntimeCall(getItaniumDynamicCastFn(CGF), args); /// C++ [expr.dynamic.cast]p9: /// A failed cast to reference type throws std::bad_cast @@ -1955,8 +1970,18 @@ llvm::Value *ItaniumCXXABI::getVTableAddressPointInStructorWithVTT( VirtualPointerIndex); // And load the address point from the VTT. - return CGF.Builder.CreateAlignedLoad(CGF.GlobalsVoidPtrTy, VTT, - CGF.getPointerAlign()); + llvm::Value *AP = + CGF.Builder.CreateAlignedLoad(CGF.GlobalsVoidPtrTy, VTT, + CGF.getPointerAlign()); + + if (auto &Schema = CGF.CGM.getCodeGenOpts().PointerAuth.CXXVTTVTablePointers) { + CGPointerAuthInfo PointerAuth = CGF.EmitPointerAuthInfo(Schema, VTT, + GlobalDecl(), + QualType()); + AP = CGF.EmitPointerAuthAuth(PointerAuth, AP); + } + + return AP; } llvm::GlobalVariable *ItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *RD, @@ -2008,8 +2033,9 @@ CGCallee ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF, llvm::Value *VTable = CGF.GetVTablePtr(This, PtrTy, MethodDecl->getParent()); uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD); - llvm::Value *VFunc; - if (CGF.ShouldEmitVTableTypeCheckedLoad(MethodDecl->getParent())) { + llvm::Value *VFunc, *VTableSlotPtr = nullptr; + auto &Schema = CGM.getCodeGenOpts().PointerAuth.CXXVirtualFunctionPointers; + if (!Schema && CGF.ShouldEmitVTableTypeCheckedLoad(MethodDecl->getParent())) { VFunc = CGF.EmitVTableTypeCheckedLoad( MethodDecl->getParent(), VTable, PtrTy, VTableIndex * @@ -2024,7 +2050,7 @@ CGCallee ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF, CGM.getIntrinsic(llvm::Intrinsic::load_relative, {CGM.Int32Ty}), {VTable, llvm::ConstantInt::get(CGM.Int32Ty, 4 * VTableIndex)}); } else { - llvm::Value *VTableSlotPtr = CGF.Builder.CreateConstInBoundsGEP1_64( + VTableSlotPtr = CGF.Builder.CreateConstInBoundsGEP1_64( PtrTy, VTable, VTableIndex, "vfn"); VFuncLoad = CGF.Builder.CreateAlignedLoad(PtrTy, VTableSlotPtr, CGF.getPointerAlign()); @@ -2048,7 +2074,13 @@ CGCallee ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF, VFunc = VFuncLoad; } - CGCallee Callee(GD, VFunc); + CGPointerAuthInfo PointerAuth; + if (Schema) { + assert(VTableSlotPtr && "virtual function pointer not set"); + GD = CGM.getItaniumVTableContext().findOriginalMethod(GD.getCanonicalDecl()); + PointerAuth = CGF.EmitPointerAuthInfo(Schema, VTableSlotPtr, GD, QualType()); + } + CGCallee Callee(GD, VFunc, PointerAuth); return Callee; } @@ -2147,6 +2179,7 @@ bool ItaniumCXXABI::canSpeculativelyEmitVTable(const CXXRecordDecl *RD) const { } static llvm::Value *performTypeAdjustment(CodeGenFunction &CGF, Address InitialPtr, + const CXXRecordDecl *UnadjustedClass, int64_t NonVirtualAdjustment, int64_t VirtualAdjustment, bool IsReturnAdjustment) { @@ -2164,8 +2197,8 @@ static llvm::Value *performTypeAdjustment(CodeGenFunction &CGF, // Perform the virtual adjustment if we have one. llvm::Value *ResultPtr; if (VirtualAdjustment) { - Address VTablePtrPtr = V.withElementType(CGF.Int8PtrTy); - llvm::Value *VTablePtr = CGF.Builder.CreateLoad(VTablePtrPtr); + llvm::Value *VTablePtr = + CGF.GetVTablePtr(V, CGF.Int8PtrTy, UnadjustedClass); llvm::Value *Offset; llvm::Value *OffsetPtr = CGF.Builder.CreateConstInBoundsGEP1_64( @@ -2200,18 +2233,20 @@ static llvm::Value *performTypeAdjustment(CodeGenFunction &CGF, return ResultPtr; } -llvm::Value *ItaniumCXXABI::performThisAdjustment(CodeGenFunction &CGF, - Address This, - const ThisAdjustment &TA) { - return performTypeAdjustment(CGF, This, TA.NonVirtual, - TA.Virtual.Itanium.VCallOffsetOffset, +llvm::Value * +ItaniumCXXABI::performThisAdjustment(CodeGenFunction &CGF, Address This, + const CXXRecordDecl *UnadjustedClass, + const ThunkInfo &TI) { + return performTypeAdjustment(CGF, This, UnadjustedClass, TI.This.NonVirtual, + TI.This.Virtual.Itanium.VCallOffsetOffset, /*IsReturnAdjustment=*/false); } llvm::Value * ItaniumCXXABI::performReturnAdjustment(CodeGenFunction &CGF, Address Ret, + const CXXRecordDecl *UnadjustedClass, const ReturnAdjustment &RA) { - return performTypeAdjustment(CGF, Ret, RA.NonVirtual, + return performTypeAdjustment(CGF, Ret, UnadjustedClass, RA.NonVirtual, RA.Virtual.Itanium.VBaseOffsetOffset, /*IsReturnAdjustment=*/true); } @@ -3694,6 +3729,10 @@ void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) { VTable, Two); } + if (auto &Schema = CGM.getCodeGenOpts().PointerAuth.CXXTypeInfoVTablePointer) + VTable = CGM.getConstantSignedPointer(VTable, Schema, nullptr, GlobalDecl(), + QualType(Ty, 0)); + Fields.push_back(VTable); } diff --git a/clang/lib/CodeGen/LinkInModulesPass.cpp b/clang/lib/CodeGen/LinkInModulesPass.cpp index c3831aae13b647..44b2df52f001a7 100644 --- a/clang/lib/CodeGen/LinkInModulesPass.cpp +++ b/clang/lib/CodeGen/LinkInModulesPass.cpp @@ -20,15 +20,13 @@ using namespace llvm; -LinkInModulesPass::LinkInModulesPass(clang::BackendConsumer *BC, - bool ShouldLinkFiles) - : BC(BC), ShouldLinkFiles(ShouldLinkFiles) {} +LinkInModulesPass::LinkInModulesPass(clang::BackendConsumer *BC) : BC(BC) {} PreservedAnalyses LinkInModulesPass::run(Module &M, ModuleAnalysisManager &AM) { if (!BC) return PreservedAnalyses::all(); - if (BC->LinkInModules(&M, ShouldLinkFiles)) + if (BC->LinkInModules(&M)) report_fatal_error("Bitcode module postopt linking failed, aborted!"); return PreservedAnalyses::none(); diff --git a/clang/lib/CodeGen/LinkInModulesPass.h b/clang/lib/CodeGen/LinkInModulesPass.h index 7fe94d6250583d..3edbfd076e1508 100644 --- a/clang/lib/CodeGen/LinkInModulesPass.h +++ b/clang/lib/CodeGen/LinkInModulesPass.h @@ -28,10 +28,9 @@ class Pass; /// for use with the legacy pass manager. class LinkInModulesPass : public PassInfoMixin { clang::BackendConsumer *BC; - bool ShouldLinkFiles; public: - LinkInModulesPass(clang::BackendConsumer *BC, bool ShouldLinkFiles = true); + LinkInModulesPass(clang::BackendConsumer *BC); PreservedAnalyses run(Module &M, AnalysisManager &); static bool isRequired() { return true; } diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 9ab634fa6ce2e0..cc6740edabcd3c 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -415,9 +415,11 @@ class MicrosoftCXXABI : public CGCXXABI { bool exportThunk() override { return false; } llvm::Value *performThisAdjustment(CodeGenFunction &CGF, Address This, - const ThisAdjustment &TA) override; + const CXXRecordDecl * /*UnadjustedClass*/, + const ThunkInfo &TI) override; llvm::Value *performReturnAdjustment(CodeGenFunction &CGF, Address Ret, + const CXXRecordDecl * /*UnadjustedClass*/, const ReturnAdjustment &RA) override; void EmitThreadLocalInitFuncs( @@ -2223,9 +2225,10 @@ void MicrosoftCXXABI::emitVBTableDefinition(const VPtrInfo &VBT, GV->setLinkage(llvm::GlobalVariable::AvailableExternallyLinkage); } -llvm::Value *MicrosoftCXXABI::performThisAdjustment(CodeGenFunction &CGF, - Address This, - const ThisAdjustment &TA) { +llvm::Value *MicrosoftCXXABI::performThisAdjustment( + CodeGenFunction &CGF, Address This, + const CXXRecordDecl * /*UnadjustedClass*/, const ThunkInfo &TI) { + const ThisAdjustment &TA = TI.This; if (TA.isEmpty()) return This.emitRawPointer(CGF); @@ -2275,9 +2278,10 @@ llvm::Value *MicrosoftCXXABI::performThisAdjustment(CodeGenFunction &CGF, return V; } -llvm::Value * -MicrosoftCXXABI::performReturnAdjustment(CodeGenFunction &CGF, Address Ret, - const ReturnAdjustment &RA) { +llvm::Value *MicrosoftCXXABI::performReturnAdjustment( + CodeGenFunction &CGF, Address Ret, + const CXXRecordDecl * /*UnadjustedClass*/, const ReturnAdjustment &RA) { + if (RA.isEmpty()) return Ret.emitRawPointer(CGF); diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 0298d22203d9d4..221e222bdd47d9 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -147,6 +147,14 @@ getNVIDIAOffloadTargetTriple(const Driver &D, const ArgList &Args, static std::optional getHIPOffloadTargetTriple(const Driver &D, const ArgList &Args) { if (!Args.hasArg(options::OPT_offload_EQ)) { + auto OffloadArchs = Args.getAllArgValues(options::OPT_offload_arch_EQ); + if (llvm::find(OffloadArchs, "amdgcnspirv") != OffloadArchs.cend()) { + if (OffloadArchs.size() == 1) + return llvm::Triple("spirv64-amd-amdhsa"); + // Mixing specific & SPIR-V compilation is not supported for now. + D.Diag(diag::err_drv_only_one_offload_target_supported); + return std::nullopt; + } return llvm::Triple("amdgcn-amd-amdhsa"); // Default HIP triple. } auto TT = getOffloadTargetTriple(D, Args); @@ -229,6 +237,9 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple, UserConfigDir = static_cast(P); } #endif + + // Compute the path to the resource directory. + ResourceDir = GetResourcesPath(ClangExecutable, CLANG_RESOURCE_DIR); } void Driver::setDriverMode(StringRef Value) { @@ -247,24 +258,6 @@ void Driver::setDriverMode(StringRef Value) { Diag(diag::err_drv_unsupported_option_argument) << OptName << Value; } -void Driver::setResourceDirectory() { - // Compute the path to the resource directory, depending on the driver mode. - switch (Mode) { - case GCCMode: - case GXXMode: - case CPPMode: - case CLMode: - case DXCMode: - ResourceDir = GetResourcesPath(ClangExecutable, CLANG_RESOURCE_DIR); - break; - case FlangMode: - SmallString<64> customResourcePathRelativeToDriver{".."}; - ResourceDir = - GetResourcesPath(ClangExecutable, customResourcePathRelativeToDriver); - break; - } -} - InputArgList Driver::ParseArgStrings(ArrayRef ArgStrings, bool UseDriverMode, bool &ContainsError) { llvm::PrettyStackTraceString CrashInfo("Command line argument parsing"); @@ -370,6 +363,7 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler. } else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) || (PhaseArg = DAL.getLastArg(options::OPT_print_supported_cpus)) || + (PhaseArg = DAL.getLastArg(options::OPT_print_enabled_extensions)) || (PhaseArg = DAL.getLastArg(options::OPT_module_file_info)) || (PhaseArg = DAL.getLastArg(options::OPT_verify_pch)) || (PhaseArg = DAL.getLastArg(options::OPT_rewrite_objc)) || @@ -905,11 +899,11 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, } for (StringRef Arch : Archs) { - if (NVPTXTriple && IsNVIDIAGpuArch(StringToCudaArch( + if (NVPTXTriple && IsNVIDIAOffloadArch(StringToOffloadArch( getProcessorFromTargetID(*NVPTXTriple, Arch)))) { DerivedArchs[NVPTXTriple->getTriple()].insert(Arch); } else if (AMDTriple && - IsAMDGpuArch(StringToCudaArch( + IsAMDOffloadArch(StringToOffloadArch( getProcessorFromTargetID(*AMDTriple, Arch)))) { DerivedArchs[AMDTriple->getTriple()].insert(Arch); } else { @@ -1217,7 +1211,6 @@ Compilation *Driver::BuildCompilation(ArrayRef ArgList) { if (!DriverMode.empty()) setDriverMode(DriverMode); - setResourceDirectory(); // FIXME: What are we going to do with -V and -b? // Arguments specified in command line. @@ -2171,7 +2164,8 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { if (C.getArgs().hasArg(options::OPT_v) || C.getArgs().hasArg(options::OPT__HASH_HASH_HASH) || C.getArgs().hasArg(options::OPT_print_supported_cpus) || - C.getArgs().hasArg(options::OPT_print_supported_extensions)) { + C.getArgs().hasArg(options::OPT_print_supported_extensions) || + C.getArgs().hasArg(options::OPT_print_enabled_extensions)) { PrintVersion(C, llvm::errs()); SuppressMissingInputWarning = true; } @@ -2954,7 +2948,7 @@ class OffloadingActionBuilder final { struct TargetID { /// Target ID string which is persistent throughout the compilation. const char *ID; - TargetID(CudaArch Arch) { ID = CudaArchToString(Arch); } + TargetID(OffloadArch Arch) { ID = OffloadArchToString(Arch); } TargetID(const char *ID) : ID(ID) {} operator const char *() { return ID; } operator StringRef() { return StringRef(ID); } @@ -2975,7 +2969,7 @@ class OffloadingActionBuilder final { bool Relocatable = false; /// Default GPU architecture if there's no one specified. - CudaArch DefaultCudaArch = CudaArch::UNKNOWN; + OffloadArch DefaultOffloadArch = OffloadArch::UNKNOWN; /// Method to generate compilation unit ID specified by option /// '-fuse-cuid='. @@ -3104,7 +3098,7 @@ class OffloadingActionBuilder final { // If we have a fat binary, add it to the list. if (CudaFatBinary) { - AddTopLevel(CudaFatBinary, CudaArch::UNUSED); + AddTopLevel(CudaFatBinary, OffloadArch::UNUSED); CudaDeviceActions.clear(); CudaFatBinary = nullptr; return; @@ -3247,10 +3241,14 @@ class OffloadingActionBuilder final { // supported GPUs. sm_20 code should work correctly, if // suboptimally, on all newer GPUs. if (GpuArchList.empty()) { - if (ToolChains.front()->getTriple().isSPIRV()) - GpuArchList.push_back(CudaArch::Generic); - else - GpuArchList.push_back(DefaultCudaArch); + if (ToolChains.front()->getTriple().isSPIRV()) { + if (ToolChains.front()->getTriple().getVendor() == llvm::Triple::AMD) + GpuArchList.push_back(OffloadArch::AMDGCNSPIRV); + else + GpuArchList.push_back(OffloadArch::Generic); + } else { + GpuArchList.push_back(DefaultOffloadArch); + } } return Error; @@ -3264,16 +3262,16 @@ class OffloadingActionBuilder final { CudaActionBuilder(Compilation &C, DerivedArgList &Args, const Driver::InputList &Inputs) : CudaActionBuilderBase(C, Args, Inputs, Action::OFK_Cuda) { - DefaultCudaArch = CudaArch::CudaDefault; + DefaultOffloadArch = OffloadArch::CudaDefault; } StringRef getCanonicalOffloadArch(StringRef ArchStr) override { - CudaArch Arch = StringToCudaArch(ArchStr); - if (Arch == CudaArch::UNKNOWN || !IsNVIDIAGpuArch(Arch)) { + OffloadArch Arch = StringToOffloadArch(ArchStr); + if (Arch == OffloadArch::UNKNOWN || !IsNVIDIAOffloadArch(Arch)) { C.getDriver().Diag(clang::diag::err_drv_cuda_bad_gpu_arch) << ArchStr; return StringRef(); } - return CudaArchToString(Arch); + return OffloadArchToString(Arch); } std::optional> @@ -3403,7 +3401,7 @@ class OffloadingActionBuilder final { const Driver::InputList &Inputs) : CudaActionBuilderBase(C, Args, Inputs, Action::OFK_HIP) { - DefaultCudaArch = CudaArch::HIPDefault; + DefaultOffloadArch = OffloadArch::HIPDefault; if (Args.hasArg(options::OPT_fhip_emit_relocatable, options::OPT_fno_hip_emit_relocatable)) { @@ -4351,13 +4349,14 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, } for (auto Opt : {options::OPT_print_supported_cpus, - options::OPT_print_supported_extensions}) { + options::OPT_print_supported_extensions, + options::OPT_print_enabled_extensions}) { // If --print-supported-cpus, -mcpu=? or -mtune=? is specified, build a // custom Compile phase that prints out supported cpu models and quits. // - // If --print-supported-extensions is specified, call the helper function - // RISCVMarchHelp in RISCVISAInfo.cpp that prints out supported extensions - // and quits. + // If either --print-supported-extensions or --print-enabled-extensions is + // specified, call the corresponding helper function that prints out the + // supported/enabled extensions and quits. if (Arg *A = Args.getLastArg(Opt)) { if (Opt == options::OPT_print_supported_extensions && !C.getDefaultToolChain().getTriple().isRISCV() && @@ -4367,6 +4366,12 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, << "--print-supported-extensions"; return; } + if (Opt == options::OPT_print_enabled_extensions && + !C.getDefaultToolChain().getTriple().isAArch64()) { + C.getDriver().Diag(diag::err_opt_not_valid_on_target) + << "--print-enabled-extensions"; + return; + } // Use the -mcpu=? flag as the dummy input to cc1. Actions.clear(); @@ -4403,23 +4408,24 @@ static StringRef getCanonicalArchString(Compilation &C, bool SuppressError = false) { // Lookup the CUDA / HIP architecture string. Only report an error if we were // expecting the triple to be only NVPTX / AMDGPU. - CudaArch Arch = StringToCudaArch(getProcessorFromTargetID(Triple, ArchStr)); + OffloadArch Arch = + StringToOffloadArch(getProcessorFromTargetID(Triple, ArchStr)); if (!SuppressError && Triple.isNVPTX() && - (Arch == CudaArch::UNKNOWN || !IsNVIDIAGpuArch(Arch))) { + (Arch == OffloadArch::UNKNOWN || !IsNVIDIAOffloadArch(Arch))) { C.getDriver().Diag(clang::diag::err_drv_offload_bad_gpu_arch) << "CUDA" << ArchStr; return StringRef(); } else if (!SuppressError && Triple.isAMDGPU() && - (Arch == CudaArch::UNKNOWN || !IsAMDGpuArch(Arch))) { + (Arch == OffloadArch::UNKNOWN || !IsAMDOffloadArch(Arch))) { C.getDriver().Diag(clang::diag::err_drv_offload_bad_gpu_arch) << "HIP" << ArchStr; return StringRef(); } - if (IsNVIDIAGpuArch(Arch)) - return Args.MakeArgStringRef(CudaArchToString(Arch)); + if (IsNVIDIAOffloadArch(Arch)) + return Args.MakeArgStringRef(OffloadArchToString(Arch)); - if (IsAMDGpuArch(Arch)) { + if (IsAMDOffloadArch(Arch)) { llvm::StringMap Features; auto HIPTriple = getHIPOffloadTargetTriple(C.getDriver(), C.getInputArgs()); if (!HIPTriple) @@ -4540,9 +4546,9 @@ Driver::getOffloadArchs(Compilation &C, const llvm::opt::DerivedArgList &Args, if (Archs.empty()) { if (Kind == Action::OFK_Cuda) - Archs.insert(CudaArchToString(CudaArch::CudaDefault)); + Archs.insert(OffloadArchToString(OffloadArch::CudaDefault)); else if (Kind == Action::OFK_HIP) - Archs.insert(CudaArchToString(CudaArch::HIPDefault)); + Archs.insert(OffloadArchToString(OffloadArch::HIPDefault)); else if (Kind == Action::OFK_OpenMP) Archs.insert(StringRef()); } else { @@ -4592,10 +4598,13 @@ Action *Driver::BuildOffloadingActions(Compilation &C, // Get the product of all bound architectures and toolchains. SmallVector> TCAndArchs; - for (const ToolChain *TC : ToolChains) - for (StringRef Arch : getOffloadArchs(C, Args, Kind, TC)) + for (const ToolChain *TC : ToolChains) { + llvm::DenseSet Arches = getOffloadArchs(C, Args, Kind, TC); + SmallVector Sorted(Arches.begin(), Arches.end()); + llvm::sort(Sorted); + for (StringRef Arch : Sorted) TCAndArchs.push_back(std::make_pair(TC, Arch)); - llvm::sort(TCAndArchs, llvm::less_second()); + } for (unsigned I = 0, E = TCAndArchs.size(); I != E; ++I) DeviceActions.push_back(C.MakeAction(*InputArg, InputType)); @@ -6517,9 +6526,11 @@ const ToolChain &Driver::getOffloadingDeviceToolChain( // things. switch (TargetDeviceOffloadKind) { case Action::OFK_HIP: { - if (Target.getArch() == llvm::Triple::amdgcn && - Target.getVendor() == llvm::Triple::AMD && - Target.getOS() == llvm::Triple::AMDHSA) + if (((Target.getArch() == llvm::Triple::amdgcn || + Target.getArch() == llvm::Triple::spirv64) && + Target.getVendor() == llvm::Triple::AMD && + Target.getOS() == llvm::Triple::AMDHSA) || + !Args.hasArgNoClaim(options::OPT_offload_EQ)) TC = std::make_unique(*this, Target, HostTC, Args); else if (Target.getArch() == llvm::Triple::spirv64 && diff --git a/clang/lib/Driver/OffloadBundler.cpp b/clang/lib/Driver/OffloadBundler.cpp index 191d108e9b7398..a4ab846ed2c57a 100644 --- a/clang/lib/Driver/OffloadBundler.cpp +++ b/clang/lib/Driver/OffloadBundler.cpp @@ -79,7 +79,8 @@ OffloadTargetInfo::OffloadTargetInfo(const StringRef Target, auto TargetFeatures = Target.split(':'); auto TripleOrGPU = TargetFeatures.first.rsplit('-'); - if (clang::StringToCudaArch(TripleOrGPU.second) != clang::CudaArch::UNKNOWN) { + if (clang::StringToOffloadArch(TripleOrGPU.second) != + clang::OffloadArch::UNKNOWN) { auto KindTriple = TripleOrGPU.first.split('-'); this->OffloadKind = KindTriple.first; diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 40ab2e91125d1e..8f4cc47e418b5d 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -195,11 +195,11 @@ static void getAArch64MultilibFlags(const Driver &D, UnifiedFeatures.end()); std::vector MArch; for (const auto &Ext : AArch64::Extensions) - if (FeatureSet.contains(Ext.Feature)) - MArch.push_back(Ext.Name.str()); + if (FeatureSet.contains(Ext.PosTargetFeature)) + MArch.push_back(Ext.UserVisibleName.str()); for (const auto &Ext : AArch64::Extensions) - if (FeatureSet.contains(Ext.NegFeature)) - MArch.push_back(("no" + Ext.Name).str()); + if (FeatureSet.contains(Ext.NegTargetFeature)) + MArch.push_back(("no" + Ext.UserVisibleName).str()); StringRef ArchName; for (const auto &ArchInfo : AArch64::ArchInfos) if (FeatureSet.contains(ArchInfo->ArchFeature)) diff --git a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp index d17ecb15c82088..1c0fb4babe3a55 100644 --- a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp @@ -87,7 +87,7 @@ llvm::opt::DerivedArgList *AMDGPUOpenMPToolChain::TranslateArgs( llvm::formatv("{0}", llvm::fmt_consume(ArchsOrErr.takeError())); getDriver().Diag(diag::err_drv_undetermined_gpu_arch) << llvm::Triple::getArchTypeName(getArch()) << ErrMsg << "-march"; - Arch = CudaArchToString(CudaArch::HIPDefault); + Arch = OffloadArchToString(OffloadArch::HIPDefault); } else { Arch = Args.MakeArgString(ArchsOrErr->front()); } diff --git a/clang/lib/Driver/ToolChains/Arch/X86.cpp b/clang/lib/Driver/ToolChains/Arch/X86.cpp index 75f9c99d5d0bf4..92821b2a82daec 100644 --- a/clang/lib/Driver/ToolChains/Arch/X86.cpp +++ b/clang/lib/Driver/ToolChains/Arch/X86.cpp @@ -274,7 +274,7 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, for (StringRef Value : A->getValues()) { if (Value == "egpr" || Value == "push2pop2" || Value == "ppx" || Value == "ndd" || Value == "ccmp" || Value == "nf" || - Value == "cf") { + Value == "cf" || Value == "zu") { Features.push_back( Args.MakeArgString((IsNegative ? "-" : "+") + Value)); continue; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 2ce9e2f4bcfcd4..1b7cc82ea816ed 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -1524,7 +1524,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args, auto isPAuthLR = [](const char *member) { llvm::AArch64::ExtensionInfo pauthlr_extension = llvm::AArch64::getExtensionByID(llvm::AArch64::AEK_PAUTHLR); - return pauthlr_extension.Feature == member; + return pauthlr_extension.PosTargetFeature == member; }; if (std::any_of(CmdArgs.begin(), CmdArgs.end(), isPAuthLR)) @@ -4939,7 +4939,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(NormalizedTriple)); if (JA.isDeviceOffloading(Action::OFK_HIP) && - getToolChain().getTriple().isAMDGPU()) { + (getToolChain().getTriple().isAMDGPU() || + (getToolChain().getTriple().isSPIRV() && + getToolChain().getTriple().getVendor() == llvm::Triple::AMD))) { // Device side compilation printf if (Args.getLastArg(options::OPT_mprintf_kind_EQ)) { CmdArgs.push_back(Args.MakeArgString( diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index 2dfc7457b0ac7c..08a4633902654d 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -223,13 +223,13 @@ CudaInstallationDetector::CudaInstallationDetector( // CUDA-9+ uses single libdevice file for all GPU variants. std::string FilePath = LibDevicePath + "/libdevice.10.bc"; if (FS.exists(FilePath)) { - for (int Arch = (int)CudaArch::SM_30, E = (int)CudaArch::LAST; Arch < E; - ++Arch) { - CudaArch GpuArch = static_cast(Arch); - if (!IsNVIDIAGpuArch(GpuArch)) + for (int Arch = (int)OffloadArch::SM_30, E = (int)OffloadArch::LAST; + Arch < E; ++Arch) { + OffloadArch OA = static_cast(Arch); + if (!IsNVIDIAOffloadArch(OA)) continue; - std::string GpuArchName(CudaArchToString(GpuArch)); - LibDeviceMap[GpuArchName] = FilePath; + std::string OffloadArchName(OffloadArchToString(OA)); + LibDeviceMap[OffloadArchName] = FilePath; } } } else { @@ -312,17 +312,17 @@ void CudaInstallationDetector::AddCudaIncludeArgs( } void CudaInstallationDetector::CheckCudaVersionSupportsArch( - CudaArch Arch) const { - if (Arch == CudaArch::UNKNOWN || Version == CudaVersion::UNKNOWN || + OffloadArch Arch) const { + if (Arch == OffloadArch::UNKNOWN || Version == CudaVersion::UNKNOWN || ArchsWithBadVersion[(int)Arch]) return; - auto MinVersion = MinVersionForCudaArch(Arch); - auto MaxVersion = MaxVersionForCudaArch(Arch); + auto MinVersion = MinVersionForOffloadArch(Arch); + auto MaxVersion = MaxVersionForOffloadArch(Arch); if (Version < MinVersion || Version > MaxVersion) { ArchsWithBadVersion[(int)Arch] = true; D.Diag(diag::err_drv_cuda_version_unsupported) - << CudaArchToString(Arch) << CudaVersionToString(MinVersion) + << OffloadArchToString(Arch) << CudaVersionToString(MinVersion) << CudaVersionToString(MaxVersion) << InstallPath << CudaVersionToString(Version); } @@ -401,8 +401,8 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA, } // Obtain architecture from the action. - CudaArch gpu_arch = StringToCudaArch(GPUArchName); - assert(gpu_arch != CudaArch::UNKNOWN && + OffloadArch gpu_arch = StringToOffloadArch(GPUArchName); + assert(gpu_arch != OffloadArch::UNKNOWN && "Device action expected to have an architecture."); // Check that our installation's ptxas supports gpu_arch. @@ -457,7 +457,7 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-v"); CmdArgs.push_back("--gpu-name"); - CmdArgs.push_back(Args.MakeArgString(CudaArchToString(gpu_arch))); + CmdArgs.push_back(Args.MakeArgString(OffloadArchToString(gpu_arch))); CmdArgs.push_back("--output-file"); std::string OutputFileName = TC.getInputFilename(Output); @@ -553,7 +553,7 @@ void NVPTX::FatBinary::ConstructJob(Compilation &C, const JobAction &JA, const char *gpu_arch_str = A->getOffloadingArch(); assert(gpu_arch_str && "Device action expected to have associated a GPU architecture!"); - CudaArch gpu_arch = StringToCudaArch(gpu_arch_str); + OffloadArch gpu_arch = StringToOffloadArch(gpu_arch_str); if (II.getType() == types::TY_PP_Asm && !shouldIncludePTX(Args, gpu_arch_str)) @@ -561,7 +561,7 @@ void NVPTX::FatBinary::ConstructJob(Compilation &C, const JobAction &JA, // We need to pass an Arch of the form "sm_XX" for cubin files and // "compute_XX" for ptx. const char *Arch = (II.getType() == types::TY_PP_Asm) - ? CudaArchToVirtualArchString(gpu_arch) + ? OffloadArchToVirtualArchString(gpu_arch) : gpu_arch_str; CmdArgs.push_back( Args.MakeArgString(llvm::Twine("--image=profile=") + Arch + @@ -758,7 +758,7 @@ NVPTXToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, if (!DAL->hasArg(options::OPT_march_EQ) && OffloadKind != Action::OFK_None) { DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), - CudaArchToString(CudaArch::CudaDefault)); + OffloadArchToString(OffloadArch::CudaDefault)); } else if (DAL->getLastArgValue(options::OPT_march_EQ) == "generic" && OffloadKind == Action::OFK_None) { DAL->eraseArg(options::OPT_march_EQ); @@ -938,7 +938,7 @@ void CudaToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, !DriverArgs.hasArg(options::OPT_no_cuda_version_check)) { StringRef Arch = DriverArgs.getLastArgValue(options::OPT_march_EQ); assert(!Arch.empty() && "Must have an explicit GPU arch."); - CudaInstallation.CheckCudaVersionSupportsArch(StringToCudaArch(Arch)); + CudaInstallation.CheckCudaVersionSupportsArch(StringToOffloadArch(Arch)); } CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); } @@ -984,7 +984,7 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, llvm::formatv("{0}", llvm::fmt_consume(ArchsOrErr.takeError())); getDriver().Diag(diag::err_drv_undetermined_gpu_arch) << llvm::Triple::getArchTypeName(getArch()) << ErrMsg << "-march"; - Arch = CudaArchToString(CudaArch::CudaDefault); + Arch = OffloadArchToString(OffloadArch::CudaDefault); } else { Arch = Args.MakeArgString(ArchsOrErr->front()); } diff --git a/clang/lib/Driver/ToolChains/Cuda.h b/clang/lib/Driver/ToolChains/Cuda.h index 43c17ba7c0ba03..7464d88cb350ba 100644 --- a/clang/lib/Driver/ToolChains/Cuda.h +++ b/clang/lib/Driver/ToolChains/Cuda.h @@ -37,7 +37,7 @@ class CudaInstallationDetector { // CUDA architectures for which we have raised an error in // CheckCudaVersionSupportsArch. - mutable std::bitset<(int)CudaArch::LAST> ArchsWithBadVersion; + mutable std::bitset<(int)OffloadArch::LAST> ArchsWithBadVersion; public: CudaInstallationDetector(const Driver &D, const llvm::Triple &HostTriple, @@ -50,7 +50,7 @@ class CudaInstallationDetector { /// /// If either Version or Arch is unknown, does not emit an error. Emits at /// most one error per Arch. - void CheckCudaVersionSupportsArch(CudaArch Arch) const; + void CheckCudaVersionSupportsArch(OffloadArch Arch) const; /// Check whether we detected a valid Cuda install. bool isValid() const { return IsValid; } diff --git a/clang/lib/Driver/ToolChains/HIPAMD.cpp b/clang/lib/Driver/ToolChains/HIPAMD.cpp index 34236e8bcf9490..c35b0febb262da 100644 --- a/clang/lib/Driver/ToolChains/HIPAMD.cpp +++ b/clang/lib/Driver/ToolChains/HIPAMD.cpp @@ -10,6 +10,7 @@ #include "AMDGPU.h" #include "CommonArgs.h" #include "HIPUtility.h" +#include "SPIRV.h" #include "clang/Basic/Cuda.h" #include "clang/Basic/TargetID.h" #include "clang/Driver/Compilation.h" @@ -193,6 +194,33 @@ void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA, Lld, LldArgs, Inputs, Output)); } +// For SPIR-V the inputs for the job are device AMDGCN SPIR-V flavoured bitcode +// and the output is either a compiled SPIR-V binary or bitcode (-emit-llvm). It +// calls llvm-link and then the llvm-spirv translator. Once the SPIR-V BE will +// be promoted from experimental, we will switch to using that. TODO: consider +// if we want to run any targeted optimisations over IR here, over generic +// SPIR-V. +void AMDGCN::Linker::constructLinkAndEmitSpirvCommand( + Compilation &C, const JobAction &JA, const InputInfoList &Inputs, + const InputInfo &Output, const llvm::opt::ArgList &Args) const { + assert(!Inputs.empty() && "Must have at least one input."); + + constructLlvmLinkCommand(C, JA, Inputs, Output, Args); + + // Linked BC is now in Output + + // Emit SPIR-V binary. + llvm::opt::ArgStringList TrArgs{ + "--spirv-max-version=1.6", + "--spirv-ext=+all", + "--spirv-allow-extra-diexpressions", + "--spirv-allow-unknown-intrinsics", + "--spirv-lower-const-expr", + "--spirv-preserve-auxdata", + "--spirv-debug-info-version=nonsemantic-shader-200"}; + SPIRV::constructTranslateCommand(C, *this, JA, Output, Output, TrArgs); +} + // For amdgcn the inputs of the linker job are device bitcode and output is // either an object file or bitcode (-emit-llvm). It calls llvm-link, opt, // llc, then lld steps. @@ -214,6 +242,9 @@ void AMDGCN::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (JA.getType() == types::TY_LLVM_BC) return constructLlvmLinkCommand(C, JA, Inputs, Output, Args); + if (getToolChain().getTriple().isSPIRV()) + return constructLinkAndEmitSpirvCommand(C, JA, Inputs, Output, Args); + return constructLldCommand(C, JA, Inputs, Output, Args); } @@ -270,6 +301,13 @@ void HIPAMDToolChain::addClangTargetOptions( CC1Args.push_back("-fapply-global-visibility-to-externs"); } + // For SPIR-V we embed the command-line into the generated binary, in order to + // retrieve it at JIT time and be able to do target specific compilation with + // options that match the user-supplied ones. + if (getTriple().isSPIRV() && + !DriverArgs.hasArg(options::OPT_fembed_bitcode_marker)) + CC1Args.push_back("-fembed-bitcode=marker"); + for (auto BCFile : getDeviceLibs(DriverArgs)) { CC1Args.push_back(BCFile.ShouldInternalize ? "-mlink-builtin-bitcode" : "-mlink-bitcode-file"); @@ -303,7 +341,8 @@ HIPAMDToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, } Tool *HIPAMDToolChain::buildLinker() const { - assert(getTriple().getArch() == llvm::Triple::amdgcn); + assert(getTriple().getArch() == llvm::Triple::amdgcn || + getTriple().getArch() == llvm::Triple::spirv64); return new tools::AMDGCN::Linker(*this); } @@ -358,7 +397,9 @@ VersionTuple HIPAMDToolChain::computeMSVCVersion(const Driver *D, llvm::SmallVector HIPAMDToolChain::getDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { llvm::SmallVector BCLibs; - if (DriverArgs.hasArg(options::OPT_nogpulib)) + if (DriverArgs.hasArg(options::OPT_nogpulib) || + (getTriple().getArch() == llvm::Triple::spirv64 && + getTriple().getVendor() == llvm::Triple::AMD)) return {}; ArgStringList LibraryPaths; diff --git a/clang/lib/Driver/ToolChains/HIPAMD.h b/clang/lib/Driver/ToolChains/HIPAMD.h index d81a9733014ccb..c31894e22c5c83 100644 --- a/clang/lib/Driver/ToolChains/HIPAMD.h +++ b/clang/lib/Driver/ToolChains/HIPAMD.h @@ -40,6 +40,10 @@ class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { const InputInfoList &Inputs, const InputInfo &Output, const llvm::opt::ArgList &Args) const; + void constructLinkAndEmitSpirvCommand(Compilation &C, const JobAction &JA, + const InputInfoList &Inputs, + const InputInfo &Output, + const llvm::opt::ArgList &Args) const; }; } // end namespace AMDGCN diff --git a/clang/lib/Driver/ToolChains/Solaris.cpp b/clang/lib/Driver/ToolChains/Solaris.cpp index 7126e018ca5b6f..e82ed2ca79ffd6 100644 --- a/clang/lib/Driver/ToolChains/Solaris.cpp +++ b/clang/lib/Driver/ToolChains/Solaris.cpp @@ -341,6 +341,7 @@ SanitizerMask Solaris::getSupportedSanitizers() const { Res |= SanitizerKind::PointerCompare; Res |= SanitizerKind::PointerSubtract; } + Res |= SanitizerKind::SafeStack; Res |= SanitizerKind::Vptr; return Res; } diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index 5b763df9b33293..60bd97e0ee987c 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -158,44 +158,46 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - // When optimizing, if wasm-opt is available, run it. - std::string WasmOptPath; - if (Args.getLastArg(options::OPT_O_Group)) { - WasmOptPath = ToolChain.GetProgramPath("wasm-opt"); - if (WasmOptPath == "wasm-opt") { - WasmOptPath = {}; + if (Args.hasFlag(options::OPT_wasm_opt, options::OPT_no_wasm_opt, true)) { + // When optimizing, if wasm-opt is available, run it. + std::string WasmOptPath; + if (Args.getLastArg(options::OPT_O_Group)) { + WasmOptPath = ToolChain.GetProgramPath("wasm-opt"); + if (WasmOptPath == "wasm-opt") { + WasmOptPath = {}; + } } - } - - if (!WasmOptPath.empty()) { - CmdArgs.push_back("--keep-section=target_features"); - } - C.addCommand(std::make_unique(JA, *this, - ResponseFileSupport::AtFileCurCP(), - Linker, CmdArgs, Inputs, Output)); - - if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { if (!WasmOptPath.empty()) { - StringRef OOpt = "s"; - if (A->getOption().matches(options::OPT_O4) || - A->getOption().matches(options::OPT_Ofast)) - OOpt = "4"; - else if (A->getOption().matches(options::OPT_O0)) - OOpt = "0"; - else if (A->getOption().matches(options::OPT_O)) - OOpt = A->getValue(); - - if (OOpt != "0") { - const char *WasmOpt = Args.MakeArgString(WasmOptPath); - ArgStringList OptArgs; - OptArgs.push_back(Output.getFilename()); - OptArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt)); - OptArgs.push_back("-o"); - OptArgs.push_back(Output.getFilename()); - C.addCommand(std::make_unique( - JA, *this, ResponseFileSupport::AtFileCurCP(), WasmOpt, OptArgs, - Inputs, Output)); + CmdArgs.push_back("--keep-section=target_features"); + } + + C.addCommand(std::make_unique(JA, *this, + ResponseFileSupport::AtFileCurCP(), + Linker, CmdArgs, Inputs, Output)); + + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { + if (!WasmOptPath.empty()) { + StringRef OOpt = "s"; + if (A->getOption().matches(options::OPT_O4) || + A->getOption().matches(options::OPT_Ofast)) + OOpt = "4"; + else if (A->getOption().matches(options::OPT_O0)) + OOpt = "0"; + else if (A->getOption().matches(options::OPT_O)) + OOpt = A->getValue(); + + if (OOpt != "0") { + const char *WasmOpt = Args.MakeArgString(WasmOptPath); + ArgStringList OptArgs; + OptArgs.push_back(Output.getFilename()); + OptArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt)); + OptArgs.push_back("-o"); + OptArgs.push_back(Output.getFilename()); + C.addCommand(std::make_unique( + JA, *this, ResponseFileSupport::AtFileCurCP(), WasmOpt, OptArgs, + Inputs, Output)); + } } } } diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index cd21fbb2221ac6..259ef1dd00e3f9 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -369,6 +369,14 @@ template <> struct ScalarEnumerationTraits { } }; +template <> struct MappingTraits { + static void mapping(IO &IO, FormatStyle::KeepEmptyLinesStyle &Value) { + IO.mapOptional("AtEndOfFile", Value.AtEndOfFile); + IO.mapOptional("AtStartOfBlock", Value.AtStartOfBlock); + IO.mapOptional("AtStartOfFile", Value.AtStartOfFile); + } +}; + template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, FormatStyle::LanguageKind &Value) { IO.enumCase(Value, "Cpp", FormatStyle::LK_Cpp); @@ -869,6 +877,9 @@ template <> struct MappingTraits { OnCurrentLine); IO.mapOptional("DeriveLineEnding", DeriveLineEnding); IO.mapOptional("DerivePointerBinding", Style.DerivePointerAlignment); + IO.mapOptional("KeepEmptyLinesAtEOF", Style.KeepEmptyLines.AtEndOfFile); + IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks", + Style.KeepEmptyLines.AtStartOfBlock); IO.mapOptional("IndentFunctionDeclarationAfterType", Style.IndentWrappedFunctionNames); IO.mapOptional("IndentRequires", Style.IndentRequiresClause); @@ -1004,9 +1015,7 @@ template <> struct MappingTraits { IO.mapOptional("JavaImportGroups", Style.JavaImportGroups); IO.mapOptional("JavaScriptQuotes", Style.JavaScriptQuotes); IO.mapOptional("JavaScriptWrapImports", Style.JavaScriptWrapImports); - IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks", - Style.KeepEmptyLinesAtTheStartOfBlocks); - IO.mapOptional("KeepEmptyLinesAtEOF", Style.KeepEmptyLinesAtEOF); + IO.mapOptional("KeepEmptyLines", Style.KeepEmptyLines); IO.mapOptional("LambdaBodyIndentation", Style.LambdaBodyIndentation); IO.mapOptional("LineEnding", Style.LineEnding); IO.mapOptional("MacroBlockBegin", Style.MacroBlockBegin); @@ -1517,8 +1526,11 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { /*Hex=*/0, /*HexMinDigits=*/0}; LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave; LLVMStyle.JavaScriptWrapImports = true; - LLVMStyle.KeepEmptyLinesAtEOF = false; - LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true; + LLVMStyle.KeepEmptyLines = { + /*AtEndOfFile=*/false, + /*AtStartOfBlock=*/true, + /*AtStartOfFile=*/true, + }; LLVMStyle.LambdaBodyIndentation = FormatStyle::LBI_Signature; LLVMStyle.Language = Language; LLVMStyle.LineEnding = FormatStyle::LE_DeriveLF; @@ -1641,7 +1653,7 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) { {".*", 3, 0, false}}; GoogleStyle.IncludeStyle.IncludeIsMainRegex = "([-_](test|unittest))?$"; GoogleStyle.IndentCaseLabels = true; - GoogleStyle.KeepEmptyLinesAtTheStartOfBlocks = false; + GoogleStyle.KeepEmptyLines.AtStartOfBlock = false; GoogleStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Never; GoogleStyle.ObjCSpaceAfterProperty = false; GoogleStyle.ObjCSpaceBeforeProtocolList = true; diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 89e134144d433c..03082cd2742c8c 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -176,10 +176,6 @@ class AnnotatingParser { Left->ParentBracket = Contexts.back().ContextKind; ScopedContextCreator ContextCreator(*this, tok::less, 12); - // If this angle is in the context of an expression, we need to be more - // hesitant to detect it as opening template parameters. - bool InExprContext = Contexts.back().IsExpression; - Contexts.back().IsExpression = false; // If there's a template keyword before the opening angle bracket, this is a // template parameter, not an argument. @@ -231,11 +227,8 @@ class AnnotatingParser { next(); continue; } - if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace) || - (CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext && - !Style.isCSharp() && !Style.isProto())) { + if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace)) return false; - } // If a && or || is found and interpreted as a binary operator, this set // of angles is likely part of something like "a < b && c > d". If the // angles are inside an expression, the ||/&& might also be a binary diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index 729f3d78f4a354..1804c1437fd41d 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -1478,11 +1478,13 @@ static auto computeNewlines(const AnnotatedLine &Line, Newlines = std::min(Newlines, 1u); if (Newlines == 0 && !RootToken.IsFirst) Newlines = 1; - if (RootToken.IsFirst && !RootToken.HasUnescapedNewline) + if (RootToken.IsFirst && + (!Style.KeepEmptyLines.AtStartOfFile || !RootToken.HasUnescapedNewline)) { Newlines = 0; + } // Remove empty lines after "{". - if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine && + if (!Style.KeepEmptyLines.AtStartOfBlock && PreviousLine && PreviousLine->Last->is(tok::l_brace) && !PreviousLine->startsWithNamespace() && !(PrevPrevLine && PrevPrevLine->startsWithNamespace() && @@ -1554,9 +1556,9 @@ void UnwrappedLineFormatter::formatFirstToken( unsigned NewlineIndent) { FormatToken &RootToken = *Line.First; if (RootToken.is(tok::eof)) { - unsigned Newlines = - std::min(RootToken.NewlinesBefore, - Style.KeepEmptyLinesAtEOF ? Style.MaxEmptyLinesToKeep + 1 : 1); + unsigned Newlines = std::min( + RootToken.NewlinesBefore, + Style.KeepEmptyLines.AtEndOfFile ? Style.MaxEmptyLinesToKeep + 1 : 1); unsigned TokenIndent = Newlines ? NewlineIndent : 0; Whitespaces->replaceWhitespace(RootToken, Newlines, TokenIndent, TokenIndent); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index a6d9f42ace9cc9..f42e28ba7e6294 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1468,6 +1468,17 @@ void CompilerInvocation::setDefaultPointerAuthOptions( // If you change anything here, be sure to update . Opts.FunctionPointers = PointerAuthSchema(Key::ASIA, false, Discrimination::None); + + Opts.CXXVTablePointers = PointerAuthSchema( + Key::ASDA, LangOpts.PointerAuthVTPtrAddressDiscrimination, + LangOpts.PointerAuthVTPtrTypeDiscrimination ? Discrimination::Type + : Discrimination::None); + Opts.CXXTypeInfoVTablePointer = + PointerAuthSchema(Key::ASDA, false, Discrimination::None); + Opts.CXXVTTVTablePointers = + PointerAuthSchema(Key::ASDA, false, Discrimination::None); + Opts.CXXVirtualFunctionPointers = Opts.CXXVirtualVariadicFunctionPointers = + PointerAuthSchema(Key::ASIA, true, Discrimination::Decl); } } diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index 2d5c94c7602522..55ec4600648308 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -934,6 +934,12 @@ static void InitializePredefinedMacros(const TargetInfo &TI, if (LangOpts.GNUCVersion && LangOpts.CPlusPlus11) Builder.defineMacro("__GXX_EXPERIMENTAL_CXX0X__"); + if (TI.getTriple().isWindowsGNUEnvironment()) { + // Set ABI defining macros for libstdc++ for MinGW, where the + // default in libstdc++ differs from the defaults for this target. + Builder.defineMacro("__GXX_TYPEINFO_EQUALITY_INLINE", "0"); + } + if (LangOpts.ObjC) { if (LangOpts.ObjCRuntime.isNonFragile()) { Builder.defineMacro("__OBJC2__"); diff --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h index 1a4bd02933ea23..40ac6dcac2ab8a 100644 --- a/clang/lib/Headers/ptrauth.h +++ b/clang/lib/Headers/ptrauth.h @@ -32,6 +32,10 @@ typedef enum { The extra data is always 0. */ ptrauth_key_function_pointer = ptrauth_key_process_independent_code, + /* The key used to sign C++ v-table pointers. + The extra data is always 0. */ + ptrauth_key_cxx_vtable_pointer = ptrauth_key_process_independent_data, + /* Other pointers signed under the ABI use private ABI rules. */ } ptrauth_key; @@ -205,6 +209,12 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t; #define ptrauth_sign_generic_data(__value, __data) \ __builtin_ptrauth_sign_generic_data(__value, __data) +/* C++ vtable pointer signing class attribute */ +#define ptrauth_cxx_vtable_pointer(key, address_discrimination, \ + extra_discrimination...) \ + [[clang::ptrauth_vtable_pointer(key, address_discrimination, \ + extra_discrimination)]] + #else #define ptrauth_strip(__value, __key) \ @@ -271,6 +281,10 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t; ((ptrauth_generic_signature_t)0); \ }) + +#define ptrauth_cxx_vtable_pointer(key, address_discrimination, \ + extra_discrimination...) + #endif /* __has_feature(ptrauth_intrinsics) */ #endif /* __PTRAUTH_H */ diff --git a/clang/lib/InstallAPI/Visitor.cpp b/clang/lib/InstallAPI/Visitor.cpp index 367ae53b208b63..a73ea0b0d124c2 100644 --- a/clang/lib/InstallAPI/Visitor.cpp +++ b/clang/lib/InstallAPI/Visitor.cpp @@ -447,16 +447,16 @@ InstallAPIVisitor::getMangledCXXVTableName(const CXXRecordDecl *D) const { return getBackendMangledName(Name); } -std::string -InstallAPIVisitor::getMangledCXXThunk(const GlobalDecl &D, - const ThunkInfo &Thunk) const { +std::string InstallAPIVisitor::getMangledCXXThunk( + const GlobalDecl &D, const ThunkInfo &Thunk, bool ElideOverrideInfo) const { SmallString<256> Name; raw_svector_ostream NameStream(Name); const auto *Method = cast(D.getDecl()); if (const auto *Dtor = dyn_cast(Method)) - MC->mangleCXXDtorThunk(Dtor, D.getDtorType(), Thunk.This, NameStream); + MC->mangleCXXDtorThunk(Dtor, D.getDtorType(), Thunk, ElideOverrideInfo, + NameStream); else - MC->mangleThunk(Method, Thunk, NameStream); + MC->mangleThunk(Method, Thunk, ElideOverrideInfo, NameStream); return getBackendMangledName(Name); } @@ -500,7 +500,8 @@ void InstallAPIVisitor::emitVTableSymbols(const CXXRecordDecl *D, return; for (const auto &Thunk : *Thunks) { - const std::string Name = getMangledCXXThunk(GD, Thunk); + const std::string Name = + getMangledCXXThunk(GD, Thunk, /*ElideOverrideInfo=*/true); auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported, GlobalRecord::Kind::Function, Avail, GD.getDecl(), Access); diff --git a/clang/lib/Interpreter/CodeCompletion.cpp b/clang/lib/Interpreter/CodeCompletion.cpp index 25183ae9eeb99e..791426807cb91d 100644 --- a/clang/lib/Interpreter/CodeCompletion.cpp +++ b/clang/lib/Interpreter/CodeCompletion.cpp @@ -368,8 +368,7 @@ void ReplCodeCompleter::codeComplete(CompilerInstance *InterpCI, llvm::SmallVector tb = {}; InterpCI->getFrontendOpts().Inputs[0] = FrontendInputFile( CodeCompletionFileName, Language::CXX, InputKind::Source); - auto Act = std::unique_ptr( - new IncrementalSyntaxOnlyAction(ParentCI)); + auto Act = std::make_unique(ParentCI); std::unique_ptr MB = llvm::MemoryBuffer::getMemBufferCopy(Content, CodeCompletionFileName); llvm::SmallVector RemappedFiles; diff --git a/clang/lib/Interpreter/DeviceOffload.cpp b/clang/lib/Interpreter/DeviceOffload.cpp index fb42964e4936f2..07c9e3005e5fd3 100644 --- a/clang/lib/Interpreter/DeviceOffload.cpp +++ b/clang/lib/Interpreter/DeviceOffload.cpp @@ -17,6 +17,7 @@ #include "clang/Frontend/CompilerInstance.h" #include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Module.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Target/TargetMachine.h" diff --git a/clang/lib/Lex/LiteralSupport.cpp b/clang/lib/Lex/LiteralSupport.cpp index 3df0391bdda772..9d2720af5dbd92 100644 --- a/clang/lib/Lex/LiteralSupport.cpp +++ b/clang/lib/Lex/LiteralSupport.cpp @@ -1123,8 +1123,9 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, break; // Invalid for floats if (HasSize) break; - if (DoubleUnderscore) - break; // Cannot be repeated. + // There is currently no way to reach this with DoubleUnderscore set. + // If new double underscope literals are added handle it here as above. + assert(!DoubleUnderscore && "unhandled double underscore case"); if (LangOpts.CPlusPlus && s + 2 < ThisTokEnd && s[1] == '_') { // s + 2 < ThisTokEnd to ensure some character exists // after __ diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index c5289174373327..a07f7ad2233fe6 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -368,6 +368,27 @@ static bool attributeIsTypeArgAttr(const IdentifierInfo &II) { #undef CLANG_ATTR_TYPE_ARG_LIST } +/// Determine whether the given attribute takes identifier arguments. +static bool attributeHasStrictIdentifierArgs(const IdentifierInfo &II) { +#define CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST + return (llvm::StringSwitch(normalizeAttrName(II.getName())) +#include "clang/Parse/AttrParserStringSwitches.inc" + .Default(0)) != 0; +#undef CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST +} + +/// Determine whether the given attribute takes an identifier argument at a +/// specific index +static bool attributeHasStrictIdentifierArgAtIndex(const IdentifierInfo &II, + size_t argIndex) { +#define CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST + return (llvm::StringSwitch(normalizeAttrName(II.getName())) +#include "clang/Parse/AttrParserStringSwitches.inc" + .Default(0)) & + (1ull << argIndex); +#undef CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST +} + /// Determine whether the given attribute requires parsing its arguments /// in an unevaluated context or not. static bool attributeParsedArgsUnevaluated(const IdentifierInfo &II) { @@ -546,7 +567,8 @@ unsigned Parser::ParseAttributeArgsCommon( } if (T.isUsable()) TheParsedType = T.get(); - } else if (AttributeHasVariadicIdentifierArg) { + } else if (AttributeHasVariadicIdentifierArg || + attributeHasStrictIdentifierArgs(*AttrName)) { // Parse variadic identifier arg. This can either consume identifiers or // expressions. Variadic identifier args do not support parameter packs // because those are typically used for attributes with enumeration @@ -557,6 +579,12 @@ unsigned Parser::ParseAttributeArgsCommon( if (ChangeKWThisToIdent && Tok.is(tok::kw_this)) Tok.setKind(tok::identifier); + if (Tok.is(tok::identifier) && attributeHasStrictIdentifierArgAtIndex( + *AttrName, ArgExprs.size())) { + ArgExprs.push_back(ParseIdentifierLoc()); + continue; + } + ExprResult ArgExpr; if (Tok.is(tok::identifier)) { ArgExprs.push_back(ParseIdentifierLoc()); diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 5e3ee5f0579aab..2fc43a7e7926b7 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -2681,6 +2681,10 @@ bool Parser::ParseCXXMemberDeclaratorBeforeInitializer( else DeclaratorInfo.SetIdentifier(nullptr, Tok.getLocation()); + if (getLangOpts().HLSL) + MaybeParseHLSLAnnotations(DeclaratorInfo, nullptr, + /*CouldBeBitField*/ true); + if (!DeclaratorInfo.isFunctionDeclarator() && TryConsumeToken(tok::colon)) { assert(DeclaratorInfo.isPastIdentifier() && "don't know where identifier would go yet?"); diff --git a/clang/lib/Parse/ParseHLSL.cpp b/clang/lib/Parse/ParseHLSL.cpp index 4b72afe9986e52..b36ea4012c26e1 100644 --- a/clang/lib/Parse/ParseHLSL.cpp +++ b/clang/lib/Parse/ParseHLSL.cpp @@ -119,9 +119,11 @@ static void fixSeparateAttrArgAndNumber(StringRef ArgStr, SourceLocation ArgLoc, } void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs, - SourceLocation *EndLoc) { + SourceLocation *EndLoc, + bool CouldBeBitField) { assert(Tok.is(tok::colon) && "Not a HLSL Annotation"); + Token OldToken = Tok; ConsumeToken(); IdentifierInfo *II = nullptr; @@ -131,6 +133,10 @@ void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs, II = Tok.getIdentifierInfo(); if (!II) { + if (CouldBeBitField) { + UnconsumeToken(OldToken); + return; + } Diag(Tok.getLocation(), diag::err_expected_semantic_identifier); return; } diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 50a872fedebf7c..326cd22ff90059 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -24,10 +24,10 @@ #include "clang/Sema/SemaAMDGPU.h" #include "clang/Sema/SemaCodeCompletion.h" #include "clang/Sema/SemaOpenMP.h" +#include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Frontend/OpenMP/OMPAssume.h" #include "llvm/Frontend/OpenMP/OMPContext.h" -#include #include using namespace clang; @@ -2146,7 +2146,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( case OMPD_requires: { SourceLocation StartLoc = ConsumeToken(); SmallVector Clauses; - std::bitset SeenClauses; + llvm::SmallBitVector SeenClauses(llvm::omp::Clause_enumSize + 1); if (Tok.is(tok::annot_pragma_openmp_end)) { Diag(Tok, diag::err_omp_expected_clause) << getOpenMPDirectiveName(OMPD_requires); @@ -2374,81 +2374,19 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( case OMPD_unknown: Diag(Tok, diag::err_omp_unknown_directive); break; - case OMPD_parallel: - case OMPD_simd: - case OMPD_tile: - case OMPD_unroll: - case OMPD_task: - case OMPD_taskyield: - case OMPD_barrier: - case OMPD_taskwait: - case OMPD_taskgroup: - case OMPD_flush: - case OMPD_depobj: - case OMPD_scan: - case OMPD_for: - case OMPD_for_simd: - case OMPD_sections: - case OMPD_section: - case OMPD_single: - case OMPD_master: - case OMPD_ordered: - case OMPD_critical: - case OMPD_parallel_for: - case OMPD_parallel_for_simd: - case OMPD_parallel_sections: - case OMPD_parallel_master: - case OMPD_parallel_masked: - case OMPD_atomic: - case OMPD_target: - case OMPD_teams: - case OMPD_cancellation_point: - case OMPD_cancel: - case OMPD_target_data: - case OMPD_target_enter_data: - case OMPD_target_exit_data: - case OMPD_target_parallel: - case OMPD_target_parallel_for: - case OMPD_taskloop: - case OMPD_taskloop_simd: - case OMPD_master_taskloop: - case OMPD_master_taskloop_simd: - case OMPD_parallel_master_taskloop: - case OMPD_parallel_master_taskloop_simd: - case OMPD_masked_taskloop: - case OMPD_masked_taskloop_simd: - case OMPD_parallel_masked_taskloop: - case OMPD_parallel_masked_taskloop_simd: - case OMPD_distribute: - case OMPD_target_update: - case OMPD_distribute_parallel_for: - case OMPD_distribute_parallel_for_simd: - case OMPD_distribute_simd: - case OMPD_target_parallel_for_simd: - case OMPD_target_simd: - case OMPD_scope: - case OMPD_teams_distribute: - case OMPD_teams_distribute_simd: - case OMPD_teams_distribute_parallel_for_simd: - case OMPD_teams_distribute_parallel_for: - case OMPD_target_teams: - case OMPD_target_teams_distribute: - case OMPD_target_teams_distribute_parallel_for: - case OMPD_target_teams_distribute_parallel_for_simd: - case OMPD_target_teams_distribute_simd: - case OMPD_dispatch: - case OMPD_masked: - case OMPD_metadirective: - case OMPD_loop: - case OMPD_teams_loop: - case OMPD_target_teams_loop: - case OMPD_parallel_loop: - case OMPD_target_parallel_loop: - Diag(Tok, diag::err_omp_unexpected_directive) - << 1 << getOpenMPDirectiveName(DKind); - break; default: - break; + switch (getDirectiveCategory(DKind)) { + case Category::Executable: + case Category::Meta: + case Category::Subsidiary: + case Category::Utility: + Diag(Tok, diag::err_omp_unexpected_directive) + << 1 << getOpenMPDirectiveName(DKind); + break; + case Category::Declarative: + case Category::Informational: + break; + } } while (Tok.isNot(tok::annot_pragma_openmp_end)) ConsumeAnyToken(); @@ -2456,6 +2394,184 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( return nullptr; } +StmtResult Parser::ParseOpenMPExecutableDirective( + ParsedStmtContext StmtCtx, OpenMPDirectiveKind DKind, SourceLocation Loc, + bool ReadDirectiveWithinMetadirective) { + assert(isOpenMPExecutableDirective(DKind) && "Unexpected directive category"); + + bool HasAssociatedStatement = true; + Association Assoc = getDirectiveAssociation(DKind); + + // OMPD_ordered has None as association, but it comes in two variants, + // the second of which is associated with a block. + // OMPD_scan and OMPD_section are both "separating", but section is treated + // as if it was associated with a statement, while scan is not. + if (DKind != OMPD_ordered && DKind != OMPD_section && + (Assoc == Association::None || Assoc == Association::Separating)) { + if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) == + ParsedStmtContext()) { + Diag(Tok, diag::err_omp_immediate_directive) + << getOpenMPDirectiveName(DKind) << 0; + if (DKind == OMPD_error) { + SkipUntil(tok::annot_pragma_openmp_end); + return StmtError(); + } + } + HasAssociatedStatement = false; + } + + SourceLocation EndLoc; + SmallVector Clauses; + llvm::SmallBitVector SeenClauses(llvm::omp::Clause_enumSize + 1); + DeclarationNameInfo DirName; + OpenMPDirectiveKind CancelRegion = OMPD_unknown; + unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope; + + // Special processing for flush and depobj clauses. + Token ImplicitTok; + bool ImplicitClauseAllowed = false; + if (DKind == OMPD_flush || DKind == OMPD_depobj) { + ImplicitTok = Tok; + ImplicitClauseAllowed = true; + } + ConsumeToken(); + // Parse directive name of the 'critical' directive if any. + if (DKind == OMPD_critical) { + BalancedDelimiterTracker T(*this, tok::l_paren, + tok::annot_pragma_openmp_end); + if (!T.consumeOpen()) { + if (Tok.isAnyIdentifier()) { + DirName = + DeclarationNameInfo(Tok.getIdentifierInfo(), Tok.getLocation()); + ConsumeAnyToken(); + } else { + Diag(Tok, diag::err_omp_expected_identifier_for_critical); + } + T.consumeClose(); + } + } else if (DKind == OMPD_cancellation_point || DKind == OMPD_cancel) { + CancelRegion = parseOpenMPDirectiveKind(*this); + if (Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeToken(); + } + + if (isOpenMPLoopDirective(DKind)) + ScopeFlags |= Scope::OpenMPLoopDirectiveScope; + if (isOpenMPSimdDirective(DKind)) + ScopeFlags |= Scope::OpenMPSimdDirectiveScope; + ParseScope OMPDirectiveScope(this, ScopeFlags); + Actions.OpenMP().StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(), + Loc); + + while (Tok.isNot(tok::annot_pragma_openmp_end)) { + // If we are parsing for a directive within a metadirective, the directive + // ends with a ')'. + if (ReadDirectiveWithinMetadirective && Tok.is(tok::r_paren)) { + while (Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + break; + } + bool HasImplicitClause = false; + if (ImplicitClauseAllowed && Tok.is(tok::l_paren)) { + HasImplicitClause = true; + // Push copy of the current token back to stream to properly parse + // pseudo-clause OMPFlushClause or OMPDepobjClause. + PP.EnterToken(Tok, /*IsReinject*/ true); + PP.EnterToken(ImplicitTok, /*IsReinject*/ true); + ConsumeAnyToken(); + } + OpenMPClauseKind CKind = Tok.isAnnotation() + ? OMPC_unknown + : getOpenMPClauseKind(PP.getSpelling(Tok)); + if (HasImplicitClause) { + assert(CKind == OMPC_unknown && "Must be unknown implicit clause."); + if (DKind == OMPD_flush) { + CKind = OMPC_flush; + } else { + assert(DKind == OMPD_depobj && "Expected flush or depobj directives."); + CKind = OMPC_depobj; + } + } + // No more implicit clauses allowed. + ImplicitClauseAllowed = false; + Actions.OpenMP().StartOpenMPClause(CKind); + HasImplicitClause = false; + OMPClause *Clause = + ParseOpenMPClause(DKind, CKind, !SeenClauses[unsigned(CKind)]); + SeenClauses[unsigned(CKind)] = true; + if (Clause) + Clauses.push_back(Clause); + + // Skip ',' if any. + if (Tok.is(tok::comma)) + ConsumeToken(); + Actions.OpenMP().EndOpenMPClause(); + } + // End location of the directive. + EndLoc = Tok.getLocation(); + // Consume final annot_pragma_openmp_end. + ConsumeAnnotationToken(); + + if (DKind == OMPD_ordered) { + // If the depend or doacross clause is specified, the ordered construct + // is a stand-alone directive. + for (auto CK : {OMPC_depend, OMPC_doacross}) { + if (SeenClauses[unsigned(CK)]) { + if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) == + ParsedStmtContext()) { + Diag(Loc, diag::err_omp_immediate_directive) + << getOpenMPDirectiveName(DKind) << 1 << getOpenMPClauseName(CK); + } + HasAssociatedStatement = false; + } + } + } + + if (DKind == OMPD_tile && !SeenClauses[unsigned(OMPC_sizes)]) { + Diag(Loc, diag::err_omp_required_clause) + << getOpenMPDirectiveName(OMPD_tile) << "sizes"; + } + + StmtResult AssociatedStmt; + if (HasAssociatedStatement) { + // The body is a block scope like in Lambdas and Blocks. + Actions.OpenMP().ActOnOpenMPRegionStart(DKind, getCurScope()); + // FIXME: We create a bogus CompoundStmt scope to hold the contents of + // the captured region. Code elsewhere assumes that any FunctionScopeInfo + // should have at least one compound statement scope within it. + ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false); + { + Sema::CompoundScopeRAII Scope(Actions); + AssociatedStmt = ParseStatement(); + + if (AssociatedStmt.isUsable() && isOpenMPLoopDirective(DKind) && + getLangOpts().OpenMPIRBuilder) + AssociatedStmt = + Actions.OpenMP().ActOnOpenMPLoopnest(AssociatedStmt.get()); + } + AssociatedStmt = + Actions.OpenMP().ActOnOpenMPRegionEnd(AssociatedStmt, Clauses); + } else if (DKind == OMPD_target_update || DKind == OMPD_target_enter_data || + DKind == OMPD_target_exit_data) { + Actions.OpenMP().ActOnOpenMPRegionStart(DKind, getCurScope()); + AssociatedStmt = (Sema::CompoundScopeRAII(Actions), + Actions.ActOnCompoundStmt(Loc, Loc, std::nullopt, + /*isStmtExpr=*/false)); + AssociatedStmt = + Actions.OpenMP().ActOnOpenMPRegionEnd(AssociatedStmt, Clauses); + } + + StmtResult Directive = Actions.OpenMP().ActOnOpenMPExecutableDirective( + DKind, DirName, CancelRegion, Clauses, AssociatedStmt.get(), Loc, EndLoc); + + // Exit scope. + Actions.OpenMP().EndOpenMPDSABlock(Directive.get()); + OMPDirectiveScope.Exit(); + + return Directive; +} + /// Parsing of declarative or executable OpenMP directives. /// /// threadprivate-directive: @@ -2503,24 +2619,30 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( "Not an OpenMP directive!"); ParsingOpenMPDirectiveRAII DirScope(*this); ParenBraceBracketBalancer BalancerRAIIObj(*this); - SmallVector Clauses; - std::bitset SeenClauses; - unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope | - Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope; SourceLocation Loc = ReadDirectiveWithinMetadirective ? Tok.getLocation() - : ConsumeAnnotationToken(), - EndLoc; + : ConsumeAnnotationToken(); OpenMPDirectiveKind DKind = parseOpenMPDirectiveKind(*this); if (ReadDirectiveWithinMetadirective && DKind == OMPD_unknown) { Diag(Tok, diag::err_omp_unknown_directive); return StmtError(); } - OpenMPDirectiveKind CancelRegion = OMPD_unknown; - // Name of critical directive. - DeclarationNameInfo DirName; + StmtResult Directive = StmtError(); - bool HasAssociatedStatement = true; + + bool IsExecutable = [&]() { + if (DKind == OMPD_error) // OMPD_error is handled as executable + return true; + auto Res = getDirectiveCategory(DKind); + return Res == Category::Executable || Res == Category::Subsidiary; + }(); + + if (IsExecutable) { + Directive = ParseOpenMPExecutableDirective( + StmtCtx, DKind, Loc, ReadDirectiveWithinMetadirective); + assert(!Directive.isUnset() && "Executable directive remained unprocessed"); + return Directive; + } switch (DKind) { case OMPD_nothing: @@ -2709,7 +2831,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( /*AllowScopeSpecifier=*/false)) { SmallVector Clauses; if (Tok.isNot(tok::annot_pragma_openmp_end)) { - std::bitset SeenClauses; + llvm::SmallBitVector SeenClauses(llvm::omp::Clause_enumSize + 1); while (Tok.isNot(tok::annot_pragma_openmp_end)) { OpenMPClauseKind CKind = Tok.isAnnotation() ? OMPC_unknown @@ -2763,233 +2885,6 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( } break; } - case OMPD_flush: - case OMPD_depobj: - case OMPD_scan: - case OMPD_taskyield: - case OMPD_error: - case OMPD_barrier: - case OMPD_taskwait: - case OMPD_cancellation_point: - case OMPD_cancel: - case OMPD_target_enter_data: - case OMPD_target_exit_data: - case OMPD_target_update: - case OMPD_interop: - if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) == - ParsedStmtContext()) { - Diag(Tok, diag::err_omp_immediate_directive) - << getOpenMPDirectiveName(DKind) << 0; - if (DKind == OMPD_error) { - SkipUntil(tok::annot_pragma_openmp_end); - break; - } - } - HasAssociatedStatement = false; - // Fall through for further analysis. - [[fallthrough]]; - case OMPD_parallel: - case OMPD_simd: - case OMPD_tile: - case OMPD_unroll: - case OMPD_for: - case OMPD_for_simd: - case OMPD_sections: - case OMPD_single: - case OMPD_section: - case OMPD_master: - case OMPD_critical: - case OMPD_parallel_for: - case OMPD_parallel_for_simd: - case OMPD_parallel_sections: - case OMPD_parallel_master: - case OMPD_parallel_masked: - case OMPD_task: - case OMPD_ordered: - case OMPD_atomic: - case OMPD_target: - case OMPD_teams: - case OMPD_taskgroup: - case OMPD_target_data: - case OMPD_target_parallel: - case OMPD_target_parallel_for: - case OMPD_loop: - case OMPD_teams_loop: - case OMPD_target_teams_loop: - case OMPD_parallel_loop: - case OMPD_target_parallel_loop: - case OMPD_scope: - case OMPD_taskloop: - case OMPD_taskloop_simd: - case OMPD_master_taskloop: - case OMPD_masked_taskloop: - case OMPD_master_taskloop_simd: - case OMPD_masked_taskloop_simd: - case OMPD_parallel_master_taskloop: - case OMPD_parallel_masked_taskloop: - case OMPD_parallel_master_taskloop_simd: - case OMPD_parallel_masked_taskloop_simd: - case OMPD_distribute: - case OMPD_distribute_parallel_for: - case OMPD_distribute_parallel_for_simd: - case OMPD_distribute_simd: - case OMPD_target_parallel_for_simd: - case OMPD_target_simd: - case OMPD_teams_distribute: - case OMPD_teams_distribute_simd: - case OMPD_teams_distribute_parallel_for_simd: - case OMPD_teams_distribute_parallel_for: - case OMPD_target_teams: - case OMPD_target_teams_distribute: - case OMPD_target_teams_distribute_parallel_for: - case OMPD_target_teams_distribute_parallel_for_simd: - case OMPD_target_teams_distribute_simd: - case OMPD_dispatch: - case OMPD_masked: { - // Special processing for flush and depobj clauses. - Token ImplicitTok; - bool ImplicitClauseAllowed = false; - if (DKind == OMPD_flush || DKind == OMPD_depobj) { - ImplicitTok = Tok; - ImplicitClauseAllowed = true; - } - ConsumeToken(); - // Parse directive name of the 'critical' directive if any. - if (DKind == OMPD_critical) { - BalancedDelimiterTracker T(*this, tok::l_paren, - tok::annot_pragma_openmp_end); - if (!T.consumeOpen()) { - if (Tok.isAnyIdentifier()) { - DirName = - DeclarationNameInfo(Tok.getIdentifierInfo(), Tok.getLocation()); - ConsumeAnyToken(); - } else { - Diag(Tok, diag::err_omp_expected_identifier_for_critical); - } - T.consumeClose(); - } - } else if (DKind == OMPD_cancellation_point || DKind == OMPD_cancel) { - CancelRegion = parseOpenMPDirectiveKind(*this); - if (Tok.isNot(tok::annot_pragma_openmp_end)) - ConsumeToken(); - } - - if (isOpenMPLoopDirective(DKind)) - ScopeFlags |= Scope::OpenMPLoopDirectiveScope; - if (isOpenMPSimdDirective(DKind)) - ScopeFlags |= Scope::OpenMPSimdDirectiveScope; - ParseScope OMPDirectiveScope(this, ScopeFlags); - Actions.OpenMP().StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(), - Loc); - - while (Tok.isNot(tok::annot_pragma_openmp_end)) { - // If we are parsing for a directive within a metadirective, the directive - // ends with a ')'. - if (ReadDirectiveWithinMetadirective && Tok.is(tok::r_paren)) { - while (Tok.isNot(tok::annot_pragma_openmp_end)) - ConsumeAnyToken(); - break; - } - bool HasImplicitClause = false; - if (ImplicitClauseAllowed && Tok.is(tok::l_paren)) { - HasImplicitClause = true; - // Push copy of the current token back to stream to properly parse - // pseudo-clause OMPFlushClause or OMPDepobjClause. - PP.EnterToken(Tok, /*IsReinject*/ true); - PP.EnterToken(ImplicitTok, /*IsReinject*/ true); - ConsumeAnyToken(); - } - OpenMPClauseKind CKind = Tok.isAnnotation() - ? OMPC_unknown - : getOpenMPClauseKind(PP.getSpelling(Tok)); - if (HasImplicitClause) { - assert(CKind == OMPC_unknown && "Must be unknown implicit clause."); - if (DKind == OMPD_flush) { - CKind = OMPC_flush; - } else { - assert(DKind == OMPD_depobj && - "Expected flush or depobj directives."); - CKind = OMPC_depobj; - } - } - // No more implicit clauses allowed. - ImplicitClauseAllowed = false; - Actions.OpenMP().StartOpenMPClause(CKind); - HasImplicitClause = false; - OMPClause *Clause = - ParseOpenMPClause(DKind, CKind, !SeenClauses[unsigned(CKind)]); - SeenClauses[unsigned(CKind)] = true; - if (Clause) - Clauses.push_back(Clause); - - // Skip ',' if any. - if (Tok.is(tok::comma)) - ConsumeToken(); - Actions.OpenMP().EndOpenMPClause(); - } - // End location of the directive. - EndLoc = Tok.getLocation(); - // Consume final annot_pragma_openmp_end. - ConsumeAnnotationToken(); - - if (DKind == OMPD_ordered) { - // If the depend or doacross clause is specified, the ordered construct - // is a stand-alone directive. - for (auto CK : {OMPC_depend, OMPC_doacross}) { - if (SeenClauses[unsigned(CK)]) { - if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) == - ParsedStmtContext()) { - Diag(Loc, diag::err_omp_immediate_directive) - << getOpenMPDirectiveName(DKind) << 1 - << getOpenMPClauseName(CK); - } - HasAssociatedStatement = false; - } - } - } - - if (DKind == OMPD_tile && !SeenClauses[unsigned(OMPC_sizes)]) { - Diag(Loc, diag::err_omp_required_clause) - << getOpenMPDirectiveName(OMPD_tile) << "sizes"; - } - - StmtResult AssociatedStmt; - if (HasAssociatedStatement) { - // The body is a block scope like in Lambdas and Blocks. - Actions.OpenMP().ActOnOpenMPRegionStart(DKind, getCurScope()); - // FIXME: We create a bogus CompoundStmt scope to hold the contents of - // the captured region. Code elsewhere assumes that any FunctionScopeInfo - // should have at least one compound statement scope within it. - ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false); - { - Sema::CompoundScopeRAII Scope(Actions); - AssociatedStmt = ParseStatement(); - - if (AssociatedStmt.isUsable() && isOpenMPLoopDirective(DKind) && - getLangOpts().OpenMPIRBuilder) - AssociatedStmt = - Actions.OpenMP().ActOnOpenMPLoopnest(AssociatedStmt.get()); - } - AssociatedStmt = - Actions.OpenMP().ActOnOpenMPRegionEnd(AssociatedStmt, Clauses); - } else if (DKind == OMPD_target_update || DKind == OMPD_target_enter_data || - DKind == OMPD_target_exit_data) { - Actions.OpenMP().ActOnOpenMPRegionStart(DKind, getCurScope()); - AssociatedStmt = (Sema::CompoundScopeRAII(Actions), - Actions.ActOnCompoundStmt(Loc, Loc, std::nullopt, - /*isStmtExpr=*/false)); - AssociatedStmt = - Actions.OpenMP().ActOnOpenMPRegionEnd(AssociatedStmt, Clauses); - } - Directive = Actions.OpenMP().ActOnOpenMPExecutableDirective( - DKind, DirName, CancelRegion, Clauses, AssociatedStmt.get(), Loc, - EndLoc); - - // Exit scope. - Actions.OpenMP().EndOpenMPDSABlock(Directive.get()); - OMPDirectiveScope.Exit(); - break; - } case OMPD_declare_target: { SourceLocation DTLoc = ConsumeAnyToken(); bool HasClauses = Tok.isNot(tok::annot_pragma_openmp_end); @@ -4785,8 +4680,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, getLangOpts()); Data.ExtraModifierLoc = Tok.getLocation(); if (Data.ExtraModifier == OMPC_ADJUST_ARGS_unknown) { - SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, - StopBeforeMatch); + Diag(Tok, diag::err_omp_unknown_adjust_args_op); + SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); } else { ConsumeToken(); if (Tok.is(tok::colon)) @@ -4799,7 +4694,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, bool IsComma = (Kind != OMPC_reduction && Kind != OMPC_task_reduction && Kind != OMPC_in_reduction && Kind != OMPC_depend && - Kind != OMPC_doacross && Kind != OMPC_map) || + Kind != OMPC_doacross && Kind != OMPC_map && Kind != OMPC_adjust_args) || (Kind == OMPC_reduction && !InvalidReductionId) || (Kind == OMPC_map && Data.ExtraModifier != OMPC_MAP_unknown) || (Kind == OMPC_depend && Data.ExtraModifier != OMPC_DEPEND_unknown) || diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 6d0cf7b174e50e..71b87147e9a5f1 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -2060,9 +2060,19 @@ bool Parser::TryAnnotateTypeOrScopeToken( return true; } + bool TemplateKWPresent = false; + if (Tok.is(tok::kw_template)) { + ConsumeToken(); + TemplateKWPresent = true; + } + TypeResult Ty; if (Tok.is(tok::identifier)) { - // FIXME: check whether the next token is '<', first! + if (TemplateKWPresent && NextToken().isNot(tok::less)) { + Diag(Tok.getLocation(), + diag::missing_template_arg_list_after_template_kw); + return true; + } Ty = Actions.ActOnTypenameType(getCurScope(), TypenameLoc, SS, *Tok.getIdentifierInfo(), Tok.getLocation()); diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index f152d243d39a5b..980a83d4431aa2 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -15,6 +15,7 @@ clang_tablegen(OpenCLBuiltins.inc -gen-clang-opencl-builtins add_clang_library(clangSema AnalysisBasedWarnings.cpp + CheckExprLifetime.cpp CodeCompleteConsumer.cpp DeclSpec.cpp DelayedDiagnostic.cpp diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp new file mode 100644 index 00000000000000..54e2f1c22536dd --- /dev/null +++ b/clang/lib/Sema/CheckExprLifetime.cpp @@ -0,0 +1,1259 @@ +//===--- CheckExprLifetime.cpp --------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "CheckExprLifetime.h" +#include "clang/AST/Expr.h" +#include "clang/Sema/Sema.h" +#include "llvm/ADT/PointerIntPair.h" + +namespace clang::sema { +namespace { +enum LifetimeKind { + /// The lifetime of a temporary bound to this entity ends at the end of the + /// full-expression, and that's (probably) fine. + LK_FullExpression, + + /// The lifetime of a temporary bound to this entity is extended to the + /// lifeitme of the entity itself. + LK_Extended, + + /// The lifetime of a temporary bound to this entity probably ends too soon, + /// because the entity is allocated in a new-expression. + LK_New, + + /// The lifetime of a temporary bound to this entity ends too soon, because + /// the entity is a return object. + LK_Return, + + /// The lifetime of a temporary bound to this entity ends too soon, because + /// the entity is the result of a statement expression. + LK_StmtExprResult, + + /// This is a mem-initializer: if it would extend a temporary (other than via + /// a default member initializer), the program is ill-formed. + LK_MemInitializer, +}; +using LifetimeResult = + llvm::PointerIntPair; +} // namespace + +/// Determine the declaration which an initialized entity ultimately refers to, +/// for the purpose of lifetime-extending a temporary bound to a reference in +/// the initialization of \p Entity. +static LifetimeResult +getEntityLifetime(const InitializedEntity *Entity, + const InitializedEntity *InitField = nullptr) { + // C++11 [class.temporary]p5: + switch (Entity->getKind()) { + case InitializedEntity::EK_Variable: + // The temporary [...] persists for the lifetime of the reference + return {Entity, LK_Extended}; + + case InitializedEntity::EK_Member: + // For subobjects, we look at the complete object. + if (Entity->getParent()) + return getEntityLifetime(Entity->getParent(), Entity); + + // except: + // C++17 [class.base.init]p8: + // A temporary expression bound to a reference member in a + // mem-initializer is ill-formed. + // C++17 [class.base.init]p11: + // A temporary expression bound to a reference member from a + // default member initializer is ill-formed. + // + // The context of p11 and its example suggest that it's only the use of a + // default member initializer from a constructor that makes the program + // ill-formed, not its mere existence, and that it can even be used by + // aggregate initialization. + return {Entity, Entity->isDefaultMemberInitializer() ? LK_Extended + : LK_MemInitializer}; + + case InitializedEntity::EK_Binding: + // Per [dcl.decomp]p3, the binding is treated as a variable of reference + // type. + return {Entity, LK_Extended}; + + case InitializedEntity::EK_Parameter: + case InitializedEntity::EK_Parameter_CF_Audited: + // -- A temporary bound to a reference parameter in a function call + // persists until the completion of the full-expression containing + // the call. + return {nullptr, LK_FullExpression}; + + case InitializedEntity::EK_TemplateParameter: + // FIXME: This will always be ill-formed; should we eagerly diagnose it + // here? + return {nullptr, LK_FullExpression}; + + case InitializedEntity::EK_Result: + // -- The lifetime of a temporary bound to the returned value in a + // function return statement is not extended; the temporary is + // destroyed at the end of the full-expression in the return statement. + return {nullptr, LK_Return}; + + case InitializedEntity::EK_StmtExprResult: + // FIXME: Should we lifetime-extend through the result of a statement + // expression? + return {nullptr, LK_StmtExprResult}; + + case InitializedEntity::EK_New: + // -- A temporary bound to a reference in a new-initializer persists + // until the completion of the full-expression containing the + // new-initializer. + return {nullptr, LK_New}; + + case InitializedEntity::EK_Temporary: + case InitializedEntity::EK_CompoundLiteralInit: + case InitializedEntity::EK_RelatedResult: + // We don't yet know the storage duration of the surrounding temporary. + // Assume it's got full-expression duration for now, it will patch up our + // storage duration if that's not correct. + return {nullptr, LK_FullExpression}; + + case InitializedEntity::EK_ArrayElement: + // For subobjects, we look at the complete object. + return getEntityLifetime(Entity->getParent(), InitField); + + case InitializedEntity::EK_Base: + // For subobjects, we look at the complete object. + if (Entity->getParent()) + return getEntityLifetime(Entity->getParent(), InitField); + return {InitField, LK_MemInitializer}; + + case InitializedEntity::EK_Delegating: + // We can reach this case for aggregate initialization in a constructor: + // struct A { int &&r; }; + // struct B : A { B() : A{0} {} }; + // In this case, use the outermost field decl as the context. + return {InitField, LK_MemInitializer}; + + case InitializedEntity::EK_BlockElement: + case InitializedEntity::EK_LambdaToBlockConversionBlockElement: + case InitializedEntity::EK_LambdaCapture: + case InitializedEntity::EK_VectorElement: + case InitializedEntity::EK_ComplexElement: + return {nullptr, LK_FullExpression}; + + case InitializedEntity::EK_Exception: + // FIXME: Can we diagnose lifetime problems with exceptions? + return {nullptr, LK_FullExpression}; + + case InitializedEntity::EK_ParenAggInitMember: + // -- A temporary object bound to a reference element of an aggregate of + // class type initialized from a parenthesized expression-list + // [dcl.init, 9.3] persists until the completion of the full-expression + // containing the expression-list. + return {nullptr, LK_FullExpression}; + } + + llvm_unreachable("unknown entity kind"); +} + +namespace { +enum ReferenceKind { + /// Lifetime would be extended by a reference binding to a temporary. + RK_ReferenceBinding, + /// Lifetime would be extended by a std::initializer_list object binding to + /// its backing array. + RK_StdInitializerList, +}; + +/// A temporary or local variable. This will be one of: +/// * A MaterializeTemporaryExpr. +/// * A DeclRefExpr whose declaration is a local. +/// * An AddrLabelExpr. +/// * A BlockExpr for a block with captures. +using Local = Expr *; + +/// Expressions we stepped over when looking for the local state. Any steps +/// that would inhibit lifetime extension or take us out of subexpressions of +/// the initializer are included. +struct IndirectLocalPathEntry { + enum EntryKind { + DefaultInit, + AddressOf, + VarInit, + LValToRVal, + LifetimeBoundCall, + TemporaryCopy, + LambdaCaptureInit, + GslReferenceInit, + GslPointerInit + } Kind; + Expr *E; + union { + const Decl *D = nullptr; + const LambdaCapture *Capture; + }; + IndirectLocalPathEntry() {} + IndirectLocalPathEntry(EntryKind K, Expr *E) : Kind(K), E(E) {} + IndirectLocalPathEntry(EntryKind K, Expr *E, const Decl *D) + : Kind(K), E(E), D(D) {} + IndirectLocalPathEntry(EntryKind K, Expr *E, const LambdaCapture *Capture) + : Kind(K), E(E), Capture(Capture) {} +}; + +using IndirectLocalPath = llvm::SmallVectorImpl; + +struct RevertToOldSizeRAII { + IndirectLocalPath &Path; + unsigned OldSize = Path.size(); + RevertToOldSizeRAII(IndirectLocalPath &Path) : Path(Path) {} + ~RevertToOldSizeRAII() { Path.resize(OldSize); } +}; + +using LocalVisitor = llvm::function_ref; +} // namespace + +static bool isVarOnPath(IndirectLocalPath &Path, VarDecl *VD) { + for (auto E : Path) + if (E.Kind == IndirectLocalPathEntry::VarInit && E.D == VD) + return true; + return false; +} + +static bool pathContainsInit(IndirectLocalPath &Path) { + return llvm::any_of(Path, [=](IndirectLocalPathEntry E) { + return E.Kind == IndirectLocalPathEntry::DefaultInit || + E.Kind == IndirectLocalPathEntry::VarInit; + }); +} + +static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path, + Expr *Init, LocalVisitor Visit, + bool RevisitSubinits, + bool EnableLifetimeWarnings); + +static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path, + Expr *Init, ReferenceKind RK, + LocalVisitor Visit, + bool EnableLifetimeWarnings); + +template static bool isRecordWithAttr(QualType Type) { + if (auto *RD = Type->getAsCXXRecordDecl()) + return RD->hasAttr(); + return false; +} + +// Decl::isInStdNamespace will return false for iterators in some STL +// implementations due to them being defined in a namespace outside of the std +// namespace. +static bool isInStlNamespace(const Decl *D) { + const DeclContext *DC = D->getDeclContext(); + if (!DC) + return false; + if (const auto *ND = dyn_cast(DC)) + if (const IdentifierInfo *II = ND->getIdentifier()) { + StringRef Name = II->getName(); + if (Name.size() >= 2 && Name.front() == '_' && + (Name[1] == '_' || isUppercase(Name[1]))) + return true; + } + + return DC->isStdNamespace(); +} + +static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) { + if (auto *Conv = dyn_cast_or_null(Callee)) + if (isRecordWithAttr(Conv->getConversionType())) + return true; + if (!isInStlNamespace(Callee->getParent())) + return false; + if (!isRecordWithAttr( + Callee->getFunctionObjectParameterType()) && + !isRecordWithAttr(Callee->getFunctionObjectParameterType())) + return false; + if (Callee->getReturnType()->isPointerType() || + isRecordWithAttr(Callee->getReturnType())) { + if (!Callee->getIdentifier()) + return false; + return llvm::StringSwitch(Callee->getName()) + .Cases("begin", "rbegin", "cbegin", "crbegin", true) + .Cases("end", "rend", "cend", "crend", true) + .Cases("c_str", "data", "get", true) + // Map and set types. + .Cases("find", "equal_range", "lower_bound", "upper_bound", true) + .Default(false); + } else if (Callee->getReturnType()->isReferenceType()) { + if (!Callee->getIdentifier()) { + auto OO = Callee->getOverloadedOperator(); + return OO == OverloadedOperatorKind::OO_Subscript || + OO == OverloadedOperatorKind::OO_Star; + } + return llvm::StringSwitch(Callee->getName()) + .Cases("front", "back", "at", "top", "value", true) + .Default(false); + } + return false; +} + +static bool shouldTrackFirstArgument(const FunctionDecl *FD) { + if (!FD->getIdentifier() || FD->getNumParams() != 1) + return false; + const auto *RD = FD->getParamDecl(0)->getType()->getPointeeCXXRecordDecl(); + if (!FD->isInStdNamespace() || !RD || !RD->isInStdNamespace()) + return false; + if (!isRecordWithAttr(QualType(RD->getTypeForDecl(), 0)) && + !isRecordWithAttr(QualType(RD->getTypeForDecl(), 0))) + return false; + if (FD->getReturnType()->isPointerType() || + isRecordWithAttr(FD->getReturnType())) { + return llvm::StringSwitch(FD->getName()) + .Cases("begin", "rbegin", "cbegin", "crbegin", true) + .Cases("end", "rend", "cend", "crend", true) + .Case("data", true) + .Default(false); + } else if (FD->getReturnType()->isReferenceType()) { + return llvm::StringSwitch(FD->getName()) + .Cases("get", "any_cast", true) + .Default(false); + } + return false; +} + +static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call, + LocalVisitor Visit) { + auto VisitPointerArg = [&](const Decl *D, Expr *Arg, bool Value) { + // We are not interested in the temporary base objects of gsl Pointers: + // Temp().ptr; // Here ptr might not dangle. + if (isa(Arg->IgnoreImpCasts())) + return; + // Once we initialized a value with a reference, it can no longer dangle. + if (!Value) { + for (const IndirectLocalPathEntry &PE : llvm::reverse(Path)) { + if (PE.Kind == IndirectLocalPathEntry::GslReferenceInit) + continue; + if (PE.Kind == IndirectLocalPathEntry::GslPointerInit) + return; + break; + } + } + Path.push_back({Value ? IndirectLocalPathEntry::GslPointerInit + : IndirectLocalPathEntry::GslReferenceInit, + Arg, D}); + if (Arg->isGLValue()) + visitLocalsRetainedByReferenceBinding(Path, Arg, RK_ReferenceBinding, + Visit, + /*EnableLifetimeWarnings=*/true); + else + visitLocalsRetainedByInitializer(Path, Arg, Visit, true, + /*EnableLifetimeWarnings=*/true); + Path.pop_back(); + }; + + if (auto *MCE = dyn_cast(Call)) { + const auto *MD = cast_or_null(MCE->getDirectCallee()); + if (MD && shouldTrackImplicitObjectArg(MD)) + VisitPointerArg(MD, MCE->getImplicitObjectArgument(), + !MD->getReturnType()->isReferenceType()); + return; + } else if (auto *OCE = dyn_cast(Call)) { + FunctionDecl *Callee = OCE->getDirectCallee(); + if (Callee && Callee->isCXXInstanceMember() && + shouldTrackImplicitObjectArg(cast(Callee))) + VisitPointerArg(Callee, OCE->getArg(0), + !Callee->getReturnType()->isReferenceType()); + return; + } else if (auto *CE = dyn_cast(Call)) { + FunctionDecl *Callee = CE->getDirectCallee(); + if (Callee && shouldTrackFirstArgument(Callee)) + VisitPointerArg(Callee, CE->getArg(0), + !Callee->getReturnType()->isReferenceType()); + return; + } + + if (auto *CCE = dyn_cast(Call)) { + const auto *Ctor = CCE->getConstructor(); + const CXXRecordDecl *RD = Ctor->getParent(); + if (CCE->getNumArgs() > 0 && RD->hasAttr()) + VisitPointerArg(Ctor->getParamDecl(0), CCE->getArgs()[0], true); + } +} + +static bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD) { + const TypeSourceInfo *TSI = FD->getTypeSourceInfo(); + if (!TSI) + return false; + // Don't declare this variable in the second operand of the for-statement; + // GCC miscompiles that by ending its lifetime before evaluating the + // third operand. See gcc.gnu.org/PR86769. + AttributedTypeLoc ATL; + for (TypeLoc TL = TSI->getTypeLoc(); + (ATL = TL.getAsAdjusted()); + TL = ATL.getModifiedLoc()) { + if (ATL.getAttrAs()) + return true; + } + + // Assume that all assignment operators with a "normal" return type return + // *this, that is, an lvalue reference that is the same type as the implicit + // object parameter (or the LHS for a non-member operator$=). + OverloadedOperatorKind OO = FD->getDeclName().getCXXOverloadedOperator(); + if (OO == OO_Equal || isCompoundAssignmentOperator(OO)) { + QualType RetT = FD->getReturnType(); + if (RetT->isLValueReferenceType()) { + ASTContext &Ctx = FD->getASTContext(); + QualType LHST; + auto *MD = dyn_cast(FD); + if (MD && MD->isCXXInstanceMember()) + LHST = Ctx.getLValueReferenceType(MD->getFunctionObjectParameterType()); + else + LHST = MD->getParamDecl(0)->getType(); + if (Ctx.hasSameType(RetT, LHST)) + return true; + } + } + + return false; +} + +static void visitLifetimeBoundArguments(IndirectLocalPath &Path, Expr *Call, + LocalVisitor Visit) { + const FunctionDecl *Callee; + ArrayRef Args; + + if (auto *CE = dyn_cast(Call)) { + Callee = CE->getDirectCallee(); + Args = llvm::ArrayRef(CE->getArgs(), CE->getNumArgs()); + } else { + auto *CCE = cast(Call); + Callee = CCE->getConstructor(); + Args = llvm::ArrayRef(CCE->getArgs(), CCE->getNumArgs()); + } + if (!Callee) + return; + + Expr *ObjectArg = nullptr; + if (isa(Call) && Callee->isCXXInstanceMember()) { + ObjectArg = Args[0]; + Args = Args.slice(1); + } else if (auto *MCE = dyn_cast(Call)) { + ObjectArg = MCE->getImplicitObjectArgument(); + } + + auto VisitLifetimeBoundArg = [&](const Decl *D, Expr *Arg) { + Path.push_back({IndirectLocalPathEntry::LifetimeBoundCall, Arg, D}); + if (Arg->isGLValue()) + visitLocalsRetainedByReferenceBinding(Path, Arg, RK_ReferenceBinding, + Visit, + /*EnableLifetimeWarnings=*/false); + else + visitLocalsRetainedByInitializer(Path, Arg, Visit, true, + /*EnableLifetimeWarnings=*/false); + Path.pop_back(); + }; + + bool CheckCoroCall = false; + if (const auto *RD = Callee->getReturnType()->getAsRecordDecl()) { + CheckCoroCall = RD->hasAttr() && + RD->hasAttr() && + !Callee->hasAttr(); + } + + if (ObjectArg) { + bool CheckCoroObjArg = CheckCoroCall; + // Coroutine lambda objects with empty capture list are not lifetimebound. + if (auto *LE = dyn_cast(ObjectArg->IgnoreImplicit()); + LE && LE->captures().empty()) + CheckCoroObjArg = false; + // Allow `get_return_object()` as the object param (__promise) is not + // lifetimebound. + if (Sema::CanBeGetReturnObject(Callee)) + CheckCoroObjArg = false; + if (implicitObjectParamIsLifetimeBound(Callee) || CheckCoroObjArg) + VisitLifetimeBoundArg(Callee, ObjectArg); + } + + for (unsigned I = 0, + N = std::min(Callee->getNumParams(), Args.size()); + I != N; ++I) { + if (CheckCoroCall || Callee->getParamDecl(I)->hasAttr()) + VisitLifetimeBoundArg(Callee->getParamDecl(I), Args[I]); + } +} + +/// Visit the locals that would be reachable through a reference bound to the +/// glvalue expression \c Init. +static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path, + Expr *Init, ReferenceKind RK, + LocalVisitor Visit, + bool EnableLifetimeWarnings) { + RevertToOldSizeRAII RAII(Path); + + // Walk past any constructs which we can lifetime-extend across. + Expr *Old; + do { + Old = Init; + + if (auto *FE = dyn_cast(Init)) + Init = FE->getSubExpr(); + + if (InitListExpr *ILE = dyn_cast(Init)) { + // If this is just redundant braces around an initializer, step over it. + if (ILE->isTransparent()) + Init = ILE->getInit(0); + } + + // Step over any subobject adjustments; we may have a materialized + // temporary inside them. + Init = const_cast(Init->skipRValueSubobjectAdjustments()); + + // Per current approach for DR1376, look through casts to reference type + // when performing lifetime extension. + if (CastExpr *CE = dyn_cast(Init)) + if (CE->getSubExpr()->isGLValue()) + Init = CE->getSubExpr(); + + // Per the current approach for DR1299, look through array element access + // on array glvalues when performing lifetime extension. + if (auto *ASE = dyn_cast(Init)) { + Init = ASE->getBase(); + auto *ICE = dyn_cast(Init); + if (ICE && ICE->getCastKind() == CK_ArrayToPointerDecay) + Init = ICE->getSubExpr(); + else + // We can't lifetime extend through this but we might still find some + // retained temporaries. + return visitLocalsRetainedByInitializer(Path, Init, Visit, true, + EnableLifetimeWarnings); + } + + // Step into CXXDefaultInitExprs so we can diagnose cases where a + // constructor inherits one as an implicit mem-initializer. + if (auto *DIE = dyn_cast(Init)) { + Path.push_back( + {IndirectLocalPathEntry::DefaultInit, DIE, DIE->getField()}); + Init = DIE->getExpr(); + } + } while (Init != Old); + + if (auto *MTE = dyn_cast(Init)) { + if (Visit(Path, Local(MTE), RK)) + visitLocalsRetainedByInitializer(Path, MTE->getSubExpr(), Visit, true, + EnableLifetimeWarnings); + } + + if (isa(Init)) { + if (EnableLifetimeWarnings) + handleGslAnnotatedTypes(Path, Init, Visit); + return visitLifetimeBoundArguments(Path, Init, Visit); + } + + switch (Init->getStmtClass()) { + case Stmt::DeclRefExprClass: { + // If we find the name of a local non-reference parameter, we could have a + // lifetime problem. + auto *DRE = cast(Init); + auto *VD = dyn_cast(DRE->getDecl()); + if (VD && VD->hasLocalStorage() && + !DRE->refersToEnclosingVariableOrCapture()) { + if (!VD->getType()->isReferenceType()) { + Visit(Path, Local(DRE), RK); + } else if (isa(DRE->getDecl())) { + // The lifetime of a reference parameter is unknown; assume it's OK + // for now. + break; + } else if (VD->getInit() && !isVarOnPath(Path, VD)) { + Path.push_back({IndirectLocalPathEntry::VarInit, DRE, VD}); + visitLocalsRetainedByReferenceBinding(Path, VD->getInit(), + RK_ReferenceBinding, Visit, + EnableLifetimeWarnings); + } + } + break; + } + + case Stmt::UnaryOperatorClass: { + // The only unary operator that make sense to handle here + // is Deref. All others don't resolve to a "name." This includes + // handling all sorts of rvalues passed to a unary operator. + const UnaryOperator *U = cast(Init); + if (U->getOpcode() == UO_Deref) + visitLocalsRetainedByInitializer(Path, U->getSubExpr(), Visit, true, + EnableLifetimeWarnings); + break; + } + + case Stmt::ArraySectionExprClass: { + visitLocalsRetainedByInitializer(Path, + cast(Init)->getBase(), + Visit, true, EnableLifetimeWarnings); + break; + } + + case Stmt::ConditionalOperatorClass: + case Stmt::BinaryConditionalOperatorClass: { + auto *C = cast(Init); + if (!C->getTrueExpr()->getType()->isVoidType()) + visitLocalsRetainedByReferenceBinding(Path, C->getTrueExpr(), RK, Visit, + EnableLifetimeWarnings); + if (!C->getFalseExpr()->getType()->isVoidType()) + visitLocalsRetainedByReferenceBinding(Path, C->getFalseExpr(), RK, Visit, + EnableLifetimeWarnings); + break; + } + + case Stmt::CompoundLiteralExprClass: { + if (auto *CLE = dyn_cast(Init)) { + if (!CLE->isFileScope()) + Visit(Path, Local(CLE), RK); + } + break; + } + + // FIXME: Visit the left-hand side of an -> or ->*. + + default: + break; + } +} + +/// Visit the locals that would be reachable through an object initialized by +/// the prvalue expression \c Init. +static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path, + Expr *Init, LocalVisitor Visit, + bool RevisitSubinits, + bool EnableLifetimeWarnings) { + RevertToOldSizeRAII RAII(Path); + + Expr *Old; + do { + Old = Init; + + // Step into CXXDefaultInitExprs so we can diagnose cases where a + // constructor inherits one as an implicit mem-initializer. + if (auto *DIE = dyn_cast(Init)) { + Path.push_back( + {IndirectLocalPathEntry::DefaultInit, DIE, DIE->getField()}); + Init = DIE->getExpr(); + } + + if (auto *FE = dyn_cast(Init)) + Init = FE->getSubExpr(); + + // Dig out the expression which constructs the extended temporary. + Init = const_cast(Init->skipRValueSubobjectAdjustments()); + + if (CXXBindTemporaryExpr *BTE = dyn_cast(Init)) + Init = BTE->getSubExpr(); + + Init = Init->IgnoreParens(); + + // Step over value-preserving rvalue casts. + if (auto *CE = dyn_cast(Init)) { + switch (CE->getCastKind()) { + case CK_LValueToRValue: + // If we can match the lvalue to a const object, we can look at its + // initializer. + Path.push_back({IndirectLocalPathEntry::LValToRVal, CE}); + return visitLocalsRetainedByReferenceBinding( + Path, Init, RK_ReferenceBinding, + [&](IndirectLocalPath &Path, Local L, ReferenceKind RK) -> bool { + if (auto *DRE = dyn_cast(L)) { + auto *VD = dyn_cast(DRE->getDecl()); + if (VD && VD->getType().isConstQualified() && VD->getInit() && + !isVarOnPath(Path, VD)) { + Path.push_back({IndirectLocalPathEntry::VarInit, DRE, VD}); + visitLocalsRetainedByInitializer( + Path, VD->getInit(), Visit, true, EnableLifetimeWarnings); + } + } else if (auto *MTE = dyn_cast(L)) { + if (MTE->getType().isConstQualified()) + visitLocalsRetainedByInitializer(Path, MTE->getSubExpr(), + Visit, true, + EnableLifetimeWarnings); + } + return false; + }, + EnableLifetimeWarnings); + + // We assume that objects can be retained by pointers cast to integers, + // but not if the integer is cast to floating-point type or to _Complex. + // We assume that casts to 'bool' do not preserve enough information to + // retain a local object. + case CK_NoOp: + case CK_BitCast: + case CK_BaseToDerived: + case CK_DerivedToBase: + case CK_UncheckedDerivedToBase: + case CK_Dynamic: + case CK_ToUnion: + case CK_UserDefinedConversion: + case CK_ConstructorConversion: + case CK_IntegralToPointer: + case CK_PointerToIntegral: + case CK_VectorSplat: + case CK_IntegralCast: + case CK_CPointerToObjCPointerCast: + case CK_BlockPointerToObjCPointerCast: + case CK_AnyPointerToBlockPointerCast: + case CK_AddressSpaceConversion: + break; + + case CK_ArrayToPointerDecay: + // Model array-to-pointer decay as taking the address of the array + // lvalue. + Path.push_back({IndirectLocalPathEntry::AddressOf, CE}); + return visitLocalsRetainedByReferenceBinding(Path, CE->getSubExpr(), + RK_ReferenceBinding, Visit, + EnableLifetimeWarnings); + + default: + return; + } + + Init = CE->getSubExpr(); + } + } while (Old != Init); + + // C++17 [dcl.init.list]p6: + // initializing an initializer_list object from the array extends the + // lifetime of the array exactly like binding a reference to a temporary. + if (auto *ILE = dyn_cast(Init)) + return visitLocalsRetainedByReferenceBinding(Path, ILE->getSubExpr(), + RK_StdInitializerList, Visit, + EnableLifetimeWarnings); + + if (InitListExpr *ILE = dyn_cast(Init)) { + // We already visited the elements of this initializer list while + // performing the initialization. Don't visit them again unless we've + // changed the lifetime of the initialized entity. + if (!RevisitSubinits) + return; + + if (ILE->isTransparent()) + return visitLocalsRetainedByInitializer(Path, ILE->getInit(0), Visit, + RevisitSubinits, + EnableLifetimeWarnings); + + if (ILE->getType()->isArrayType()) { + for (unsigned I = 0, N = ILE->getNumInits(); I != N; ++I) + visitLocalsRetainedByInitializer(Path, ILE->getInit(I), Visit, + RevisitSubinits, + EnableLifetimeWarnings); + return; + } + + if (CXXRecordDecl *RD = ILE->getType()->getAsCXXRecordDecl()) { + assert(RD->isAggregate() && "aggregate init on non-aggregate"); + + // If we lifetime-extend a braced initializer which is initializing an + // aggregate, and that aggregate contains reference members which are + // bound to temporaries, those temporaries are also lifetime-extended. + if (RD->isUnion() && ILE->getInitializedFieldInUnion() && + ILE->getInitializedFieldInUnion()->getType()->isReferenceType()) + visitLocalsRetainedByReferenceBinding(Path, ILE->getInit(0), + RK_ReferenceBinding, Visit, + EnableLifetimeWarnings); + else { + unsigned Index = 0; + for (; Index < RD->getNumBases() && Index < ILE->getNumInits(); ++Index) + visitLocalsRetainedByInitializer(Path, ILE->getInit(Index), Visit, + RevisitSubinits, + EnableLifetimeWarnings); + for (const auto *I : RD->fields()) { + if (Index >= ILE->getNumInits()) + break; + if (I->isUnnamedBitField()) + continue; + Expr *SubInit = ILE->getInit(Index); + if (I->getType()->isReferenceType()) + visitLocalsRetainedByReferenceBinding(Path, SubInit, + RK_ReferenceBinding, Visit, + EnableLifetimeWarnings); + else + // This might be either aggregate-initialization of a member or + // initialization of a std::initializer_list object. Regardless, + // we should recursively lifetime-extend that initializer. + visitLocalsRetainedByInitializer( + Path, SubInit, Visit, RevisitSubinits, EnableLifetimeWarnings); + ++Index; + } + } + } + return; + } + + // The lifetime of an init-capture is that of the closure object constructed + // by a lambda-expression. + if (auto *LE = dyn_cast(Init)) { + LambdaExpr::capture_iterator CapI = LE->capture_begin(); + for (Expr *E : LE->capture_inits()) { + assert(CapI != LE->capture_end()); + const LambdaCapture &Cap = *CapI++; + if (!E) + continue; + if (Cap.capturesVariable()) + Path.push_back({IndirectLocalPathEntry::LambdaCaptureInit, E, &Cap}); + if (E->isGLValue()) + visitLocalsRetainedByReferenceBinding(Path, E, RK_ReferenceBinding, + Visit, EnableLifetimeWarnings); + else + visitLocalsRetainedByInitializer(Path, E, Visit, true, + EnableLifetimeWarnings); + if (Cap.capturesVariable()) + Path.pop_back(); + } + } + + // Assume that a copy or move from a temporary references the same objects + // that the temporary does. + if (auto *CCE = dyn_cast(Init)) { + if (CCE->getConstructor()->isCopyOrMoveConstructor()) { + if (auto *MTE = dyn_cast(CCE->getArg(0))) { + // assert(false && "hit temporary copy path"); + Expr *Arg = MTE->getSubExpr(); + Path.push_back({IndirectLocalPathEntry::TemporaryCopy, Arg, + CCE->getConstructor()}); + visitLocalsRetainedByInitializer(Path, Arg, Visit, true, + /*EnableLifetimeWarnings*/ false); + Path.pop_back(); + } + } + } + + if (isa(Init) || isa(Init)) { + if (EnableLifetimeWarnings) + handleGslAnnotatedTypes(Path, Init, Visit); + return visitLifetimeBoundArguments(Path, Init, Visit); + } + + switch (Init->getStmtClass()) { + case Stmt::UnaryOperatorClass: { + auto *UO = cast(Init); + // If the initializer is the address of a local, we could have a lifetime + // problem. + if (UO->getOpcode() == UO_AddrOf) { + // If this is &rvalue, then it's ill-formed and we have already diagnosed + // it. Don't produce a redundant warning about the lifetime of the + // temporary. + if (isa(UO->getSubExpr())) + return; + + Path.push_back({IndirectLocalPathEntry::AddressOf, UO}); + visitLocalsRetainedByReferenceBinding(Path, UO->getSubExpr(), + RK_ReferenceBinding, Visit, + EnableLifetimeWarnings); + } + break; + } + + case Stmt::BinaryOperatorClass: { + // Handle pointer arithmetic. + auto *BO = cast(Init); + BinaryOperatorKind BOK = BO->getOpcode(); + if (!BO->getType()->isPointerType() || (BOK != BO_Add && BOK != BO_Sub)) + break; + + if (BO->getLHS()->getType()->isPointerType()) + visitLocalsRetainedByInitializer(Path, BO->getLHS(), Visit, true, + EnableLifetimeWarnings); + else if (BO->getRHS()->getType()->isPointerType()) + visitLocalsRetainedByInitializer(Path, BO->getRHS(), Visit, true, + EnableLifetimeWarnings); + break; + } + + case Stmt::ConditionalOperatorClass: + case Stmt::BinaryConditionalOperatorClass: { + auto *C = cast(Init); + // In C++, we can have a throw-expression operand, which has 'void' type + // and isn't interesting from a lifetime perspective. + if (!C->getTrueExpr()->getType()->isVoidType()) + visitLocalsRetainedByInitializer(Path, C->getTrueExpr(), Visit, true, + EnableLifetimeWarnings); + if (!C->getFalseExpr()->getType()->isVoidType()) + visitLocalsRetainedByInitializer(Path, C->getFalseExpr(), Visit, true, + EnableLifetimeWarnings); + break; + } + + case Stmt::BlockExprClass: + if (cast(Init)->getBlockDecl()->hasCaptures()) { + // This is a local block, whose lifetime is that of the function. + Visit(Path, Local(cast(Init)), RK_ReferenceBinding); + } + break; + + case Stmt::AddrLabelExprClass: + // We want to warn if the address of a label would escape the function. + Visit(Path, Local(cast(Init)), RK_ReferenceBinding); + break; + + default: + break; + } +} + +/// Whether a path to an object supports lifetime extension. +enum PathLifetimeKind { + /// Lifetime-extend along this path. + Extend, + /// We should lifetime-extend, but we don't because (due to technical + /// limitations) we can't. This happens for default member initializers, + /// which we don't clone for every use, so we don't have a unique + /// MaterializeTemporaryExpr to update. + ShouldExtend, + /// Do not lifetime extend along this path. + NoExtend +}; + +/// Determine whether this is an indirect path to a temporary that we are +/// supposed to lifetime-extend along. +static PathLifetimeKind +shouldLifetimeExtendThroughPath(const IndirectLocalPath &Path) { + PathLifetimeKind Kind = PathLifetimeKind::Extend; + for (auto Elem : Path) { + if (Elem.Kind == IndirectLocalPathEntry::DefaultInit) + Kind = PathLifetimeKind::ShouldExtend; + else if (Elem.Kind != IndirectLocalPathEntry::LambdaCaptureInit) + return PathLifetimeKind::NoExtend; + } + return Kind; +} + +/// Find the range for the first interesting entry in the path at or after I. +static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I, + Expr *E) { + for (unsigned N = Path.size(); I != N; ++I) { + switch (Path[I].Kind) { + case IndirectLocalPathEntry::AddressOf: + case IndirectLocalPathEntry::LValToRVal: + case IndirectLocalPathEntry::LifetimeBoundCall: + case IndirectLocalPathEntry::TemporaryCopy: + case IndirectLocalPathEntry::GslReferenceInit: + case IndirectLocalPathEntry::GslPointerInit: + // These exist primarily to mark the path as not permitting or + // supporting lifetime extension. + break; + + case IndirectLocalPathEntry::VarInit: + if (cast(Path[I].D)->isImplicit()) + return SourceRange(); + [[fallthrough]]; + case IndirectLocalPathEntry::DefaultInit: + return Path[I].E->getSourceRange(); + + case IndirectLocalPathEntry::LambdaCaptureInit: + if (!Path[I].Capture->capturesVariable()) + continue; + return Path[I].E->getSourceRange(); + } + } + return E->getSourceRange(); +} + +static bool pathOnlyInitializesGslPointer(IndirectLocalPath &Path) { + for (const auto &It : llvm::reverse(Path)) { + if (It.Kind == IndirectLocalPathEntry::VarInit) + continue; + if (It.Kind == IndirectLocalPathEntry::AddressOf) + continue; + if (It.Kind == IndirectLocalPathEntry::LifetimeBoundCall) + continue; + return It.Kind == IndirectLocalPathEntry::GslPointerInit || + It.Kind == IndirectLocalPathEntry::GslReferenceInit; + } + return false; +} + +void checkExprLifetime(Sema &SemaRef, const InitializedEntity &Entity, + Expr *Init) { + LifetimeResult LR = getEntityLifetime(&Entity); + LifetimeKind LK = LR.getInt(); + const InitializedEntity *ExtendingEntity = LR.getPointer(); + + // If this entity doesn't have an interesting lifetime, don't bother looking + // for temporaries within its initializer. + if (LK == LK_FullExpression) + return; + + auto TemporaryVisitor = [&](IndirectLocalPath &Path, Local L, + ReferenceKind RK) -> bool { + SourceRange DiagRange = nextPathEntryRange(Path, 0, L); + SourceLocation DiagLoc = DiagRange.getBegin(); + + auto *MTE = dyn_cast(L); + + bool IsGslPtrInitWithGslTempOwner = false; + bool IsLocalGslOwner = false; + if (pathOnlyInitializesGslPointer(Path)) { + if (isa(L)) { + // We do not want to follow the references when returning a pointer + // originating from a local owner to avoid the following false positive: + // int &p = *localUniquePtr; + // someContainer.add(std::move(localUniquePtr)); + // return p; + IsLocalGslOwner = isRecordWithAttr(L->getType()); + if (pathContainsInit(Path) || !IsLocalGslOwner) + return false; + } else { + IsGslPtrInitWithGslTempOwner = + MTE && !MTE->getExtendingDecl() && + isRecordWithAttr(MTE->getType()); + // Skipping a chain of initializing gsl::Pointer annotated objects. + // We are looking only for the final source to find out if it was + // a local or temporary owner or the address of a local variable/param. + if (!IsGslPtrInitWithGslTempOwner) + return true; + } + } + + switch (LK) { + case LK_FullExpression: + llvm_unreachable("already handled this"); + + case LK_Extended: { + if (!MTE) { + // The initialized entity has lifetime beyond the full-expression, + // and the local entity does too, so don't warn. + // + // FIXME: We should consider warning if a static / thread storage + // duration variable retains an automatic storage duration local. + return false; + } + + if (IsGslPtrInitWithGslTempOwner && DiagLoc.isValid()) { + SemaRef.Diag(DiagLoc, diag::warn_dangling_lifetime_pointer) + << DiagRange; + return false; + } + + switch (shouldLifetimeExtendThroughPath(Path)) { + case PathLifetimeKind::Extend: + // Update the storage duration of the materialized temporary. + // FIXME: Rebuild the expression instead of mutating it. + MTE->setExtendingDecl(ExtendingEntity->getDecl(), + ExtendingEntity->allocateManglingNumber()); + // Also visit the temporaries lifetime-extended by this initializer. + return true; + + case PathLifetimeKind::ShouldExtend: + // We're supposed to lifetime-extend the temporary along this path (per + // the resolution of DR1815), but we don't support that yet. + // + // FIXME: Properly handle this situation. Perhaps the easiest approach + // would be to clone the initializer expression on each use that would + // lifetime extend its temporaries. + SemaRef.Diag(DiagLoc, diag::warn_unsupported_lifetime_extension) + << RK << DiagRange; + break; + + case PathLifetimeKind::NoExtend: + // If the path goes through the initialization of a variable or field, + // it can't possibly reach a temporary created in this full-expression. + // We will have already diagnosed any problems with the initializer. + if (pathContainsInit(Path)) + return false; + + SemaRef.Diag(DiagLoc, diag::warn_dangling_variable) + << RK << !Entity.getParent() + << ExtendingEntity->getDecl()->isImplicit() + << ExtendingEntity->getDecl() << Init->isGLValue() << DiagRange; + break; + } + break; + } + + case LK_MemInitializer: { + if (isa(L)) { + // Under C++ DR1696, if a mem-initializer (or a default member + // initializer used by the absence of one) would lifetime-extend a + // temporary, the program is ill-formed. + if (auto *ExtendingDecl = + ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) { + if (IsGslPtrInitWithGslTempOwner) { + SemaRef.Diag(DiagLoc, diag::warn_dangling_lifetime_pointer_member) + << ExtendingDecl << DiagRange; + SemaRef.Diag(ExtendingDecl->getLocation(), + diag::note_ref_or_ptr_member_declared_here) + << true; + return false; + } + bool IsSubobjectMember = ExtendingEntity != &Entity; + SemaRef.Diag(DiagLoc, shouldLifetimeExtendThroughPath(Path) != + PathLifetimeKind::NoExtend + ? diag::err_dangling_member + : diag::warn_dangling_member) + << ExtendingDecl << IsSubobjectMember << RK << DiagRange; + // Don't bother adding a note pointing to the field if we're inside + // its default member initializer; our primary diagnostic points to + // the same place in that case. + if (Path.empty() || + Path.back().Kind != IndirectLocalPathEntry::DefaultInit) { + SemaRef.Diag(ExtendingDecl->getLocation(), + diag::note_lifetime_extending_member_declared_here) + << RK << IsSubobjectMember; + } + } else { + // We have a mem-initializer but no particular field within it; this + // is either a base class or a delegating initializer directly + // initializing the base-class from something that doesn't live long + // enough. + // + // FIXME: Warn on this. + return false; + } + } else { + // Paths via a default initializer can only occur during error recovery + // (there's no other way that a default initializer can refer to a + // local). Don't produce a bogus warning on those cases. + if (pathContainsInit(Path)) + return false; + + // Suppress false positives for code like the one below: + // Ctor(unique_ptr up) : member(*up), member2(move(up)) {} + if (IsLocalGslOwner && pathOnlyInitializesGslPointer(Path)) + return false; + + auto *DRE = dyn_cast(L); + auto *VD = DRE ? dyn_cast(DRE->getDecl()) : nullptr; + if (!VD) { + // A member was initialized to a local block. + // FIXME: Warn on this. + return false; + } + + if (auto *Member = + ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) { + bool IsPointer = !Member->getType()->isReferenceType(); + SemaRef.Diag(DiagLoc, + IsPointer ? diag::warn_init_ptr_member_to_parameter_addr + : diag::warn_bind_ref_member_to_parameter) + << Member << VD << isa(VD) << DiagRange; + SemaRef.Diag(Member->getLocation(), + diag::note_ref_or_ptr_member_declared_here) + << (unsigned)IsPointer; + } + } + break; + } + + case LK_New: + if (isa(L)) { + if (IsGslPtrInitWithGslTempOwner) + SemaRef.Diag(DiagLoc, diag::warn_dangling_lifetime_pointer) + << DiagRange; + else + SemaRef.Diag(DiagLoc, RK == RK_ReferenceBinding + ? diag::warn_new_dangling_reference + : diag::warn_new_dangling_initializer_list) + << !Entity.getParent() << DiagRange; + } else { + // We can't determine if the allocation outlives the local declaration. + return false; + } + break; + + case LK_Return: + case LK_StmtExprResult: + if (auto *DRE = dyn_cast(L)) { + // We can't determine if the local variable outlives the statement + // expression. + if (LK == LK_StmtExprResult) + return false; + SemaRef.Diag(DiagLoc, diag::warn_ret_stack_addr_ref) + << Entity.getType()->isReferenceType() << DRE->getDecl() + << isa(DRE->getDecl()) << DiagRange; + } else if (isa(L)) { + SemaRef.Diag(DiagLoc, diag::err_ret_local_block) << DiagRange; + } else if (isa(L)) { + // Don't warn when returning a label from a statement expression. + // Leaving the scope doesn't end its lifetime. + if (LK == LK_StmtExprResult) + return false; + SemaRef.Diag(DiagLoc, diag::warn_ret_addr_label) << DiagRange; + } else if (auto *CLE = dyn_cast(L)) { + SemaRef.Diag(DiagLoc, diag::warn_ret_stack_addr_ref) + << Entity.getType()->isReferenceType() << CLE->getInitializer() << 2 + << DiagRange; + } else { + // P2748R5: Disallow Binding a Returned Glvalue to a Temporary. + // [stmt.return]/p6: In a function whose return type is a reference, + // other than an invented function for std::is_convertible ([meta.rel]), + // a return statement that binds the returned reference to a temporary + // expression ([class.temporary]) is ill-formed. + if (SemaRef.getLangOpts().CPlusPlus26 && + Entity.getType()->isReferenceType()) + SemaRef.Diag(DiagLoc, diag::err_ret_local_temp_ref) + << Entity.getType()->isReferenceType() << DiagRange; + else + SemaRef.Diag(DiagLoc, diag::warn_ret_local_temp_addr_ref) + << Entity.getType()->isReferenceType() << DiagRange; + } + break; + } + + for (unsigned I = 0; I != Path.size(); ++I) { + auto Elem = Path[I]; + + switch (Elem.Kind) { + case IndirectLocalPathEntry::AddressOf: + case IndirectLocalPathEntry::LValToRVal: + // These exist primarily to mark the path as not permitting or + // supporting lifetime extension. + break; + + case IndirectLocalPathEntry::LifetimeBoundCall: + case IndirectLocalPathEntry::TemporaryCopy: + case IndirectLocalPathEntry::GslPointerInit: + case IndirectLocalPathEntry::GslReferenceInit: + // FIXME: Consider adding a note for these. + break; + + case IndirectLocalPathEntry::DefaultInit: { + auto *FD = cast(Elem.D); + SemaRef.Diag(FD->getLocation(), + diag::note_init_with_default_member_initializer) + << FD << nextPathEntryRange(Path, I + 1, L); + break; + } + + case IndirectLocalPathEntry::VarInit: { + const VarDecl *VD = cast(Elem.D); + SemaRef.Diag(VD->getLocation(), diag::note_local_var_initializer) + << VD->getType()->isReferenceType() << VD->isImplicit() + << VD->getDeclName() << nextPathEntryRange(Path, I + 1, L); + break; + } + + case IndirectLocalPathEntry::LambdaCaptureInit: + if (!Elem.Capture->capturesVariable()) + break; + // FIXME: We can't easily tell apart an init-capture from a nested + // capture of an init-capture. + const ValueDecl *VD = Elem.Capture->getCapturedVar(); + SemaRef.Diag(Elem.Capture->getLocation(), + diag::note_lambda_capture_initializer) + << VD << VD->isInitCapture() << Elem.Capture->isExplicit() + << (Elem.Capture->getCaptureKind() == LCK_ByRef) << VD + << nextPathEntryRange(Path, I + 1, L); + break; + } + } + + // We didn't lifetime-extend, so don't go any further; we don't need more + // warnings or errors on inner temporaries within this one's initializer. + return false; + }; + + bool EnableLifetimeWarnings = !SemaRef.getDiagnostics().isIgnored( + diag::warn_dangling_lifetime_pointer, SourceLocation()); + llvm::SmallVector Path; + if (Init->isGLValue()) + visitLocalsRetainedByReferenceBinding(Path, Init, RK_ReferenceBinding, + TemporaryVisitor, + EnableLifetimeWarnings); + else + visitLocalsRetainedByInitializer(Path, Init, TemporaryVisitor, false, + EnableLifetimeWarnings); +} + +} // namespace clang::sema diff --git a/clang/lib/Sema/CheckExprLifetime.h b/clang/lib/Sema/CheckExprLifetime.h new file mode 100644 index 00000000000000..f9cd3f55d3dbf2 --- /dev/null +++ b/clang/lib/Sema/CheckExprLifetime.h @@ -0,0 +1,29 @@ +//===- CheckExprLifetime.h ----------------------------------- -*- 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 files implements a statement-local lifetime analysis. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_CHECK_EXPR_LIFETIME_H +#define LLVM_CLANG_SEMA_CHECK_EXPR_LIFETIME_H + +#include "clang/AST/Expr.h" +#include "clang/Sema/Initialization.h" +#include "clang/Sema/Sema.h" + +namespace clang::sema { + +/// Check that the lifetime of the given expr (and its subobjects) is +/// sufficient for initializing the entity, and perform lifetime extension +/// (when permitted) if not. +void checkExprLifetime(Sema &SemaRef, const InitializedEntity &Entity, + Expr *Init); + +} // namespace clang::sema + +#endif // LLVM_CLANG_SEMA_CHECK_EXPR_LIFETIME_H diff --git a/clang/lib/Sema/ScopeInfo.cpp b/clang/lib/Sema/ScopeInfo.cpp index ce90451f2613bf..12fb7060727233 100644 --- a/clang/lib/Sema/ScopeInfo.cpp +++ b/clang/lib/Sema/ScopeInfo.cpp @@ -39,6 +39,7 @@ void FunctionScopeInfo::Clear() { FirstReturnLoc = SourceLocation(); FirstCXXOrObjCTryLoc = SourceLocation(); FirstSEHTryLoc = SourceLocation(); + FirstVLALoc = SourceLocation(); FoundImmediateEscalatingExpression = false; // Coroutine state diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 069978c1b40239..3f8f2f027172de 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -638,6 +638,19 @@ void Sema::diagnoseNullableToNonnullConversion(QualType DstType, Diag(Loc, diag::warn_nullability_lost) << SrcType << DstType; } +// Generate diagnostics when adding or removing effects in a type conversion. +void Sema::diagnoseFunctionEffectConversion(QualType DstType, QualType SrcType, + SourceLocation Loc) { + const auto SrcFX = FunctionEffectsRef::get(SrcType); + const auto DstFX = FunctionEffectsRef::get(DstType); + if (SrcFX != DstFX) { + for (const auto &Diff : FunctionEffectDifferences(SrcFX, DstFX)) { + if (Diff.shouldDiagnoseConversion(SrcType, SrcFX, DstType, DstFX)) + Diag(Loc, diag::warn_invalid_add_func_effects) << Diff.effectName(); + } + } +} + void Sema::diagnoseZeroToNullptrConversion(CastKind Kind, const Expr *E) { // nullptr only exists from C++11 on, so don't warn on its absence earlier. if (!getLangOpts().CPlusPlus11) @@ -715,6 +728,9 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty, diagnoseNullableToNonnullConversion(Ty, E->getType(), E->getBeginLoc()); diagnoseZeroToNullptrConversion(Kind, E); + if (!isCast(CCK) && Kind != CK_NullToPointer && + Kind != CK_NullToMemberPointer) + diagnoseFunctionEffectConversion(Ty, E->getType(), E->getBeginLoc()); QualType ExprTy = Context.getCanonicalType(E->getType()); QualType TypeTy = Context.getCanonicalType(Ty); @@ -2796,3 +2812,153 @@ bool Sema::isDeclaratorFunctionLike(Declarator &D) { }); return Result; } + +FunctionEffectDifferences::FunctionEffectDifferences( + const FunctionEffectsRef &Old, const FunctionEffectsRef &New) { + + FunctionEffectsRef::iterator POld = Old.begin(); + FunctionEffectsRef::iterator OldEnd = Old.end(); + FunctionEffectsRef::iterator PNew = New.begin(); + FunctionEffectsRef::iterator NewEnd = New.end(); + + while (true) { + int cmp = 0; + if (POld == OldEnd) { + if (PNew == NewEnd) + break; + cmp = 1; + } else if (PNew == NewEnd) + cmp = -1; + else { + FunctionEffectWithCondition Old = *POld; + FunctionEffectWithCondition New = *PNew; + if (Old.Effect.kind() < New.Effect.kind()) + cmp = -1; + else if (New.Effect.kind() < Old.Effect.kind()) + cmp = 1; + else { + cmp = 0; + if (Old.Cond.getCondition() != New.Cond.getCondition()) { + // FIXME: Cases where the expressions are equivalent but + // don't have the same identity. + push_back(FunctionEffectDiff{ + Old.Effect.kind(), FunctionEffectDiff::Kind::ConditionMismatch, + Old, New}); + } + } + } + + if (cmp < 0) { + // removal + FunctionEffectWithCondition Old = *POld; + push_back(FunctionEffectDiff{ + Old.Effect.kind(), FunctionEffectDiff::Kind::Removed, Old, {}}); + ++POld; + } else if (cmp > 0) { + // addition + FunctionEffectWithCondition New = *PNew; + push_back(FunctionEffectDiff{ + New.Effect.kind(), FunctionEffectDiff::Kind::Added, {}, New}); + ++PNew; + } else { + ++POld; + ++PNew; + } + } +} + +bool FunctionEffectDiff::shouldDiagnoseConversion( + QualType SrcType, const FunctionEffectsRef &SrcFX, QualType DstType, + const FunctionEffectsRef &DstFX) const { + + switch (EffectKind) { + case FunctionEffect::Kind::NonAllocating: + // nonallocating can't be added (spoofed) during a conversion, unless we + // have nonblocking. + if (DiffKind == Kind::Added) { + for (const auto &CFE : SrcFX) { + if (CFE.Effect.kind() == FunctionEffect::Kind::NonBlocking) + return false; + } + } + [[fallthrough]]; + case FunctionEffect::Kind::NonBlocking: + // nonblocking can't be added (spoofed) during a conversion. + switch (DiffKind) { + case Kind::Added: + return true; + case Kind::Removed: + return false; + case Kind::ConditionMismatch: + // FIXME: Condition mismatches are too coarse right now -- expressions + // which are equivalent but don't have the same identity are detected as + // mismatches. We're going to diagnose those anyhow until expression + // matching is better. + return true; + } + case FunctionEffect::Kind::Blocking: + case FunctionEffect::Kind::Allocating: + return false; + case FunctionEffect::Kind::None: + break; + } + llvm_unreachable("unknown effect kind"); +} + +bool FunctionEffectDiff::shouldDiagnoseRedeclaration( + const FunctionDecl &OldFunction, const FunctionEffectsRef &OldFX, + const FunctionDecl &NewFunction, const FunctionEffectsRef &NewFX) const { + switch (EffectKind) { + case FunctionEffect::Kind::NonAllocating: + case FunctionEffect::Kind::NonBlocking: + // nonblocking/nonallocating can't be removed in a redeclaration. + switch (DiffKind) { + case Kind::Added: + return false; // No diagnostic. + case Kind::Removed: + return true; // Issue diagnostic. + case Kind::ConditionMismatch: + // All these forms of mismatches are diagnosed. + return true; + } + case FunctionEffect::Kind::Blocking: + case FunctionEffect::Kind::Allocating: + return false; + case FunctionEffect::Kind::None: + break; + } + llvm_unreachable("unknown effect kind"); +} + +FunctionEffectDiff::OverrideResult +FunctionEffectDiff::shouldDiagnoseMethodOverride( + const CXXMethodDecl &OldMethod, const FunctionEffectsRef &OldFX, + const CXXMethodDecl &NewMethod, const FunctionEffectsRef &NewFX) const { + switch (EffectKind) { + case FunctionEffect::Kind::NonAllocating: + case FunctionEffect::Kind::NonBlocking: + switch (DiffKind) { + + // If added on an override, that's fine and not diagnosed. + case Kind::Added: + return OverrideResult::NoAction; + + // If missing from an override (removed), propagate from base to derived. + case Kind::Removed: + return OverrideResult::Merge; + + // If there's a mismatch involving the effect's polarity or condition, + // issue a warning. + case Kind::ConditionMismatch: + return OverrideResult::Warn; + } + + case FunctionEffect::Kind::Blocking: + case FunctionEffect::Kind::Allocating: + return OverrideResult::NoAction; + + case FunctionEffect::Kind::None: + break; + } + llvm_unreachable("unknown effect kind"); +} diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 87988519e76916..cc3615da7f9401 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -64,12 +64,14 @@ #include "clang/Sema/SemaAMDGPU.h" #include "clang/Sema/SemaARM.h" #include "clang/Sema/SemaBPF.h" +#include "clang/Sema/SemaHLSL.h" #include "clang/Sema/SemaHexagon.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/SemaLoongArch.h" #include "clang/Sema/SemaMIPS.h" #include "clang/Sema/SemaNVPTX.h" #include "clang/Sema/SemaObjC.h" +#include "clang/Sema/SemaOpenCL.h" #include "clang/Sema/SemaPPC.h" #include "clang/Sema/SemaRISCV.h" #include "clang/Sema/SemaSystemZ.h" @@ -183,6 +185,33 @@ bool Sema::checkArgCount(CallExpr *Call, unsigned DesiredArgCount) { << /*is non object*/ 0 << Call->getArg(1)->getSourceRange(); } +static bool checkBuiltinVerboseTrap(CallExpr *Call, Sema &S) { + bool HasError = false; + + for (unsigned I = 0; I < Call->getNumArgs(); ++I) { + Expr *Arg = Call->getArg(I); + + if (Arg->isValueDependent()) + continue; + + std::optional ArgString = Arg->tryEvaluateString(S.Context); + int DiagMsgKind = -1; + // Arguments must be pointers to constant strings and cannot use '$'. + if (!ArgString.has_value()) + DiagMsgKind = 0; + else if (ArgString->find('$') != std::string::npos) + DiagMsgKind = 1; + + if (DiagMsgKind >= 0) { + S.Diag(Arg->getBeginLoc(), diag::err_builtin_verbose_trap_arg) + << DiagMsgKind << Arg->getSourceRange(); + HasError = true; + } + } + + return !HasError; +} + static bool convertArgumentToType(Sema &S, Expr *&Value, QualType Ty) { if (Value->isTypeDependent()) return false; @@ -1459,528 +1488,6 @@ static bool BuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall, return false; } -static inline bool isBlockPointer(Expr *Arg) { - return Arg->getType()->isBlockPointerType(); -} - -/// OpenCL C v2.0, s6.13.17.2 - Checks that the block parameters are all local -/// void*, which is a requirement of device side enqueue. -static bool checkOpenCLBlockArgs(Sema &S, Expr *BlockArg) { - const BlockPointerType *BPT = - cast(BlockArg->getType().getCanonicalType()); - ArrayRef Params = - BPT->getPointeeType()->castAs()->getParamTypes(); - unsigned ArgCounter = 0; - bool IllegalParams = false; - // Iterate through the block parameters until either one is found that is not - // a local void*, or the block is valid. - for (ArrayRef::iterator I = Params.begin(), E = Params.end(); - I != E; ++I, ++ArgCounter) { - if (!(*I)->isPointerType() || !(*I)->getPointeeType()->isVoidType() || - (*I)->getPointeeType().getQualifiers().getAddressSpace() != - LangAS::opencl_local) { - // Get the location of the error. If a block literal has been passed - // (BlockExpr) then we can point straight to the offending argument, - // else we just point to the variable reference. - SourceLocation ErrorLoc; - if (isa(BlockArg)) { - BlockDecl *BD = cast(BlockArg)->getBlockDecl(); - ErrorLoc = BD->getParamDecl(ArgCounter)->getBeginLoc(); - } else if (isa(BlockArg)) { - ErrorLoc = cast(BlockArg)->getBeginLoc(); - } - S.Diag(ErrorLoc, - diag::err_opencl_enqueue_kernel_blocks_non_local_void_args); - IllegalParams = true; - } - } - - return IllegalParams; -} - -static bool checkOpenCLSubgroupExt(Sema &S, CallExpr *Call) { - // OpenCL device can support extension but not the feature as extension - // requires subgroup independent forward progress, but subgroup independent - // forward progress is optional in OpenCL C 3.0 __opencl_c_subgroups feature. - if (!S.getOpenCLOptions().isSupported("cl_khr_subgroups", S.getLangOpts()) && - !S.getOpenCLOptions().isSupported("__opencl_c_subgroups", - S.getLangOpts())) { - S.Diag(Call->getBeginLoc(), diag::err_opencl_requires_extension) - << 1 << Call->getDirectCallee() - << "cl_khr_subgroups or __opencl_c_subgroups"; - return true; - } - return false; -} - -static bool OpenCLBuiltinNDRangeAndBlock(Sema &S, CallExpr *TheCall) { - if (S.checkArgCount(TheCall, 2)) - return true; - - if (checkOpenCLSubgroupExt(S, TheCall)) - return true; - - // First argument is an ndrange_t type. - Expr *NDRangeArg = TheCall->getArg(0); - if (NDRangeArg->getType().getUnqualifiedType().getAsString() != "ndrange_t") { - S.Diag(NDRangeArg->getBeginLoc(), diag::err_opencl_builtin_expected_type) - << TheCall->getDirectCallee() << "'ndrange_t'"; - return true; - } - - Expr *BlockArg = TheCall->getArg(1); - if (!isBlockPointer(BlockArg)) { - S.Diag(BlockArg->getBeginLoc(), diag::err_opencl_builtin_expected_type) - << TheCall->getDirectCallee() << "block"; - return true; - } - return checkOpenCLBlockArgs(S, BlockArg); -} - -/// OpenCL C v2.0, s6.13.17.6 - Check the argument to the -/// get_kernel_work_group_size -/// and get_kernel_preferred_work_group_size_multiple builtin functions. -static bool OpenCLBuiltinKernelWorkGroupSize(Sema &S, CallExpr *TheCall) { - if (S.checkArgCount(TheCall, 1)) - return true; - - Expr *BlockArg = TheCall->getArg(0); - if (!isBlockPointer(BlockArg)) { - S.Diag(BlockArg->getBeginLoc(), diag::err_opencl_builtin_expected_type) - << TheCall->getDirectCallee() << "block"; - return true; - } - return checkOpenCLBlockArgs(S, BlockArg); -} - -/// Diagnose integer type and any valid implicit conversion to it. -static bool checkOpenCLEnqueueIntType(Sema &S, Expr *E, - const QualType &IntType); - -static bool checkOpenCLEnqueueLocalSizeArgs(Sema &S, CallExpr *TheCall, - unsigned Start, unsigned End) { - bool IllegalParams = false; - for (unsigned I = Start; I <= End; ++I) - IllegalParams |= checkOpenCLEnqueueIntType(S, TheCall->getArg(I), - S.Context.getSizeType()); - return IllegalParams; -} - -/// OpenCL v2.0, s6.13.17.1 - Check that sizes are provided for all -/// 'local void*' parameter of passed block. -static bool checkOpenCLEnqueueVariadicArgs(Sema &S, CallExpr *TheCall, - Expr *BlockArg, - unsigned NumNonVarArgs) { - const BlockPointerType *BPT = - cast(BlockArg->getType().getCanonicalType()); - unsigned NumBlockParams = - BPT->getPointeeType()->castAs()->getNumParams(); - unsigned TotalNumArgs = TheCall->getNumArgs(); - - // For each argument passed to the block, a corresponding uint needs to - // be passed to describe the size of the local memory. - if (TotalNumArgs != NumBlockParams + NumNonVarArgs) { - S.Diag(TheCall->getBeginLoc(), - diag::err_opencl_enqueue_kernel_local_size_args); - return true; - } - - // Check that the sizes of the local memory are specified by integers. - return checkOpenCLEnqueueLocalSizeArgs(S, TheCall, NumNonVarArgs, - TotalNumArgs - 1); -} - -/// OpenCL C v2.0, s6.13.17 - Enqueue kernel function contains four different -/// overload formats specified in Table 6.13.17.1. -/// int enqueue_kernel(queue_t queue, -/// kernel_enqueue_flags_t flags, -/// const ndrange_t ndrange, -/// void (^block)(void)) -/// int enqueue_kernel(queue_t queue, -/// kernel_enqueue_flags_t flags, -/// const ndrange_t ndrange, -/// uint num_events_in_wait_list, -/// clk_event_t *event_wait_list, -/// clk_event_t *event_ret, -/// void (^block)(void)) -/// int enqueue_kernel(queue_t queue, -/// kernel_enqueue_flags_t flags, -/// const ndrange_t ndrange, -/// void (^block)(local void*, ...), -/// uint size0, ...) -/// int enqueue_kernel(queue_t queue, -/// kernel_enqueue_flags_t flags, -/// const ndrange_t ndrange, -/// uint num_events_in_wait_list, -/// clk_event_t *event_wait_list, -/// clk_event_t *event_ret, -/// void (^block)(local void*, ...), -/// uint size0, ...) -static bool OpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { - unsigned NumArgs = TheCall->getNumArgs(); - - if (NumArgs < 4) { - S.Diag(TheCall->getBeginLoc(), - diag::err_typecheck_call_too_few_args_at_least) - << 0 << 4 << NumArgs << /*is non object*/ 0; - return true; - } - - Expr *Arg0 = TheCall->getArg(0); - Expr *Arg1 = TheCall->getArg(1); - Expr *Arg2 = TheCall->getArg(2); - Expr *Arg3 = TheCall->getArg(3); - - // First argument always needs to be a queue_t type. - if (!Arg0->getType()->isQueueT()) { - S.Diag(TheCall->getArg(0)->getBeginLoc(), - diag::err_opencl_builtin_expected_type) - << TheCall->getDirectCallee() << S.Context.OCLQueueTy; - return true; - } - - // Second argument always needs to be a kernel_enqueue_flags_t enum value. - if (!Arg1->getType()->isIntegerType()) { - S.Diag(TheCall->getArg(1)->getBeginLoc(), - diag::err_opencl_builtin_expected_type) - << TheCall->getDirectCallee() << "'kernel_enqueue_flags_t' (i.e. uint)"; - return true; - } - - // Third argument is always an ndrange_t type. - if (Arg2->getType().getUnqualifiedType().getAsString() != "ndrange_t") { - S.Diag(TheCall->getArg(2)->getBeginLoc(), - diag::err_opencl_builtin_expected_type) - << TheCall->getDirectCallee() << "'ndrange_t'"; - return true; - } - - // With four arguments, there is only one form that the function could be - // called in: no events and no variable arguments. - if (NumArgs == 4) { - // check that the last argument is the right block type. - if (!isBlockPointer(Arg3)) { - S.Diag(Arg3->getBeginLoc(), diag::err_opencl_builtin_expected_type) - << TheCall->getDirectCallee() << "block"; - return true; - } - // we have a block type, check the prototype - const BlockPointerType *BPT = - cast(Arg3->getType().getCanonicalType()); - if (BPT->getPointeeType()->castAs()->getNumParams() > 0) { - S.Diag(Arg3->getBeginLoc(), - diag::err_opencl_enqueue_kernel_blocks_no_args); - return true; - } - return false; - } - // we can have block + varargs. - if (isBlockPointer(Arg3)) - return (checkOpenCLBlockArgs(S, Arg3) || - checkOpenCLEnqueueVariadicArgs(S, TheCall, Arg3, 4)); - // last two cases with either exactly 7 args or 7 args and varargs. - if (NumArgs >= 7) { - // check common block argument. - Expr *Arg6 = TheCall->getArg(6); - if (!isBlockPointer(Arg6)) { - S.Diag(Arg6->getBeginLoc(), diag::err_opencl_builtin_expected_type) - << TheCall->getDirectCallee() << "block"; - return true; - } - if (checkOpenCLBlockArgs(S, Arg6)) - return true; - - // Forth argument has to be any integer type. - if (!Arg3->getType()->isIntegerType()) { - S.Diag(TheCall->getArg(3)->getBeginLoc(), - diag::err_opencl_builtin_expected_type) - << TheCall->getDirectCallee() << "integer"; - return true; - } - // check remaining common arguments. - Expr *Arg4 = TheCall->getArg(4); - Expr *Arg5 = TheCall->getArg(5); - - // Fifth argument is always passed as a pointer to clk_event_t. - if (!Arg4->isNullPointerConstant(S.Context, - Expr::NPC_ValueDependentIsNotNull) && - !Arg4->getType()->getPointeeOrArrayElementType()->isClkEventT()) { - S.Diag(TheCall->getArg(4)->getBeginLoc(), - diag::err_opencl_builtin_expected_type) - << TheCall->getDirectCallee() - << S.Context.getPointerType(S.Context.OCLClkEventTy); - return true; - } - - // Sixth argument is always passed as a pointer to clk_event_t. - if (!Arg5->isNullPointerConstant(S.Context, - Expr::NPC_ValueDependentIsNotNull) && - !(Arg5->getType()->isPointerType() && - Arg5->getType()->getPointeeType()->isClkEventT())) { - S.Diag(TheCall->getArg(5)->getBeginLoc(), - diag::err_opencl_builtin_expected_type) - << TheCall->getDirectCallee() - << S.Context.getPointerType(S.Context.OCLClkEventTy); - return true; - } - - if (NumArgs == 7) - return false; - - return checkOpenCLEnqueueVariadicArgs(S, TheCall, Arg6, 7); - } - - // None of the specific case has been detected, give generic error - S.Diag(TheCall->getBeginLoc(), - diag::err_opencl_enqueue_kernel_incorrect_args); - return true; -} - -/// Returns OpenCL access qual. -static OpenCLAccessAttr *getOpenCLArgAccess(const Decl *D) { - return D->getAttr(); -} - -/// Returns true if pipe element type is different from the pointer. -static bool checkOpenCLPipeArg(Sema &S, CallExpr *Call) { - const Expr *Arg0 = Call->getArg(0); - // First argument type should always be pipe. - if (!Arg0->getType()->isPipeType()) { - S.Diag(Call->getBeginLoc(), diag::err_opencl_builtin_pipe_first_arg) - << Call->getDirectCallee() << Arg0->getSourceRange(); - return true; - } - OpenCLAccessAttr *AccessQual = - getOpenCLArgAccess(cast(Arg0)->getDecl()); - // Validates the access qualifier is compatible with the call. - // OpenCL v2.0 s6.13.16 - The access qualifiers for pipe should only be - // read_only and write_only, and assumed to be read_only if no qualifier is - // specified. - switch (Call->getDirectCallee()->getBuiltinID()) { - case Builtin::BIread_pipe: - case Builtin::BIreserve_read_pipe: - case Builtin::BIcommit_read_pipe: - case Builtin::BIwork_group_reserve_read_pipe: - case Builtin::BIsub_group_reserve_read_pipe: - case Builtin::BIwork_group_commit_read_pipe: - case Builtin::BIsub_group_commit_read_pipe: - if (!(!AccessQual || AccessQual->isReadOnly())) { - S.Diag(Arg0->getBeginLoc(), - diag::err_opencl_builtin_pipe_invalid_access_modifier) - << "read_only" << Arg0->getSourceRange(); - return true; - } - break; - case Builtin::BIwrite_pipe: - case Builtin::BIreserve_write_pipe: - case Builtin::BIcommit_write_pipe: - case Builtin::BIwork_group_reserve_write_pipe: - case Builtin::BIsub_group_reserve_write_pipe: - case Builtin::BIwork_group_commit_write_pipe: - case Builtin::BIsub_group_commit_write_pipe: - if (!(AccessQual && AccessQual->isWriteOnly())) { - S.Diag(Arg0->getBeginLoc(), - diag::err_opencl_builtin_pipe_invalid_access_modifier) - << "write_only" << Arg0->getSourceRange(); - return true; - } - break; - default: - break; - } - return false; -} - -/// Returns true if pipe element type is different from the pointer. -static bool checkOpenCLPipePacketType(Sema &S, CallExpr *Call, unsigned Idx) { - const Expr *Arg0 = Call->getArg(0); - const Expr *ArgIdx = Call->getArg(Idx); - const PipeType *PipeTy = cast(Arg0->getType()); - const QualType EltTy = PipeTy->getElementType(); - const PointerType *ArgTy = ArgIdx->getType()->getAs(); - // The Idx argument should be a pointer and the type of the pointer and - // the type of pipe element should also be the same. - if (!ArgTy || - !S.Context.hasSameType( - EltTy, ArgTy->getPointeeType()->getCanonicalTypeInternal())) { - S.Diag(Call->getBeginLoc(), diag::err_opencl_builtin_pipe_invalid_arg) - << Call->getDirectCallee() << S.Context.getPointerType(EltTy) - << ArgIdx->getType() << ArgIdx->getSourceRange(); - return true; - } - return false; -} - -// Performs semantic analysis for the read/write_pipe call. -// \param S Reference to the semantic analyzer. -// \param Call A pointer to the builtin call. -// \return True if a semantic error has been found, false otherwise. -static bool BuiltinRWPipe(Sema &S, CallExpr *Call) { - // OpenCL v2.0 s6.13.16.2 - The built-in read/write - // functions have two forms. - switch (Call->getNumArgs()) { - case 2: - if (checkOpenCLPipeArg(S, Call)) - return true; - // The call with 2 arguments should be - // read/write_pipe(pipe T, T*). - // Check packet type T. - if (checkOpenCLPipePacketType(S, Call, 1)) - return true; - break; - - case 4: { - if (checkOpenCLPipeArg(S, Call)) - return true; - // The call with 4 arguments should be - // read/write_pipe(pipe T, reserve_id_t, uint, T*). - // Check reserve_id_t. - if (!Call->getArg(1)->getType()->isReserveIDT()) { - S.Diag(Call->getBeginLoc(), diag::err_opencl_builtin_pipe_invalid_arg) - << Call->getDirectCallee() << S.Context.OCLReserveIDTy - << Call->getArg(1)->getType() << Call->getArg(1)->getSourceRange(); - return true; - } - - // Check the index. - const Expr *Arg2 = Call->getArg(2); - if (!Arg2->getType()->isIntegerType() && - !Arg2->getType()->isUnsignedIntegerType()) { - S.Diag(Call->getBeginLoc(), diag::err_opencl_builtin_pipe_invalid_arg) - << Call->getDirectCallee() << S.Context.UnsignedIntTy - << Arg2->getType() << Arg2->getSourceRange(); - return true; - } - - // Check packet type T. - if (checkOpenCLPipePacketType(S, Call, 3)) - return true; - } break; - default: - S.Diag(Call->getBeginLoc(), diag::err_opencl_builtin_pipe_arg_num) - << Call->getDirectCallee() << Call->getSourceRange(); - return true; - } - - return false; -} - -// Performs a semantic analysis on the {work_group_/sub_group_ -// /_}reserve_{read/write}_pipe -// \param S Reference to the semantic analyzer. -// \param Call The call to the builtin function to be analyzed. -// \return True if a semantic error was found, false otherwise. -static bool BuiltinReserveRWPipe(Sema &S, CallExpr *Call) { - if (S.checkArgCount(Call, 2)) - return true; - - if (checkOpenCLPipeArg(S, Call)) - return true; - - // Check the reserve size. - if (!Call->getArg(1)->getType()->isIntegerType() && - !Call->getArg(1)->getType()->isUnsignedIntegerType()) { - S.Diag(Call->getBeginLoc(), diag::err_opencl_builtin_pipe_invalid_arg) - << Call->getDirectCallee() << S.Context.UnsignedIntTy - << Call->getArg(1)->getType() << Call->getArg(1)->getSourceRange(); - return true; - } - - // Since return type of reserve_read/write_pipe built-in function is - // reserve_id_t, which is not defined in the builtin def file , we used int - // as return type and need to override the return type of these functions. - Call->setType(S.Context.OCLReserveIDTy); - - return false; -} - -// Performs a semantic analysis on {work_group_/sub_group_ -// /_}commit_{read/write}_pipe -// \param S Reference to the semantic analyzer. -// \param Call The call to the builtin function to be analyzed. -// \return True if a semantic error was found, false otherwise. -static bool BuiltinCommitRWPipe(Sema &S, CallExpr *Call) { - if (S.checkArgCount(Call, 2)) - return true; - - if (checkOpenCLPipeArg(S, Call)) - return true; - - // Check reserve_id_t. - if (!Call->getArg(1)->getType()->isReserveIDT()) { - S.Diag(Call->getBeginLoc(), diag::err_opencl_builtin_pipe_invalid_arg) - << Call->getDirectCallee() << S.Context.OCLReserveIDTy - << Call->getArg(1)->getType() << Call->getArg(1)->getSourceRange(); - return true; - } - - return false; -} - -// Performs a semantic analysis on the call to built-in Pipe -// Query Functions. -// \param S Reference to the semantic analyzer. -// \param Call The call to the builtin function to be analyzed. -// \return True if a semantic error was found, false otherwise. -static bool BuiltinPipePackets(Sema &S, CallExpr *Call) { - if (S.checkArgCount(Call, 1)) - return true; - - if (!Call->getArg(0)->getType()->isPipeType()) { - S.Diag(Call->getBeginLoc(), diag::err_opencl_builtin_pipe_first_arg) - << Call->getDirectCallee() << Call->getArg(0)->getSourceRange(); - return true; - } - - return false; -} - -// OpenCL v2.0 s6.13.9 - Address space qualifier functions. -// Performs semantic analysis for the to_global/local/private call. -// \param S Reference to the semantic analyzer. -// \param BuiltinID ID of the builtin function. -// \param Call A pointer to the builtin call. -// \return True if a semantic error has been found, false otherwise. -static bool OpenCLBuiltinToAddr(Sema &S, unsigned BuiltinID, CallExpr *Call) { - if (S.checkArgCount(Call, 1)) - return true; - - auto RT = Call->getArg(0)->getType(); - if (!RT->isPointerType() || RT->getPointeeType() - .getAddressSpace() == LangAS::opencl_constant) { - S.Diag(Call->getBeginLoc(), diag::err_opencl_builtin_to_addr_invalid_arg) - << Call->getArg(0) << Call->getDirectCallee() << Call->getSourceRange(); - return true; - } - - if (RT->getPointeeType().getAddressSpace() != LangAS::opencl_generic) { - S.Diag(Call->getArg(0)->getBeginLoc(), - diag::warn_opencl_generic_address_space_arg) - << Call->getDirectCallee()->getNameInfo().getAsString() - << Call->getArg(0)->getSourceRange(); - } - - RT = RT->getPointeeType(); - auto Qual = RT.getQualifiers(); - switch (BuiltinID) { - case Builtin::BIto_global: - Qual.setAddressSpace(LangAS::opencl_global); - break; - case Builtin::BIto_local: - Qual.setAddressSpace(LangAS::opencl_local); - break; - case Builtin::BIto_private: - Qual.setAddressSpace(LangAS::opencl_private); - break; - default: - llvm_unreachable("Invalid builtin function"); - } - Call->setType(S.Context.getPointerType(S.Context.getQualifiedType( - RT.getUnqualifiedType(), Qual))); - - return false; -} - namespace { enum PointerAuthOpKind { PAO_Strip, @@ -3051,59 +2558,59 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BIwrite_pipe: // Since those two functions are declared with var args, we need a semantic // check for the argument. - if (BuiltinRWPipe(*this, TheCall)) + if (OpenCL().checkBuiltinRWPipe(TheCall)) return ExprError(); break; case Builtin::BIreserve_read_pipe: case Builtin::BIreserve_write_pipe: case Builtin::BIwork_group_reserve_read_pipe: case Builtin::BIwork_group_reserve_write_pipe: - if (BuiltinReserveRWPipe(*this, TheCall)) + if (OpenCL().checkBuiltinReserveRWPipe(TheCall)) return ExprError(); break; case Builtin::BIsub_group_reserve_read_pipe: case Builtin::BIsub_group_reserve_write_pipe: - if (checkOpenCLSubgroupExt(*this, TheCall) || - BuiltinReserveRWPipe(*this, TheCall)) + if (OpenCL().checkSubgroupExt(TheCall) || + OpenCL().checkBuiltinReserveRWPipe(TheCall)) return ExprError(); break; case Builtin::BIcommit_read_pipe: case Builtin::BIcommit_write_pipe: case Builtin::BIwork_group_commit_read_pipe: case Builtin::BIwork_group_commit_write_pipe: - if (BuiltinCommitRWPipe(*this, TheCall)) + if (OpenCL().checkBuiltinCommitRWPipe(TheCall)) return ExprError(); break; case Builtin::BIsub_group_commit_read_pipe: case Builtin::BIsub_group_commit_write_pipe: - if (checkOpenCLSubgroupExt(*this, TheCall) || - BuiltinCommitRWPipe(*this, TheCall)) + if (OpenCL().checkSubgroupExt(TheCall) || + OpenCL().checkBuiltinCommitRWPipe(TheCall)) return ExprError(); break; case Builtin::BIget_pipe_num_packets: case Builtin::BIget_pipe_max_packets: - if (BuiltinPipePackets(*this, TheCall)) + if (OpenCL().checkBuiltinPipePackets(TheCall)) return ExprError(); break; case Builtin::BIto_global: case Builtin::BIto_local: case Builtin::BIto_private: - if (OpenCLBuiltinToAddr(*this, BuiltinID, TheCall)) + if (OpenCL().checkBuiltinToAddr(BuiltinID, TheCall)) return ExprError(); break; // OpenCL v2.0, s6.13.17 - Enqueue kernel functions. case Builtin::BIenqueue_kernel: - if (OpenCLBuiltinEnqueueKernel(*this, TheCall)) + if (OpenCL().checkBuiltinEnqueueKernel(TheCall)) return ExprError(); break; case Builtin::BIget_kernel_work_group_size: case Builtin::BIget_kernel_preferred_work_group_size_multiple: - if (OpenCLBuiltinKernelWorkGroupSize(*this, TheCall)) + if (OpenCL().checkBuiltinKernelWorkGroupSize(TheCall)) return ExprError(); break; case Builtin::BIget_kernel_max_sub_group_size_for_ndrange: case Builtin::BIget_kernel_sub_group_count_for_ndrange: - if (OpenCLBuiltinNDRangeAndBlock(*this, TheCall)) + if (OpenCL().checkBuiltinNDRangeAndBlock(TheCall)) return ExprError(); break; case Builtin::BI__builtin_os_log_format: @@ -3351,6 +2858,11 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin_matrix_column_major_store: return BuiltinMatrixColumnMajorStore(TheCall, TheCallResult); + case Builtin::BI__builtin_verbose_trap: + if (!checkBuiltinVerboseTrap(TheCall, *this)) + return ExprError(); + break; + case Builtin::BI__builtin_get_device_side_mangled_name: { auto Check = [](CallExpr *TheCall) { if (TheCall->getNumArgs() != 1) @@ -3393,7 +2905,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, } } - if (getLangOpts().HLSL && CheckHLSLBuiltinFunctionCall(BuiltinID, TheCall)) + if (getLangOpts().HLSL && HLSL().CheckBuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); // Since the target specific builtins for each arch overlap, only check those @@ -3441,234 +2953,6 @@ bool Sema::ValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum) { << ArgNum << Arg->getSourceRange(); } -// Helper function for CheckHLSLBuiltinFunctionCall -bool CheckVectorElementCallArgs(Sema *S, CallExpr *TheCall) { - assert(TheCall->getNumArgs() > 1); - ExprResult A = TheCall->getArg(0); - - QualType ArgTyA = A.get()->getType(); - - auto *VecTyA = ArgTyA->getAs(); - SourceLocation BuiltinLoc = TheCall->getBeginLoc(); - - for (unsigned i = 1; i < TheCall->getNumArgs(); ++i) { - ExprResult B = TheCall->getArg(i); - QualType ArgTyB = B.get()->getType(); - auto *VecTyB = ArgTyB->getAs(); - if (VecTyA == nullptr && VecTyB == nullptr) - return false; - - if (VecTyA && VecTyB) { - bool retValue = false; - if (VecTyA->getElementType() != VecTyB->getElementType()) { - // Note: type promotion is intended to be handeled via the intrinsics - // and not the builtin itself. - S->Diag(TheCall->getBeginLoc(), - diag::err_vec_builtin_incompatible_vector) - << TheCall->getDirectCallee() << /*useAllTerminology*/ true - << SourceRange(A.get()->getBeginLoc(), B.get()->getEndLoc()); - retValue = true; - } - if (VecTyA->getNumElements() != VecTyB->getNumElements()) { - // You should only be hitting this case if you are calling the builtin - // directly. HLSL intrinsics should avoid this case via a - // HLSLVectorTruncation. - S->Diag(BuiltinLoc, diag::err_vec_builtin_incompatible_vector) - << TheCall->getDirectCallee() << /*useAllTerminology*/ true - << SourceRange(TheCall->getArg(0)->getBeginLoc(), - TheCall->getArg(1)->getEndLoc()); - retValue = true; - } - return retValue; - } - } - - // Note: if we get here one of the args is a scalar which - // requires a VectorSplat on Arg0 or Arg1 - S->Diag(BuiltinLoc, diag::err_vec_builtin_non_vector) - << TheCall->getDirectCallee() << /*useAllTerminology*/ true - << SourceRange(TheCall->getArg(0)->getBeginLoc(), - TheCall->getArg(1)->getEndLoc()); - return true; -} - -bool CheckArgsTypesAreCorrect( - Sema *S, CallExpr *TheCall, QualType ExpectedType, - llvm::function_ref Check) { - for (unsigned i = 0; i < TheCall->getNumArgs(); ++i) { - QualType PassedType = TheCall->getArg(i)->getType(); - if (Check(PassedType)) { - if (auto *VecTyA = PassedType->getAs()) - ExpectedType = S->Context.getVectorType( - ExpectedType, VecTyA->getNumElements(), VecTyA->getVectorKind()); - S->Diag(TheCall->getArg(0)->getBeginLoc(), - diag::err_typecheck_convert_incompatible) - << PassedType << ExpectedType << 1 << 0 << 0; - return true; - } - } - return false; -} - -bool CheckAllArgsHaveFloatRepresentation(Sema *S, CallExpr *TheCall) { - auto checkAllFloatTypes = [](clang::QualType PassedType) -> bool { - return !PassedType->hasFloatingRepresentation(); - }; - return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy, - checkAllFloatTypes); -} - -bool CheckFloatOrHalfRepresentations(Sema *S, CallExpr *TheCall) { - auto checkFloatorHalf = [](clang::QualType PassedType) -> bool { - clang::QualType BaseType = - PassedType->isVectorType() - ? PassedType->getAs()->getElementType() - : PassedType; - return !BaseType->isHalfType() && !BaseType->isFloat32Type(); - }; - return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy, - checkFloatorHalf); -} - -bool CheckNoDoubleVectors(Sema *S, CallExpr *TheCall) { - auto checkDoubleVector = [](clang::QualType PassedType) -> bool { - if (const auto *VecTy = PassedType->getAs()) - return VecTy->getElementType()->isDoubleType(); - return false; - }; - return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy, - checkDoubleVector); -} - -bool CheckUnsignedIntRepresentation(Sema *S, CallExpr *TheCall) { - auto checkAllUnsignedTypes = [](clang::QualType PassedType) -> bool { - return !PassedType->hasUnsignedIntegerRepresentation(); - }; - return CheckArgsTypesAreCorrect(S, TheCall, S->Context.UnsignedIntTy, - checkAllUnsignedTypes); -} - -void SetElementTypeAsReturnType(Sema *S, CallExpr *TheCall, - QualType ReturnType) { - auto *VecTyA = TheCall->getArg(0)->getType()->getAs(); - if (VecTyA) - ReturnType = S->Context.getVectorType(ReturnType, VecTyA->getNumElements(), - VectorKind::Generic); - TheCall->setType(ReturnType); -} - -// Note: returning true in this case results in CheckBuiltinFunctionCall -// returning an ExprError -bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { - switch (BuiltinID) { - case Builtin::BI__builtin_hlsl_elementwise_all: - case Builtin::BI__builtin_hlsl_elementwise_any: { - if (checkArgCount(TheCall, 1)) - return true; - break; - } - case Builtin::BI__builtin_hlsl_elementwise_clamp: { - if (checkArgCount(TheCall, 3)) - return true; - if (CheckVectorElementCallArgs(this, TheCall)) - return true; - if (BuiltinElementwiseTernaryMath( - TheCall, /*CheckForFloatArgs*/ - TheCall->getArg(0)->getType()->hasFloatingRepresentation())) - return true; - break; - } - case Builtin::BI__builtin_hlsl_dot: { - if (checkArgCount(TheCall, 2)) - return true; - if (CheckVectorElementCallArgs(this, TheCall)) - return true; - if (BuiltinVectorToScalarMath(TheCall)) - return true; - if (CheckNoDoubleVectors(this, TheCall)) - return true; - break; - } - case Builtin::BI__builtin_hlsl_elementwise_rcp: { - if (CheckAllArgsHaveFloatRepresentation(this, TheCall)) - return true; - if (PrepareBuiltinElementwiseMathOneArgCall(TheCall)) - return true; - break; - } - case Builtin::BI__builtin_hlsl_elementwise_rsqrt: - case Builtin::BI__builtin_hlsl_elementwise_frac: { - if (CheckFloatOrHalfRepresentations(this, TheCall)) - return true; - if (PrepareBuiltinElementwiseMathOneArgCall(TheCall)) - return true; - break; - } - case Builtin::BI__builtin_hlsl_elementwise_isinf: { - if (CheckFloatOrHalfRepresentations(this, TheCall)) - return true; - if (PrepareBuiltinElementwiseMathOneArgCall(TheCall)) - return true; - SetElementTypeAsReturnType(this, TheCall, this->Context.BoolTy); - break; - } - case Builtin::BI__builtin_hlsl_lerp: { - if (checkArgCount(TheCall, 3)) - return true; - if (CheckVectorElementCallArgs(this, TheCall)) - return true; - if (BuiltinElementwiseTernaryMath(TheCall)) - return true; - if (CheckFloatOrHalfRepresentations(this, TheCall)) - return true; - break; - } - case Builtin::BI__builtin_hlsl_mad: { - if (checkArgCount(TheCall, 3)) - return true; - if (CheckVectorElementCallArgs(this, TheCall)) - return true; - if (BuiltinElementwiseTernaryMath( - TheCall, /*CheckForFloatArgs*/ - TheCall->getArg(0)->getType()->hasFloatingRepresentation())) - return true; - break; - } - // Note these are llvm builtins that we want to catch invalid intrinsic - // generation. Normal handling of these builitns will occur elsewhere. - case Builtin::BI__builtin_elementwise_bitreverse: { - if (CheckUnsignedIntRepresentation(this, TheCall)) - return true; - break; - } - case Builtin::BI__builtin_elementwise_acos: - case Builtin::BI__builtin_elementwise_asin: - case Builtin::BI__builtin_elementwise_atan: - case Builtin::BI__builtin_elementwise_ceil: - case Builtin::BI__builtin_elementwise_cos: - case Builtin::BI__builtin_elementwise_cosh: - case Builtin::BI__builtin_elementwise_exp: - case Builtin::BI__builtin_elementwise_exp2: - case Builtin::BI__builtin_elementwise_floor: - case Builtin::BI__builtin_elementwise_log: - case Builtin::BI__builtin_elementwise_log2: - case Builtin::BI__builtin_elementwise_log10: - case Builtin::BI__builtin_elementwise_pow: - case Builtin::BI__builtin_elementwise_roundeven: - case Builtin::BI__builtin_elementwise_sin: - case Builtin::BI__builtin_elementwise_sinh: - case Builtin::BI__builtin_elementwise_sqrt: - case Builtin::BI__builtin_elementwise_tan: - case Builtin::BI__builtin_elementwise_tanh: - case Builtin::BI__builtin_elementwise_trunc: { - if (CheckFloatOrHalfRepresentations(this, TheCall)) - return true; - break; - } - } - return false; -} - /// Given a FunctionDecl's FormatAttr, attempts to populate the FomatStringInfo /// parameter with the FormatAttr's correct format_idx and firstDataArg. /// Returns true when the format fits the function and the FormatStringInfo has @@ -3740,58 +3024,6 @@ static void CheckNonNullArgument(Sema &S, << ArgExpr->getSourceRange()); } -bool Sema::GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx) { - FormatStringInfo FSI; - if ((GetFormatStringType(Format) == FST_NSString) && - getFormatStringInfo(Format, false, true, &FSI)) { - Idx = FSI.FormatIdx; - return true; - } - return false; -} - -/// Diagnose use of %s directive in an NSString which is being passed -/// as formatting string to formatting method. -static void -DiagnoseCStringFormatDirectiveInCFAPI(Sema &S, - const NamedDecl *FDecl, - Expr **Args, - unsigned NumArgs) { - unsigned Idx = 0; - bool Format = false; - ObjCStringFormatFamily SFFamily = FDecl->getObjCFStringFormattingFamily(); - if (SFFamily == ObjCStringFormatFamily::SFF_CFString) { - Idx = 2; - Format = true; - } - else - for (const auto *I : FDecl->specific_attrs()) { - if (S.GetFormatNSStringIdx(I, Idx)) { - Format = true; - break; - } - } - if (!Format || NumArgs <= Idx) - return; - const Expr *FormatExpr = Args[Idx]; - if (const CStyleCastExpr *CSCE = dyn_cast(FormatExpr)) - FormatExpr = CSCE->getSubExpr(); - const StringLiteral *FormatString; - if (const ObjCStringLiteral *OSL = - dyn_cast(FormatExpr->IgnoreParenImpCasts())) - FormatString = OSL->getString(); - else - FormatString = dyn_cast(FormatExpr->IgnoreParenImpCasts()); - if (!FormatString) - return; - if (S.FormatStringHasSArg(FormatString)) { - S.Diag(FormatExpr->getExprLoc(), diag::warn_objc_cdirective_format_string) - << "%s" << 1 << 1; - S.Diag(FDecl->getLocation(), diag::note_entity_declared_at) - << FDecl->getDeclName(); - } -} - /// Determine whether the given type has a non-null nullability annotation. static bool isNonNullType(QualType type) { if (auto nullability = type->getNullability()) @@ -4208,7 +3440,7 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, CheckInfNaNFunction(TheCall, FDecl); if (getLangOpts().ObjC) - DiagnoseCStringFormatDirectiveInCFAPI(*this, FDecl, Args, NumArgs); + ObjC().DiagnoseCStringFormatDirectiveInCFAPI(FDecl, Args, NumArgs); unsigned CMId = FDecl->getMemoryFunctionKind(); @@ -4582,6 +3814,9 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, } // Pointer to object of size zero is not allowed. + if (RequireCompleteType(Ptr->getBeginLoc(), AtomTy, + diag::err_incomplete_type)) + return ExprError(); if (Context.getTypeInfoInChars(AtomTy).Width.isZero()) { Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer) << Ptr->getType() << 1 << Ptr->getSourceRange(); @@ -11274,26 +10509,6 @@ static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, DiagnoseImpCast(S, E, E->getType(), T, CContext, diag, pruneControlFlow); } -static bool isObjCSignedCharBool(Sema &S, QualType Ty) { - return Ty->isSpecificBuiltinType(BuiltinType::SChar) && - S.getLangOpts().ObjC && S.ObjC().NSAPIObj->isObjCBOOLType(Ty); -} - -static void adornObjCBoolConversionDiagWithTernaryFixit( - Sema &S, Expr *SourceExpr, const Sema::SemaDiagnosticBuilder &Builder) { - Expr *Ignored = SourceExpr->IgnoreImplicit(); - if (const auto *OVE = dyn_cast(Ignored)) - Ignored = OVE->getSourceExpr(); - bool NeedsParens = isa(Ignored) || - isa(Ignored) || - isa(Ignored); - SourceLocation EndLoc = S.getLocForEndOfToken(SourceExpr->getEndLoc()); - if (NeedsParens) - Builder << FixItHint::CreateInsertion(SourceExpr->getBeginLoc(), "(") - << FixItHint::CreateInsertion(EndLoc, ")"); - Builder << FixItHint::CreateInsertion(EndLoc, " ? YES : NO"); -} - /// Diagnose an implicit cast from a floating point value to an integer value. static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, SourceLocation CContext) { @@ -11313,11 +10528,10 @@ static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, bool IsConstant = E->EvaluateAsFloat(Value, S.Context, Expr::SE_AllowSideEffects); if (!IsConstant) { - if (isObjCSignedCharBool(S, T)) { - return adornObjCBoolConversionDiagWithTernaryFixit( - S, E, - S.Diag(CContext, diag::warn_impcast_float_to_objc_signed_char_bool) - << E->getType()); + if (S.ObjC().isSignedCharBool(T)) { + return S.ObjC().adornBoolConversionDiagWithTernaryFixit( + E, S.Diag(CContext, diag::warn_impcast_float_to_objc_signed_char_bool) + << E->getType()); } return DiagnoseImpCast(S, E, T, CContext, @@ -11341,11 +10555,10 @@ static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, precision = (precision * 59 + 195) / 196; Value.toString(PrettySourceValue, precision); - if (isObjCSignedCharBool(S, T) && IntegerValue != 0 && IntegerValue != 1) { - return adornObjCBoolConversionDiagWithTernaryFixit( - S, E, - S.Diag(CContext, diag::warn_impcast_constant_value_to_objc_bool) - << PrettySourceValue); + if (S.ObjC().isSignedCharBool(T) && IntegerValue != 0 && IntegerValue != 1) { + return S.ObjC().adornBoolConversionDiagWithTernaryFixit( + E, S.Diag(CContext, diag::warn_impcast_constant_value_to_objc_bool) + << PrettySourceValue); } if (Result == llvm::APFloat::opOK && isExact) { @@ -11546,102 +10759,6 @@ static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, S.getFixItZeroLiteralForType(T, Loc)); } -static void checkObjCArrayLiteral(Sema &S, QualType TargetType, - ObjCArrayLiteral *ArrayLiteral); - -static void -checkObjCDictionaryLiteral(Sema &S, QualType TargetType, - ObjCDictionaryLiteral *DictionaryLiteral); - -/// Check a single element within a collection literal against the -/// target element type. -static void checkObjCCollectionLiteralElement(Sema &S, - QualType TargetElementType, - Expr *Element, - unsigned ElementKind) { - // Skip a bitcast to 'id' or qualified 'id'. - if (auto ICE = dyn_cast(Element)) { - if (ICE->getCastKind() == CK_BitCast && - ICE->getSubExpr()->getType()->getAs()) - Element = ICE->getSubExpr(); - } - - QualType ElementType = Element->getType(); - ExprResult ElementResult(Element); - if (ElementType->getAs() && - S.CheckSingleAssignmentConstraints(TargetElementType, - ElementResult, - false, false) - != Sema::Compatible) { - S.Diag(Element->getBeginLoc(), diag::warn_objc_collection_literal_element) - << ElementType << ElementKind << TargetElementType - << Element->getSourceRange(); - } - - if (auto ArrayLiteral = dyn_cast(Element)) - checkObjCArrayLiteral(S, TargetElementType, ArrayLiteral); - else if (auto DictionaryLiteral = dyn_cast(Element)) - checkObjCDictionaryLiteral(S, TargetElementType, DictionaryLiteral); -} - -/// Check an Objective-C array literal being converted to the given -/// target type. -static void checkObjCArrayLiteral(Sema &S, QualType TargetType, - ObjCArrayLiteral *ArrayLiteral) { - if (!S.ObjC().NSArrayDecl) - return; - - const auto *TargetObjCPtr = TargetType->getAs(); - if (!TargetObjCPtr) - return; - - if (TargetObjCPtr->isUnspecialized() || - TargetObjCPtr->getInterfaceDecl()->getCanonicalDecl() != - S.ObjC().NSArrayDecl->getCanonicalDecl()) - return; - - auto TypeArgs = TargetObjCPtr->getTypeArgs(); - if (TypeArgs.size() != 1) - return; - - QualType TargetElementType = TypeArgs[0]; - for (unsigned I = 0, N = ArrayLiteral->getNumElements(); I != N; ++I) { - checkObjCCollectionLiteralElement(S, TargetElementType, - ArrayLiteral->getElement(I), - 0); - } -} - -/// Check an Objective-C dictionary literal being converted to the given -/// target type. -static void -checkObjCDictionaryLiteral(Sema &S, QualType TargetType, - ObjCDictionaryLiteral *DictionaryLiteral) { - if (!S.ObjC().NSDictionaryDecl) - return; - - const auto *TargetObjCPtr = TargetType->getAs(); - if (!TargetObjCPtr) - return; - - if (TargetObjCPtr->isUnspecialized() || - TargetObjCPtr->getInterfaceDecl()->getCanonicalDecl() != - S.ObjC().NSDictionaryDecl->getCanonicalDecl()) - return; - - auto TypeArgs = TargetObjCPtr->getTypeArgs(); - if (TypeArgs.size() != 2) - return; - - QualType TargetKeyType = TypeArgs[0]; - QualType TargetObjectType = TypeArgs[1]; - for (unsigned I = 0, N = DictionaryLiteral->getNumElements(); I != N; ++I) { - auto Element = DictionaryLiteral->getKeyValueElement(I); - checkObjCCollectionLiteralElement(S, TargetKeyType, Element.Key, 1); - checkObjCCollectionLiteralElement(S, TargetObjectType, Element.Value, 2); - } -} - // Helper function to filter out cases for constant width constant conversion. // Don't warn on char array initialization or for non-decimal values. static bool isSameWidthConstantConversion(Sema &S, Expr *E, QualType T, @@ -11717,14 +10834,12 @@ static void DiagnoseIntInBoolContext(Sema &S, Expr *E) { } } -static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, - SourceLocation CC, - bool *ICContext = nullptr, - bool IsListInit = false) { +void Sema::CheckImplicitConversion(Expr *E, QualType T, SourceLocation CC, + bool *ICContext, bool IsListInit) { if (E->isTypeDependent() || E->isValueDependent()) return; - const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr(); - const Type *Target = S.Context.getCanonicalType(T).getTypePtr(); + const Type *Source = Context.getCanonicalType(E->getType()).getTypePtr(); + const Type *Target = Context.getCanonicalType(T).getTypePtr(); if (Source == Target) return; if (Target->isDependentType()) return; @@ -11737,7 +10852,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, return; if (Source->isAtomicType()) - S.Diag(E->getExprLoc(), diag::warn_atomic_implicit_seq_cst); + Diag(E->getExprLoc(), diag::warn_atomic_implicit_seq_cst); // Diagnose implicit casts to bool. if (Target->isSpecificBuiltinType(BuiltinType::Bool)) { @@ -11745,34 +10860,32 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, // Warn on string literal to bool. Checks for string literals in logical // and expressions, for instance, assert(0 && "error here"), are // prevented by a check in AnalyzeImplicitConversions(). - return DiagnoseImpCast(S, E, T, CC, + return DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_string_literal_to_bool); if (isa(E) || isa(E) || isa(E) || isa(E)) { // This covers the literal expressions that evaluate to Objective-C // objects. - return DiagnoseImpCast(S, E, T, CC, + return DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_objective_c_literal_to_bool); } if (Source->isPointerType() || Source->canDecayToPointerType()) { // Warn on pointer to bool conversion that is always true. - S.DiagnoseAlwaysNonNullPointer(E, Expr::NPCK_NotNull, /*IsEqual*/ false, - SourceRange(CC)); + DiagnoseAlwaysNonNullPointer(E, Expr::NPCK_NotNull, /*IsEqual*/ false, + SourceRange(CC)); } } // If the we're converting a constant to an ObjC BOOL on a platform where BOOL // is a typedef for signed char (macOS), then that constant value has to be 1 // or 0. - if (isObjCSignedCharBool(S, T) && Source->isIntegralType(S.Context)) { + if (ObjC().isSignedCharBool(T) && Source->isIntegralType(Context)) { Expr::EvalResult Result; - if (E->EvaluateAsInt(Result, S.getASTContext(), - Expr::SE_AllowSideEffects)) { + if (E->EvaluateAsInt(Result, getASTContext(), Expr::SE_AllowSideEffects)) { if (Result.Val.getInt() != 1 && Result.Val.getInt() != 0) { - adornObjCBoolConversionDiagWithTernaryFixit( - S, E, - S.Diag(CC, diag::warn_impcast_constant_value_to_objc_bool) - << toString(Result.Val.getInt(), 10)); + ObjC().adornBoolConversionDiagWithTernaryFixit( + E, Diag(CC, diag::warn_impcast_constant_value_to_objc_bool) + << toString(Result.Val.getInt(), 10)); } return; } @@ -11781,42 +10894,43 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, // Check implicit casts from Objective-C collection literals to specialized // collection types, e.g., NSArray *. if (auto *ArrayLiteral = dyn_cast(E)) - checkObjCArrayLiteral(S, QualType(Target, 0), ArrayLiteral); + ObjC().checkArrayLiteral(QualType(Target, 0), ArrayLiteral); else if (auto *DictionaryLiteral = dyn_cast(E)) - checkObjCDictionaryLiteral(S, QualType(Target, 0), DictionaryLiteral); + ObjC().checkDictionaryLiteral(QualType(Target, 0), DictionaryLiteral); // Strip vector types. if (isa(Source)) { if (Target->isSveVLSBuiltinType() && - (S.Context.areCompatibleSveTypes(QualType(Target, 0), - QualType(Source, 0)) || - S.Context.areLaxCompatibleSveTypes(QualType(Target, 0), - QualType(Source, 0)))) + (Context.areCompatibleSveTypes(QualType(Target, 0), + QualType(Source, 0)) || + Context.areLaxCompatibleSveTypes(QualType(Target, 0), + QualType(Source, 0)))) return; if (Target->isRVVVLSBuiltinType() && - (S.Context.areCompatibleRVVTypes(QualType(Target, 0), - QualType(Source, 0)) || - S.Context.areLaxCompatibleRVVTypes(QualType(Target, 0), - QualType(Source, 0)))) + (Context.areCompatibleRVVTypes(QualType(Target, 0), + QualType(Source, 0)) || + Context.areLaxCompatibleRVVTypes(QualType(Target, 0), + QualType(Source, 0)))) return; if (!isa(Target)) { - if (S.SourceMgr.isInSystemMacro(CC)) + if (SourceMgr.isInSystemMacro(CC)) return; - return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_vector_scalar); - } else if (S.getLangOpts().HLSL && + return DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_vector_scalar); + } else if (getLangOpts().HLSL && Target->castAs()->getNumElements() < Source->castAs()->getNumElements()) { // Diagnose vector truncation but don't return. We may also want to // diagnose an element conversion. - DiagnoseImpCast(S, E, T, CC, diag::warn_hlsl_impcast_vector_truncation); + DiagnoseImpCast(*this, E, T, CC, + diag::warn_hlsl_impcast_vector_truncation); } // If the vector cast is cast between two vectors of the same size, it is // a bitcast, not a conversion, except under HLSL where it is a conversion. - if (!S.getLangOpts().HLSL && - S.Context.getTypeSize(Source) == S.Context.getTypeSize(Target)) + if (!getLangOpts().HLSL && + Context.getTypeSize(Source) == Context.getTypeSize(Target)) return; Source = cast(Source)->getElementType().getTypePtr(); @@ -11828,11 +10942,11 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, // Strip complex types. if (isa(Source)) { if (!isa(Target)) { - if (S.SourceMgr.isInSystemMacro(CC) || Target->isBooleanType()) + if (SourceMgr.isInSystemMacro(CC) || Target->isBooleanType()) return; - return DiagnoseImpCast(S, E, T, CC, - S.getLangOpts().CPlusPlus + return DiagnoseImpCast(*this, E, T, CC, + getLangOpts().CPlusPlus ? diag::err_impcast_complex_scalar : diag::warn_impcast_complex_scalar); } @@ -11847,25 +10961,25 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, // Strip SVE vector types if (SourceBT && SourceBT->isSveVLSBuiltinType()) { // Need the original target type for vector type checks - const Type *OriginalTarget = S.Context.getCanonicalType(T).getTypePtr(); + const Type *OriginalTarget = Context.getCanonicalType(T).getTypePtr(); // Handle conversion from scalable to fixed when msve-vector-bits is // specified - if (S.Context.areCompatibleSveTypes(QualType(OriginalTarget, 0), - QualType(Source, 0)) || - S.Context.areLaxCompatibleSveTypes(QualType(OriginalTarget, 0), - QualType(Source, 0))) + if (Context.areCompatibleSveTypes(QualType(OriginalTarget, 0), + QualType(Source, 0)) || + Context.areLaxCompatibleSveTypes(QualType(OriginalTarget, 0), + QualType(Source, 0))) return; // If the vector cast is cast between two vectors of the same size, it is // a bitcast, not a conversion. - if (S.Context.getTypeSize(Source) == S.Context.getTypeSize(Target)) + if (Context.getTypeSize(Source) == Context.getTypeSize(Target)) return; - Source = SourceBT->getSveEltType(S.Context).getTypePtr(); + Source = SourceBT->getSveEltType(Context).getTypePtr(); } if (TargetBT && TargetBT->isSveVLSBuiltinType()) - Target = TargetBT->getSveEltType(S.Context).getTypePtr(); + Target = TargetBT->getSveEltType(Context).getTypePtr(); // If the source is floating point... if (SourceBT && SourceBT->isFloatingPoint()) { @@ -11873,41 +10987,42 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, if (TargetBT && TargetBT->isFloatingPoint()) { // ...then warn if we're dropping FP rank. - int Order = S.getASTContext().getFloatingTypeSemanticOrder( + int Order = getASTContext().getFloatingTypeSemanticOrder( QualType(SourceBT, 0), QualType(TargetBT, 0)); if (Order > 0) { // Don't warn about float constants that are precisely // representable in the target type. Expr::EvalResult result; - if (E->EvaluateAsRValue(result, S.Context)) { + if (E->EvaluateAsRValue(result, Context)) { // Value might be a float, a float vector, or a float complex. - if (IsSameFloatAfterCast(result.Val, - S.Context.getFloatTypeSemantics(QualType(TargetBT, 0)), - S.Context.getFloatTypeSemantics(QualType(SourceBT, 0)))) + if (IsSameFloatAfterCast( + result.Val, + Context.getFloatTypeSemantics(QualType(TargetBT, 0)), + Context.getFloatTypeSemantics(QualType(SourceBT, 0)))) return; } - if (S.SourceMgr.isInSystemMacro(CC)) + if (SourceMgr.isInSystemMacro(CC)) return; - DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_float_precision); + DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_float_precision); } // ... or possibly if we're increasing rank, too else if (Order < 0) { - if (S.SourceMgr.isInSystemMacro(CC)) + if (SourceMgr.isInSystemMacro(CC)) return; - DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_double_promotion); + DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_double_promotion); } return; } // If the target is integral, always warn. if (TargetBT && TargetBT->isInteger()) { - if (S.SourceMgr.isInSystemMacro(CC)) + if (SourceMgr.isInSystemMacro(CC)) return; - DiagnoseFloatingImpCast(S, E, T, CC); + DiagnoseFloatingImpCast(*this, E, T, CC); } // Detect the case where a call result is converted from floating-point to @@ -11929,7 +11044,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, if (isa(LastA) && InnerE->getType()->isBooleanType()) { // Warn on this floating-point to bool conversion - DiagnoseImpCast(S, E, T, CC, + DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_floating_point_to_bool); } } @@ -11941,38 +11056,37 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, if (Source->isFixedPointType()) { if (Target->isUnsaturatedFixedPointType()) { Expr::EvalResult Result; - if (E->EvaluateAsFixedPoint(Result, S.Context, Expr::SE_AllowSideEffects, - S.isConstantEvaluatedContext())) { + if (E->EvaluateAsFixedPoint(Result, Context, Expr::SE_AllowSideEffects, + isConstantEvaluatedContext())) { llvm::APFixedPoint Value = Result.Val.getFixedPoint(); - llvm::APFixedPoint MaxVal = S.Context.getFixedPointMax(T); - llvm::APFixedPoint MinVal = S.Context.getFixedPointMin(T); + llvm::APFixedPoint MaxVal = Context.getFixedPointMax(T); + llvm::APFixedPoint MinVal = Context.getFixedPointMin(T); if (Value > MaxVal || Value < MinVal) { - S.DiagRuntimeBehavior(E->getExprLoc(), E, - S.PDiag(diag::warn_impcast_fixed_point_range) - << Value.toString() << T - << E->getSourceRange() - << clang::SourceRange(CC)); + DiagRuntimeBehavior(E->getExprLoc(), E, + PDiag(diag::warn_impcast_fixed_point_range) + << Value.toString() << T + << E->getSourceRange() + << clang::SourceRange(CC)); return; } } } else if (Target->isIntegerType()) { Expr::EvalResult Result; - if (!S.isConstantEvaluatedContext() && - E->EvaluateAsFixedPoint(Result, S.Context, - Expr::SE_AllowSideEffects)) { + if (!isConstantEvaluatedContext() && + E->EvaluateAsFixedPoint(Result, Context, Expr::SE_AllowSideEffects)) { llvm::APFixedPoint FXResult = Result.Val.getFixedPoint(); bool Overflowed; llvm::APSInt IntResult = FXResult.convertToInt( - S.Context.getIntWidth(T), - Target->isSignedIntegerOrEnumerationType(), &Overflowed); + Context.getIntWidth(T), Target->isSignedIntegerOrEnumerationType(), + &Overflowed); if (Overflowed) { - S.DiagRuntimeBehavior(E->getExprLoc(), E, - S.PDiag(diag::warn_impcast_fixed_point_range) - << FXResult.toString() << T - << E->getSourceRange() - << clang::SourceRange(CC)); + DiagRuntimeBehavior(E->getExprLoc(), E, + PDiag(diag::warn_impcast_fixed_point_range) + << FXResult.toString() << T + << E->getSourceRange() + << clang::SourceRange(CC)); return; } } @@ -11980,20 +11094,20 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, } else if (Target->isUnsaturatedFixedPointType()) { if (Source->isIntegerType()) { Expr::EvalResult Result; - if (!S.isConstantEvaluatedContext() && - E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects)) { + if (!isConstantEvaluatedContext() && + E->EvaluateAsInt(Result, Context, Expr::SE_AllowSideEffects)) { llvm::APSInt Value = Result.Val.getInt(); bool Overflowed; llvm::APFixedPoint IntResult = llvm::APFixedPoint::getFromIntValue( - Value, S.Context.getFixedPointSemantics(T), &Overflowed); + Value, Context.getFixedPointSemantics(T), &Overflowed); if (Overflowed) { - S.DiagRuntimeBehavior(E->getExprLoc(), E, - S.PDiag(diag::warn_impcast_fixed_point_range) - << toString(Value, /*Radix=*/10) << T - << E->getSourceRange() - << clang::SourceRange(CC)); + DiagRuntimeBehavior(E->getExprLoc(), E, + PDiag(diag::warn_impcast_fixed_point_range) + << toString(Value, /*Radix=*/10) << T + << E->getSourceRange() + << clang::SourceRange(CC)); return; } } @@ -12007,25 +11121,25 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, TargetBT->isFloatingType() && !IsListInit) { // Determine the number of precision bits in the source integer type. IntRange SourceRange = - GetExprRange(S.Context, E, S.isConstantEvaluatedContext(), + GetExprRange(Context, E, isConstantEvaluatedContext(), /*Approximate=*/true); unsigned int SourcePrecision = SourceRange.Width; // Determine the number of precision bits in the // target floating point type. unsigned int TargetPrecision = llvm::APFloatBase::semanticsPrecision( - S.Context.getFloatTypeSemantics(QualType(TargetBT, 0))); + Context.getFloatTypeSemantics(QualType(TargetBT, 0))); if (SourcePrecision > 0 && TargetPrecision > 0 && SourcePrecision > TargetPrecision) { if (std::optional SourceInt = - E->getIntegerConstantExpr(S.Context)) { + E->getIntegerConstantExpr(Context)) { // If the source integer is a constant, convert it to the target // floating point type. Issue a warning if the value changes // during the whole conversion. llvm::APFloat TargetFloatValue( - S.Context.getFloatTypeSemantics(QualType(TargetBT, 0))); + Context.getFloatTypeSemantics(QualType(TargetBT, 0))); llvm::APFloat::opStatus ConversionStatus = TargetFloatValue.convertFromAPInt( *SourceInt, SourceBT->isSignedInteger(), @@ -12037,26 +11151,26 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, SmallString<32> PrettyTargetValue; TargetFloatValue.toString(PrettyTargetValue, TargetPrecision); - S.DiagRuntimeBehavior( + DiagRuntimeBehavior( E->getExprLoc(), E, - S.PDiag(diag::warn_impcast_integer_float_precision_constant) + PDiag(diag::warn_impcast_integer_float_precision_constant) << PrettySourceValue << PrettyTargetValue << E->getType() << T << E->getSourceRange() << clang::SourceRange(CC)); } } else { // Otherwise, the implicit conversion may lose precision. - DiagnoseImpCast(S, E, T, CC, + DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_integer_float_precision); } } } - DiagnoseNullConversion(S, E, T, CC); + DiagnoseNullConversion(*this, E, T, CC); - S.DiscardMisalignedMemberAddress(Target, E); + DiscardMisalignedMemberAddress(Target, E); if (Target->isBooleanType()) - DiagnoseIntInBoolContext(S, E); + DiagnoseIntInBoolContext(*this, E); if (!Source->isIntegerType() || !Target->isIntegerType()) return; @@ -12066,51 +11180,51 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, if (Target->isSpecificBuiltinType(BuiltinType::Bool)) return; - if (isObjCSignedCharBool(S, T) && !Source->isCharType() && + if (ObjC().isSignedCharBool(T) && !Source->isCharType() && !E->isKnownToHaveBooleanValue(/*Semantic=*/false)) { - return adornObjCBoolConversionDiagWithTernaryFixit( - S, E, - S.Diag(CC, diag::warn_impcast_int_to_objc_signed_char_bool) - << E->getType()); + return ObjC().adornBoolConversionDiagWithTernaryFixit( + E, Diag(CC, diag::warn_impcast_int_to_objc_signed_char_bool) + << E->getType()); } IntRange SourceTypeRange = - IntRange::forTargetOfCanonicalType(S.Context, Source); + IntRange::forTargetOfCanonicalType(Context, Source); IntRange LikelySourceRange = GetExprRange( - S.Context, E, S.isConstantEvaluatedContext(), /*Approximate=*/true); - IntRange TargetRange = IntRange::forTargetOfCanonicalType(S.Context, Target); + Context, E, isConstantEvaluatedContext(), /*Approximate=*/true); + IntRange TargetRange = IntRange::forTargetOfCanonicalType(Context, Target); if (LikelySourceRange.Width > TargetRange.Width) { // If the source is a constant, use a default-on diagnostic. // TODO: this should happen for bitfield stores, too. Expr::EvalResult Result; - if (E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects, - S.isConstantEvaluatedContext())) { + if (E->EvaluateAsInt(Result, Context, Expr::SE_AllowSideEffects, + isConstantEvaluatedContext())) { llvm::APSInt Value(32); Value = Result.Val.getInt(); - if (S.SourceMgr.isInSystemMacro(CC)) + if (SourceMgr.isInSystemMacro(CC)) return; std::string PrettySourceValue = toString(Value, 10); std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange); - S.DiagRuntimeBehavior( - E->getExprLoc(), E, - S.PDiag(diag::warn_impcast_integer_precision_constant) - << PrettySourceValue << PrettyTargetValue << E->getType() << T - << E->getSourceRange() << SourceRange(CC)); + DiagRuntimeBehavior(E->getExprLoc(), E, + PDiag(diag::warn_impcast_integer_precision_constant) + << PrettySourceValue << PrettyTargetValue + << E->getType() << T << E->getSourceRange() + << SourceRange(CC)); return; } // People want to build with -Wshorten-64-to-32 and not -Wconversion. - if (S.SourceMgr.isInSystemMacro(CC)) + if (SourceMgr.isInSystemMacro(CC)) return; - if (TargetRange.Width == 32 && S.Context.getIntWidth(E->getType()) == 64) - return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_integer_64_32, + if (TargetRange.Width == 32 && Context.getIntWidth(E->getType()) == 64) + return DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_integer_64_32, /* pruneControlFlow */ true); - return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_integer_precision); + return DiagnoseImpCast(*this, E, T, CC, + diag::warn_impcast_integer_precision); } if (TargetRange.Width > SourceTypeRange.Width) { @@ -12118,10 +11232,10 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, if (UO->getOpcode() == UO_Minus) if (Source->isUnsignedIntegerType()) { if (Target->isUnsignedIntegerType()) - return DiagnoseImpCast(S, E, T, CC, + return DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_high_order_zero_bits); if (Target->isSignedIntegerType()) - return DiagnoseImpCast(S, E, T, CC, + return DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_nonnegative_result); } } @@ -12134,17 +11248,17 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, // cause a negative value to be stored. Expr::EvalResult Result; - if (E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects) && - !S.SourceMgr.isInSystemMacro(CC)) { + if (E->EvaluateAsInt(Result, Context, Expr::SE_AllowSideEffects) && + !SourceMgr.isInSystemMacro(CC)) { llvm::APSInt Value = Result.Val.getInt(); - if (isSameWidthConstantConversion(S, E, T, CC)) { + if (isSameWidthConstantConversion(*this, E, T, CC)) { std::string PrettySourceValue = toString(Value, 10); std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange); - S.Diag(E->getExprLoc(), - S.PDiag(diag::warn_impcast_integer_precision_constant) - << PrettySourceValue << PrettyTargetValue << E->getType() - << T << E->getSourceRange() << SourceRange(CC)); + Diag(E->getExprLoc(), + PDiag(diag::warn_impcast_integer_precision_constant) + << PrettySourceValue << PrettyTargetValue << E->getType() << T + << E->getSourceRange() << SourceRange(CC)); return; } } @@ -12156,7 +11270,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, ((TargetRange.NonNegative && !LikelySourceRange.NonNegative) || (!TargetRange.NonNegative && LikelySourceRange.NonNegative && LikelySourceRange.Width == TargetRange.Width))) { - if (S.SourceMgr.isInSystemMacro(CC)) + if (SourceMgr.isInSystemMacro(CC)) return; if (SourceBT && SourceBT->isInteger() && TargetBT && @@ -12177,24 +11291,24 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, *ICContext = true; } - return DiagnoseImpCast(S, E, T, CC, DiagID); + return DiagnoseImpCast(*this, E, T, CC, DiagID); } // Diagnose conversions between different enumeration types. // In C, we pretend that the type of an EnumConstantDecl is its enumeration // type, to give us better diagnostics. - QualType SourceType = E->getEnumCoercedType(S.Context); - Source = S.Context.getCanonicalType(SourceType).getTypePtr(); + QualType SourceType = E->getEnumCoercedType(Context); + Source = Context.getCanonicalType(SourceType).getTypePtr(); if (const EnumType *SourceEnum = Source->getAs()) if (const EnumType *TargetEnum = Target->getAs()) if (SourceEnum->getDecl()->hasNameForLinkage() && TargetEnum->getDecl()->hasNameForLinkage() && SourceEnum != TargetEnum) { - if (S.SourceMgr.isInSystemMacro(CC)) + if (SourceMgr.isInSystemMacro(CC)) return; - return DiagnoseImpCast(S, E, SourceType, T, CC, + return DiagnoseImpCast(*this, E, SourceType, T, CC, diag::warn_impcast_different_enum_types); } } @@ -12214,7 +11328,7 @@ static void CheckConditionalOperand(Sema &S, Expr *E, QualType T, AnalyzeImplicitConversions(S, E, CC); if (E->getType() != T) - return CheckImplicitConversion(S, E, T, CC, &ICContext); + return S.CheckImplicitConversion(E, T, CC, &ICContext); } static void CheckConditionalOperator(Sema &S, AbstractConditionalOperator *E, @@ -12245,11 +11359,11 @@ static void CheckConditionalOperator(Sema &S, AbstractConditionalOperator *E, if (E->getType() == T) return; Suspicious = false; - CheckImplicitConversion(S, TrueExpr->IgnoreParenImpCasts(), - E->getType(), CC, &Suspicious); + S.CheckImplicitConversion(TrueExpr->IgnoreParenImpCasts(), E->getType(), CC, + &Suspicious); if (!Suspicious) - CheckImplicitConversion(S, E->getFalseExpr()->IgnoreParenImpCasts(), - E->getType(), CC, &Suspicious); + S.CheckImplicitConversion(E->getFalseExpr()->IgnoreParenImpCasts(), + E->getType(), CC, &Suspicious); } /// Check conversion of given expression to boolean. @@ -12262,7 +11376,7 @@ static void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) { return; if (E->IgnoreParenImpCasts()->getType()->isAtomicType()) return; - CheckImplicitConversion(S, E->IgnoreParenImpCasts(), S.Context.BoolTy, CC); + S.CheckImplicitConversion(E->IgnoreParenImpCasts(), S.Context.BoolTy, CC); } namespace { @@ -12352,7 +11466,7 @@ static void AnalyzeImplicitConversions( // The non-canonical typecheck is just an optimization; // CheckImplicitConversion will filter out dead implicit conversions. if (SourceExpr->getType() != T) - CheckImplicitConversion(S, SourceExpr, T, CC, nullptr, IsListInit); + S.CheckImplicitConversion(SourceExpr, T, CC, nullptr, IsListInit); // Now continue drilling into this expression. @@ -12452,21 +11566,6 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC, AnalyzeImplicitConversions(S, WorkList.pop_back_val(), WorkList); } -/// Diagnose integer type and any valid implicit conversion to it. -static bool checkOpenCLEnqueueIntType(Sema &S, Expr *E, const QualType &IntT) { - // Taking into account implicit conversions, - // allow any integer. - if (!E->getType()->isIntegerType()) { - S.Diag(E->getBeginLoc(), - diag::err_opencl_enqueue_kernel_invalid_local_size_type); - return true; - } - // Potentially emit standard warnings for implicit conversions if enabled - // using -Wconversion. - CheckImplicitConversion(S, E, IntT, E->getBeginLoc()); - return false; -} - // Helper function for Sema::DiagnoseAlwaysNonNullPointer. // Returns true when emitting a warning about taking the address of a reference. static bool CheckForReference(Sema &SemaRef, const Expr *E, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index e28e5c56c11a7b..029ccf944c513f 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1663,8 +1663,7 @@ bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) { // Partitions are part of the module, but a partition could import another // module, so verify that the PMIs agree. if ((NewM->isModulePartition() || OldM->isModulePartition()) && - NewM->getPrimaryModuleInterfaceName() == - OldM->getPrimaryModuleInterfaceName()) + getASTContext().isInSameModule(NewM, OldM)) return false; } @@ -3912,6 +3911,49 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S, return true; } + const auto OldFX = Old->getFunctionEffects(); + const auto NewFX = New->getFunctionEffects(); + QualType OldQTypeForComparison = OldQType; + if (OldFX != NewFX) { + const auto Diffs = FunctionEffectDifferences(OldFX, NewFX); + for (const auto &Diff : Diffs) { + if (Diff.shouldDiagnoseRedeclaration(*Old, OldFX, *New, NewFX)) { + Diag(New->getLocation(), + diag::warn_mismatched_func_effect_redeclaration) + << Diff.effectName(); + Diag(Old->getLocation(), diag::note_previous_declaration); + } + } + // Following a warning, we could skip merging effects from the previous + // declaration, but that would trigger an additional "conflicting types" + // error. + if (const auto *NewFPT = NewQType->getAs()) { + FunctionEffectSet::Conflicts MergeErrs; + FunctionEffectSet MergedFX = + FunctionEffectSet::getUnion(OldFX, NewFX, MergeErrs); + if (!MergeErrs.empty()) + diagnoseFunctionEffectMergeConflicts(MergeErrs, New->getLocation(), + Old->getLocation()); + + FunctionProtoType::ExtProtoInfo EPI = NewFPT->getExtProtoInfo(); + EPI.FunctionEffects = FunctionEffectsRef(MergedFX); + QualType ModQT = Context.getFunctionType(NewFPT->getReturnType(), + NewFPT->getParamTypes(), EPI); + + New->setType(ModQT); + NewQType = New->getType(); + + // Revise OldQTForComparison to include the merged effects, + // so as not to fail due to differences later. + if (const auto *OldFPT = OldQType->getAs()) { + EPI = OldFPT->getExtProtoInfo(); + EPI.FunctionEffects = FunctionEffectsRef(MergedFX); + OldQTypeForComparison = Context.getFunctionType( + OldFPT->getReturnType(), OldFPT->getParamTypes(), EPI); + } + } + } + if (getLangOpts().CPlusPlus) { OldQType = Context.getCanonicalType(Old->getType()); NewQType = Context.getCanonicalType(New->getType()); @@ -4076,9 +4118,8 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S, // We also want to respect all the extended bits except noreturn. // noreturn should now match unless the old type info didn't have it. - QualType OldQTypeForComparison = OldQType; if (!OldTypeInfo.getNoReturn() && NewTypeInfo.getNoReturn()) { - auto *OldType = OldQType->castAs(); + auto *OldType = OldQTypeForComparison->castAs(); const FunctionType *OldTypeForComparison = Context.adjustFunctionType(OldType, OldTypeInfo.withNoReturn(true)); OldQTypeForComparison = QualType(OldTypeForComparison, 0); @@ -20547,3 +20588,62 @@ bool Sema::shouldIgnoreInHostDeviceCheck(FunctionDecl *Callee) { return LangOpts.CUDA && !LangOpts.CUDAIsDevice && CUDA().IdentifyTarget(Callee) == CUDAFunctionTarget::Global; } + +// Report a failure to merge function effects between declarations due to a +// conflict. +void Sema::diagnoseFunctionEffectMergeConflicts( + const FunctionEffectSet::Conflicts &Errs, SourceLocation NewLoc, + SourceLocation OldLoc) { + for (const FunctionEffectSet::Conflict &Conflict : Errs) { + Diag(NewLoc, diag::warn_conflicting_func_effects) + << Conflict.Kept.description() << Conflict.Rejected.description(); + Diag(OldLoc, diag::note_previous_declaration); + } +} + +// Warn and return true if adding an effect to a set would create a conflict. +bool Sema::diagnoseConflictingFunctionEffect( + const FunctionEffectsRef &FX, const FunctionEffectWithCondition &NewEC, + SourceLocation NewAttrLoc) { + // If the new effect has a condition, we can't detect conflicts until the + // condition is resolved. + if (NewEC.Cond.getCondition() != nullptr) + return false; + + // Diagnose the new attribute as incompatible with a previous one. + auto Incompatible = [&](const FunctionEffectWithCondition &PrevEC) { + Diag(NewAttrLoc, diag::err_attributes_are_not_compatible) + << ("'" + NewEC.description() + "'") + << ("'" + PrevEC.description() + "'") << false; + // We don't necessarily have the location of the previous attribute, + // so no note. + return true; + }; + + // Compare against previous attributes. + FunctionEffect::Kind NewKind = NewEC.Effect.kind(); + + for (const FunctionEffectWithCondition &PrevEC : FX) { + // Again, can't check yet when the effect is conditional. + if (PrevEC.Cond.getCondition() != nullptr) + continue; + + FunctionEffect::Kind PrevKind = PrevEC.Effect.kind(); + // Note that we allow PrevKind == NewKind; it's redundant and ignored. + + if (PrevEC.Effect.oppositeKind() == NewKind) + return Incompatible(PrevEC); + + // A new allocating is incompatible with a previous nonblocking. + if (PrevKind == FunctionEffect::Kind::NonBlocking && + NewKind == FunctionEffect::Kind::Allocating) + return Incompatible(PrevEC); + + // A new nonblocking is incompatible with a previous allocating. + if (PrevKind == FunctionEffect::Kind::Allocating && + NewKind == FunctionEffect::Kind::NonBlocking) + return Incompatible(PrevEC); + } + + return false; +} diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index ce6b5b1ff6f931..41489789919d03 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -14,6 +14,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/CXXInheritance.h" +#include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" @@ -25,6 +26,7 @@ #include "clang/Basic/CharInfo.h" #include "clang/Basic/Cuda.h" #include "clang/Basic/DarwinSDKInfo.h" +#include "clang/Basic/DiagnosticSema.h" #include "clang/Basic/HLSLRuntime.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LangOptions.h" @@ -65,10 +67,13 @@ #include "llvm/Demangle/Demangle.h" #include "llvm/IR/Assumptions.h" #include "llvm/MC/MCSectionMachO.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TargetParser/Triple.h" +#include #include using namespace clang; @@ -166,13 +171,6 @@ bool Sema::checkStringLiteralArgumentAttr(const ParsedAttr &AL, unsigned ArgNum, return checkStringLiteralArgumentAttr(AL, ArgExpr, Str, ArgLocation); } -/// Check if the passed-in expression is of type int or bool. -static bool isIntOrBool(Expr *Exp) { - QualType QT = Exp->getType(); - return QT->isBooleanType() || QT->isIntegerType(); -} - - // Check to see if the type is a smart pointer of some kind. We assume // it's a smart pointer if it defines both operator-> and operator*. static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) { @@ -608,15 +606,31 @@ static bool checkTryLockFunAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL, if (!AL.checkAtLeastNumArgs(S, 1)) return false; - if (!isIntOrBool(AL.getArgAsExpr(0))) { + // The attribute's first argument defines the success value. + const Expr *SuccessArg = AL.getArgAsExpr(0); + if (!isa(SuccessArg) && + !isa(SuccessArg) && !isa(SuccessArg) && + !isa(SuccessArg) && !SuccessArg->getEnumConstantDecl()) { S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) - << AL << 1 << AANT_ArgumentIntOrBool; + << AL << 1 << AANT_ArgumentNullptrOrBoolIntOrEnumLiteral; return false; } - // check that all arguments are lockable objects + // All remaining arguments must be lockable objects. checkAttrArgsAreCapabilityObjs(S, D, AL, Args, 1); + // The function must return a pointer, boolean, integer, or enum. We already + // know that `D` is a function because `ExclusiveTrylockFunction` and friends + // are defined in Attr.td with subject lists that only include functions. + QualType ReturnType = D->getAsFunction()->getReturnType(); + if (!ReturnType->isPointerType() && !ReturnType->isBooleanType() && + !ReturnType->isIntegerType() && !ReturnType->isEnumeralType()) { + S.Diag(AL.getLoc(), diag::err_attribute_wrong_decl_type) + << AL << AL.isRegularKeywordAttribute() + << ExpectedFunctionReturningPointerBoolIntOrEnum; + return false; + } + return true; } @@ -5102,12 +5116,12 @@ bool Sema::CheckRegparmAttr(const ParsedAttr &AL, unsigned &numParams) { return false; } -// Helper to get CudaArch. -static CudaArch getCudaArch(const TargetInfo &TI) { +// Helper to get OffloadArch. +static OffloadArch getOffloadArch(const TargetInfo &TI) { if (!TI.getTriple().isNVPTX()) - llvm_unreachable("getCudaArch is only valid for NVPTX triple"); + llvm_unreachable("getOffloadArch is only valid for NVPTX triple"); auto &TO = TI.getTargetOpts(); - return StringToCudaArch(TO.CPU); + return StringToOffloadArch(TO.CPU); } // Checks whether an argument of launch_bounds attribute is @@ -5167,10 +5181,10 @@ Sema::CreateLaunchBoundsAttr(const AttributeCommonInfo &CI, Expr *MaxThreads, if (MaxBlocks) { // '.maxclusterrank' ptx directive requires .target sm_90 or higher. - auto SM = getCudaArch(Context.getTargetInfo()); - if (SM == CudaArch::UNKNOWN || SM < CudaArch::SM_90) { + auto SM = getOffloadArch(Context.getTargetInfo()); + if (SM == OffloadArch::UNKNOWN || SM < OffloadArch::SM_90) { Diag(MaxBlocks->getBeginLoc(), diag::warn_cuda_maxclusterrank_sm_90) - << CudaArchToString(SM) << CI << MaxBlocks->getSourceRange(); + << OffloadArchToString(SM) << CI << MaxBlocks->getSourceRange(); // Ignore it by setting MaxBlocks to null; MaxBlocks = nullptr; } else { @@ -6267,6 +6281,116 @@ EnforceTCBLeafAttr *Sema::mergeEnforceTCBLeafAttr( *this, D, AL); } +static void handleVTablePointerAuthentication(Sema &S, Decl *D, + const ParsedAttr &AL) { + CXXRecordDecl *Decl = cast(D); + const uint32_t NumArgs = AL.getNumArgs(); + if (NumArgs > 4) { + S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 4; + AL.setInvalid(); + } + + if (NumArgs == 0) { + S.Diag(AL.getLoc(), diag::err_attribute_too_few_arguments) << AL; + AL.setInvalid(); + return; + } + + if (D->getAttr()) { + S.Diag(AL.getLoc(), diag::err_duplicated_vtable_pointer_auth) << Decl; + AL.setInvalid(); + } + + auto KeyType = VTablePointerAuthenticationAttr::VPtrAuthKeyType::DefaultKey; + if (AL.isArgIdent(0)) { + IdentifierLoc *IL = AL.getArgAsIdent(0); + if (!VTablePointerAuthenticationAttr::ConvertStrToVPtrAuthKeyType( + IL->Ident->getName(), KeyType)) { + S.Diag(IL->Loc, diag::err_invalid_authentication_key) << IL->Ident; + AL.setInvalid(); + } + if (KeyType == VTablePointerAuthenticationAttr::DefaultKey && + !S.getLangOpts().PointerAuthCalls) { + S.Diag(AL.getLoc(), diag::err_no_default_vtable_pointer_auth) << 0; + AL.setInvalid(); + } + } else { + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIdentifier; + return; + } + + auto AddressDiversityMode = VTablePointerAuthenticationAttr:: + AddressDiscriminationMode::DefaultAddressDiscrimination; + if (AL.getNumArgs() > 1) { + if (AL.isArgIdent(1)) { + IdentifierLoc *IL = AL.getArgAsIdent(1); + if (!VTablePointerAuthenticationAttr:: + ConvertStrToAddressDiscriminationMode(IL->Ident->getName(), + AddressDiversityMode)) { + S.Diag(IL->Loc, diag::err_invalid_address_discrimination) << IL->Ident; + AL.setInvalid(); + } + if (AddressDiversityMode == + VTablePointerAuthenticationAttr::DefaultAddressDiscrimination && + !S.getLangOpts().PointerAuthCalls) { + S.Diag(IL->Loc, diag::err_no_default_vtable_pointer_auth) << 1; + AL.setInvalid(); + } + } else { + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIdentifier; + } + } + + auto ED = VTablePointerAuthenticationAttr::ExtraDiscrimination:: + DefaultExtraDiscrimination; + if (AL.getNumArgs() > 2) { + if (AL.isArgIdent(2)) { + IdentifierLoc *IL = AL.getArgAsIdent(2); + if (!VTablePointerAuthenticationAttr::ConvertStrToExtraDiscrimination( + IL->Ident->getName(), ED)) { + S.Diag(IL->Loc, diag::err_invalid_extra_discrimination) << IL->Ident; + AL.setInvalid(); + } + if (ED == VTablePointerAuthenticationAttr::DefaultExtraDiscrimination && + !S.getLangOpts().PointerAuthCalls) { + S.Diag(AL.getLoc(), diag::err_no_default_vtable_pointer_auth) << 2; + AL.setInvalid(); + } + } else { + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIdentifier; + } + } + + uint32_t CustomDiscriminationValue = 0; + if (ED == VTablePointerAuthenticationAttr::CustomDiscrimination) { + if (NumArgs < 4) { + S.Diag(AL.getLoc(), diag::err_missing_custom_discrimination) << AL << 4; + AL.setInvalid(); + return; + } + if (NumArgs > 4) { + S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 4; + AL.setInvalid(); + } + + if (!AL.isArgExpr(3) || !S.checkUInt32Argument(AL, AL.getArgAsExpr(3), + CustomDiscriminationValue)) { + S.Diag(AL.getLoc(), diag::err_invalid_custom_discrimination); + AL.setInvalid(); + } + } else if (NumArgs > 3) { + S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 3; + AL.setInvalid(); + } + + Decl->addAttr(::new (S.Context) VTablePointerAuthenticationAttr( + S.Context, AL, KeyType, AddressDiversityMode, ED, + CustomDiscriminationValue)); +} + //===----------------------------------------------------------------------===// // Top Level Sema Entry Points //===----------------------------------------------------------------------===// @@ -7136,6 +7260,10 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_TypeNullable: handleNullableTypeAttr(S, D, AL); break; + + case ParsedAttr::AT_VTablePointerAuthentication: + handleVTablePointerAuthentication(S, D, AL); + break; } } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 234e89b91da07a..ffa6bcac44cbde 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -7116,6 +7116,10 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { return false; }; + if (!Record->isInvalidDecl() && + Record->hasAttr()) + checkIncorrectVTablePointerAuthenticationAttribute(*Record); + auto CompleteMemberFunction = [&](CXXMethodDecl *M) { // Check whether the explicitly-defaulted members are valid. bool Incomplete = CheckForDefaultedFunction(M); @@ -10500,6 +10504,39 @@ void Sema::checkIllFormedTrivialABIStruct(CXXRecordDecl &RD) { } } +void Sema::checkIncorrectVTablePointerAuthenticationAttribute( + CXXRecordDecl &RD) { + if (RequireCompleteType(RD.getLocation(), Context.getRecordType(&RD), + diag::err_incomplete_type_vtable_pointer_auth)) + return; + + const CXXRecordDecl *PrimaryBase = &RD; + if (PrimaryBase->hasAnyDependentBases()) + return; + + while (1) { + assert(PrimaryBase); + const CXXRecordDecl *Base = nullptr; + for (auto BasePtr : PrimaryBase->bases()) { + if (!BasePtr.getType()->getAsCXXRecordDecl()->isDynamicClass()) + continue; + Base = BasePtr.getType()->getAsCXXRecordDecl(); + break; + } + if (!Base || Base == PrimaryBase || !Base->isPolymorphic()) + break; + Diag(RD.getAttr()->getLocation(), + diag::err_non_top_level_vtable_pointer_auth) + << &RD << Base; + PrimaryBase = Base; + } + + if (!RD.isPolymorphic()) + Diag(RD.getAttr()->getLocation(), + diag::err_non_polymorphic_vtable_pointer_auth) + << &RD; +} + void Sema::ActOnFinishCXXMemberSpecification( Scope *S, SourceLocation RLoc, Decl *TagDecl, SourceLocation LBrac, SourceLocation RBrac, const ParsedAttributesView &AttrList) { @@ -18291,7 +18328,7 @@ void Sema::SetFunctionBodyKind(Decl *D, SourceLocation Loc, FnBodyKind BodyKind, } } -bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New, +bool Sema::CheckOverridingFunctionAttributes(CXXMethodDecl *New, const CXXMethodDecl *Old) { const auto *NewFT = New->getType()->castAs(); const auto *OldFT = Old->getType()->castAs(); @@ -18327,6 +18364,41 @@ bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New, return true; } + // Virtual overrides: check for matching effects. + const auto OldFX = Old->getFunctionEffects(); + const auto NewFXOrig = New->getFunctionEffects(); + + if (OldFX != NewFXOrig) { + FunctionEffectSet NewFX(NewFXOrig); + const auto Diffs = FunctionEffectDifferences(OldFX, NewFX); + FunctionEffectSet::Conflicts Errs; + for (const auto &Diff : Diffs) { + switch (Diff.shouldDiagnoseMethodOverride(*Old, OldFX, *New, NewFX)) { + case FunctionEffectDiff::OverrideResult::NoAction: + break; + case FunctionEffectDiff::OverrideResult::Warn: + Diag(New->getLocation(), diag::warn_mismatched_func_effect_override) + << Diff.effectName(); + Diag(Old->getLocation(), diag::note_overridden_virtual_function) + << Old->getReturnTypeSourceRange(); + break; + case FunctionEffectDiff::OverrideResult::Merge: { + NewFX.insert(Diff.Old, Errs); + const auto *NewFT = New->getType()->castAs(); + FunctionProtoType::ExtProtoInfo EPI = NewFT->getExtProtoInfo(); + EPI.FunctionEffects = FunctionEffectsRef(NewFX); + QualType ModQT = Context.getFunctionType(NewFT->getReturnType(), + NewFT->getParamTypes(), EPI); + New->setType(ModQT); + break; + } + } + } + if (!Errs.empty()) + diagnoseFunctionEffectMergeConflicts(Errs, New->getLocation(), + Old->getLocation()); + } + CallingConv NewCC = NewFT->getCallConv(), OldCC = OldFT->getCallConv(); // If the calling conventions match, everything is fine diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 4a2f3a65eac96f..db44cfe1288b69 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -14217,6 +14217,39 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { QualType MPTy = Context.getMemberPointerType( op->getType(), Context.getTypeDeclType(MD->getParent()).getTypePtr()); + + if (getLangOpts().PointerAuthCalls && MD->isVirtual() && + !isUnevaluatedContext() && !MPTy->isDependentType()) { + // When pointer authentication is enabled, argument and return types of + // vitual member functions must be complete. This is because vitrual + // member function pointers are implemented using virtual dispatch + // thunks and the thunks cannot be emitted if the argument or return + // types are incomplete. + auto ReturnOrParamTypeIsIncomplete = [&](QualType T, + SourceLocation DeclRefLoc, + SourceLocation RetArgTypeLoc) { + if (RequireCompleteType(DeclRefLoc, T, diag::err_incomplete_type)) { + Diag(DeclRefLoc, + diag::note_ptrauth_virtual_function_pointer_incomplete_arg_ret); + Diag(RetArgTypeLoc, + diag::note_ptrauth_virtual_function_incomplete_arg_ret_type) + << T; + return true; + } + return false; + }; + QualType RetTy = MD->getReturnType(); + bool IsIncomplete = + !RetTy->isVoidType() && + ReturnOrParamTypeIsIncomplete( + RetTy, OpLoc, MD->getReturnTypeSourceRange().getBegin()); + for (auto *PVD : MD->parameters()) + IsIncomplete |= ReturnOrParamTypeIsIncomplete(PVD->getType(), OpLoc, + PVD->getBeginLoc()); + if (IsIncomplete) + return QualType(); + } + // Under the MS ABI, lock down the inheritance model now. if (Context.getTargetInfo().getCXXABI().isMicrosoft()) (void)isCompleteType(OpLoc, MPTy); diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 9c423529c80e77..7ccecf055feedd 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -2564,7 +2564,7 @@ DiagnoseCStringFormatDirectiveInObjCAPI(Sema &S, } else if (Method) { for (const auto *I : Method->specific_attrs()) { - if (S.GetFormatNSStringIdx(I, Idx)) { + if (S.ObjC().GetFormatNSStringIdx(I, Idx)) { Format = true; break; } diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index cc9c2598581488..eebe17a5b4bf72 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -356,15 +356,7 @@ static bool isLegalTypeForHLSLSV_DispatchThreadID(QualType T) { return true; } -void SemaHLSL::handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL) { - // FIXME: support semantic on field. - // See https://github.com/llvm/llvm-project/issues/57889. - if (isa(D)) { - Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node) - << AL << "parameter"; - return; - } - +void SemaHLSL::handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL) { auto *VD = cast(D); if (!isLegalTypeForHLSLSV_DispatchThreadID(VD->getType())) { Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type) @@ -852,3 +844,231 @@ void SemaHLSL::DiagnoseAvailabilityViolations(TranslationUnitDecl *TU) { DiagnoseHLSLAvailability(SemaRef).RunOnTranslationUnit(TU); } + +// Helper function for CheckHLSLBuiltinFunctionCall +bool CheckVectorElementCallArgs(Sema *S, CallExpr *TheCall) { + assert(TheCall->getNumArgs() > 1); + ExprResult A = TheCall->getArg(0); + + QualType ArgTyA = A.get()->getType(); + + auto *VecTyA = ArgTyA->getAs(); + SourceLocation BuiltinLoc = TheCall->getBeginLoc(); + + for (unsigned i = 1; i < TheCall->getNumArgs(); ++i) { + ExprResult B = TheCall->getArg(i); + QualType ArgTyB = B.get()->getType(); + auto *VecTyB = ArgTyB->getAs(); + if (VecTyA == nullptr && VecTyB == nullptr) + return false; + + if (VecTyA && VecTyB) { + bool retValue = false; + if (VecTyA->getElementType() != VecTyB->getElementType()) { + // Note: type promotion is intended to be handeled via the intrinsics + // and not the builtin itself. + S->Diag(TheCall->getBeginLoc(), + diag::err_vec_builtin_incompatible_vector) + << TheCall->getDirectCallee() << /*useAllTerminology*/ true + << SourceRange(A.get()->getBeginLoc(), B.get()->getEndLoc()); + retValue = true; + } + if (VecTyA->getNumElements() != VecTyB->getNumElements()) { + // You should only be hitting this case if you are calling the builtin + // directly. HLSL intrinsics should avoid this case via a + // HLSLVectorTruncation. + S->Diag(BuiltinLoc, diag::err_vec_builtin_incompatible_vector) + << TheCall->getDirectCallee() << /*useAllTerminology*/ true + << SourceRange(TheCall->getArg(0)->getBeginLoc(), + TheCall->getArg(1)->getEndLoc()); + retValue = true; + } + return retValue; + } + } + + // Note: if we get here one of the args is a scalar which + // requires a VectorSplat on Arg0 or Arg1 + S->Diag(BuiltinLoc, diag::err_vec_builtin_non_vector) + << TheCall->getDirectCallee() << /*useAllTerminology*/ true + << SourceRange(TheCall->getArg(0)->getBeginLoc(), + TheCall->getArg(1)->getEndLoc()); + return true; +} + +bool CheckArgsTypesAreCorrect( + Sema *S, CallExpr *TheCall, QualType ExpectedType, + llvm::function_ref Check) { + for (unsigned i = 0; i < TheCall->getNumArgs(); ++i) { + QualType PassedType = TheCall->getArg(i)->getType(); + if (Check(PassedType)) { + if (auto *VecTyA = PassedType->getAs()) + ExpectedType = S->Context.getVectorType( + ExpectedType, VecTyA->getNumElements(), VecTyA->getVectorKind()); + S->Diag(TheCall->getArg(0)->getBeginLoc(), + diag::err_typecheck_convert_incompatible) + << PassedType << ExpectedType << 1 << 0 << 0; + return true; + } + } + return false; +} + +bool CheckAllArgsHaveFloatRepresentation(Sema *S, CallExpr *TheCall) { + auto checkAllFloatTypes = [](clang::QualType PassedType) -> bool { + return !PassedType->hasFloatingRepresentation(); + }; + return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy, + checkAllFloatTypes); +} + +bool CheckFloatOrHalfRepresentations(Sema *S, CallExpr *TheCall) { + auto checkFloatorHalf = [](clang::QualType PassedType) -> bool { + clang::QualType BaseType = + PassedType->isVectorType() + ? PassedType->getAs()->getElementType() + : PassedType; + return !BaseType->isHalfType() && !BaseType->isFloat32Type(); + }; + return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy, + checkFloatorHalf); +} + +bool CheckNoDoubleVectors(Sema *S, CallExpr *TheCall) { + auto checkDoubleVector = [](clang::QualType PassedType) -> bool { + if (const auto *VecTy = PassedType->getAs()) + return VecTy->getElementType()->isDoubleType(); + return false; + }; + return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy, + checkDoubleVector); +} + +bool CheckUnsignedIntRepresentation(Sema *S, CallExpr *TheCall) { + auto checkAllUnsignedTypes = [](clang::QualType PassedType) -> bool { + return !PassedType->hasUnsignedIntegerRepresentation(); + }; + return CheckArgsTypesAreCorrect(S, TheCall, S->Context.UnsignedIntTy, + checkAllUnsignedTypes); +} + +void SetElementTypeAsReturnType(Sema *S, CallExpr *TheCall, + QualType ReturnType) { + auto *VecTyA = TheCall->getArg(0)->getType()->getAs(); + if (VecTyA) + ReturnType = S->Context.getVectorType(ReturnType, VecTyA->getNumElements(), + VectorKind::Generic); + TheCall->setType(ReturnType); +} + +// Note: returning true in this case results in CheckBuiltinFunctionCall +// returning an ExprError +bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { + switch (BuiltinID) { + case Builtin::BI__builtin_hlsl_elementwise_all: + case Builtin::BI__builtin_hlsl_elementwise_any: { + if (SemaRef.checkArgCount(TheCall, 1)) + return true; + break; + } + case Builtin::BI__builtin_hlsl_elementwise_clamp: { + if (SemaRef.checkArgCount(TheCall, 3)) + return true; + if (CheckVectorElementCallArgs(&SemaRef, TheCall)) + return true; + if (SemaRef.BuiltinElementwiseTernaryMath( + TheCall, /*CheckForFloatArgs*/ + TheCall->getArg(0)->getType()->hasFloatingRepresentation())) + return true; + break; + } + case Builtin::BI__builtin_hlsl_dot: { + if (SemaRef.checkArgCount(TheCall, 2)) + return true; + if (CheckVectorElementCallArgs(&SemaRef, TheCall)) + return true; + if (SemaRef.BuiltinVectorToScalarMath(TheCall)) + return true; + if (CheckNoDoubleVectors(&SemaRef, TheCall)) + return true; + break; + } + case Builtin::BI__builtin_hlsl_elementwise_rcp: { + if (CheckAllArgsHaveFloatRepresentation(&SemaRef, TheCall)) + return true; + if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall)) + return true; + break; + } + case Builtin::BI__builtin_hlsl_elementwise_rsqrt: + case Builtin::BI__builtin_hlsl_elementwise_frac: { + if (CheckFloatOrHalfRepresentations(&SemaRef, TheCall)) + return true; + if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall)) + return true; + break; + } + case Builtin::BI__builtin_hlsl_elementwise_isinf: { + if (CheckFloatOrHalfRepresentations(&SemaRef, TheCall)) + return true; + if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall)) + return true; + SetElementTypeAsReturnType(&SemaRef, TheCall, getASTContext().BoolTy); + break; + } + case Builtin::BI__builtin_hlsl_lerp: { + if (SemaRef.checkArgCount(TheCall, 3)) + return true; + if (CheckVectorElementCallArgs(&SemaRef, TheCall)) + return true; + if (SemaRef.BuiltinElementwiseTernaryMath(TheCall)) + return true; + if (CheckFloatOrHalfRepresentations(&SemaRef, TheCall)) + return true; + break; + } + case Builtin::BI__builtin_hlsl_mad: { + if (SemaRef.checkArgCount(TheCall, 3)) + return true; + if (CheckVectorElementCallArgs(&SemaRef, TheCall)) + return true; + if (SemaRef.BuiltinElementwiseTernaryMath( + TheCall, /*CheckForFloatArgs*/ + TheCall->getArg(0)->getType()->hasFloatingRepresentation())) + return true; + break; + } + // Note these are llvm builtins that we want to catch invalid intrinsic + // generation. Normal handling of these builitns will occur elsewhere. + case Builtin::BI__builtin_elementwise_bitreverse: { + if (CheckUnsignedIntRepresentation(&SemaRef, TheCall)) + return true; + break; + } + case Builtin::BI__builtin_elementwise_acos: + case Builtin::BI__builtin_elementwise_asin: + case Builtin::BI__builtin_elementwise_atan: + case Builtin::BI__builtin_elementwise_ceil: + case Builtin::BI__builtin_elementwise_cos: + case Builtin::BI__builtin_elementwise_cosh: + case Builtin::BI__builtin_elementwise_exp: + case Builtin::BI__builtin_elementwise_exp2: + case Builtin::BI__builtin_elementwise_floor: + case Builtin::BI__builtin_elementwise_log: + case Builtin::BI__builtin_elementwise_log2: + case Builtin::BI__builtin_elementwise_log10: + case Builtin::BI__builtin_elementwise_pow: + case Builtin::BI__builtin_elementwise_roundeven: + case Builtin::BI__builtin_elementwise_sin: + case Builtin::BI__builtin_elementwise_sinh: + case Builtin::BI__builtin_elementwise_sqrt: + case Builtin::BI__builtin_elementwise_tan: + case Builtin::BI__builtin_elementwise_tanh: + case Builtin::BI__builtin_elementwise_trunc: { + if (CheckFloatOrHalfRepresentations(&SemaRef, TheCall)) + return true; + break; + } + } + return false; +} diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index f820db5233f539..26c65b34f4cc45 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "CheckExprLifetime.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" @@ -7284,1238 +7285,9 @@ PerformConstructorInitialization(Sema &S, return CurInit; } -namespace { -enum LifetimeKind { - /// The lifetime of a temporary bound to this entity ends at the end of the - /// full-expression, and that's (probably) fine. - LK_FullExpression, - - /// The lifetime of a temporary bound to this entity is extended to the - /// lifeitme of the entity itself. - LK_Extended, - - /// The lifetime of a temporary bound to this entity probably ends too soon, - /// because the entity is allocated in a new-expression. - LK_New, - - /// The lifetime of a temporary bound to this entity ends too soon, because - /// the entity is a return object. - LK_Return, - - /// The lifetime of a temporary bound to this entity ends too soon, because - /// the entity is the result of a statement expression. - LK_StmtExprResult, - - /// This is a mem-initializer: if it would extend a temporary (other than via - /// a default member initializer), the program is ill-formed. - LK_MemInitializer, -}; -using LifetimeResult = - llvm::PointerIntPair; -} - -/// Determine the declaration which an initialized entity ultimately refers to, -/// for the purpose of lifetime-extending a temporary bound to a reference in -/// the initialization of \p Entity. -static LifetimeResult getEntityLifetime( - const InitializedEntity *Entity, - const InitializedEntity *InitField = nullptr) { - // C++11 [class.temporary]p5: - switch (Entity->getKind()) { - case InitializedEntity::EK_Variable: - // The temporary [...] persists for the lifetime of the reference - return {Entity, LK_Extended}; - - case InitializedEntity::EK_Member: - // For subobjects, we look at the complete object. - if (Entity->getParent()) - return getEntityLifetime(Entity->getParent(), Entity); - - // except: - // C++17 [class.base.init]p8: - // A temporary expression bound to a reference member in a - // mem-initializer is ill-formed. - // C++17 [class.base.init]p11: - // A temporary expression bound to a reference member from a - // default member initializer is ill-formed. - // - // The context of p11 and its example suggest that it's only the use of a - // default member initializer from a constructor that makes the program - // ill-formed, not its mere existence, and that it can even be used by - // aggregate initialization. - return {Entity, Entity->isDefaultMemberInitializer() ? LK_Extended - : LK_MemInitializer}; - - case InitializedEntity::EK_Binding: - // Per [dcl.decomp]p3, the binding is treated as a variable of reference - // type. - return {Entity, LK_Extended}; - - case InitializedEntity::EK_Parameter: - case InitializedEntity::EK_Parameter_CF_Audited: - // -- A temporary bound to a reference parameter in a function call - // persists until the completion of the full-expression containing - // the call. - return {nullptr, LK_FullExpression}; - - case InitializedEntity::EK_TemplateParameter: - // FIXME: This will always be ill-formed; should we eagerly diagnose it here? - return {nullptr, LK_FullExpression}; - - case InitializedEntity::EK_Result: - // -- The lifetime of a temporary bound to the returned value in a - // function return statement is not extended; the temporary is - // destroyed at the end of the full-expression in the return statement. - return {nullptr, LK_Return}; - - case InitializedEntity::EK_StmtExprResult: - // FIXME: Should we lifetime-extend through the result of a statement - // expression? - return {nullptr, LK_StmtExprResult}; - - case InitializedEntity::EK_New: - // -- A temporary bound to a reference in a new-initializer persists - // until the completion of the full-expression containing the - // new-initializer. - return {nullptr, LK_New}; - - case InitializedEntity::EK_Temporary: - case InitializedEntity::EK_CompoundLiteralInit: - case InitializedEntity::EK_RelatedResult: - // We don't yet know the storage duration of the surrounding temporary. - // Assume it's got full-expression duration for now, it will patch up our - // storage duration if that's not correct. - return {nullptr, LK_FullExpression}; - - case InitializedEntity::EK_ArrayElement: - // For subobjects, we look at the complete object. - return getEntityLifetime(Entity->getParent(), InitField); - - case InitializedEntity::EK_Base: - // For subobjects, we look at the complete object. - if (Entity->getParent()) - return getEntityLifetime(Entity->getParent(), InitField); - return {InitField, LK_MemInitializer}; - - case InitializedEntity::EK_Delegating: - // We can reach this case for aggregate initialization in a constructor: - // struct A { int &&r; }; - // struct B : A { B() : A{0} {} }; - // In this case, use the outermost field decl as the context. - return {InitField, LK_MemInitializer}; - - case InitializedEntity::EK_BlockElement: - case InitializedEntity::EK_LambdaToBlockConversionBlockElement: - case InitializedEntity::EK_LambdaCapture: - case InitializedEntity::EK_VectorElement: - case InitializedEntity::EK_ComplexElement: - return {nullptr, LK_FullExpression}; - - case InitializedEntity::EK_Exception: - // FIXME: Can we diagnose lifetime problems with exceptions? - return {nullptr, LK_FullExpression}; - - case InitializedEntity::EK_ParenAggInitMember: - // -- A temporary object bound to a reference element of an aggregate of - // class type initialized from a parenthesized expression-list - // [dcl.init, 9.3] persists until the completion of the full-expression - // containing the expression-list. - return {nullptr, LK_FullExpression}; - } - - llvm_unreachable("unknown entity kind"); -} - -namespace { -enum ReferenceKind { - /// Lifetime would be extended by a reference binding to a temporary. - RK_ReferenceBinding, - /// Lifetime would be extended by a std::initializer_list object binding to - /// its backing array. - RK_StdInitializerList, -}; - -/// A temporary or local variable. This will be one of: -/// * A MaterializeTemporaryExpr. -/// * A DeclRefExpr whose declaration is a local. -/// * An AddrLabelExpr. -/// * A BlockExpr for a block with captures. -using Local = Expr*; - -/// Expressions we stepped over when looking for the local state. Any steps -/// that would inhibit lifetime extension or take us out of subexpressions of -/// the initializer are included. -struct IndirectLocalPathEntry { - enum EntryKind { - DefaultInit, - AddressOf, - VarInit, - LValToRVal, - LifetimeBoundCall, - TemporaryCopy, - LambdaCaptureInit, - GslReferenceInit, - GslPointerInit - } Kind; - Expr *E; - union { - const Decl *D = nullptr; - const LambdaCapture *Capture; - }; - IndirectLocalPathEntry() {} - IndirectLocalPathEntry(EntryKind K, Expr *E) : Kind(K), E(E) {} - IndirectLocalPathEntry(EntryKind K, Expr *E, const Decl *D) - : Kind(K), E(E), D(D) {} - IndirectLocalPathEntry(EntryKind K, Expr *E, const LambdaCapture *Capture) - : Kind(K), E(E), Capture(Capture) {} -}; - -using IndirectLocalPath = llvm::SmallVectorImpl; - -struct RevertToOldSizeRAII { - IndirectLocalPath &Path; - unsigned OldSize = Path.size(); - RevertToOldSizeRAII(IndirectLocalPath &Path) : Path(Path) {} - ~RevertToOldSizeRAII() { Path.resize(OldSize); } -}; - -using LocalVisitor = llvm::function_ref; -} - -static bool isVarOnPath(IndirectLocalPath &Path, VarDecl *VD) { - for (auto E : Path) - if (E.Kind == IndirectLocalPathEntry::VarInit && E.D == VD) - return true; - return false; -} - -static bool pathContainsInit(IndirectLocalPath &Path) { - return llvm::any_of(Path, [=](IndirectLocalPathEntry E) { - return E.Kind == IndirectLocalPathEntry::DefaultInit || - E.Kind == IndirectLocalPathEntry::VarInit; - }); -} - -static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path, - Expr *Init, LocalVisitor Visit, - bool RevisitSubinits, - bool EnableLifetimeWarnings); - -static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path, - Expr *Init, ReferenceKind RK, - LocalVisitor Visit, - bool EnableLifetimeWarnings); - -template static bool isRecordWithAttr(QualType Type) { - if (auto *RD = Type->getAsCXXRecordDecl()) - return RD->hasAttr(); - return false; -} - -// Decl::isInStdNamespace will return false for iterators in some STL -// implementations due to them being defined in a namespace outside of the std -// namespace. -static bool isInStlNamespace(const Decl *D) { - const DeclContext *DC = D->getDeclContext(); - if (!DC) - return false; - if (const auto *ND = dyn_cast(DC)) - if (const IdentifierInfo *II = ND->getIdentifier()) { - StringRef Name = II->getName(); - if (Name.size() >= 2 && Name.front() == '_' && - (Name[1] == '_' || isUppercase(Name[1]))) - return true; - } - - return DC->isStdNamespace(); -} - -static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) { - if (auto *Conv = dyn_cast_or_null(Callee)) - if (isRecordWithAttr(Conv->getConversionType())) - return true; - if (!isInStlNamespace(Callee->getParent())) - return false; - if (!isRecordWithAttr( - Callee->getFunctionObjectParameterType()) && - !isRecordWithAttr(Callee->getFunctionObjectParameterType())) - return false; - if (Callee->getReturnType()->isPointerType() || - isRecordWithAttr(Callee->getReturnType())) { - if (!Callee->getIdentifier()) - return false; - return llvm::StringSwitch(Callee->getName()) - .Cases("begin", "rbegin", "cbegin", "crbegin", true) - .Cases("end", "rend", "cend", "crend", true) - .Cases("c_str", "data", "get", true) - // Map and set types. - .Cases("find", "equal_range", "lower_bound", "upper_bound", true) - .Default(false); - } else if (Callee->getReturnType()->isReferenceType()) { - if (!Callee->getIdentifier()) { - auto OO = Callee->getOverloadedOperator(); - return OO == OverloadedOperatorKind::OO_Subscript || - OO == OverloadedOperatorKind::OO_Star; - } - return llvm::StringSwitch(Callee->getName()) - .Cases("front", "back", "at", "top", "value", true) - .Default(false); - } - return false; -} - -static bool shouldTrackFirstArgument(const FunctionDecl *FD) { - if (!FD->getIdentifier() || FD->getNumParams() != 1) - return false; - const auto *RD = FD->getParamDecl(0)->getType()->getPointeeCXXRecordDecl(); - if (!FD->isInStdNamespace() || !RD || !RD->isInStdNamespace()) - return false; - if (!isRecordWithAttr(QualType(RD->getTypeForDecl(), 0)) && - !isRecordWithAttr(QualType(RD->getTypeForDecl(), 0))) - return false; - if (FD->getReturnType()->isPointerType() || - isRecordWithAttr(FD->getReturnType())) { - return llvm::StringSwitch(FD->getName()) - .Cases("begin", "rbegin", "cbegin", "crbegin", true) - .Cases("end", "rend", "cend", "crend", true) - .Case("data", true) - .Default(false); - } else if (FD->getReturnType()->isReferenceType()) { - return llvm::StringSwitch(FD->getName()) - .Cases("get", "any_cast", true) - .Default(false); - } - return false; -} - -static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call, - LocalVisitor Visit) { - auto VisitPointerArg = [&](const Decl *D, Expr *Arg, bool Value) { - // We are not interested in the temporary base objects of gsl Pointers: - // Temp().ptr; // Here ptr might not dangle. - if (isa(Arg->IgnoreImpCasts())) - return; - // Once we initialized a value with a reference, it can no longer dangle. - if (!Value) { - for (const IndirectLocalPathEntry &PE : llvm::reverse(Path)) { - if (PE.Kind == IndirectLocalPathEntry::GslReferenceInit) - continue; - if (PE.Kind == IndirectLocalPathEntry::GslPointerInit) - return; - break; - } - } - Path.push_back({Value ? IndirectLocalPathEntry::GslPointerInit - : IndirectLocalPathEntry::GslReferenceInit, - Arg, D}); - if (Arg->isGLValue()) - visitLocalsRetainedByReferenceBinding(Path, Arg, RK_ReferenceBinding, - Visit, - /*EnableLifetimeWarnings=*/true); - else - visitLocalsRetainedByInitializer(Path, Arg, Visit, true, - /*EnableLifetimeWarnings=*/true); - Path.pop_back(); - }; - - if (auto *MCE = dyn_cast(Call)) { - const auto *MD = cast_or_null(MCE->getDirectCallee()); - if (MD && shouldTrackImplicitObjectArg(MD)) - VisitPointerArg(MD, MCE->getImplicitObjectArgument(), - !MD->getReturnType()->isReferenceType()); - return; - } else if (auto *OCE = dyn_cast(Call)) { - FunctionDecl *Callee = OCE->getDirectCallee(); - if (Callee && Callee->isCXXInstanceMember() && - shouldTrackImplicitObjectArg(cast(Callee))) - VisitPointerArg(Callee, OCE->getArg(0), - !Callee->getReturnType()->isReferenceType()); - return; - } else if (auto *CE = dyn_cast(Call)) { - FunctionDecl *Callee = CE->getDirectCallee(); - if (Callee && shouldTrackFirstArgument(Callee)) - VisitPointerArg(Callee, CE->getArg(0), - !Callee->getReturnType()->isReferenceType()); - return; - } - - if (auto *CCE = dyn_cast(Call)) { - const auto *Ctor = CCE->getConstructor(); - const CXXRecordDecl *RD = Ctor->getParent(); - if (CCE->getNumArgs() > 0 && RD->hasAttr()) - VisitPointerArg(Ctor->getParamDecl(0), CCE->getArgs()[0], true); - } -} - -static bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD) { - const TypeSourceInfo *TSI = FD->getTypeSourceInfo(); - if (!TSI) - return false; - // Don't declare this variable in the second operand of the for-statement; - // GCC miscompiles that by ending its lifetime before evaluating the - // third operand. See gcc.gnu.org/PR86769. - AttributedTypeLoc ATL; - for (TypeLoc TL = TSI->getTypeLoc(); - (ATL = TL.getAsAdjusted()); - TL = ATL.getModifiedLoc()) { - if (ATL.getAttrAs()) - return true; - } - - // Assume that all assignment operators with a "normal" return type return - // *this, that is, an lvalue reference that is the same type as the implicit - // object parameter (or the LHS for a non-member operator$=). - OverloadedOperatorKind OO = FD->getDeclName().getCXXOverloadedOperator(); - if (OO == OO_Equal || isCompoundAssignmentOperator(OO)) { - QualType RetT = FD->getReturnType(); - if (RetT->isLValueReferenceType()) { - ASTContext &Ctx = FD->getASTContext(); - QualType LHST; - auto *MD = dyn_cast(FD); - if (MD && MD->isCXXInstanceMember()) - LHST = Ctx.getLValueReferenceType(MD->getFunctionObjectParameterType()); - else - LHST = MD->getParamDecl(0)->getType(); - if (Ctx.hasSameType(RetT, LHST)) - return true; - } - } - - return false; -} - -static void visitLifetimeBoundArguments(IndirectLocalPath &Path, Expr *Call, - LocalVisitor Visit) { - const FunctionDecl *Callee; - ArrayRef Args; - - if (auto *CE = dyn_cast(Call)) { - Callee = CE->getDirectCallee(); - Args = llvm::ArrayRef(CE->getArgs(), CE->getNumArgs()); - } else { - auto *CCE = cast(Call); - Callee = CCE->getConstructor(); - Args = llvm::ArrayRef(CCE->getArgs(), CCE->getNumArgs()); - } - if (!Callee) - return; - - Expr *ObjectArg = nullptr; - if (isa(Call) && Callee->isCXXInstanceMember()) { - ObjectArg = Args[0]; - Args = Args.slice(1); - } else if (auto *MCE = dyn_cast(Call)) { - ObjectArg = MCE->getImplicitObjectArgument(); - } - - auto VisitLifetimeBoundArg = [&](const Decl *D, Expr *Arg) { - Path.push_back({IndirectLocalPathEntry::LifetimeBoundCall, Arg, D}); - if (Arg->isGLValue()) - visitLocalsRetainedByReferenceBinding(Path, Arg, RK_ReferenceBinding, - Visit, - /*EnableLifetimeWarnings=*/false); - else - visitLocalsRetainedByInitializer(Path, Arg, Visit, true, - /*EnableLifetimeWarnings=*/false); - Path.pop_back(); - }; - - bool CheckCoroCall = false; - if (const auto *RD = Callee->getReturnType()->getAsRecordDecl()) { - CheckCoroCall = RD->hasAttr() && - RD->hasAttr() && - !Callee->hasAttr(); - } - - if (ObjectArg) { - bool CheckCoroObjArg = CheckCoroCall; - // Coroutine lambda objects with empty capture list are not lifetimebound. - if (auto *LE = dyn_cast(ObjectArg->IgnoreImplicit()); - LE && LE->captures().empty()) - CheckCoroObjArg = false; - // Allow `get_return_object()` as the object param (__promise) is not - // lifetimebound. - if (Sema::CanBeGetReturnObject(Callee)) - CheckCoroObjArg = false; - if (implicitObjectParamIsLifetimeBound(Callee) || CheckCoroObjArg) - VisitLifetimeBoundArg(Callee, ObjectArg); - } - - for (unsigned I = 0, - N = std::min(Callee->getNumParams(), Args.size()); - I != N; ++I) { - if (CheckCoroCall || Callee->getParamDecl(I)->hasAttr()) - VisitLifetimeBoundArg(Callee->getParamDecl(I), Args[I]); - } -} - -/// Visit the locals that would be reachable through a reference bound to the -/// glvalue expression \c Init. -static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path, - Expr *Init, ReferenceKind RK, - LocalVisitor Visit, - bool EnableLifetimeWarnings) { - RevertToOldSizeRAII RAII(Path); - - // Walk past any constructs which we can lifetime-extend across. - Expr *Old; - do { - Old = Init; - - if (auto *FE = dyn_cast(Init)) - Init = FE->getSubExpr(); - - if (InitListExpr *ILE = dyn_cast(Init)) { - // If this is just redundant braces around an initializer, step over it. - if (ILE->isTransparent()) - Init = ILE->getInit(0); - } - - // Step over any subobject adjustments; we may have a materialized - // temporary inside them. - Init = const_cast(Init->skipRValueSubobjectAdjustments()); - - // Per current approach for DR1376, look through casts to reference type - // when performing lifetime extension. - if (CastExpr *CE = dyn_cast(Init)) - if (CE->getSubExpr()->isGLValue()) - Init = CE->getSubExpr(); - - // Per the current approach for DR1299, look through array element access - // on array glvalues when performing lifetime extension. - if (auto *ASE = dyn_cast(Init)) { - Init = ASE->getBase(); - auto *ICE = dyn_cast(Init); - if (ICE && ICE->getCastKind() == CK_ArrayToPointerDecay) - Init = ICE->getSubExpr(); - else - // We can't lifetime extend through this but we might still find some - // retained temporaries. - return visitLocalsRetainedByInitializer(Path, Init, Visit, true, - EnableLifetimeWarnings); - } - - // Step into CXXDefaultInitExprs so we can diagnose cases where a - // constructor inherits one as an implicit mem-initializer. - if (auto *DIE = dyn_cast(Init)) { - Path.push_back( - {IndirectLocalPathEntry::DefaultInit, DIE, DIE->getField()}); - Init = DIE->getExpr(); - } - } while (Init != Old); - - if (auto *MTE = dyn_cast(Init)) { - if (Visit(Path, Local(MTE), RK)) - visitLocalsRetainedByInitializer(Path, MTE->getSubExpr(), Visit, true, - EnableLifetimeWarnings); - } - - if (isa(Init)) { - if (EnableLifetimeWarnings) - handleGslAnnotatedTypes(Path, Init, Visit); - return visitLifetimeBoundArguments(Path, Init, Visit); - } - - switch (Init->getStmtClass()) { - case Stmt::DeclRefExprClass: { - // If we find the name of a local non-reference parameter, we could have a - // lifetime problem. - auto *DRE = cast(Init); - auto *VD = dyn_cast(DRE->getDecl()); - if (VD && VD->hasLocalStorage() && - !DRE->refersToEnclosingVariableOrCapture()) { - if (!VD->getType()->isReferenceType()) { - Visit(Path, Local(DRE), RK); - } else if (isa(DRE->getDecl())) { - // The lifetime of a reference parameter is unknown; assume it's OK - // for now. - break; - } else if (VD->getInit() && !isVarOnPath(Path, VD)) { - Path.push_back({IndirectLocalPathEntry::VarInit, DRE, VD}); - visitLocalsRetainedByReferenceBinding(Path, VD->getInit(), - RK_ReferenceBinding, Visit, - EnableLifetimeWarnings); - } - } - break; - } - - case Stmt::UnaryOperatorClass: { - // The only unary operator that make sense to handle here - // is Deref. All others don't resolve to a "name." This includes - // handling all sorts of rvalues passed to a unary operator. - const UnaryOperator *U = cast(Init); - if (U->getOpcode() == UO_Deref) - visitLocalsRetainedByInitializer(Path, U->getSubExpr(), Visit, true, - EnableLifetimeWarnings); - break; - } - - case Stmt::ArraySectionExprClass: { - visitLocalsRetainedByInitializer(Path, - cast(Init)->getBase(), - Visit, true, EnableLifetimeWarnings); - break; - } - - case Stmt::ConditionalOperatorClass: - case Stmt::BinaryConditionalOperatorClass: { - auto *C = cast(Init); - if (!C->getTrueExpr()->getType()->isVoidType()) - visitLocalsRetainedByReferenceBinding(Path, C->getTrueExpr(), RK, Visit, - EnableLifetimeWarnings); - if (!C->getFalseExpr()->getType()->isVoidType()) - visitLocalsRetainedByReferenceBinding(Path, C->getFalseExpr(), RK, Visit, - EnableLifetimeWarnings); - break; - } - - case Stmt::CompoundLiteralExprClass: { - if (auto *CLE = dyn_cast(Init)) { - if (!CLE->isFileScope()) - Visit(Path, Local(CLE), RK); - } - break; - } - - // FIXME: Visit the left-hand side of an -> or ->*. - - default: - break; - } -} - -/// Visit the locals that would be reachable through an object initialized by -/// the prvalue expression \c Init. -static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path, - Expr *Init, LocalVisitor Visit, - bool RevisitSubinits, - bool EnableLifetimeWarnings) { - RevertToOldSizeRAII RAII(Path); - - Expr *Old; - do { - Old = Init; - - // Step into CXXDefaultInitExprs so we can diagnose cases where a - // constructor inherits one as an implicit mem-initializer. - if (auto *DIE = dyn_cast(Init)) { - Path.push_back({IndirectLocalPathEntry::DefaultInit, DIE, DIE->getField()}); - Init = DIE->getExpr(); - } - - if (auto *FE = dyn_cast(Init)) - Init = FE->getSubExpr(); - - // Dig out the expression which constructs the extended temporary. - Init = const_cast(Init->skipRValueSubobjectAdjustments()); - - if (CXXBindTemporaryExpr *BTE = dyn_cast(Init)) - Init = BTE->getSubExpr(); - - Init = Init->IgnoreParens(); - - // Step over value-preserving rvalue casts. - if (auto *CE = dyn_cast(Init)) { - switch (CE->getCastKind()) { - case CK_LValueToRValue: - // If we can match the lvalue to a const object, we can look at its - // initializer. - Path.push_back({IndirectLocalPathEntry::LValToRVal, CE}); - return visitLocalsRetainedByReferenceBinding( - Path, Init, RK_ReferenceBinding, - [&](IndirectLocalPath &Path, Local L, ReferenceKind RK) -> bool { - if (auto *DRE = dyn_cast(L)) { - auto *VD = dyn_cast(DRE->getDecl()); - if (VD && VD->getType().isConstQualified() && VD->getInit() && - !isVarOnPath(Path, VD)) { - Path.push_back({IndirectLocalPathEntry::VarInit, DRE, VD}); - visitLocalsRetainedByInitializer(Path, VD->getInit(), Visit, true, - EnableLifetimeWarnings); - } - } else if (auto *MTE = dyn_cast(L)) { - if (MTE->getType().isConstQualified()) - visitLocalsRetainedByInitializer(Path, MTE->getSubExpr(), Visit, - true, EnableLifetimeWarnings); - } - return false; - }, EnableLifetimeWarnings); - - // We assume that objects can be retained by pointers cast to integers, - // but not if the integer is cast to floating-point type or to _Complex. - // We assume that casts to 'bool' do not preserve enough information to - // retain a local object. - case CK_NoOp: - case CK_BitCast: - case CK_BaseToDerived: - case CK_DerivedToBase: - case CK_UncheckedDerivedToBase: - case CK_Dynamic: - case CK_ToUnion: - case CK_UserDefinedConversion: - case CK_ConstructorConversion: - case CK_IntegralToPointer: - case CK_PointerToIntegral: - case CK_VectorSplat: - case CK_IntegralCast: - case CK_CPointerToObjCPointerCast: - case CK_BlockPointerToObjCPointerCast: - case CK_AnyPointerToBlockPointerCast: - case CK_AddressSpaceConversion: - break; - - case CK_ArrayToPointerDecay: - // Model array-to-pointer decay as taking the address of the array - // lvalue. - Path.push_back({IndirectLocalPathEntry::AddressOf, CE}); - return visitLocalsRetainedByReferenceBinding(Path, CE->getSubExpr(), - RK_ReferenceBinding, Visit, - EnableLifetimeWarnings); - - default: - return; - } - - Init = CE->getSubExpr(); - } - } while (Old != Init); - - // C++17 [dcl.init.list]p6: - // initializing an initializer_list object from the array extends the - // lifetime of the array exactly like binding a reference to a temporary. - if (auto *ILE = dyn_cast(Init)) - return visitLocalsRetainedByReferenceBinding(Path, ILE->getSubExpr(), - RK_StdInitializerList, Visit, - EnableLifetimeWarnings); - - if (InitListExpr *ILE = dyn_cast(Init)) { - // We already visited the elements of this initializer list while - // performing the initialization. Don't visit them again unless we've - // changed the lifetime of the initialized entity. - if (!RevisitSubinits) - return; - - if (ILE->isTransparent()) - return visitLocalsRetainedByInitializer(Path, ILE->getInit(0), Visit, - RevisitSubinits, - EnableLifetimeWarnings); - - if (ILE->getType()->isArrayType()) { - for (unsigned I = 0, N = ILE->getNumInits(); I != N; ++I) - visitLocalsRetainedByInitializer(Path, ILE->getInit(I), Visit, - RevisitSubinits, - EnableLifetimeWarnings); - return; - } - - if (CXXRecordDecl *RD = ILE->getType()->getAsCXXRecordDecl()) { - assert(RD->isAggregate() && "aggregate init on non-aggregate"); - - // If we lifetime-extend a braced initializer which is initializing an - // aggregate, and that aggregate contains reference members which are - // bound to temporaries, those temporaries are also lifetime-extended. - if (RD->isUnion() && ILE->getInitializedFieldInUnion() && - ILE->getInitializedFieldInUnion()->getType()->isReferenceType()) - visitLocalsRetainedByReferenceBinding(Path, ILE->getInit(0), - RK_ReferenceBinding, Visit, - EnableLifetimeWarnings); - else { - unsigned Index = 0; - for (; Index < RD->getNumBases() && Index < ILE->getNumInits(); ++Index) - visitLocalsRetainedByInitializer(Path, ILE->getInit(Index), Visit, - RevisitSubinits, - EnableLifetimeWarnings); - for (const auto *I : RD->fields()) { - if (Index >= ILE->getNumInits()) - break; - if (I->isUnnamedBitField()) - continue; - Expr *SubInit = ILE->getInit(Index); - if (I->getType()->isReferenceType()) - visitLocalsRetainedByReferenceBinding(Path, SubInit, - RK_ReferenceBinding, Visit, - EnableLifetimeWarnings); - else - // This might be either aggregate-initialization of a member or - // initialization of a std::initializer_list object. Regardless, - // we should recursively lifetime-extend that initializer. - visitLocalsRetainedByInitializer(Path, SubInit, Visit, - RevisitSubinits, - EnableLifetimeWarnings); - ++Index; - } - } - } - return; - } - - // The lifetime of an init-capture is that of the closure object constructed - // by a lambda-expression. - if (auto *LE = dyn_cast(Init)) { - LambdaExpr::capture_iterator CapI = LE->capture_begin(); - for (Expr *E : LE->capture_inits()) { - assert(CapI != LE->capture_end()); - const LambdaCapture &Cap = *CapI++; - if (!E) - continue; - if (Cap.capturesVariable()) - Path.push_back({IndirectLocalPathEntry::LambdaCaptureInit, E, &Cap}); - if (E->isGLValue()) - visitLocalsRetainedByReferenceBinding(Path, E, RK_ReferenceBinding, - Visit, EnableLifetimeWarnings); - else - visitLocalsRetainedByInitializer(Path, E, Visit, true, - EnableLifetimeWarnings); - if (Cap.capturesVariable()) - Path.pop_back(); - } - } - - // Assume that a copy or move from a temporary references the same objects - // that the temporary does. - if (auto *CCE = dyn_cast(Init)) { - if (CCE->getConstructor()->isCopyOrMoveConstructor()) { - if (auto *MTE = dyn_cast(CCE->getArg(0))) { - Expr *Arg = MTE->getSubExpr(); - Path.push_back({IndirectLocalPathEntry::TemporaryCopy, Arg, - CCE->getConstructor()}); - visitLocalsRetainedByInitializer(Path, Arg, Visit, true, - /*EnableLifetimeWarnings*/false); - Path.pop_back(); - } - } - } - - if (isa(Init) || isa(Init)) { - if (EnableLifetimeWarnings) - handleGslAnnotatedTypes(Path, Init, Visit); - return visitLifetimeBoundArguments(Path, Init, Visit); - } - - switch (Init->getStmtClass()) { - case Stmt::UnaryOperatorClass: { - auto *UO = cast(Init); - // If the initializer is the address of a local, we could have a lifetime - // problem. - if (UO->getOpcode() == UO_AddrOf) { - // If this is &rvalue, then it's ill-formed and we have already diagnosed - // it. Don't produce a redundant warning about the lifetime of the - // temporary. - if (isa(UO->getSubExpr())) - return; - - Path.push_back({IndirectLocalPathEntry::AddressOf, UO}); - visitLocalsRetainedByReferenceBinding(Path, UO->getSubExpr(), - RK_ReferenceBinding, Visit, - EnableLifetimeWarnings); - } - break; - } - - case Stmt::BinaryOperatorClass: { - // Handle pointer arithmetic. - auto *BO = cast(Init); - BinaryOperatorKind BOK = BO->getOpcode(); - if (!BO->getType()->isPointerType() || (BOK != BO_Add && BOK != BO_Sub)) - break; - - if (BO->getLHS()->getType()->isPointerType()) - visitLocalsRetainedByInitializer(Path, BO->getLHS(), Visit, true, - EnableLifetimeWarnings); - else if (BO->getRHS()->getType()->isPointerType()) - visitLocalsRetainedByInitializer(Path, BO->getRHS(), Visit, true, - EnableLifetimeWarnings); - break; - } - - case Stmt::ConditionalOperatorClass: - case Stmt::BinaryConditionalOperatorClass: { - auto *C = cast(Init); - // In C++, we can have a throw-expression operand, which has 'void' type - // and isn't interesting from a lifetime perspective. - if (!C->getTrueExpr()->getType()->isVoidType()) - visitLocalsRetainedByInitializer(Path, C->getTrueExpr(), Visit, true, - EnableLifetimeWarnings); - if (!C->getFalseExpr()->getType()->isVoidType()) - visitLocalsRetainedByInitializer(Path, C->getFalseExpr(), Visit, true, - EnableLifetimeWarnings); - break; - } - - case Stmt::BlockExprClass: - if (cast(Init)->getBlockDecl()->hasCaptures()) { - // This is a local block, whose lifetime is that of the function. - Visit(Path, Local(cast(Init)), RK_ReferenceBinding); - } - break; - - case Stmt::AddrLabelExprClass: - // We want to warn if the address of a label would escape the function. - Visit(Path, Local(cast(Init)), RK_ReferenceBinding); - break; - - default: - break; - } -} - -/// Whether a path to an object supports lifetime extension. -enum PathLifetimeKind { - /// Lifetime-extend along this path. - Extend, - /// We should lifetime-extend, but we don't because (due to technical - /// limitations) we can't. This happens for default member initializers, - /// which we don't clone for every use, so we don't have a unique - /// MaterializeTemporaryExpr to update. - ShouldExtend, - /// Do not lifetime extend along this path. - NoExtend -}; - -/// Determine whether this is an indirect path to a temporary that we are -/// supposed to lifetime-extend along. -static PathLifetimeKind -shouldLifetimeExtendThroughPath(const IndirectLocalPath &Path) { - PathLifetimeKind Kind = PathLifetimeKind::Extend; - for (auto Elem : Path) { - if (Elem.Kind == IndirectLocalPathEntry::DefaultInit) - Kind = PathLifetimeKind::ShouldExtend; - else if (Elem.Kind != IndirectLocalPathEntry::LambdaCaptureInit) - return PathLifetimeKind::NoExtend; - } - return Kind; -} - -/// Find the range for the first interesting entry in the path at or after I. -static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I, - Expr *E) { - for (unsigned N = Path.size(); I != N; ++I) { - switch (Path[I].Kind) { - case IndirectLocalPathEntry::AddressOf: - case IndirectLocalPathEntry::LValToRVal: - case IndirectLocalPathEntry::LifetimeBoundCall: - case IndirectLocalPathEntry::TemporaryCopy: - case IndirectLocalPathEntry::GslReferenceInit: - case IndirectLocalPathEntry::GslPointerInit: - // These exist primarily to mark the path as not permitting or - // supporting lifetime extension. - break; - - case IndirectLocalPathEntry::VarInit: - if (cast(Path[I].D)->isImplicit()) - return SourceRange(); - [[fallthrough]]; - case IndirectLocalPathEntry::DefaultInit: - return Path[I].E->getSourceRange(); - - case IndirectLocalPathEntry::LambdaCaptureInit: - if (!Path[I].Capture->capturesVariable()) - continue; - return Path[I].E->getSourceRange(); - } - } - return E->getSourceRange(); -} - -static bool pathOnlyInitializesGslPointer(IndirectLocalPath &Path) { - for (const auto &It : llvm::reverse(Path)) { - if (It.Kind == IndirectLocalPathEntry::VarInit) - continue; - if (It.Kind == IndirectLocalPathEntry::AddressOf) - continue; - if (It.Kind == IndirectLocalPathEntry::LifetimeBoundCall) - continue; - return It.Kind == IndirectLocalPathEntry::GslPointerInit || - It.Kind == IndirectLocalPathEntry::GslReferenceInit; - } - return false; -} - void Sema::checkInitializerLifetime(const InitializedEntity &Entity, Expr *Init) { - LifetimeResult LR = getEntityLifetime(&Entity); - LifetimeKind LK = LR.getInt(); - const InitializedEntity *ExtendingEntity = LR.getPointer(); - - // If this entity doesn't have an interesting lifetime, don't bother looking - // for temporaries within its initializer. - if (LK == LK_FullExpression) - return; - - auto TemporaryVisitor = [&](IndirectLocalPath &Path, Local L, - ReferenceKind RK) -> bool { - SourceRange DiagRange = nextPathEntryRange(Path, 0, L); - SourceLocation DiagLoc = DiagRange.getBegin(); - - auto *MTE = dyn_cast(L); - - bool IsGslPtrInitWithGslTempOwner = false; - bool IsLocalGslOwner = false; - if (pathOnlyInitializesGslPointer(Path)) { - if (isa(L)) { - // We do not want to follow the references when returning a pointer originating - // from a local owner to avoid the following false positive: - // int &p = *localUniquePtr; - // someContainer.add(std::move(localUniquePtr)); - // return p; - IsLocalGslOwner = isRecordWithAttr(L->getType()); - if (pathContainsInit(Path) || !IsLocalGslOwner) - return false; - } else { - IsGslPtrInitWithGslTempOwner = MTE && !MTE->getExtendingDecl() && - isRecordWithAttr(MTE->getType()); - // Skipping a chain of initializing gsl::Pointer annotated objects. - // We are looking only for the final source to find out if it was - // a local or temporary owner or the address of a local variable/param. - if (!IsGslPtrInitWithGslTempOwner) - return true; - } - } - - switch (LK) { - case LK_FullExpression: - llvm_unreachable("already handled this"); - - case LK_Extended: { - if (!MTE) { - // The initialized entity has lifetime beyond the full-expression, - // and the local entity does too, so don't warn. - // - // FIXME: We should consider warning if a static / thread storage - // duration variable retains an automatic storage duration local. - return false; - } - - if (IsGslPtrInitWithGslTempOwner && DiagLoc.isValid()) { - Diag(DiagLoc, diag::warn_dangling_lifetime_pointer) << DiagRange; - return false; - } - - switch (shouldLifetimeExtendThroughPath(Path)) { - case PathLifetimeKind::Extend: - // Update the storage duration of the materialized temporary. - // FIXME: Rebuild the expression instead of mutating it. - MTE->setExtendingDecl(ExtendingEntity->getDecl(), - ExtendingEntity->allocateManglingNumber()); - // Also visit the temporaries lifetime-extended by this initializer. - return true; - - case PathLifetimeKind::ShouldExtend: - // We're supposed to lifetime-extend the temporary along this path (per - // the resolution of DR1815), but we don't support that yet. - // - // FIXME: Properly handle this situation. Perhaps the easiest approach - // would be to clone the initializer expression on each use that would - // lifetime extend its temporaries. - Diag(DiagLoc, diag::warn_unsupported_lifetime_extension) - << RK << DiagRange; - break; - - case PathLifetimeKind::NoExtend: - // If the path goes through the initialization of a variable or field, - // it can't possibly reach a temporary created in this full-expression. - // We will have already diagnosed any problems with the initializer. - if (pathContainsInit(Path)) - return false; - - Diag(DiagLoc, diag::warn_dangling_variable) - << RK << !Entity.getParent() - << ExtendingEntity->getDecl()->isImplicit() - << ExtendingEntity->getDecl() << Init->isGLValue() << DiagRange; - break; - } - break; - } - - case LK_MemInitializer: { - if (isa(L)) { - // Under C++ DR1696, if a mem-initializer (or a default member - // initializer used by the absence of one) would lifetime-extend a - // temporary, the program is ill-formed. - if (auto *ExtendingDecl = - ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) { - if (IsGslPtrInitWithGslTempOwner) { - Diag(DiagLoc, diag::warn_dangling_lifetime_pointer_member) - << ExtendingDecl << DiagRange; - Diag(ExtendingDecl->getLocation(), - diag::note_ref_or_ptr_member_declared_here) - << true; - return false; - } - bool IsSubobjectMember = ExtendingEntity != &Entity; - Diag(DiagLoc, shouldLifetimeExtendThroughPath(Path) != - PathLifetimeKind::NoExtend - ? diag::err_dangling_member - : diag::warn_dangling_member) - << ExtendingDecl << IsSubobjectMember << RK << DiagRange; - // Don't bother adding a note pointing to the field if we're inside - // its default member initializer; our primary diagnostic points to - // the same place in that case. - if (Path.empty() || - Path.back().Kind != IndirectLocalPathEntry::DefaultInit) { - Diag(ExtendingDecl->getLocation(), - diag::note_lifetime_extending_member_declared_here) - << RK << IsSubobjectMember; - } - } else { - // We have a mem-initializer but no particular field within it; this - // is either a base class or a delegating initializer directly - // initializing the base-class from something that doesn't live long - // enough. - // - // FIXME: Warn on this. - return false; - } - } else { - // Paths via a default initializer can only occur during error recovery - // (there's no other way that a default initializer can refer to a - // local). Don't produce a bogus warning on those cases. - if (pathContainsInit(Path)) - return false; - - // Suppress false positives for code like the one below: - // Ctor(unique_ptr up) : member(*up), member2(move(up)) {} - if (IsLocalGslOwner && pathOnlyInitializesGslPointer(Path)) - return false; - - auto *DRE = dyn_cast(L); - auto *VD = DRE ? dyn_cast(DRE->getDecl()) : nullptr; - if (!VD) { - // A member was initialized to a local block. - // FIXME: Warn on this. - return false; - } - - if (auto *Member = - ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) { - bool IsPointer = !Member->getType()->isReferenceType(); - Diag(DiagLoc, IsPointer ? diag::warn_init_ptr_member_to_parameter_addr - : diag::warn_bind_ref_member_to_parameter) - << Member << VD << isa(VD) << DiagRange; - Diag(Member->getLocation(), - diag::note_ref_or_ptr_member_declared_here) - << (unsigned)IsPointer; - } - } - break; - } - - case LK_New: - if (isa(L)) { - if (IsGslPtrInitWithGslTempOwner) - Diag(DiagLoc, diag::warn_dangling_lifetime_pointer) << DiagRange; - else - Diag(DiagLoc, RK == RK_ReferenceBinding - ? diag::warn_new_dangling_reference - : diag::warn_new_dangling_initializer_list) - << !Entity.getParent() << DiagRange; - } else { - // We can't determine if the allocation outlives the local declaration. - return false; - } - break; - - case LK_Return: - case LK_StmtExprResult: - if (auto *DRE = dyn_cast(L)) { - // We can't determine if the local variable outlives the statement - // expression. - if (LK == LK_StmtExprResult) - return false; - Diag(DiagLoc, diag::warn_ret_stack_addr_ref) - << Entity.getType()->isReferenceType() << DRE->getDecl() - << isa(DRE->getDecl()) << DiagRange; - } else if (isa(L)) { - Diag(DiagLoc, diag::err_ret_local_block) << DiagRange; - } else if (isa(L)) { - // Don't warn when returning a label from a statement expression. - // Leaving the scope doesn't end its lifetime. - if (LK == LK_StmtExprResult) - return false; - Diag(DiagLoc, diag::warn_ret_addr_label) << DiagRange; - } else if (auto *CLE = dyn_cast(L)) { - Diag(DiagLoc, diag::warn_ret_stack_addr_ref) - << Entity.getType()->isReferenceType() << CLE->getInitializer() << 2 - << DiagRange; - } else { - // P2748R5: Disallow Binding a Returned Glvalue to a Temporary. - // [stmt.return]/p6: In a function whose return type is a reference, - // other than an invented function for std::is_convertible ([meta.rel]), - // a return statement that binds the returned reference to a temporary - // expression ([class.temporary]) is ill-formed. - if (getLangOpts().CPlusPlus26 && Entity.getType()->isReferenceType()) - Diag(DiagLoc, diag::err_ret_local_temp_ref) - << Entity.getType()->isReferenceType() << DiagRange; - else - Diag(DiagLoc, diag::warn_ret_local_temp_addr_ref) - << Entity.getType()->isReferenceType() << DiagRange; - } - break; - } - - for (unsigned I = 0; I != Path.size(); ++I) { - auto Elem = Path[I]; - - switch (Elem.Kind) { - case IndirectLocalPathEntry::AddressOf: - case IndirectLocalPathEntry::LValToRVal: - // These exist primarily to mark the path as not permitting or - // supporting lifetime extension. - break; - - case IndirectLocalPathEntry::LifetimeBoundCall: - case IndirectLocalPathEntry::TemporaryCopy: - case IndirectLocalPathEntry::GslPointerInit: - case IndirectLocalPathEntry::GslReferenceInit: - // FIXME: Consider adding a note for these. - break; - - case IndirectLocalPathEntry::DefaultInit: { - auto *FD = cast(Elem.D); - Diag(FD->getLocation(), diag::note_init_with_default_member_initializer) - << FD << nextPathEntryRange(Path, I + 1, L); - break; - } - - case IndirectLocalPathEntry::VarInit: { - const VarDecl *VD = cast(Elem.D); - Diag(VD->getLocation(), diag::note_local_var_initializer) - << VD->getType()->isReferenceType() - << VD->isImplicit() << VD->getDeclName() - << nextPathEntryRange(Path, I + 1, L); - break; - } - - case IndirectLocalPathEntry::LambdaCaptureInit: - if (!Elem.Capture->capturesVariable()) - break; - // FIXME: We can't easily tell apart an init-capture from a nested - // capture of an init-capture. - const ValueDecl *VD = Elem.Capture->getCapturedVar(); - Diag(Elem.Capture->getLocation(), diag::note_lambda_capture_initializer) - << VD << VD->isInitCapture() << Elem.Capture->isExplicit() - << (Elem.Capture->getCaptureKind() == LCK_ByRef) << VD - << nextPathEntryRange(Path, I + 1, L); - break; - } - } - - // We didn't lifetime-extend, so don't go any further; we don't need more - // warnings or errors on inner temporaries within this one's initializer. - return false; - }; - - bool EnableLifetimeWarnings = !getDiagnostics().isIgnored( - diag::warn_dangling_lifetime_pointer, SourceLocation()); - llvm::SmallVector Path; - if (Init->isGLValue()) - visitLocalsRetainedByReferenceBinding(Path, Init, RK_ReferenceBinding, - TemporaryVisitor, - EnableLifetimeWarnings); - else - visitLocalsRetainedByInitializer(Path, Init, TemporaryVisitor, false, - EnableLifetimeWarnings); + return sema::checkExprLifetime(*this, Entity, Init); } static void DiagnoseNarrowingInInitList(Sema &S, diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index e9476a0c93c5d4..ca9c7cb9faadfb 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -2391,7 +2391,7 @@ Sema::LambdaScopeForCallOperatorInstantiationRAII:: Pattern = dyn_cast(getLambdaAwareParentOfDeclContext(Pattern)); - if (!FD || !Pattern) + if (!ParentFD || !Pattern) break; SemaRef.addInstantiatedParametersToScope(ParentFD, Pattern, Scope, MLTAL); diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index be6ea20a956a39..9a3fabc5933eee 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -1606,22 +1606,32 @@ bool Sema::isUsableModule(const Module *M) { // [module.global.frag]p1: // The global module fragment can be used to provide declarations that are // attached to the global module and usable within the module unit. - if (M == TheGlobalModuleFragment || M == TheImplicitGlobalModuleFragment || - // If M is the module we're parsing, it should be usable. This covers the - // private module fragment. The private module fragment is usable only if - // it is within the current module unit. And it must be the current - // parsing module unit if it is within the current module unit according - // to the grammar of the private module fragment. NOTE: This is covered by - // the following condition. The intention of the check is to avoid string - // comparison as much as possible. - M == getCurrentModule() || - // The module unit which is in the same module with the current module - // unit is usable. - // - // FIXME: Here we judge if they are in the same module by comparing the - // string. Is there any better solution? - M->getPrimaryModuleInterfaceName() == - llvm::StringRef(getLangOpts().CurrentModule).split(':').first) { + if (M == TheGlobalModuleFragment || M == TheImplicitGlobalModuleFragment) { + UsableModuleUnitsCache.insert(M); + return true; + } + + // Otherwise, the global module fragment from other translation unit is not + // directly usable. + if (M->isGlobalModule()) + return false; + + Module *Current = getCurrentModule(); + + // If we're not parsing a module, we can't use all the declarations from + // another module easily. + if (!Current) + return false; + + // If M is the module we're parsing or M and the current module unit lives in + // the same module, M should be usable. + // + // Note: It should be fine to search the vector `ModuleScopes` linearly since + // it should be generally small enough. There should be rare module fragments + // in a named module unit. + if (llvm::count_if(ModuleScopes, + [&M](const ModuleScope &MS) { return MS.Module == M; }) || + getASTContext().isInSameModule(M, Current)) { UsableModuleUnitsCache.insert(M); return true; } @@ -5816,19 +5826,13 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, const NamedDecl *Decl, if (M->isModuleMapModule()) return M->getFullModuleName(); - Module *CurrentModule = getCurrentModule(); - if (M->isImplicitGlobalModule()) M = M->getTopLevelModule(); - bool IsInTheSameModule = - CurrentModule && CurrentModule->getPrimaryModuleInterfaceName() == - M->getPrimaryModuleInterfaceName(); - // If the current module unit is in the same module with M, it is OK to show // the partition name. Otherwise, it'll be sufficient to show the primary // module name. - if (IsInTheSameModule) + if (getASTContext().isInSameModule(M, getCurrentModule())) return M->getTopLevelModuleName().str(); else return M->getPrimaryModuleInterfaceName().str(); @@ -5961,7 +5965,7 @@ RedeclarationKind Sema::forRedeclarationInCurContext() const { // anything that is not visible. We don't need to check linkage here; if // the context has internal linkage, redeclaration lookup won't find things // from other TUs, and we can't safely compute linkage yet in general. - if (cast(CurContext)->getOwningModuleForLinkage(/*IgnoreLinkage*/ true)) + if (cast(CurContext)->getOwningModuleForLinkage()) return RedeclarationKind::ForVisibleRedeclaration; return RedeclarationKind::ForExternalRedeclaration; } diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp index ad118ac90e4aa6..98e7971dc0bf3f 100644 --- a/clang/lib/Sema/SemaModule.cpp +++ b/clang/lib/Sema/SemaModule.cpp @@ -82,7 +82,8 @@ static std::string stringFromPath(ModuleIdPath Path) { /// CurrentModule. Since currently it is expensive to decide whether two module /// units come from the same module by comparing the module name. static bool -isImportingModuleUnitFromSameModule(Module *Imported, Module *CurrentModule, +isImportingModuleUnitFromSameModule(ASTContext &Ctx, Module *Imported, + Module *CurrentModule, Module *&FoundPrimaryModuleInterface) { if (!Imported->isNamedModule()) return false; @@ -109,8 +110,7 @@ isImportingModuleUnitFromSameModule(Module *Imported, Module *CurrentModule, if (!CurrentModule->isModulePartitionImplementation()) return false; - if (Imported->getPrimaryModuleInterfaceName() == - CurrentModule->getPrimaryModuleInterfaceName()) { + if (Ctx.isInSameModule(Imported, CurrentModule)) { assert(!FoundPrimaryModuleInterface || FoundPrimaryModuleInterface == Imported); FoundPrimaryModuleInterface = Imported; @@ -127,8 +127,9 @@ isImportingModuleUnitFromSameModule(Module *Imported, Module *CurrentModule, /// the module unit purview of U. These rules can in turn lead to the /// importation of yet more translation units. static void -makeTransitiveImportsVisible(VisibleModuleSet &VisibleModules, Module *Imported, - Module *CurrentModule, SourceLocation ImportLoc, +makeTransitiveImportsVisible(ASTContext &Ctx, VisibleModuleSet &VisibleModules, + Module *Imported, Module *CurrentModule, + SourceLocation ImportLoc, bool IsImportingPrimaryModuleInterface = false) { assert(Imported->isNamedModule() && "'makeTransitiveImportsVisible()' is intended for standard C++ named " @@ -150,7 +151,7 @@ makeTransitiveImportsVisible(VisibleModuleSet &VisibleModules, Module *Imported, // use the sourcelocation loaded from the visible modules. VisibleModules.setVisible(Importing, ImportLoc); - if (isImportingModuleUnitFromSameModule(Importing, CurrentModule, + if (isImportingModuleUnitFromSameModule(Ctx, Importing, CurrentModule, FoundPrimaryModuleInterface)) for (Module *TransImported : Importing->Imports) if (!VisibleModules.isVisible(TransImported)) @@ -484,7 +485,8 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, // and return the import decl to be added to the current TU. if (Interface) { - makeTransitiveImportsVisible(VisibleModules, Interface, Mod, ModuleLoc, + makeTransitiveImportsVisible(getASTContext(), VisibleModules, Interface, + Mod, ModuleLoc, /*IsImportingPrimaryModuleInterface=*/true); // Make the import decl for the interface in the impl module. @@ -643,8 +645,8 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, Diag(ImportLoc, diag::warn_experimental_header_unit); if (Mod->isNamedModule()) - makeTransitiveImportsVisible(VisibleModules, Mod, getCurrentModule(), - ImportLoc); + makeTransitiveImportsVisible(getASTContext(), VisibleModules, Mod, + getCurrentModule(), ImportLoc); else VisibleModules.setVisible(Mod, ImportLoc); diff --git a/clang/lib/Sema/SemaObjC.cpp b/clang/lib/Sema/SemaObjC.cpp index d396258cfc7d18..75233689769c5b 100644 --- a/clang/lib/Sema/SemaObjC.cpp +++ b/clang/lib/Sema/SemaObjC.cpp @@ -2255,4 +2255,154 @@ void SemaObjC::handleExternallyRetainedAttr(Decl *D, const ParsedAttr &AL) { handleSimpleAttribute(*this, D, AL); } +bool SemaObjC::GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx) { + Sema::FormatStringInfo FSI; + if ((SemaRef.GetFormatStringType(Format) == Sema::FST_NSString) && + SemaRef.getFormatStringInfo(Format, false, true, &FSI)) { + Idx = FSI.FormatIdx; + return true; + } + return false; +} + +/// Diagnose use of %s directive in an NSString which is being passed +/// as formatting string to formatting method. +void SemaObjC::DiagnoseCStringFormatDirectiveInCFAPI(const NamedDecl *FDecl, + Expr **Args, + unsigned NumArgs) { + unsigned Idx = 0; + bool Format = false; + ObjCStringFormatFamily SFFamily = FDecl->getObjCFStringFormattingFamily(); + if (SFFamily == ObjCStringFormatFamily::SFF_CFString) { + Idx = 2; + Format = true; + } else + for (const auto *I : FDecl->specific_attrs()) { + if (GetFormatNSStringIdx(I, Idx)) { + Format = true; + break; + } + } + if (!Format || NumArgs <= Idx) + return; + const Expr *FormatExpr = Args[Idx]; + if (const CStyleCastExpr *CSCE = dyn_cast(FormatExpr)) + FormatExpr = CSCE->getSubExpr(); + const StringLiteral *FormatString; + if (const ObjCStringLiteral *OSL = + dyn_cast(FormatExpr->IgnoreParenImpCasts())) + FormatString = OSL->getString(); + else + FormatString = dyn_cast(FormatExpr->IgnoreParenImpCasts()); + if (!FormatString) + return; + if (SemaRef.FormatStringHasSArg(FormatString)) { + Diag(FormatExpr->getExprLoc(), diag::warn_objc_cdirective_format_string) + << "%s" << 1 << 1; + Diag(FDecl->getLocation(), diag::note_entity_declared_at) + << FDecl->getDeclName(); + } +} + +bool SemaObjC::isSignedCharBool(QualType Ty) { + return Ty->isSpecificBuiltinType(BuiltinType::SChar) && getLangOpts().ObjC && + NSAPIObj->isObjCBOOLType(Ty); +} + +void SemaObjC::adornBoolConversionDiagWithTernaryFixit( + Expr *SourceExpr, const Sema::SemaDiagnosticBuilder &Builder) { + Expr *Ignored = SourceExpr->IgnoreImplicit(); + if (const auto *OVE = dyn_cast(Ignored)) + Ignored = OVE->getSourceExpr(); + bool NeedsParens = isa(Ignored) || + isa(Ignored) || + isa(Ignored); + SourceLocation EndLoc = SemaRef.getLocForEndOfToken(SourceExpr->getEndLoc()); + if (NeedsParens) + Builder << FixItHint::CreateInsertion(SourceExpr->getBeginLoc(), "(") + << FixItHint::CreateInsertion(EndLoc, ")"); + Builder << FixItHint::CreateInsertion(EndLoc, " ? YES : NO"); +} + +/// Check a single element within a collection literal against the +/// target element type. +static void checkCollectionLiteralElement(Sema &S, QualType TargetElementType, + Expr *Element, unsigned ElementKind) { + // Skip a bitcast to 'id' or qualified 'id'. + if (auto ICE = dyn_cast(Element)) { + if (ICE->getCastKind() == CK_BitCast && + ICE->getSubExpr()->getType()->getAs()) + Element = ICE->getSubExpr(); + } + + QualType ElementType = Element->getType(); + ExprResult ElementResult(Element); + if (ElementType->getAs() && + S.CheckSingleAssignmentConstraints(TargetElementType, ElementResult, + false, false) != Sema::Compatible) { + S.Diag(Element->getBeginLoc(), diag::warn_objc_collection_literal_element) + << ElementType << ElementKind << TargetElementType + << Element->getSourceRange(); + } + + if (auto ArrayLiteral = dyn_cast(Element)) + S.ObjC().checkArrayLiteral(TargetElementType, ArrayLiteral); + else if (auto DictionaryLiteral = dyn_cast(Element)) + S.ObjC().checkDictionaryLiteral(TargetElementType, DictionaryLiteral); +} + +/// Check an Objective-C array literal being converted to the given +/// target type. +void SemaObjC::checkArrayLiteral(QualType TargetType, + ObjCArrayLiteral *ArrayLiteral) { + if (!NSArrayDecl) + return; + + const auto *TargetObjCPtr = TargetType->getAs(); + if (!TargetObjCPtr) + return; + + if (TargetObjCPtr->isUnspecialized() || + TargetObjCPtr->getInterfaceDecl()->getCanonicalDecl() != + NSArrayDecl->getCanonicalDecl()) + return; + + auto TypeArgs = TargetObjCPtr->getTypeArgs(); + if (TypeArgs.size() != 1) + return; + + QualType TargetElementType = TypeArgs[0]; + for (unsigned I = 0, N = ArrayLiteral->getNumElements(); I != N; ++I) { + checkCollectionLiteralElement(SemaRef, TargetElementType, + ArrayLiteral->getElement(I), 0); + } +} + +void SemaObjC::checkDictionaryLiteral( + QualType TargetType, ObjCDictionaryLiteral *DictionaryLiteral) { + if (!NSDictionaryDecl) + return; + + const auto *TargetObjCPtr = TargetType->getAs(); + if (!TargetObjCPtr) + return; + + if (TargetObjCPtr->isUnspecialized() || + TargetObjCPtr->getInterfaceDecl()->getCanonicalDecl() != + NSDictionaryDecl->getCanonicalDecl()) + return; + + auto TypeArgs = TargetObjCPtr->getTypeArgs(); + if (TypeArgs.size() != 2) + return; + + QualType TargetKeyType = TypeArgs[0]; + QualType TargetObjectType = TypeArgs[1]; + for (unsigned I = 0, N = DictionaryLiteral->getNumElements(); I != N; ++I) { + auto Element = DictionaryLiteral->getKeyValueElement(I); + checkCollectionLiteralElement(SemaRef, TargetKeyType, Element.Key, 1); + checkCollectionLiteralElement(SemaRef, TargetObjectType, Element.Value, 2); + } +} + } // namespace clang diff --git a/clang/lib/Sema/SemaOpenCL.cpp b/clang/lib/Sema/SemaOpenCL.cpp index b3b495a15e02c3..9f746fffd34d0a 100644 --- a/clang/lib/Sema/SemaOpenCL.cpp +++ b/clang/lib/Sema/SemaOpenCL.cpp @@ -96,4 +96,483 @@ void SemaOpenCL::handleSubGroupSize(Decl *D, const ParsedAttr &AL) { OpenCLIntelReqdSubGroupSizeAttr(getASTContext(), AL, SGSize)); } +static inline bool isBlockPointer(Expr *Arg) { + return Arg->getType()->isBlockPointerType(); +} + +/// OpenCL C v2.0, s6.13.17.2 - Checks that the block parameters are all local +/// void*, which is a requirement of device side enqueue. +static bool checkBlockArgs(Sema &S, Expr *BlockArg) { + const BlockPointerType *BPT = + cast(BlockArg->getType().getCanonicalType()); + ArrayRef Params = + BPT->getPointeeType()->castAs()->getParamTypes(); + unsigned ArgCounter = 0; + bool IllegalParams = false; + // Iterate through the block parameters until either one is found that is not + // a local void*, or the block is valid. + for (ArrayRef::iterator I = Params.begin(), E = Params.end(); + I != E; ++I, ++ArgCounter) { + if (!(*I)->isPointerType() || !(*I)->getPointeeType()->isVoidType() || + (*I)->getPointeeType().getQualifiers().getAddressSpace() != + LangAS::opencl_local) { + // Get the location of the error. If a block literal has been passed + // (BlockExpr) then we can point straight to the offending argument, + // else we just point to the variable reference. + SourceLocation ErrorLoc; + if (isa(BlockArg)) { + BlockDecl *BD = cast(BlockArg)->getBlockDecl(); + ErrorLoc = BD->getParamDecl(ArgCounter)->getBeginLoc(); + } else if (isa(BlockArg)) { + ErrorLoc = cast(BlockArg)->getBeginLoc(); + } + S.Diag(ErrorLoc, + diag::err_opencl_enqueue_kernel_blocks_non_local_void_args); + IllegalParams = true; + } + } + + return IllegalParams; +} + +bool SemaOpenCL::checkSubgroupExt(CallExpr *Call) { + // OpenCL device can support extension but not the feature as extension + // requires subgroup independent forward progress, but subgroup independent + // forward progress is optional in OpenCL C 3.0 __opencl_c_subgroups feature. + if (!SemaRef.getOpenCLOptions().isSupported("cl_khr_subgroups", + getLangOpts()) && + !SemaRef.getOpenCLOptions().isSupported("__opencl_c_subgroups", + getLangOpts())) { + Diag(Call->getBeginLoc(), diag::err_opencl_requires_extension) + << 1 << Call->getDirectCallee() + << "cl_khr_subgroups or __opencl_c_subgroups"; + return true; + } + return false; +} + +bool SemaOpenCL::checkBuiltinNDRangeAndBlock(CallExpr *TheCall) { + if (SemaRef.checkArgCount(TheCall, 2)) + return true; + + if (checkSubgroupExt(TheCall)) + return true; + + // First argument is an ndrange_t type. + Expr *NDRangeArg = TheCall->getArg(0); + if (NDRangeArg->getType().getUnqualifiedType().getAsString() != "ndrange_t") { + Diag(NDRangeArg->getBeginLoc(), diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << "'ndrange_t'"; + return true; + } + + Expr *BlockArg = TheCall->getArg(1); + if (!isBlockPointer(BlockArg)) { + Diag(BlockArg->getBeginLoc(), diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << "block"; + return true; + } + return checkBlockArgs(SemaRef, BlockArg); +} + +bool SemaOpenCL::checkBuiltinKernelWorkGroupSize(CallExpr *TheCall) { + if (SemaRef.checkArgCount(TheCall, 1)) + return true; + + Expr *BlockArg = TheCall->getArg(0); + if (!isBlockPointer(BlockArg)) { + Diag(BlockArg->getBeginLoc(), diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << "block"; + return true; + } + return checkBlockArgs(SemaRef, BlockArg); +} + +/// Diagnose integer type and any valid implicit conversion to it. +static bool checkOpenCLEnqueueIntType(Sema &S, Expr *E, const QualType &IntT) { + // Taking into account implicit conversions, + // allow any integer. + if (!E->getType()->isIntegerType()) { + S.Diag(E->getBeginLoc(), + diag::err_opencl_enqueue_kernel_invalid_local_size_type); + return true; + } + // Potentially emit standard warnings for implicit conversions if enabled + // using -Wconversion. + S.CheckImplicitConversion(E, IntT, E->getBeginLoc()); + return false; +} + +static bool checkOpenCLEnqueueLocalSizeArgs(Sema &S, CallExpr *TheCall, + unsigned Start, unsigned End) { + bool IllegalParams = false; + for (unsigned I = Start; I <= End; ++I) + IllegalParams |= checkOpenCLEnqueueIntType(S, TheCall->getArg(I), + S.Context.getSizeType()); + return IllegalParams; +} + +/// OpenCL v2.0, s6.13.17.1 - Check that sizes are provided for all +/// 'local void*' parameter of passed block. +static bool checkOpenCLEnqueueVariadicArgs(Sema &S, CallExpr *TheCall, + Expr *BlockArg, + unsigned NumNonVarArgs) { + const BlockPointerType *BPT = + cast(BlockArg->getType().getCanonicalType()); + unsigned NumBlockParams = + BPT->getPointeeType()->castAs()->getNumParams(); + unsigned TotalNumArgs = TheCall->getNumArgs(); + + // For each argument passed to the block, a corresponding uint needs to + // be passed to describe the size of the local memory. + if (TotalNumArgs != NumBlockParams + NumNonVarArgs) { + S.Diag(TheCall->getBeginLoc(), + diag::err_opencl_enqueue_kernel_local_size_args); + return true; + } + + // Check that the sizes of the local memory are specified by integers. + return checkOpenCLEnqueueLocalSizeArgs(S, TheCall, NumNonVarArgs, + TotalNumArgs - 1); +} + +bool SemaOpenCL::checkBuiltinEnqueueKernel(CallExpr *TheCall) { + ASTContext &Context = getASTContext(); + unsigned NumArgs = TheCall->getNumArgs(); + + if (NumArgs < 4) { + Diag(TheCall->getBeginLoc(), diag::err_typecheck_call_too_few_args_at_least) + << 0 << 4 << NumArgs << /*is non object*/ 0; + return true; + } + + Expr *Arg0 = TheCall->getArg(0); + Expr *Arg1 = TheCall->getArg(1); + Expr *Arg2 = TheCall->getArg(2); + Expr *Arg3 = TheCall->getArg(3); + + // First argument always needs to be a queue_t type. + if (!Arg0->getType()->isQueueT()) { + Diag(TheCall->getArg(0)->getBeginLoc(), + diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << getASTContext().OCLQueueTy; + return true; + } + + // Second argument always needs to be a kernel_enqueue_flags_t enum value. + if (!Arg1->getType()->isIntegerType()) { + Diag(TheCall->getArg(1)->getBeginLoc(), + diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << "'kernel_enqueue_flags_t' (i.e. uint)"; + return true; + } + + // Third argument is always an ndrange_t type. + if (Arg2->getType().getUnqualifiedType().getAsString() != "ndrange_t") { + Diag(TheCall->getArg(2)->getBeginLoc(), + diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << "'ndrange_t'"; + return true; + } + + // With four arguments, there is only one form that the function could be + // called in: no events and no variable arguments. + if (NumArgs == 4) { + // check that the last argument is the right block type. + if (!isBlockPointer(Arg3)) { + Diag(Arg3->getBeginLoc(), diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << "block"; + return true; + } + // we have a block type, check the prototype + const BlockPointerType *BPT = + cast(Arg3->getType().getCanonicalType()); + if (BPT->getPointeeType()->castAs()->getNumParams() > + 0) { + Diag(Arg3->getBeginLoc(), diag::err_opencl_enqueue_kernel_blocks_no_args); + return true; + } + return false; + } + // we can have block + varargs. + if (isBlockPointer(Arg3)) + return (checkBlockArgs(SemaRef, Arg3) || + checkOpenCLEnqueueVariadicArgs(SemaRef, TheCall, Arg3, 4)); + // last two cases with either exactly 7 args or 7 args and varargs. + if (NumArgs >= 7) { + // check common block argument. + Expr *Arg6 = TheCall->getArg(6); + if (!isBlockPointer(Arg6)) { + Diag(Arg6->getBeginLoc(), diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << "block"; + return true; + } + if (checkBlockArgs(SemaRef, Arg6)) + return true; + + // Forth argument has to be any integer type. + if (!Arg3->getType()->isIntegerType()) { + Diag(TheCall->getArg(3)->getBeginLoc(), + diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << "integer"; + return true; + } + // check remaining common arguments. + Expr *Arg4 = TheCall->getArg(4); + Expr *Arg5 = TheCall->getArg(5); + + // Fifth argument is always passed as a pointer to clk_event_t. + if (!Arg4->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNotNull) && + !Arg4->getType()->getPointeeOrArrayElementType()->isClkEventT()) { + Diag(TheCall->getArg(4)->getBeginLoc(), + diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() + << Context.getPointerType(Context.OCLClkEventTy); + return true; + } + + // Sixth argument is always passed as a pointer to clk_event_t. + if (!Arg5->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNotNull) && + !(Arg5->getType()->isPointerType() && + Arg5->getType()->getPointeeType()->isClkEventT())) { + Diag(TheCall->getArg(5)->getBeginLoc(), + diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() + << Context.getPointerType(Context.OCLClkEventTy); + return true; + } + + if (NumArgs == 7) + return false; + + return checkOpenCLEnqueueVariadicArgs(SemaRef, TheCall, Arg6, 7); + } + + // None of the specific case has been detected, give generic error + Diag(TheCall->getBeginLoc(), diag::err_opencl_enqueue_kernel_incorrect_args); + return true; +} + +/// Returns OpenCL access qual. +static OpenCLAccessAttr *getOpenCLArgAccess(const Decl *D) { + return D->getAttr(); +} + +/// Returns true if pipe element type is different from the pointer. +static bool checkPipeArg(Sema &S, CallExpr *Call) { + const Expr *Arg0 = Call->getArg(0); + // First argument type should always be pipe. + if (!Arg0->getType()->isPipeType()) { + S.Diag(Call->getBeginLoc(), diag::err_opencl_builtin_pipe_first_arg) + << Call->getDirectCallee() << Arg0->getSourceRange(); + return true; + } + OpenCLAccessAttr *AccessQual = + getOpenCLArgAccess(cast(Arg0)->getDecl()); + // Validates the access qualifier is compatible with the call. + // OpenCL v2.0 s6.13.16 - The access qualifiers for pipe should only be + // read_only and write_only, and assumed to be read_only if no qualifier is + // specified. + switch (Call->getDirectCallee()->getBuiltinID()) { + case Builtin::BIread_pipe: + case Builtin::BIreserve_read_pipe: + case Builtin::BIcommit_read_pipe: + case Builtin::BIwork_group_reserve_read_pipe: + case Builtin::BIsub_group_reserve_read_pipe: + case Builtin::BIwork_group_commit_read_pipe: + case Builtin::BIsub_group_commit_read_pipe: + if (!(!AccessQual || AccessQual->isReadOnly())) { + S.Diag(Arg0->getBeginLoc(), + diag::err_opencl_builtin_pipe_invalid_access_modifier) + << "read_only" << Arg0->getSourceRange(); + return true; + } + break; + case Builtin::BIwrite_pipe: + case Builtin::BIreserve_write_pipe: + case Builtin::BIcommit_write_pipe: + case Builtin::BIwork_group_reserve_write_pipe: + case Builtin::BIsub_group_reserve_write_pipe: + case Builtin::BIwork_group_commit_write_pipe: + case Builtin::BIsub_group_commit_write_pipe: + if (!(AccessQual && AccessQual->isWriteOnly())) { + S.Diag(Arg0->getBeginLoc(), + diag::err_opencl_builtin_pipe_invalid_access_modifier) + << "write_only" << Arg0->getSourceRange(); + return true; + } + break; + default: + break; + } + return false; +} + +/// Returns true if pipe element type is different from the pointer. +static bool checkPipePacketType(Sema &S, CallExpr *Call, unsigned Idx) { + const Expr *Arg0 = Call->getArg(0); + const Expr *ArgIdx = Call->getArg(Idx); + const PipeType *PipeTy = cast(Arg0->getType()); + const QualType EltTy = PipeTy->getElementType(); + const PointerType *ArgTy = ArgIdx->getType()->getAs(); + // The Idx argument should be a pointer and the type of the pointer and + // the type of pipe element should also be the same. + if (!ArgTy || + !S.Context.hasSameType( + EltTy, ArgTy->getPointeeType()->getCanonicalTypeInternal())) { + S.Diag(Call->getBeginLoc(), diag::err_opencl_builtin_pipe_invalid_arg) + << Call->getDirectCallee() << S.Context.getPointerType(EltTy) + << ArgIdx->getType() << ArgIdx->getSourceRange(); + return true; + } + return false; +} + +bool SemaOpenCL::checkBuiltinRWPipe(CallExpr *Call) { + // OpenCL v2.0 s6.13.16.2 - The built-in read/write + // functions have two forms. + switch (Call->getNumArgs()) { + case 2: + if (checkPipeArg(SemaRef, Call)) + return true; + // The call with 2 arguments should be + // read/write_pipe(pipe T, T*). + // Check packet type T. + if (checkPipePacketType(SemaRef, Call, 1)) + return true; + break; + + case 4: { + if (checkPipeArg(SemaRef, Call)) + return true; + // The call with 4 arguments should be + // read/write_pipe(pipe T, reserve_id_t, uint, T*). + // Check reserve_id_t. + if (!Call->getArg(1)->getType()->isReserveIDT()) { + Diag(Call->getBeginLoc(), diag::err_opencl_builtin_pipe_invalid_arg) + << Call->getDirectCallee() << getASTContext().OCLReserveIDTy + << Call->getArg(1)->getType() << Call->getArg(1)->getSourceRange(); + return true; + } + + // Check the index. + const Expr *Arg2 = Call->getArg(2); + if (!Arg2->getType()->isIntegerType() && + !Arg2->getType()->isUnsignedIntegerType()) { + Diag(Call->getBeginLoc(), diag::err_opencl_builtin_pipe_invalid_arg) + << Call->getDirectCallee() << getASTContext().UnsignedIntTy + << Arg2->getType() << Arg2->getSourceRange(); + return true; + } + + // Check packet type T. + if (checkPipePacketType(SemaRef, Call, 3)) + return true; + } break; + default: + Diag(Call->getBeginLoc(), diag::err_opencl_builtin_pipe_arg_num) + << Call->getDirectCallee() << Call->getSourceRange(); + return true; + } + + return false; +} + +bool SemaOpenCL::checkBuiltinReserveRWPipe(CallExpr *Call) { + if (SemaRef.checkArgCount(Call, 2)) + return true; + + if (checkPipeArg(SemaRef, Call)) + return true; + + // Check the reserve size. + if (!Call->getArg(1)->getType()->isIntegerType() && + !Call->getArg(1)->getType()->isUnsignedIntegerType()) { + Diag(Call->getBeginLoc(), diag::err_opencl_builtin_pipe_invalid_arg) + << Call->getDirectCallee() << getASTContext().UnsignedIntTy + << Call->getArg(1)->getType() << Call->getArg(1)->getSourceRange(); + return true; + } + + // Since return type of reserve_read/write_pipe built-in function is + // reserve_id_t, which is not defined in the builtin def file , we used int + // as return type and need to override the return type of these functions. + Call->setType(getASTContext().OCLReserveIDTy); + + return false; +} + +bool SemaOpenCL::checkBuiltinCommitRWPipe(CallExpr *Call) { + if (SemaRef.checkArgCount(Call, 2)) + return true; + + if (checkPipeArg(SemaRef, Call)) + return true; + + // Check reserve_id_t. + if (!Call->getArg(1)->getType()->isReserveIDT()) { + Diag(Call->getBeginLoc(), diag::err_opencl_builtin_pipe_invalid_arg) + << Call->getDirectCallee() << getASTContext().OCLReserveIDTy + << Call->getArg(1)->getType() << Call->getArg(1)->getSourceRange(); + return true; + } + + return false; +} + +bool SemaOpenCL::checkBuiltinPipePackets(CallExpr *Call) { + if (SemaRef.checkArgCount(Call, 1)) + return true; + + if (!Call->getArg(0)->getType()->isPipeType()) { + Diag(Call->getBeginLoc(), diag::err_opencl_builtin_pipe_first_arg) + << Call->getDirectCallee() << Call->getArg(0)->getSourceRange(); + return true; + } + + return false; +} + +bool SemaOpenCL::checkBuiltinToAddr(unsigned BuiltinID, CallExpr *Call) { + if (SemaRef.checkArgCount(Call, 1)) + return true; + + auto RT = Call->getArg(0)->getType(); + if (!RT->isPointerType() || + RT->getPointeeType().getAddressSpace() == LangAS::opencl_constant) { + Diag(Call->getBeginLoc(), diag::err_opencl_builtin_to_addr_invalid_arg) + << Call->getArg(0) << Call->getDirectCallee() << Call->getSourceRange(); + return true; + } + + if (RT->getPointeeType().getAddressSpace() != LangAS::opencl_generic) { + Diag(Call->getArg(0)->getBeginLoc(), + diag::warn_opencl_generic_address_space_arg) + << Call->getDirectCallee()->getNameInfo().getAsString() + << Call->getArg(0)->getSourceRange(); + } + + RT = RT->getPointeeType(); + auto Qual = RT.getQualifiers(); + switch (BuiltinID) { + case Builtin::BIto_global: + Qual.setAddressSpace(LangAS::opencl_global); + break; + case Builtin::BIto_local: + Qual.setAddressSpace(LangAS::opencl_local); + break; + case Builtin::BIto_private: + Qual.setAddressSpace(LangAS::opencl_private); + break; + default: + llvm_unreachable("Invalid builtin function"); + } + Call->setType(getASTContext().getPointerType( + getASTContext().getQualifiedType(RT.getUnqualifiedType(), Qual))); + + return false; +} + } // namespace clang diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 5c759aedf9798a..3e6c6c94a47cda 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/SemaOpenMP.h" + #include "TreeTransform.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" @@ -466,7 +467,7 @@ class DSAStackTy { getTopOfStack().PossiblyLoopCounter = D ? D->getCanonicalDecl() : D; } /// Gets the possible loop counter decl. - const Decl *getPossiblyLoopCunter() const { + const Decl *getPossiblyLoopCounter() const { return getTopOfStack().PossiblyLoopCounter; } /// Start new OpenMP region stack in new non-capturing function. @@ -718,7 +719,7 @@ class DSAStackTy { TargetLocations.push_back(LocStart); } - /// Add location for the first encountered atomicc directive. + /// Add location for the first encountered atomic directive. void addAtomicDirectiveLoc(SourceLocation Loc) { if (AtomicLocation.isInvalid()) AtomicLocation = Loc; @@ -2584,7 +2585,7 @@ OpenMPClauseKind SemaOpenMP::isOpenMPPrivateDecl(ValueDecl *D, unsigned Level, DSAStack->loopStart(); return OMPC_private; } - if ((DSAStack->getPossiblyLoopCunter() == D->getCanonicalDecl() || + if ((DSAStack->getPossiblyLoopCounter() == D->getCanonicalDecl() || DSAStack->isLoopControlVariable(D).first) && !DSAStack->hasExplicitDSA( D, [](OpenMPClauseKind K, bool) { return K != OMPC_private; }, @@ -2694,8 +2695,8 @@ bool SemaOpenMP::isOpenMPGlobalCapturedDecl(ValueDecl *D, unsigned Level, unsigned NumLevels = getOpenMPCaptureLevels(DSAStack->getDirective(Level)); if (Level == 0) - // non-file scope static variale with default(firstprivate) - // should be gloabal captured. + // non-file scope static variable with default(firstprivate) + // should be global captured. return (NumLevels == CaptureLevel + 1 && (TopDVar.CKind != OMPC_shared || DSAStack->getDefaultDSA() == DSA_firstprivate)); @@ -2730,11 +2731,11 @@ void SemaOpenMP::finalizeOpenMPDelayedAnalysis(const FunctionDecl *Caller, assert(getLangOpts().OpenMP && "Expected OpenMP compilation mode."); std::optional DevTy = OMPDeclareTargetDeclAttr::getDeviceType(Caller->getMostRecentDecl()); - // Ignore host functions during device analyzis. + // Ignore host functions during device analysis. if (getLangOpts().OpenMPIsTargetDevice && (!DevTy || *DevTy == OMPDeclareTargetDeclAttr::DT_Host)) return; - // Ignore nohost functions during host analyzis. + // Ignore nohost functions during host analysis. if (!getLangOpts().OpenMPIsTargetDevice && DevTy && *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) return; @@ -3010,6 +3011,29 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, Expr *NumIterations, Sema &SemaRef, Scope *S, DSAStackTy *Stack); +static bool finishLinearClauses(Sema &SemaRef, ArrayRef Clauses, + OMPLoopBasedDirective::HelperExprs &B, + DSAStackTy *Stack) { + assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && + "loop exprs were not built"); + + if (SemaRef.CurContext->isDependentContext()) + return false; + + // Finalize the clauses that need pre-built expressions for CodeGen. + for (OMPClause *C : Clauses) { + auto *LC = dyn_cast(C); + if (!LC) + continue; + if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), + B.NumIterations, SemaRef, + SemaRef.getCurScope(), Stack)) + return true; + } + + return false; +} + namespace { class VarDeclFilterCCC final : public CorrectionCandidateCallback { @@ -3880,7 +3904,7 @@ class DSAAttrChecker final : public StmtVisitor { if (SemaRef.LangOpts.OpenMP >= 50) return !StackComponents.empty(); // Variable is used if it has been marked as an array, array - // section, array shaping or the variable iself. + // section, array shaping or the variable itself. return StackComponents.size() == 1 || llvm::all_of( llvm::drop_begin(llvm::reverse(StackComponents)), @@ -5759,7 +5783,7 @@ static CapturedStmt *buildDistanceFunc(Sema &Actions, QualType LogicalTy, // Divide by the absolute step amount. If the range is not a multiple of // the step size, rounding-up the effective upper bound ensures that the // last iteration is included. - // Note that the rounding-up may cause an overflow in a temporry that + // Note that the rounding-up may cause an overflow in a temporary that // could be avoided, but would have occurred in a C-style for-loop as // well. Expr *Divisor = BuildVarRef(NewStep); @@ -6040,7 +6064,7 @@ static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S, static void processImplicitMapsWithDefaultMappers(Sema &S, DSAStackTy *Stack, SmallVectorImpl &Clauses) { - // Check for the deault mapper for data members. + // Check for the default mapper for data members. if (S.getLangOpts().OpenMP < 50) return; SmallVector ImplicitMaps; @@ -6333,6 +6357,8 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( OpenMPDirectiveKind CancelRegion, ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, OpenMPDirectiveKind PrevMappedDirective) { + assert(isOpenMPExecutableDirective(Kind) && "Unexpected directive category"); + StmtResult Res = StmtError(); OpenMPBindClauseKind BindKind = OMPC_BIND_unknown; llvm::SmallVector ClausesWithoutBind; @@ -6525,18 +6551,14 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( ClausesWithImplicit); } - llvm::SmallVector AllowedNameModifiers; switch (Kind) { case OMPD_parallel: Res = ActOnOpenMPParallelDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); - AllowedNameModifiers.push_back(OMPD_parallel); break; case OMPD_simd: Res = ActOnOpenMPSimdDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - if (getLangOpts().OpenMP >= 50) - AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_tile: Res = @@ -6553,8 +6575,6 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( case OMPD_for_simd: Res = ActOnOpenMPForSimdDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - if (getLangOpts().OpenMP >= 50) - AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_sections: Res = ActOnOpenMPSectionsDirective(ClausesWithImplicit, AStmt, StartLoc, @@ -6585,14 +6605,10 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( case OMPD_parallel_for: Res = ActOnOpenMPParallelForDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - AllowedNameModifiers.push_back(OMPD_parallel); break; case OMPD_parallel_for_simd: Res = ActOnOpenMPParallelForSimdDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - AllowedNameModifiers.push_back(OMPD_parallel); - if (getLangOpts().OpenMP >= 50) - AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_scope: Res = @@ -6601,22 +6617,18 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( case OMPD_parallel_master: Res = ActOnOpenMPParallelMasterDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); - AllowedNameModifiers.push_back(OMPD_parallel); break; case OMPD_parallel_masked: Res = ActOnOpenMPParallelMaskedDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); - AllowedNameModifiers.push_back(OMPD_parallel); break; case OMPD_parallel_sections: Res = ActOnOpenMPParallelSectionsDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); - AllowedNameModifiers.push_back(OMPD_parallel); break; case OMPD_task: Res = ActOnOpenMPTaskDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); - AllowedNameModifiers.push_back(OMPD_task); break; case OMPD_taskyield: assert(ClausesWithImplicit.empty() && @@ -6676,19 +6688,14 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( case OMPD_target: Res = ActOnOpenMPTargetDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); - AllowedNameModifiers.push_back(OMPD_target); break; case OMPD_target_parallel: Res = ActOnOpenMPTargetParallelDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); - AllowedNameModifiers.push_back(OMPD_target); - AllowedNameModifiers.push_back(OMPD_parallel); break; case OMPD_target_parallel_for: Res = ActOnOpenMPTargetParallelForDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - AllowedNameModifiers.push_back(OMPD_target); - AllowedNameModifiers.push_back(OMPD_parallel); break; case OMPD_cancellation_point: assert(ClausesWithImplicit.empty() && @@ -6702,90 +6709,58 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( "No associated statement allowed for 'omp cancel' directive"); Res = ActOnOpenMPCancelDirective(ClausesWithImplicit, StartLoc, EndLoc, CancelRegion); - AllowedNameModifiers.push_back(OMPD_cancel); break; case OMPD_target_data: Res = ActOnOpenMPTargetDataDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); - AllowedNameModifiers.push_back(OMPD_target_data); break; case OMPD_target_enter_data: Res = ActOnOpenMPTargetEnterDataDirective(ClausesWithImplicit, StartLoc, EndLoc, AStmt); - AllowedNameModifiers.push_back(OMPD_target_enter_data); break; case OMPD_target_exit_data: Res = ActOnOpenMPTargetExitDataDirective(ClausesWithImplicit, StartLoc, EndLoc, AStmt); - AllowedNameModifiers.push_back(OMPD_target_exit_data); break; case OMPD_taskloop: Res = ActOnOpenMPTaskLoopDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - AllowedNameModifiers.push_back(OMPD_taskloop); break; case OMPD_taskloop_simd: Res = ActOnOpenMPTaskLoopSimdDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - AllowedNameModifiers.push_back(OMPD_taskloop); - if (getLangOpts().OpenMP >= 50) - AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_master_taskloop: Res = ActOnOpenMPMasterTaskLoopDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - AllowedNameModifiers.push_back(OMPD_taskloop); break; case OMPD_masked_taskloop: Res = ActOnOpenMPMaskedTaskLoopDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - AllowedNameModifiers.push_back(OMPD_taskloop); break; case OMPD_master_taskloop_simd: Res = ActOnOpenMPMasterTaskLoopSimdDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - AllowedNameModifiers.push_back(OMPD_taskloop); - if (getLangOpts().OpenMP >= 50) - AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_masked_taskloop_simd: Res = ActOnOpenMPMaskedTaskLoopSimdDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - if (getLangOpts().OpenMP >= 51) { - AllowedNameModifiers.push_back(OMPD_taskloop); - AllowedNameModifiers.push_back(OMPD_simd); - } break; case OMPD_parallel_master_taskloop: Res = ActOnOpenMPParallelMasterTaskLoopDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - AllowedNameModifiers.push_back(OMPD_taskloop); - AllowedNameModifiers.push_back(OMPD_parallel); break; case OMPD_parallel_masked_taskloop: Res = ActOnOpenMPParallelMaskedTaskLoopDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - if (getLangOpts().OpenMP >= 51) { - AllowedNameModifiers.push_back(OMPD_taskloop); - AllowedNameModifiers.push_back(OMPD_parallel); - } break; case OMPD_parallel_master_taskloop_simd: Res = ActOnOpenMPParallelMasterTaskLoopSimdDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - AllowedNameModifiers.push_back(OMPD_taskloop); - AllowedNameModifiers.push_back(OMPD_parallel); - if (getLangOpts().OpenMP >= 50) - AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_parallel_masked_taskloop_simd: Res = ActOnOpenMPParallelMaskedTaskLoopSimdDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - if (getLangOpts().OpenMP >= 51) { - AllowedNameModifiers.push_back(OMPD_taskloop); - AllowedNameModifiers.push_back(OMPD_parallel); - AllowedNameModifiers.push_back(OMPD_simd); - } break; case OMPD_distribute: Res = ActOnOpenMPDistributeDirective(ClausesWithImplicit, AStmt, StartLoc, @@ -6794,40 +6769,26 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( case OMPD_target_update: Res = ActOnOpenMPTargetUpdateDirective(ClausesWithImplicit, StartLoc, EndLoc, AStmt); - AllowedNameModifiers.push_back(OMPD_target_update); break; case OMPD_distribute_parallel_for: Res = ActOnOpenMPDistributeParallelForDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - AllowedNameModifiers.push_back(OMPD_parallel); break; case OMPD_distribute_parallel_for_simd: Res = ActOnOpenMPDistributeParallelForSimdDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - AllowedNameModifiers.push_back(OMPD_parallel); - if (getLangOpts().OpenMP >= 50) - AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_distribute_simd: Res = ActOnOpenMPDistributeSimdDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - if (getLangOpts().OpenMP >= 50) - AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_target_parallel_for_simd: Res = ActOnOpenMPTargetParallelForSimdDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - AllowedNameModifiers.push_back(OMPD_target); - AllowedNameModifiers.push_back(OMPD_parallel); - if (getLangOpts().OpenMP >= 50) - AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_target_simd: Res = ActOnOpenMPTargetSimdDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - AllowedNameModifiers.push_back(OMPD_target); - if (getLangOpts().OpenMP >= 50) - AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_teams_distribute: Res = ActOnOpenMPTeamsDistributeDirective( @@ -6836,51 +6797,34 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( case OMPD_teams_distribute_simd: Res = ActOnOpenMPTeamsDistributeSimdDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - if (getLangOpts().OpenMP >= 50) - AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_teams_distribute_parallel_for_simd: Res = ActOnOpenMPTeamsDistributeParallelForSimdDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - AllowedNameModifiers.push_back(OMPD_parallel); - if (getLangOpts().OpenMP >= 50) - AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_teams_distribute_parallel_for: Res = ActOnOpenMPTeamsDistributeParallelForDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - AllowedNameModifiers.push_back(OMPD_parallel); break; case OMPD_target_teams: Res = ActOnOpenMPTargetTeamsDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); - AllowedNameModifiers.push_back(OMPD_target); break; case OMPD_target_teams_distribute: Res = ActOnOpenMPTargetTeamsDistributeDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - AllowedNameModifiers.push_back(OMPD_target); break; case OMPD_target_teams_distribute_parallel_for: Res = ActOnOpenMPTargetTeamsDistributeParallelForDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - AllowedNameModifiers.push_back(OMPD_target); - AllowedNameModifiers.push_back(OMPD_parallel); break; case OMPD_target_teams_distribute_parallel_for_simd: Res = ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - AllowedNameModifiers.push_back(OMPD_target); - AllowedNameModifiers.push_back(OMPD_parallel); - if (getLangOpts().OpenMP >= 50) - AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_target_teams_distribute_simd: Res = ActOnOpenMPTargetTeamsDistributeSimdDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - AllowedNameModifiers.push_back(OMPD_target); - if (getLangOpts().OpenMP >= 50) - AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_interop: assert(AStmt == nullptr && @@ -6902,7 +6846,6 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( case OMPD_target_teams_loop: Res = ActOnOpenMPTargetTeamsGenericLoopDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); - AllowedNameModifiers.push_back(OMPD_target); break; case OMPD_parallel_loop: Res = ActOnOpenMPParallelGenericLoopDirective( @@ -6941,7 +6884,7 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( switch (C->getClauseKind()) { case OMPC_num_threads: case OMPC_dist_schedule: - // Do not analyse if no parent teams directive. + // Do not analyze if no parent teams directive. if (isOpenMPTeamsDirective(Kind)) break; continue; @@ -7072,6 +7015,11 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( } } + llvm::SmallVector AllowedNameModifiers; + for (OpenMPDirectiveKind D : getLeafConstructsOrSelf(Kind)) { + if (isAllowedClauseForDirective(D, OMPC_if, getLangOpts().OpenMP)) + AllowedNameModifiers.push_back(D); + } if (!AllowedNameModifiers.empty()) ErrorFound = checkIfClauses(SemaRef, Kind, Clauses, AllowedNameModifiers) || ErrorFound; @@ -7757,7 +7705,7 @@ SemaOpenMP::checkOpenMPDeclareVariantFunction(SemaOpenMP::DeclGroupPtrTy DG, FnPtrType = Context.getMemberPointerType(AdjustedFnType, ClassType); ExprResult ER; { - // Build adrr_of unary op to correctly handle type checks for member + // Build addr_of unary op to correctly handle type checks for member // functions. Sema::TentativeAnalysisScope Trap(SemaRef); ER = SemaRef.CreateBuiltinUnaryOp(VariantRef->getBeginLoc(), UO_AddrOf, @@ -7994,14 +7942,10 @@ void SemaOpenMP::ActOnOpenMPDeclareVariantDirective( FD->addAttr(NewAttr); } -StmtResult -SemaOpenMP::ActOnOpenMPParallelDirective(ArrayRef Clauses, - Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc) { - if (!AStmt) - return StmtError(); - - auto *CS = cast(AStmt); +static CapturedStmt * +setBranchProtectedScope(Sema &SemaRef, OpenMPDirectiveKind DKind, Stmt *AStmt) { + auto *CS = dyn_cast(AStmt); + assert(CS && "Captured statement expected"); // 1.2.2 OpenMP Language Terminology // Structured block - An executable statement with a single entry at the // top and a single exit at the bottom. @@ -8009,7 +7953,28 @@ SemaOpenMP::ActOnOpenMPParallelDirective(ArrayRef Clauses, // longjmp() and throw() must not violate the entry/exit criteria. CS->getCapturedDecl()->setNothrow(); + for (int ThisCaptureLevel = SemaRef.OpenMP().getOpenMPCaptureLevels(DKind); + ThisCaptureLevel > 1; --ThisCaptureLevel) { + CS = cast(CS->getCapturedStmt()); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + } SemaRef.setFunctionHasBranchProtectedScope(); + return CS; +} + +StmtResult +SemaOpenMP::ActOnOpenMPParallelDirective(ArrayRef Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc) { + if (!AStmt) + return StmtError(); + + setBranchProtectedScope(SemaRef, OMPD_parallel, AStmt); return OMPParallelDirective::Create( getASTContext(), StartLoc, EndLoc, Clauses, AStmt, @@ -8299,7 +8264,7 @@ bool OpenMPIterationSpaceChecker::setStep(Expr *NewStep, bool Subtract) { diag::err_omp_loop_incr_not_compatible) << LCDecl << *TestIsLessOp << NewStep->getSourceRange(); SemaRef.Diag(ConditionLoc, - diag::note_omp_loop_cond_requres_compatible_incr) + diag::note_omp_loop_cond_requires_compatible_incr) << *TestIsLessOp << ConditionSrcRange; return true; } @@ -9382,7 +9347,7 @@ void SemaOpenMP::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, } } DSAStack->addLoopControlVariable(D, VD); - const Decl *LD = DSAStack->getPossiblyLoopCunter(); + const Decl *LD = DSAStack->getPossiblyLoopCounter(); if (LD != D->getCanonicalDecl()) { DSAStack->resetPossibleLoopCounter(); if (auto *Var = dyn_cast_or_null(LD)) @@ -9444,7 +9409,7 @@ void SemaOpenMP::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, } namespace { -// Utility for openmp doacross clause kind +// Utility for OpenMP doacross clause kind class OMPDoacrossKind { public: bool isSource(const OMPDoacrossClause *C) { @@ -9822,7 +9787,7 @@ static Stmt *buildPreInits(ASTContext &Context, /// stored in lieu of using an explicit list. Flattening is necessary because /// contained DeclStmts need to be visible after the execution of the list. Used /// for OpenMP pre-init declarations/statements. -static void appendFlattendedStmtList(SmallVectorImpl &TargetList, +static void appendFlattenedStmtList(SmallVectorImpl &TargetList, Stmt *Item) { // nullptr represents an empty list. if (!Item) @@ -9854,7 +9819,7 @@ static Stmt *buildPreInits(ASTContext &Context, ArrayRef PreInits) { SmallVector Stmts; for (Stmt *S : PreInits) - appendFlattendedStmtList(Stmts, S); + appendFlattenedStmtList(Stmts, S); return CompoundStmt::Create(Context, PreInits, FPOptionsOverride(), {}, {}); } @@ -9958,7 +9923,7 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, // Search for pre-init declared variables that need to be captured // to be referenceable inside the directive. SmallVector Constituents; - appendFlattendedStmtList(Constituents, DependentPreInits); + appendFlattenedStmtList(Constituents, DependentPreInits); for (Stmt *S : Constituents) { if (auto *DC = dyn_cast(S)) { for (Decl *C : DC->decls()) { @@ -10678,19 +10643,8 @@ StmtResult SemaOpenMP::ActOnOpenMPSimdDirective( if (NestedLoopCount == 0) return StmtError(); - assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && - "omp simd loop exprs were not built"); - - if (!SemaRef.CurContext->isDependentContext()) { - // Finalize the clauses that need pre-built expressions for CodeGen. - for (OMPClause *C : Clauses) { - if (auto *LC = dyn_cast(C)) - if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, SemaRef, - SemaRef.getCurScope(), DSAStack)) - return StmtError(); - } - } + if (finishLinearClauses(SemaRef, Clauses, B, DSAStack)) + return StmtError(); if (checkSimdlenSafelenSpecified(SemaRef, Clauses)) return StmtError(); @@ -10721,19 +10675,8 @@ StmtResult SemaOpenMP::ActOnOpenMPForDirective( if (NestedLoopCount == 0) return StmtError(); - assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && - "omp for loop exprs were not built"); - - if (!SemaRef.CurContext->isDependentContext()) { - // Finalize the clauses that need pre-built expressions for CodeGen. - for (OMPClause *C : Clauses) { - if (auto *LC = dyn_cast(C)) - if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, SemaRef, - SemaRef.getCurScope(), DSAStack)) - return StmtError(); - } - } + if (finishLinearClauses(SemaRef, Clauses, B, DSAStack)) + return StmtError(); auto *ForDirective = OMPForDirective::Create( getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, @@ -10759,19 +10702,8 @@ StmtResult SemaOpenMP::ActOnOpenMPForSimdDirective( if (NestedLoopCount == 0) return StmtError(); - assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && - "omp for simd loop exprs were not built"); - - if (!SemaRef.CurContext->isDependentContext()) { - // Finalize the clauses that need pre-built expressions for CodeGen. - for (OMPClause *C : Clauses) { - if (auto *LC = dyn_cast(C)) - if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, SemaRef, - SemaRef.getCurScope(), DSAStack)) - return StmtError(); - } - } + if (finishLinearClauses(SemaRef, Clauses, B, DSAStack)) + return StmtError(); if (checkSimdlenSafelenSpecified(SemaRef, Clauses)) return StmtError(); @@ -10781,12 +10713,10 @@ StmtResult SemaOpenMP::ActOnOpenMPForSimdDirective( NestedLoopCount, Clauses, AStmt, B); } -StmtResult -SemaOpenMP::ActOnOpenMPSectionsDirective(ArrayRef Clauses, - Stmt *AStmt, SourceLocation StartLoc, - SourceLocation EndLoc) { +static bool checkSectionsDirective(Sema &SemaRef, OpenMPDirectiveKind DKind, + Stmt *AStmt, DSAStackTy *Stack) { if (!AStmt) - return StmtError(); + return true; assert(isa(AStmt) && "Captured statement expected"); auto BaseStmt = AStmt; @@ -10795,23 +10725,34 @@ SemaOpenMP::ActOnOpenMPSectionsDirective(ArrayRef Clauses, if (auto *C = dyn_cast_or_null(BaseStmt)) { auto S = C->children(); if (S.begin() == S.end()) - return StmtError(); + return true; // All associated statements must be '#pragma omp section' except for // the first one. for (Stmt *SectionStmt : llvm::drop_begin(S)) { if (!SectionStmt || !isa(SectionStmt)) { if (SectionStmt) - Diag(SectionStmt->getBeginLoc(), - diag::err_omp_sections_substmt_not_section); - return StmtError(); + SemaRef.Diag(SectionStmt->getBeginLoc(), + diag::err_omp_sections_substmt_not_section) + << getOpenMPDirectiveName(DKind); + return true; } cast(SectionStmt) - ->setHasCancel(DSAStack->isCancelRegion()); + ->setHasCancel(Stack->isCancelRegion()); } } else { - Diag(AStmt->getBeginLoc(), diag::err_omp_sections_not_compound_stmt); - return StmtError(); + SemaRef.Diag(AStmt->getBeginLoc(), diag::err_omp_sections_not_compound_stmt) + << getOpenMPDirectiveName(DKind); + return true; } + return false; +} + +StmtResult +SemaOpenMP::ActOnOpenMPSectionsDirective(ArrayRef Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc) { + if (checkSectionsDirective(SemaRef, OMPD_sections, AStmt, DSAStack)) + return StmtError(); SemaRef.setFunctionHasBranchProtectedScope(); @@ -10928,13 +10869,7 @@ StmtResult SemaOpenMP::ActOnOpenMPGenericLoopDirective( if (checkGenericLoopLastprivate(SemaRef, Clauses, OMPD_loop, DSAStack)) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); + setBranchProtectedScope(SemaRef, OMPD_loop, AStmt); OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse', it will define the nested loops number. @@ -10947,7 +10882,6 @@ StmtResult SemaOpenMP::ActOnOpenMPGenericLoopDirective( assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && "omp loop exprs were not built"); - SemaRef.setFunctionHasBranchProtectedScope(); return OMPGenericLoopDirective::Create(getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } @@ -10964,23 +10898,7 @@ StmtResult SemaOpenMP::ActOnOpenMPTeamsGenericLoopDirective( if (checkGenericLoopLastprivate(SemaRef, Clauses, OMPD_teams_loop, DSAStack)) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_teams_loop); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + CapturedStmt *CS = setBranchProtectedScope(SemaRef, OMPD_teams_loop, AStmt); OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse', it will define the nested loops number. @@ -10994,7 +10912,6 @@ StmtResult SemaOpenMP::ActOnOpenMPTeamsGenericLoopDirective( assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && "omp loop exprs were not built"); - SemaRef.setFunctionHasBranchProtectedScope(); DSAStack->setParentTeamsRegionLoc(StartLoc); return OMPTeamsGenericLoopDirective::Create( @@ -11014,23 +10931,8 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsGenericLoopDirective( DSAStack)) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_teams_loop); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + CapturedStmt *CS = + setBranchProtectedScope(SemaRef, OMPD_target_teams_loop, AStmt); OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse', it will define the nested loops number. @@ -11044,8 +10946,6 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsGenericLoopDirective( assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && "omp loop exprs were not built"); - SemaRef.setFunctionHasBranchProtectedScope(); - return OMPTargetTeamsGenericLoopDirective::Create( getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, teamsLoopCanBeParallelFor(AStmt, SemaRef)); @@ -11064,23 +10964,8 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelGenericLoopDirective( DSAStack)) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_parallel_loop); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + CapturedStmt *CS = + setBranchProtectedScope(SemaRef, OMPD_parallel_loop, AStmt); OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse', it will define the nested loops number. @@ -11094,8 +10979,6 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelGenericLoopDirective( assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && "omp loop exprs were not built"); - SemaRef.setFunctionHasBranchProtectedScope(); - return OMPParallelGenericLoopDirective::Create( getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } @@ -11113,23 +10996,8 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetParallelGenericLoopDirective( DSAStack)) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_parallel_loop); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + CapturedStmt *CS = + setBranchProtectedScope(SemaRef, OMPD_target_parallel_loop, AStmt); OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse', it will define the nested loops number. @@ -11143,8 +11011,6 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetParallelGenericLoopDirective( assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && "omp loop exprs were not built"); - SemaRef.setFunctionHasBranchProtectedScope(); - return OMPTargetParallelGenericLoopDirective::Create( getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } @@ -11268,13 +11134,7 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelForDirective( if (!AStmt) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); + setBranchProtectedScope(SemaRef, OMPD_parallel_for, AStmt); OMPLoopBasedDirective::HelperExprs B; // In presence of clause 'collapse' or 'ordered' with number of loops, it will @@ -11286,21 +11146,9 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelForDirective( if (NestedLoopCount == 0) return StmtError(); - assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && - "omp parallel for loop exprs were not built"); - - if (!SemaRef.CurContext->isDependentContext()) { - // Finalize the clauses that need pre-built expressions for CodeGen. - for (OMPClause *C : Clauses) { - if (auto *LC = dyn_cast(C)) - if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, SemaRef, - SemaRef.getCurScope(), DSAStack)) - return StmtError(); - } - } + if (finishLinearClauses(SemaRef, Clauses, B, DSAStack)) + return StmtError(); - SemaRef.setFunctionHasBranchProtectedScope(); return OMPParallelForDirective::Create( getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); @@ -11312,13 +11160,7 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelForSimdDirective( if (!AStmt) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); + setBranchProtectedScope(SemaRef, OMPD_parallel_for_simd, AStmt); OMPLoopBasedDirective::HelperExprs B; // In presence of clause 'collapse' or 'ordered' with number of loops, it will @@ -11330,21 +11172,12 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelForSimdDirective( if (NestedLoopCount == 0) return StmtError(); - if (!SemaRef.CurContext->isDependentContext()) { - // Finalize the clauses that need pre-built expressions for CodeGen. - for (OMPClause *C : Clauses) { - if (auto *LC = dyn_cast(C)) - if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, SemaRef, - SemaRef.getCurScope(), DSAStack)) - return StmtError(); - } - } + if (finishLinearClauses(SemaRef, Clauses, B, DSAStack)) + return StmtError(); if (checkSimdlenSafelenSpecified(SemaRef, Clauses)) return StmtError(); - SemaRef.setFunctionHasBranchProtectedScope(); return OMPParallelForSimdDirective::Create( getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } @@ -11355,16 +11188,7 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelMasterDirective( if (!AStmt) return StmtError(); - assert(isa(AStmt) && "Captured statement expected"); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - - SemaRef.setFunctionHasBranchProtectedScope(); + setBranchProtectedScope(SemaRef, OMPD_parallel_master, AStmt); return OMPParallelMasterDirective::Create( getASTContext(), StartLoc, EndLoc, Clauses, AStmt, @@ -11377,16 +11201,7 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelMaskedDirective( if (!AStmt) return StmtError(); - assert(isa(AStmt) && "Captured statement expected"); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - - SemaRef.setFunctionHasBranchProtectedScope(); + setBranchProtectedScope(SemaRef, OMPD_parallel_masked, AStmt); return OMPParallelMaskedDirective::Create( getASTContext(), StartLoc, EndLoc, Clauses, AStmt, @@ -11396,34 +11211,8 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelMaskedDirective( StmtResult SemaOpenMP::ActOnOpenMPParallelSectionsDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { - if (!AStmt) - return StmtError(); - - assert(isa(AStmt) && "Captured statement expected"); - auto BaseStmt = AStmt; - while (auto *CS = dyn_cast_or_null(BaseStmt)) - BaseStmt = CS->getCapturedStmt(); - if (auto *C = dyn_cast_or_null(BaseStmt)) { - auto S = C->children(); - if (S.begin() == S.end()) - return StmtError(); - // All associated statements must be '#pragma omp section' except for - // the first one. - for (Stmt *SectionStmt : llvm::drop_begin(S)) { - if (!SectionStmt || !isa(SectionStmt)) { - if (SectionStmt) - Diag(SectionStmt->getBeginLoc(), - diag::err_omp_parallel_sections_substmt_not_section); - return StmtError(); - } - cast(SectionStmt) - ->setHasCancel(DSAStack->isCancelRegion()); - } - } else { - Diag(AStmt->getBeginLoc(), - diag::err_omp_parallel_sections_not_compound_stmt); + if (checkSectionsDirective(SemaRef, OMPD_parallel_sections, AStmt, DSAStack)) return StmtError(); - } SemaRef.setFunctionHasBranchProtectedScope(); @@ -11469,15 +11258,7 @@ StmtResult SemaOpenMP::ActOnOpenMPTaskDirective(ArrayRef Clauses, {OMPC_detach, OMPC_mergeable})) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - - SemaRef.setFunctionHasBranchProtectedScope(); + setBranchProtectedScope(SemaRef, OMPD_task, AStmt); return OMPTaskDirective::Create(getASTContext(), StartLoc, EndLoc, Clauses, AStmt, DSAStack->isCancelRegion()); @@ -11628,7 +11409,7 @@ StmtResult SemaOpenMP::ActOnOpenMPScanDirective(ArrayRef Clauses, diag::err_omp_scan_single_clause_expected); return StmtError(); } - // Check that scan directive is used in the scopeof the OpenMP loop body. + // Check that scan directive is used in the scope of the OpenMP loop body. if (Scope *S = DSAStack->getCurScope()) { Scope *ParentS = S->getParent(); if (!ParentS || ParentS->getParent() != ParentS->getBreakParent() || @@ -11783,7 +11564,7 @@ class OpenMPAtomicUpdateChecker { NotAnAssignmentOp, /// RHS part of the binary operation is not a binary expression. NotABinaryExpression, - /// RHS part is not additive/multiplicative/shift/biwise binary + /// RHS part is not additive/multiplicative/shift/bitwise binary /// expression. NotABinaryOperator, /// RHS binary operation does not have reference to the updated LHS @@ -12061,7 +11842,7 @@ class OpenMPAtomicCompareChecker { InvalidAssignment, /// Not if statement NotIfStmt, - /// More than two statements in a compund statement. + /// More than two statements in a compound statement. MoreThanTwoStmts, /// Not a compound statement. NotCompoundStmt, @@ -12148,7 +11929,7 @@ class OpenMPAtomicCompareChecker { return true; } - }; +}; bool OpenMPAtomicCompareChecker::checkCondUpdateStmt(IfStmt *S, ErrorInfoTy &ErrorInfo) { @@ -13357,7 +13138,7 @@ StmtResult SemaOpenMP::ActOnOpenMPAtomicDirective(ArrayRef Clauses, Diag(ErrorInfo.ErrorLoc, diag::err_omp_atomic_compare) << ErrorInfo.ErrorRange; Diag(ErrorInfo.NoteLoc, diag::note_omp_atomic_compare) - << ErrorInfo.Error << ErrorInfo.NoteRange; + << ErrorInfo.Error << ErrorInfo.NoteRange; return StmtError(); } X = Checker.getX(); @@ -13404,23 +13185,7 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetDirective(ArrayRef Clauses, if (!AStmt) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + CapturedStmt *CS = setBranchProtectedScope(SemaRef, OMPD_target, AStmt); // OpenMP [2.16, Nesting of Regions] // If specified, a teams construct must be contained within a target @@ -13433,10 +13198,14 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetDirective(ArrayRef Clauses, auto I = CS->body_begin(); while (I != CS->body_end()) { const auto *OED = dyn_cast(*I); - if (!OED || !isOpenMPTeamsDirective(OED->getDirectiveKind()) || - OMPTeamsFound) { - + bool IsTeams = OED && isOpenMPTeamsDirective(OED->getDirectiveKind()); + if (!IsTeams || I != CS->body_begin()) { OMPTeamsFound = false; + if (IsTeams && I != CS->body_begin()) { + // This is the two teams case. Since the InnerTeamsRegionLoc will + // point to this second one reset the iterator to the other teams. + --I; + } break; } ++I; @@ -13457,8 +13226,6 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetDirective(ArrayRef Clauses, } } - SemaRef.setFunctionHasBranchProtectedScope(); - return OMPTargetDirective::Create(getASTContext(), StartLoc, EndLoc, Clauses, AStmt); } @@ -13469,25 +13236,7 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetParallelDirective( if (!AStmt) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_parallel); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } - - SemaRef.setFunctionHasBranchProtectedScope(); + setBranchProtectedScope(SemaRef, OMPD_target_parallel, AStmt); return OMPTargetParallelDirective::Create( getASTContext(), StartLoc, EndLoc, Clauses, AStmt, @@ -13500,23 +13249,8 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetParallelForDirective( if (!AStmt) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_parallel_for); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + CapturedStmt *CS = + setBranchProtectedScope(SemaRef, OMPD_target_parallel_for, AStmt); OMPLoopBasedDirective::HelperExprs B; // In presence of clause 'collapse' or 'ordered' with number of loops, it will @@ -13528,21 +13262,9 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetParallelForDirective( if (NestedLoopCount == 0) return StmtError(); - assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && - "omp target parallel for loop exprs were not built"); - - if (!SemaRef.CurContext->isDependentContext()) { - // Finalize the clauses that need pre-built expressions for CodeGen. - for (OMPClause *C : Clauses) { - if (auto *LC = dyn_cast(C)) - if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, SemaRef, - SemaRef.getCurScope(), DSAStack)) - return StmtError(); - } - } + if (finishLinearClauses(SemaRef, Clauses, B, DSAStack)) + return StmtError(); - SemaRef.setFunctionHasBranchProtectedScope(); return OMPTargetParallelForDirective::Create( getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); @@ -13618,23 +13340,7 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetEnterDataDirective( if (!AStmt) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_enter_data); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + setBranchProtectedScope(SemaRef, OMPD_target_enter_data, AStmt); // OpenMP [2.10.2, Restrictions, p. 99] // At least one map clause must appear on the directive. @@ -13654,23 +13360,7 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetExitDataDirective( if (!AStmt) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_exit_data); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + setBranchProtectedScope(SemaRef, OMPD_target_exit_data, AStmt); // OpenMP [2.10.3, Restrictions, p. 102] // At least one map clause must appear on the directive. @@ -13690,23 +13380,7 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetUpdateDirective( if (!AStmt) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_update); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + setBranchProtectedScope(SemaRef, OMPD_target_update, AStmt); if (!hasClauses(Clauses, OMPC_to, OMPC_from)) { Diag(StartLoc, diag::err_omp_at_least_one_motion_clause_required); @@ -13733,15 +13407,7 @@ StmtResult SemaOpenMP::ActOnOpenMPTeamsDirective(ArrayRef Clauses, if (getLangOpts().HIP && (DSAStack->getParentDirective() == OMPD_target)) Diag(StartLoc, diag::warn_hip_omp_target_directives); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - - SemaRef.setFunctionHasBranchProtectedScope(); + setBranchProtectedScope(SemaRef, OMPD_teams, AStmt); DSAStack->setParentTeamsRegionLoc(StartLoc); @@ -13862,19 +13528,8 @@ StmtResult SemaOpenMP::ActOnOpenMPTaskLoopSimdDirective( if (NestedLoopCount == 0) return StmtError(); - assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && - "omp for loop exprs were not built"); - - if (!SemaRef.CurContext->isDependentContext()) { - // Finalize the clauses that need pre-built expressions for CodeGen. - for (OMPClause *C : Clauses) { - if (auto *LC = dyn_cast(C)) - if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, SemaRef, - SemaRef.getCurScope(), DSAStack)) - return StmtError(); - } - } + if (finishLinearClauses(SemaRef, Clauses, B, DSAStack)) + return StmtError(); // OpenMP, [2.9.2 taskloop Construct, Restrictions] // The grainsize clause and num_tasks clause are mutually exclusive and may @@ -13988,19 +13643,8 @@ StmtResult SemaOpenMP::ActOnOpenMPMasterTaskLoopSimdDirective( if (NestedLoopCount == 0) return StmtError(); - assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && - "omp for loop exprs were not built"); - - if (!SemaRef.CurContext->isDependentContext()) { - // Finalize the clauses that need pre-built expressions for CodeGen. - for (OMPClause *C : Clauses) { - if (auto *LC = dyn_cast(C)) - if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, SemaRef, - SemaRef.getCurScope(), DSAStack)) - return StmtError(); - } - } + if (finishLinearClauses(SemaRef, Clauses, B, DSAStack)) + return StmtError(); // OpenMP, [2.9.2 taskloop Construct, Restrictions] // The grainsize clause and num_tasks clause are mutually exclusive and may @@ -14038,19 +13682,8 @@ StmtResult SemaOpenMP::ActOnOpenMPMaskedTaskLoopSimdDirective( if (NestedLoopCount == 0) return StmtError(); - assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && - "omp for loop exprs were not built"); - - if (!SemaRef.CurContext->isDependentContext()) { - // Finalize the clauses that need pre-built expressions for CodeGen. - for (OMPClause *C : Clauses) { - if (auto *LC = dyn_cast(C)) - if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, SemaRef, - SemaRef.getCurScope(), DSAStack)) - return StmtError(); - } - } + if (finishLinearClauses(SemaRef, Clauses, B, DSAStack)) + return StmtError(); // OpenMP, [2.9.2 taskloop Construct, Restrictions] // The grainsize clause and num_tasks clause are mutually exclusive and may @@ -14077,25 +13710,8 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelMasterTaskLoopDirective( if (!AStmt) return StmtError(); - assert(isa(AStmt) && "Captured statement expected"); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = - getOpenMPCaptureLevels(OMPD_parallel_master_taskloop); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + CapturedStmt *CS = + setBranchProtectedScope(SemaRef, OMPD_parallel_master_taskloop, AStmt); OMPLoopBasedDirective::HelperExprs B; // In presence of clause 'collapse' or 'ordered' with number of loops, it will @@ -14122,7 +13738,6 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelMasterTaskLoopDirective( if (checkReductionClauseWithNogroup(SemaRef, Clauses)) return StmtError(); - SemaRef.setFunctionHasBranchProtectedScope(); return OMPParallelMasterTaskLoopDirective::Create( getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, DSAStack->isCancelRegion()); @@ -14134,25 +13749,8 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelMaskedTaskLoopDirective( if (!AStmt) return StmtError(); - assert(isa(AStmt) && "Captured statement expected"); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = - getOpenMPCaptureLevels(OMPD_parallel_masked_taskloop); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + CapturedStmt *CS = + setBranchProtectedScope(SemaRef, OMPD_parallel_masked_taskloop, AStmt); OMPLoopBasedDirective::HelperExprs B; // In presence of clause 'collapse' or 'ordered' with number of loops, it will @@ -14179,7 +13777,6 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelMaskedTaskLoopDirective( if (checkReductionClauseWithNogroup(SemaRef, Clauses)) return StmtError(); - SemaRef.setFunctionHasBranchProtectedScope(); return OMPParallelMaskedTaskLoopDirective::Create( getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, DSAStack->isCancelRegion()); @@ -14191,25 +13788,8 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelMasterTaskLoopSimdDirective( if (!AStmt) return StmtError(); - assert(isa(AStmt) && "Captured statement expected"); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = - getOpenMPCaptureLevels(OMPD_parallel_master_taskloop_simd); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + CapturedStmt *CS = setBranchProtectedScope( + SemaRef, OMPD_parallel_master_taskloop_simd, AStmt); OMPLoopBasedDirective::HelperExprs B; // In presence of clause 'collapse' or 'ordered' with number of loops, it will @@ -14221,19 +13801,8 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelMasterTaskLoopSimdDirective( if (NestedLoopCount == 0) return StmtError(); - assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && - "omp for loop exprs were not built"); - - if (!SemaRef.CurContext->isDependentContext()) { - // Finalize the clauses that need pre-built expressions for CodeGen. - for (OMPClause *C : Clauses) { - if (auto *LC = dyn_cast(C)) - if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, SemaRef, - SemaRef.getCurScope(), DSAStack)) - return StmtError(); - } - } + if (finishLinearClauses(SemaRef, Clauses, B, DSAStack)) + return StmtError(); // OpenMP, [2.9.2 taskloop Construct, Restrictions] // The grainsize clause and num_tasks clause are mutually exclusive and may @@ -14249,7 +13818,6 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelMasterTaskLoopSimdDirective( if (checkSimdlenSafelenSpecified(SemaRef, Clauses)) return StmtError(); - SemaRef.setFunctionHasBranchProtectedScope(); return OMPParallelMasterTaskLoopSimdDirective::Create( getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } @@ -14260,25 +13828,8 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelMaskedTaskLoopSimdDirective( if (!AStmt) return StmtError(); - assert(isa(AStmt) && "Captured statement expected"); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = - getOpenMPCaptureLevels(OMPD_parallel_masked_taskloop_simd); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + CapturedStmt *CS = setBranchProtectedScope( + SemaRef, OMPD_parallel_masked_taskloop_simd, AStmt); OMPLoopBasedDirective::HelperExprs B; // In presence of clause 'collapse' or 'ordered' with number of loops, it will @@ -14290,19 +13841,8 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelMaskedTaskLoopSimdDirective( if (NestedLoopCount == 0) return StmtError(); - assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && - "omp for loop exprs were not built"); - - if (!SemaRef.CurContext->isDependentContext()) { - // Finalize the clauses that need pre-built expressions for CodeGen. - for (OMPClause *C : Clauses) { - if (auto *LC = dyn_cast(C)) - if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, SemaRef, - SemaRef.getCurScope(), DSAStack)) - return StmtError(); - } - } + if (finishLinearClauses(SemaRef, Clauses, B, DSAStack)) + return StmtError(); // OpenMP, [2.9.2 taskloop Construct, Restrictions] // The grainsize clause and num_tasks clause are mutually exclusive and may @@ -14318,7 +13858,6 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelMaskedTaskLoopSimdDirective( if (checkSimdlenSafelenSpecified(SemaRef, Clauses)) return StmtError(); - SemaRef.setFunctionHasBranchProtectedScope(); return OMPParallelMaskedTaskLoopSimdDirective::Create( getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } @@ -14359,24 +13898,8 @@ StmtResult SemaOpenMP::ActOnOpenMPDistributeParallelForDirective( if (!AStmt) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = - getOpenMPCaptureLevels(OMPD_distribute_parallel_for); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + CapturedStmt *CS = + setBranchProtectedScope(SemaRef, OMPD_distribute_parallel_for, AStmt); OMPLoopBasedDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will @@ -14391,7 +13914,6 @@ StmtResult SemaOpenMP::ActOnOpenMPDistributeParallelForDirective( assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && "omp for loop exprs were not built"); - SemaRef.setFunctionHasBranchProtectedScope(); return OMPDistributeParallelForDirective::Create( getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); @@ -14403,24 +13925,8 @@ StmtResult SemaOpenMP::ActOnOpenMPDistributeParallelForSimdDirective( if (!AStmt) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = - getOpenMPCaptureLevels(OMPD_distribute_parallel_for_simd); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + CapturedStmt *CS = setBranchProtectedScope( + SemaRef, OMPD_distribute_parallel_for_simd, AStmt); OMPLoopBasedDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will @@ -14432,24 +13938,12 @@ StmtResult SemaOpenMP::ActOnOpenMPDistributeParallelForSimdDirective( if (NestedLoopCount == 0) return StmtError(); - assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && - "omp for loop exprs were not built"); - - if (!SemaRef.CurContext->isDependentContext()) { - // Finalize the clauses that need pre-built expressions for CodeGen. - for (OMPClause *C : Clauses) { - if (auto *LC = dyn_cast(C)) - if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, SemaRef, - SemaRef.getCurScope(), DSAStack)) - return StmtError(); - } - } + if (finishLinearClauses(SemaRef, Clauses, B, DSAStack)) + return StmtError(); if (checkSimdlenSafelenSpecified(SemaRef, Clauses)) return StmtError(); - SemaRef.setFunctionHasBranchProtectedScope(); return OMPDistributeParallelForSimdDirective::Create( getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } @@ -14457,26 +13951,11 @@ StmtResult SemaOpenMP::ActOnOpenMPDistributeParallelForSimdDirective( StmtResult SemaOpenMP::ActOnOpenMPDistributeSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { - if (!AStmt) - return StmtError(); - - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_distribute_simd); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + if (!AStmt) + return StmtError(); + + CapturedStmt *CS = + setBranchProtectedScope(SemaRef, OMPD_distribute_simd, AStmt); OMPLoopBasedDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will @@ -14488,24 +13967,12 @@ StmtResult SemaOpenMP::ActOnOpenMPDistributeSimdDirective( if (NestedLoopCount == 0) return StmtError(); - assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && - "omp for loop exprs were not built"); - - if (!SemaRef.CurContext->isDependentContext()) { - // Finalize the clauses that need pre-built expressions for CodeGen. - for (OMPClause *C : Clauses) { - if (auto *LC = dyn_cast(C)) - if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, SemaRef, - SemaRef.getCurScope(), DSAStack)) - return StmtError(); - } - } + if (finishLinearClauses(SemaRef, Clauses, B, DSAStack)) + return StmtError(); if (checkSimdlenSafelenSpecified(SemaRef, Clauses)) return StmtError(); - SemaRef.setFunctionHasBranchProtectedScope(); return OMPDistributeSimdDirective::Create(getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } @@ -14516,24 +13983,8 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetParallelForSimdDirective( if (!AStmt) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = - getOpenMPCaptureLevels(OMPD_target_parallel_for_simd); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + CapturedStmt *CS = + setBranchProtectedScope(SemaRef, OMPD_target_parallel_for_simd, AStmt); OMPLoopBasedDirective::HelperExprs B; // In presence of clause 'collapse' or 'ordered' with number of loops, it will @@ -14545,23 +13996,12 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetParallelForSimdDirective( if (NestedLoopCount == 0) return StmtError(); - assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && - "omp target parallel for simd loop exprs were not built"); + if (finishLinearClauses(SemaRef, Clauses, B, DSAStack)) + return StmtError(); - if (!SemaRef.CurContext->isDependentContext()) { - // Finalize the clauses that need pre-built expressions for CodeGen. - for (OMPClause *C : Clauses) { - if (auto *LC = dyn_cast(C)) - if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, SemaRef, - SemaRef.getCurScope(), DSAStack)) - return StmtError(); - } - } if (checkSimdlenSafelenSpecified(SemaRef, Clauses)) return StmtError(); - SemaRef.setFunctionHasBranchProtectedScope(); return OMPTargetParallelForSimdDirective::Create( getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } @@ -14572,23 +14012,7 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetSimdDirective( if (!AStmt) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_simd); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + CapturedStmt *CS = setBranchProtectedScope(SemaRef, OMPD_target_simd, AStmt); OMPLoopBasedDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will define the @@ -14600,24 +14024,12 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetSimdDirective( if (NestedLoopCount == 0) return StmtError(); - assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && - "omp target simd loop exprs were not built"); - - if (!SemaRef.CurContext->isDependentContext()) { - // Finalize the clauses that need pre-built expressions for CodeGen. - for (OMPClause *C : Clauses) { - if (auto *LC = dyn_cast(C)) - if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, SemaRef, - SemaRef.getCurScope(), DSAStack)) - return StmtError(); - } - } + if (finishLinearClauses(SemaRef, Clauses, B, DSAStack)) + return StmtError(); if (checkSimdlenSafelenSpecified(SemaRef, Clauses)) return StmtError(); - SemaRef.setFunctionHasBranchProtectedScope(); return OMPTargetSimdDirective::Create(getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } @@ -14628,23 +14040,8 @@ StmtResult SemaOpenMP::ActOnOpenMPTeamsDistributeDirective( if (!AStmt) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_teams_distribute); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + CapturedStmt *CS = + setBranchProtectedScope(SemaRef, OMPD_teams_distribute, AStmt); OMPLoopBasedDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will @@ -14659,8 +14056,6 @@ StmtResult SemaOpenMP::ActOnOpenMPTeamsDistributeDirective( assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && "omp teams distribute loop exprs were not built"); - SemaRef.setFunctionHasBranchProtectedScope(); - DSAStack->setParentTeamsRegionLoc(StartLoc); return OMPTeamsDistributeDirective::Create( @@ -14673,24 +14068,8 @@ StmtResult SemaOpenMP::ActOnOpenMPTeamsDistributeSimdDirective( if (!AStmt) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = - getOpenMPCaptureLevels(OMPD_teams_distribute_simd); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + CapturedStmt *CS = + setBranchProtectedScope(SemaRef, OMPD_teams_distribute_simd, AStmt); OMPLoopBasedDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will @@ -14699,29 +14078,15 @@ StmtResult SemaOpenMP::ActOnOpenMPTeamsDistributeSimdDirective( OMPD_teams_distribute_simd, getCollapseNumberExpr(Clauses), nullptr /*ordered not a clause on distribute*/, CS, SemaRef, *DSAStack, VarsWithImplicitDSA, B); - if (NestedLoopCount == 0) return StmtError(); - assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && - "omp teams distribute simd loop exprs were not built"); - - if (!SemaRef.CurContext->isDependentContext()) { - // Finalize the clauses that need pre-built expressions for CodeGen. - for (OMPClause *C : Clauses) { - if (auto *LC = dyn_cast(C)) - if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, SemaRef, - SemaRef.getCurScope(), DSAStack)) - return StmtError(); - } - } + if (finishLinearClauses(SemaRef, Clauses, B, DSAStack)) + return StmtError(); if (checkSimdlenSafelenSpecified(SemaRef, Clauses)) return StmtError(); - SemaRef.setFunctionHasBranchProtectedScope(); - DSAStack->setParentTeamsRegionLoc(StartLoc); return OMPTeamsDistributeSimdDirective::Create( @@ -14734,25 +14099,8 @@ StmtResult SemaOpenMP::ActOnOpenMPTeamsDistributeParallelForSimdDirective( if (!AStmt) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - - for (int ThisCaptureLevel = - getOpenMPCaptureLevels(OMPD_teams_distribute_parallel_for_simd); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + CapturedStmt *CS = setBranchProtectedScope( + SemaRef, OMPD_teams_distribute_parallel_for_simd, AStmt); OMPLoopBasedDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will @@ -14761,29 +14109,15 @@ StmtResult SemaOpenMP::ActOnOpenMPTeamsDistributeParallelForSimdDirective( OMPD_teams_distribute_parallel_for_simd, getCollapseNumberExpr(Clauses), nullptr /*ordered not a clause on distribute*/, CS, SemaRef, *DSAStack, VarsWithImplicitDSA, B); - if (NestedLoopCount == 0) return StmtError(); - assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && - "omp for loop exprs were not built"); - - if (!SemaRef.CurContext->isDependentContext()) { - // Finalize the clauses that need pre-built expressions for CodeGen. - for (OMPClause *C : Clauses) { - if (auto *LC = dyn_cast(C)) - if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, SemaRef, - SemaRef.getCurScope(), DSAStack)) - return StmtError(); - } - } + if (finishLinearClauses(SemaRef, Clauses, B, DSAStack)) + return StmtError(); if (checkSimdlenSafelenSpecified(SemaRef, Clauses)) return StmtError(); - SemaRef.setFunctionHasBranchProtectedScope(); - DSAStack->setParentTeamsRegionLoc(StartLoc); return OMPTeamsDistributeParallelForSimdDirective::Create( @@ -14796,25 +14130,8 @@ StmtResult SemaOpenMP::ActOnOpenMPTeamsDistributeParallelForDirective( if (!AStmt) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - - for (int ThisCaptureLevel = - getOpenMPCaptureLevels(OMPD_teams_distribute_parallel_for); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + CapturedStmt *CS = setBranchProtectedScope( + SemaRef, OMPD_teams_distribute_parallel_for, AStmt); OMPLoopBasedDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will @@ -14830,8 +14147,6 @@ StmtResult SemaOpenMP::ActOnOpenMPTeamsDistributeParallelForDirective( assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && "omp for loop exprs were not built"); - SemaRef.setFunctionHasBranchProtectedScope(); - DSAStack->setParentTeamsRegionLoc(StartLoc); return OMPTeamsDistributeParallelForDirective::Create( @@ -14845,25 +14160,7 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDirective( if (!AStmt) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - - for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_teams); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } - SemaRef.setFunctionHasBranchProtectedScope(); + setBranchProtectedScope(SemaRef, OMPD_target_teams, AStmt); const OMPClause *BareClause = nullptr; bool HasThreadLimitAndNumTeamsClause = hasClauses(Clauses, OMPC_num_teams) && @@ -14888,24 +14185,8 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeDirective( if (!AStmt) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = - getOpenMPCaptureLevels(OMPD_target_teams_distribute); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + CapturedStmt *CS = + setBranchProtectedScope(SemaRef, OMPD_target_teams_distribute, AStmt); OMPLoopBasedDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will @@ -14920,7 +14201,6 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeDirective( assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && "omp target teams distribute loop exprs were not built"); - SemaRef.setFunctionHasBranchProtectedScope(); return OMPTargetTeamsDistributeDirective::Create( getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } @@ -14931,24 +14211,8 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeParallelForDirective( if (!AStmt) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = - getOpenMPCaptureLevels(OMPD_target_teams_distribute_parallel_for); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + CapturedStmt *CS = setBranchProtectedScope( + SemaRef, OMPD_target_teams_distribute_parallel_for, AStmt); OMPLoopBasedDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will @@ -14960,21 +14224,9 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeParallelForDirective( if (NestedLoopCount == 0) return StmtError(); - assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && - "omp target teams distribute parallel for loop exprs were not built"); - - if (!SemaRef.CurContext->isDependentContext()) { - // Finalize the clauses that need pre-built expressions for CodeGen. - for (OMPClause *C : Clauses) { - if (auto *LC = dyn_cast(C)) - if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, SemaRef, - SemaRef.getCurScope(), DSAStack)) - return StmtError(); - } - } + if (finishLinearClauses(SemaRef, Clauses, B, DSAStack)) + return StmtError(); - SemaRef.setFunctionHasBranchProtectedScope(); return OMPTargetTeamsDistributeParallelForDirective::Create( getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); @@ -14986,24 +14238,8 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective( if (!AStmt) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = getOpenMPCaptureLevels( - OMPD_target_teams_distribute_parallel_for_simd); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + CapturedStmt *CS = setBranchProtectedScope( + SemaRef, OMPD_target_teams_distribute_parallel_for_simd, AStmt); OMPLoopBasedDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will @@ -15016,25 +14252,12 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective( if (NestedLoopCount == 0) return StmtError(); - assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && - "omp target teams distribute parallel for simd loop exprs were not " - "built"); - - if (!SemaRef.CurContext->isDependentContext()) { - // Finalize the clauses that need pre-built expressions for CodeGen. - for (OMPClause *C : Clauses) { - if (auto *LC = dyn_cast(C)) - if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, SemaRef, - SemaRef.getCurScope(), DSAStack)) - return StmtError(); - } - } + if (finishLinearClauses(SemaRef, Clauses, B, DSAStack)) + return StmtError(); if (checkSimdlenSafelenSpecified(SemaRef, Clauses)) return StmtError(); - SemaRef.setFunctionHasBranchProtectedScope(); return OMPTargetTeamsDistributeParallelForSimdDirective::Create( getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } @@ -15045,24 +14268,8 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeSimdDirective( if (!AStmt) return StmtError(); - auto *CS = cast(AStmt); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - for (int ThisCaptureLevel = - getOpenMPCaptureLevels(OMPD_target_teams_distribute_simd); - ThisCaptureLevel > 1; --ThisCaptureLevel) { - CS = cast(CS->getCapturedStmt()); - // 1.2.2 OpenMP Language Terminology - // Structured block - An executable statement with a single entry at the - // top and a single exit at the bottom. - // The point of exit cannot be a branch out of the structured block. - // longjmp() and throw() must not violate the entry/exit criteria. - CS->getCapturedDecl()->setNothrow(); - } + CapturedStmt *CS = setBranchProtectedScope( + SemaRef, OMPD_target_teams_distribute_simd, AStmt); OMPLoopBasedDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will @@ -15074,24 +14281,12 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeSimdDirective( if (NestedLoopCount == 0) return StmtError(); - assert((SemaRef.CurContext->isDependentContext() || B.builtAll()) && - "omp target teams distribute simd loop exprs were not built"); - - if (!SemaRef.CurContext->isDependentContext()) { - // Finalize the clauses that need pre-built expressions for CodeGen. - for (OMPClause *C : Clauses) { - if (auto *LC = dyn_cast(C)) - if (FinishOpenMPLinearClause(*LC, cast(B.IterationVarRef), - B.NumIterations, SemaRef, - SemaRef.getCurScope(), DSAStack)) - return StmtError(); - } - } + if (finishLinearClauses(SemaRef, Clauses, B, DSAStack)) + return StmtError(); if (checkSimdlenSafelenSpecified(SemaRef, Clauses)) return StmtError(); - SemaRef.setFunctionHasBranchProtectedScope(); return OMPTargetTeamsDistributeSimdDirective::Create( getASTContext(), StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } @@ -15134,7 +14329,7 @@ bool SemaOpenMP::checkTransformableLoopNest( else llvm_unreachable("Unhandled loop transformation"); - appendFlattendedStmtList(OriginalInits.back(), DependentPreInits); + appendFlattenedStmtList(OriginalInits.back(), DependentPreInits); }); assert(OriginalInits.back().empty() && "No preinit after innermost loop"); OriginalInits.pop_back(); @@ -17238,9 +16433,8 @@ OMPClause *SemaOpenMP::ActOnOpenMPSimpleClause( ArgumentLoc, StartLoc, LParenLoc, EndLoc); break; case OMPC_fail: - Res = ActOnOpenMPFailClause( - static_cast(Argument), - ArgumentLoc, StartLoc, LParenLoc, EndLoc); + Res = ActOnOpenMPFailClause(static_cast(Argument), + ArgumentLoc, StartLoc, LParenLoc, EndLoc); break; case OMPC_update: Res = ActOnOpenMPUpdateClause(static_cast(Argument), @@ -23895,8 +23089,7 @@ void SemaOpenMP::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, /// This class visits every VarDecl that the initializer references and adds /// OMPDeclareTargetDeclAttr to each of them. -class GlobalDeclRefChecker final - : public StmtVisitor { +class GlobalDeclRefChecker final : public StmtVisitor { SmallVector DeclVector; Attr *A; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index fb4ff72e42eb53..f8f55ce6526acd 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -1877,6 +1877,27 @@ bool Sema::IsFunctionConversion(QualType FromType, QualType ToType, FromFn = QT->getAs(); Changed = true; } + + // For C, when called from checkPointerTypesForAssignment, + // we need to not alter FromFn, or else even an innocuous cast + // like dropping effects will fail. In C++ however we do want to + // alter FromFn (because of the way PerformImplicitConversion works). + if (getLangOpts().CPlusPlus) { + FromFPT = cast(FromFn); // in case FromFn changed above + + // Transparently add/drop effects; here we are concerned with + // language rules/canonicalization. Adding/dropping effects is a warning. + const auto FromFX = FromFPT->getFunctionEffects(); + const auto ToFX = ToFPT->getFunctionEffects(); + if (FromFX != ToFX) { + FunctionProtoType::ExtProtoInfo ExtInfo = FromFPT->getExtProtoInfo(); + ExtInfo.FunctionEffects = ToFX; + QualType QT = Context.getFunctionType( + FromFPT->getReturnType(), FromFPT->getParamTypes(), ExtInfo); + FromFn = QT->getAs(); + Changed = true; + } + } } if (!Changed) @@ -4351,8 +4372,8 @@ HLSLCompareFloatingRank(QualType LHS, QualType RHS) { if (const auto *VT = RHS->getAs()) RHS = VT->getElementType(); - const auto L = LHS->getAs()->getKind(); - const auto R = RHS->getAs()->getKind(); + const auto L = LHS->castAs()->getKind(); + const auto R = RHS->castAs()->getKind(); if (L == R) return ImplicitConversionSequence::Indistinguishable; return L < R ? ImplicitConversionSequence::Better @@ -12148,7 +12169,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, case ovl_fail_bad_conversion: { unsigned I = (Cand->IgnoreObjectArgument ? 1 : 0); for (unsigned N = Cand->Conversions.size(); I != N; ++I) - if (Cand->Conversions[I].isBad()) + if (Cand->Conversions[I].isInitialized() && Cand->Conversions[I].isBad()) return DiagnoseBadConversion(S, Cand, I, TakingCandidateAddress); // FIXME: this currently happens when we're called from SemaInit diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index a032e3ec6f6353..9f4acbe5e6dd55 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2513,6 +2513,9 @@ struct ConvertConstructorToDeductionGuideTransform { TSI = SemaRef.SubstType(TSI, OuterInstantiationArgs, Loc, DeductionGuideName); + if (!TSI) + return nullptr; + FunctionProtoTypeLoc FPTL = TSI->getTypeLoc().castAs(); @@ -2523,6 +2526,9 @@ struct ConvertConstructorToDeductionGuideTransform { if (NestedPattern) TSI = SemaRef.SubstType(TSI, OuterInstantiationArgs, Loc, DeclarationName()); + if (!TSI) + return nullptr; + ParmVarDecl *NewParam = ParmVarDecl::Create(SemaRef.Context, DC, Loc, Loc, nullptr, TSI->getType(), TSI, SC_None, nullptr); @@ -3170,10 +3176,6 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef, Expr *RequiresClause = buildAssociatedConstraints( SemaRef, F, AliasTemplate, DeduceResults, IsDeducible); - // FIXME: implement the is_deducible constraint per C++ - // [over.match.class.deduct]p3.3: - // ... and a constraint that is satisfied if and only if the arguments - // of A are deducible (see below) from the return type. auto *FPrimeTemplateParamList = TemplateParameterList::Create( Context, AliasTemplate->getTemplateParameters()->getTemplateLoc(), AliasTemplate->getTemplateParameters()->getLAngleLoc(), diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 9bb12c6aa7b122..308274720d58d6 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -31,6 +31,7 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/DelayedDiagnostic.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/ParsedAttr.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaCUDA.h" @@ -149,6 +150,10 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr, #define FUNCTION_TYPE_ATTRS_CASELIST \ case ParsedAttr::AT_NSReturnsRetained: \ case ParsedAttr::AT_NoReturn: \ + case ParsedAttr::AT_NonBlocking: \ + case ParsedAttr::AT_NonAllocating: \ + case ParsedAttr::AT_Blocking: \ + case ParsedAttr::AT_Allocating: \ case ParsedAttr::AT_Regparm: \ case ParsedAttr::AT_CmseNSCall: \ case ParsedAttr::AT_ArmStreaming: \ @@ -7522,6 +7527,111 @@ static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) { llvm_unreachable("unexpected attribute kind!"); } +std::optional +Sema::ActOnEffectExpression(Expr *CondExpr, StringRef AttributeName) { + if (CondExpr->isTypeDependent() || CondExpr->isValueDependent()) + return FunctionEffectMode::Dependent; + + std::optional ConditionValue = + CondExpr->getIntegerConstantExpr(Context); + if (!ConditionValue) { + // FIXME: err_attribute_argument_type doesn't quote the attribute + // name but needs to; users are inconsistent. + Diag(CondExpr->getExprLoc(), diag::err_attribute_argument_type) + << AttributeName << AANT_ArgumentIntegerConstant + << CondExpr->getSourceRange(); + return std::nullopt; + } + return !ConditionValue->isZero() ? FunctionEffectMode::True + : FunctionEffectMode::False; +} + +static bool +handleNonBlockingNonAllocatingTypeAttr(TypeProcessingState &TPState, + ParsedAttr &PAttr, QualType &QT, + FunctionTypeUnwrapper &Unwrapped) { + // Delay if this is not a function type. + if (!Unwrapped.isFunctionType()) + return false; + + Sema &S = TPState.getSema(); + + // Require FunctionProtoType. + auto *FPT = Unwrapped.get()->getAs(); + if (FPT == nullptr) { + S.Diag(PAttr.getLoc(), diag::err_func_with_effects_no_prototype) + << PAttr.getAttrName()->getName(); + return true; + } + + // Parse the new attribute. + // non/blocking or non/allocating? Or conditional (computed)? + bool IsNonBlocking = PAttr.getKind() == ParsedAttr::AT_NonBlocking || + PAttr.getKind() == ParsedAttr::AT_Blocking; + + FunctionEffectMode NewMode = FunctionEffectMode::None; + Expr *CondExpr = nullptr; // only valid if dependent + + if (PAttr.getKind() == ParsedAttr::AT_NonBlocking || + PAttr.getKind() == ParsedAttr::AT_NonAllocating) { + if (!PAttr.checkAtMostNumArgs(S, 1)) { + PAttr.setInvalid(); + return true; + } + + // Parse the condition, if any. + if (PAttr.getNumArgs() == 1) { + CondExpr = PAttr.getArgAsExpr(0); + std::optional MaybeMode = + S.ActOnEffectExpression(CondExpr, PAttr.getAttrName()->getName()); + if (!MaybeMode) { + PAttr.setInvalid(); + return true; + } + NewMode = *MaybeMode; + if (NewMode != FunctionEffectMode::Dependent) + CondExpr = nullptr; + } else { + NewMode = FunctionEffectMode::True; + } + } else { + // This is the `blocking` or `allocating` attribute. + if (S.CheckAttrNoArgs(PAttr)) { + // The attribute has been marked invalid. + return true; + } + NewMode = FunctionEffectMode::False; + } + + const FunctionEffect::Kind FEKind = + (NewMode == FunctionEffectMode::False) + ? (IsNonBlocking ? FunctionEffect::Kind::Blocking + : FunctionEffect::Kind::Allocating) + : (IsNonBlocking ? FunctionEffect::Kind::NonBlocking + : FunctionEffect::Kind::NonAllocating); + const FunctionEffectWithCondition NewEC{FunctionEffect(FEKind), + EffectConditionExpr(CondExpr)}; + + if (S.diagnoseConflictingFunctionEffect(FPT->getFunctionEffects(), NewEC, + PAttr.getLoc())) { + PAttr.setInvalid(); + return true; + } + + // Add the effect to the FunctionProtoType. + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + FunctionEffectSet FX(EPI.FunctionEffects); + FunctionEffectSet::Conflicts Errs; + [[maybe_unused]] bool Success = FX.insert(NewEC, Errs); + assert(Success && "effect conflicts should have been diagnosed above"); + EPI.FunctionEffects = FunctionEffectsRef(FX); + + QualType NewType = S.Context.getFunctionType(FPT->getReturnType(), + FPT->getParamTypes(), EPI); + QT = Unwrapped.wrap(S, NewType->getAs()); + return true; +} + static bool checkMutualExclusion(TypeProcessingState &state, const FunctionProtoType::ExtProtoInfo &EPI, ParsedAttr &Attr, @@ -7834,6 +7944,13 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, return true; } + if (attr.getKind() == ParsedAttr::AT_NonBlocking || + attr.getKind() == ParsedAttr::AT_NonAllocating || + attr.getKind() == ParsedAttr::AT_Blocking || + attr.getKind() == ParsedAttr::AT_Allocating) { + return handleNonBlockingNonAllocatingTypeAttr(state, attr, type, unwrapped); + } + // Delay if the type didn't work out to a function. if (!unwrapped.isFunctionType()) return false; @@ -8086,23 +8203,19 @@ static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr, // Target must have NEON (or MVE, whose vectors are similar enough // not to need a separate attribute) - if (!(S.Context.getTargetInfo().hasFeature("neon") || - S.Context.getTargetInfo().hasFeature("mve") || - S.Context.getTargetInfo().hasFeature("sve") || - S.Context.getTargetInfo().hasFeature("sme") || - IsTargetCUDAAndHostARM) && - VecKind == VectorKind::Neon) { - S.Diag(Attr.getLoc(), diag::err_attribute_unsupported) - << Attr << "'neon', 'mve', 'sve' or 'sme'"; + if (!S.Context.getTargetInfo().hasFeature("mve") && + VecKind == VectorKind::Neon && + S.Context.getTargetInfo().getTriple().isArmMClass()) { + S.Diag(Attr.getLoc(), diag::err_attribute_unsupported_m_profile) + << Attr << "'mve'"; Attr.setInvalid(); return; } - if (!(S.Context.getTargetInfo().hasFeature("neon") || - S.Context.getTargetInfo().hasFeature("mve") || - IsTargetCUDAAndHostARM) && - VecKind == VectorKind::NeonPoly) { - S.Diag(Attr.getLoc(), diag::err_attribute_unsupported) - << Attr << "'neon' or 'mve'"; + if (!S.Context.getTargetInfo().hasFeature("mve") && + VecKind == VectorKind::NeonPoly && + S.Context.getTargetInfo().getTriple().isArmMClass()) { + S.Diag(Attr.getLoc(), diag::err_attribute_unsupported_m_profile) + << Attr << "'mve'"; Attr.setInvalid(); return; } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index cf4e80399632b2..51ba22f99e3a3c 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -6267,6 +6267,55 @@ QualType TreeTransform::TransformFunctionProtoType( EPI.ExtParameterInfos = nullptr; } + // Transform any function effects with unevaluated conditions. + // Hold this set in a local for the rest of this function, since EPI + // may need to hold a FunctionEffectsRef pointing into it. + std::optional NewFX; + if (ArrayRef FXConds = EPI.FunctionEffects.conditions(); !FXConds.empty()) { + NewFX.emplace(); + EnterExpressionEvaluationContext Unevaluated( + getSema(), Sema::ExpressionEvaluationContext::ConstantEvaluated); + + for (const FunctionEffectWithCondition &PrevEC : EPI.FunctionEffects) { + FunctionEffectWithCondition NewEC = PrevEC; + if (Expr *CondExpr = PrevEC.Cond.getCondition()) { + ExprResult NewExpr = getDerived().TransformExpr(CondExpr); + if (NewExpr.isInvalid()) + return QualType(); + std::optional Mode = + SemaRef.ActOnEffectExpression(NewExpr.get(), PrevEC.Effect.name()); + if (!Mode) + return QualType(); + + // The condition expression has been transformed, and re-evaluated. + // It may or may not have become constant. + switch (*Mode) { + case FunctionEffectMode::True: + NewEC.Cond = {}; + break; + case FunctionEffectMode::False: + NewEC.Effect = FunctionEffect(PrevEC.Effect.oppositeKind()); + NewEC.Cond = {}; + break; + case FunctionEffectMode::Dependent: + NewEC.Cond = EffectConditionExpr(NewExpr.get()); + break; + case FunctionEffectMode::None: + llvm_unreachable( + "FunctionEffectMode::None shouldn't be possible here"); + } + } + if (!SemaRef.diagnoseConflictingFunctionEffect(*NewFX, NewEC, + TL.getBeginLoc())) { + FunctionEffectSet::Conflicts Errs; + NewFX->insert(NewEC, Errs); + assert(Errs.empty()); + } + } + EPI.FunctionEffects = *NewFX; + EPIChanged = true; + } + QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ResultType != T->getReturnType() || T->getParamTypes() != llvm::ArrayRef(ParamTypes) || EPIChanged) { @@ -6502,7 +6551,7 @@ QualType TreeTransform::TransformTypeOfExprType(TypeLocBuilder &TLB, return QualType(); QualType Result = TL.getType(); - TypeOfKind Kind = Result->getAs()->getKind(); + TypeOfKind Kind = Result->castAs()->getKind(); if (getDerived().AlwaysRebuild() || E.get() != TL.getUnderlyingExpr()) { Result = getDerived().RebuildTypeOfExprType(E.get(), TL.getTypeofLoc(), Kind); @@ -6527,7 +6576,7 @@ QualType TreeTransform::TransformTypeOfType(TypeLocBuilder &TLB, return QualType(); QualType Result = TL.getType(); - TypeOfKind Kind = Result->getAs()->getKind(); + TypeOfKind Kind = Result->castAs()->getKind(); if (getDerived().AlwaysRebuild() || New_Under_TI != Old_Under_TI) { Result = getDerived().RebuildTypeOfType(New_Under_TI->getType(), Kind); if (Result.isNull()) diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index e8b398615e0e1a..079ac3f0e3545f 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -935,9 +935,8 @@ LocalDeclID LocalDeclID::get(ASTReader &Reader, ModuleFile &MF, DeclID Value) { return ID; } -static LocalDeclID getLocalDeclID(ASTReader &Reader, ModuleFile &MF, - unsigned ModuleFileIndex, - unsigned LocalDeclID) { +LocalDeclID LocalDeclID::get(ASTReader &Reader, ModuleFile &MF, + unsigned ModuleFileIndex, unsigned LocalDeclID) { DeclID Value = (DeclID)ModuleFileIndex << 32 | (DeclID)LocalDeclID; return LocalDeclID::get(Reader, MF, Value); } @@ -7884,7 +7883,7 @@ LocalDeclID ASTReader::mapGlobalIDToModuleFileGlobalID(ModuleFile &M, if (!OrignalModuleFileIndex) return LocalDeclID(); - return getLocalDeclID(*this, M, OrignalModuleFileIndex, ID); + return LocalDeclID::get(*this, M, OrignalModuleFileIndex, ID); } GlobalDeclID ASTReader::ReadDeclID(ModuleFile &F, const RecordDataImpl &Record, diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 4b8b515c02c70d..6afb18f932e724 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -3723,6 +3723,23 @@ void ASTDeclReader::attachPreviousDecl(ASTReader &Reader, Decl *D, #include "clang/AST/DeclNodes.inc" } + // [basic.link]/p10: + // If two declarations of an entity are attached to different modules, + // the program is ill-formed; + // + // FIXME: Get rid of the enumeration of decl types once we have an appropriate + // abstract for decls of an entity. e.g., the namespace decl and using decl + // doesn't introduce an entity. + if (Module *M = Previous->getOwningModule(); + M && M->isNamedModule() && + isa(Previous) && + !Reader.getContext().isInSameModule(M, D->getOwningModule())) { + Reader.Diag(Previous->getLocation(), + diag::err_multiple_decl_in_different_modules) + << cast(Previous) << M->Name; + Reader.Diag(D->getLocation(), diag::note_also_found); + } + // If the declaration was visible in one module, a redeclaration of it in // another module remains visible even if it wouldn't be visible by itself. // diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index d99d85652c7b77..9c55960b14cba9 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -5355,6 +5355,20 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, writeUnhashedControlBlock(PP, Context); + // Don't reuse type ID and Identifier ID from readers for C++ standard named + // modules since we want to support no-transitive-change model for named + // modules. The theory for no-transitive-change model is, + // for a user of a named module, the user can only access the indirectly + // imported decls via the directly imported module. So that it is possible to + // control what matters to the users when writing the module. It would be + // problematic if the users can reuse the type IDs and identifier IDs from + // indirectly imported modules arbitrarily. So we choose to clear these ID + // here. + if (isWritingStdCXXNamedModules()) { + TypeIdxs.clear(); + IdentifierIDs.clear(); + } + // Look for any identifiers that were named while processing the // headers, but are otherwise not needed. We add these to the hash // table to enable checking of the predefines buffer in the case @@ -5387,6 +5401,17 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, } } + // Form the record of special types. + RecordData SpecialTypes; + AddTypeRef(Context.getRawCFConstantStringType(), SpecialTypes); + AddTypeRef(Context.getFILEType(), SpecialTypes); + AddTypeRef(Context.getjmp_bufType(), SpecialTypes); + AddTypeRef(Context.getsigjmp_bufType(), SpecialTypes); + AddTypeRef(Context.ObjCIdRedefinitionType, SpecialTypes); + AddTypeRef(Context.ObjCClassRedefinitionType, SpecialTypes); + AddTypeRef(Context.ObjCSelRedefinitionType, SpecialTypes); + AddTypeRef(Context.getucontext_tType(), SpecialTypes); + PrepareWritingSpecialDecls(SemaRef); // Write the control block @@ -5418,17 +5443,6 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, for (auto &Selector : AllSelectors) SemaRef.ObjC().updateOutOfDateSelector(Selector); - // Form the record of special types. - RecordData SpecialTypes; - AddTypeRef(Context.getRawCFConstantStringType(), SpecialTypes); - AddTypeRef(Context.getFILEType(), SpecialTypes); - AddTypeRef(Context.getjmp_bufType(), SpecialTypes); - AddTypeRef(Context.getsigjmp_bufType(), SpecialTypes); - AddTypeRef(Context.ObjCIdRedefinitionType, SpecialTypes); - AddTypeRef(Context.ObjCClassRedefinitionType, SpecialTypes); - AddTypeRef(Context.ObjCSelRedefinitionType, SpecialTypes); - AddTypeRef(Context.getucontext_tType(), SpecialTypes); - if (Chain) { // Write the mapping information describing our module dependencies and how // each of those modules were mapped into our own offset/ID space, so that @@ -6686,6 +6700,11 @@ void ASTWriter::ReaderInitialized(ASTReader *Reader) { } void ASTWriter::IdentifierRead(IdentifierID ID, IdentifierInfo *II) { + // Don't reuse Type ID from external modules for named modules. See the + // comments in WriteASTCore for details. + if (isWritingStdCXXNamedModules()) + return; + IdentifierID &StoredID = IdentifierIDs[II]; unsigned OriginalModuleFileIndex = StoredID >> 32; @@ -6708,6 +6727,11 @@ void ASTWriter::MacroRead(serialization::MacroID ID, MacroInfo *MI) { } void ASTWriter::TypeRead(TypeIdx Idx, QualType T) { + // Don't reuse Type ID from external modules for named modules. See the + // comments in WriteASTCore for details. + if (isWritingStdCXXNamedModules()) + return; + // Always take the type index that comes in later module files. // This copes with an interesting // case for chained AST writing where we schedule writing the type and then, diff --git a/clang/lib/StaticAnalyzer/Checkers/NoOwnershipChangeVisitor.cpp b/clang/lib/StaticAnalyzer/Checkers/NoOwnershipChangeVisitor.cpp index 2ff76679b5ebf7..22b5ebfd6fab04 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NoOwnershipChangeVisitor.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NoOwnershipChangeVisitor.cpp @@ -18,6 +18,7 @@ using namespace clang; using namespace ento; using OwnerSet = NoOwnershipChangeVisitor::OwnerSet; +namespace { // Collect which entities point to the allocated memory, and could be // responsible for deallocating it. class OwnershipBindingsHandler : public StoreManager::BindingsHandler { @@ -46,6 +47,7 @@ class OwnershipBindingsHandler : public StoreManager::BindingsHandler { out << "}\n"; } }; +} // namespace OwnerSet NoOwnershipChangeVisitor::getOwnersAtNode(const ExplodedNode *N) { OwnerSet Ret; diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp index b73534136fdf02..eea93a41f13841 100644 --- a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp @@ -43,8 +43,6 @@ class PointerSubChecker bool checkArrayBounds(CheckerContext &C, const Expr *E, const ElementRegion *ElemReg, const MemRegion *Reg) const; - void reportBug(CheckerContext &C, const Expr *E, - const llvm::StringLiteral &Msg) const; public: void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const; @@ -57,6 +55,14 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext &C, const Expr *E, if (!ElemReg) return true; + auto ReportBug = [&](const llvm::StringLiteral &Msg) { + if (ExplodedNode *N = C.generateNonFatalErrorNode()) { + auto R = std::make_unique(BT, Msg, N); + R->addRange(E->getSourceRange()); + C.emitReport(std::move(R)); + } + }; + ProgramStateRef State = C.getState(); const MemRegion *SuperReg = ElemReg->getSuperRegion(); SValBuilder &SVB = C.getSValBuilder(); @@ -64,7 +70,7 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext &C, const Expr *E, if (SuperReg == Reg) { if (const llvm::APSInt *I = SVB.getKnownValue(State, ElemReg->getIndex()); I && (!I->isOne() && !I->isZero())) - reportBug(C, E, Msg_BadVarIndex); + ReportBug(Msg_BadVarIndex); return false; } @@ -77,7 +83,7 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext &C, const Expr *E, ProgramStateRef S1, S2; std::tie(S1, S2) = C.getState()->assume(*IndexTooLarge); if (S1 && !S2) { - reportBug(C, E, Msg_LargeArrayIndex); + ReportBug(Msg_LargeArrayIndex); return false; } } @@ -89,22 +95,13 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext &C, const Expr *E, ProgramStateRef S1, S2; std::tie(S1, S2) = State->assume(*IndexTooSmall); if (S1 && !S2) { - reportBug(C, E, Msg_NegativeArrayIndex); + ReportBug(Msg_NegativeArrayIndex); return false; } } return true; } -void PointerSubChecker::reportBug(CheckerContext &C, const Expr *E, - const llvm::StringLiteral &Msg) const { - if (ExplodedNode *N = C.generateNonFatalErrorNode()) { - auto R = std::make_unique(BT, Msg, N); - R->addRange(E->getSourceRange()); - C.emitReport(std::move(R)); - } -} - void PointerSubChecker::checkPreStmt(const BinaryOperator *B, CheckerContext &C) const { // When doing pointer subtraction, if the two pointers do not point to the @@ -136,6 +133,9 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B, if (!checkArrayBounds(C, B->getRHS(), ElemRR, LR)) return; + const ValueDecl *DiffDeclL = nullptr; + const ValueDecl *DiffDeclR = nullptr; + if (ElemLR && ElemRR) { const MemRegion *SuperLR = ElemLR->getSuperRegion(); const MemRegion *SuperRR = ElemRR->getSuperRegion(); @@ -144,9 +144,30 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B, // Allow arithmetic on different symbolic regions. if (isa(SuperLR) || isa(SuperRR)) return; + if (const auto *SuperDLR = dyn_cast(SuperLR)) + DiffDeclL = SuperDLR->getDecl(); + if (const auto *SuperDRR = dyn_cast(SuperRR)) + DiffDeclR = SuperDRR->getDecl(); } - reportBug(C, B, Msg_MemRegionDifferent); + if (ExplodedNode *N = C.generateNonFatalErrorNode()) { + auto R = + std::make_unique(BT, Msg_MemRegionDifferent, N); + R->addRange(B->getSourceRange()); + // The declarations may be identical even if the regions are different: + // struct { int array[10]; } a, b; + // do_something(&a.array[5] - &b.array[5]); + // In this case don't emit notes. + if (DiffDeclL != DiffDeclR) { + if (DiffDeclL) + R->addNote("Array at the left-hand side of subtraction", + {DiffDeclL, C.getSourceManager()}); + if (DiffDeclR) + R->addNote("Array at the right-hand side of subtraction", + {DiffDeclR, C.getSourceManager()}); + } + C.emitReport(std::move(R)); + } } void ento::registerPointerSubChecker(CheckerManager &mgr) { diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp index 845a5f9b390dc4..8f4bd17afc8581 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -672,7 +672,7 @@ class StdLibraryFunctionsChecker StringRef getNote() const { return Note; } }; - using ArgTypes = std::vector>; + using ArgTypes = ArrayRef>; using RetType = std::optional; // A placeholder type, we use it whenever we do not care about the concrete @@ -1746,7 +1746,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( } // Add the same summary for different names with the Signature explicitly // given. - void operator()(std::vector Names, Signature Sign, Summary Sum) { + void operator()(ArrayRef Names, Signature Sign, Summary Sum) { for (StringRef Name : Names) operator()(Name, Sign, Sum); } diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index 613c221de7b4cd..9aee7f952ad2d8 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -10,6 +10,9 @@ // //===----------------------------------------------------------------------===// +#include "NoOwnershipChangeVisitor.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" @@ -74,6 +77,12 @@ struct StreamErrorState { /// Returns if the StreamErrorState is a valid object. operator bool() const { return NoError || FEof || FError; } + LLVM_DUMP_METHOD void dump() const { dumpToStream(llvm::errs()); } + LLVM_DUMP_METHOD void dumpToStream(llvm::raw_ostream &os) const { + os << "NoError: " << NoError << ", FEof: " << FEof + << ", FError: " << FError; + } + void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddBoolean(NoError); ID.AddBoolean(FEof); @@ -98,6 +107,18 @@ struct StreamState { OpenFailed /// The last open operation has failed. } State; + StringRef getKindStr() const { + switch (State) { + case Opened: + return "Opened"; + case Closed: + return "Closed"; + case OpenFailed: + return "OpenFailed"; + } + llvm_unreachable("Unknown StreamState!"); + } + /// State of the error flags. /// Ignored in non-opened stream state but must be NoError. StreamErrorState const ErrorState; @@ -146,6 +167,9 @@ struct StreamState { return StreamState{L, OpenFailed, {}, false}; } + LLVM_DUMP_METHOD void dump() const { dumpToStream(llvm::errs()); } + LLVM_DUMP_METHOD void dumpToStream(llvm::raw_ostream &os) const; + void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddPointer(LastOperation); ID.AddInteger(State); @@ -183,6 +207,14 @@ struct FnDescription { ArgNoTy StreamArgNo; }; +LLVM_DUMP_METHOD void StreamState::dumpToStream(llvm::raw_ostream &os) const { + os << "{Kind: " << getKindStr() << ", Last operation: " << LastOperation + << ", ErrorState: "; + ErrorState.dumpToStream(os); + os << ", FilePos: " << (FilePositionIndeterminate ? "Indeterminate" : "OK") + << '}'; +} + /// Get the value of the stream argument out of the passed call event. /// The call should contain a function that is described by Desc. SVal getStreamArg(const FnDescription *Desc, const CallEvent &Call) { @@ -300,6 +332,8 @@ class StreamChecker : public Checker FnDescriptions = { {{CDM::CLibrary, {"fopen"}, 2}, @@ -310,8 +344,7 @@ class StreamChecker : public Checker(&Checker); + return StreamChk->FCloseDesc.matchesAsWritten(Call); + } + + bool doesFnIntendToHandleOwnership(const Decl *Callee, + ASTContext &ACtx) final { + using namespace clang::ast_matchers; + const FunctionDecl *FD = dyn_cast(Callee); + + auto Matches = + match(findAll(callExpr().bind("call")), *FD->getBody(), ACtx); + for (BoundNodes Match : Matches) { + if (const auto *Call = Match.getNodeAs("call")) + if (isClosingCallAsWritten(*Call)) + return true; + } + // TODO: Ownership might change with an attempt to store stream object, not + // only through closing it. Check for attempted stores as well. + return false; + } + + bool hasResourceStateChanged(ProgramStateRef CallEnterState, + ProgramStateRef CallExitEndState) final { + return CallEnterState->get(Sym) != + CallExitEndState->get(Sym); + } + + PathDiagnosticPieceRef emitNote(const ExplodedNode *N) override { + PathDiagnosticLocation L = PathDiagnosticLocation::create( + N->getLocation(), + N->getState()->getStateManager().getContext().getSourceManager()); + return std::make_shared( + L, "Returning without closing stream object or storing it for later " + "release"); + } + +public: + NoStreamStateChangeVisitor(SymbolRef Sym, const StreamChecker *Checker) + : NoOwnershipChangeVisitor(Sym, Checker) {} +}; + +} // end anonymous namespace + const ExplodedNode *StreamChecker::getAcquisitionSite(const ExplodedNode *N, SymbolRef StreamSym, CheckerContext &C) { @@ -1872,6 +1961,7 @@ StreamChecker::reportLeaks(const SmallVector &LeakedSyms, LocUsedForUniqueing, StreamOpenNode->getLocationContext()->getDecl()); R->markInteresting(LeakSym); + R->addVisitor(LeakSym, this); C.emitReport(std::move(R)); } diff --git a/clang/lib/Tooling/Inclusions/Stdlib/CMakeLists.txt b/clang/lib/Tooling/Inclusions/Stdlib/CMakeLists.txt index ed323ab3528b10..4d01a0850a074b 100644 --- a/clang/lib/Tooling/Inclusions/Stdlib/CMakeLists.txt +++ b/clang/lib/Tooling/Inclusions/Stdlib/CMakeLists.txt @@ -4,6 +4,7 @@ # our goal is to disable the /Og flag while retaining the other optimizations from the /O1|/O2 set if(MSVC AND NOT CMAKE_CXX_COMPILER_ID MATCHES Clang AND MSVC_VERSION VERSION_GREATER_EQUAL 1932 + AND MSVC_VERSION VERSION_LESS 1939 AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64") string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE) diff --git a/clang/lib/Tooling/Transformer/RangeSelector.cpp b/clang/lib/Tooling/Transformer/RangeSelector.cpp index 7370baf010834c..e84ddde74a7079 100644 --- a/clang/lib/Tooling/Transformer/RangeSelector.cpp +++ b/clang/lib/Tooling/Transformer/RangeSelector.cpp @@ -96,13 +96,6 @@ static SourceLocation findPreviousTokenKind(SourceLocation Start, } } -static SourceLocation findOpenParen(const CallExpr &E, const SourceManager &SM, - const LangOptions &LangOpts) { - SourceLocation EndLoc = - E.getNumArgs() == 0 ? E.getRParenLoc() : E.getArg(0)->getBeginLoc(); - return findPreviousTokenKind(EndLoc, SM, LangOpts, tok::TokenKind::l_paren); -} - RangeSelector transformer::before(RangeSelector Selector) { return [Selector](const MatchResult &Result) -> Expected { Expected SelectedRange = Selector(Result); @@ -287,18 +280,50 @@ RangeSelector transformer::statements(std::string ID) { } namespace { -// Returns the range of the source between the call's parentheses. -CharSourceRange getCallArgumentsRange(const MatchResult &Result, - const CallExpr &CE) { + +SourceLocation getRLoc(const CallExpr &E) { return E.getRParenLoc(); } + +SourceLocation getRLoc(const CXXConstructExpr &E) { + return E.getParenOrBraceRange().getEnd(); +} + +tok::TokenKind getStartToken(const CallExpr &E) { + return tok::TokenKind::l_paren; +} + +tok::TokenKind getStartToken(const CXXConstructExpr &E) { + return isa(E) ? tok::TokenKind::l_paren + : tok::TokenKind::l_brace; +} + +template +SourceLocation findArgStartDelimiter(const ExprWithArgs &E, SourceLocation RLoc, + const SourceManager &SM, + const LangOptions &LangOpts) { + SourceLocation Loc = E.getNumArgs() == 0 ? RLoc : E.getArg(0)->getBeginLoc(); + return findPreviousTokenKind(Loc, SM, LangOpts, getStartToken(E)); +} +// Returns the range of the source between the call's or construct expr's +// parentheses/braces. +template +CharSourceRange getArgumentsRange(const MatchResult &Result, + const ExprWithArgs &CE) { + const SourceLocation RLoc = getRLoc(CE); return CharSourceRange::getCharRange( - findOpenParen(CE, *Result.SourceManager, Result.Context->getLangOpts()) + findArgStartDelimiter(CE, RLoc, *Result.SourceManager, + Result.Context->getLangOpts()) .getLocWithOffset(1), - CE.getRParenLoc()); + RLoc); } } // namespace RangeSelector transformer::callArgs(std::string ID) { - return RelativeSelector(std::move(ID)); + return RelativeSelector>(std::move(ID)); +} + +RangeSelector transformer::constructExprArgs(std::string ID) { + return RelativeSelector>(std::move(ID)); } namespace { diff --git a/clang/lib/Tooling/Transformer/Stencil.cpp b/clang/lib/Tooling/Transformer/Stencil.cpp index d91c9e0a20cc1b..bc4fa6e36057c1 100644 --- a/clang/lib/Tooling/Transformer/Stencil.cpp +++ b/clang/lib/Tooling/Transformer/Stencil.cpp @@ -51,7 +51,7 @@ static Error printNode(StringRef Id, const MatchFinder::MatchResult &Match, if (auto Err = NodeOrErr.takeError()) return Err; NodeOrErr->print(Os, PrintingPolicy(Match.Context->getLangOpts())); - *Result += Os.str(); + *Result += Output; return Error::success(); } @@ -371,7 +371,7 @@ class SelectBoundStencil : public clang::transformer::StencilInterface { Stream << ", " << DefaultStencil->toString(); } Stream << ")"; - return Stream.str(); + return Buffer; } private: diff --git a/clang/test/AST/Interp/arrays.cpp b/clang/test/AST/Interp/arrays.cpp index 6f6fca8c1cfd8e..933437c3401c40 100644 --- a/clang/test/AST/Interp/arrays.cpp +++ b/clang/test/AST/Interp/arrays.cpp @@ -26,6 +26,9 @@ static_assert(foo[2][2] == nullptr, ""); static_assert(foo[2][3] == &m, ""); static_assert(foo[2][4] == nullptr, ""); +constexpr int afterEnd[] = {1,2,3}; +static_assert(&afterEnd[3] == afterEnd + 3, ""); + constexpr int ZeroSizeArray[] = {}; constexpr int SomeInt[] = {1}; @@ -510,11 +513,9 @@ namespace NonConstReads { // both-note {{read of non-const variable 'z'}} #else void *p = nullptr; - int arr[!p]; // ref-error {{not allowed at file scope}} \ - // expected-error {{not allowed at file scope}} + int arr[!p]; // both-error {{not allowed at file scope}} int z; - int a[z]; // ref-error {{not allowed at file scope}} \ - // expected-error {{not allowed at file scope}} + int a[z]; // both-error {{not allowed at file scope}} #endif const int y = 0; @@ -623,3 +624,4 @@ constexpr int *get2() { extern int same_entity_2[]; return same_entity_2; } +static_assert(get2() == same_entity_2, "failed to find previous decl"); diff --git a/clang/test/AST/Interp/c.c b/clang/test/AST/Interp/c.c index 1cc450e48def06..684658da26a0ed 100644 --- a/clang/test/AST/Interp/c.c +++ b/clang/test/AST/Interp/c.c @@ -288,3 +288,8 @@ char test10_global[test10_bound]; // all-error {{variable length array declarati void test10(void) { char test10_local[test10_bound] = "help"; // all-error {{variable-sized object may not be initialized}} } + +void SuperSpecialFunc(void) { +const int SuperSpecialCase = 10; +_Static_assert((sizeof(SuperSpecialCase) == 12 && SuperSpecialCase == 3) || SuperSpecialCase == 10, ""); // pedantic-warning {{GNU extension}} +} diff --git a/clang/test/AST/Interp/const-temporaries.cpp b/clang/test/AST/Interp/const-temporaries.cpp new file mode 100644 index 00000000000000..1dc16ef63a8468 --- /dev/null +++ b/clang/test/AST/Interp/const-temporaries.cpp @@ -0,0 +1,101 @@ +// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin -emit-llvm -o - %s -std=c++1y -fexperimental-new-constant-interpreter | FileCheck %s +// +// expected-no-diagnostics + +struct A { + constexpr A() : n(1) {} + ~A(); + int n; +}; +struct B : A { + A a[3]; + constexpr B() { + ++a[0].n; + a[1].n += 2; + a[2].n = n + a[1].n; + } +}; +B b; + +// CHECK: @b ={{.*}} global {{.*}} i32 1, {{.*}} { i32 2 }, {{.*}} { i32 3 }, {{.*}} { i32 4 } +// CHECK-NOT: _ZN1BC + +namespace ModifyStaticTemporary { + struct A { int &&temporary; int x; }; + constexpr int f(int &r) { r *= 9; return r - 12; } + A a = { 6, f(a.temporary) }; + // CHECK: @_ZGRN21ModifyStaticTemporary1aE_ = internal global i32 54 + // CHECK: @_ZN21ModifyStaticTemporary1aE ={{.*}} global {{.*}} ptr @_ZGRN21ModifyStaticTemporary1aE_, i32 42 + + A b = { 7, ++b.temporary }; + // CHECK: @_ZGRN21ModifyStaticTemporary1bE_ = internal global i32 8 + // CHECK: @_ZN21ModifyStaticTemporary1bE ={{.*}} global {{.*}} ptr @_ZGRN21ModifyStaticTemporary1bE_, i32 8 + + // Can't emit all of 'c' as a constant here, so emit the initial value of + // 'c.temporary', not the value as modified by the partial evaluation within + // the initialization of 'c.x'. + A c = { 10, (++c.temporary, b.x) }; + // CHECK: @_ZN21ModifyStaticTemporary1cE ={{.*}} global {{.*}} zeroinitializer + // CHECK: @_ZGRN21ModifyStaticTemporary1cE_ = internal global i32 10 +} + +// CHECK: @_ZGRN28VariableTemplateWithConstRef1iIvEE_ = linkonce_odr constant i32 5, align 4 +// CHECK: @_ZN28VariableTemplateWithConstRef3useE ={{.*}} constant ptr @_ZGRN28VariableTemplateWithConstRef1iIvEE_ +namespace VariableTemplateWithConstRef { + template + const int &i = 5; + const int &use = i; +} + +// CHECK: @_ZGRN34HiddenVariableTemplateWithConstRef1iIvEE_ = linkonce_odr hidden constant i32 5, align 4 +// CHECK: @_ZN34HiddenVariableTemplateWithConstRef3useE ={{.*}} constant ptr @_ZGRN34HiddenVariableTemplateWithConstRef1iIvEE_ +namespace HiddenVariableTemplateWithConstRef { + template + __attribute__((visibility("hidden"))) const int &i = 5; + const int &use = i; +} + +// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE1_ = linkonce_odr constant i32 1 +// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE0_ = linkonce_odr global {{.*}} { ptr @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE1_ } +// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE3_ = linkonce_odr constant i32 2 +// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE2_ = linkonce_odr global {{.*}} { ptr @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE3_ } +// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE5_ = linkonce_odr constant i32 3 +// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE4_ = linkonce_odr global {{.*}} { ptr @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE5_ } +// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE7_ = linkonce_odr constant i32 4 +// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE6_ = linkonce_odr global {{.*}} { ptr @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE7_ } +// CHECK: @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE_ = linkonce_odr global %"struct.VariableTemplateWithPack::S" { ptr @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE0_, ptr @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE2_, ptr @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE4_, ptr @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE6_ } +// CHECK: @_ZN24VariableTemplateWithPack1pE ={{.*}} global {{.*}} @_ZGRN24VariableTemplateWithPack1sIJLi1ELi2ELi3ELi4EEEE_ +namespace VariableTemplateWithPack { + struct A { + const int &r; + }; + struct S { + A &&a, &&b, &&c, &&d; + }; + template + S &&s = {A{N}...}; + S *p = &s<1, 2, 3, 4>; +} + + +// CHECK: @_ZGR1z_ ={{.*}} global [2 x i32] [i32 10, i32 2] +// CHECK: @z = global { ptr, i32 } { ptr @_ZGR1z_, i32 10 } +typedef int v[2]; +struct Z { int &&x, y; }; +Z z = { v{1,2}[0], z.x = 10 }; + +// CHECK: @_ZGR2z2_ ={{.*}} global %struct.R { i64 10 } +// @z = {{.}} global %struct.Z { ptr @_ZGR1z_, %struct.R { i64 10 } } +struct R { mutable long x; }; +struct Z2 { const R &x, y; }; +Z2 z2 = { R{1}, z2.x.x = 10 }; + +// CHECK: __cxa_atexit({{.*}} @_ZN1BD1Ev, {{.*}} @b + +// CHECK: define +// CHECK-NOT: @_ZGRN21ModifyStaticTemporary1cE_ +// CHECK: store {{.*}} @_ZGRN21ModifyStaticTemporary1cE_, {{.*}} @_ZN21ModifyStaticTemporary1cE +// CHECK: add +// CHECK: store +// CHECK: load {{.*}} @_ZN21ModifyStaticTemporary1bE +// CHECK: store {{.*}} @_ZN21ModifyStaticTemporary1cE diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp index 10c62a43ef33b4..f43be1d3c0403d 100644 --- a/clang/test/AST/Interp/functions.cpp +++ b/clang/test/AST/Interp/functions.cpp @@ -473,6 +473,10 @@ namespace AddressOf { constexpr _Complex float F = {3, 4}; static_assert(__builtin_addressof(F) == &F, ""); + + void testAddressof(int x) { + static_assert(&x == __builtin_addressof(x), ""); + } } namespace std { diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp index 5a29013a053a20..a7a602ec355d5f 100644 --- a/clang/test/AST/Interp/literals.cpp +++ b/clang/test/AST/Interp/literals.cpp @@ -45,6 +45,8 @@ constexpr int Failed2 = Failed1 + 1; // both-error {{must be initialized by a co static_assert(Failed2 == 0, ""); // both-error {{not an integral constant expression}} \ // both-note {{initializer of 'Failed2' is not a constant expression}} +const int x = *(volatile int*)0x1234; + namespace ScalarTypes { constexpr int ScalarInitInt = int(); static_assert(ScalarInitInt == 0, ""); @@ -1211,6 +1213,18 @@ constexpr int externvar1() { // both-error {{never produces a constant expressio return arr[0]; // ref-note {{read of non-constexpr variable 'arr'}} \ // expected-note {{indexing of array without known bound}} } + +namespace StmtExprs { + constexpr int foo() { + ({ + int i; + for (i = 0; i < 76; i++) {} + i; // both-warning {{expression result unused}} + }); + return 76; + } + static_assert(foo() == 76, ""); +} #endif namespace Extern { diff --git a/clang/test/AST/Interp/mutable.cpp b/clang/test/AST/Interp/mutable.cpp new file mode 100644 index 00000000000000..aebbea920578c6 --- /dev/null +++ b/clang/test/AST/Interp/mutable.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++11 -verify=expected,expected11,both,both11 %s +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++14 -verify=expected,expected14,both %s +// RUN: %clang_cc1 -std=c++11 -verify=ref,ref11,both,both11 %s +// RUN: %clang_cc1 -std=c++14 -verify=ref,ref14,both %s + + + + + +namespace Simple { + struct S { + mutable int a; // both-note {{declared here}} \ + // both11-note {{declared here}} + int a2; + }; + + constexpr S s{12, 24}; + static_assert(s.a == 12, ""); // both-error {{not an integral constant expression}} \ + // both-note {{read of mutable member 'a'}} + static_assert(s.a2 == 24, ""); + + + constexpr S s2{12, s2.a}; // both11-error {{must be initialized by a constant expression}} \ + // both11-note {{read of mutable member 'a'}} \ + // both11-note {{declared here}} + static_assert(s2.a2 == 12, ""); // both11-error {{not an integral constant expression}} \ + // both11-note {{initializer of 's2' is not a constant expression}} +} diff --git a/clang/test/AST/Interp/references.cpp b/clang/test/AST/Interp/references.cpp index efb756545b4aa1..9a790dc75d7308 100644 --- a/clang/test/AST/Interp/references.cpp +++ b/clang/test/AST/Interp/references.cpp @@ -130,3 +130,8 @@ const char (&nonextended_string_ref)[3] = {"hi"}; static_assert(nonextended_string_ref[0] == 'h', ""); static_assert(nonextended_string_ref[1] == 'i', ""); static_assert(nonextended_string_ref[2] == '\0', ""); + +/// This isa non-constant context. Reading A is not allowed, +/// but taking its address is. +int &&A = 12; +int arr[!&A]; diff --git a/clang/test/Analysis/analyzer-checker-option-help.c b/clang/test/Analysis/analyzer-checker-option-help.c index 5f95569e58498e..c95b8e7064c5f7 100644 --- a/clang/test/Analysis/analyzer-checker-option-help.c +++ b/clang/test/Analysis/analyzer-checker-option-help.c @@ -34,27 +34,7 @@ // CHECK-STABLE: OPTIONS: // // CHECK-STABLE: cplusplus.Move:WarnOn -// CHECK-STABLE-SAME: (string) In non-aggressive mode, only warn -// CHECK-STABLLE: on use-after-move of local variables (or -// CHECK-STABLLE: local rvalue references) and of STL objects. -// CHECK-STABLLE: The former is possible because local variables -// CHECK-STABLLE: (or local rvalue references) are not tempting -// CHECK-STABLLE: their user to re-use the storage. The latter -// CHECK-STABLLE: is possible because STL objects are known -// CHECK-STABLLE: to end up in a valid but unspecified state -// CHECK-STABLLE: after the move and their state-reset methods -// CHECK-STABLLE: are also known, which allows us to predict -// CHECK-STABLLE: precisely when use-after-move is invalid. -// CHECK-STABLLE: Some STL objects are known to conform to -// CHECK-STABLLE: additional contracts after move, so they -// CHECK-STABLLE: are not tracked. However, smart pointers -// CHECK-STABLLE: specifically are tracked because we can -// CHECK-STABLLE: perform extra checking over them. In aggressive -// CHECK-STABLLE: mode, warn on any use-after-move because -// CHECK-STABLLE: the user has intentionally asked us to completely -// CHECK-STABLLE: eliminate use-after-move in his code. Values: -// CHECK-STABLLE: "KnownsOnly", "KnownsAndLocals", "All". -// CHECK-STABLLE: (default: KnownsAndLocals) +// CHECK-STABLE-SAME: (string) With setting "KnownsOnly" warn // CHECK-STABLE-NOT: debug.AnalysisOrder:* // CHECK-DEVELOPER: debug.AnalysisOrder:* diff --git a/clang/test/Analysis/casts.c b/clang/test/Analysis/casts.c index 7dad4edfa89b99..462a9865f15640 100644 --- a/clang/test/Analysis/casts.c +++ b/clang/test/Analysis/casts.c @@ -129,7 +129,7 @@ void locAsIntegerCasts(void *p) { } void multiDimensionalArrayPointerCasts(void) { - static int x[10][10]; + static int x[10][10]; // expected-note2{{Array at the right-hand side of subtraction}} int *y1 = &(x[3][5]); char *z = ((char *) y1) + 2; int *y2 = (int *)(z - 2); diff --git a/clang/test/Analysis/pointer-sub-notes.c b/clang/test/Analysis/pointer-sub-notes.c new file mode 100644 index 00000000000000..6e347557354226 --- /dev/null +++ b/clang/test/Analysis/pointer-sub-notes.c @@ -0,0 +1,66 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.core.PointerSub -analyzer-output=text -verify %s + +void negative_1() { + int a[3]; + int x = -1; + // FIXME: should indicate that 'x' is -1 + int d = &a[x] - &a[0]; // expected-warning{{Using a negative array index at pointer subtraction is undefined behavior}} \ + // expected-note{{Using a negative array index at pointer subtraction is undefined behavior}} +} + +void negative_2() { + int a[3]; + int *p1 = a, *p2 = a; + --p2; + // FIXME: should indicate that 'p2' is negative + int d = p1 - p2; // expected-warning{{Using a negative array index at pointer subtraction is undefined behavior}} \ + // expected-note{{Using a negative array index at pointer subtraction is undefined behavior}} +} + +void different_1() { + int a[3]; // expected-note{{Array at the left-hand side of subtraction}} + int b[3]; // expected-note{{Array at the right-hand side of subtraction}} + int d = &a[2] - &b[0]; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}} \ + // expected-note{{Subtraction of two pointers that do not point into the same array is undefined behavior}} +} + +void different_2() { + int a[3]; // expected-note{{Array at the right-hand side of subtraction}} + int b[3]; // expected-note{{Array at the left-hand side of subtraction}} + int *p1 = a + 1; + int *p2 = b; + int d = p2 - p1; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}} \ + // expected-note{{Subtraction of two pointers that do not point into the same array is undefined behavior}} +} + +int different_3() { + struct { + int array[5]; + } a, b; + return &a.array[3] - &b.array[2]; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}} \ + // expected-note{{Subtraction of two pointers that do not point into the same array is undefined behavior}} +} + +int different_4() { + struct { + int array1[5]; // expected-note{{Array at the left-hand side of subtraction}} + int array2[5]; // expected-note{{Array at the right-hand side of subtraction}} + } a; + return &a.array1[3] - &a.array2[4]; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}} \ + // expected-note{{Subtraction of two pointers that do not point into the same array is undefined behavior}} +} + +void different_5() { + int d; + static int x[10][10]; // expected-note2{{Array at the left-hand side of subtraction}} + int *y1 = &(x[3][5]); + char *z = ((char *) y1) + 2; + int *y2 = (int *)(z - 2); + int *y3 = ((int *)x) + 35; // This is offset for [3][5]. + + d = y2 - y1; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}} \ + // expected-note{{Subtraction of two pointers that do not point into the same array is undefined behavior}} + d = y3 - y1; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}} \ + // expected-note{{Subtraction of two pointers that do not point into the same array is undefined behavior}} + d = y3 - y2; +} diff --git a/clang/test/Analysis/pointer-sub.c b/clang/test/Analysis/pointer-sub.c index 9a446547e2868f..88e6dec2d172f8 100644 --- a/clang/test/Analysis/pointer-sub.c +++ b/clang/test/Analysis/pointer-sub.c @@ -19,7 +19,8 @@ void f1(void) { } void f2(void) { - int a[10], b[10], c; + int a[10], b[10], c; // expected-note{{Array at the left-hand side of subtraction}} \ + // expected-note2{{Array at the right-hand side of subtraction}} int *p = &a[2]; int *q = &a[8]; int d = q - p; // no-warning (pointers into the same array) @@ -41,7 +42,8 @@ void f2(void) { } void f3(void) { - int a[3][4]; + int a[3][4]; // expected-note{{Array at the left-hand side of subtraction}} \ + // expected-note2{{Array at the right-hand side of subtraction}} int d; d = &(a[2]) - &(a[1]); @@ -74,8 +76,8 @@ void f4(void) { typedef struct { int a; int b; - int c[10]; - int d[10]; + int c[10]; // expected-note2{{Array at the right-hand side of subtraction}} + int d[10]; // expected-note2{{Array at the left-hand side of subtraction}} } S; void f5(void) { @@ -100,8 +102,8 @@ void f6(void) { char *a1 = (char *)&l; int d = a1[3] - l; - long long la1[3]; - long long la2[3]; + long long la1[3]; // expected-note{{Array at the right-hand side of subtraction}} + long long la2[3]; // expected-note{{Array at the left-hand side of subtraction}} char *pla1 = (char *)la1; char *pla2 = (char *)la2; d = pla1[1] - pla1[0]; diff --git a/clang/test/Analysis/stream-notes-missing-close.cpp b/clang/test/Analysis/stream-notes-missing-close.cpp new file mode 100644 index 00000000000000..272ca96c76ee18 --- /dev/null +++ b/clang/test/Analysis/stream-notes-missing-close.cpp @@ -0,0 +1,179 @@ +// RUN: %clang_analyze_cc1 -verify %s -analyzer-output=text \ +// RUN: -analyzer-checker=core \ +// RUN: -analyzer-checker=unix.Stream + + +#include "Inputs/system-header-simulator.h" +char *logDump(); +bool coin(); + +[[noreturn]] void halt(); + +void assert(bool b) { + if (!b) + halt(); +} + +//===----------------------------------------------------------------------===// +// Report for which we expect NoOwnershipChangeVisitor to add a new note. +//===----------------------------------------------------------------------===// + +namespace stream_opened_in_fn_call { +// TODO: AST analysis of sink would reveal that it doesn't intent to free the +// allocated memory, but in this instance, its also the only function with +// the ability to do so, we should see a note here. +void sink(FILE *f) { +} + +void f() { + sink(fopen("input.txt", "w")); + // expected-note@-1{{Stream opened here}} +} // expected-warning{{Opened stream never closed. Potential resource leak [unix.Stream]}} +// expected-note@-1{{Opened stream never closed. Potential resource leak}} +} // namespace stream_opened_in_fn_call + +namespace stream_passed_to_fn_call { + +void expectedClose(FILE *f) { + if (char *log = logDump()) { // expected-note{{Assuming 'log' is null}} + // expected-note@-1{{Taking false branch}} + printf("%s", log); + fclose(f); + } +} // expected-note{{Returning without closing stream object or storing it for later release}} + +void f() { + FILE *f = fopen("input.txt", "w"); // expected-note{{Stream opened here}} + if (!f) // expected-note{{'f' is non-null}} + // expected-note@-1{{Taking false branch}} + return; + if (coin()) { // expected-note{{Assuming the condition is true}} + // expected-note@-1{{Taking true branch}} + expectedClose(f); // expected-note{{Calling 'expectedClose'}} + // expected-note@-1{{Returning from 'expectedClose'}} + + return; // expected-warning{{Opened stream never closed. Potential resource leak [unix.Stream]}} + // expected-note@-1{{Opened stream never closed. Potential resource leak}} + } + fclose(f); +} +} // namespace stream_passed_to_fn_call + +namespace stream_shared_with_ptr_of_shorter_lifetime { + +void sink(FILE *f) { + FILE *Q = f; + if (coin()) // expected-note {{Assuming the condition is false}} + // expected-note@-1 {{Taking false branch}} + fclose(f); + (void)Q; +} // expected-note{{Returning without closing stream object or storing it for later release}} + +void foo() { + FILE *f = fopen("input.txt", "w"); // expected-note{{Stream opened here}} + if (!f) // expected-note{{'f' is non-null}} + // expected-note@-1{{Taking false branch}} + return; + sink(f); // expected-note {{Calling 'sink'}} + // expected-note@-1 {{Returning from 'sink'}} +} // expected-warning{{Opened stream never closed. Potential resource leak [unix.Stream]}} +// expected-note@-1{{Opened stream never closed. Potential resource leak}} + +} // namespace stream_shared_with_ptr_of_shorter_lifetime + +//===----------------------------------------------------------------------===// +// Report for which we *do not* expect NoOwnershipChangeVisitor add a new note, +// nor do we want it to. +//===----------------------------------------------------------------------===// + +namespace stream_not_passed_to_fn_call { + +void expectedClose(FILE *f) { + if (char *log = logDump()) { + printf("%s", log); + fclose(f); + } +} + +void f(FILE *p) { + FILE *f = fopen("input.txt", "w"); // expected-note{{Stream opened here}} + if (!f) // expected-note{{'f' is non-null}} + // expected-note@-1{{Taking false branch}} + return; + expectedClose(p); // expected-warning{{Opened stream never closed. Potential resource leak [unix.Stream]}} + // expected-note@-1{{Opened stream never closed. Potential resource leak}} +} +} // namespace stream_not_passed_to_fn_call + +namespace stream_shared_with_ptr_of_same_lifetime { + +void expectedClose(FILE *f, FILE **p) { + // NOTE: Not a job of NoOwnershipChangeVisitor, but maybe this could be + // highlighted still? + *p = f; +} + +void f() { + FILE *f = fopen("input.txt", "w"); // expected-note{{Stream opened here}} + FILE *p = NULL; + if (!f) // expected-note{{'f' is non-null}} + // expected-note@-1{{Taking false branch}} + return; + expectedClose(f, &p); +} // expected-warning{{Opened stream never closed. Potential resource leak [unix.Stream]}} + // expected-note@-1{{Opened stream never closed. Potential resource leak}} +} // namespace stream_shared_with_ptr_of_same_lifetime + +namespace stream_passed_into_fn_that_doesnt_intend_to_free { +void expectedClose(FILE *f) { +} + +void f() { + FILE *f = fopen("input.txt", "w"); // expected-note{{Stream opened here}} + if (!f) // expected-note{{'f' is non-null}} + // expected-note@-1{{Taking false branch}} + return; + expectedClose(f); + +} // expected-warning{{Opened stream never closed. Potential resource leak [unix.Stream]}} + // expected-note@-1{{Opened stream never closed. Potential resource leak}} +} // namespace stream_passed_into_fn_that_doesnt_intend_to_free + +namespace stream_passed_into_fn_that_doesnt_intend_to_free2 { +void bar(); + +void expectedClose(FILE *f) { + // Correctly realize that calling bar() doesn't mean that this function would + // like to deallocate anything. + bar(); +} + +void f() { + FILE *f = fopen("input.txt", "w"); // expected-note{{Stream opened here}} + if (!f) // expected-note{{'f' is non-null}} + // expected-note@-1{{Taking false branch}} + return; + expectedClose(f); + +} // expected-warning{{Opened stream never closed. Potential resource leak [unix.Stream]}} + // expected-note@-1{{Opened stream never closed. Potential resource leak}} +} // namespace stream_passed_into_fn_that_doesnt_intend_to_free2 + +namespace streamstate_from_closed_to_open { + +// StreamState of the symbol changed from nothing to Allocated. We don't want to +// emit notes when the RefKind changes in the stack frame. +static FILE *fopenWrapper() { + FILE *f = fopen("input.txt", "w"); // expected-note{{Stream opened here}} + assert(f); + return f; +} +void use_ret() { + FILE *v; + v = fopenWrapper(); // expected-note {{Calling 'fopenWrapper'}} + // expected-note@-1{{Returning from 'fopenWrapper'}} + +} // expected-warning{{Opened stream never closed. Potential resource leak [unix.Stream]}} + // expected-note@-1{{Opened stream never closed. Potential resource leak}} + +} // namespace streamstate_from_closed_to_open diff --git a/clang/test/C/C11/n1285.c b/clang/test/C/C11/n1285.c new file mode 100644 index 00000000000000..e7a9463e68103a --- /dev/null +++ b/clang/test/C/C11/n1285.c @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -verify=wrong -std=c99 %s +// RUN: %clang_cc1 -verify=wrong -std=c11 %s +// RUN: %clang_cc1 -verify=cpp -std=c++11 -x c++ %s + +/* WG14 N1285: No + * Extending the lifetime of temporary objects (factored approach) + * + * NB: we do not properly materialize temporary expressions in situations where + * it would be expected; that is why the "no-diagnostics" marking is named + * "wrong". We do issue the expected diagnostic in C++ mode. + */ + +// wrong-no-diagnostics + +struct X { int a[5]; }; +struct X f(void); + +int foo(void) { + // FIXME: This diagnostic should be issued in C11 as well (though not in C99, + // as this paper was a breaking change between C99 and C11). + int *p = f().a; // cpp-warning {{temporary whose address is used as value of local variable 'p' will be destroyed at the end of the full-expression}} + return *p; +} + diff --git a/clang/test/C/C2x/n2819.c b/clang/test/C/C2x/n2819.c new file mode 100644 index 00000000000000..c428fbba802453 --- /dev/null +++ b/clang/test/C/C2x/n2819.c @@ -0,0 +1,57 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 3 +// RUN: %clang_cc1 -triple=x86_64 -emit-llvm -o - -std=c23 %s | FileCheck %s + +/* WG14 N2819: No + * Disambiguate the storage class of some compound literals + */ + +int *escaped; +// CHECK-LABEL: define dso_local i32 @f( +// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: store ptr [[TMP0]], ptr @escaped, align 8 +// CHECK-NEXT: ret i32 1 +// +int f(int *ptr) { escaped = ptr; return 1; } + +// CHECK-LABEL: define dso_local i32 @g( +// CHECK-SAME: ptr noundef [[PARA:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[PARA_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[PARA]], ptr [[PARA_ADDR]], align 8 +// CHECK-NEXT: [[CALL:%.*]] = call i32 @f(ptr noundef @.compoundliteral) +// CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[CALL]] to i64 +// CHECK-NEXT: ret i32 0 +// +// FIXME: notice the we are using the global .compoundliteral object, not +// allocating a new object on each call to g(). That's what was clarified by +// N2819. +int g(char *para [f(( int [27]) { 0 })]) { + return 0; +} + +// CHECK-LABEL: define dso_local i32 @main( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[RETVAL:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 0, ptr [[RETVAL]], align 4 +// CHECK-NEXT: [[CALL:%.*]] = call i32 @g(ptr noundef null) +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr @escaped, align 8 +// CHECK-NEXT: store i32 12, ptr [[TMP0]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr @escaped, align 8 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[TMP1]], align 4 +// CHECK-NEXT: ret i32 [[TMP2]] +// +int main() { + // Sets 'escaped' to the address of the array created by the compound literal. + g(nullptr); + + // The lifetime of that object should have ended when g() returned, so this + // should be a use-after-free. + *escaped = 12; + return *escaped; +} + diff --git a/clang/test/C/C2x/n3033.c b/clang/test/C/C2x/n3033.c new file mode 100644 index 00000000000000..bf249a37facb37 --- /dev/null +++ b/clang/test/C/C2x/n3033.c @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -std=c23 -E %s | FileCheck %s + +/* WG14 N3033: Clang 12 + * Comma ommission and deletion (__VA_OPT__) + */ + +#define F(...) f(0 __VA_OPT__(,) __VA_ARGS__) +#define G(X, ...) f(0, X __VA_OPT__(,) __VA_ARGS__) +#define SDEF(sname, ...) S sname __VA_OPT__(= { __VA_ARGS__ }) +#define EMP + +F(a, b, c) // replaced by f(0, a, b, c) +// CHECK: f(0 , a, b, c) +F() // replaced by f(0) +// CHECK: f(0 ) +F(EMP) // replaced by f(0) +// CHECK: f(0 ) + +G(a, b, c) // replaced by f(0, a, b, c) +// CHECK: f(0, a , b, c) +G(a, ) // replaced by f(0, a) +// CHECK: f(0, a ) +G(a) // replaced by f(0, a) +// CHECK: f(0, a ) + +SDEF(foo); // replaced by S foo; +// CHECK: S foo ; +SDEF(bar, 1, 2); // replaced by S bar = { 1, 2 }; +// CHECK: S bar = { 1, 2 }; + +//#define H1(X, ...) X __VA_OPT__(##) __VA_ARGS__ // error: ## may not appear at the beginning of a replacement list (6.10.3.3) + +#define H2(X, Y, ...) __VA_OPT__(X ## Y,) __VA_ARGS__ +H2(a, b, c, d) // replaced by ab, c, d +// CHECK: ab, c, d + +#define H3(X, ...) #__VA_OPT__(X##X X##X) +H3(, 0) // replaced by "" +// CHECK: "" + +#define H4(X, ...) __VA_OPT__(a X ## X) ## b +H4(, 1) // replaced by a b +// CHECK: a b + +#define H5A(...) __VA_OPT__()/**/__VA_OPT__() +#define H5B(X) a ## X ## b +#define H5C(X) H5B(X) +H5C(H5A()) // replaced by ab +// CHECK: ab + diff --git a/clang/test/C/C2x/n3033_2.c b/clang/test/C/C2x/n3033_2.c new file mode 100644 index 00000000000000..5da206658690cd --- /dev/null +++ b/clang/test/C/C2x/n3033_2.c @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c23 -verify %s + +#define H1(X, ...) X __VA_OPT__(##) __VA_ARGS__ // expected-error {{'##' cannot appear at start of __VA_OPT__ argument}} + diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p1.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p1.cpp index f6b5d2487e73d0..9efa7b67f5bdbd 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p1.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p1.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify=expected,spec %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wno-explicit-specialization-storage-class %s // A storage-class-specifier shall not be specified in an explicit // specialization (14.7.3) or an explicit instantiation (14.7.2) @@ -7,13 +8,13 @@ template void f(T) {} template static void g(T) {} -template<> static void f(int); // expected-warning{{explicit specialization cannot have a storage class}} +template<> static void f(int); // spec-warning{{explicit specialization cannot have a storage class}} template static void f(float); // expected-error{{explicit instantiation cannot have a storage class}} template<> void f(double); template void f(long); -template<> static void g(int); // expected-warning{{explicit specialization cannot have a storage class}} +template<> static void g(int); // spec-warning{{explicit specialization cannot have a storage class}} template static void g(float); // expected-error{{explicit instantiation cannot have a storage class}} template<> void g(double); @@ -29,5 +30,12 @@ int X::value = 17; template static int X::value; // expected-error{{explicit instantiation cannot have a storage class}} -template<> static int X::value; // expected-warning{{explicit specialization cannot have a storage class}} +template<> static int X::value; // spec-warning{{explicit specialization cannot have a storage class}} // expected-error@-1{{'static' can only be specified inside the class definition}} + +struct t1 { + template + static void f1(); + template<> + static void f1(); // spec-warning{{explicit specialization cannot have a storage class}} +}; diff --git a/clang/test/CodeGen/PowerPC/inline-asm-constraints-error.c b/clang/test/CodeGen/PowerPC/inline-asm-constraints-error.c new file mode 100644 index 00000000000000..2f35e52fc0b77c --- /dev/null +++ b/clang/test/CodeGen/PowerPC/inline-asm-constraints-error.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -emit-llvm-only -triple powerpc64-ibm-aix-xcoff -verify %s +// RUN: %clang_cc1 -emit-llvm-only -triple powerpc-ibm-aix-xcoff -verify %s +// This test case exist to test marking the 'a' inline assembly constraint as +// unsupported because powerpc previously marked it as supported. +int foo(int arg){ + asm goto ("bc 12,2,%l[TEST_LABEL]" : : "a"(&&TEST_LABEL) : : TEST_LABEL); //expected-error {{invalid input constraint 'a' in asm}} + return 0; +TEST_LABEL: return arg + 1; +} diff --git a/clang/test/CodeGen/aarch64-mixed-target-attributes.c b/clang/test/CodeGen/aarch64-mixed-target-attributes.c index 6aa747d4cb4617..3c047fec6ceedb 100644 --- a/clang/test/CodeGen/aarch64-mixed-target-attributes.c +++ b/clang/test/CodeGen/aarch64-mixed-target-attributes.c @@ -30,9 +30,6 @@ __attribute__((target_version("jscvt"))) int default_def_with_version_decls(void //. // CHECK: @__aarch64_cpu_features = external dso_local global { i64 } -// CHECK: @explicit_default.ifunc = weak_odr alias i32 (), ptr @explicit_default -// CHECK: @implicit_default.ifunc = weak_odr alias i32 (), ptr @implicit_default -// CHECK: @default_def_with_version_decls.ifunc = weak_odr alias i32 (), ptr @default_def_with_version_decls // CHECK: @explicit_default = weak_odr ifunc i32 (), ptr @explicit_default.resolver // CHECK: @implicit_default = weak_odr ifunc i32 (), ptr @implicit_default.resolver // CHECK: @default_def_with_version_decls = weak_odr ifunc i32 (), ptr @default_def_with_version_decls.resolver diff --git a/clang/test/CodeGen/aarch64-sme2p1-intrinsics/acle_sme2p1_movaz.c b/clang/test/CodeGen/aarch64-sme2p1-intrinsics/acle_sme2p1_movaz.c new file mode 100644 index 00000000000000..7c9067a5ceece3 --- /dev/null +++ b/clang/test/CodeGen/aarch64-sme2p1-intrinsics/acle_sme2p1_movaz.c @@ -0,0 +1,1825 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 4 +// REQUIRES: aarch64-registered-target +//RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme2p1 -target-feature +sme -target-feature +bf16 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme2p1 -target-feature +sme -target-feature +bf16 -disable-O0-optnone -Werror -Wall -emit-llvm -o - -x c++ %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CPP-CHECK +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme2p1 -target-feature +sme -target-feature +bf16 -S -disable-O0-optnone -Werror -Wall -o /dev/null %s + +#include + +// +// X2- hor +// CHECK-LABEL: define dso_local @test_svreadz_hor_za8_s8_x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.horiz.x2.nxv16i8(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv32i8.nxv16i8( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32i8.nxv16i8( [[TMP2]], [[TMP3]], i64 16) +// CHECK-NEXT: ret [[TMP4]] +// +// CPP-CHECK-LABEL: define dso_local @_Z26test_svreadz_hor_za8_s8_x2j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0:[0-9]+]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.horiz.x2.nxv16i8(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv32i8.nxv16i8( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32i8.nxv16i8( [[TMP2]], [[TMP3]], i64 16) +// CPP-CHECK-NEXT: ret [[TMP4]] +// +svint8x2_t test_svreadz_hor_za8_s8_x2(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za8_s8_vg2(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za8_u8_x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.horiz.x2.nxv16i8(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv32i8.nxv16i8( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32i8.nxv16i8( [[TMP2]], [[TMP3]], i64 16) +// CHECK-NEXT: ret [[TMP4]] +// +// CPP-CHECK-LABEL: define dso_local @_Z26test_svreadz_hor_za8_u8_x2j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.horiz.x2.nxv16i8(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv32i8.nxv16i8( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32i8.nxv16i8( [[TMP2]], [[TMP3]], i64 16) +// CPP-CHECK-NEXT: ret [[TMP4]] +// +svuint8x2_t test_svreadz_hor_za8_u8_x2(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za8_u8_vg2(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za16_s16_x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.horiz.x2.nxv8i16(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16i16.nxv8i16( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16i16.nxv8i16( [[TMP2]], [[TMP3]], i64 8) +// CHECK-NEXT: ret [[TMP4]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_hor_za16_s16_x2j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.horiz.x2.nxv8i16(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16i16.nxv8i16( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16i16.nxv8i16( [[TMP2]], [[TMP3]], i64 8) +// CPP-CHECK-NEXT: ret [[TMP4]] +// +svint16x2_t test_svreadz_hor_za16_s16_x2(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za16_s16_vg2(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za16_u16_x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.horiz.x2.nxv8i16(i32 1, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16i16.nxv8i16( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16i16.nxv8i16( [[TMP2]], [[TMP3]], i64 8) +// CHECK-NEXT: ret [[TMP4]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_hor_za16_u16_x2j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.horiz.x2.nxv8i16(i32 1, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16i16.nxv8i16( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16i16.nxv8i16( [[TMP2]], [[TMP3]], i64 8) +// CPP-CHECK-NEXT: ret [[TMP4]] +// +svuint16x2_t test_svreadz_hor_za16_u16_x2(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za16_u16_vg2(1, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za16_f16_x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.horiz.x2.nxv8f16(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16f16.nxv8f16( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16f16.nxv8f16( [[TMP2]], [[TMP3]], i64 8) +// CHECK-NEXT: ret [[TMP4]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_hor_za16_f16_x2j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.horiz.x2.nxv8f16(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16f16.nxv8f16( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16f16.nxv8f16( [[TMP2]], [[TMP3]], i64 8) +// CPP-CHECK-NEXT: ret [[TMP4]] +// +svfloat16x2_t test_svreadz_hor_za16_f16_x2(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za16_f16_vg2(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za16_bf16_x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.horiz.x2.nxv8bf16(i32 1, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16bf16.nxv8bf16( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16bf16.nxv8bf16( [[TMP2]], [[TMP3]], i64 8) +// CHECK-NEXT: ret [[TMP4]] +// +// CPP-CHECK-LABEL: define dso_local @_Z29test_svreadz_hor_za16_bf16_x2j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.horiz.x2.nxv8bf16(i32 1, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16bf16.nxv8bf16( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16bf16.nxv8bf16( [[TMP2]], [[TMP3]], i64 8) +// CPP-CHECK-NEXT: ret [[TMP4]] +// +svbfloat16x2_t test_svreadz_hor_za16_bf16_x2(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za16_bf16_vg2(1, slice); +} + + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za32_s32_x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.horiz.x2.nxv4i32(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv8i32.nxv4i32( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8i32.nxv4i32( [[TMP2]], [[TMP3]], i64 4) +// CHECK-NEXT: ret [[TMP4]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_hor_za32_s32_x2j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.horiz.x2.nxv4i32(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv8i32.nxv4i32( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8i32.nxv4i32( [[TMP2]], [[TMP3]], i64 4) +// CPP-CHECK-NEXT: ret [[TMP4]] +// +svint32x2_t test_svreadz_hor_za32_s32_x2(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za32_s32_vg2(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za32_u32_x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.horiz.x2.nxv4i32(i32 2, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv8i32.nxv4i32( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8i32.nxv4i32( [[TMP2]], [[TMP3]], i64 4) +// CHECK-NEXT: ret [[TMP4]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_hor_za32_u32_x2j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.horiz.x2.nxv4i32(i32 2, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv8i32.nxv4i32( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8i32.nxv4i32( [[TMP2]], [[TMP3]], i64 4) +// CPP-CHECK-NEXT: ret [[TMP4]] +// +svuint32x2_t test_svreadz_hor_za32_u32_x2(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za32_u32_vg2(2, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za32_f32_x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.horiz.x2.nxv4f32(i32 3, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv8f32.nxv4f32( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8f32.nxv4f32( [[TMP2]], [[TMP3]], i64 4) +// CHECK-NEXT: ret [[TMP4]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_hor_za32_f32_x2j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.horiz.x2.nxv4f32(i32 3, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv8f32.nxv4f32( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8f32.nxv4f32( [[TMP2]], [[TMP3]], i64 4) +// CPP-CHECK-NEXT: ret [[TMP4]] +// +svfloat32x2_t test_svreadz_hor_za32_f32_x2(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za32_f32_vg2(3, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za64_s64_x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.horiz.x2.nxv2i64(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv4i64.nxv2i64( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv4i64.nxv2i64( [[TMP2]], [[TMP3]], i64 2) +// CHECK-NEXT: ret [[TMP4]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_hor_za64_s64_x2j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.horiz.x2.nxv2i64(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv4i64.nxv2i64( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv4i64.nxv2i64( [[TMP2]], [[TMP3]], i64 2) +// CPP-CHECK-NEXT: ret [[TMP4]] +// +svint64x2_t test_svreadz_hor_za64_s64_x2(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za64_s64_vg2(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za64_u64_x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.horiz.x2.nxv2i64(i32 4, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv4i64.nxv2i64( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv4i64.nxv2i64( [[TMP2]], [[TMP3]], i64 2) +// CHECK-NEXT: ret [[TMP4]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_hor_za64_u64_x2j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.horiz.x2.nxv2i64(i32 4, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv4i64.nxv2i64( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv4i64.nxv2i64( [[TMP2]], [[TMP3]], i64 2) +// CPP-CHECK-NEXT: ret [[TMP4]] +// +svuint64x2_t test_svreadz_hor_za64_u64_x2(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za64_u64_vg2(4, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za64_f64_x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.horiz.x2.nxv2f64(i32 7, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv4f64.nxv2f64( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv4f64.nxv2f64( [[TMP2]], [[TMP3]], i64 2) +// CHECK-NEXT: ret [[TMP4]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_hor_za64_f64_x2j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.horiz.x2.nxv2f64(i32 7, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv4f64.nxv2f64( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv4f64.nxv2f64( [[TMP2]], [[TMP3]], i64 2) +// CPP-CHECK-NEXT: ret [[TMP4]] +// +svfloat64x2_t test_svreadz_hor_za64_f64_x2(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za64_f64_vg2(7, slice); +} + + +// +// X2- ver +// + +// CHECK-LABEL: define dso_local @test_svreadz_ver_za8_s8_x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.vert.x2.nxv16i8(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv32i8.nxv16i8( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32i8.nxv16i8( [[TMP2]], [[TMP3]], i64 16) +// CHECK-NEXT: ret [[TMP4]] +// +// CPP-CHECK-LABEL: define dso_local @_Z26test_svreadz_ver_za8_s8_x2j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.vert.x2.nxv16i8(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv32i8.nxv16i8( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32i8.nxv16i8( [[TMP2]], [[TMP3]], i64 16) +// CPP-CHECK-NEXT: ret [[TMP4]] +// +svint8x2_t test_svreadz_ver_za8_s8_x2(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_ver_za8_s8_vg2(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_ver_za8_u8_x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.vert.x2.nxv16i8(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv32i8.nxv16i8( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32i8.nxv16i8( [[TMP2]], [[TMP3]], i64 16) +// CHECK-NEXT: ret [[TMP4]] +// +// CPP-CHECK-LABEL: define dso_local @_Z26test_svreadz_ver_za8_u8_x2j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.vert.x2.nxv16i8(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv32i8.nxv16i8( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32i8.nxv16i8( [[TMP2]], [[TMP3]], i64 16) +// CPP-CHECK-NEXT: ret [[TMP4]] +// +svuint8x2_t test_svreadz_ver_za8_u8_x2(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_ver_za8_u8_vg2(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_ver_za16_s16_x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.vert.x2.nxv8i16(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16i16.nxv8i16( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16i16.nxv8i16( [[TMP2]], [[TMP3]], i64 8) +// CHECK-NEXT: ret [[TMP4]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_ver_za16_s16_x2j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.vert.x2.nxv8i16(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16i16.nxv8i16( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16i16.nxv8i16( [[TMP2]], [[TMP3]], i64 8) +// CPP-CHECK-NEXT: ret [[TMP4]] +// +svint16x2_t test_svreadz_ver_za16_s16_x2(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_ver_za16_s16_vg2(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_ver_za16_u16_x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.vert.x2.nxv8i16(i32 1, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16i16.nxv8i16( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16i16.nxv8i16( [[TMP2]], [[TMP3]], i64 8) +// CHECK-NEXT: ret [[TMP4]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_ver_za16_u16_x2j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.vert.x2.nxv8i16(i32 1, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16i16.nxv8i16( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16i16.nxv8i16( [[TMP2]], [[TMP3]], i64 8) +// CPP-CHECK-NEXT: ret [[TMP4]] +// +svuint16x2_t test_svreadz_ver_za16_u16_x2(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_ver_za16_u16_vg2(1, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_ver_za16_f16_x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.vert.x2.nxv8f16(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16f16.nxv8f16( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16f16.nxv8f16( [[TMP2]], [[TMP3]], i64 8) +// CHECK-NEXT: ret [[TMP4]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_ver_za16_f16_x2j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.vert.x2.nxv8f16(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16f16.nxv8f16( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16f16.nxv8f16( [[TMP2]], [[TMP3]], i64 8) +// CPP-CHECK-NEXT: ret [[TMP4]] +// +svfloat16x2_t test_svreadz_ver_za16_f16_x2(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_ver_za16_f16_vg2(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_ver_za16_bf16_x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.vert.x2.nxv8bf16(i32 1, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16bf16.nxv8bf16( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16bf16.nxv8bf16( [[TMP2]], [[TMP3]], i64 8) +// CHECK-NEXT: ret [[TMP4]] +// +// CPP-CHECK-LABEL: define dso_local @_Z29test_svreadz_ver_za16_bf16_x2j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.vert.x2.nxv8bf16(i32 1, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16bf16.nxv8bf16( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16bf16.nxv8bf16( [[TMP2]], [[TMP3]], i64 8) +// CPP-CHECK-NEXT: ret [[TMP4]] +// +svbfloat16x2_t test_svreadz_ver_za16_bf16_x2(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_ver_za16_bf16_vg2(1, slice); +} + + +// CHECK-LABEL: define dso_local @test_svreadz_ver_za32_s32_x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.vert.x2.nxv4i32(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv8i32.nxv4i32( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8i32.nxv4i32( [[TMP2]], [[TMP3]], i64 4) +// CHECK-NEXT: ret [[TMP4]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_ver_za32_s32_x2j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.vert.x2.nxv4i32(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv8i32.nxv4i32( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8i32.nxv4i32( [[TMP2]], [[TMP3]], i64 4) +// CPP-CHECK-NEXT: ret [[TMP4]] +// +svint32x2_t test_svreadz_ver_za32_s32_x2(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_ver_za32_s32_vg2(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_ver_za32_u32_x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.vert.x2.nxv4i32(i32 2, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv8i32.nxv4i32( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8i32.nxv4i32( [[TMP2]], [[TMP3]], i64 4) +// CHECK-NEXT: ret [[TMP4]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_ver_za32_u32_x2j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.vert.x2.nxv4i32(i32 2, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv8i32.nxv4i32( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8i32.nxv4i32( [[TMP2]], [[TMP3]], i64 4) +// CPP-CHECK-NEXT: ret [[TMP4]] +// +svuint32x2_t test_svreadz_ver_za32_u32_x2(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_ver_za32_u32_vg2(2, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_ver_za32_f32_x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.vert.x2.nxv4f32(i32 3, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv8f32.nxv4f32( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8f32.nxv4f32( [[TMP2]], [[TMP3]], i64 4) +// CHECK-NEXT: ret [[TMP4]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_ver_za32_f32_x2j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.vert.x2.nxv4f32(i32 3, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv8f32.nxv4f32( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8f32.nxv4f32( [[TMP2]], [[TMP3]], i64 4) +// CPP-CHECK-NEXT: ret [[TMP4]] +// +svfloat32x2_t test_svreadz_ver_za32_f32_x2(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_ver_za32_f32_vg2(3, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_ver_za64_s64_x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.vert.x2.nxv2i64(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv4i64.nxv2i64( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv4i64.nxv2i64( [[TMP2]], [[TMP3]], i64 2) +// CHECK-NEXT: ret [[TMP4]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_ver_za64_s64_x2j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.vert.x2.nxv2i64(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv4i64.nxv2i64( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv4i64.nxv2i64( [[TMP2]], [[TMP3]], i64 2) +// CPP-CHECK-NEXT: ret [[TMP4]] +// +svint64x2_t test_svreadz_ver_za64_s64_x2(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_ver_za64_s64_vg2(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_ver_za64_u64_x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.vert.x2.nxv2i64(i32 4, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv4i64.nxv2i64( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv4i64.nxv2i64( [[TMP2]], [[TMP3]], i64 2) +// CHECK-NEXT: ret [[TMP4]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_ver_za64_u64_x2j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.vert.x2.nxv2i64(i32 4, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv4i64.nxv2i64( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv4i64.nxv2i64( [[TMP2]], [[TMP3]], i64 2) +// CPP-CHECK-NEXT: ret [[TMP4]] +// +svuint64x2_t test_svreadz_ver_za64_u64_x2(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_ver_za64_u64_vg2(4, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_ver_za64_f64_x2( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.vert.x2.nxv2f64(i32 7, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv4f64.nxv2f64( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv4f64.nxv2f64( [[TMP2]], [[TMP3]], i64 2) +// CHECK-NEXT: ret [[TMP4]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_ver_za64_f64_x2j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , } @llvm.aarch64.sme.readz.vert.x2.nxv2f64(i32 7, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv4f64.nxv2f64( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv4f64.nxv2f64( [[TMP2]], [[TMP3]], i64 2) +// CPP-CHECK-NEXT: ret [[TMP4]] +// +svfloat64x2_t test_svreadz_ver_za64_f64_x2(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_ver_za64_f64_vg2(7, slice); +} + + +// +// X4 - hor +// CHECK-LABEL: define dso_local @test_svreadz_hor_za8_s8_x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.horiz.x4.nxv16i8(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP2]], [[TMP3]], i64 16) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP4]], [[TMP5]], i64 32) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP6]], [[TMP7]], i64 48) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: define dso_local @_Z26test_svreadz_hor_za8_s8_x4j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.horiz.x4.nxv16i8(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP2]], [[TMP3]], i64 16) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP4]], [[TMP5]], i64 32) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP6]], [[TMP7]], i64 48) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svint8x4_t test_svreadz_hor_za8_s8_x4(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za8_s8_vg4(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za8_u8_x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.horiz.x4.nxv16i8(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP2]], [[TMP3]], i64 16) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP4]], [[TMP5]], i64 32) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP6]], [[TMP7]], i64 48) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: define dso_local @_Z26test_svreadz_hor_za8_u8_x4j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.horiz.x4.nxv16i8(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP2]], [[TMP3]], i64 16) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP4]], [[TMP5]], i64 32) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP6]], [[TMP7]], i64 48) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svuint8x4_t test_svreadz_hor_za8_u8_x4(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za8_u8_vg4(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za16_s16_x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.horiz.x4.nxv8i16(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP2]], [[TMP3]], i64 8) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP4]], [[TMP5]], i64 16) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP6]], [[TMP7]], i64 24) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_hor_za16_s16_x4j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.horiz.x4.nxv8i16(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP2]], [[TMP3]], i64 8) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP4]], [[TMP5]], i64 16) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP6]], [[TMP7]], i64 24) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svint16x4_t test_svreadz_hor_za16_s16_x4(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za16_s16_vg4(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za16_u16_x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.horiz.x4.nxv8i16(i32 1, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP2]], [[TMP3]], i64 8) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP4]], [[TMP5]], i64 16) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP6]], [[TMP7]], i64 24) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_hor_za16_u16_x4j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.horiz.x4.nxv8i16(i32 1, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP2]], [[TMP3]], i64 8) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP4]], [[TMP5]], i64 16) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP6]], [[TMP7]], i64 24) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svuint16x4_t test_svreadz_hor_za16_u16_x4(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za16_u16_vg4(1, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za16_f16_x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.horiz.x4.nxv8f16(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv32f16.nxv8f16( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32f16.nxv8f16( [[TMP2]], [[TMP3]], i64 8) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv32f16.nxv8f16( [[TMP4]], [[TMP5]], i64 16) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv32f16.nxv8f16( [[TMP6]], [[TMP7]], i64 24) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_hor_za16_f16_x4j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.horiz.x4.nxv8f16(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv32f16.nxv8f16( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32f16.nxv8f16( [[TMP2]], [[TMP3]], i64 8) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv32f16.nxv8f16( [[TMP4]], [[TMP5]], i64 16) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv32f16.nxv8f16( [[TMP6]], [[TMP7]], i64 24) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svfloat16x4_t test_svreadz_hor_za16_f16_x4(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za16_f16_vg4(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za16_bf16_x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.horiz.x4.nxv8bf16(i32 1, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv32bf16.nxv8bf16( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32bf16.nxv8bf16( [[TMP2]], [[TMP3]], i64 8) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv32bf16.nxv8bf16( [[TMP4]], [[TMP5]], i64 16) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv32bf16.nxv8bf16( [[TMP6]], [[TMP7]], i64 24) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: define dso_local @_Z29test_svreadz_hor_za16_bf16_x4j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.horiz.x4.nxv8bf16(i32 1, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv32bf16.nxv8bf16( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32bf16.nxv8bf16( [[TMP2]], [[TMP3]], i64 8) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv32bf16.nxv8bf16( [[TMP4]], [[TMP5]], i64 16) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv32bf16.nxv8bf16( [[TMP6]], [[TMP7]], i64 24) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svbfloat16x4_t test_svreadz_hor_za16_bf16_x4(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za16_bf16_vg4(1, slice); +} + + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za32_s32_x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.horiz.x4.nxv4i32(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP2]], [[TMP3]], i64 4) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP4]], [[TMP5]], i64 8) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP6]], [[TMP7]], i64 12) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_hor_za32_s32_x4j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.horiz.x4.nxv4i32(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP2]], [[TMP3]], i64 4) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP4]], [[TMP5]], i64 8) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP6]], [[TMP7]], i64 12) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svint32x4_t test_svreadz_hor_za32_s32_x4(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za32_s32_vg4(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za32_u32_x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.horiz.x4.nxv4i32(i32 2, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP2]], [[TMP3]], i64 4) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP4]], [[TMP5]], i64 8) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP6]], [[TMP7]], i64 12) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_hor_za32_u32_x4j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.horiz.x4.nxv4i32(i32 2, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP2]], [[TMP3]], i64 4) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP4]], [[TMP5]], i64 8) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP6]], [[TMP7]], i64 12) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svuint32x4_t test_svreadz_hor_za32_u32_x4(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za32_u32_vg4(2, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za32_f32_x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.horiz.x4.nxv4f32(i32 3, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16f32.nxv4f32( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16f32.nxv4f32( [[TMP2]], [[TMP3]], i64 4) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv16f32.nxv4f32( [[TMP4]], [[TMP5]], i64 8) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv16f32.nxv4f32( [[TMP6]], [[TMP7]], i64 12) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_hor_za32_f32_x4j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.horiz.x4.nxv4f32(i32 3, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16f32.nxv4f32( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16f32.nxv4f32( [[TMP2]], [[TMP3]], i64 4) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv16f32.nxv4f32( [[TMP4]], [[TMP5]], i64 8) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv16f32.nxv4f32( [[TMP6]], [[TMP7]], i64 12) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svfloat32x4_t test_svreadz_hor_za32_f32_x4(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za32_f32_vg4(3, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za64_s64_x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.horiz.x4.nxv2i64(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP2]], [[TMP3]], i64 2) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP4]], [[TMP5]], i64 4) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP6]], [[TMP7]], i64 6) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_hor_za64_s64_x4j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.horiz.x4.nxv2i64(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP2]], [[TMP3]], i64 2) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP4]], [[TMP5]], i64 4) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP6]], [[TMP7]], i64 6) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svint64x4_t test_svreadz_hor_za64_s64_x4(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za64_s64_vg4(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za64_u64_x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.horiz.x4.nxv2i64(i32 4, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP2]], [[TMP3]], i64 2) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP4]], [[TMP5]], i64 4) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP6]], [[TMP7]], i64 6) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_hor_za64_u64_x4j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.horiz.x4.nxv2i64(i32 4, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP2]], [[TMP3]], i64 2) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP4]], [[TMP5]], i64 4) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP6]], [[TMP7]], i64 6) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svuint64x4_t test_svreadz_hor_za64_u64_x4(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za64_u64_vg4(4, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za64_f64_x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.horiz.x4.nxv2f64(i32 7, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv8f64.nxv2f64( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8f64.nxv2f64( [[TMP2]], [[TMP3]], i64 2) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv8f64.nxv2f64( [[TMP4]], [[TMP5]], i64 4) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv8f64.nxv2f64( [[TMP6]], [[TMP7]], i64 6) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_hor_za64_f64_x4j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.horiz.x4.nxv2f64(i32 7, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv8f64.nxv2f64( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8f64.nxv2f64( [[TMP2]], [[TMP3]], i64 2) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv8f64.nxv2f64( [[TMP4]], [[TMP5]], i64 4) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv8f64.nxv2f64( [[TMP6]], [[TMP7]], i64 6) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svfloat64x4_t test_svreadz_hor_za64_f64_x4(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za64_f64_vg4(7, slice); +} + +// +// X4 - ver +// CHECK-LABEL: define dso_local @test_svreadz_ver_za8_s8_x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.vert.x4.nxv16i8(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP2]], [[TMP3]], i64 16) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP4]], [[TMP5]], i64 32) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP6]], [[TMP7]], i64 48) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: define dso_local @_Z26test_svreadz_ver_za8_s8_x4j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.vert.x4.nxv16i8(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP2]], [[TMP3]], i64 16) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP4]], [[TMP5]], i64 32) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP6]], [[TMP7]], i64 48) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svint8x4_t test_svreadz_ver_za8_s8_x4(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_ver_za8_s8_vg4(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_ver_za8_u8_x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.vert.x4.nxv16i8(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP2]], [[TMP3]], i64 16) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP4]], [[TMP5]], i64 32) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP6]], [[TMP7]], i64 48) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: define dso_local @_Z26test_svreadz_ver_za8_u8_x4j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.vert.x4.nxv16i8(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP2]], [[TMP3]], i64 16) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP4]], [[TMP5]], i64 32) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv64i8.nxv16i8( [[TMP6]], [[TMP7]], i64 48) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svuint8x4_t test_svreadz_ver_za8_u8_x4(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_ver_za8_u8_vg4(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_ver_za16_s16_x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.vert.x4.nxv8i16(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP2]], [[TMP3]], i64 8) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP4]], [[TMP5]], i64 16) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP6]], [[TMP7]], i64 24) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_ver_za16_s16_x4j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.vert.x4.nxv8i16(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP2]], [[TMP3]], i64 8) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP4]], [[TMP5]], i64 16) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP6]], [[TMP7]], i64 24) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svint16x4_t test_svreadz_ver_za16_s16_x4(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_ver_za16_s16_vg4(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_ver_za16_u16_x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.vert.x4.nxv8i16(i32 1, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP2]], [[TMP3]], i64 8) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP4]], [[TMP5]], i64 16) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP6]], [[TMP7]], i64 24) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_ver_za16_u16_x4j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.vert.x4.nxv8i16(i32 1, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP2]], [[TMP3]], i64 8) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP4]], [[TMP5]], i64 16) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv32i16.nxv8i16( [[TMP6]], [[TMP7]], i64 24) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svuint16x4_t test_svreadz_ver_za16_u16_x4(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_ver_za16_u16_vg4(1, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_ver_za16_f16_x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.vert.x4.nxv8f16(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv32f16.nxv8f16( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32f16.nxv8f16( [[TMP2]], [[TMP3]], i64 8) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv32f16.nxv8f16( [[TMP4]], [[TMP5]], i64 16) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv32f16.nxv8f16( [[TMP6]], [[TMP7]], i64 24) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_ver_za16_f16_x4j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.vert.x4.nxv8f16(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv32f16.nxv8f16( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32f16.nxv8f16( [[TMP2]], [[TMP3]], i64 8) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv32f16.nxv8f16( [[TMP4]], [[TMP5]], i64 16) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv32f16.nxv8f16( [[TMP6]], [[TMP7]], i64 24) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svfloat16x4_t test_svreadz_ver_za16_f16_x4(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_ver_za16_f16_vg4(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_ver_za16_bf16_x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.vert.x4.nxv8bf16(i32 1, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv32bf16.nxv8bf16( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32bf16.nxv8bf16( [[TMP2]], [[TMP3]], i64 8) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv32bf16.nxv8bf16( [[TMP4]], [[TMP5]], i64 16) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv32bf16.nxv8bf16( [[TMP6]], [[TMP7]], i64 24) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: define dso_local @_Z29test_svreadz_ver_za16_bf16_x4j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.vert.x4.nxv8bf16(i32 1, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv32bf16.nxv8bf16( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv32bf16.nxv8bf16( [[TMP2]], [[TMP3]], i64 8) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv32bf16.nxv8bf16( [[TMP4]], [[TMP5]], i64 16) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv32bf16.nxv8bf16( [[TMP6]], [[TMP7]], i64 24) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svbfloat16x4_t test_svreadz_ver_za16_bf16_x4(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_ver_za16_bf16_vg4(1, slice); +} + + +// CHECK-LABEL: define dso_local @test_svreadz_ver_za32_s32_x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.vert.x4.nxv4i32(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP2]], [[TMP3]], i64 4) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP4]], [[TMP5]], i64 8) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP6]], [[TMP7]], i64 12) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_ver_za32_s32_x4j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.vert.x4.nxv4i32(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP2]], [[TMP3]], i64 4) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP4]], [[TMP5]], i64 8) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP6]], [[TMP7]], i64 12) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svint32x4_t test_svreadz_ver_za32_s32_x4(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_ver_za32_s32_vg4(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_ver_za32_u32_x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.vert.x4.nxv4i32(i32 2, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP2]], [[TMP3]], i64 4) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP4]], [[TMP5]], i64 8) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP6]], [[TMP7]], i64 12) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_ver_za32_u32_x4j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.vert.x4.nxv4i32(i32 2, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP2]], [[TMP3]], i64 4) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP4]], [[TMP5]], i64 8) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv16i32.nxv4i32( [[TMP6]], [[TMP7]], i64 12) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svuint32x4_t test_svreadz_ver_za32_u32_x4(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_ver_za32_u32_vg4(2, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_ver_za32_f32_x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.vert.x4.nxv4f32(i32 3, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16f32.nxv4f32( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16f32.nxv4f32( [[TMP2]], [[TMP3]], i64 4) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv16f32.nxv4f32( [[TMP4]], [[TMP5]], i64 8) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv16f32.nxv4f32( [[TMP6]], [[TMP7]], i64 12) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_ver_za32_f32_x4j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.vert.x4.nxv4f32(i32 3, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv16f32.nxv4f32( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv16f32.nxv4f32( [[TMP2]], [[TMP3]], i64 4) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv16f32.nxv4f32( [[TMP4]], [[TMP5]], i64 8) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv16f32.nxv4f32( [[TMP6]], [[TMP7]], i64 12) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svfloat32x4_t test_svreadz_ver_za32_f32_x4(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_ver_za32_f32_vg4(3, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_ver_za64_s64_x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.vert.x4.nxv2i64(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP2]], [[TMP3]], i64 2) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP4]], [[TMP5]], i64 4) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP6]], [[TMP7]], i64 6) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_ver_za64_s64_x4j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.vert.x4.nxv2i64(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP2]], [[TMP3]], i64 2) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP4]], [[TMP5]], i64 4) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP6]], [[TMP7]], i64 6) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svint64x4_t test_svreadz_ver_za64_s64_x4(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_ver_za64_s64_vg4(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_ver_za64_u64_x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.vert.x4.nxv2i64(i32 4, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP2]], [[TMP3]], i64 2) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP4]], [[TMP5]], i64 4) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP6]], [[TMP7]], i64 6) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_ver_za64_u64_x4j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.vert.x4.nxv2i64(i32 4, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP2]], [[TMP3]], i64 2) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP4]], [[TMP5]], i64 4) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv8i64.nxv2i64( [[TMP6]], [[TMP7]], i64 6) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svuint64x4_t test_svreadz_ver_za64_u64_x4(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_ver_za64_u64_vg4(4, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_ver_za64_f64_x4( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.vert.x4.nxv2f64(i32 7, i32 [[SLICE]]) +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv8f64.nxv2f64( poison, [[TMP1]], i64 0) +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8f64.nxv2f64( [[TMP2]], [[TMP3]], i64 2) +// CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv8f64.nxv2f64( [[TMP4]], [[TMP5]], i64 4) +// CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv8f64.nxv2f64( [[TMP6]], [[TMP7]], i64 6) +// CHECK-NEXT: ret [[TMP8]] +// +// CPP-CHECK-LABEL: define dso_local @_Z28test_svreadz_ver_za64_f64_x4j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.readz.vert.x4.nxv2f64(i32 7, i32 [[SLICE]]) +// CPP-CHECK-NEXT: [[TMP1:%.*]] = extractvalue { , , , } [[TMP0]], 0 +// CPP-CHECK-NEXT: [[TMP2:%.*]] = tail call @llvm.vector.insert.nxv8f64.nxv2f64( poison, [[TMP1]], i64 0) +// CPP-CHECK-NEXT: [[TMP3:%.*]] = extractvalue { , , , } [[TMP0]], 1 +// CPP-CHECK-NEXT: [[TMP4:%.*]] = tail call @llvm.vector.insert.nxv8f64.nxv2f64( [[TMP2]], [[TMP3]], i64 2) +// CPP-CHECK-NEXT: [[TMP5:%.*]] = extractvalue { , , , } [[TMP0]], 2 +// CPP-CHECK-NEXT: [[TMP6:%.*]] = tail call @llvm.vector.insert.nxv8f64.nxv2f64( [[TMP4]], [[TMP5]], i64 4) +// CPP-CHECK-NEXT: [[TMP7:%.*]] = extractvalue { , , , } [[TMP0]], 3 +// CPP-CHECK-NEXT: [[TMP8:%.*]] = tail call @llvm.vector.insert.nxv8f64.nxv2f64( [[TMP6]], [[TMP7]], i64 6) +// CPP-CHECK-NEXT: ret [[TMP8]] +// +svfloat64x4_t test_svreadz_ver_za64_f64_x4(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_ver_za64_f64_vg4(7, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za8_s8( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.horiz.nxv16i8(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z23test_svreadz_hor_za8_s8j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0:[0-9]+]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.horiz.nxv16i8(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svint8_t test_svreadz_hor_za8_s8(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za8_s8(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za8_u8( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.horiz.nxv16i8(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z23test_svreadz_hor_za8_u8j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.horiz.nxv16i8(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svuint8_t test_svreadz_hor_za8_u8(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za8_u8(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za16_s16( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.horiz.nxv8i16(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z25test_svreadz_hor_za16_s16j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.horiz.nxv8i16(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svint16_t test_svreadz_hor_za16_s16(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za16_s16(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za16_u16( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.horiz.nxv8i16(i32 1, i32 [[SLICE]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z25test_svreadz_hor_za16_u16j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.horiz.nxv8i16(i32 1, i32 [[SLICE]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svuint16_t test_svreadz_hor_za16_u16(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za16_u16(1, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za16_f16( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.horiz.nxv8f16(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z25test_svreadz_hor_za16_f16j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.horiz.nxv8f16(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svfloat16_t test_svreadz_hor_za16_f16(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za16_f16(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za16_bf16( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.horiz.nxv8bf16(i32 1, i32 [[SLICE]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z26test_svreadz_hor_za16_bf16j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.horiz.nxv8bf16(i32 1, i32 [[SLICE]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svbfloat16_t test_svreadz_hor_za16_bf16(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za16_bf16(1, slice); +} + + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za32_s32( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.horiz.nxv4i32(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z25test_svreadz_hor_za32_s32j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.horiz.nxv4i32(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svint32_t test_svreadz_hor_za32_s32(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za32_s32(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za32_u32( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.horiz.nxv4i32(i32 2, i32 [[SLICE]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z25test_svreadz_hor_za32_u32j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.horiz.nxv4i32(i32 2, i32 [[SLICE]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svuint32_t test_svreadz_hor_za32_u32(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za32_u32(2, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za32_f32( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.horiz.nxv4f32(i32 3, i32 [[SLICE]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z25test_svreadz_hor_za32_f32j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.horiz.nxv4f32(i32 3, i32 [[SLICE]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svfloat32_t test_svreadz_hor_za32_f32(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za32_f32(3, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za64_s64( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.horiz.nxv2i64(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z25test_svreadz_hor_za64_s64j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.horiz.nxv2i64(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svint64_t test_svreadz_hor_za64_s64(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za64_s64(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za64_u64( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.horiz.nxv2i64(i32 4, i32 [[SLICE]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z25test_svreadz_hor_za64_u64j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.horiz.nxv2i64(i32 4, i32 [[SLICE]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svuint64_t test_svreadz_hor_za64_u64(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za64_u64(4, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za64_f64( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.horiz.nxv2f64(i32 7, i32 [[SLICE]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z25test_svreadz_hor_za64_f64j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.horiz.nxv2f64(i32 7, i32 [[SLICE]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svfloat64_t test_svreadz_hor_za64_f64(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za64_f64(7, slice); +} + +// ZA128 +// CHECK-LABEL: define dso_local @test_svreadz_hor_za128_s8( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.q.horiz.nxv16i8(i32 0, i32 [[SLICE]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z25test_svreadz_hor_za128_s8j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.q.horiz.nxv16i8(i32 0, i32 [[SLICE]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svint8_t test_svreadz_hor_za128_s8(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za128_s8(0, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za128_u8( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.q.horiz.nxv16i8(i32 1, i32 [[SLICE]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z25test_svreadz_hor_za128_u8j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.q.horiz.nxv16i8(i32 1, i32 [[SLICE]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svuint8_t test_svreadz_hor_za128_u8(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za128_u8(1, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za128_s16( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.q.horiz.nxv8i16(i32 2, i32 [[SLICE]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z26test_svreadz_hor_za128_s16j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.q.horiz.nxv8i16(i32 2, i32 [[SLICE]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svint16_t test_svreadz_hor_za128_s16(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za128_s16(2, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za128_u16( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.q.horiz.nxv8i16(i32 3, i32 [[SLICE]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z26test_svreadz_hor_za128_u16j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.q.horiz.nxv8i16(i32 3, i32 [[SLICE]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svuint16_t test_svreadz_hor_za128_u16(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za128_u16(3, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za128_f16( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.q.horiz.nxv8f16(i32 4, i32 [[SLICE]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z26test_svreadz_hor_za128_f16j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.q.horiz.nxv8f16(i32 4, i32 [[SLICE]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svfloat16_t test_svreadz_hor_za128_f16(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za128_f16(4, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za128_bf16( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.q.horiz.nxv8bf16(i32 5, i32 [[SLICE]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z27test_svreadz_hor_za128_bf16j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.q.horiz.nxv8bf16(i32 5, i32 [[SLICE]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svbfloat16_t test_svreadz_hor_za128_bf16(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za128_bf16(5, slice); +} + + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za128_s32( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.q.horiz.nxv4i32(i32 6, i32 [[SLICE]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z26test_svreadz_hor_za128_s32j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.q.horiz.nxv4i32(i32 6, i32 [[SLICE]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svint32_t test_svreadz_hor_za128_s32(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za128_s32(6, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za128_u32( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.q.horiz.nxv4i32(i32 7, i32 [[SLICE]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z26test_svreadz_hor_za128_u32j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.q.horiz.nxv4i32(i32 7, i32 [[SLICE]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svuint32_t test_svreadz_hor_za128_u32(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za128_u32(7, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za128_f32( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.q.horiz.nxv4f32(i32 8, i32 [[SLICE]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z26test_svreadz_hor_za128_f32j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.q.horiz.nxv4f32(i32 8, i32 [[SLICE]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svfloat32_t test_svreadz_hor_za128_f32(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za128_f32(8, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za128_s64( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.q.horiz.nxv2i64(i32 13, i32 [[SLICE]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z26test_svreadz_hor_za128_s64j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.q.horiz.nxv2i64(i32 13, i32 [[SLICE]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svint64_t test_svreadz_hor_za128_s64(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za128_s64(13, slice); +} +// CHECK-LABEL: define dso_local @test_svreadz_hor_za128_u64( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.q.horiz.nxv2i64(i32 14, i32 [[SLICE]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z26test_svreadz_hor_za128_u64j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.q.horiz.nxv2i64(i32 14, i32 [[SLICE]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svuint64_t test_svreadz_hor_za128_u64(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za128_u64(14, slice); +} + +// CHECK-LABEL: define dso_local @test_svreadz_hor_za128_f64( +// CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.q.horiz.nxv2f64(i32 15, i32 [[SLICE]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z26test_svreadz_hor_za128_f64j( +// CPP-CHECK-SAME: i32 noundef [[SLICE:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sme.readz.q.horiz.nxv2f64(i32 15, i32 [[SLICE]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svfloat64_t test_svreadz_hor_za128_f64(uint32_t slice) __arm_streaming __arm_inout("za") +{ + return svreadz_hor_za128_f64(15, slice); +} diff --git a/clang/test/CodeGen/aarch64-targetattr.c b/clang/test/CodeGen/aarch64-targetattr.c index 7aabecd1c07b85..e4e0ae7b66afc8 100644 --- a/clang/test/CodeGen/aarch64-targetattr.c +++ b/clang/test/CodeGen/aarch64-targetattr.c @@ -196,14 +196,14 @@ void minusarch() {} // CHECK: attributes #[[ATTR1]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+crc,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rdm,+sve,+v8.1a,+v8.2a,+v8a" } // CHECK: attributes #[[ATTR2]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+crc,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rdm,+sve,+sve2,+v8.1a,+v8.2a,+v8a" } // CHECK: attributes #[[ATTR3]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+complxnum,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+jsconv,+lse,+neon,+pauth,+ras,+rcpc,+rdm,+sve,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8.6a,+v8a" } -// CHECK: attributes #[[ATTR4]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="cortex-a710" "target-features"="+bf16,+complxnum,+crc,+dotprod,+flagm,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+jsconv,+lse,+mte,+neon,+pauth,+perfmon,+ras,+rcpc,+rdm,+sb,+sve,+sve2,+sve2-bitperm,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+v9a" } +// CHECK: attributes #[[ATTR4]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="cortex-a710" "target-features"="+bf16,+complxnum,+crc,+dotprod,+ete,+flagm,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+jsconv,+lse,+mte,+neon,+pauth,+perfmon,+ras,+rcpc,+rdm,+sb,+sve,+sve2,+sve2-bitperm,+trbe,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+v9a" } // CHECK: attributes #[[ATTR5]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "tune-cpu"="cortex-a710" } -// CHECK: attributes #[[ATTR6]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+fp-armv8,+neon,+v8a" } +// CHECK: attributes #[[ATTR6]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+ete,+fp-armv8,+neon,+trbe,+v8a" } // CHECK: attributes #[[ATTR7]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "tune-cpu"="generic" } // CHECK: attributes #[[ATTR8]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="neoverse-n1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+perfmon,+ras,+rcpc,+rdm,+sha2,+spe,+ssbs,+v8.1a,+v8.2a,+v8a" "tune-cpu"="cortex-a710" } // CHECK: attributes #[[ATTR9]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+sve" "tune-cpu"="cortex-a710" } -// CHECK: attributes #[[ATTR10]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="neoverse-v1" "target-features"="+aes,+bf16,+complxnum,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+jsconv,+lse,+neon,+pauth,+perfmon,+rand,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+spe,+ssbs,+sve,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8a" } -// CHECK: attributes #[[ATTR11]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="neoverse-v1" "target-features"="+aes,+bf16,+complxnum,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+jsconv,+lse,+neon,+pauth,+perfmon,+rand,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+spe,+ssbs,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8a,-sve" } +// CHECK: attributes #[[ATTR10]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="neoverse-v1" "target-features"="+aes,+bf16,+ccdp,+complxnum,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+jsconv,+lse,+neon,+pauth,+perfmon,+rand,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+spe,+ssbs,+sve,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8a" } +// CHECK: attributes #[[ATTR11]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="neoverse-v1" "target-features"="+aes,+bf16,+ccdp,+complxnum,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+jsconv,+lse,+neon,+pauth,+perfmon,+rand,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+spe,+ssbs,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8a,-sve" } // CHECK: attributes #[[ATTR12]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+sve" } // CHECK: attributes #[[ATTR13]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16" } // CHECK: attributes #[[ATTR14]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="neoverse-n1" "target-features"="+aes,+bf16,+complxnum,+crc,+dotprod,+fp-armv8,+fullfp16,+i8mm,+jsconv,+lse,+neon,+pauth,+perfmon,+ras,+rcpc,+rdm,+sha2,+spe,+ssbs,+sve,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8.6a,+v8a" "tune-cpu"="cortex-a710" } diff --git a/clang/test/CodeGen/asan-frame-pointer.cpp b/clang/test/CodeGen/asan-frame-pointer.cpp index ed3624f3146ebb..ecc1a18c11daa3 100644 --- a/clang/test/CodeGen/asan-frame-pointer.cpp +++ b/clang/test/CodeGen/asan-frame-pointer.cpp @@ -8,12 +8,12 @@ int global; // NONE: define internal void @asan.module_ctor() #[[#ATTR:]] { // NONE: define internal void @asan.module_dtor() #[[#ATTR]] { -// NONE: attributes #[[#ATTR]] = { nounwind } +// NONE: attributes #[[#ATTR]] = { nounwind // NONLEAF: define internal void @asan.module_ctor() #[[#ATTR:]] { // NONLEAF: define internal void @asan.module_dtor() #[[#ATTR]] { -// NONLEAF: attributes #[[#ATTR]] = { nounwind "frame-pointer"="non-leaf" } +// NONLEAF: attributes #[[#ATTR]] = { nounwind "frame-pointer"="non-leaf" // ALL: define internal void @asan.module_ctor() #[[#ATTR:]] { // ALL: define internal void @asan.module_dtor() #[[#ATTR]] { -// ALL: attributes #[[#ATTR]] = { nounwind "frame-pointer"="all" } +// ALL: attributes #[[#ATTR]] = { nounwind "frame-pointer"="all" diff --git a/clang/test/CodeGen/asan-globals.cpp b/clang/test/CodeGen/asan-globals.cpp index 4a370cbd446500..be52ea99de9692 100644 --- a/clang/test/CodeGen/asan-globals.cpp +++ b/clang/test/CodeGen/asan-globals.cpp @@ -67,13 +67,13 @@ void func() { // CHECK-NEXT: call void @__asan_unregister_globals // CHECK-NEXT: ret void -// CHECK: attributes #[[#ATTR]] = { nounwind } +// CHECK: attributes #[[#ATTR]] = { nounwind /// If -fasynchronous-unwind-tables, set the module flag "uwtable". ctor/dtor /// will thus get the uwtable attribute. // RUN: %clang_cc1 -emit-llvm -fsanitize=address -funwind-tables=2 -o - %s | FileCheck %s --check-prefixes=UWTABLE // UWTABLE: define internal void @asan.module_dtor() #[[#ATTR:]] { -// UWTABLE: attributes #[[#ATTR]] = { nounwind uwtable } +// UWTABLE: attributes #[[#ATTR]] = { nounwind uwtable // UWTABLE: ![[#]] = !{i32 7, !"uwtable", i32 2} // IGNORELIST-SRC: @{{.*}}extra_global{{.*}} ={{.*}} global diff --git a/clang/test/CodeGen/attr-target-clones-aarch64.c b/clang/test/CodeGen/attr-target-clones-aarch64.c index ad6079a91fcd59..60f9c7f1fc24ed 100644 --- a/clang/test/CodeGen/attr-target-clones-aarch64.c +++ b/clang/test/CodeGen/attr-target-clones-aarch64.c @@ -27,14 +27,6 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) //. // CHECK: @__aarch64_cpu_features = external dso_local global { i64 } -// CHECK: @ftc.ifunc = weak_odr alias i32 (), ptr @ftc -// CHECK: @ftc_def.ifunc = weak_odr alias i32 (), ptr @ftc_def -// CHECK: @ftc_dup1.ifunc = weak_odr alias i32 (), ptr @ftc_dup1 -// CHECK: @ftc_dup2.ifunc = weak_odr alias i32 (), ptr @ftc_dup2 -// CHECK: @ftc_dup3.ifunc = weak_odr alias i32 (), ptr @ftc_dup3 -// CHECK: @ftc_inline2.ifunc = weak_odr alias i32 (), ptr @ftc_inline2 -// CHECK: @ftc_inline1.ifunc = weak_odr alias i32 (), ptr @ftc_inline1 -// CHECK: @ftc_inline3.ifunc = weak_odr alias i32 (), ptr @ftc_inline3 // CHECK: @ftc = weak_odr ifunc i32 (), ptr @ftc.resolver // CHECK: @ftc_def = weak_odr ifunc i32 (), ptr @ftc_def.resolver // CHECK: @ftc_dup1 = weak_odr ifunc i32 (), ptr @ftc_dup1.resolver @@ -45,14 +37,6 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) // CHECK: @ftc_inline3 = weak_odr ifunc i32 (), ptr @ftc_inline3.resolver //. // CHECK-MTE-BTI: @__aarch64_cpu_features = external dso_local global { i64 } -// CHECK-MTE-BTI: @ftc.ifunc = weak_odr alias i32 (), ptr @ftc -// CHECK-MTE-BTI: @ftc_def.ifunc = weak_odr alias i32 (), ptr @ftc_def -// CHECK-MTE-BTI: @ftc_dup1.ifunc = weak_odr alias i32 (), ptr @ftc_dup1 -// CHECK-MTE-BTI: @ftc_dup2.ifunc = weak_odr alias i32 (), ptr @ftc_dup2 -// CHECK-MTE-BTI: @ftc_dup3.ifunc = weak_odr alias i32 (), ptr @ftc_dup3 -// CHECK-MTE-BTI: @ftc_inline2.ifunc = weak_odr alias i32 (), ptr @ftc_inline2 -// CHECK-MTE-BTI: @ftc_inline1.ifunc = weak_odr alias i32 (), ptr @ftc_inline1 -// CHECK-MTE-BTI: @ftc_inline3.ifunc = weak_odr alias i32 (), ptr @ftc_inline3 // CHECK-MTE-BTI: @ftc = weak_odr ifunc i32 (), ptr @ftc.resolver // CHECK-MTE-BTI: @ftc_def = weak_odr ifunc i32 (), ptr @ftc_def.resolver // CHECK-MTE-BTI: @ftc_dup1 = weak_odr ifunc i32 (), ptr @ftc_dup1.resolver diff --git a/clang/test/CodeGen/attr-target-version.c b/clang/test/CodeGen/attr-target-version.c index 75f8734e5aaf37..024aafffca6299 100644 --- a/clang/test/CodeGen/attr-target-version.c +++ b/clang/test/CodeGen/attr-target-version.c @@ -137,19 +137,6 @@ int caller(void) { return used_def_without_default_decl() + used_decl_without_de //. // CHECK: @__aarch64_cpu_features = external dso_local global { i64 } -// CHECK: @fmv.ifunc = weak_odr alias i32 (), ptr @fmv -// CHECK: @fmv_one.ifunc = weak_odr alias i32 (), ptr @fmv_one -// CHECK: @fmv_two.ifunc = weak_odr alias i32 (), ptr @fmv_two -// CHECK: @fmv_e.ifunc = weak_odr alias i32 (), ptr @fmv_e -// CHECK: @fmv_d.ifunc = internal alias i32 (), ptr @fmv_d -// CHECK: @fmv_c.ifunc = weak_odr alias void (), ptr @fmv_c -// CHECK: @fmv_inline.ifunc = weak_odr alias i32 (), ptr @fmv_inline -// CHECK: @unused_with_default_def.ifunc = weak_odr alias i32 (), ptr @unused_with_default_def -// CHECK: @unused_with_implicit_default_def.ifunc = weak_odr alias i32 (), ptr @unused_with_implicit_default_def -// CHECK: @unused_with_implicit_forward_default_def.ifunc = weak_odr alias i32 (), ptr @unused_with_implicit_forward_default_def -// CHECK: @default_def_with_version_decls.ifunc = weak_odr alias i32 (), ptr @default_def_with_version_decls -// CHECK: @used_def_without_default_decl.ifunc = weak_odr alias i32 (), ptr @used_def_without_default_decl -// CHECK: @used_decl_without_default_decl.ifunc = weak_odr alias i32 (), ptr @used_decl_without_default_decl // CHECK: @fmv = weak_odr ifunc i32 (), ptr @fmv.resolver // CHECK: @fmv_one = weak_odr ifunc i32 (), ptr @fmv_one.resolver // CHECK: @fmv_two = weak_odr ifunc i32 (), ptr @fmv_two.resolver diff --git a/clang/test/CodeGen/coverage-target-attr.c b/clang/test/CodeGen/coverage-target-attr.c new file mode 100644 index 00000000000000..d46299f5bee223 --- /dev/null +++ b/clang/test/CodeGen/coverage-target-attr.c @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -emit-llvm -coverage-notes-file=/dev/null -coverage-data-file=/dev/null -triple aarch64-linux-android30 -target-cpu generic -target-feature +tagged-globals -fsanitize=hwaddress %s -o %t +// RUN: FileCheck %s < %t + +// CHECK: define internal void @__llvm_gcov_writeout() unnamed_addr [[ATTR:#[0-9]+]] +// CHECK: define internal void @__llvm_gcov_reset() unnamed_addr [[ATTR]] +// CHECK: define internal void @__llvm_gcov_init() unnamed_addr [[ATTR]] +// CHECK: define internal void @hwasan.module_ctor() [[ATTR2:#[0-9]+]] +// CHECK: attributes [[ATTR]] = {{.*}} "target-cpu"="generic" "target-features"="+tagged-globals" +// CHECK: attributes [[ATTR2]] = {{.*}} "target-cpu"="generic" "target-features"="+tagged-globals" + +__attribute__((weak)) int foo = 0; + +__attribute__((weak)) void bar() {} + +int main() { + if (foo) bar(); +} diff --git a/clang/test/CodeGen/ptrauth-intrinsics.c b/clang/test/CodeGen/ptrauth-intrinsics.c index db37d785537691..50bf1898e4b372 100644 --- a/clang/test/CodeGen/ptrauth-intrinsics.c +++ b/clang/test/CodeGen/ptrauth-intrinsics.c @@ -1,5 +1,8 @@ // RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck %s // RUN: %clang_cc1 -triple aarch64-elf -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck %s +// +// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-intrinsics -emit-llvm %s -o - -fexperimental-new-constant-interpreter | FileCheck %s +// RUN: %clang_cc1 -triple aarch64-elf -fptrauth-intrinsics -emit-llvm %s -o - -fexperimental-new-constant-interpreter | FileCheck %s void (*fnptr)(void); long int_discriminator; diff --git a/clang/test/CodeGen/ptrauth-ubsan-vptr.cpp b/clang/test/CodeGen/ptrauth-ubsan-vptr.cpp new file mode 100644 index 00000000000000..6c36004641477d --- /dev/null +++ b/clang/test/CodeGen/ptrauth-ubsan-vptr.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -triple arm64e-apple-ios15 -fsanitize=vptr -O0 -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple arm64e-apple-ios15 -fsanitize=vptr -O2 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s + +struct S { + S() {} + ~S() {} + virtual int v() { return 0; } + int a; +}; + +struct T : public S { + virtual int v(); +}; + +// CHECK-LABEL: foo1 +int foo1(void* Buffer) { + T *p = reinterpret_cast(Buffer); + return p->v(); +} +// CHECK-NOT: call {{.*}} @llvm.ptrauth.auth{{.*}} +// CHECK-NOT: call {{.*}} @llvm.ptrauth.strip{{.*}} + +// CHECK-LABEL: foo2 +int foo2(S* s) { + T *p = dynamic_cast(s); + return p->v(); +} + +// CHECK-NOT: call {{.*}} @llvm.ptrauth.auth{{.*}} +// CHECK-NOT: call {{.*}} @llvm.ptrauth.strip{{.*}} diff --git a/clang/test/CodeGen/sanitize-metadata-nosanitize.c b/clang/test/CodeGen/sanitize-metadata-nosanitize.c index 60f93476b050ff..6414956fb67967 100644 --- a/clang/test/CodeGen/sanitize-metadata-nosanitize.c +++ b/clang/test/CodeGen/sanitize-metadata-nosanitize.c @@ -93,7 +93,7 @@ __attribute__((no_sanitize("all"))) int test_no_sanitize_all(int *x, int *y) { // CHECK: attributes #1 = { mustprogress nofree norecurse nounwind willreturn memory(write, argmem: readwrite, inaccessiblemem: none) "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } // CHECK: attributes #2 = { disable_sanitizer_instrumentation mustprogress nofree norecurse nounwind willreturn memory(write, argmem: readwrite, inaccessiblemem: none) "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } // CHECK: attributes #3 = { mustprogress nofree norecurse nounwind willreturn memory(write, argmem: readwrite, inaccessiblemem: none) "min-legal-vector-width"="0" "no-trapping-math"="true" "no_sanitize_thread" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } -// CHECK: attributes #4 = { nounwind } +// CHECK: attributes #4 = { nounwind "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } //. // CHECK: !2 = !{!"sanmd_covered!C", !3} // CHECK: !3 = !{i64 0} diff --git a/clang/test/CodeGen/target-data.c b/clang/test/CodeGen/target-data.c index 7f7005d21b99a3..9a9fda70226fc2 100644 --- a/clang/test/CodeGen/target-data.c +++ b/clang/test/CodeGen/target-data.c @@ -269,6 +269,6 @@ // RUN: FileCheck %s -check-prefix=VE // VE: target datalayout = "e-m:e-i64:64-n32:64-S128-v64:64:64-v128:64:64-v256:64:64-v512:64:64-v1024:64:64-v2048:64:64-v4096:64:64-v8192:64:64-v16384:64:64" -// RUN: %clang_cc1 -triple spirv64-amd -o - -emit-llvm %s | \ -// RUN: FileCheck %s -check-prefix=SPIR64 +// RUN: %clang_cc1 -triple spirv64-amd-amdhsa -o - -emit-llvm %s | \ +// RUN: FileCheck %s -check-prefix=AMDGPUSPIRV64 // AMDGPUSPIRV64: target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-G1-P4-A0" diff --git a/clang/test/CodeGenCUDA/amdgpu-atomic-ops.cu b/clang/test/CodeGenCUDA/amdgpu-atomic-ops.cu index 57557bf09f411c..eeb23bc7e1c01e 100644 --- a/clang/test/CodeGenCUDA/amdgpu-atomic-ops.cu +++ b/clang/test/CodeGenCUDA/amdgpu-atomic-ops.cu @@ -49,18 +49,18 @@ __global__ void ffp2(double *p) { // CHECK: atomicrmw fmin ptr {{.*}} monotonic // CHECK: atomicrmw fmax ptr {{.*}} syncscope("agent-one-as") monotonic // CHECK: atomicrmw fmin ptr {{.*}} syncscope("workgroup-one-as") monotonic - // SAFE: _Z4ffp2Pd + // SAFE-LABEL: @_Z4ffp2Pd // SAFE: global_atomic_cmpswap_b64 // SAFE: global_atomic_cmpswap_b64 // SAFE: global_atomic_cmpswap_b64 // SAFE: global_atomic_cmpswap_b64 // SAFE: global_atomic_cmpswap_b64 - // UNSAFE: _Z4ffp2Pd - // UNSAFE: global_atomic_cmpswap_x2 - // UNSAFE: global_atomic_cmpswap_x2 + // UNSAFE-LABEL: @_Z4ffp2Pd // UNSAFE: global_atomic_cmpswap_x2 // UNSAFE: global_atomic_cmpswap_x2 // UNSAFE: global_atomic_cmpswap_x2 + // UNSAFE: global_atomic_max_f64 + // UNSAFE: global_atomic_min_f64 __atomic_fetch_sub(p, 1.0, memory_order_relaxed); __atomic_fetch_max(p, 1.0, memory_order_relaxed); __atomic_fetch_min(p, 1.0, memory_order_relaxed); @@ -76,18 +76,18 @@ __global__ void ffp3(long double *p) { // CHECK: atomicrmw fmin ptr {{.*}} monotonic // CHECK: atomicrmw fmax ptr {{.*}} syncscope("agent-one-as") monotonic // CHECK: atomicrmw fmin ptr {{.*}} syncscope("workgroup-one-as") monotonic - // SAFE: _Z4ffp3Pe + // SAFE-LABEL: @_Z4ffp3Pe // SAFE: global_atomic_cmpswap_b64 // SAFE: global_atomic_cmpswap_b64 // SAFE: global_atomic_cmpswap_b64 // SAFE: global_atomic_cmpswap_b64 // SAFE: global_atomic_cmpswap_b64 - // UNSAFE: _Z4ffp3Pe - // UNSAFE: global_atomic_cmpswap_x2 - // UNSAFE: global_atomic_cmpswap_x2 + // UNSAFE-LABEL: @_Z4ffp3Pe // UNSAFE: global_atomic_cmpswap_x2 // UNSAFE: global_atomic_cmpswap_x2 // UNSAFE: global_atomic_cmpswap_x2 + // UNSAFE: global_atomic_max_f64 + // UNSAFE: global_atomic_min_f64 __atomic_fetch_sub(p, 1.0L, memory_order_relaxed); __atomic_fetch_max(p, 1.0L, memory_order_relaxed); __atomic_fetch_min(p, 1.0L, memory_order_relaxed); diff --git a/clang/test/CodeGenCUDA/builtins-amdgcn.cu b/clang/test/CodeGenCUDA/builtins-amdgcn.cu index 132cbd27b08fc3..2e88afac813f43 100644 --- a/clang/test/CodeGenCUDA/builtins-amdgcn.cu +++ b/clang/test/CodeGenCUDA/builtins-amdgcn.cu @@ -98,7 +98,7 @@ __global__ // CHECK-NEXT: [[X_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[X]] to ptr // CHECK-NEXT: store float [[SRC:%.*]], ptr [[SRC_ADDR_ASCAST]], align 4 // CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[SRC_ADDR_ASCAST]], align 4 -// CHECK-NEXT: [[TMP1:%.*]] = call contract float @llvm.amdgcn.ds.fmax.f32(ptr addrspace(3) @_ZZ12test_ds_fmaxfE6shared, float [[TMP0]], i32 0, i32 0, i1 false) +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw fmax ptr addrspace(3) @_ZZ12test_ds_fmaxfE6shared, float [[TMP0]] monotonic, align 4 // CHECK-NEXT: store volatile float [[TMP1]], ptr [[X_ASCAST]], align 4 // CHECK-NEXT: ret void // @@ -142,7 +142,7 @@ __global__ void test_ds_fadd(float src) { // CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[SHARED_ADDR_ASCAST]], align 8 // CHECK-NEXT: [[TMP2:%.*]] = addrspacecast ptr [[TMP1]] to ptr addrspace(3) // CHECK-NEXT: [[TMP3:%.*]] = load float, ptr [[SRC_ADDR_ASCAST]], align 4 -// CHECK-NEXT: [[TMP4:%.*]] = call contract float @llvm.amdgcn.ds.fmin.f32(ptr addrspace(3) [[TMP2]], float [[TMP3]], i32 0, i32 0, i1 false) +// CHECK-NEXT: [[TMP4:%.*]] = atomicrmw fmin ptr addrspace(3) [[TMP2]], float [[TMP3]] monotonic, align 4 // CHECK-NEXT: store volatile float [[TMP4]], ptr [[X_ASCAST]], align 4 // CHECK-NEXT: ret void // @@ -245,10 +245,10 @@ __device__ void func(float *x); // CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[SHARED_ADDR_ASCAST]], align 8 // CHECK-NEXT: [[TMP2:%.*]] = addrspacecast ptr [[TMP1]] to ptr addrspace(3) // CHECK-NEXT: [[TMP3:%.*]] = load float, ptr [[SRC_ADDR_ASCAST]], align 4 -// CHECK-NEXT: [[TMP4:%.*]] = call contract float @llvm.amdgcn.ds.fmin.f32(ptr addrspace(3) [[TMP2]], float [[TMP3]], i32 0, i32 0, i1 false) +// CHECK-NEXT: [[TMP4:%.*]] = atomicrmw fmin ptr addrspace(3) [[TMP2]], float [[TMP3]] monotonic, align 4 // CHECK-NEXT: store volatile float [[TMP4]], ptr [[X_ASCAST]], align 4 // CHECK-NEXT: [[TMP5:%.*]] = load ptr, ptr [[SHARED_ADDR_ASCAST]], align 8 -// CHECK-NEXT: call void @_Z4funcPf(ptr noundef [[TMP5]]) #[[ATTR8:[0-9]+]] +// CHECK-NEXT: call void @_Z4funcPf(ptr noundef [[TMP5]]) #[[ATTR7:[0-9]+]] // CHECK-NEXT: ret void // __global__ void test_ds_fmin_func(float src, float *__restrict shared) { diff --git a/clang/test/CodeGenCUDA/builtins-spirv-amdgcn.cu b/clang/test/CodeGenCUDA/builtins-spirv-amdgcn.cu index 7bb756a4a27314..32851805298f18 100644 --- a/clang/test/CodeGenCUDA/builtins-spirv-amdgcn.cu +++ b/clang/test/CodeGenCUDA/builtins-spirv-amdgcn.cu @@ -95,7 +95,7 @@ __global__ // CHECK-NEXT: [[X_ASCAST:%.*]] = addrspacecast ptr [[X]] to ptr addrspace(4) // CHECK-NEXT: store float [[SRC:%.*]], ptr addrspace(4) [[SRC_ADDR_ASCAST]], align 4 // CHECK-NEXT: [[TMP0:%.*]] = load float, ptr addrspace(4) [[SRC_ADDR_ASCAST]], align 4 -// CHECK-NEXT: [[TMP1:%.*]] = call contract addrspace(4) float @llvm.amdgcn.ds.fmax.f32(ptr addrspace(3) @_ZZ12test_ds_fmaxfE6shared, float [[TMP0]], i32 0, i32 0, i1 false) +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw fmax ptr addrspace(3) @_ZZ12test_ds_fmaxfE6shared, float [[TMP0]] monotonic, align 4 // CHECK-NEXT: store volatile float [[TMP1]], ptr addrspace(4) [[X_ASCAST]], align 4 // CHECK-NEXT: ret void // @@ -139,7 +139,7 @@ __global__ void test_ds_fadd(float src) { // CHECK-NEXT: [[TMP1:%.*]] = load ptr addrspace(4), ptr addrspace(4) [[SHARED_ADDR_ASCAST]], align 8 // CHECK-NEXT: [[TMP2:%.*]] = addrspacecast ptr addrspace(4) [[TMP1]] to ptr addrspace(3) // CHECK-NEXT: [[TMP3:%.*]] = load float, ptr addrspace(4) [[SRC_ADDR_ASCAST]], align 4 -// CHECK-NEXT: [[TMP4:%.*]] = call contract addrspace(4) float @llvm.amdgcn.ds.fmin.f32(ptr addrspace(3) [[TMP2]], float [[TMP3]], i32 0, i32 0, i1 false) +// CHECK-NEXT: [[TMP4:%.*]] = atomicrmw fmin ptr addrspace(3) [[TMP2]], float [[TMP3]] monotonic, align 4 // CHECK-NEXT: store volatile float [[TMP4]], ptr addrspace(4) [[X_ASCAST]], align 4 // CHECK-NEXT: ret void // @@ -236,10 +236,10 @@ __device__ void func(float *x); // CHECK-NEXT: [[TMP1:%.*]] = load ptr addrspace(4), ptr addrspace(4) [[SHARED_ADDR_ASCAST]], align 8 // CHECK-NEXT: [[TMP2:%.*]] = addrspacecast ptr addrspace(4) [[TMP1]] to ptr addrspace(3) // CHECK-NEXT: [[TMP3:%.*]] = load float, ptr addrspace(4) [[SRC_ADDR_ASCAST]], align 4 -// CHECK-NEXT: [[TMP4:%.*]] = call contract addrspace(4) float @llvm.amdgcn.ds.fmin.f32(ptr addrspace(3) [[TMP2]], float [[TMP3]], i32 0, i32 0, i1 false) +// CHECK-NEXT: [[TMP4:%.*]] = atomicrmw fmin ptr addrspace(3) [[TMP2]], float [[TMP3]] monotonic, align 4 // CHECK-NEXT: store volatile float [[TMP4]], ptr addrspace(4) [[X_ASCAST]], align 4 // CHECK-NEXT: [[TMP5:%.*]] = load ptr addrspace(4), ptr addrspace(4) [[SHARED_ADDR_ASCAST]], align 8 -// CHECK-NEXT: call spir_func addrspace(4) void @_Z4funcPf(ptr addrspace(4) noundef [[TMP5]]) #[[ATTR7:[0-9]+]] +// CHECK-NEXT: call spir_func addrspace(4) void @_Z4funcPf(ptr addrspace(4) noundef [[TMP5]]) #[[ATTR6:[0-9]+]] // CHECK-NEXT: ret void // __global__ void test_ds_fmin_func(float src, float *__restrict shared) { diff --git a/clang/test/CodeGenCXX/attr-annotate.cpp b/clang/test/CodeGenCXX/attr-annotate.cpp index 64627a6b83e11c..ce284c7d199828 100644 --- a/clang/test/CodeGenCXX/attr-annotate.cpp +++ b/clang/test/CodeGenCXX/attr-annotate.cpp @@ -3,9 +3,9 @@ //CHECK: @[[STR1:.*]] = private unnamed_addr constant [{{.*}} x i8] c"{{.*}}attr-annotate.cpp\00", section "llvm.metadata" //CHECK: @[[STR2:.*]] = private unnamed_addr constant [4 x i8] c"abc\00", align 1 //CHECK: @[[STR:.*]] = private unnamed_addr constant [5 x i8] c"test\00", section "llvm.metadata" -//CHECK: @[[ARGS:.*]] = private unnamed_addr constant { %struct.Struct } { %struct.Struct { ptr @_ZN1AIjLj9EE2SVE, ptr getelementptr (i8, ptr @_ZN1AIjLj9EE2SVE, i64 4) } }, section "llvm.metadata" -//CHECK: @[[ARGS2:.*]] = private unnamed_addr constant { i32, ptr, i32 } { i32 9, ptr @[[STR2:.*]], i32 8 }, section "llvm.metadata" -//CHECK: @llvm.global.annotations = appending global [2 x { ptr, ptr, ptr, i32, ptr }] [{ ptr, ptr, ptr, i32, ptr } { ptr @_ZN1AIjLj9EE5test2Ev, ptr @.str.6, ptr @.str.1, i32 24, ptr @[[ARGS]] }, { ptr, ptr, ptr, i32, ptr } { ptr @_ZN1AIjLj9EE4testILi8EEEvv, ptr @[[STR:.*]], ptr @[[STR1:.*]], i32 {{.*}}, ptr @[[ARGS2:.*]] }] +//CHECK: @[[ARGS:.*]] = private unnamed_addr constant { i32, ptr, i32 } { i32 9, ptr @[[STR2:.*]], i32 8 }, section "llvm.metadata" +//CHECK: @[[ARGS2:.*]] = private unnamed_addr constant { %struct.Struct } { %struct.Struct { ptr @_ZN1AIjLj9EE2SVE, ptr getelementptr (i8, ptr @_ZN1AIjLj9EE2SVE, i64 4) } }, section "llvm.metadata" +//CHECK: @llvm.global.annotations = appending global [2 x { ptr, ptr, ptr, i32, ptr }] [{ ptr, ptr, ptr, i32, ptr } { ptr @_ZN1AIjLj9EE4testILi8EEEvv, ptr @.str.6, ptr @.str.1, i32 23, ptr @.args.7 }, { ptr, ptr, ptr, i32, ptr } { ptr @_ZN1AIjLj9EE5test2Ev, ptr @.str.6, ptr @.str.1, i32 24, ptr @.args.8 }], section "llvm.metadata" constexpr const char* str() { return "abc"; diff --git a/clang/test/CodeGenCXX/attr-target-clones-aarch64.cpp b/clang/test/CodeGenCXX/attr-target-clones-aarch64.cpp index 7953f902bf09b2..29ae6b6856500f 100644 --- a/clang/test/CodeGenCXX/attr-target-clones-aarch64.cpp +++ b/clang/test/CodeGenCXX/attr-target-clones-aarch64.cpp @@ -40,10 +40,6 @@ void run_foo_tml() { //. // CHECK: @__aarch64_cpu_features = external dso_local global { i64 } -// CHECK: @_Z7foo_ovli.ifunc = weak_odr alias i32 (i32), ptr @_Z7foo_ovli -// CHECK: @_Z7foo_ovlv.ifunc = weak_odr alias i32 (), ptr @_Z7foo_ovlv -// CHECK: @_ZN7MyClassIssE7foo_tmlEv.ifunc = weak_odr alias i32 (ptr), ptr @_ZN7MyClassIssE7foo_tmlEv -// CHECK: @_ZN7MyClassIisE7foo_tmlEv.ifunc = weak_odr alias i32 (ptr), ptr @_ZN7MyClassIisE7foo_tmlEv // CHECK: @_Z7foo_ovli = weak_odr ifunc i32 (i32), ptr @_Z7foo_ovli.resolver // CHECK: @_Z7foo_ovlv = weak_odr ifunc i32 (), ptr @_Z7foo_ovlv.resolver // CHECK: @_ZN7MyClassIssE7foo_tmlEv = weak_odr ifunc i32 (ptr), ptr @_ZN7MyClassIssE7foo_tmlEv.resolver diff --git a/clang/test/CodeGenCXX/attr-target-version.cpp b/clang/test/CodeGenCXX/attr-target-version.cpp index 8b7273fe3bb517..fd19f4c5a30304 100644 --- a/clang/test/CodeGenCXX/attr-target-version.cpp +++ b/clang/test/CodeGenCXX/attr-target-version.cpp @@ -62,12 +62,6 @@ int bar() { //. // CHECK: @__aarch64_cpu_features = external dso_local global { i64 } -// CHECK: @_Z3fooi.ifunc = weak_odr alias i32 (i32), ptr @_Z3fooi -// CHECK: @_Z3foov.ifunc = weak_odr alias i32 (), ptr @_Z3foov -// CHECK: @_ZN7MyClass3gooEi.ifunc = weak_odr alias i32 (ptr, i32), ptr @_ZN7MyClass3gooEi -// CHECK: @_ZN7MyClass23unused_with_default_defEv.ifunc = weak_odr alias i32 (ptr), ptr @_ZN7MyClass23unused_with_default_defEv -// CHECK: @_ZN7MyClass32unused_with_implicit_default_defEv.ifunc = weak_odr alias i32 (ptr), ptr @_ZN7MyClass32unused_with_implicit_default_defEv -// CHECK: @_ZN7MyClass40unused_with_implicit_forward_default_defEv.ifunc = weak_odr alias i32 (ptr), ptr @_ZN7MyClass40unused_with_implicit_forward_default_defEv // CHECK: @_ZN7MyClass3gooEi = weak_odr ifunc i32 (ptr, i32), ptr @_ZN7MyClass3gooEi.resolver // CHECK: @_Z3fooi = weak_odr ifunc i32 (i32), ptr @_Z3fooi.resolver // CHECK: @_Z3foov = weak_odr ifunc i32 (), ptr @_Z3foov.resolver diff --git a/clang/test/CodeGenCXX/auto-var-init-max-size.cpp b/clang/test/CodeGenCXX/auto-var-init-max-size.cpp index ef38b8227a9a1a..25c30c383332b5 100644 --- a/clang/test/CodeGenCXX/auto-var-init-max-size.cpp +++ b/clang/test/CodeGenCXX/auto-var-init-max-size.cpp @@ -15,7 +15,9 @@ struct Foo { int foo(unsigned n) { bool var_size_1; - long var_size_8 = 123; + long var_size_8_init = 123; + long var_size_8_noinit; + long var_size_8_init_later; void *var_size_8p; int var_size_1024[256]; Foo var_size_1028; @@ -24,29 +26,39 @@ int foo(unsigned n) { int var_vla[n]; // builtin, non-constant size var_size_8p = __builtin_alloca(sizeof(unsigned long long) * n); - // There are 8 variables: var_size_1, var_size_8, var_size_8p, var_size_1024, + var_size_8_init_later = 456; + // There are 10 variables: var_size_1, var_size_8_init, var_size_8_noinit, + // var_size_8_init_later, var_size_8p, var_size_1024, // var_size_1028, var_size_4096, var_vla, and a builtin anonymous var ("%5"). + // - Doesn't need auto-init: var_size_8_init // - COMMON (auto-init regardless of the max size): "var_vla", and "%5" // - Max size 1: "var_size_1" - // - Max size 1024: "var_size_1", "var_size_8", "var_size_8p", "var_size_1024" - // - Max size 4096: "var_size_1", "var_size_8", "var_size_8p", "var_size_1024", "var_size_1028", "var_size_4096" + // - Max size 1024: "var_size_1", "var_size_8_noinit", "var_size_8_init_later", "var_size_8p", "var_size_1024" + // - Max size 4096: "var_size_1", "var_size_8_noinit", "var_size_8_init_later", "var_size_8p", "var_size_1024", + // "var_size_1028", "var_size_4096" // // PATTERN-MAX-1: store i8 -86, ptr %var_size_1, align 1, !annotation [[AUTO_INIT:!.+]] - // PATTERN-MAX-1-NOT: store i64 -6148914691236517206, ptr %var_size_8, align 8, !annotation [[AUTO_INIT:!.+]] + // PATTERN-MAX-1-NEXT: store i64 123, ptr %var_size_8_init, align 8 + // PATTERN-MAX-1-NOT: store i64 -6148914691236517206, ptr %var_size_8_noinit, align 8, !annotation [[AUTO_INIT:!.+]] + // PATTERN-MAX-1-NOT: store i64 -6148914691236517206, ptr %var_size_8_init_later, align 8, !annotation [[AUTO_INIT:!.+]] // PATTERN-MAX-1-NOT: store ptr inttoptr (i64 -6148914691236517206 to ptr), ptr %var_size_8p, align 8, !annotation [[AUTO_INIT:!.+]] // PATTERN-MAX-1-NOT: call void @llvm.memset.p0.i64(ptr align 16 %var_size_1024, i8 -86, i64 1024, i1 false), !annotation [[AUTO_INIT:!.+]] // PATTERN-MAX-1-NOT: call void @llvm.memset.p0.i64(ptr align 4 %var_size_1028, i8 -86, i64 1028, i1 false), !annotation [[AUTO_INIT:!.+]] // PATTERN-MAX-1-NOT: call void @llvm.memset.p0.i64(ptr align 16 %var_size_4096, i8 -86, i64 4096, i1 false), !annotation [[AUTO_INIT:!.+]] // PATTERN-MAX-1024: store i8 -86, ptr %var_size_1, align 1, !annotation [[AUTO_INIT:!.+]] - // PATTERN-MAX-1024: store i64 -6148914691236517206, ptr %var_size_8, align 8, !annotation [[AUTO_INIT:!.+]] + // PATTERN-MAX-1024-NEXT: store i64 123, ptr %var_size_8_init, align 8 + // PATTERN-MAX-1024: store i64 -6148914691236517206, ptr %var_size_8_noinit, align 8, !annotation [[AUTO_INIT:!.+]] + // PATTERN-MAX-1024: store i64 -6148914691236517206, ptr %var_size_8_init_later, align 8, !annotation [[AUTO_INIT:!.+]] // PATTERN-MAX-1024: store ptr inttoptr (i64 -6148914691236517206 to ptr), ptr %var_size_8p, align 8, !annotation [[AUTO_INIT:!.+]] // PATTERN-MAX-1024: call void @llvm.memset.p0.i64(ptr align 16 %var_size_1024, i8 -86, i64 1024, i1 false), !annotation [[AUTO_INIT:!.+]] // PATTERN-MAX-1024-NOT: call void @llvm.memset.p0.i64(ptr align 4 %var_size_1028, i8 -86, i64 1028, i1 false), !annotation [[AUTO_INIT:!.+]] // PATTERN-MAX-1024-NOT: call void @llvm.memset.p0.i64(ptr align 16 %var_size_4096, i8 -86, i64 4096, i1 false), !annotation [[AUTO_INIT:!.+]] // PATTERN-MAX-4096: store i8 -86, ptr %var_size_1, align 1, !annotation [[AUTO_INIT:!.+]] - // PATTERN-MAX-4096: store i64 -6148914691236517206, ptr %var_size_8, align 8, !annotation [[AUTO_INIT:!.+]] + // PATTERN-MAX-4096-NEXT: store i64 123, ptr %var_size_8_init, align 8 + // PATTERN-MAX-4096: store i64 -6148914691236517206, ptr %var_size_8_noinit, align 8, !annotation [[AUTO_INIT:!.+]] + // PATTERN-MAX-4096: store i64 -6148914691236517206, ptr %var_size_8_init_later, align 8, !annotation [[AUTO_INIT:!.+]] // PATTERN-MAX-4096: store ptr inttoptr (i64 -6148914691236517206 to ptr), ptr %var_size_8p, align 8, !annotation [[AUTO_INIT:!.+]] // PATTERN-MAX-4096: call void @llvm.memset.p0.i64(ptr align 16 %var_size_1024, i8 -86, i64 1024, i1 false), !annotation [[AUTO_INIT:!.+]] // PATTERN-MAX-4096: call void @llvm.memset.p0.i64(ptr align 4 %var_size_1028, i8 -86, i64 1028, i1 false), !annotation [[AUTO_INIT:!.+]] @@ -56,21 +68,27 @@ int foo(unsigned n) { // PATTERN-COMMON: call void @llvm.memset.p0.i64(ptr align 16 %5, i8 -86, i64 %mul, i1 false), !annotation [[AUTO_INIT:!.+]] // ZERO-MAX-1: store i8 0, ptr %var_size_1, align 1, !annotation [[AUTO_INIT:!.+]] - // ZERO-MAX-1-NOT: store i64 0, ptr %var_size_8, align 8, !annotation [[AUTO_INIT:!.+]] + // ZERO-MAX-1-NEXT: store i64 123, ptr %var_size_8_init, align 8 + // ZERO-MAX-1-NOT: store i64 0, ptr %var_size_8_noinit, align 8, !annotation [[AUTO_INIT:!.+]] + // ZERO-MAX-1-NOT: store i64 0, ptr %var_size_8_init_later, align 8, !annotation [[AUTO_INIT:!.+]] // ZERO-MAX-1-NOT: store ptr null, ptr %var_size_8p, align 8, !annotation [[AUTO_INIT:!.+]] // ZERO-MAX-1-NOT: call void @llvm.memset.p0.i64(ptr align 16 %var_size_1024, i8 0, i64 1024, i1 false), !annotation [[AUTO_INIT:!.+]] // ZERO-MAX-1-NOT: call void @llvm.memset.p0.i64(ptr align 4 %var_size_1028, i8 0, i64 1028, i1 false), !annotation [[AUTO_INIT:!.+]] // ZERO-MAX-1-NOT: call void @llvm.memset.p0.i64(ptr align 16 %var_size_4096, i8 0, i64 4096, i1 false), !annotation [[AUTO_INIT:!.+]] // ZERO-MAX-1024: store i8 0, ptr %var_size_1, align 1, !annotation [[AUTO_INIT:!.+]] - // ZERO-MAX-1024: store i64 0, ptr %var_size_8, align 8, !annotation [[AUTO_INIT:!.+]] + // ZERO-MAX-1024-NEXT: store i64 123, ptr %var_size_8_init, align 8 + // ZERO-MAX-1024: store i64 0, ptr %var_size_8_noinit, align 8, !annotation [[AUTO_INIT:!.+]] + // ZERO-MAX-1024: store i64 0, ptr %var_size_8_init_later, align 8, !annotation [[AUTO_INIT:!.+]] // ZERO-MAX-1024: store ptr null, ptr %var_size_8p, align 8, !annotation [[AUTO_INIT:!.+]] // ZERO-MAX-1024: call void @llvm.memset.p0.i64(ptr align 16 %var_size_1024, i8 0, i64 1024, i1 false), !annotation [[AUTO_INIT:!.+]] // ZERO-MAX-1024-NOT: call void @llvm.memset.p0.i64(ptr align 4 %var_size_1028, i8 0, i64 1028, i1 false), !annotation [[AUTO_INIT:!.+]] // ZERO-MAX-1024-NOT: call void @llvm.memset.p0.i64(ptr align 16 %var_size_4096, i8 0, i64 4096, i1 false), !annotation [[AUTO_INIT:!.+]] // ZERO-MAX-4096: store i8 0, ptr %var_size_1, align 1, !annotation [[AUTO_INIT:!.+]] - // ZERO-MAX-4096: store i64 0, ptr %var_size_8, align 8, !annotation [[AUTO_INIT:!.+]] + // ZERO-MAX-4096-NEXT: store i64 123, ptr %var_size_8_init, align 8 + // ZERO-MAX-4096: store i64 0, ptr %var_size_8_noinit, align 8, !annotation [[AUTO_INIT:!.+]] + // ZERO-MAX-4096: store i64 0, ptr %var_size_8_init_later, align 8, !annotation [[AUTO_INIT:!.+]] // ZERO-MAX-4096: store ptr null, ptr %var_size_8p, align 8, !annotation [[AUTO_INIT:!.+]] // ZERO-MAX-4096: call void @llvm.memset.p0.i64(ptr align 16 %var_size_1024, i8 0, i64 1024, i1 false), !annotation [[AUTO_INIT:!.+]] // ZERO-MAX-4096: call void @llvm.memset.p0.i64(ptr align 4 %var_size_1028, i8 0, i64 1028, i1 false), !annotation [[AUTO_INIT:!.+]] diff --git a/clang/test/CodeGenCXX/auto-var-init-stop-after.cpp b/clang/test/CodeGenCXX/auto-var-init-stop-after.cpp index a782692d0127ec..f1dc0e3a068e76 100644 --- a/clang/test/CodeGenCXX/auto-var-init-stop-after.cpp +++ b/clang/test/CodeGenCXX/auto-var-init-stop-after.cpp @@ -18,7 +18,7 @@ typedef struct { int foo(unsigned n) { // scalar variable - long a = 888; + long a; // array S arr[ARRLEN]; // VLA diff --git a/clang/test/CodeGenCXX/auto-var-init.cpp b/clang/test/CodeGenCXX/auto-var-init.cpp index e1568bee136e5e..e697731b0cdf1e 100644 --- a/clang/test/CodeGenCXX/auto-var-init.cpp +++ b/clang/test/CodeGenCXX/auto-var-init.cpp @@ -146,16 +146,8 @@ struct notlockfree { long long a[4]; }; // PATTERN-O1-NOT: @__const.test_atomictailpad_uninit.uninit // PATTERN-O0: @__const.test_complexfloat_uninit.uninit = private unnamed_addr constant { float, float } { float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000 }, align 4 // PATTERN-O1-NOT: @__const.test_complexfloat_uninit.uninit -// PATTERN-O0: @__const.test_complexfloat_braces.braces = private unnamed_addr constant { float, float } { float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000 }, align 4 -// PATTERN-O1-NOT: @__const.test_complexfloat_braces.braces -// PATTERN-O0: @__const.test_complexfloat_custom.custom = private unnamed_addr constant { float, float } { float 0xFFFFFFFFE0000000, float 0xFFFFFFFFE0000000 }, align 4 -// PATTERN-O1-NOT: @__const.test_complexfloat_custom.custom // PATTERN-O0: @__const.test_complexdouble_uninit.uninit = private unnamed_addr constant { double, double } { double 0xFFFFFFFFFFFFFFFF, double 0xFFFFFFFFFFFFFFFF }, align 8 // PATTERN-O1-NOT: @__const.test_complexdouble_uninit.uninit -// PATTERN-O0: @__const.test_complexdouble_braces.braces = private unnamed_addr constant { double, double } { double 0xFFFFFFFFFFFFFFFF, double 0xFFFFFFFFFFFFFFFF }, align 8 -// PATTERN-O1-NOT: @__const.test_complexdouble_braces.braces -// PATTERN-O0: @__const.test_complexdouble_custom.custom = private unnamed_addr constant { double, double } { double 0xFFFFFFFFFFFFFFFF, double 0xFFFFFFFFFFFFFFFF }, align 8 -// PATTERN-O1-NOT: @__const.test_complexdouble_custom.custom // PATTERN-O0: @__const.test_semivolatile_uninit.uninit = private unnamed_addr constant %struct.semivolatile { i32 [[I32]], i32 [[I32]] }, align 4 // PATTERN-O0: @__const.test_semivolatile_custom.custom = private unnamed_addr constant %struct.semivolatile { i32 1145324612, i32 1145324612 }, align 4 // PATTERN-O1-NOT: @__const.test_semivolatile_custom.custom diff --git a/clang/test/CodeGenCXX/catch-undef-behavior.cpp b/clang/test/CodeGenCXX/catch-undef-behavior.cpp index 1a0e98a6613754..0c14c97dacca95 100644 --- a/clang/test/CodeGenCXX/catch-undef-behavior.cpp +++ b/clang/test/CodeGenCXX/catch-undef-behavior.cpp @@ -56,8 +56,8 @@ void member_access(S *p) { // (1b) Check that 'p' actually points to an 'S'. - // CHECK: %[[VPTR:.*]] = load i64, ptr - // + // CHECK: %[[VTABLE:.*]] = load ptr, ptr %0 + // CHECK: %[[VPTR:.*]] = ptrtoint ptr %[[VTABLE]] to i64 // hash_16_bytes: // // If this number changes, it indicates that either the mangled name of ::S @@ -110,7 +110,8 @@ void member_access(S *p) { // (3b) Check that 'p' actually points to an 'S' - // CHECK: load i64, ptr + // CHECK: [[VTABLE2:%.*]] = load ptr, ptr + // CHECK: ptrtoint ptr [[VTABLE2]] to i64 // CHECK-NEXT: mul i64 %[[#]], -4658895280553007687, !nosanitize // [...] // CHECK: getelementptr inbounds [128 x i64], ptr @__ubsan_vptr_type_cache, i32 0, i64 % diff --git a/clang/test/CodeGenCXX/debug-info-verbose-trap.cpp b/clang/test/CodeGenCXX/debug-info-verbose-trap.cpp new file mode 100644 index 00000000000000..f492698ccab83d --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-verbose-trap.cpp @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -std=c++20 -emit-llvm -debug-info-kind=limited %s -o - | FileCheck %s + +// CHECK-LABEL: define void @_Z2f0v() +// CHECK: call void @llvm.trap(), !dbg ![[LOC17:.*]] + +// CHECK: declare void @llvm.trap() #[[ATTR1:.*]] + +// CHECK-LABEL: define void @_Z2f1v() +// CHECK: call void @llvm.trap(), !dbg ![[LOC23:.*]] +// CHECK: call void @llvm.trap(), !dbg ![[LOC25:.*]] + +// CHECK-LABEL: define void @_Z2f3v() +// CHECK: call void @_Z2f2IXadsoKcL_ZL8constCatEEEXadsoS0_L_ZL8constMsgEEEEvv() + +// CHECK-LABEL: define internal void @_Z2f2IXadsoKcL_ZL8constCatEEEXadsoS0_L_ZL8constMsgEEEEvv +// CHECK: call void @llvm.trap(), !dbg ![[LOC36:.*]] + +// CHECK: attributes #[[ATTR1]] = { cold {{.*}}} + +// CHECK: ![[FILESCOPE:.*]] = !DIFile(filename: "{{.*}}debug-info-verbose-trap.cpp" + +char const constCat[] = "category2"; +char const constMsg[] = "hello"; + +// CHECK: ![[SUBPROG14:.*]] = distinct !DISubprogram(name: "f0", linkageName: "_Z2f0v", +// CHECK: ![[LOC17]] = !DILocation(line: 0, scope: ![[SUBPROG18:.*]], inlinedAt: ![[LOC20:.*]]) +// CHECK: ![[SUBPROG18]] = distinct !DISubprogram(name: "__clang_trap_msg$category1$Argument_must_not_be_null", scope: ![[FILESCOPE]], file: ![[FILESCOPE]], type: !{{.*}}, flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: !{{.*}}) +// CHECK: ![[LOC20]] = !DILocation(line: [[@LINE+2]], column: 3, scope: ![[SUBPROG14]]) +void f0() { + __builtin_verbose_trap("category1", "Argument_must_not_be_null"); +} + +// CHECK: ![[SUBPROG22:.*]] = distinct !DISubprogram(name: "f1", linkageName: "_Z2f1v", +// CHECK: ![[LOC23]] = !DILocation(line: 0, scope: ![[SUBPROG18]], inlinedAt: ![[LOC24:.*]]) +// CHECK: ![[LOC24]] = !DILocation(line: [[@LINE+5]], column: 3, scope: ![[SUBPROG22]]) +// CHECK: ![[LOC25]] = !DILocation(line: 0, scope: ![[SUBPROG26:.*]], inlinedAt: ![[LOC27:.*]]) +// CHECK: ![[SUBPROG26]] = distinct !DISubprogram(name: "__clang_trap_msg$category2$hello", scope: ![[FILESCOPE]], file: ![[FILESCOPE]], type: !{{.*}}, flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: !{{.*}}) +// CHECK: ![[LOC27]] = !DILocation(line: [[@LINE+3]], column: 3, scope: ![[SUBPROG22]]) +void f1() { + __builtin_verbose_trap("category1", "Argument_must_not_be_null"); + __builtin_verbose_trap("category2", "hello"); +} + +// CHECK: ![[SUBPROG32:.*]] = distinct !DISubprogram(name: "f2", linkageName: "_Z2f2IXadsoKcL_ZL8constCatEEEXadsoS0_L_ZL8constMsgEEEEvv", +// CHECK: ![[LOC36]] = !DILocation(line: 0, scope: ![[SUBPROG26]], inlinedAt: ![[LOC37:.*]]) +// CHECK: ![[LOC37]] = !DILocation(line: [[@LINE+3]], column: 3, scope: ![[SUBPROG32]]) +template +void f2() { + __builtin_verbose_trap(category, reason); +} + +void f3() { + f2(); +} diff --git a/clang/test/CodeGenCXX/fmv-namespace.cpp b/clang/test/CodeGenCXX/fmv-namespace.cpp index 5bcd0da06eebc3..193f01db4c5d3a 100644 --- a/clang/test/CodeGenCXX/fmv-namespace.cpp +++ b/clang/test/CodeGenCXX/fmv-namespace.cpp @@ -19,8 +19,6 @@ int baz() { return OtherName::foo(); } //. // CHECK: @__aarch64_cpu_features = external dso_local global { i64 } -// CHECK: @_ZN4Name3fooEv.ifunc = weak_odr alias i32 (), ptr @_ZN4Name3fooEv -// CHECK: @_ZN9OtherName3fooEv.ifunc = weak_odr alias i32 (), ptr @_ZN9OtherName3fooEv // CHECK: @_ZN4Name3fooEv = weak_odr ifunc i32 (), ptr @_ZN4Name3fooEv.resolver // CHECK: @_ZN9OtherName3fooEv = weak_odr ifunc i32 (), ptr @_ZN9OtherName3fooEv.resolver //. diff --git a/clang/test/CodeGenCXX/microsoft-uuidof.cpp b/clang/test/CodeGenCXX/microsoft-uuidof.cpp index 35b4f027e54d1d..2de964a152dd56 100644 --- a/clang/test/CodeGenCXX/microsoft-uuidof.cpp +++ b/clang/test/CodeGenCXX/microsoft-uuidof.cpp @@ -4,6 +4,13 @@ // RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-pc-linux -fms-extensions | FileCheck %s --check-prefix=CHECK-64 // RUN: %clang_cc1 -emit-llvm %s -o - -DDEFINE_GUID -DWRONG_GUID -triple=i386-pc-linux -fms-extensions | FileCheck %s --check-prefix=CHECK-DEFINE-WRONG-GUID +/// The same, but with the new constant interpreter. +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -emit-llvm %s -o - -DDEFINE_GUID -triple=i386-pc-linux -fms-extensions | FileCheck %s --check-prefix=CHECK-DEFINE-GUID +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -emit-llvm %s -o - -DDEFINE_GUID -DBRACKET_ATTRIB -triple=i386-pc-linux -fms-extensions | FileCheck %s --check-prefix=CHECK-DEFINE-GUID +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -emit-llvm %s -o - -triple=i386-pc-linux -fms-extensions | FileCheck %s +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -emit-llvm %s -o - -triple=x86_64-pc-linux -fms-extensions | FileCheck %s --check-prefix=CHECK-64 +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -emit-llvm %s -o - -DDEFINE_GUID -DWRONG_GUID -triple=i386-pc-linux -fms-extensions | FileCheck %s --check-prefix=CHECK-DEFINE-WRONG-GUID + #ifdef DEFINE_GUID struct _GUID { #ifdef WRONG_GUID diff --git a/clang/test/CodeGenCXX/msabi-preserve-none-cc.cpp b/clang/test/CodeGenCXX/msabi-preserve-none-cc.cpp new file mode 100644 index 00000000000000..29df5e4d84a700 --- /dev/null +++ b/clang/test/CodeGenCXX/msabi-preserve-none-cc.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -fdeclspec -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple aarch64-unknown-windows-msvc -fdeclspec -emit-llvm %s -o - | FileCheck %s + +void __attribute__((__preserve_none__)) f() {} +// CHECK-DAG: @"?f@@YVXXZ" + +void (__attribute__((__preserve_none__)) *p)(); +// CHECK-DAG: @"?p@@3P6VXXZEA + +namespace { +void __attribute__((__preserve_none__)) __attribute__((__used__)) f() { } +} +// CHECK-DAG: @"?f@?A0x{{[^@]*}}@@YVXXZ" + +namespace n { +void __attribute__((__preserve_none__)) f() {} +} +// CHECK-DAG: @"?f@n@@YVXXZ" + +struct __declspec(dllexport) S { + S(const S &) = delete; + S & operator=(const S &) = delete; + void __attribute__((__preserve_none__)) m() { } +}; +// CHECK-DAG: @"?m@S@@QEAVXXZ" + +void f(void (__attribute__((__preserve_none__))())) {} +// CHECK-DAG: @"?f@@YAXP6VXXZ@Z" diff --git a/clang/test/CodeGenCXX/ptrauth-apple-kext-indirect-call-2.cpp b/clang/test/CodeGenCXX/ptrauth-apple-kext-indirect-call-2.cpp new file mode 100644 index 00000000000000..c2f20d56b0a6b0 --- /dev/null +++ b/clang/test/CodeGenCXX/ptrauth-apple-kext-indirect-call-2.cpp @@ -0,0 +1,105 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fapple-kext -fno-rtti -emit-llvm -o - %s | FileCheck %s + +// CHECK: @_ZTV1A = unnamed_addr constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr null, ptr ptrauth (ptr @_ZNK1A3abcEv, i32 0, i64 12401, ptr getelementptr inbounds ({ [4 x ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 2)), ptr null] }, align 8 +// CHECK: @_ZTV4Base = unnamed_addr constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr null, ptr ptrauth (ptr @_ZNK4Base3abcEv, i32 0, i64 64320, ptr getelementptr inbounds ({ [4 x ptr] }, ptr @_ZTV4Base, i32 0, i32 0, i32 2)), ptr null] }, align 8 +// CHECK: @_ZTV8Derived2 = unnamed_addr constant { [5 x ptr] } { [5 x ptr] [ptr null, ptr null, ptr null, ptr ptrauth (ptr @_ZNK8Derived23efgEv, i32 0, i64 36603, ptr getelementptr inbounds ({ [5 x ptr] }, ptr @_ZTV8Derived2, i32 0, i32 0, i32 3)), ptr null] }, align 8 +// CHECK: @_ZTV2D2 = unnamed_addr constant { [5 x ptr] } { [5 x ptr] [ptr null, ptr null, ptr null, ptr ptrauth (ptr @_ZNK2D23abcEv, i32 0, i64 20222, ptr getelementptr inbounds ({ [5 x ptr] }, ptr @_ZTV2D2, i32 0, i32 0, i32 3)), ptr null] }, align 8 + +struct A { + virtual const char* abc(void) const; +}; + +const char* A::abc(void) const {return "A"; }; + +struct B : virtual A { + virtual void VF(); +}; + +void B::VF() {} + +void FUNC(B* p) { +// CHECK: [[T1:%.*]] = load ptr, ptr getelementptr inbounds (ptr, ptr @_ZTV1A, i64 2) +// CHECK-NEXT: [[BT1:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr getelementptr inbounds (ptr, ptr @_ZTV1A, i64 2) to i64), i64 12401) +// CHECK-NEXT: [[T2:%.*]] = call noundef ptr [[T1]](ptr noundef {{.*}}) [ "ptrauth"(i32 0, i64 [[BT1]]) ] + const char* c = p->A::abc(); +} + + +// Test2 +struct Base { virtual char* abc(void) const; }; + +char* Base::abc() const { return 0; } + +struct Derived : public Base { +}; + +void FUNC1(Derived* p) { +// CHECK: [[U1:%.*]] = load ptr, ptr getelementptr inbounds (ptr, ptr @_ZTV4Base, i64 2) +// CHECK-NEXT: [[BU1:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr getelementptr inbounds (ptr, ptr @_ZTV4Base, i64 2) to i64), i64 64320) +// CHECK-NEXT: [[U2:%.*]] = call noundef ptr [[U1]](ptr noundef {{.*}}) [ "ptrauth"(i32 0, i64 [[BU1]]) ] + char* c = p->Base::abc(); +} + + +// Test3 +struct Base2 { }; + +struct Derived2 : virtual Base2 { + virtual char* efg(void) const; +}; + +char* Derived2::efg(void) const { return 0; } + +void FUNC2(Derived2* p) { +// CHECK: [[V1:%.*]] = load ptr, ptr getelementptr inbounds (ptr, ptr @_ZTV8Derived2, i64 3) +// CHECK-NEXT: [[BV1:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr getelementptr inbounds (ptr, ptr @_ZTV8Derived2, i64 3) to i64), i64 36603) +// CHECK-NEXT: [[V2:%.*]] = call noundef ptr [[V1]](ptr noundef {{.*}}) [ "ptrauth"(i32 0, i64 [[BV1]]) ] + char* c = p->Derived2::efg(); +} + +// Test4 +struct Base3 { }; + +struct D1 : virtual Base3 { +}; + +struct D2 : virtual Base3 { + virtual char *abc(void) const; +}; + +struct Sub : D1, D2 { +}; + +char* D2::abc(void) const { return 0; } + +void FUNC3(Sub* p) { +// CHECK: [[W1:%.*]] = load ptr, ptr getelementptr inbounds (ptr, ptr @_ZTV2D2, i64 3) +// CHECK-NEXT: [[BW1:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr getelementptr inbounds (ptr, ptr @_ZTV2D2, i64 3) to i64), i64 20222) +// CHECK-NEXT: [[W2:%.*]] = call noundef ptr [[W1]](ptr noundef {{.*}}) [ "ptrauth"(i32 0, i64 [[BW1]]) ] + char* c = p->D2::abc(); +} + + +// Test4 +struct Base4 { virtual void abc(); }; + +void Base4::abc() {} + +struct Derived4 : public Base4 { + void abc() override; +}; + +void Derived4::abc() {} + +void FUNC4(Derived4* p) { +// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}} +// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64 +// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0) +// CHECK: %[[T4:[0-9]+]] = inttoptr i64 %[[T3]] to ptr +// CHECK: %[[VFN:[a-z]+]] = getelementptr inbounds ptr, ptr %[[T4]], i64 0 +// CHECK: %[[T5:[0-9]+]] = load ptr, ptr %[[VFN]] +// CHECK: %[[T6:[0-9]+]] = ptrtoint ptr %[[VFN]] to i64 +// CHECK: %[[T7:[0-9]+]] = call i64 @llvm.ptrauth.blend(i64 %[[T6]], i64 426) +// CHECK: call void %[[T5]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(8) %{{.*}}) [ "ptrauth"(i32 0, i64 %[[T7]]) ] + p->abc(); +} diff --git a/clang/test/CodeGenCXX/ptrauth-apple-kext-indirect-call.cpp b/clang/test/CodeGenCXX/ptrauth-apple-kext-indirect-call.cpp new file mode 100644 index 00000000000000..996829a14d7d16 --- /dev/null +++ b/clang/test/CodeGenCXX/ptrauth-apple-kext-indirect-call.cpp @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fapple-kext -emit-llvm -o - %s | FileCheck %s + +// CHECK: @_ZTV5TemplIiE = internal unnamed_addr constant { [5 x ptr] } { [5 x ptr] [ptr null, ptr @_ZTI5TemplIiE, ptr ptrauth (ptr @_ZN5TemplIiE1fEv, i32 0, i64 22189, ptr getelementptr inbounds ({ [5 x ptr] }, ptr @_ZTV5TemplIiE, i32 0, i32 0, i32 2)), ptr ptrauth (ptr @_ZN5TemplIiE1gEv, i32 0, i64 9912, ptr getelementptr inbounds ({ [5 x ptr] }, ptr @_ZTV5TemplIiE, i32 0, i32 0, i32 3)), ptr null] }, align 8 + +struct Base { + virtual void abc(void) const; +}; + +void Base::abc(void) const {} + +void FUNC(Base* p) { + p->Base::abc(); +} + +// CHECK: getelementptr inbounds (ptr, ptr @_ZTV4Base, i64 2) +// CHECK-NOT: call void @_ZNK4Base3abcEv + +template +struct Templ { + virtual void f() {} + virtual void g() {} +}; +template +struct SubTempl : public Templ { + virtual void f() {} // override + virtual void g() {} // override +}; + +void f(SubTempl* t) { + // Qualified calls go through the (qualified) vtable in apple-kext mode. + // Since t's this pointer points to SubTempl's vtable, the call needs + // to load Templ's vtable. Hence, Templ::g needs to be + // instantiated in this TU, for it's referenced by the vtable. + // (This happens only in apple-kext mode; elsewhere virtual calls can always + // use the vtable pointer off this instead of having to load the vtable + // symbol.) + t->Templ::f(); +} + +// CHECK: getelementptr inbounds (ptr, ptr @_ZTV5TemplIiE, i64 2) +// CHECK: define internal void @_ZN5TemplIiE1fEv(ptr noundef nonnull align {{[0-9]+}} dereferenceable(8) %this) +// CHECK: define internal void @_ZN5TemplIiE1gEv(ptr noundef nonnull align {{[0-9]+}} dereferenceable(8) %this) diff --git a/clang/test/CodeGenCXX/ptrauth-apple-kext-indirect-virtual-dtor-call.cpp b/clang/test/CodeGenCXX/ptrauth-apple-kext-indirect-virtual-dtor-call.cpp new file mode 100644 index 00000000000000..7bcf1fbfdb9de9 --- /dev/null +++ b/clang/test/CodeGenCXX/ptrauth-apple-kext-indirect-virtual-dtor-call.cpp @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -std=c++98 -fptrauth-calls -fapple-kext -fno-rtti -disable-O0-optnone -emit-llvm -o - %s | FileCheck %s + +// CHECK: @_ZTV5TemplIiE = internal unnamed_addr constant { [7 x ptr] } { [7 x ptr] [ptr null, ptr null, ptr ptrauth (ptr @_ZN5TemplIiED1Ev, i32 0, i64 57986, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV5TemplIiE, i32 0, i32 0, i32 2)), ptr ptrauth (ptr @_ZN5TemplIiED0Ev, i32 0, i64 22856, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV5TemplIiE, i32 0, i32 0, i32 3)), ptr ptrauth (ptr @_ZN5TemplIiE1fEv, i32 0, i64 22189, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV5TemplIiE, i32 0, i32 0, i32 4)), ptr ptrauth (ptr @_ZN5TemplIiE1gEv, i32 0, i64 9912, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV5TemplIiE, i32 0, i32 0, i32 5)), ptr null] }, align 8 + +struct B1 { + virtual ~B1(); +}; + +B1::~B1() {} + +void DELETE(B1 *pb1) { + pb1->B1::~B1(); +} +// CHECK-LABEL: define void @_ZN2B1D0Ev +// CHECK: [[T1:%.*]] = load ptr, ptr getelementptr inbounds (ptr, ptr @_ZTV2B1, i64 2) +// CHECK-NEXT: [[B1:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr getelementptr inbounds (ptr, ptr @_ZTV2B1, i64 2) to i64), i64 14635) +// CHECK-NEXT: call noundef ptr [[T1]](ptr noundef nonnull align 8 dereferenceable(8) [[T2:%.*]]) [ "ptrauth"(i32 0, i64 [[B1]]) ] +// CHECK-LABEL: define void @_Z6DELETEP2B1 +// CHECK: [[T3:%.*]] = load ptr, ptr getelementptr inbounds (ptr, ptr @_ZTV2B1, i64 2) +// CHECK-NEXT: [[B3:%.*]] = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr getelementptr inbounds (ptr, ptr @_ZTV2B1, i64 2) to i64), i64 14635) +// CHECK-NEXT: call noundef ptr [[T3]](ptr noundef nonnull align 8 dereferenceable(8) [[T4:%.*]]) [ "ptrauth"(i32 0, i64 [[B3]]) + +template +struct Templ { + virtual ~Templ(); // Out-of-line so that the destructor doesn't cause a vtable + virtual void f() {} + virtual void g() {} +}; +template +struct SubTempl : public Templ { + virtual ~SubTempl() {} // override + virtual void f() {} // override + virtual void g() {} // override +}; + +void f(SubTempl* t) { + // Qualified calls go through the (qualified) vtable in apple-kext mode. + // Since t's this pointer points to SubTempl's vtable, the call needs + // to load Templ's vtable. Hence, Templ::g needs to be + // instantiated in this TU, for it's referenced by the vtable. + // (This happens only in apple-kext mode; elsewhere virtual calls can always + // use the vtable pointer off this instead of having to load the vtable + // symbol.) + t->Templ::~Templ(); +} + +// CHECK: getelementptr inbounds (ptr, ptr @_ZTV5TemplIiE, i64 2) +// CHECK: declare void @_ZN5TemplIiED0Ev(ptr noundef nonnull align 8 dereferenceable(8)) +// CHECK: define internal void @_ZN5TemplIiE1fEv(ptr noundef nonnull align 8 dereferenceable(8) %this) +// CHECK: define internal void @_ZN5TemplIiE1gEv(ptr noundef nonnull align 8 dereferenceable(8) %this) diff --git a/clang/test/CodeGenCXX/ptrauth-explicit-vtable-pointer-control.cpp b/clang/test/CodeGenCXX/ptrauth-explicit-vtable-pointer-control.cpp new file mode 100644 index 00000000000000..e6497b3f152aa0 --- /dev/null +++ b/clang/test/CodeGenCXX/ptrauth-explicit-vtable-pointer-control.cpp @@ -0,0 +1,564 @@ +// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics \ +// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,NODISC %s + +// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics \ +// RUN: -fptrauth-vtable-pointer-type-discrimination \ +// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,TYPE %s + +// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics \ +// RUN: -fptrauth-vtable-pointer-address-discrimination \ +// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,ADDR %s + +// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics \ +// RUN: -fptrauth-vtable-pointer-type-discrimination \ +// RUN: -fptrauth-vtable-pointer-address-discrimination \ +// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,BOTH %s + +#include + +namespace test1 { + +#define authenticated(a...) ptrauth_cxx_vtable_pointer(a) + +struct NoExplicitAuth { + virtual ~NoExplicitAuth(); + virtual void f(); + virtual void g(); +}; + +struct authenticated(no_authentication, no_address_discrimination, no_extra_discrimination) ExplicitlyDisableAuth { + virtual ~ExplicitlyDisableAuth(); + virtual void f(); + virtual void g(); +}; + +struct authenticated(default_key, address_discrimination, default_extra_discrimination) ExplicitAddressDiscrimination { + virtual ~ExplicitAddressDiscrimination(); + virtual void f(); + virtual void g(); +}; + +struct authenticated(default_key, no_address_discrimination, default_extra_discrimination) ExplicitNoAddressDiscrimination { + virtual ~ExplicitNoAddressDiscrimination(); + virtual void f(); + virtual void g(); +}; + +struct authenticated(default_key, default_address_discrimination, no_extra_discrimination) ExplicitNoExtraDiscrimination { + virtual ~ExplicitNoExtraDiscrimination(); + virtual void f(); + virtual void g(); +}; + +struct authenticated(default_key, default_address_discrimination, type_discrimination) ExplicitTypeDiscrimination { + virtual ~ExplicitTypeDiscrimination(); + virtual void f(); + virtual void g(); +}; + +struct authenticated(default_key, default_address_discrimination, custom_discrimination, 42424) ExplicitCustomDiscrimination { + virtual ~ExplicitCustomDiscrimination(); + virtual void f(); + virtual void g(); +}; + +template +struct SubClass : T { + virtual void g(); + virtual T *h(); +}; + +template +SubClass *make_subclass(T *); + +struct authenticated(default_key, address_discrimination, type_discrimination) BasicStruct { + virtual ~BasicStruct(); +}; + +template +struct PrimaryBasicStruct : BasicStruct, T {}; +template +struct PrimaryBasicStruct *make_multiple_primary(T *); + +template +struct VirtualSubClass : virtual T { + virtual void g(); + virtual T *h(); +}; +template +struct VirtualPrimaryStruct : virtual T, VirtualSubClass {}; +template +struct VirtualPrimaryStruct *make_virtual_primary(T *); + +extern "C" { + +// CHECK: @TVDisc_NoExplicitAuth = global i32 [[DISC_DEFAULT:49565]], align 4 +int TVDisc_NoExplicitAuth = ptrauth_string_discriminator("_ZTVN5test114NoExplicitAuthE"); + +// CHECK: @TVDisc_ExplicitlyDisableAuth = global i32 [[DISC_DISABLED:24369]], align 4 +int TVDisc_ExplicitlyDisableAuth = ptrauth_string_discriminator("_ZTVN5test121ExplicitlyDisableAuthE"); + +// CHECK: @TVDisc_ExplicitAddressDiscrimination = global i32 [[DISC_ADDR:56943]], align 4 +int TVDisc_ExplicitAddressDiscrimination = ptrauth_string_discriminator("_ZTVN5test129ExplicitAddressDiscriminationE"); + +// CHECK: @TVDisc_ExplicitNoAddressDiscrimination = global i32 [[DISC_NO_ADDR:6022]], align 4 +int TVDisc_ExplicitNoAddressDiscrimination = ptrauth_string_discriminator("_ZTVN5test131ExplicitNoAddressDiscriminationE"); + +// CHECK: @TVDisc_ExplicitNoExtraDiscrimination = global i32 [[DISC_NO_EXTRA:9072]], align 4 +int TVDisc_ExplicitNoExtraDiscrimination = ptrauth_string_discriminator("_ZTVN5test129ExplicitNoExtraDiscriminationE"); + +// CHECK: @TVDisc_ExplicitTypeDiscrimination = global i32 [[DISC_TYPE:6177]], align 4 +int TVDisc_ExplicitTypeDiscrimination = ptrauth_string_discriminator("_ZTVN5test126ExplicitTypeDiscriminationE"); + + +// CHECK-LABEL: define void @test_default(ptr noundef {{%.*}}) {{#.*}} { +// CHECK: [[VTADDR:%.*]] = load ptr, ptr {{%.*}}, align 8 +// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8 +// +// NODISC: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// NODISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 0) +// +// TYPE: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// TYPE: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[DISC_DEFAULT]]) +// +// ADDR: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// ADDR: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// ADDR: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[VTADDRI64]]) +// +// BOTH: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// BOTH: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTADDRI64]], i64 [[DISC_DEFAULT]]) +// BOTH: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// BOTH: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[BLEND]]) +void test_default(NoExplicitAuth *a) { + a->f(); +} + +// CHECK-LABEL: define void @test_disabled(ptr noundef {{%.*}}) {{#.*}} { +// CHECK: [[VTADDR:%.*]] = load ptr, ptr {{%.*}}, align 8 +// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8 +// CHECK-NOT: call i64 @llvm.ptrauth.auth +void test_disabled(ExplicitlyDisableAuth *a) { + a->f(); +} + +// CHECK-LABEL: define void @test_addr_disc(ptr noundef {{%.*}}) {{#.*}} { +// CHECK: [[VTADDR:%.*]] = load ptr, ptr {{%.*}}, align 8 +// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8 +// +// NODISC: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// NODISC: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// NODISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[VTADDRI64]]) +// +// TYPE: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// TYPE: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTADDRI64]], i64 [[DISC_ADDR]]) +// TYPE: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// TYPE: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[BLEND]]) +// +// ADDR: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// ADDR: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// ADDR: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[VTADDRI64]]) +// +// BOTH: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// BOTH: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTADDRI64]], i64 [[DISC_ADDR]]) +// BOTH: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// BOTH: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[BLEND]]) +void test_addr_disc(ExplicitAddressDiscrimination *a) { + a->f(); +} + +// CHECK-LABEL: define void @test_no_addr_disc(ptr noundef {{%.*}}) {{#.*}} { +// CHECK: [[VTADDR:%.*]] = load ptr, ptr {{%.*}}, align 8 +// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8 +// +// NODISC: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// NODISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 0) +// +// TYPE: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// TYPE: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[DISC_NO_ADDR]]) +// +// ADDR: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// ADDR: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 0) +// +// BOTH: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// BOTH: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[DISC_NO_ADDR]]) +void test_no_addr_disc(ExplicitNoAddressDiscrimination *a) { + a->f(); +} + +// CHECK-LABEL: define void @test_no_extra_disc(ptr noundef {{%.*}}) {{#.*}} { +// CHECK: [[VTADDR:%.*]] = load ptr, ptr {{%.*}}, align 8 +// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8 +// +// NODISC: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// NODISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 0) +// +// TYPE: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// TYPE: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 0) +// +// ADDR: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// ADDR: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// ADDR: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[VTADDRI64]]) +// +// BOTH: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// BOTH: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// BOTH: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[VTADDRI64]]) +void test_no_extra_disc(ExplicitNoExtraDiscrimination *a) { + a->f(); +} + +// CHECK-LABEL: define void @test_type_disc(ptr noundef {{%.*}}) {{#.*}} { +// CHECK: [[VTADDR:%.*]] = load ptr, ptr {{%.*}}, align 8 +// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8 +// +// NODISC: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// NODISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[DISC_TYPE]]) +// +// TYPE: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// TYPE: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[DISC_TYPE]]) +// +// ADDR: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// ADDR: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTADDRI64]], i64 [[DISC_TYPE]]) +// ADDR: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// ADDR: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[BLEND]]) +// +// BOTH: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// BOTH: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTADDRI64]], i64 [[DISC_TYPE]]) +// BOTH: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// BOTH: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[BLEND]]) +void test_type_disc(ExplicitTypeDiscrimination *a) { + a->f(); +} + +// CHECK-LABEL: define void @test_custom_disc(ptr noundef {{%.*}}) {{#.*}} { +// CHECK: [[VTADDR:%.*]] = load ptr, ptr {{%.*}}, align 8 +// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8 +// +// NODISC: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// NODISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 42424) +// +// TYPE: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// TYPE: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 42424) +// +// ADDR: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// ADDR: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTADDRI64]], i64 42424) +// ADDR: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// ADDR: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[BLEND]]) +// +// BOTH: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// BOTH: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTADDRI64]], i64 42424) +// BOTH: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// BOTH: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[BLEND]]) +void test_custom_disc(ExplicitCustomDiscrimination *a) { + a->f(); +} + +// +// Test some simple single inheritance cases. +// Codegen should be the same as the simple cases above once we have a vtable. +// + +// CHECK-LABEL: define void @test_subclass_default(ptr noundef {{%.*}}) {{#.*}} { +// CHECK: [[VTADDR:%.*]] = call noundef ptr @_ZN5test113make_subclass +// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8 +// +// NODISC: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// NODISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 0) +// +// TYPE: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// TYPE: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[DISC_DEFAULT]]) +// +// ADDR: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// ADDR: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// ADDR: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[VTADDRI64]]) +// +// BOTH: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// BOTH: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTADDRI64]], i64 [[DISC_DEFAULT]]) +// BOTH: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// BOTH: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[BLEND]]) +void test_subclass_default(NoExplicitAuth *a) { + make_subclass(a)->f(); +} + +// CHECK-LABEL: define void @test_subclass_disabled(ptr noundef {{%.*}}) {{#.*}} { +// CHECK: [[VTADDR:%.*]] = call noundef ptr @_ZN5test113make_subclass +// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8 +// CHECK-NOT: call i64 @llvm.ptrauth.auth +void test_subclass_disabled(ExplicitlyDisableAuth *a) { + make_subclass(a)->f(); +} + +// CHECK-LABEL: define void @test_subclass_addr_disc(ptr noundef {{%.*}}) {{#.*}} { +// CHECK: [[VTADDR:%.*]] = call noundef ptr @_ZN5test113make_subclass +// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8 +// +// NODISC: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// NODISC: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// NODISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[VTADDRI64]]) +// +// TYPE: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// TYPE: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTADDRI64]], i64 [[DISC_ADDR]]) +// TYPE: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// TYPE: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[BLEND]]) +// +// ADDR: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// ADDR: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// ADDR: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[VTADDRI64]]) +// +// BOTH: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// BOTH: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTADDRI64]], i64 [[DISC_ADDR]]) +// BOTH: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// BOTH: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[BLEND]]) +void test_subclass_addr_disc(ExplicitAddressDiscrimination *a) { + make_subclass(a)->f(); +} + +// CHECK-LABEL: define void @test_subclass_no_addr_disc(ptr noundef {{%.*}}) {{#.*}} { +// CHECK: [[VTADDR:%.*]] = call noundef ptr @_ZN5test113make_subclass +// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8 +// +// NODISC: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// NODISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 0) +// +// TYPE: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// TYPE: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[DISC_NO_ADDR]]) +// +// ADDR: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// ADDR: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 0) +// +// BOTH: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// BOTH: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[DISC_NO_ADDR]]) +void test_subclass_no_addr_disc(ExplicitNoAddressDiscrimination *a) { + make_subclass(a)->f(); +} + +// CHECK-LABEL: define void @test_subclass_no_extra_disc(ptr noundef {{%.*}}) {{#.*}} { +// CHECK: [[VTADDR:%.*]] = call noundef ptr @_ZN5test113make_subclass +// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8 +// +// NODISC: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// NODISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 0) +// +// TYPE: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// TYPE: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 0) +// +// ADDR: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// ADDR: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// ADDR: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[VTADDRI64]]) +// +// BOTH: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// BOTH: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// BOTH: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[VTADDRI64]]) +void test_subclass_no_extra_disc(ExplicitNoExtraDiscrimination *a) { + make_subclass(a)->f(); +} + +// CHECK-LABEL: define void @test_subclass_type_disc(ptr noundef {{%.*}}) {{#.*}} { +// CHECK: [[VTADDR:%.*]] = call noundef ptr @_ZN5test113make_subclass +// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8 +// +// NODISC: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// NODISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[DISC_TYPE]]) +// +// TYPE: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// TYPE: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[DISC_TYPE]]) +// +// ADDR: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// ADDR: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTADDRI64]], i64 [[DISC_TYPE]]) +// ADDR: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// ADDR: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[BLEND]]) +// +// BOTH: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// BOTH: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTADDRI64]], i64 [[DISC_TYPE]]) +// BOTH: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// BOTH: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[BLEND]]) +void test_subclass_type_disc(ExplicitTypeDiscrimination *a) { + make_subclass(a)->f(); +} + +// CHECK-LABEL: define void @test_subclass_custom_disc(ptr noundef {{%.*}}) {{#.*}} { +// CHECK: [[VTADDR:%.*]] = call noundef ptr @_ZN5test113make_subclass +// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8 +// +// NODISC: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// NODISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 42424) +// +// TYPE: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// TYPE: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 42424) +// +// ADDR: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// ADDR: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTADDRI64]], i64 42424) +// ADDR: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// ADDR: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[BLEND]]) +// +// BOTH: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// BOTH: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTADDRI64]], i64 42424) +// BOTH: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// BOTH: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[BLEND]]) +void test_subclass_custom_disc(ExplicitCustomDiscrimination *a) { + make_subclass(a)->f(); +} + + +// +// Test some simple multiple inheritance cases. +// Codegen should be the same as the simple cases above once we have a vtable. +// + +// CHECK-LABEL: define void @test_multiple_default(ptr noundef {{%.*}}) {{#.*}} { +// CHECK: [[CALL:%.*]] = call noundef ptr @_ZN5test121make_multiple_primary +// CHECK: [[VTADDR:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 8 +// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8 +// +// NODISC: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// NODISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 0) +// +// TYPE: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// TYPE: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[DISC_DEFAULT]]) +// +// ADDR: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// ADDR: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// ADDR: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[VTADDRI64]]) +// +// BOTH: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// BOTH: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTADDRI64]], i64 [[DISC_DEFAULT]]) +// BOTH: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// BOTH: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[BLEND]]) +void test_multiple_default(NoExplicitAuth *a) { + make_multiple_primary(a)->f(); +} + +// CHECK-LABEL: define void @test_multiple_disabled(ptr noundef {{%.*}}) {{#.*}} { +// CHECK: [[CALL:%.*]] = call noundef ptr @_ZN5test121make_multiple_primary +// CHECK: [[VTADDR:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 8 +// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8 +// CHECK-NOT: call i64 @llvm.ptrauth.auth +void test_multiple_disabled(ExplicitlyDisableAuth *a) { + make_multiple_primary(a)->f(); +} + +// CHECK-LABEL: define void @test_multiple_custom_disc(ptr noundef {{%.*}}) {{#.*}} { +// CHECK: [[CALL:%.*]] = call noundef ptr @_ZN5test121make_multiple_primary +// CHECK: [[VTADDR:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 8 +// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8 +// +// NODISC: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// NODISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 42424) +// +// TYPE: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// TYPE: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 42424) +// +// ADDR: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// ADDR: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTADDRI64]], i64 42424) +// ADDR: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// ADDR: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[BLEND]]) +// +// BOTH: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// BOTH: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTADDRI64]], i64 42424) +// BOTH: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// BOTH: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[BLEND]]) +void test_multiple_custom_disc(ExplicitCustomDiscrimination *a) { + make_multiple_primary(a)->f(); +} + +// +// Test some virtual inheritance cases. +// Codegen should be the same as the simple cases above once we have a vtable, +// but twice for vtt/vtable. The names in the vtt version have "VTT" prefixes. +// + +// CHECK-LABEL: define void @test_virtual_default(ptr noundef {{%.*}}) {{#.*}} { +// CHECK: [[VTTADDR:%.*]] = call noundef ptr @_ZN5test120make_virtual_primary +// CHECK: [[VTTABLE:%.*]] = load ptr, ptr [[VTTADDR]], align 8 +// +// NODISC: [[VTTABLEI64:%.*]] = ptrtoint ptr [[VTTABLE]] to i64 +// NODISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTTABLEI64]], i32 2, i64 0) +// +// TYPE: [[VTTABLEI64:%.*]] = ptrtoint ptr [[VTTABLE]] to i64 +// TYPE: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTTABLEI64]], i32 2, i64 [[DISC_DEFAULT]]) +// +// ADDR: [[VTTADDRI64:%.*]] = ptrtoint ptr [[VTTADDR]] to i64 +// ADDR: [[VTTABLEI64:%.*]] = ptrtoint ptr [[VTTABLE]] to i64 +// ADDR: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTTABLEI64]], i32 2, i64 [[VTTADDRI64]]) +// +// BOTH: [[VTTADDRI64:%.*]] = ptrtoint ptr [[VTTADDR]] to i64 +// BOTH: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTTADDRI64]], i64 [[DISC_DEFAULT]]) +// BOTH: [[VTTABLEI64:%.*]] = ptrtoint ptr [[VTTABLE]] to i64 +// BOTH: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTTABLEI64]], i32 2, i64 [[BLEND]]) + +// CHECK: [[AUTHEDPTR:%.*]] = inttoptr i64 [[AUTHED]] to ptr +// CHECK: [[VBOFFPTR:%.*]] = getelementptr i8, ptr [[AUTHEDPTR]], i64 -48 +// CHECK: [[VBOFFSET:%.*]] = load i64, ptr [[VBOFFPTR]] +// CHECK: [[VTADDR:%.*]] = getelementptr inbounds i8, ptr [[VTTADDR]], i64 [[VBOFFSET]] +// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8 +// +// NODISC: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// NODISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 0) +// +// TYPE: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// TYPE: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[DISC_DEFAULT]]) +// +// ADDR: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// ADDR: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// ADDR: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[VTADDRI64]]) +// +// BOTH: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// BOTH: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTADDRI64]], i64 [[DISC_DEFAULT]]) +// BOTH: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// BOTH: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[BLEND]]) +void test_virtual_default(NoExplicitAuth *a) { + make_virtual_primary(a)->f(); +} + +// CHECK-LABEL: define void @test_virtual_disabled(ptr noundef {{%.*}}) {{#.*}} { +// CHECK-NOT: call i64 @llvm.ptrauth.auth +void test_virtual_disabled(ExplicitlyDisableAuth *a) { + make_virtual_primary(a)->f(); +} + +// CHECK-LABEL: define void @test_virtual_custom_disc(ptr noundef {{%.*}}) {{#.*}} { +// CHECK: [[VTTADDR:%.*]] = call noundef ptr @_ZN5test120make_virtual_primary +// CHECK: [[VTTABLE:%.*]] = load ptr, ptr [[VTTADDR]], align 8 +// +// NODISC: [[VTTABLEI64:%.*]] = ptrtoint ptr [[VTTABLE]] to i64 +// NODISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTTABLEI64]], i32 2, i64 42424) +// +// TYPE: [[VTTABLEI64:%.*]] = ptrtoint ptr [[VTTABLE]] to i64 +// TYPE: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTTABLEI64]], i32 2, i64 42424) +// +// ADDR: [[VTTADDRI64:%.*]] = ptrtoint ptr [[VTTADDR]] to i64 +// ADDR: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTTADDRI64]], i64 42424) +// ADDR: [[VTTABLEI64:%.*]] = ptrtoint ptr [[VTTABLE]] to i64 +// ADDR: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTTABLEI64]], i32 2, i64 [[BLEND]]) +// +// BOTH: [[VTTADDRI64:%.*]] = ptrtoint ptr [[VTTADDR]] to i64 +// BOTH: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTTADDRI64]], i64 42424) +// BOTH: [[VTTABLEI64:%.*]] = ptrtoint ptr [[VTTABLE]] to i64 +// BOTH: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTTABLEI64]], i32 2, i64 [[BLEND]]) + +// CHECK: [[AUTHEDPTR:%.*]] = inttoptr i64 [[AUTHED]] to ptr +// CHECK: [[VBOFFPTR:%.*]] = getelementptr i8, ptr [[AUTHEDPTR]], i64 -48 +// CHECK: [[VBOFFSET:%.*]] = load i64, ptr [[VBOFFPTR]] +// CHECK: [[VTADDR:%.*]] = getelementptr inbounds i8, ptr [[VTTADDR]], i64 [[VBOFFSET]] +// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8 +// +// NODISC: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// NODISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 42424) +// +// TYPE: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// TYPE: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 42424) +// +// ADDR: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// ADDR: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTADDRI64]], i64 42424) +// ADDR: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// ADDR: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[BLEND]]) +// +// BOTH: [[VTADDRI64:%.*]] = ptrtoint ptr [[VTADDR]] to i64 +// BOTH: [[BLEND:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[VTADDRI64]], i64 42424) +// BOTH: [[VTABLEI64:%.*]] = ptrtoint ptr [[VTABLE]] to i64 +// BOTH: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VTABLEI64]], i32 2, i64 [[BLEND]]) +void test_virtual_custom_disc(ExplicitCustomDiscrimination *a) { + make_virtual_primary(a)->f(); +} + +} // extern "C" +} // namespace test1 diff --git a/clang/test/CodeGenCXX/ptrauth-rtti-layout.cpp b/clang/test/CodeGenCXX/ptrauth-rtti-layout.cpp new file mode 100644 index 00000000000000..b4a8784a33d8cd --- /dev/null +++ b/clang/test/CodeGenCXX/ptrauth-rtti-layout.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 %s -I%S -triple=arm64-apple-ios -fptrauth-calls -std=c++11 -emit-llvm -o - | FileCheck %s +#include + +struct A { int a; }; + +// CHECK: @_ZTVN10__cxxabiv117__class_type_infoE = external global [0 x ptr] +// CHECK: @_ZTS1A = linkonce_odr hidden constant [3 x i8] c"1A\00" +// CHECK: @_ZTI1A = linkonce_odr hidden constant { ptr, ptr } { ptr ptrauth (ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), i32 2), ptr inttoptr (i64 add (i64 ptrtoint (ptr @_ZTS1A to i64), i64 -9223372036854775808) to ptr) } + +auto ATI = typeid(A); diff --git a/clang/test/CodeGenCXX/ptrauth-thunks.cpp b/clang/test/CodeGenCXX/ptrauth-thunks.cpp new file mode 100644 index 00000000000000..a85c8c4c065c46 --- /dev/null +++ b/clang/test/CodeGenCXX/ptrauth-thunks.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -emit-llvm -std=c++11 %s -o - | FileCheck %s + +namespace Test1 { + struct B1 { + virtual void* foo1() { + return 0; + } + }; + struct Pad1 { + virtual ~Pad1() {} + }; + struct Proxy1 : Pad1, B1 { + virtual ~Proxy1() {} + }; + struct D : virtual Proxy1 { + virtual ~D() {} + virtual void* foo1(); + }; + void* D::foo1() { + return (void*)this; + } +} + +// CHECK-LABEL: define linkonce_odr void @_ZTv0_n24_N5Test11DD0Ev(ptr noundef %this) +// CHECK: %[[This:.*]] = load ptr +// CHECK: %[[SignedVTable:.*]] = load ptr, ptr %[[This]], align 8 +// CHECK: %[[SignedVTableAsInt:.*]] = ptrtoint ptr %[[SignedVTable]] to i64 +// CHECK: %[[VTable:.*]] = call i64 @llvm.ptrauth.auth(i64 %[[SignedVTableAsInt]], i32 2, i64 0) diff --git a/clang/test/CodeGenCXX/ptrauth-virtual-function.cpp b/clang/test/CodeGenCXX/ptrauth-virtual-function.cpp new file mode 100644 index 00000000000000..563d60780769bb --- /dev/null +++ b/clang/test/CodeGenCXX/ptrauth-virtual-function.cpp @@ -0,0 +1,581 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -emit-llvm -std=c++11 %s -o - | FileCheck %s + +// Check virtual function pointers in vtables are signed. + +// CHECK: %[[CLASS_B1:.*]] = type { ptr } + +// CHECK: @_ZTV2B1 = unnamed_addr constant { [3 x ptr] } { [3 x ptr] [ptr null, ptr @_ZTI2B1, ptr ptrauth (ptr @_ZN2B12m0Ev, i32 0, i64 58196, ptr getelementptr inbounds ({ [3 x ptr] }, ptr @_ZTV2B1, i32 0, i32 0, i32 2))] }, align 8 + +// CHECK: @g_B1 = global %class.B1 { ptr ptrauth (ptr getelementptr inbounds inrange(-16, 8) ({ [3 x ptr] }, ptr @_ZTV2B1, i32 0, i32 0, i32 2), i32 2) }, align 8 + +// CHECK: @_ZTV2B0 = unnamed_addr constant { [7 x ptr] } { [7 x ptr] [ptr null, ptr @_ZTI2B0, +// CHECK-SAME: ptr ptrauth (ptr @_ZN2B02m0Ev, i32 0, i64 53119, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV2B0, i32 0, i32 0, i32 2)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2B02m1Ev, i32 0, i64 15165, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV2B0, i32 0, i32 0, i32 3)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2B02m2Ev, i32 0, i64 43073, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV2B0, i32 0, i32 0, i32 4)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2B0D1Ev, i32 0, i64 25525, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV2B0, i32 0, i32 0, i32 5)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2B0D0Ev, i32 0, i64 21295, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV2B0, i32 0, i32 0, i32 6))] }, align 8 + +// CHECK: @_ZTV2D0 = unnamed_addr constant { [9 x ptr] } { [9 x ptr] [ptr null, ptr @_ZTI2D0, +// CHECK-SAME: ptr ptrauth (ptr @_ZN2D02m0Ev, i32 0, i64 53119, ptr getelementptr inbounds ({ [9 x ptr] }, ptr @_ZTV2D0, i32 0, i32 0, i32 2)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTch0_h4_N2D02m1Ev, i32 0, i64 15165, ptr getelementptr inbounds ({ [9 x ptr] }, ptr @_ZTV2D0, i32 0, i32 0, i32 3)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2B02m2Ev, i32 0, i64 43073, ptr getelementptr inbounds ({ [9 x ptr] }, ptr @_ZTV2D0, i32 0, i32 0, i32 4)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2D0D1Ev, i32 0, i64 25525, ptr getelementptr inbounds ({ [9 x ptr] }, ptr @_ZTV2D0, i32 0, i32 0, i32 5)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2D0D0Ev, i32 0, i64 21295, ptr getelementptr inbounds ({ [9 x ptr] }, ptr @_ZTV2D0, i32 0, i32 0, i32 6)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2D02m1Ev, i32 0, i64 35045, ptr getelementptr inbounds ({ [9 x ptr] }, ptr @_ZTV2D0, i32 0, i32 0, i32 7)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2D02m3Ev, i32 0, i64 10565, ptr getelementptr inbounds ({ [9 x ptr] }, ptr @_ZTV2D0, i32 0, i32 0, i32 8))] }, align 8 + +// CHECK: @_ZTV2D1 = unnamed_addr constant { [8 x ptr] } { [8 x ptr] [ptr null, ptr @_ZTI2D1, +// CHECK-SAME: ptr ptrauth (ptr @_ZN2D12m0Ev, i32 0, i64 53119, ptr getelementptr inbounds ({ [8 x ptr] }, ptr @_ZTV2D1, i32 0, i32 0, i32 2)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTch0_h4_N2D12m1Ev, i32 0, i64 15165, ptr getelementptr inbounds ({ [8 x ptr] }, ptr @_ZTV2D1, i32 0, i32 0, i32 3)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2B02m2Ev, i32 0, i64 43073, ptr getelementptr inbounds ({ [8 x ptr] }, ptr @_ZTV2D1, i32 0, i32 0, i32 4)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2D1D1Ev, i32 0, i64 25525, ptr getelementptr inbounds ({ [8 x ptr] }, ptr @_ZTV2D1, i32 0, i32 0, i32 5)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2D1D0Ev, i32 0, i64 21295, ptr getelementptr inbounds ({ [8 x ptr] }, ptr @_ZTV2D1, i32 0, i32 0, i32 6)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2D12m1Ev, i32 0, i64 52864, ptr getelementptr inbounds ({ [8 x ptr] }, ptr @_ZTV2D1, i32 0, i32 0, i32 7))] }, align 8 + +// CHECK: @_ZTV2D2 = unnamed_addr constant { [9 x ptr], [8 x ptr] } { [9 x ptr] [ptr null, ptr @_ZTI2D2, +// CHECK-SAME: ptr ptrauth (ptr @_ZN2D22m0Ev, i32 0, i64 53119, ptr getelementptr inbounds ({ [9 x ptr], [8 x ptr] }, ptr @_ZTV2D2, i32 0, i32 0, i32 2)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTch0_h4_N2D22m1Ev, i32 0, i64 15165, ptr getelementptr inbounds ({ [9 x ptr], [8 x ptr] }, ptr @_ZTV2D2, i32 0, i32 0, i32 3)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2B02m2Ev, i32 0, i64 43073, ptr getelementptr inbounds ({ [9 x ptr], [8 x ptr] }, ptr @_ZTV2D2, i32 0, i32 0, i32 4)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2D2D1Ev, i32 0, i64 25525, ptr getelementptr inbounds ({ [9 x ptr], [8 x ptr] }, ptr @_ZTV2D2, i32 0, i32 0, i32 5)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2D2D0Ev, i32 0, i64 21295, ptr getelementptr inbounds ({ [9 x ptr], [8 x ptr] }, ptr @_ZTV2D2, i32 0, i32 0, i32 6)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2D22m1Ev, i32 0, i64 35045, ptr getelementptr inbounds ({ [9 x ptr], [8 x ptr] }, ptr @_ZTV2D2, i32 0, i32 0, i32 7)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2D22m3Ev, i32 0, i64 10565, ptr getelementptr inbounds ({ [9 x ptr], [8 x ptr] }, ptr @_ZTV2D2, i32 0, i32 0, i32 8))], +// CHECK-SAME: [8 x ptr] [ptr inttoptr (i64 -16 to ptr), ptr @_ZTI2D2, +// CHECK-SAME: ptr ptrauth (ptr @_ZThn16_N2D22m0Ev, i32 0, i64 53119, ptr getelementptr inbounds ({ [9 x ptr], [8 x ptr] }, ptr @_ZTV2D2, i32 0, i32 1, i32 2)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTchn16_h4_N2D22m1Ev, i32 0, i64 15165, ptr getelementptr inbounds ({ [9 x ptr], [8 x ptr] }, ptr @_ZTV2D2, i32 0, i32 1, i32 3)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2B02m2Ev, i32 0, i64 43073, ptr getelementptr inbounds ({ [9 x ptr], [8 x ptr] }, ptr @_ZTV2D2, i32 0, i32 1, i32 4)), +// CHECK-SAME: ptr ptrauth (ptr @_ZThn16_N2D2D1Ev, i32 0, i64 25525, ptr getelementptr inbounds ({ [9 x ptr], [8 x ptr] }, ptr @_ZTV2D2, i32 0, i32 1, i32 5)), +// CHECK-SAME: ptr ptrauth (ptr @_ZThn16_N2D2D0Ev, i32 0, i64 21295, ptr getelementptr inbounds ({ [9 x ptr], [8 x ptr] }, ptr @_ZTV2D2, i32 0, i32 1, i32 6)), +// CHECK-SAME: ptr ptrauth (ptr @_ZThn16_N2D22m1Ev, i32 0, i64 52864, ptr getelementptr inbounds ({ [9 x ptr], [8 x ptr] }, ptr @_ZTV2D2, i32 0, i32 1, i32 7))] }, align 8 + +// CHECK: @_ZTV2D3 = unnamed_addr constant { [7 x ptr], [7 x ptr], [11 x ptr] } { [7 x ptr] [ptr inttoptr (i64 32 to ptr), ptr null, ptr @_ZTI2D3, +// CHECK-SAME: ptr ptrauth (ptr @_ZN2D32m0Ev, i32 0, i64 44578, ptr getelementptr inbounds ({ [7 x ptr], [7 x ptr], [11 x ptr] }, ptr @_ZTV2D3, i32 0, i32 0, i32 3)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2D32m1Ev, i32 0, i64 30766, ptr getelementptr inbounds ({ [7 x ptr], [7 x ptr], [11 x ptr] }, ptr @_ZTV2D3, i32 0, i32 0, i32 4)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2D3D1Ev, i32 0, i64 57279, ptr getelementptr inbounds ({ [7 x ptr], [7 x ptr], [11 x ptr] }, ptr @_ZTV2D3, i32 0, i32 0, i32 5)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2D3D0Ev, i32 0, i64 62452, ptr getelementptr inbounds ({ [7 x ptr], [7 x ptr], [11 x ptr] }, ptr @_ZTV2D3, i32 0, i32 0, i32 6))], +// CHECK-SAME: [7 x ptr] [ptr inttoptr (i64 16 to ptr), ptr inttoptr (i64 -16 to ptr), ptr @_ZTI2D3, +// CHECK-SAME: ptr ptrauth (ptr @_ZThn16_N2D32m0Ev, i32 0, i64 49430, ptr getelementptr inbounds ({ [7 x ptr], [7 x ptr], [11 x ptr] }, ptr @_ZTV2D3, i32 0, i32 1, i32 3)), +// CHECK-SAME: ptr ptrauth (ptr @_ZThn16_N2D32m1Ev, i32 0, i64 57119, ptr getelementptr inbounds ({ [7 x ptr], [7 x ptr], [11 x ptr] }, ptr @_ZTV2D3, i32 0, i32 1, i32 4)), +// CHECK-SAME: ptr ptrauth (ptr @_ZThn16_N2D3D1Ev, i32 0, i64 60799, ptr getelementptr inbounds ({ [7 x ptr], [7 x ptr], [11 x ptr] }, ptr @_ZTV2D3, i32 0, i32 1, i32 5)), +// CHECK-SAME: ptr ptrauth (ptr @_ZThn16_N2D3D0Ev, i32 0, i64 52565, ptr getelementptr inbounds ({ [7 x ptr], [7 x ptr], [11 x ptr] }, ptr @_ZTV2D3, i32 0, i32 1, i32 6))], +// CHECK-SAME: [11 x ptr] [ptr inttoptr (i64 -32 to ptr), ptr null, ptr inttoptr (i64 -32 to ptr), ptr inttoptr (i64 -32 to ptr), ptr inttoptr (i64 -32 to ptr), ptr @_ZTI2D3, +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n24_N2D32m0Ev, i32 0, i64 53119, ptr getelementptr inbounds ({ [7 x ptr], [7 x ptr], [11 x ptr] }, ptr @_ZTV2D3, i32 0, i32 2, i32 6)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTcv0_n32_h4_N2D32m1Ev, i32 0, i64 15165, ptr getelementptr inbounds ({ [7 x ptr], [7 x ptr], [11 x ptr] }, ptr @_ZTV2D3, i32 0, i32 2, i32 7)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2B02m2Ev, i32 0, i64 43073, ptr getelementptr inbounds ({ [7 x ptr], [7 x ptr], [11 x ptr] }, ptr @_ZTV2D3, i32 0, i32 2, i32 8)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N2D3D1Ev, i32 0, i64 25525, ptr getelementptr inbounds ({ [7 x ptr], [7 x ptr], [11 x ptr] }, ptr @_ZTV2D3, i32 0, i32 2, i32 9)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N2D3D0Ev, i32 0, i64 21295, ptr getelementptr inbounds ({ [7 x ptr], [7 x ptr], [11 x ptr] }, ptr @_ZTV2D3, i32 0, i32 2, i32 10))] }, align 8 + +// CHECK: @_ZTC2D30_2V0 = unnamed_addr constant { [7 x ptr], [11 x ptr] } { [7 x ptr] [ptr inttoptr (i64 32 to ptr), ptr null, ptr @_ZTI2V0, +// CHECK-SAME: ptr ptrauth (ptr @_ZN2V02m0Ev, i32 0, i64 44578, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC2D30_2V0, i32 0, i32 0, i32 3)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2V02m1Ev, i32 0, i64 30766, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC2D30_2V0, i32 0, i32 0, i32 4)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2V0D1Ev, i32 0, i64 57279, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC2D30_2V0, i32 0, i32 0, i32 5)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2V0D0Ev, i32 0, i64 62452, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC2D30_2V0, i32 0, i32 0, i32 6))], +// CHECK-SAME: [11 x ptr] [ptr inttoptr (i64 -32 to ptr), ptr null, ptr inttoptr (i64 -32 to ptr), ptr inttoptr (i64 -32 to ptr), ptr inttoptr (i64 -32 to ptr), ptr @_ZTI2V0, +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n24_N2V02m0Ev, i32 0, i64 53119, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC2D30_2V0, i32 0, i32 1, i32 6)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTcv0_n32_h4_N2V02m1Ev, i32 0, i64 15165, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC2D30_2V0, i32 0, i32 1, i32 7)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2B02m2Ev, i32 0, i64 43073, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC2D30_2V0, i32 0, i32 1, i32 8)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N2V0D1Ev, i32 0, i64 25525, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC2D30_2V0, i32 0, i32 1, i32 9)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N2V0D0Ev, i32 0, i64 21295, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC2D30_2V0, i32 0, i32 1, i32 10))] }, align 8 + +// CHECK: @_ZTC2D316_2V1 = unnamed_addr constant { [7 x ptr], [11 x ptr] } { [7 x ptr] [ptr inttoptr (i64 16 to ptr), ptr null, ptr @_ZTI2V1, +// CHECK-SAME: ptr ptrauth (ptr @_ZN2V12m0Ev, i32 0, i64 49430, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC2D316_2V1, i32 0, i32 0, i32 3)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2V12m1Ev, i32 0, i64 57119, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC2D316_2V1, i32 0, i32 0, i32 4)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2V1D1Ev, i32 0, i64 60799, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC2D316_2V1, i32 0, i32 0, i32 5)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2V1D0Ev, i32 0, i64 52565, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC2D316_2V1, i32 0, i32 0, i32 6))], +// CHECK-SAME: [11 x ptr] [ptr inttoptr (i64 -16 to ptr), ptr null, ptr inttoptr (i64 -16 to ptr), ptr inttoptr (i64 -16 to ptr), ptr inttoptr (i64 -16 to ptr), ptr @_ZTI2V1, +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n24_N2V12m0Ev, i32 0, i64 53119, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC2D316_2V1, i32 0, i32 1, i32 6)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTcv0_n32_h4_N2V12m1Ev, i32 0, i64 15165, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC2D316_2V1, i32 0, i32 1, i32 7)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN2B02m2Ev, i32 0, i64 43073, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC2D316_2V1, i32 0, i32 1, i32 8)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N2V1D1Ev, i32 0, i64 25525, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC2D316_2V1, i32 0, i32 1, i32 9)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N2V1D0Ev, i32 0, i64 21295, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC2D316_2V1, i32 0, i32 1, i32 10))] }, align 8 + + +struct S0 { + int f; +}; + +struct S1 { + int f; +}; + +struct S2 : S0, S1 { + int f; +}; + +class B0 { +public: + virtual void m0(); + virtual S1 *m1(); + virtual void m2(); + virtual ~B0(); + int f; +}; + +class B1 { +public: + virtual void m0(); +}; + +class D0 : public B0 { +public: + void m0() override; + S2 *m1() override; + virtual void m3(); + int f; +}; + +class D1 : public B0 { +public: + void m0() override; + S2 *m1() override; + int f; +}; + +class D2 : public D0, public D1 { +public: + void m0() override; + S2 *m1() override; + void m3() override; + int f; +}; + +class V0 : public virtual B0 { +public: + void m0() override; + S2 *m1() override; + int f; +}; + +class V1 : public virtual B0 { +public: + void m0() override; + S2 *m1() override; + ~V1(); + int f; +}; + +class D3 : public V0, public V1 { +public: + void m0() override; + S2 *m1() override; + int f; +}; + +B1 g_B1; + +void B0::m0() {} + +void B1::m0() {} + +void D0::m0() {} + +void D1::m0() {} + +void D2::m0() {} + +void D3::m0() {} + +V1::~V1() { + m1(); +} + +// Check sign/authentication of vtable pointers and authentication of virtual +// functions. + +// CHECK-LABEL: define noundef ptr @_ZN2V1D2Ev( +// CHECK: %[[THIS1:.*]] = load ptr, ptr %{{.*}} +// CHECK: %[[T0:[0-9]+]] = load ptr, ptr %{{.*}} +// CHECK: %[[T1:[0-9]+]] = ptrtoint ptr %[[T0]] to i64 +// CHECK: %[[T2:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T1]], i32 2, i64 0) +// CHECK: %[[T3:[0-9]+]] = inttoptr i64 %[[T2]] to ptr +// CHECK: %[[T6:[0-9]+]] = ptrtoint ptr %[[T3]] to i64 +// CHECK: %[[T7:[0-9]+]] = call i64 @llvm.ptrauth.sign(i64 %[[T6]], i32 2, i64 0) +// CHECK: %[[SIGNED_VTADDR:[0-9]+]] = inttoptr i64 %[[T7]] to ptr +// CHECK: store ptr %[[SIGNED_VTADDR]], ptr %[[THIS1]] + +// CHECK-LABEL: define void @_Z8testB0m0P2B0( +// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}} +// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64 +// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0) +// CHECK: %[[T4:[0-9]+]] = inttoptr i64 %[[T3]] to ptr +// CHECK: %[[VFN:[a-z]+]] = getelementptr inbounds ptr, ptr %[[T4]], i64 0 +// CHECK: %[[T5:[0-9]+]] = load ptr, ptr %[[VFN]] +// CHECK: %[[T6:[0-9]+]] = ptrtoint ptr %[[VFN]] to i64 +// CHECK: %[[T7:[0-9]+]] = call i64 @llvm.ptrauth.blend(i64 %[[T6]], i64 53119) +// CHECK: call void %[[T5]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(12) %{{.*}}) [ "ptrauth"(i32 0, i64 %[[T7]]) ] + +void testB0m0(B0 *a) { + a->m0(); +} + +// CHECK-LABEL: define void @_Z8testB0m1P2B0( +// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}} +// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64 +// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0) +// CHECK: %[[T4:[0-9]+]] = inttoptr i64 %[[T3]] to ptr +// CHECK: %[[VFN:[a-z]+]] = getelementptr inbounds ptr, ptr %[[T4]], i64 1 +// CHECK: %[[T5:[0-9]+]] = load ptr, ptr %[[VFN]] +// CHECK: %[[T6:[0-9]+]] = ptrtoint ptr %[[VFN]] to i64 +// CHECK: %[[T7:[0-9]+]] = call i64 @llvm.ptrauth.blend(i64 %[[T6]], i64 15165) +// CHECK: call noundef ptr %[[T5]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(12) %{{.*}}) [ "ptrauth"(i32 0, i64 %[[T7]]) ] + +void testB0m1(B0 *a) { + a->m1(); +} + +// CHECK-LABEL: define void @_Z8testB0m2P2B0( +// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}} +// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64 +// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0) +// CHECK: %[[T4:[0-9]+]] = inttoptr i64 %[[T3]] to ptr +// CHECK: %[[VFN:[a-z]+]] = getelementptr inbounds ptr, ptr %[[T4]], i64 2 +// CHECK: %[[T5:[0-9]+]] = load ptr, ptr %[[VFN]] +// CHECK: %[[T6:[0-9]+]] = ptrtoint ptr %[[VFN]] to i64 +// CHECK: %[[T7:[0-9]+]] = call i64 @llvm.ptrauth.blend(i64 %[[T6]], i64 43073) +// CHECK: call void %[[T5]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(12) %{{.*}}) [ "ptrauth"(i32 0, i64 %[[T7]]) ] + +void testB0m2(B0 *a) { + a->m2(); +} + +// CHECK-LABEL: define void @_Z8testD0m0P2D0( +// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}} +// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64 +// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0) +// CHECK: %[[T4:[0-9]+]] = inttoptr i64 %[[T3]] to ptr +// CHECK: %[[VFN:[a-z]+]] = getelementptr inbounds ptr, ptr %[[T4]], i64 0 +// CHECK: %[[T5:[0-9]+]] = load ptr, ptr %[[VFN]] +// CHECK: %[[T6:[0-9]+]] = ptrtoint ptr %[[VFN]] to i64 +// CHECK: %[[T7:[0-9]+]] = call i64 @llvm.ptrauth.blend(i64 %[[T6]], i64 53119) +// CHECK: call void %[[T5]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(16) %{{.*}}) [ "ptrauth"(i32 0, i64 %[[T7]]) ] + +void testD0m0(D0 *a) { + a->m0(); +} + +// CHECK-LABEL: define void @_Z8testD0m1P2D0( +// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}} +// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64 +// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0) +// CHECK: %[[T4:[0-9]+]] = inttoptr i64 %[[T3]] to ptr +// CHECK: %[[VFN:[a-z]+]] = getelementptr inbounds ptr, ptr %[[T4]], i64 5 +// CHECK: %[[T5:[0-9]+]] = load ptr, ptr %[[VFN]] +// CHECK: %[[T6:[0-9]+]] = ptrtoint ptr %[[VFN]] to i64 +// CHECK: %[[T7:[0-9]+]] = call i64 @llvm.ptrauth.blend(i64 %[[T6]], i64 35045) +// CHECK: call noundef ptr %[[T5]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(16) %{{.*}}) [ "ptrauth"(i32 0, i64 %[[T7]]) ] + +void testD0m1(D0 *a) { + a->m1(); +} + +// CHECK-LABEL: define void @_Z8testD0m2P2D0( +// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}} +// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64 +// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0) +// CHECK: %[[T4:[0-9]+]] = inttoptr i64 %[[T3]] to ptr +// CHECK: %[[VFN:[a-z]+]] = getelementptr inbounds ptr, ptr %[[T4]], i64 2 +// CHECK: %[[T5:[0-9]+]] = load ptr, ptr %[[VFN]] +// CHECK: %[[T6:[0-9]+]] = ptrtoint ptr %[[VFN]] to i64 +// CHECK: %[[T7:[0-9]+]] = call i64 @llvm.ptrauth.blend(i64 %[[T6]], i64 43073) +// CHECK: call void %[[T5]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(12) %{{.*}}) [ "ptrauth"(i32 0, i64 %[[T7]]) ] + +void testD0m2(D0 *a) { + a->m2(); +} + +// CHECK-LABEL: define void @_Z8testD0m3P2D0( +// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}} +// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64 +// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0) +// CHECK: %[[T4:[0-9]+]] = inttoptr i64 %[[T3]] to ptr +// CHECK: %[[VFN:[a-z]+]] = getelementptr inbounds ptr, ptr %[[T4]], i64 6 +// CHECK: %[[T5:[0-9]+]] = load ptr, ptr %[[VFN]] +// CHECK: %[[T6:[0-9]+]] = ptrtoint ptr %[[VFN]] to i64 +// CHECK: %[[T7:[0-9]+]] = call i64 @llvm.ptrauth.blend(i64 %[[T6]], i64 10565) +// CHECK: call void %[[T5]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(16) %{{.*}}) [ "ptrauth"(i32 0, i64 %[[T7]]) ] + +void testD0m3(D0 *a) { + a->m3(); +} + + +// CHECK-LABEL: define void @_Z8testD1m0P2D1( +// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}} +// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64 +// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0) +// CHECK: %[[T4:[0-9]+]] = inttoptr i64 %[[T3]] to ptr +// CHECK: %[[VFN:[a-z]+]] = getelementptr inbounds ptr, ptr %[[T4]], i64 0 +// CHECK: %[[T5:[0-9]+]] = load ptr, ptr %[[VFN]] +// CHECK: %[[T6:[0-9]+]] = ptrtoint ptr %[[VFN]] to i64 +// CHECK: %[[T7:[0-9]+]] = call i64 @llvm.ptrauth.blend(i64 %[[T6]], i64 53119) +// CHECK: call void %[[T5]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(16) %{{.*}}) [ "ptrauth"(i32 0, i64 %[[T7]]) ] + +void testD1m0(D1 *a) { + a->m0(); +} + +// CHECK-LABEL: define void @_Z8testD1m1P2D1( +// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}} +// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64 +// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0) +// CHECK: %[[T4:[0-9]+]] = inttoptr i64 %[[T3]] to ptr +// CHECK: %[[VFN:[a-z]+]] = getelementptr inbounds ptr, ptr %[[T4]], i64 5 +// CHECK: %[[T5:[0-9]+]] = load ptr, ptr %[[VFN]] +// CHECK: %[[T6:[0-9]+]] = ptrtoint ptr %[[VFN]] to i64 +// CHECK: %[[T7:[0-9]+]] = call i64 @llvm.ptrauth.blend(i64 %[[T6]], i64 52864) +// CHECK: call noundef ptr %[[T5]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(16) %{{.*}}) [ "ptrauth"(i32 0, i64 %[[T7]]) ] + +void testD1m1(D1 *a) { + a->m1(); +} + +// CHECK-LABEL: define void @_Z8testD1m2P2D1( +// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}} +// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64 +// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0) +// CHECK: %[[T4:[0-9]+]] = inttoptr i64 %[[T3]] to ptr +// CHECK: %[[VFN:[a-z]+]] = getelementptr inbounds ptr, ptr %[[T4]], i64 2 +// CHECK: %[[T5:[0-9]+]] = load ptr, ptr %[[VFN]] +// CHECK: %[[T6:[0-9]+]] = ptrtoint ptr %[[VFN]] to i64 +// CHECK: %[[T7:[0-9]+]] = call i64 @llvm.ptrauth.blend(i64 %[[T6]], i64 43073) +// CHECK: call void %[[T5]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(12) %{{.*}}) [ "ptrauth"(i32 0, i64 %[[T7]]) ] + +void testD1m2(D1 *a) { + a->m2(); +} + + +// CHECK-LABEL: define void @_Z8testD2m0P2D2( +// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}} +// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64 +// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0) +// CHECK: %[[T4:[0-9]+]] = inttoptr i64 %[[T3]] to ptr +// CHECK: %[[VFN:[a-z]+]] = getelementptr inbounds ptr, ptr %[[T4]], i64 0 +// CHECK: %[[T5:[0-9]+]] = load ptr, ptr %[[VFN]] +// CHECK: %[[T6:[0-9]+]] = ptrtoint ptr %[[VFN]] to i64 +// CHECK: %[[T7:[0-9]+]] = call i64 @llvm.ptrauth.blend(i64 %[[T6]], i64 53119) +// CHECK: call void %[[T5]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(36) %{{.*}}) [ "ptrauth"(i32 0, i64 %[[T7]]) ] + +void testD2m0(D2 *a) { + a->m0(); +} + +// CHECK-LABEL: define void @_Z8testD2m1P2D2( +// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}} +// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64 +// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0) +// CHECK: %[[T4:[0-9]+]] = inttoptr i64 %[[T3]] to ptr +// CHECK: %[[VFN:[a-z]+]] = getelementptr inbounds ptr, ptr %[[T4]], i64 5 +// CHECK: %[[T5:[0-9]+]] = load ptr, ptr %[[VFN]] +// CHECK: %[[T6:[0-9]+]] = ptrtoint ptr %[[VFN]] to i64 +// CHECK: %[[T7:[0-9]+]] = call i64 @llvm.ptrauth.blend(i64 %[[T6]], i64 35045) +// CHECK: call noundef ptr %[[T5]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(36) %{{.*}}) [ "ptrauth"(i32 0, i64 %[[T7]]) ] + +void testD2m1(D2 *a) { + a->m1(); +} + +// CHECK-LABEL: define void @_Z10testD2m2D0P2D2( +// CHECK: call void @_ZN2B02m2Ev(ptr noundef nonnull align {{[0-9]+}} dereferenceable(12) %{{.*}}){{$}} + +void testD2m2D0(D2 *a) { + a->D0::m2(); +} + +// CHECK-LABEL: define void @_Z10testD2m2D1P2D2( +// CHECK: call void @_ZN2B02m2Ev(ptr noundef nonnull align {{[0-9]+}} dereferenceable(12) %{{.*}}){{$}} + +void testD2m2D1(D2 *a) { + a->D1::m2(); +} + +// CHECK-LABEL: define void @_Z8testD2m3P2D2( +// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}} +// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64 +// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0) +// CHECK: %[[T4:[0-9]+]] = inttoptr i64 %[[T3]] to ptr +// CHECK: %[[VFN:[a-z]+]] = getelementptr inbounds ptr, ptr %[[T4]], i64 6 +// CHECK: %[[T5:[0-9]+]] = load ptr, ptr %[[VFN]] +// CHECK: %[[T6:[0-9]+]] = ptrtoint ptr %[[VFN]] to i64 +// CHECK: %[[T7:[0-9]+]] = call i64 @llvm.ptrauth.blend(i64 %[[T6]], i64 10565) +// CHECK: call void %[[T5]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(36) %{{.*}}) [ "ptrauth"(i32 0, i64 %[[T7]]) ] + +void testD2m3(D2 *a) { + a->m3(); +} + +// CHECK-LABEL: define void @_Z8testD3m0P2D3( +// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}} +// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64 +// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0) +// CHECK: %[[T4:[0-9]+]] = inttoptr i64 %[[T3]] to ptr +// CHECK: %[[VFN:[a-z]+]] = getelementptr inbounds ptr, ptr %[[T4]], i64 0 +// CHECK: %[[T5:[0-9]+]] = load ptr, ptr %[[VFN]] +// CHECK: %[[T6:[0-9]+]] = ptrtoint ptr %[[VFN]] to i64 +// CHECK: %[[T7:[0-9]+]] = call i64 @llvm.ptrauth.blend(i64 %[[T6]], i64 44578) +// CHECK: call void %[[T5]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(32) %{{.*}}) [ "ptrauth"(i32 0, i64 %[[T7]]) ] + +void testD3m0(D3 *a) { + a->m0(); +} + +// CHECK-LABEL: define void @_Z8testD3m1P2D3( +// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}} +// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64 +// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0) +// CHECK: %[[T4:[0-9]+]] = inttoptr i64 %[[T3]] to ptr +// CHECK: %[[VFN:[a-z]+]] = getelementptr inbounds ptr, ptr %[[T4]], i64 1 +// CHECK: %[[T5:[0-9]+]] = load ptr, ptr %[[VFN]] +// CHECK: %[[T6:[0-9]+]] = ptrtoint ptr %[[VFN]] to i64 +// CHECK: %[[T7:[0-9]+]] = call i64 @llvm.ptrauth.blend(i64 %[[T6]], i64 30766) +// CHECK: call noundef ptr %[[T5]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(32) %{{.*}}) [ "ptrauth"(i32 0, i64 %[[T7]]) ] + +void testD3m1(D3 *a) { + a->m1(); +} + +// CHECK: define void @_Z8testD3m2P2D3(ptr noundef %[[A:.*]]) +// CHECK: %[[A_ADDR:.*]] = alloca ptr, align 8 +// CHECK: store ptr %[[A]], ptr %[[A_ADDR]], align 8 +// CHECK: %[[V0:.*]] = load ptr, ptr %[[A_ADDR]], align 8 +// CHECK: %[[VTABLE:.*]] = load ptr, ptr %[[V0]], align 8 +// CHECK: %[[V1:.*]] = ptrtoint ptr %[[VTABLE]] to i64 +// CHECK: %[[V2:.*]] = call i64 @llvm.ptrauth.auth(i64 %[[V1]], i32 2, i64 0) +// CHECK: %[[V3:.*]] = inttoptr i64 %[[V2]] to ptr +// CHECK: %[[VBASE_OFFSET_PTR:.*]] = getelementptr i8, ptr %[[V3]], i64 -24 +// CHECK: %[[VBASE_OFFSET:.*]] = load i64, ptr %[[VBASE_OFFSET_PTR]], align 8 +// CHECK: %[[ADD_PTR:.*]] = getelementptr inbounds i8, ptr %[[V0]], i64 %[[VBASE_OFFSET]] +// CHECK: %[[VTABLE1:.*]] = load ptr, ptr %[[ADD_PTR]], align 8 +// CHECK: %[[V4:.*]] = ptrtoint ptr %[[VTABLE1]] to i64 +// CHECK: %[[V5:.*]] = call i64 @llvm.ptrauth.auth(i64 %[[V4]], i32 2, i64 0) +// CHECK: %[[V6:.*]] = inttoptr i64 %[[V5]] to ptr +// CHECK: %[[VFN:.*]] = getelementptr inbounds ptr, ptr %[[V6]], i64 2 +// CHECK: %[[V7:.*]] = load ptr, ptr %[[VFN]], align 8 +// CHECK: %[[V8:.*]] = ptrtoint ptr %[[VFN]] to i64 +// CHECK: %[[V9:.*]] = call i64 @llvm.ptrauth.blend(i64 %[[V8]], i64 43073) +// CHECK: call void %[[V7]](ptr noundef nonnull align 8 dereferenceable(12) %[[ADD_PTR]]) [ "ptrauth"(i32 0, i64 %[[V9]]) ] + +void testD3m2(D3 *a) { + a->m2(); +} + +// CHECK-LABEL: define void @_Z17testD3Destructor0P2D3( +// CHECK: load ptr, ptr +// CHECK: %[[VTABLE:.*]] = load ptr, ptr %{{.*}} +// CHECK: %[[T2:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64 +// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T2]], i32 2, i64 0) +// CHECK: %[[T4:[0-9]+]] = inttoptr i64 %[[T3]] to ptr +// CHECK: %[[VFN:[a-z]+]] = getelementptr inbounds ptr, ptr %[[T4]], i64 3 +// CHECK: %[[T5:[0-9]+]] = load ptr, ptr %[[VFN]] +// CHECK: %[[T6:[0-9]+]] = ptrtoint ptr %[[VFN]] to i64 +// CHECK: %[[T7:[0-9]+]] = call i64 @llvm.ptrauth.blend(i64 %[[T6]], i64 62452) +// CHECK: call void %[[T5]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(32) %{{.*}}) #{{.*}} [ "ptrauth"(i32 0, i64 %[[T7]]) ] + +void testD3Destructor0(D3 *a) { + delete a; +} + +// CHECK-LABEL: define void @_Z17testD3Destructor1P2D3( +// CHECK: %[[T6:.*]] = load ptr, ptr % +// CHECK: %[[VTABLE0:[a-z0-9]+]] = load ptr, ptr % +// CHECK: %[[T2:[0-9]+]] = ptrtoint ptr %[[VTABLE0]] to i64 +// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T2]], i32 2, i64 0) +// CHECK: %[[T4:[0-9]+]] = inttoptr i64 %[[T3]] to ptr +// CHECK: %[[COMPLETE_OFFSET_PTR:.*]] = getelementptr inbounds i64, ptr %[[T4]], i64 -2 +// CHECK: %[[T5:[0-9]+]] = load i64, ptr %[[COMPLETE_OFFSET_PTR]] +// CHECK: %[[T7:[0-9]+]] = getelementptr inbounds i8, ptr %[[T6]], i64 %[[T5]] +// CHECK: %[[VTABLE1:[a-z0-9]+]] = load ptr, ptr %[[T6]] +// CHECK: %[[T9:[0-9]+]] = ptrtoint ptr %[[VTABLE1]] to i64 +// CHECK: %[[T10:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T9]], i32 2, i64 0) +// CHECK: %[[T11:[0-9]+]] = inttoptr i64 %[[T10]] to ptr +// CHECK: %[[VFN:[a-z0-9]+]] = getelementptr inbounds ptr, ptr %[[T11]], i64 2 +// CHECK: %[[T12:[0-9]+]] = load ptr, ptr %[[VFN]] +// CHECK: %[[T13:[0-9]+]] = ptrtoint ptr %[[VFN]] to i64 +// CHECK: %[[T14:[0-9]+]] = call i64 @llvm.ptrauth.blend(i64 %[[T13]], i64 57279) +// CHECK: %call = call noundef ptr %[[T12]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(32) %{{.*}}) #{{.*}} [ "ptrauth"(i32 0, i64 %[[T14]]) ] +// CHECK: call void @_ZdlPv(ptr noundef %[[T7]]) + +void testD3Destructor1(D3 *a) { + ::delete a; +} + +// CHECK-LABEL: define void @_Z17testD3Destructor2P2D3( +// CHECK: load ptr, ptr +// CHECK: %[[VTABLE:.*]] = load ptr, ptr % +// CHECK: %[[T2:.*]] = ptrtoint ptr %[[VTABLE]] to i64 +// CHECK: %[[T3:.*]] = call i64 @llvm.ptrauth.auth(i64 %[[T2]], i32 2, i64 0) +// CHECK: %[[T4:.*]] = inttoptr i64 %[[T3]] to ptr +// CHECK: %[[VFN:.*]] = getelementptr inbounds ptr, ptr %[[T4]], i64 2 +// CHECK: %[[T5:.*]] = load ptr, ptr %[[VFN]] +// CHECK: %[[T6:.*]] = ptrtoint ptr %[[VFN]] to i64 +// CHECK: %[[T7:.*]] = call i64 @llvm.ptrauth.blend(i64 %[[T6]], i64 57279) +// CHECK: %call = call noundef ptr %[[T5]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(32) %{{.*}}) #{{.*}} [ "ptrauth"(i32 0, i64 %[[T7]]) ] + +void testD3Destructor2(D3 *a) { + a->~D3(); +} + +void materializeConstructors() { + B0 B0; + B1 B1; + D0 D0; + D1 D1; + D2 D2; + D3 D3; + V0 V0; + V1 V1; +} + +// CHECK-LABEL: define linkonce_odr noundef ptr @_ZN2B0C2Ev( +// CHECK: %[[THIS:.*]] = load ptr, ptr % +// CHECK: %[[T0:[0-9]+]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr inbounds inrange(-16, 40) ({ [7 x ptr] }, ptr @_ZTV2B0, i32 0, i32 0, i32 2) to i64), i32 2, i64 0) +// CHECK: %[[SIGNED_VTADDR:[0-9]+]] = inttoptr i64 %[[T0]] to ptr +// CHECK: store ptr %[[SIGNED_VTADDR]], ptr %[[THIS]] + +// CHECK-LABEL: define linkonce_odr noundef ptr @_ZN2D0C2Ev( +// CHECK: %[[T0:[0-9]+]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr inbounds inrange(-16, 56) ({ [9 x ptr] }, ptr @_ZTV2D0, i32 0, i32 0, i32 2) to i64), i32 2, i64 0) +// CHECK: %[[SIGNED_VTADDR:[0-9]+]] = inttoptr i64 %[[T0]] to ptr +// CHECK: store ptr %[[SIGNED_VTADDR]], ptr %[[THIS]] + +// CHECK-LABEL: define linkonce_odr noundef ptr @_ZN2D1C2Ev( +// CHECK: %[[T0:[0-9]+]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr inbounds inrange(-16, 48) ({ [8 x ptr] }, ptr @_ZTV2D1, i32 0, i32 0, i32 2) to i64), i32 2, i64 0) +// CHECK: %[[SIGNED_VTADDR:[0-9]+]] = inttoptr i64 %[[T0]] to ptr +// CHECK: store ptr %[[SIGNED_VTADDR]], ptr %[[THIS]] + +// CHECK-LABEL: define linkonce_odr noundef ptr @_ZN2D2C2Ev( +// CHECK: %[[SLOT0:.*]] = load ptr, ptr +// CHECK: %[[SIGN_VTADDR0:[0-9]+]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr inbounds inrange(-16, 56) ({ [9 x ptr], [8 x ptr] }, ptr @_ZTV2D2, i32 0, i32 0, i32 2) to i64), i32 2, i64 0) +// CHECK: %[[T1:[0-9]+]] = inttoptr i64 %[[SIGN_VTADDR0]] to ptr +// CHECK: store ptr %[[T1]], ptr %[[SLOT0]] +// CHECK: %[[T3:[a-z0-9.]+]] = getelementptr inbounds i8, ptr %[[SLOT0]], i64 16 +// CHECK: %[[SIGN_VTADDR1:[0-9]+]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr inbounds inrange(-16, 48) ({ [9 x ptr], [8 x ptr] }, ptr @_ZTV2D2, i32 0, i32 1, i32 2) to i64), i32 2, i64 0) +// CHECK: %[[T5:[0-9]+]] = inttoptr i64 %[[SIGN_VTADDR1]] to ptr +// CHECK: store ptr %[[T5]], ptr %[[T3]] + +// CHECK-LABEL: define linkonce_odr noundef ptr @_ZN2V0C2Ev( +// CHECK: %[[THIS1]] = load ptr, ptr % +// CHECK: %[[VTT:[a-z0-9]+]] = load ptr, ptr %{{.*}} +// CHECK: %[[T0:[0-9]+]] = load ptr, ptr %[[VTT]] +// CHECK: %[[T1:[0-9]+]] = ptrtoint ptr %[[T0]] to i64 +// CHECK: %[[T2:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T1]], i32 2, i64 0) +// CHECK: %[[T3:[0-9]+]] = inttoptr i64 %[[T2]] to ptr +// CHECK: %[[VTADDR0:[0-9]+]] = ptrtoint ptr %[[T3]] to i64 +// CHECK: %[[T7:[0-9]+]] = call i64 @llvm.ptrauth.sign(i64 %[[VTADDR0]], i32 2, i64 0) +// CHECK: %[[SIGN_VTADDR0:[0-9]+]] = inttoptr i64 %[[T7]] to ptr +// CHECK: store ptr %[[SIGN_VTADDR0]], ptr %[[SLOT0]] +// CHECK: %[[T9:[0-9]+]] = getelementptr inbounds ptr, ptr %[[VTT]], i64 1 +// CHECK: %[[T10:[0-9]+]] = load ptr, ptr %[[T9]] +// CHECK: %[[T11:[0-9]+]] = ptrtoint ptr %[[T10]] to i64 +// CHECK: %[[T12:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T11]], i32 2, i64 0) +// CHECK: %[[T13:[0-9]+]] = inttoptr i64 %[[T12]] to ptr +// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %[[THIS1]] +// CHECK: %[[T15:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64 +// CHECK: %[[T16:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T15]], i32 2, i64 0) +// CHECK: %[[T17:[0-9]+]] = inttoptr i64 %[[T16]] to ptr +// CHECK: %[[VBASE_OFFSET_PTR:[a-z.]+]] = getelementptr i8, ptr %[[T17]], i64 -24 +// CHECK: %[[VBASE_OFFSET:[a-z.]+]] = load i64, ptr %[[VBASE_OFFSET_PTR]] +// CHECK: %[[T20:[a-z.]+]] = getelementptr inbounds i8, ptr %[[THIS1]], i64 %[[VBASE_OFFSET]] +// CHECK: %[[VTADDR1:[0-9]+]] = ptrtoint ptr %[[T13]] to i64 +// CHECK: %[[T23:[0-9]+]] = call i64 @llvm.ptrauth.sign(i64 %[[VTADDR1]], i32 2, i64 0) +// CHECK: %[[SIGN_VTADDR1:[0-9]+]] = inttoptr i64 %[[T23]] to ptr +// CHECK: store ptr %[[SIGN_VTADDR1]], ptr %[[T20]] diff --git a/clang/test/CodeGenCXX/ptrauth-vtable-virtual-inheritance-thunk.cpp b/clang/test/CodeGenCXX/ptrauth-vtable-virtual-inheritance-thunk.cpp new file mode 100644 index 00000000000000..00b1cbd06e0f03 --- /dev/null +++ b/clang/test/CodeGenCXX/ptrauth-vtable-virtual-inheritance-thunk.cpp @@ -0,0 +1,309 @@ +// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple arm64-apple-ios -fptrauth-intrinsics -fptrauth-calls -fptrauth-vtable-pointer-type-discrimination -emit-llvm -O0 -disable-llvm-passes -o - | FileCheck --check-prefix=CHECK %s + +// The actual vtable construction + +// CHECK: @_ZTV1C = unnamed_addr constant { [5 x ptr], [11 x ptr] } { [5 x ptr] [ptr inttoptr (i64 8 to ptr), ptr null, ptr @_ZTI1C, +// CHECK-SAME: ptr ptrauth (ptr @_ZN1CD1Ev, i32 0, i64 31214, ptr getelementptr inbounds ({ [5 x ptr], [11 x ptr] }, ptr @_ZTV1C, i32 0, i32 0, i32 3)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1CD0Ev, i32 0, i64 8507, ptr getelementptr inbounds ({ [5 x ptr], [11 x ptr] }, ptr @_ZTV1C, i32 0, i32 0, i32 4))], +// CHECK-SAME: [11 x ptr] [ptr inttoptr (i64 -8 to ptr), ptr null, ptr null, ptr null, ptr inttoptr (i64 -8 to ptr), ptr @_ZTI1C, +// CHECK-SAME: ptr ptrauth (ptr @_ZN1A1fEv, i32 0, i64 55636, ptr getelementptr inbounds ({ [5 x ptr], [11 x ptr] }, ptr @_ZTV1C, i32 0, i32 1, i32 6)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1A1gEv, i32 0, i64 19402, ptr getelementptr inbounds ({ [5 x ptr], [11 x ptr] }, ptr @_ZTV1C, i32 0, i32 1, i32 7)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1A1hEz, i32 0, i64 31735, ptr getelementptr inbounds ({ [5 x ptr], [11 x ptr] }, ptr @_ZTV1C, i32 0, i32 1, i32 8)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N1CD1Ev, i32 0, i64 2043, ptr getelementptr inbounds ({ [5 x ptr], [11 x ptr] }, ptr @_ZTV1C, i32 0, i32 1, i32 9)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N1CD0Ev, i32 0, i64 63674, ptr getelementptr inbounds ({ [5 x ptr], [11 x ptr] }, ptr @_ZTV1C, i32 0, i32 1, i32 10))] }, align 8 + +// CHECK: @_ZTT1C = unnamed_addr constant [2 x ptr] [ptr ptrauth (ptr getelementptr inbounds inrange(-24, 16) ({ [5 x ptr], [11 x ptr] }, ptr @_ZTV1C, i32 0, i32 0, i32 3), i32 2), +// CHECK-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-48, 40) ({ [5 x ptr], [11 x ptr] }, ptr @_ZTV1C, i32 0, i32 1, i32 6), i32 2)], align 8 + +// CHECK: @_ZTV1D = unnamed_addr constant { [7 x ptr], [11 x ptr] } { [7 x ptr] [ptr inttoptr (i64 8 to ptr), ptr null, ptr @_ZTI1D, +// CHECK-SAME: ptr ptrauth (ptr @_ZN1DD1Ev, i32 0, i64 59423, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 3)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1DD0Ev, i32 0, i64 25900, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 4)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1D1gEv, i32 0, i64 59070, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 5)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1D1hEz, i32 0, i64 65100, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 6))], +// CHECK-SAME: [11 x ptr] [ptr inttoptr (i64 -8 to ptr), ptr inttoptr (i64 -8 to ptr), ptr inttoptr (i64 -8 to ptr), ptr null, ptr inttoptr (i64 -8 to ptr), ptr @_ZTI1D, +// CHECK-SAME: ptr ptrauth (ptr @_ZN1A1fEv, i32 0, i64 55636, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTV1D, i32 0, i32 1, i32 6)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n32_N1D1gEv, i32 0, i64 19402, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTV1D, i32 0, i32 1, i32 7)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n40_N1D1hEz, i32 0, i64 31735, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTV1D, i32 0, i32 1, i32 8)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N1DD1Ev, i32 0, i64 2043, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTV1D, i32 0, i32 1, i32 9)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N1DD0Ev, i32 0, i64 63674, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTV1D, i32 0, i32 1, i32 10))] }, align 8 + +// CHECK: @_ZTT1D = unnamed_addr constant [2 x ptr] [ptr ptrauth (ptr getelementptr inbounds inrange(-24, 32) ({ [7 x ptr], [11 x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 3), i32 2), +// CHECK-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-48, 40) ({ [7 x ptr], [11 x ptr] }, ptr @_ZTV1D, i32 0, i32 1, i32 6), i32 2)], align 8 + +// CHECK: @_ZTV1F = unnamed_addr constant { [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] } { [6 x ptr] [ptr inttoptr (i64 32 to ptr), ptr inttoptr (i64 16 to ptr), ptr null, ptr @_ZTI1F, +// CHECK-SAME: ptr ptrauth (ptr @_ZN1FD1Ev, i32 0, i64 31214, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1F, i32 0, i32 0, i32 4)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1FD0Ev, i32 0, i64 8507, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1F, i32 0, i32 0, i32 5))], [7 x ptr] [ptr inttoptr (i64 8 to ptr), ptr inttoptr (i64 -8 to ptr), ptr @_ZTI1F, +// CHECK-SAME: ptr ptrauth (ptr @_ZThn8_N1FD1Ev, i32 0, i64 59423, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1F, i32 0, i32 1, i32 3)), +// CHECK-SAME: ptr ptrauth (ptr @_ZThn8_N1FD0Ev, i32 0, i64 25900, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1F, i32 0, i32 1, i32 4)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1D1gEv, i32 0, i64 59070, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1F, i32 0, i32 1, i32 5)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1D1hEz, i32 0, i64 65100, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1F, i32 0, i32 1, i32 6))], [11 x ptr] [ptr inttoptr (i64 -16 to ptr), ptr inttoptr (i64 -8 to ptr), ptr inttoptr (i64 -8 to ptr), ptr null, ptr inttoptr (i64 -16 to ptr), ptr @_ZTI1F, +// CHECK-SAME: ptr ptrauth (ptr @_ZN1A1fEv, i32 0, i64 55636, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1F, i32 0, i32 2, i32 6)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n32_N1D1gEv, i32 0, i64 19402, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1F, i32 0, i32 2, i32 7)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n40_N1D1hEz, i32 0, i64 31735, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1F, i32 0, i32 2, i32 8)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N1FD1EvU11__vtptrauthILj0Lb0Lj62866E, i32 0, i64 2043, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1F, i32 0, i32 2, i32 9)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N1FD0EvU11__vtptrauthILj0Lb0Lj62866E, i32 0, i64 63674, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1F, i32 0, i32 2, i32 10))], [11 x ptr] [ptr inttoptr (i64 -32 to ptr), ptr null, ptr null, ptr null, ptr inttoptr (i64 -32 to ptr), ptr @_ZTI1F, +// CHECK-SAME: ptr ptrauth (ptr @_ZN1E1fEv, i32 0, i64 28408, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1F, i32 0, i32 3, i32 6)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1E1gEv, i32 0, i64 22926, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1F, i32 0, i32 3, i32 7)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1E1hEz, i32 0, i64 9832, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1F, i32 0, i32 3, i32 8)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N1FD1Ev, i32 0, i64 5817, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1F, i32 0, i32 3, i32 9)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N1FD0Ev, i32 0, i64 26464, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1F, i32 0, i32 3, i32 10))] }, align 8 + +// CHECK: @_ZTT1F = unnamed_addr constant [8 x ptr] [ptr ptrauth (ptr getelementptr inbounds inrange(-32, 16) ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1F, i32 0, i32 0, i32 4), i32 2), +// CHECK-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-24, 16) ({ [5 x ptr], [11 x ptr] }, ptr @_ZTC1F0_1C, i32 0, i32 0, i32 3), i32 2), +// CHECK-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-48, 40) ({ [5 x ptr], [11 x ptr] }, ptr @_ZTC1F0_1C, i32 0, i32 1, i32 6), i32 2), +// CHECK-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-24, 32) ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC1F8_1D, i32 0, i32 0, i32 3), i32 2), +// CHECK-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-48, 40) ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC1F8_1D, i32 0, i32 1, i32 6), i32 2), +// CHECK-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-48, 40) ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1F, i32 0, i32 2, i32 6), i32 2), +// CHECK-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-24, 32) ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1F, i32 0, i32 1, i32 3), i32 2), +// CHECK-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-48, 40) ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1F, i32 0, i32 3, i32 6), i32 2)], align 8 + +// CHECK: @_ZTV1G = unnamed_addr constant { [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] } { [6 x ptr] [ptr inttoptr (i64 16 to ptr), ptr inttoptr (i64 24 to ptr), ptr null, ptr @_ZTI1G, +// CHECK-SAME: ptr ptrauth (ptr @_ZN1GD1Ev, i32 0, i64 31214, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1G, i32 0, i32 0, i32 4)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1GD0Ev, i32 0, i64 8507, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1G, i32 0, i32 0, i32 5))], [7 x ptr] [ptr inttoptr (i64 16 to ptr), ptr inttoptr (i64 -8 to ptr), ptr @_ZTI1G, +// CHECK-SAME: ptr ptrauth (ptr @_ZThn8_N1GD1Ev, i32 0, i64 59423, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1G, i32 0, i32 1, i32 3)), +// CHECK-SAME: ptr ptrauth (ptr @_ZThn8_N1GD0Ev, i32 0, i64 25900, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1G, i32 0, i32 1, i32 4)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1D1gEv, i32 0, i64 59070, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1G, i32 0, i32 1, i32 5)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1D1hEz, i32 0, i64 65100, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1G, i32 0, i32 1, i32 6))], [11 x ptr] [ptr inttoptr (i64 -16 to ptr), ptr null, ptr null, ptr null, ptr inttoptr (i64 -16 to ptr), ptr @_ZTI1G, +// CHECK-SAME: ptr ptrauth (ptr @_ZN1E1fEv, i32 0, i64 28408, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1G, i32 0, i32 2, i32 6)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1E1gEv, i32 0, i64 22926, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1G, i32 0, i32 2, i32 7)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1E1hEz, i32 0, i64 9832, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1G, i32 0, i32 2, i32 8)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N1GD1Ev, i32 0, i64 5817, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1G, i32 0, i32 2, i32 9)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N1GD0Ev, i32 0, i64 26464, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1G, i32 0, i32 2, i32 10))], [11 x ptr] [ptr inttoptr (i64 -24 to ptr), ptr inttoptr (i64 -16 to ptr), ptr inttoptr (i64 -16 to ptr), ptr null, ptr inttoptr (i64 -24 to ptr), ptr @_ZTI1G, +// CHECK-SAME: ptr ptrauth (ptr @_ZN1A1fEv, i32 0, i64 55636, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1G, i32 0, i32 3, i32 6)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n32_N1D1gEv, i32 0, i64 19402, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1G, i32 0, i32 3, i32 7)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n40_N1D1hEz, i32 0, i64 31735, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1G, i32 0, i32 3, i32 8)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N1GD1EvU11__vtptrauthILj0Lb0Lj62866E, i32 0, i64 2043, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1G, i32 0, i32 3, i32 9)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N1GD0EvU11__vtptrauthILj0Lb0Lj62866E, i32 0, i64 63674, ptr getelementptr inbounds ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1G, i32 0, i32 3, i32 10))] }, align 8 + +// CHECK: @_ZTT1G = unnamed_addr constant [8 x ptr] [ptr ptrauth (ptr getelementptr inbounds inrange(-32, 16) ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1G, i32 0, i32 0, i32 4), i32 2), +// CHECK-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-24, 16) ({ [5 x ptr], [11 x ptr] }, ptr @_ZTC1G0_1C, i32 0, i32 0, i32 3), i32 2), +// CHECK-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-48, 40) ({ [5 x ptr], [11 x ptr] }, ptr @_ZTC1G0_1C, i32 0, i32 1, i32 6), i32 2), +// CHECK-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-24, 32) ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC1G8_1D, i32 0, i32 0, i32 3), i32 2), +// CHECK-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-48, 40) ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC1G8_1D, i32 0, i32 1, i32 6), i32 2), +// CHECK-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-48, 40) ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1G, i32 0, i32 2, i32 6), i32 2), +// CHECK-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-48, 40) ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1G, i32 0, i32 3, i32 6), i32 2), +// CHECK-SAME: ptr ptrauth (ptr getelementptr inbounds inrange(-24, 32) ({ [6 x ptr], [7 x ptr], [11 x ptr], [11 x ptr] }, ptr @_ZTV1G, i32 0, i32 1, i32 3), i32 2)], align 8 + +// CHECK: @_ZTV1A = unnamed_addr constant { [7 x ptr] } { [7 x ptr] [ptr null, ptr @_ZTI1A, +// CHECK-SAME: ptr ptrauth (ptr @_ZN1A1fEv, i32 0, i64 55636, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 2)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1A1gEv, i32 0, i64 19402, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 3)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1A1hEz, i32 0, i64 31735, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 4)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1AD1Ev, i32 0, i64 2043, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 5)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1AD0Ev, i32 0, i64 63674, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 6))] }, align 8 + +// CHECK: @_ZTVN10__cxxabiv117__class_type_infoE = external global [0 x ptr] + +// CHECK: @_ZTS1A = constant [3 x i8] c"1A\00", align 1 + +// CHECK: @_ZTI1A = constant { ptr, ptr } { ptr ptrauth (ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), i32 2), ptr @_ZTS1A }, align 8 + +// CHECK: @_ZTVN10__cxxabiv121__vmi_class_type_infoE = external global [0 x ptr] + +// CHECK: @_ZTS1C = constant [3 x i8] c"1C\00", align 1 + +// CHECK: @_ZTVN10__cxxabiv120__si_class_type_infoE = external global [0 x ptr] + +// CHECK: @_ZTS1B = linkonce_odr hidden constant [3 x i8] c"1B\00", align 1 + +// CHECK: @_ZTI1B = linkonce_odr hidden constant { ptr, ptr, ptr } { ptr ptrauth (ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2), i32 2), ptr inttoptr (i64 add (i64 ptrtoint (ptr @_ZTS1B to i64), i64 -9223372036854775808) to ptr), ptr @_ZTI1A }, align 8 + +// CHECK: @_ZTI1C = constant { ptr, ptr, i32, i32, ptr, i64 } { ptr ptrauth (ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2), i32 2), ptr @_ZTS1C, i32 0, i32 1, ptr @_ZTI1B, i64 -6141 }, align 8 + +// CHECK: @_ZTS1D = constant [3 x i8] c"1D\00", align 1 + +// CHECK: @_ZTI1D = constant { ptr, ptr, i32, i32, ptr, i64 } { ptr ptrauth (ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2), i32 2), ptr @_ZTS1D, i32 0, i32 1, ptr @_ZTI1B, i64 -6141 }, align 8 + +// CHECK: @_ZTV1E = unnamed_addr constant { [7 x ptr] } { [7 x ptr] [ptr null, ptr @_ZTI1E, +// CHECK-SAME: ptr ptrauth (ptr @_ZN1E1fEv, i32 0, i64 28408, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV1E, i32 0, i32 0, i32 2)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1E1gEv, i32 0, i64 22926, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV1E, i32 0, i32 0, i32 3)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1E1hEz, i32 0, i64 9832, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV1E, i32 0, i32 0, i32 4)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1ED1Ev, i32 0, i64 5817, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV1E, i32 0, i32 0, i32 5)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1ED0Ev, i32 0, i64 26464, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV1E, i32 0, i32 0, i32 6))] }, align 8 + +// CHECK: @_ZTS1E = constant [3 x i8] c"1E\00", align 1 + +// CHECK: @_ZTI1E = constant { ptr, ptr } { ptr ptrauth (ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), i32 2), ptr @_ZTS1E }, align 8 + +// CHECK: @_ZTC1F0_1C = unnamed_addr constant { [5 x ptr], [11 x ptr] } { [5 x ptr] [ptr inttoptr (i64 16 to ptr), ptr null, ptr @_ZTI1C, +// CHECK-SAME: ptr ptrauth (ptr @_ZN1CD1Ev, i32 0, i64 31214, ptr getelementptr inbounds ({ [5 x ptr], [11 x ptr] }, ptr @_ZTC1F0_1C, i32 0, i32 0, i32 3)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1CD0Ev, i32 0, i64 8507, ptr getelementptr inbounds ({ [5 x ptr], [11 x ptr] }, ptr @_ZTC1F0_1C, i32 0, i32 0, i32 4))], [11 x ptr] [ptr inttoptr (i64 -16 to ptr), ptr null, ptr null, ptr null, ptr inttoptr (i64 -16 to ptr), ptr @_ZTI1C, +// CHECK-SAME: ptr ptrauth (ptr @_ZN1A1fEv, i32 0, i64 55636, ptr getelementptr inbounds ({ [5 x ptr], [11 x ptr] }, ptr @_ZTC1F0_1C, i32 0, i32 1, i32 6)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1A1gEv, i32 0, i64 19402, ptr getelementptr inbounds ({ [5 x ptr], [11 x ptr] }, ptr @_ZTC1F0_1C, i32 0, i32 1, i32 7)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1A1hEz, i32 0, i64 31735, ptr getelementptr inbounds ({ [5 x ptr], [11 x ptr] }, ptr @_ZTC1F0_1C, i32 0, i32 1, i32 8)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N1CD1Ev, i32 0, i64 2043, ptr getelementptr inbounds ({ [5 x ptr], [11 x ptr] }, ptr @_ZTC1F0_1C, i32 0, i32 1, i32 9)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N1CD0Ev, i32 0, i64 63674, ptr getelementptr inbounds ({ [5 x ptr], [11 x ptr] }, ptr @_ZTC1F0_1C, i32 0, i32 1, i32 10))] }, align 8 + +// CHECK: @_ZTC1F8_1D = unnamed_addr constant { [7 x ptr], [11 x ptr] } { [7 x ptr] [ptr inttoptr (i64 8 to ptr), ptr null, ptr @_ZTI1D, +// CHECK-SAME: ptr ptrauth (ptr @_ZN1DD1Ev, i32 0, i64 59423, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC1F8_1D, i32 0, i32 0, i32 3)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1DD0Ev, i32 0, i64 25900, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC1F8_1D, i32 0, i32 0, i32 4)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1D1gEv, i32 0, i64 59070, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC1F8_1D, i32 0, i32 0, i32 5)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1D1hEz, i32 0, i64 65100, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC1F8_1D, i32 0, i32 0, i32 6))], [11 x ptr] [ptr inttoptr (i64 -8 to ptr), ptr inttoptr (i64 -8 to ptr), ptr inttoptr (i64 -8 to ptr), ptr null, ptr inttoptr (i64 -8 to ptr), ptr @_ZTI1D, +// CHECK-SAME: ptr ptrauth (ptr @_ZN1A1fEv, i32 0, i64 55636, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC1F8_1D, i32 0, i32 1, i32 6)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n32_N1D1gEv, i32 0, i64 19402, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC1F8_1D, i32 0, i32 1, i32 7)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n40_N1D1hEz, i32 0, i64 31735, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC1F8_1D, i32 0, i32 1, i32 8)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N1DD1Ev, i32 0, i64 2043, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC1F8_1D, i32 0, i32 1, i32 9)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N1DD0Ev, i32 0, i64 63674, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC1F8_1D, i32 0, i32 1, i32 10))] }, align 8 + +// CHECK: @_ZTS1F = constant [3 x i8] c"1F\00", align 1 + +// CHECK: @_ZTI1F = constant { ptr, ptr, i32, i32, ptr, i64, ptr, i64, ptr, i64 } { ptr ptrauth (ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2), i32 2), ptr @_ZTS1F, i32 3, i32 3, ptr @_ZTI1C, i64 2, ptr @_ZTI1D, i64 2050, ptr @_ZTI1E, i64 -8189 }, align 8 + +// CHECK: @_ZTC1G0_1C = unnamed_addr constant { [5 x ptr], [11 x ptr] } { [5 x ptr] [ptr inttoptr (i64 24 to ptr), ptr null, ptr @_ZTI1C, +// CHECK-SAME: ptr ptrauth (ptr @_ZN1CD1Ev, i32 0, i64 31214, ptr getelementptr inbounds ({ [5 x ptr], [11 x ptr] }, ptr @_ZTC1G0_1C, i32 0, i32 0, i32 3)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1CD0Ev, i32 0, i64 8507, ptr getelementptr inbounds ({ [5 x ptr], [11 x ptr] }, ptr @_ZTC1G0_1C, i32 0, i32 0, i32 4))], [11 x ptr] [ptr inttoptr (i64 -24 to ptr), ptr null, ptr null, ptr null, ptr inttoptr (i64 -24 to ptr), ptr @_ZTI1C, +// CHECK-SAME: ptr ptrauth (ptr @_ZN1A1fEv, i32 0, i64 55636, ptr getelementptr inbounds ({ [5 x ptr], [11 x ptr] }, ptr @_ZTC1G0_1C, i32 0, i32 1, i32 6)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1A1gEv, i32 0, i64 19402, ptr getelementptr inbounds ({ [5 x ptr], [11 x ptr] }, ptr @_ZTC1G0_1C, i32 0, i32 1, i32 7)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1A1hEz, i32 0, i64 31735, ptr getelementptr inbounds ({ [5 x ptr], [11 x ptr] }, ptr @_ZTC1G0_1C, i32 0, i32 1, i32 8)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N1CD1Ev, i32 0, i64 2043, ptr getelementptr inbounds ({ [5 x ptr], [11 x ptr] }, ptr @_ZTC1G0_1C, i32 0, i32 1, i32 9)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N1CD0Ev, i32 0, i64 63674, ptr getelementptr inbounds ({ [5 x ptr], [11 x ptr] }, ptr @_ZTC1G0_1C, i32 0, i32 1, i32 10))] }, align 8 + +// CHECK: @_ZTC1G8_1D = unnamed_addr constant { [7 x ptr], [11 x ptr] } { [7 x ptr] [ptr inttoptr (i64 16 to ptr), ptr null, ptr @_ZTI1D, +// CHECK-SAME: ptr ptrauth (ptr @_ZN1DD1Ev, i32 0, i64 59423, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC1G8_1D, i32 0, i32 0, i32 3)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1DD0Ev, i32 0, i64 25900, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC1G8_1D, i32 0, i32 0, i32 4)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1D1gEv, i32 0, i64 59070, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC1G8_1D, i32 0, i32 0, i32 5)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1D1hEz, i32 0, i64 65100, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC1G8_1D, i32 0, i32 0, i32 6))], [11 x ptr] [ptr inttoptr (i64 -16 to ptr), ptr inttoptr (i64 -16 to ptr), ptr inttoptr (i64 -16 to ptr), ptr null, ptr inttoptr (i64 -16 to ptr), ptr @_ZTI1D, +// CHECK-SAME: ptr ptrauth (ptr @_ZN1A1fEv, i32 0, i64 55636, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC1G8_1D, i32 0, i32 1, i32 6)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n32_N1D1gEv, i32 0, i64 19402, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC1G8_1D, i32 0, i32 1, i32 7)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n40_N1D1hEz, i32 0, i64 31735, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC1G8_1D, i32 0, i32 1, i32 8)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N1DD1Ev, i32 0, i64 2043, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC1G8_1D, i32 0, i32 1, i32 9)), +// CHECK-SAME: ptr ptrauth (ptr @_ZTv0_n48_N1DD0Ev, i32 0, i64 63674, ptr getelementptr inbounds ({ [7 x ptr], [11 x ptr] }, ptr @_ZTC1G8_1D, i32 0, i32 1, i32 10))] }, align 8 + +// CHECK: @_ZTS1G = constant [3 x i8] c"1G\00", align 1 + +// CHECK: @_ZTI1G = constant { ptr, ptr, i32, i32, ptr, i64, ptr, i64, ptr, i64 } { ptr ptrauth (ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2), i32 2), ptr @_ZTS1G, i32 3, i32 3, ptr @_ZTI1E, i64 -8189, ptr @_ZTI1C, i64 2, ptr @_ZTI1D, i64 2050 }, align 8 + +// CHECK: @_ZTV1B = linkonce_odr unnamed_addr constant { [7 x ptr] } { [7 x ptr] [ptr null, ptr @_ZTI1B, +// CHECK-SAME: ptr ptrauth (ptr @_ZN1A1fEv, i32 0, i64 55636, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV1B, i32 0, i32 0, i32 2)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1A1gEv, i32 0, i64 19402, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV1B, i32 0, i32 0, i32 3)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1A1hEz, i32 0, i64 31735, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV1B, i32 0, i32 0, i32 4)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1BD1Ev, i32 0, i64 2043, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV1B, i32 0, i32 0, i32 5)), +// CHECK-SAME: ptr ptrauth (ptr @_ZN1BD0Ev, i32 0, i64 63674, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV1B, i32 0, i32 0, i32 6))] }, align 8 + +extern "C" int printf(const char *format, ...); + +class A { +public: + A() {} + virtual int f(); + virtual int g(); + virtual int h(...); + virtual ~A() {} + +public: + bool necessary_field; +}; + +class B : public A { +public: + B() : A() {} + virtual ~B() {} +}; + +class C : public virtual B { +public: + C() : B() {} + ~C(); +}; + +class D : public virtual B { +public: + D() : B() {} + ~D(); + virtual int g(); + virtual int h(...); +}; + +class E { +public: + virtual int f(); + virtual int g(); + virtual int h(...); + virtual ~E(){}; +}; + +class F : public C, public D, public virtual E { + ~F(); +}; + +class G : public virtual E, public C, public D { + ~G(); +}; + +C::~C() {} +D::~D() {} +F::~F() {} +G::~G() {} +int E::f() { return 1; } +int A::f() { return 0; } +int E::g() { return 1; } +int A::g() { return 0; } +int D::g() { return 0; } + +int E::h(...) { return 1; } +int A::h(...) { return 0; } +int D::h(...) { return 0; } + +int main() { + A *ans = new C(); + delete ans; + + B *b = new D(); + b->f(); + b->g(); + b->h(1,2,3); + b = new C(); + b->f(); + b->h(1,2,3); + b = new C(); + b->f(); + b->h(1,2,3); + b = new F(); + b->f(); + b->g(); + b->h(1,2,3); + + ans = new B(); + delete ans; + + ans = new F(); + ans->f(); + ans->g(); + ans->h(1,2,3); + delete ans; + + E *e = new F(); + e->f(); + e->g(); + e->h(1,2,3); + delete e; + e = new G(); + e->f(); + e->g(); + e->h(1,2,3); + delete e; +} + +// And check the thunks +// CHECK: ptr @_ZTv0_n48_N1CD1Ev(ptr noundef %this) +// CHECK: [[TEMP:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[TEMP:%.*]], i32 2, i64 62866) + +// CHECK: void @_ZTv0_n48_N1CD0Ev(ptr noundef %this) +// CHECK: [[TEMP:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[TEMP:%.*]], i32 2, i64 62866) + +// CHECK: ptr @_ZTv0_n48_N1DD1Ev(ptr noundef %this) +// CHECK: [[TEMP:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[TEMP:%.*]], i32 2, i64 62866) + +// CHECK: void @_ZTv0_n48_N1DD0Ev(ptr noundef %this) +// CHECK: [[TEMP:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[TEMP:%.*]], i32 2, i64 62866) + +// CHECK: void @_ZTv0_n48_N1FD0EvU11__vtptrauthILj0Lb0Lj62866E(ptr noundef %this) +// CHECK: [[TEMP:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[TEMP:%.*]], i32 2, i64 62866) + +// CHECK: void @_ZTv0_n48_N1FD0Ev(ptr noundef %this) +// CHECK: [[TEMP:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[TEMP:%.*]], i32 2, i64 12810) + +// CHECK: void @_ZTv0_n48_N1GD0Ev(ptr noundef %this) +// CHECK: [[TEMP:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[TEMP:%.*]], i32 2, i64 12810) + +// CHECK: void @_ZTv0_n48_N1GD0EvU11__vtptrauthILj0Lb0Lj62866E(ptr noundef %this) +// CHECK: [[TEMP:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[TEMP:%.*]], i32 2, i64 62866) diff --git a/clang/test/CodeGenCXX/trivial-auto-var-init-skip-scalar-with-nonconst-init.cpp b/clang/test/CodeGenCXX/trivial-auto-var-init-skip-scalar-with-nonconst-init.cpp new file mode 100644 index 00000000000000..ba4df6ebe115fe --- /dev/null +++ b/clang/test/CodeGenCXX/trivial-auto-var-init-skip-scalar-with-nonconst-init.cpp @@ -0,0 +1,121 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -emit-llvm -o - | FileCheck %s -check-prefix=UNINIT +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ftrivial-auto-var-init=pattern %s -emit-llvm -o - | FileCheck %s -check-prefix=PATTERN +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ftrivial-auto-var-init=zero %s -emit-llvm -o - | FileCheck %s -check-prefix=ZERO + +template void used(T &) noexcept; + +extern "C" { + +extern int get_int(int) noexcept; +struct C { + int x; + int y; +}; +extern C make_c() noexcept; + +// Scalar with a self-reference: does need auto-init. +// UNINIT-LABEL: test_selfinit_call( +// ZERO-LABEL: test_selfinit_call( +// ZERO: store i32 0, ptr %self, align 4, !annotation [[AUTO_INIT:!.+]] +// PATTERN-LABEL: test_selfinit_call( +// PATTERN: store i32 -1431655766, ptr %self, align 4, !annotation [[AUTO_INIT:!.+]] +void test_selfinit_call() { + int self = get_int(self); + used(self); +} + +// Scalar without a self-reference: no auto-init needed. +// UNINIT-LABEL: test_nonself_call( +// ZERO-LABEL: test_nonself_call( +// ZERO-NOT: !annotation [[AUTO_INIT:!.+]] +// PATTERN-LABEL: test_nonself_call( +// PATTERN-NOT: !annotation [[AUTO_INIT:!.+]] +void test_nonself_call() { + int x = get_int(2); + used(x); +} + +// Scalar with a self-reference: does need auto-init. +// UNINIT-LABEL: test_selfinit_lambda_call( +// ZERO-LABEL: test_selfinit_lambda_call( +// ZERO: store i32 0, ptr %self, align 4, !annotation [[AUTO_INIT:!.+]] +// PATTERN-LABEL: test_selfinit_lambda_call( +// PATTERN: store i32 -1431655766, ptr %self, align 4, !annotation [[AUTO_INIT:!.+]] +void test_selfinit_lambda_call() { + int self = [&](){ return self; }(); + used(self); +} + +// Scalar with a self-reference: does need auto-init. +// UNINIT-LABEL: test_selfinit_gnu_stmt_expression( +// ZERO-LABEL: test_selfinit_gnu_stmt_expression( +// ZERO: store i32 0, ptr %self, align 4, !annotation [[AUTO_INIT:!.+]] +// PATTERN-LABEL: test_selfinit_gnu_stmt_expression( +// PATTERN: store i32 -1431655766, ptr %self, align 4, !annotation [[AUTO_INIT:!.+]] +void test_selfinit_gnu_stmt_expression() { + int self = ({int x = self; x + 1; }); + used(self); +} + +// Not a scalar: auto-init just in case +// UNINIT-LABEL: test_nonscalar_call( +// ZERO-LABEL: test_nonscalar_call( +// ZERO: call void @llvm.memset{{.*}}, i8 0, i64 8, {{.*}} !annotation [[AUTO_INIT:!.+]] +// PATTERN-LABEL: test_nonscalar_call( +// PATTERN: call void @llvm.memcpy{{.*}}, i64 8, {{.*}} !annotation [[AUTO_INIT:!.+]] +void test_nonscalar_call() { + C c = make_c(); + used(c); +} + +// Scalar with a self-reference: does need auto-init. +// UNINIT-LABEL: test_self_ptr( +// ZERO-LABEL: test_self_ptr( +// ZERO: store ptr null, ptr %self, align 8, !annotation [[AUTO_INIT:!.+]] +// PATTERN-LABEL: test_self_ptr( +// PATTERN: store ptr inttoptr (i64 -6148914691236517206 to ptr), ptr %self, align 8, !annotation [[AUTO_INIT:!.+]] +void test_self_ptr() { + void* self = self; + used(self); +} + +// Scalar without a self-reference: no auto-init needed. +// UNINIT-LABEL: test_nonself_ptr( +// ZERO-LABEL: test_nonself_ptr( +// ZERO-NOT: !annotation [[AUTO_INIT:!.+]] +// PATTERN-LABEL: test_nonself_ptr( +// PATTERN-NOT: !annotation [[AUTO_INIT:!.+]] +void test_nonself_ptr() { + int y = 0; + void* x = &y; + used(x); +} + +// Scalar with a self-reference: does need auto-init. +// UNINIT-LABEL: test_self_complex( +// ZERO-LABEL: test_self_complex( +// ZERO: call void @llvm.memset{{.*}} !annotation [[AUTO_INIT:!.+]] +// PATTERN-LABEL: test_self_complex( +// PATTERN: call void @llvm.memcpy{{.*}} !annotation [[AUTO_INIT:!.+]] +void test_self_complex() { + _Complex float self = 3.0 * 3.0 * self; + used(self); +} + +// Scalar without a self-reference: no auto-init needed. +// UNINIT-LABEL: test_nonself_complex( +// ZERO-LABEL: test_nonself_complex( +// ZERO-NOT: !annotation [[AUTO_INIT:!.+]] +// PATTERN-LABEL: test_nonself_complex( +// PATTERN-NOT: !annotation [[AUTO_INIT:!.+]] +void test_nonself_complex() { + _Complex float y = 0.0; + _Complex float x = 3.0 * 3.0 * y; + used(x); +} + +} // extern "C" + +// ZERO: [[AUTO_INIT]] = !{!"auto-init"} +// PATTERN: [[AUTO_INIT]] = !{!"auto-init"} + diff --git a/clang/test/CodeGenCXX/ubsan-vtable-checks.cpp b/clang/test/CodeGenCXX/ubsan-vtable-checks.cpp index c70316214cf665..72c59cb41c34b1 100644 --- a/clang/test/CodeGenCXX/ubsan-vtable-checks.cpp +++ b/clang/test/CodeGenCXX/ubsan-vtable-checks.cpp @@ -2,6 +2,7 @@ // RUN: %clang_cc1 -std=c++11 -triple x86_64-windows -emit-llvm -fsanitize=null %s -o - | FileCheck %s --check-prefix=CHECK-NULL --check-prefix=MSABI // RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux -emit-llvm -fsanitize=null,vptr %s -o - | FileCheck %s --check-prefix=CHECK-VPTR --check-prefix=ITANIUM // RUN: %clang_cc1 -std=c++11 -triple x86_64-windows -emit-llvm -fsanitize=null,vptr %s -o - | FileCheck %s --check-prefix=CHECK-VPTR --check-prefix=MSABI --check-prefix=CHECK-VPTR-MS +// RUN: %clang_cc1 -std=c++11 -triple arm64e-ios-13 -emit-llvm -fptrauth-intrinsics -fptrauth-calls -fptrauth-vtable-pointer-type-discrimination -fptrauth-vtable-pointer-address-discrimination -fsanitize=null,vptr %s -o - | FileCheck %s --check-prefix=CHECK-VPTR --check-prefix=ITANIUM --check-prefix=CHECK-PTRAUTH struct T { virtual ~T() {} virtual int v() { return 1; } @@ -26,18 +27,49 @@ int get_v(T* t) { // CHECK-NULL: call void @__ubsan_handle_type_mismatch_v1_abort // Second, we check that vtable is actually loaded once the type check is done. // CHECK-NULL: load ptr, ptr {{.*}} + + // CHECK-PTRAUTH: [[CAST_VTABLE:%.*]] = ptrtoint ptr %vtable to i64 + // CHECK-PTRAUTH: [[STRIPPED_VTABLE:%.*]] = call i64 @llvm.ptrauth.strip(i64 [[CAST_VTABLE]], i32 0), !nosanitize !2 + // CHECK-PTRAUTH: [[STRIPPED_PTR:%.*]] = inttoptr i64 [[STRIPPED_VTABLE]] to ptr + // CHECK-PTRAUTH: [[STRIPPED_INT:%.*]] = ptrtoint ptr [[STRIPPED_PTR]] to i64 + // Make sure authed vtable pointer feeds into hashing + // CHECK-PTRAUTH: {{%.*}} = mul i64 [[STRIPPED_INT]], {{.*}} + + // Verify that we authenticate for the actual vcall + // CHECK-PTRAUTH: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 {{%.*}}, i64 17113) + // CHECK-PTRAUTH: [[CAST_VTABLE:%.*]] = ptrtoint ptr %vtable2 to i64 + // CHECK-PTRAUTH: [[AUTHED_INT:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[CAST_VTABLE]], i32 2, i64 [[BLENDED]]) + // CHECK-PTRAUTH: [[AUTHED_PTR:%.*]] = inttoptr i64 [[AUTHED_INT]] to ptr + // CHECK-PTRAUTH: {{%.*}} = getelementptr inbounds ptr, ptr [[AUTHED_PTR]], i64 2 return t->v(); } // ITANIUM: define{{.*}} void @_Z9delete_itP1T // MSABI: define dso_local void @"?delete_it void delete_it(T *t) { - // First, we check that vtable is not loaded before a type check. // CHECK-VPTR-NOT: load {{.*}} (ptr{{.*}})**, {{.*}} (ptr{{.*}})*** // CHECK-VPTR: br i1 {{.*}} label %{{.*}} - // CHECK-VPTR: call void @__ubsan_handle_dynamic_type_cache_miss_abort + // CHECK-VPTR: call void @__ubsan_handle_type_mismatch_v1_abort // Second, we check that vtable is actually loaded once the type check is done. // CHECK-VPTR: load ptr, ptr {{.*}} + + // First, we check that vtable is not loaded before a type check. + // CHECK-PTRAUTH: ptrtoint ptr {{%.*}} to i64 + // CHECK-PTRAUTH: [[CAST_VTABLE:%.*]] = ptrtoint ptr [[VTABLE:%.*]] to i64 + // CHECK-PTRAUTH: [[STRIPPED_VTABLE:%.*]] = call i64 @llvm.ptrauth.strip(i64 [[CAST_VTABLE]], i32 0) + // CHECK-PTRAUTH: [[STRIPPED_PTR:%.*]] = inttoptr i64 [[STRIPPED_VTABLE]] to ptr + // CHECK-PTRAUTH: [[STRIPPED_INT:%.*]] = ptrtoint ptr [[STRIPPED_PTR]] to i64 + // CHECK-PTRAUTH: {{%.*}} = mul i64 [[STRIPPED_INT]], {{.*}} + // CHECK-PTRAUTH: call void @__ubsan_handle_dynamic_type_cache_miss_abort( + // Second, we check that vtable is actually loaded once the type check is done. + // ptrauth for the virtual function load + // CHECK-PTRAUTH: [[VTABLE2:%.*]] = load ptr, ptr {{.*}} + // CHECK-PTRAUTH: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 %{{.*}}, i64 17113) + // CHECK-PTRAUTH: [[CAST_VTABLE:%.*]] = ptrtoint ptr [[VTABLE2]] to i64 + // CHECK-PTRAUTH: [[AUTHED_INT:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[CAST_VTABLE]], i32 2, i64 [[BLENDED]]) + // CHECK-PTRAUTH: [[AUTHED_PTR:%.*]] = inttoptr i64 [[AUTHED_INT]] to ptr + // CHECK-PTRAUTH: getelementptr inbounds ptr, ptr + // CHECK-PTRAUTH {{%.*}} = getelementptr inbounds ptr, ptr [[AUTHED_PTR]], i64 1 delete t; } @@ -47,7 +79,19 @@ U* dyncast(T *t) { // First, we check that dynamic_cast is not called before a type check. // CHECK-VPTR-NOT: call ptr @__{{dynamic_cast|RTDynamicCast}} // CHECK-VPTR: br i1 {{.*}} label %{{.*}} + // CHECK-PTRAUTH: [[V0:%.*]] = ptrtoint ptr {{%.*}} to i64 + // CHECK-PTRAUTH: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[V0]], i64 17113) + // CHECK-PTRAUTH: [[CAST_VTABLE:%.*]] = ptrtoint ptr {{%.*}} to i64 + // CHECK-PTRAUTH: [[STRIPPED_VTABLE:%.*]] = call i64 @llvm.ptrauth.strip(i64 [[CAST_VTABLE]], i32 0) + // CHECK-PTRAUTH: [[STRIPPED_PTR:%.*]] = inttoptr i64 [[STRIPPED_VTABLE]] to ptr + // CHECK-PTRAUTH: [[STRIPPED_INT:%.*]] = ptrtoint ptr [[STRIPPED_PTR]] to i64 + // CHECK-PTRAUTH: {{%.*}} = mul i64 [[STRIPPED_INT]], {{.*}} // CHECK-VPTR: call void @__ubsan_handle_dynamic_type_cache_miss_abort + // CHECK-PTRAUTH: [[BLENDED:%.*]] = call i64 @llvm.ptrauth.blend(i64 {{%.*}}, i64 17113) + // CHECK-PTRAUTH: [[CAST_VTABLE:%.*]] = ptrtoint ptr %vtable1 to i64 + // CHECK-PTRAUTH: [[AUTHED_INT:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[CAST_VTABLE]], i32 2, i64 [[BLENDED]]) + // CHECK-PTRAUTH: [[AUTHED_PTR:%.*]] = inttoptr i64 [[AUTHED_INT]] to ptr + // CHECK-PTRAUTH: {{%.*}} = load volatile i8, ptr [[AUTHED_PTR]], align 8 // Second, we check that dynamic_cast is actually called once the type check is done. // CHECK-VPTR: call ptr @__{{dynamic_cast|RTDynamicCast}} return dynamic_cast(t); diff --git a/clang/test/CodeGenOpenCL/builtins-amdgcn-gfx10.cl b/clang/test/CodeGenOpenCL/builtins-amdgcn-gfx10.cl index f30776a8bb85b9..3cf1056cf4f48b 100644 --- a/clang/test/CodeGenOpenCL/builtins-amdgcn-gfx10.cl +++ b/clang/test/CodeGenOpenCL/builtins-amdgcn-gfx10.cl @@ -8,13 +8,13 @@ typedef unsigned int uint; typedef unsigned long ulong; // CHECK-LABEL: @test_permlane16( -// CHECK: {{.*}}call{{.*}} i32 @llvm.amdgcn.permlane16(i32 %a, i32 %b, i32 %c, i32 %d, i1 false, i1 false) +// CHECK: {{.*}}call{{.*}} i32 @llvm.amdgcn.permlane16.i32(i32 %a, i32 %b, i32 %c, i32 %d, i1 false, i1 false) void test_permlane16(global uint* out, uint a, uint b, uint c, uint d) { *out = __builtin_amdgcn_permlane16(a, b, c, d, 0, 0); } // CHECK-LABEL: @test_permlanex16( -// CHECK: {{.*}}call{{.*}} i32 @llvm.amdgcn.permlanex16(i32 %a, i32 %b, i32 %c, i32 %d, i1 false, i1 false) +// CHECK: {{.*}}call{{.*}} i32 @llvm.amdgcn.permlanex16.i32(i32 %a, i32 %b, i32 %c, i32 %d, i1 false, i1 false) void test_permlanex16(global uint* out, uint a, uint b, uint c, uint d) { *out = __builtin_amdgcn_permlanex16(a, b, c, d, 0, 0); } diff --git a/clang/test/CodeGenOpenCL/builtins-amdgcn-gfx11.cl b/clang/test/CodeGenOpenCL/builtins-amdgcn-gfx11.cl index 868b5bed0c9522..f4446574635687 100644 --- a/clang/test/CodeGenOpenCL/builtins-amdgcn-gfx11.cl +++ b/clang/test/CodeGenOpenCL/builtins-amdgcn-gfx11.cl @@ -37,7 +37,7 @@ void test_ds_bvh_stack_rtn(global uint2* out, uint addr, uint data, uint4 data1) } // CHECK-LABEL: @test_permlane64( -// CHECK: {{.*}}call{{.*}} i32 @llvm.amdgcn.permlane64(i32 %a) +// CHECK: {{.*}}call{{.*}} i32 @llvm.amdgcn.permlane64.i32(i32 %a) void test_permlane64(global uint* out, uint a) { *out = __builtin_amdgcn_permlane64(a); } diff --git a/clang/test/CodeGenOpenCL/builtins-amdgcn-raw-buffer-store.cl b/clang/test/CodeGenOpenCL/builtins-amdgcn-raw-buffer-store.cl new file mode 100644 index 00000000000000..37975d59730c55 --- /dev/null +++ b/clang/test/CodeGenOpenCL/builtins-amdgcn-raw-buffer-store.cl @@ -0,0 +1,172 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// REQUIRES: amdgpu-registered-target +// RUN: %clang_cc1 -triple amdgcn-unknown-unknown -target-cpu verde -emit-llvm -o - %s | FileCheck %s + +typedef char i8; +typedef short i16; +typedef int i32; +typedef int i64 __attribute__((ext_vector_type(2))); +typedef int i96 __attribute__((ext_vector_type(3))); +typedef int i128 __attribute__((ext_vector_type(4))); + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_store_b8( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.i8(i8 [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 0, i32 0) +// CHECK-NEXT: ret void +// +void test_amdgcn_raw_ptr_buffer_store_b8(i8 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + __builtin_amdgcn_raw_buffer_store_b8(vdata, rsrc, /*offset=*/0, /*soffset=*/0, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_store_b16( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.i16(i16 [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 0, i32 0) +// CHECK-NEXT: ret void +// +void test_amdgcn_raw_ptr_buffer_store_b16(i16 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + __builtin_amdgcn_raw_buffer_store_b16(vdata, rsrc, /*offset=*/0, /*soffset=*/0, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_store_b32( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.i32(i32 [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 0, i32 0) +// CHECK-NEXT: ret void +// +void test_amdgcn_raw_ptr_buffer_store_b32(i32 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + __builtin_amdgcn_raw_buffer_store_b32(vdata, rsrc, /*offset=*/0, /*soffset=*/0, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_store_b64( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.v2i32(<2 x i32> [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 0, i32 0) +// CHECK-NEXT: ret void +// +void test_amdgcn_raw_ptr_buffer_store_b64(i64 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + __builtin_amdgcn_raw_buffer_store_b64(vdata, rsrc, /*offset=*/0, /*soffset=*/0, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_store_b96( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.v3i32(<3 x i32> [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 0, i32 0) +// CHECK-NEXT: ret void +// +void test_amdgcn_raw_ptr_buffer_store_b96(i96 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + __builtin_amdgcn_raw_buffer_store_b96(vdata, rsrc, /*offset=*/0, /*soffset=*/0, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_store_b128( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.v4i32(<4 x i32> [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 0, i32 0) +// CHECK-NEXT: ret void +// +void test_amdgcn_raw_ptr_buffer_store_b128(i128 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + __builtin_amdgcn_raw_buffer_store_b128(vdata, rsrc, /*offset=*/0, /*soffset=*/0, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_store_b8_non_const_offset( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.i8(i8 [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 [[OFFSET:%.*]], i32 0, i32 0) +// CHECK-NEXT: ret void +// +void test_amdgcn_raw_ptr_buffer_store_b8_non_const_offset(i8 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + __builtin_amdgcn_raw_buffer_store_b8(vdata, rsrc, offset, /*soffset=*/0, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_store_b16_non_const_offset( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.i16(i16 [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 [[OFFSET:%.*]], i32 0, i32 0) +// CHECK-NEXT: ret void +// +void test_amdgcn_raw_ptr_buffer_store_b16_non_const_offset(i16 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + __builtin_amdgcn_raw_buffer_store_b16(vdata, rsrc, offset, /*soffset=*/0, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_store_b32_non_const_offset( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.i32(i32 [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 [[OFFSET:%.*]], i32 0, i32 0) +// CHECK-NEXT: ret void +// +void test_amdgcn_raw_ptr_buffer_store_b32_non_const_offset(i32 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + __builtin_amdgcn_raw_buffer_store_b32(vdata, rsrc, offset, /*soffset=*/0, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_store_b64_non_const_offset( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.v2i32(<2 x i32> [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 [[OFFSET:%.*]], i32 0, i32 0) +// CHECK-NEXT: ret void +// +void test_amdgcn_raw_ptr_buffer_store_b64_non_const_offset(i64 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + __builtin_amdgcn_raw_buffer_store_b64(vdata, rsrc, offset, /*soffset=*/0, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_store_b96_non_const_offset( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.v3i32(<3 x i32> [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 [[OFFSET:%.*]], i32 0, i32 0) +// CHECK-NEXT: ret void +// +void test_amdgcn_raw_ptr_buffer_store_b96_non_const_offset(i96 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + __builtin_amdgcn_raw_buffer_store_b96(vdata, rsrc, offset, /*soffset=*/0, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_store_b128_non_const_offset( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.v4i32(<4 x i32> [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 [[OFFSET:%.*]], i32 0, i32 0) +// CHECK-NEXT: ret void +// +void test_amdgcn_raw_ptr_buffer_store_b128_non_const_offset(i128 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + __builtin_amdgcn_raw_buffer_store_b128(vdata, rsrc, offset, /*soffset=*/0, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_store_b8_non_const_soffset( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.i8(i8 [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 [[SOFFSET:%.*]], i32 0) +// CHECK-NEXT: ret void +// +void test_amdgcn_raw_ptr_buffer_store_b8_non_const_soffset(i8 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + __builtin_amdgcn_raw_buffer_store_b8(vdata, rsrc, /*offset=*/0, soffset, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_store_b16_non_const_soffset( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.i16(i16 [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 [[SOFFSET:%.*]], i32 0) +// CHECK-NEXT: ret void +// +void test_amdgcn_raw_ptr_buffer_store_b16_non_const_soffset(i16 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + __builtin_amdgcn_raw_buffer_store_b16(vdata, rsrc, /*offset=*/0, soffset, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_store_b32_non_const_soffset( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.i32(i32 [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 [[SOFFSET:%.*]], i32 0) +// CHECK-NEXT: ret void +// +void test_amdgcn_raw_ptr_buffer_store_b32_non_const_soffset(i32 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + __builtin_amdgcn_raw_buffer_store_b32(vdata, rsrc, /*offset=*/0, soffset, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_store_b64_non_const_soffset( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.v2i32(<2 x i32> [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 [[SOFFSET:%.*]], i32 0) +// CHECK-NEXT: ret void +// +void test_amdgcn_raw_ptr_buffer_store_b64_non_const_soffset(i64 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + __builtin_amdgcn_raw_buffer_store_b64(vdata, rsrc, /*offset=*/0, soffset, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_store_b96_non_const_soffset( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.v3i32(<3 x i32> [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 [[SOFFSET:%.*]], i32 0) +// CHECK-NEXT: ret void +// +void test_amdgcn_raw_ptr_buffer_store_b96_non_const_soffset(i96 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + __builtin_amdgcn_raw_buffer_store_b96(vdata, rsrc, /*offset=*/0, soffset, /*aux=*/0); +} + +// CHECK-LABEL: @test_amdgcn_raw_ptr_buffer_store_b128_non_const_soffset( +// CHECK-NEXT: entry: +// CHECK-NEXT: tail call void @llvm.amdgcn.raw.ptr.buffer.store.v4i32(<4 x i32> [[VDATA:%.*]], ptr addrspace(8) [[RSRC:%.*]], i32 0, i32 [[SOFFSET:%.*]], i32 0) +// CHECK-NEXT: ret void +// +void test_amdgcn_raw_ptr_buffer_store_b128_non_const_soffset(i128 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset) { + __builtin_amdgcn_raw_buffer_store_b128(vdata, rsrc, /*offset=*/0, soffset, /*aux=*/0); +} diff --git a/clang/test/CodeGenOpenCL/builtins-amdgcn-vi.cl b/clang/test/CodeGenOpenCL/builtins-amdgcn-vi.cl index 46af87f5e1d683..5bd8f77a5930c4 100644 --- a/clang/test/CodeGenOpenCL/builtins-amdgcn-vi.cl +++ b/clang/test/CodeGenOpenCL/builtins-amdgcn-vi.cl @@ -158,23 +158,85 @@ void test_ds_faddf(local float *out, float src) { } // CHECK-LABEL: @test_ds_fmin -// CHECK: {{.*}}call{{.*}} float @llvm.amdgcn.ds.fmin.f32(ptr addrspace(3) %out, float %src, i32 0, i32 0, i1 false) +// CHECK: atomicrmw fmin ptr addrspace(3) %out, float %src monotonic, align 4{{$}} +// CHECK: atomicrmw volatile fmin ptr addrspace(3) %out, float %src monotonic, align 4{{$}} + +// CHECK: atomicrmw fmin ptr addrspace(3) %out, float %src acquire, align 4{{$}} +// CHECK: atomicrmw fmin ptr addrspace(3) %out, float %src acquire, align 4{{$}} +// CHECK: atomicrmw fmin ptr addrspace(3) %out, float %src release, align 4{{$}} +// CHECK: atomicrmw fmin ptr addrspace(3) %out, float %src acq_rel, align 4{{$}} +// CHECK: atomicrmw fmin ptr addrspace(3) %out, float %src seq_cst, align 4{{$}} +// CHECK: atomicrmw fmin ptr addrspace(3) %out, float %src seq_cst, align 4{{$}} + +// CHECK: atomicrmw fmin ptr addrspace(3) %out, float %src syncscope("agent") monotonic, align 4{{$}} +// CHECK: atomicrmw fmin ptr addrspace(3) %out, float %src syncscope("workgroup") monotonic, align 4{{$}} +// CHECK: atomicrmw fmin ptr addrspace(3) %out, float %src syncscope("wavefront") monotonic, align 4{{$}} +// CHECK: atomicrmw fmin ptr addrspace(3) %out, float %src syncscope("singlethread") monotonic, align 4{{$}} +// CHECK: atomicrmw fmin ptr addrspace(3) %out, float %src monotonic, align 4{{$}} + #if !defined(__SPIRV__) void test_ds_fminf(local float *out, float src) { #else void test_ds_fminf(__attribute__((address_space(3))) float *out, float src) { #endif *out = __builtin_amdgcn_ds_fminf(out, src, 0, 0, false); + *out = __builtin_amdgcn_ds_fminf(out, src, 0, 0, true); + + // Test all orders. + *out = __builtin_amdgcn_ds_fminf(out, src, __ATOMIC_CONSUME, __MEMORY_SCOPE_SYSTEM, false); + *out = __builtin_amdgcn_ds_fminf(out, src, __ATOMIC_ACQUIRE, __MEMORY_SCOPE_SYSTEM, false); + *out = __builtin_amdgcn_ds_fminf(out, src, __ATOMIC_RELEASE, __MEMORY_SCOPE_SYSTEM, false); + *out = __builtin_amdgcn_ds_fminf(out, src, __ATOMIC_ACQ_REL, __MEMORY_SCOPE_SYSTEM, false); + *out = __builtin_amdgcn_ds_fminf(out, src, __ATOMIC_SEQ_CST, __MEMORY_SCOPE_SYSTEM, false); + *out = __builtin_amdgcn_ds_fminf(out, src, __ATOMIC_SEQ_CST, __MEMORY_SCOPE_SYSTEM, false); // invalid + + // Test all syncscopes. + *out = __builtin_amdgcn_ds_fminf(out, src, __ATOMIC_RELAXED, __MEMORY_SCOPE_DEVICE, false); + *out = __builtin_amdgcn_ds_fminf(out, src, __ATOMIC_RELAXED, __MEMORY_SCOPE_WRKGRP, false); + *out = __builtin_amdgcn_ds_fminf(out, src, __ATOMIC_RELAXED, __MEMORY_SCOPE_WVFRNT, false); + *out = __builtin_amdgcn_ds_fminf(out, src, __ATOMIC_RELAXED, __MEMORY_SCOPE_SINGLE, false); + *out = __builtin_amdgcn_ds_fminf(out, src, __ATOMIC_RELAXED, 5, false); // invalid } // CHECK-LABEL: @test_ds_fmax -// CHECK: {{.*}}call{{.*}} float @llvm.amdgcn.ds.fmax.f32(ptr addrspace(3) %out, float %src, i32 0, i32 0, i1 false) +// CHECK: atomicrmw fmax ptr addrspace(3) %out, float %src monotonic, align 4{{$}} +// CHECK: atomicrmw volatile fmax ptr addrspace(3) %out, float %src monotonic, align 4{{$}} + +// CHECK: atomicrmw fmax ptr addrspace(3) %out, float %src acquire, align 4{{$}} +// CHECK: atomicrmw fmax ptr addrspace(3) %out, float %src acquire, align 4{{$}} +// CHECK: atomicrmw fmax ptr addrspace(3) %out, float %src release, align 4{{$}} +// CHECK: atomicrmw fmax ptr addrspace(3) %out, float %src acq_rel, align 4{{$}} +// CHECK: atomicrmw fmax ptr addrspace(3) %out, float %src seq_cst, align 4{{$}} +// CHECK: atomicrmw fmax ptr addrspace(3) %out, float %src seq_cst, align 4{{$}} + +// CHECK: atomicrmw fmax ptr addrspace(3) %out, float %src syncscope("agent") monotonic, align 4{{$}} +// CHECK: atomicrmw fmax ptr addrspace(3) %out, float %src syncscope("workgroup") monotonic, align 4{{$}} +// CHECK: atomicrmw fmax ptr addrspace(3) %out, float %src syncscope("wavefront") monotonic, align 4{{$}} +// CHECK: atomicrmw fmax ptr addrspace(3) %out, float %src syncscope("singlethread") monotonic, align 4{{$}} +// CHECK: atomicrmw fmax ptr addrspace(3) %out, float %src monotonic, align 4{{$}} + #if !defined(__SPIRV__) void test_ds_fmaxf(local float *out, float src) { #else void test_ds_fmaxf(__attribute__((address_space(3))) float *out, float src) { #endif *out = __builtin_amdgcn_ds_fmaxf(out, src, 0, 0, false); + *out = __builtin_amdgcn_ds_fmaxf(out, src, 0, 0, true); + + // Test all orders. + *out = __builtin_amdgcn_ds_fmaxf(out, src, __ATOMIC_CONSUME, __MEMORY_SCOPE_SYSTEM, false); + *out = __builtin_amdgcn_ds_fmaxf(out, src, __ATOMIC_ACQUIRE, __MEMORY_SCOPE_SYSTEM, false); + *out = __builtin_amdgcn_ds_fmaxf(out, src, __ATOMIC_RELEASE, __MEMORY_SCOPE_SYSTEM, false); + *out = __builtin_amdgcn_ds_fmaxf(out, src, __ATOMIC_ACQ_REL, __MEMORY_SCOPE_SYSTEM, false); + *out = __builtin_amdgcn_ds_fmaxf(out, src, __ATOMIC_SEQ_CST, __MEMORY_SCOPE_SYSTEM, false); + *out = __builtin_amdgcn_ds_fmaxf(out, src, __ATOMIC_SEQ_CST, __MEMORY_SCOPE_SYSTEM, false); // invalid + + // Test all syncscopes. + *out = __builtin_amdgcn_ds_fmaxf(out, src, __ATOMIC_RELAXED, __MEMORY_SCOPE_DEVICE, false); + *out = __builtin_amdgcn_ds_fmaxf(out, src, __ATOMIC_RELAXED, __MEMORY_SCOPE_WRKGRP, false); + *out = __builtin_amdgcn_ds_fmaxf(out, src, __ATOMIC_RELAXED, __MEMORY_SCOPE_WVFRNT, false); + *out = __builtin_amdgcn_ds_fmaxf(out, src, __ATOMIC_RELAXED, __MEMORY_SCOPE_SINGLE, false); + *out = __builtin_amdgcn_ds_fmaxf(out, src, __ATOMIC_RELAXED, 5, false); // invalid } // CHECK-LABEL: @test_s_memtime diff --git a/clang/test/CodeGenOpenCL/builtins-amdgcn.cl b/clang/test/CodeGenOpenCL/builtins-amdgcn.cl index 95daa2cdbc92cb..6a6d5b1dfed3df 100644 --- a/clang/test/CodeGenOpenCL/builtins-amdgcn.cl +++ b/clang/test/CodeGenOpenCL/builtins-amdgcn.cl @@ -308,14 +308,14 @@ void test_ds_bpermute(global int* out, int a, int b) } // CHECK-LABEL: @test_readfirstlane -// CHECK: {{.*}}call{{.*}} i32 @llvm.amdgcn.readfirstlane(i32 %a) +// CHECK: {{.*}}call{{.*}} i32 @llvm.amdgcn.readfirstlane.i32(i32 %a) void test_readfirstlane(global int* out, int a) { *out = __builtin_amdgcn_readfirstlane(a); } // CHECK-LABEL: @test_readlane -// CHECK: {{.*}}call{{.*}} i32 @llvm.amdgcn.readlane(i32 %a, i32 %b) +// CHECK: {{.*}}call{{.*}} i32 @llvm.amdgcn.readlane.i32(i32 %a, i32 %b) void test_readlane(global int* out, int a, int b) { *out = __builtin_amdgcn_readlane(a, b); diff --git a/clang/test/Driver/aarch64-fp16.c b/clang/test/Driver/aarch64-fp16.c index 4da1834cf68765..72ccd79850148f 100644 --- a/clang/test/Driver/aarch64-fp16.c +++ b/clang/test/Driver/aarch64-fp16.c @@ -21,7 +21,7 @@ // RUN: %clang --target=aarch64 -march=armv8a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8-a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A-FP16FML %s -// GENERICV8A-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV8A-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.2a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-NO-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.2-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-NO-FP16FML %s @@ -35,11 +35,11 @@ // GENERICV82A-FP16-SAME: {{$}} // RUN: %clang --target=aarch64 -march=armv8.2-a+profile -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-SPE %s -// GENERICV82A-SPE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.2a"{{.*}} "-target-feature" "+spe"{{.*}} "-target-feature" "+neon" +// GENERICV82A-SPE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.2a"{{.*}} "-target-feature" "+neon"{{.*}} "-target-feature" "+spe" // RUN: %clang --target=aarch64 -march=armv8.2a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.2-a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16FML %s -// GENERICV82A-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV82A-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.2a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16-NO-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.2-a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16-NO-FP16FML %s @@ -51,15 +51,15 @@ // RUN: %clang --target=aarch64 -march=armv8.2a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16FML-NO-FP16 %s // RUN: %clang --target=aarch64 -march=armv8.2-a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16FML-NO-FP16 %s -// GENERICV82A-FP16FML-NO-FP16: "-target-feature" "-fullfp16"{{.*}} "-target-feature" "-fp16fml" +// GENERICV82A-FP16FML-NO-FP16: "-target-feature" "-fp16fml"{{.*}} "-target-feature" "-fullfp16" // RUN: %clang --target=aarch64 -march=armv8.2a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-NO-FP16-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.2-a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-NO-FP16-FP16FML %s -// GENERICV82A-NO-FP16-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV82A-NO-FP16-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.2a+fp16+profile -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16-SPE %s // RUN: %clang --target=aarch64 -march=armv8.2-a+fp16+profile -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16-SPE %s -// GENERICV82A-FP16-SPE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}"{{.*}} "-target-cpu" "generic"{{.*}} "-target-feature" "+v8.2a"{{.*}} "-target-feature" "+fullfp16"{{.*}} "-target-feature" "+spe"{{.*}} "-target-feature" "+neon" +// GENERICV82A-FP16-SPE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}"{{.*}} "-target-cpu" "generic"{{.*}} "-target-feature" "+v8.2a"{{.*}} "-target-feature" "+fullfp16"{{.*}} "-target-feature" "+neon"{{.*}} "-target-feature" "+spe" // GENERICV82A-FP16-SPE-NOT: "-target-feature" "{{[+-]}}fp16fml" // GENERICV82A-FP16-SPE-SAME: {{$}} @@ -74,7 +74,7 @@ // RUN: %clang --target=aarch64 -march=armv8.3a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.3-a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-FP16FML %s -// GENERICV83A-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV83A-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.3a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-FP16-NO-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.3-a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-FP16-NO-FP16FML %s @@ -88,11 +88,11 @@ // RUN: %clang --target=aarch64 -march=armv8.3a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-FP16FML-NO-FP16 %s // RUN: %clang --target=aarch64 -march=armv8.3-a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-FP16FML-NO-FP16 %s -// GENERICV83A-FP16FML-NO-FP16: "-target-feature" "-fullfp16" "-target-feature" "-fp16fml" +// GENERICV83A-FP16FML-NO-FP16: "-target-feature" "-fp16fml" "-target-feature" "-fullfp16" // RUN: %clang --target=aarch64 -march=armv8.3a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-NO-FP16-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.3-a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-NO-FP16-FP16FML %s -// GENERICV83A-NO-FP16-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV83A-NO-FP16-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.4a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-NO-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.4-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-NO-FP16FML %s @@ -101,27 +101,27 @@ // RUN: %clang --target=aarch64 -march=armv8.4a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-FP16 %s // RUN: %clang --target=aarch64 -march=armv8.4-a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-FP16 %s -// GENERICV84A-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV84A-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.4a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.4-a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-FP16FML %s -// GENERICV84A-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV84A-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.4a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-FP16-NO-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.4-a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-FP16-NO-FP16FML %s -// GENERICV84A-FP16-NO-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "-fp16fml" +// GENERICV84A-FP16-NO-FP16FML: "-target-feature" "-fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.4a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-NO-FP16FML-FP16 %s // RUN: %clang --target=aarch64 -march=armv8.4-a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-NO-FP16FML-FP16 %s -// GENERICV84A-NO-FP16FML-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV84A-NO-FP16FML-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.4a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-FP16FML-NO-FP16 %s // RUN: %clang --target=aarch64 -march=armv8.4-a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-FP16FML-NO-FP16 %s -// GENERICV84A-FP16FML-NO-FP16: "-target-feature" "-fullfp16" "-target-feature" "-fp16fml" +// GENERICV84A-FP16FML-NO-FP16: "-target-feature" "-fp16fml" "-target-feature" "-fullfp16" // RUN: %clang --target=aarch64 -march=armv8.4a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-NO-FP16-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.4-a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-NO-FP16-FP16FML %s -// GENERICV84A-NO-FP16-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV84A-NO-FP16-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.5a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-NO-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.5-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-NO-FP16FML %s @@ -130,27 +130,27 @@ // RUN: %clang --target=aarch64 -march=armv8.5a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-FP16 %s // RUN: %clang --target=aarch64 -march=armv8.5-a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-FP16 %s -// GENERICV85A-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV85A-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.5a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.5-a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-FP16FML %s -// GENERICV85A-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV85A-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.5a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-FP16-NO-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.5-a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-FP16-NO-FP16FML %s -// GENERICV85A-FP16-NO-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "-fp16fml" +// GENERICV85A-FP16-NO-FP16FML: "-target-feature" "-fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.5a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-NO-FP16FML-FP16 %s // RUN: %clang --target=aarch64 -march=armv8.5-a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-NO-FP16FML-FP16 %s -// GENERICV85A-NO-FP16FML-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV85A-NO-FP16FML-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.5a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-FP16FML-NO-FP16 %s // RUN: %clang --target=aarch64 -march=armv8.5-a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-FP16FML-NO-FP16 %s -// GENERICV85A-FP16FML-NO-FP16: "-target-feature" "-fullfp16" "-target-feature" "-fp16fml" +// GENERICV85A-FP16FML-NO-FP16: "-target-feature" "-fp16fml" "-target-feature" "-fullfp16" // RUN: %clang --target=aarch64 -march=armv8.5a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-NO-FP16-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.5-a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-NO-FP16-FP16FML %s -// GENERICV85A-NO-FP16-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV85A-NO-FP16-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.6a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-NO-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.6-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-NO-FP16FML %s @@ -159,27 +159,27 @@ // RUN: %clang --target=aarch64 -march=armv8.6a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-FP16 %s // RUN: %clang --target=aarch64 -march=armv8.6-a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-FP16 %s -// GENERICV86A-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV86A-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.6a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.6-a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-FP16FML %s -// GENERICV86A-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV86A-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.6a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-FP16-NO-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.6-a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-FP16-NO-FP16FML %s -// GENERICV86A-FP16-NO-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "-fp16fml" +// GENERICV86A-FP16-NO-FP16FML: "-target-feature" "-fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.6a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-NO-FP16FML-FP16 %s // RUN: %clang --target=aarch64 -march=armv8.6-a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-NO-FP16FML-FP16 %s -// GENERICV86A-NO-FP16FML-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV86A-NO-FP16FML-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.6a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-FP16FML-NO-FP16 %s // RUN: %clang --target=aarch64 -march=armv8.6-a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-FP16FML-NO-FP16 %s -// GENERICV86A-FP16FML-NO-FP16: "-target-feature" "-fullfp16" "-target-feature" "-fp16fml" +// GENERICV86A-FP16FML-NO-FP16: "-target-feature" "-fp16fml" "-target-feature" "-fullfp16" // RUN: %clang --target=aarch64 -march=armv8.6a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-NO-FP16-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.6-a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-NO-FP16-FP16FML %s -// GENERICV86A-NO-FP16-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV86A-NO-FP16-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.7a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-NO-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.7-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-NO-FP16FML %s @@ -188,27 +188,27 @@ // RUN: %clang --target=aarch64 -march=armv8.7a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-FP16 %s // RUN: %clang --target=aarch64 -march=armv8.7-a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-FP16 %s -// GENERICV87A-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV87A-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.7a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.7-a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-FP16FML %s -// GENERICV87A-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV87A-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.7a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-FP16-NO-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.7-a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-FP16-NO-FP16FML %s -// GENERICV87A-FP16-NO-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "-fp16fml" +// GENERICV87A-FP16-NO-FP16FML: "-target-feature" "-fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.7a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-NO-FP16FML-FP16 %s // RUN: %clang --target=aarch64 -march=armv8.7-a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-NO-FP16FML-FP16 %s -// GENERICV87A-NO-FP16FML-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV87A-NO-FP16FML-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.7a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-FP16FML-NO-FP16 %s // RUN: %clang --target=aarch64 -march=armv8.7-a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-FP16FML-NO-FP16 %s -// GENERICV87A-FP16FML-NO-FP16: "-target-feature" "-fullfp16" "-target-feature" "-fp16fml" +// GENERICV87A-FP16FML-NO-FP16: "-target-feature" "-fp16fml" "-target-feature" "-fullfp16" // RUN: %clang --target=aarch64 -march=armv8.7a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-NO-FP16-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.7-a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-NO-FP16-FP16FML %s -// GENERICV87A-NO-FP16-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV87A-NO-FP16-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.8a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-NO-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.8-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-NO-FP16FML %s @@ -217,24 +217,24 @@ // RUN: %clang --target=aarch64 -march=armv8.8a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-FP16 %s // RUN: %clang --target=aarch64 -march=armv8.8-a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-FP16 %s -// GENERICV88A-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV88A-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.8a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.8-a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-FP16FML %s -// GENERICV88A-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV88A-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.8a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-FP16-NO-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.8-a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-FP16-NO-FP16FML %s -// GENERICV88A-FP16-NO-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "-fp16fml" +// GENERICV88A-FP16-NO-FP16FML: "-target-feature" "-fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.8a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-NO-FP16FML-FP16 %s // RUN: %clang --target=aarch64 -march=armv8.8-a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-NO-FP16FML-FP16 %s -// GENERICV88A-NO-FP16FML-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV88A-NO-FP16FML-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" // RUN: %clang --target=aarch64 -march=armv8.8a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-FP16FML-NO-FP16 %s // RUN: %clang --target=aarch64 -march=armv8.8-a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-FP16FML-NO-FP16 %s -// GENERICV88A-FP16FML-NO-FP16: "-target-feature" "-fullfp16" "-target-feature" "-fp16fml" +// GENERICV88A-FP16FML-NO-FP16: "-target-feature" "-fp16fml" "-target-feature" "-fullfp16" // RUN: %clang --target=aarch64 -march=armv8.8a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-NO-FP16-FP16FML %s // RUN: %clang --target=aarch64 -march=armv8.8-a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-NO-FP16-FP16FML %s -// GENERICV88A-NO-FP16-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" +// GENERICV88A-NO-FP16-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" diff --git a/clang/test/Driver/aarch64-mac-cpus.c b/clang/test/Driver/aarch64-mac-cpus.c index 488298cfd2d245..8d23ad8c956fd7 100644 --- a/clang/test/Driver/aarch64-mac-cpus.c +++ b/clang/test/Driver/aarch64-mac-cpus.c @@ -21,4 +21,4 @@ // EXPLICIT-A11: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "apple-a11" // EXPLICIT-A7: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "apple-a7" // EXPLICIT-A14: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "apple-a14" -// EXPLICIT-M1: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "apple-m1" +// EXPLICIT-M1: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "apple-a14" diff --git a/clang/test/Driver/aarch64-sve2.c b/clang/test/Driver/aarch64-sve2.c index c801f44d3cb842..389c3a52bde44b 100644 --- a/clang/test/Driver/aarch64-sve2.c +++ b/clang/test/Driver/aarch64-sve2.c @@ -5,4 +5,4 @@ // RUN: %clang --target=aarch64 -mlittle-endian -march=armv9-a+nosve2 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-NOSVE2 %s // RUN: %clang --target=aarch64_be -mlittle-endian -march=armv9a+nosve2 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-NOSVE2 %s // RUN: %clang --target=aarch64_be -mlittle-endian -march=armv9-a+nosve2 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-NOSVE2 %s -// GENERICV9A-NOSVE2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9a"{{.*}} "-target-feature" "+neon" "-target-feature" "+sve" "-target-feature" "-sve2" +// GENERICV9A-NOSVE2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9a"{{.*}} "-target-feature" "+neon"{{.*}} "-target-feature" "+sve" "-target-feature" "-sve2" diff --git a/clang/test/Driver/aarch64-v81a.c b/clang/test/Driver/aarch64-v81a.c index e84652ec7f11e1..f3873b3ab1864e 100644 --- a/clang/test/Driver/aarch64-v81a.c +++ b/clang/test/Driver/aarch64-v81a.c @@ -19,3 +19,17 @@ // RUN: %clang --target=arm64 -mlittle-endian -march=armv8.1a -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERICV81A %s // RUN: %clang --target=arm64 -mlittle-endian -march=armv8.1-a -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERICV81A %s // ARM64-GENERICV81A: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic"{{.*}} "-target-feature" "+v8.1a"{{.*}} "-target-feature" "+neon" + +// ===== Architecture extensions ===== + +// RUN: %if aarch64-registered-target %{ %clang -target aarch64 -march=armv8.1-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s %} +// ARCH-EXTENSION: FEAT_AdvSIMD +// ARCH-EXTENSION: FEAT_CRC32 +// ARCH-EXTENSION: FEAT_ETE +// ARCH-EXTENSION: FEAT_FP +// ARCH-EXTENSION: FEAT_LOR +// ARCH-EXTENSION: FEAT_LSE +// ARCH-EXTENSION: FEAT_PAN +// ARCH-EXTENSION: FEAT_RDM +// ARCH-EXTENSION: FEAT_TRBE +// ARCH-EXTENSION: FEAT_VHE diff --git a/clang/test/Driver/aarch64-v82a.c b/clang/test/Driver/aarch64-v82a.c index 9dd355934c1059..318c270cad3966 100644 --- a/clang/test/Driver/aarch64-v82a.c +++ b/clang/test/Driver/aarch64-v82a.c @@ -13,3 +13,21 @@ // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.2a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-BE %s // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.2-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-BE %s // GENERICV82A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.2a"{{.*}} "-target-feature" "+neon" + +// ===== Architecture extensions ===== + +// RUN: %if aarch64-registered-target %{ %clang -target aarch64 -march=armv8.2-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s %} +// ARCH-EXTENSION: FEAT_AdvSIMD +// ARCH-EXTENSION: FEAT_CRC32 +// ARCH-EXTENSION: FEAT_DPB +// ARCH-EXTENSION: FEAT_ETE +// ARCH-EXTENSION: FEAT_FP +// ARCH-EXTENSION: FEAT_LOR +// ARCH-EXTENSION: FEAT_LSE +// ARCH-EXTENSION: FEAT_PAN +// ARCH-EXTENSION: FEAT_PAN2 +// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1 +// ARCH-EXTENSION: FEAT_RDM +// ARCH-EXTENSION: FEAT_TRBE +// ARCH-EXTENSION: FEAT_UAO +// ARCH-EXTENSION: FEAT_VHE diff --git a/clang/test/Driver/aarch64-v83a.c b/clang/test/Driver/aarch64-v83a.c index b0ff9fb3abc24c..f35c500ee0a9be 100644 --- a/clang/test/Driver/aarch64-v83a.c +++ b/clang/test/Driver/aarch64-v83a.c @@ -13,3 +13,26 @@ // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.3a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-BE %s // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.3-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-BE %s // GENERICV83A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.3a"{{.*}} "-target-feature" "+neon" + +// ===== Architecture extensions ===== + +// RUN: %if aarch64-registered-target %{ %clang -target aarch64 -march=armv8.3-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s %} +// ARCH-EXTENSION: FEAT_AdvSIMD +// ARCH-EXTENSION: FEAT_CCIDX +// ARCH-EXTENSION: FEAT_CRC32 +// ARCH-EXTENSION: FEAT_DPB +// ARCH-EXTENSION: FEAT_ETE +// ARCH-EXTENSION: FEAT_FCMA +// ARCH-EXTENSION: FEAT_FP +// ARCH-EXTENSION: FEAT_JSCVT +// ARCH-EXTENSION: FEAT_LOR +// ARCH-EXTENSION: FEAT_LRCPC +// ARCH-EXTENSION: FEAT_LSE +// ARCH-EXTENSION: FEAT_PAN +// ARCH-EXTENSION: FEAT_PAN2 +// ARCH-EXTENSION: FEAT_PAuth +// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1 +// ARCH-EXTENSION: FEAT_RDM +// ARCH-EXTENSION: FEAT_TRBE +// ARCH-EXTENSION: FEAT_UAO +// ARCH-EXTENSION: FEAT_VHE diff --git a/clang/test/Driver/aarch64-v84a.c b/clang/test/Driver/aarch64-v84a.c index 030990bfe5131c..d72c79fc14cec5 100644 --- a/clang/test/Driver/aarch64-v84a.c +++ b/clang/test/Driver/aarch64-v84a.c @@ -13,3 +13,37 @@ // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.4a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-BE %s // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.4-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-BE %s // GENERICV84A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.4a"{{.*}} "-target-feature" "+neon" + +// ===== Architecture extensions ===== + +// RUN: %if aarch64-registered-target %{ %clang -target aarch64 -march=armv8.4-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s %} +// ARCH-EXTENSION: FEAT_AMUv1 +// ARCH-EXTENSION: FEAT_AdvSIMD +// ARCH-EXTENSION: FEAT_CCIDX +// ARCH-EXTENSION: FEAT_CRC32 +// ARCH-EXTENSION: FEAT_DIT +// ARCH-EXTENSION: FEAT_DPB +// ARCH-EXTENSION: FEAT_DotProd +// ARCH-EXTENSION: FEAT_ETE +// ARCH-EXTENSION: FEAT_FCMA +// ARCH-EXTENSION: FEAT_FP +// ARCH-EXTENSION: FEAT_FlagM +// ARCH-EXTENSION: FEAT_JSCVT +// ARCH-EXTENSION: FEAT_LOR +// ARCH-EXTENSION: FEAT_LRCPC +// ARCH-EXTENSION: FEAT_LRCPC2 +// ARCH-EXTENSION: FEAT_LSE +// ARCH-EXTENSION: FEAT_LSE2 +// ARCH-EXTENSION: FEAT_MPAM +// ARCH-EXTENSION: FEAT_NV, FEAT_NV2 +// ARCH-EXTENSION: FEAT_PAN +// ARCH-EXTENSION: FEAT_PAN2 +// ARCH-EXTENSION: FEAT_PAuth +// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1 +// ARCH-EXTENSION: FEAT_RDM +// ARCH-EXTENSION: FEAT_SEL2 +// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE +// ARCH-EXTENSION: FEAT_TRBE +// ARCH-EXTENSION: FEAT_TRF +// ARCH-EXTENSION: FEAT_UAO +// ARCH-EXTENSION: FEAT_VHE diff --git a/clang/test/Driver/aarch64-v85a.c b/clang/test/Driver/aarch64-v85a.c index 3e1e921dcc0133..06c0989bc8e9b2 100644 --- a/clang/test/Driver/aarch64-v85a.c +++ b/clang/test/Driver/aarch64-v85a.c @@ -13,3 +13,45 @@ // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.5a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-BE %s // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.5-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-BE %s // GENERICV85A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.5a"{{.*}} "-target-feature" "+neon" + +// ===== Architecture extensions ===== + +// RUN: %if aarch64-registered-target %{ %clang -target aarch64 -march=armv8.5-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s %} +// ARCH-EXTENSION: FEAT_AMUv1 +// ARCH-EXTENSION: FEAT_AdvSIMD +// ARCH-EXTENSION: FEAT_BTI +// ARCH-EXTENSION: FEAT_CCIDX +// ARCH-EXTENSION: FEAT_CRC32 +// ARCH-EXTENSION: FEAT_CSV2_2 +// ARCH-EXTENSION: FEAT_DIT +// ARCH-EXTENSION: FEAT_DPB +// ARCH-EXTENSION: FEAT_DPB2 +// ARCH-EXTENSION: FEAT_DotProd +// ARCH-EXTENSION: FEAT_ETE +// ARCH-EXTENSION: FEAT_FCMA +// ARCH-EXTENSION: FEAT_FP +// ARCH-EXTENSION: FEAT_FRINTTS +// ARCH-EXTENSION: FEAT_FlagM +// ARCH-EXTENSION: FEAT_FlagM2 +// ARCH-EXTENSION: FEAT_JSCVT +// ARCH-EXTENSION: FEAT_LOR +// ARCH-EXTENSION: FEAT_LRCPC +// ARCH-EXTENSION: FEAT_LRCPC2 +// ARCH-EXTENSION: FEAT_LSE +// ARCH-EXTENSION: FEAT_LSE2 +// ARCH-EXTENSION: FEAT_MPAM +// ARCH-EXTENSION: FEAT_NV, FEAT_NV2 +// ARCH-EXTENSION: FEAT_PAN +// ARCH-EXTENSION: FEAT_PAN2 +// ARCH-EXTENSION: FEAT_PAuth +// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1 +// ARCH-EXTENSION: FEAT_RDM +// ARCH-EXTENSION: FEAT_SB +// ARCH-EXTENSION: FEAT_SEL2 +// ARCH-EXTENSION: FEAT_SPECRES +// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2 +// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE +// ARCH-EXTENSION: FEAT_TRBE +// ARCH-EXTENSION: FEAT_TRF +// ARCH-EXTENSION: FEAT_UAO +// ARCH-EXTENSION: FEAT_VHE diff --git a/clang/test/Driver/aarch64-v86a.c b/clang/test/Driver/aarch64-v86a.c index ba2b57979b5187..04d372e762a37d 100644 --- a/clang/test/Driver/aarch64-v86a.c +++ b/clang/test/Driver/aarch64-v86a.c @@ -13,3 +13,50 @@ // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.6a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-BE %s // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.6-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-BE %s // GENERICV86A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.6a"{{.*}} "-target-feature" "+neon" + +// ===== Architecture extensions ===== + +// RUN: %if aarch64-registered-target %{ %clang -target aarch64 -march=armv8.6-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s %} +// ARCH-EXTENSION: FEAT_AMUv1 +// ARCH-EXTENSION: FEAT_AMUv1p1 +// ARCH-EXTENSION: FEAT_AdvSIMD +// ARCH-EXTENSION: FEAT_BF16 +// ARCH-EXTENSION: FEAT_BTI +// ARCH-EXTENSION: FEAT_CCIDX +// ARCH-EXTENSION: FEAT_CRC32 +// ARCH-EXTENSION: FEAT_CSV2_2 +// ARCH-EXTENSION: FEAT_DIT +// ARCH-EXTENSION: FEAT_DPB +// ARCH-EXTENSION: FEAT_DPB2 +// ARCH-EXTENSION: FEAT_DotProd +// ARCH-EXTENSION: FEAT_ECV +// ARCH-EXTENSION: FEAT_ETE +// ARCH-EXTENSION: FEAT_FCMA +// ARCH-EXTENSION: FEAT_FGT +// ARCH-EXTENSION: FEAT_FP +// ARCH-EXTENSION: FEAT_FRINTTS +// ARCH-EXTENSION: FEAT_FlagM +// ARCH-EXTENSION: FEAT_FlagM2 +// ARCH-EXTENSION: FEAT_I8MM +// ARCH-EXTENSION: FEAT_JSCVT +// ARCH-EXTENSION: FEAT_LOR +// ARCH-EXTENSION: FEAT_LRCPC +// ARCH-EXTENSION: FEAT_LRCPC2 +// ARCH-EXTENSION: FEAT_LSE +// ARCH-EXTENSION: FEAT_LSE2 +// ARCH-EXTENSION: FEAT_MPAM +// ARCH-EXTENSION: FEAT_NV, FEAT_NV2 +// ARCH-EXTENSION: FEAT_PAN +// ARCH-EXTENSION: FEAT_PAN2 +// ARCH-EXTENSION: FEAT_PAuth +// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1 +// ARCH-EXTENSION: FEAT_RDM +// ARCH-EXTENSION: FEAT_SB +// ARCH-EXTENSION: FEAT_SEL2 +// ARCH-EXTENSION: FEAT_SPECRES +// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2 +// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE +// ARCH-EXTENSION: FEAT_TRBE +// ARCH-EXTENSION: FEAT_TRF +// ARCH-EXTENSION: FEAT_UAO +// ARCH-EXTENSION: FEAT_VHE diff --git a/clang/test/Driver/aarch64-v87a.c b/clang/test/Driver/aarch64-v87a.c index ee4b68882739a8..b385e7cfb2ad61 100644 --- a/clang/test/Driver/aarch64-v87a.c +++ b/clang/test/Driver/aarch64-v87a.c @@ -13,3 +13,53 @@ // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.7a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-BE %s // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.7-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-BE %s // GENERICV87A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.7a"{{.*}} "-target-feature" "+neon" + +// ===== Architecture extensions ===== + +// RUN: %if aarch64-registered-target %{ %clang -target aarch64 -march=armv8.7-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s %} +// ARCH-EXTENSION: FEAT_AMUv1 +// ARCH-EXTENSION: FEAT_AMUv1p1 +// ARCH-EXTENSION: FEAT_AdvSIMD +// ARCH-EXTENSION: FEAT_BF16 +// ARCH-EXTENSION: FEAT_BTI +// ARCH-EXTENSION: FEAT_CCIDX +// ARCH-EXTENSION: FEAT_CRC32 +// ARCH-EXTENSION: FEAT_CSV2_2 +// ARCH-EXTENSION: FEAT_DIT +// ARCH-EXTENSION: FEAT_DPB +// ARCH-EXTENSION: FEAT_DPB2 +// ARCH-EXTENSION: FEAT_DotProd +// ARCH-EXTENSION: FEAT_ECV +// ARCH-EXTENSION: FEAT_ETE +// ARCH-EXTENSION: FEAT_FCMA +// ARCH-EXTENSION: FEAT_FGT +// ARCH-EXTENSION: FEAT_FP +// ARCH-EXTENSION: FEAT_FRINTTS +// ARCH-EXTENSION: FEAT_FlagM +// ARCH-EXTENSION: FEAT_FlagM2 +// ARCH-EXTENSION: FEAT_HCX +// ARCH-EXTENSION: FEAT_I8MM +// ARCH-EXTENSION: FEAT_JSCVT +// ARCH-EXTENSION: FEAT_LOR +// ARCH-EXTENSION: FEAT_LRCPC +// ARCH-EXTENSION: FEAT_LRCPC2 +// ARCH-EXTENSION: FEAT_LSE +// ARCH-EXTENSION: FEAT_LSE2 +// ARCH-EXTENSION: FEAT_MPAM +// ARCH-EXTENSION: FEAT_NV, FEAT_NV2 +// ARCH-EXTENSION: FEAT_PAN +// ARCH-EXTENSION: FEAT_PAN2 +// ARCH-EXTENSION: FEAT_PAuth +// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1 +// ARCH-EXTENSION: FEAT_RDM +// ARCH-EXTENSION: FEAT_SB +// ARCH-EXTENSION: FEAT_SEL2 +// ARCH-EXTENSION: FEAT_SPECRES +// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2 +// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE +// ARCH-EXTENSION: FEAT_TRBE +// ARCH-EXTENSION: FEAT_TRF +// ARCH-EXTENSION: FEAT_UAO +// ARCH-EXTENSION: FEAT_VHE +// ARCH-EXTENSION: FEAT_WFxT +// ARCH-EXTENSION: FEAT_XS diff --git a/clang/test/Driver/aarch64-v88a.c b/clang/test/Driver/aarch64-v88a.c index b680c1f567134d..438796b91fff61 100644 --- a/clang/test/Driver/aarch64-v88a.c +++ b/clang/test/Driver/aarch64-v88a.c @@ -13,3 +13,56 @@ // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.8a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-BE %s // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.8-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-BE %s // GENERICV88A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.8a"{{.*}} "-target-feature" "+neon" + +// ===== Architecture extensions ===== + +// RUN: %if aarch64-registered-target %{ %clang -target aarch64 -march=armv8.8-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s %} +// ARCH-EXTENSION: FEAT_AMUv1 +// ARCH-EXTENSION: FEAT_AMUv1p1 +// ARCH-EXTENSION: FEAT_AdvSIMD +// ARCH-EXTENSION: FEAT_BF16 +// ARCH-EXTENSION: FEAT_BTI +// ARCH-EXTENSION: FEAT_CCIDX +// ARCH-EXTENSION: FEAT_CRC32 +// ARCH-EXTENSION: FEAT_CSV2_2 +// ARCH-EXTENSION: FEAT_DIT +// ARCH-EXTENSION: FEAT_DPB +// ARCH-EXTENSION: FEAT_DPB2 +// ARCH-EXTENSION: FEAT_DotProd +// ARCH-EXTENSION: FEAT_ECV +// ARCH-EXTENSION: FEAT_ETE +// ARCH-EXTENSION: FEAT_FCMA +// ARCH-EXTENSION: FEAT_FGT +// ARCH-EXTENSION: FEAT_FP +// ARCH-EXTENSION: FEAT_FRINTTS +// ARCH-EXTENSION: FEAT_FlagM +// ARCH-EXTENSION: FEAT_FlagM2 +// ARCH-EXTENSION: FEAT_HBC +// ARCH-EXTENSION: FEAT_HCX +// ARCH-EXTENSION: FEAT_I8MM +// ARCH-EXTENSION: FEAT_JSCVT +// ARCH-EXTENSION: FEAT_LOR +// ARCH-EXTENSION: FEAT_LRCPC +// ARCH-EXTENSION: FEAT_LRCPC2 +// ARCH-EXTENSION: FEAT_LSE +// ARCH-EXTENSION: FEAT_LSE2 +// ARCH-EXTENSION: FEAT_MOPS +// ARCH-EXTENSION: FEAT_MPAM +// ARCH-EXTENSION: FEAT_NMI, FEAT_GICv3_NMI +// ARCH-EXTENSION: FEAT_NV, FEAT_NV2 +// ARCH-EXTENSION: FEAT_PAN +// ARCH-EXTENSION: FEAT_PAN2 +// ARCH-EXTENSION: FEAT_PAuth +// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1 +// ARCH-EXTENSION: FEAT_RDM +// ARCH-EXTENSION: FEAT_SB +// ARCH-EXTENSION: FEAT_SEL2 +// ARCH-EXTENSION: FEAT_SPECRES +// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2 +// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE +// ARCH-EXTENSION: FEAT_TRBE +// ARCH-EXTENSION: FEAT_TRF +// ARCH-EXTENSION: FEAT_UAO +// ARCH-EXTENSION: FEAT_VHE +// ARCH-EXTENSION: FEAT_WFxT +// ARCH-EXTENSION: FEAT_XS diff --git a/clang/test/Driver/aarch64-v89a.c b/clang/test/Driver/aarch64-v89a.c index 903b793d046ba6..42bcb127cd3bd2 100644 --- a/clang/test/Driver/aarch64-v89a.c +++ b/clang/test/Driver/aarch64-v89a.c @@ -12,3 +12,62 @@ // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.9a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV89A-BE %s // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.9-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV89A-BE %s // GENERICV89A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.9a"{{.*}} "-target-feature" "+neon" + +// ===== Architecture extensions ===== + +// RUN: %if aarch64-registered-target %{ %clang -target aarch64 -march=armv8.9-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s %} +// ARCH-EXTENSION: FEAT_AMUv1 +// ARCH-EXTENSION: FEAT_AMUv1p1 +// ARCH-EXTENSION: FEAT_AdvSIMD +// ARCH-EXTENSION: FEAT_BF16 +// ARCH-EXTENSION: FEAT_BTI +// ARCH-EXTENSION: FEAT_CCIDX +// ARCH-EXTENSION: FEAT_CHK +// ARCH-EXTENSION: FEAT_CLRBHB +// ARCH-EXTENSION: FEAT_CRC32 +// ARCH-EXTENSION: FEAT_CSSC +// ARCH-EXTENSION: FEAT_CSV2_2 +// ARCH-EXTENSION: FEAT_DIT +// ARCH-EXTENSION: FEAT_DPB +// ARCH-EXTENSION: FEAT_DPB2 +// ARCH-EXTENSION: FEAT_DotProd +// ARCH-EXTENSION: FEAT_ECV +// ARCH-EXTENSION: FEAT_ETE +// ARCH-EXTENSION: FEAT_FCMA +// ARCH-EXTENSION: FEAT_FGT +// ARCH-EXTENSION: FEAT_FP +// ARCH-EXTENSION: FEAT_FRINTTS +// ARCH-EXTENSION: FEAT_FlagM +// ARCH-EXTENSION: FEAT_FlagM2 +// ARCH-EXTENSION: FEAT_HBC +// ARCH-EXTENSION: FEAT_HCX +// ARCH-EXTENSION: FEAT_I8MM +// ARCH-EXTENSION: FEAT_JSCVT +// ARCH-EXTENSION: FEAT_LOR +// ARCH-EXTENSION: FEAT_LRCPC +// ARCH-EXTENSION: FEAT_LRCPC2 +// ARCH-EXTENSION: FEAT_LSE +// ARCH-EXTENSION: FEAT_LSE2 +// ARCH-EXTENSION: FEAT_MOPS +// ARCH-EXTENSION: FEAT_MPAM +// ARCH-EXTENSION: FEAT_NMI, FEAT_GICv3_NMI +// ARCH-EXTENSION: FEAT_NV, FEAT_NV2 +// ARCH-EXTENSION: FEAT_PAN +// ARCH-EXTENSION: FEAT_PAN2 +// ARCH-EXTENSION: FEAT_PAuth +// ARCH-EXTENSION: FEAT_PRFMSLC +// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1 +// ARCH-EXTENSION: FEAT_RASv2 +// ARCH-EXTENSION: FEAT_RDM +// ARCH-EXTENSION: FEAT_SB +// ARCH-EXTENSION: FEAT_SEL2 +// ARCH-EXTENSION: FEAT_SPECRES +// ARCH-EXTENSION: FEAT_SPECRES2 +// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2 +// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE +// ARCH-EXTENSION: FEAT_TRBE +// ARCH-EXTENSION: FEAT_TRF +// ARCH-EXTENSION: FEAT_UAO +// ARCH-EXTENSION: FEAT_VHE +// ARCH-EXTENSION: FEAT_WFxT +// ARCH-EXTENSION: FEAT_XS diff --git a/clang/test/Driver/aarch64-v8a.c b/clang/test/Driver/aarch64-v8a.c new file mode 100644 index 00000000000000..a3b01560b22a6f --- /dev/null +++ b/clang/test/Driver/aarch64-v8a.c @@ -0,0 +1,29 @@ +// RUN: %clang --target=aarch64_be -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A-BE %s +// RUN: %clang --target=aarch64_be -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A-BE %s +// RUN: %clang --target=aarch64 -mbig-endian -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A-BE %s +// RUN: %clang --target=aarch64 -mbig-endian -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A-BE %s +// RUN: %clang --target=aarch64_be -mbig-endian -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A-BE %s +// RUN: %clang --target=aarch64_be -mbig-endian -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A-BE %s +// GENERICV8A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic"{{.*}} "-target-feature" "+v8a"{{.*}} "-target-feature" "+neon" + +// RUN: %clang --target=aarch64 -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A %s +// RUN: %clang --target=aarch64 -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A %s +// RUN: %clang --target=aarch64 -mlittle-endian -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A %s +// RUN: %clang --target=aarch64 -mlittle-endian -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A %s +// RUN: %clang --target=aarch64_be -mlittle-endian -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A %s +// RUN: %clang --target=aarch64_be -mlittle-endian -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A %s +// GENERICV8A: "-cc1"{{.*}} "-triple" "aarch64{{(--)?}}"{{.*}} "-target-cpu" "generic"{{.*}} "-target-feature" "+v8a"{{.*}} "-target-feature" "+neon"{{.*}} + +// RUN: %clang --target=arm64 -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERICV8A %s +// RUN: %clang --target=arm64 -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERICV8A %s +// RUN: %clang --target=arm64 -mlittle-endian -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERICV8A %s +// RUN: %clang --target=arm64 -mlittle-endian -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERICV8A %s +// ARM64-GENERICV8A: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic"{{.*}} "-target-feature" "+v8a"{{.*}} "-target-feature" "+neon" + +// ===== Architecture extensions ===== + +// RUN: %if aarch64-registered-target %{ %clang -target aarch64 -march=armv8-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s %} +// ARCH-EXTENSION: FEAT_AdvSIMD +// ARCH-EXTENSION: FEAT_ETE +// ARCH-EXTENSION: FEAT_FP +// ARCH-EXTENSION: FEAT_TRBE diff --git a/clang/test/Driver/aarch64-v91a.c b/clang/test/Driver/aarch64-v91a.c index 80853a59d01537..c5667f8fb3bcdc 100644 --- a/clang/test/Driver/aarch64-v91a.c +++ b/clang/test/Driver/aarch64-v91a.c @@ -13,3 +13,55 @@ // RUN: %clang --target=aarch64_be -mbig-endian -march=armv9.1a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV91A-BE %s // RUN: %clang --target=aarch64_be -mbig-endian -march=armv9.1-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV91A-BE %s // GENERICV91A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9.1a"{{.*}} "-target-feature" "+sve" "-target-feature" "+sve2" + +// ===== Architecture extensions ===== + +// RUN: %if aarch64-registered-target %{ %clang -target aarch64 -march=armv9.1-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s %} +// ARCH-EXTENSION: FEAT_AMUv1 +// ARCH-EXTENSION: FEAT_AMUv1p1 +// ARCH-EXTENSION: FEAT_AdvSIMD +// ARCH-EXTENSION: FEAT_BF16 +// ARCH-EXTENSION: FEAT_BTI +// ARCH-EXTENSION: FEAT_CCIDX +// ARCH-EXTENSION: FEAT_CRC32 +// ARCH-EXTENSION: FEAT_CSV2_2 +// ARCH-EXTENSION: FEAT_DIT +// ARCH-EXTENSION: FEAT_DPB +// ARCH-EXTENSION: FEAT_DPB2 +// ARCH-EXTENSION: FEAT_DotProd +// ARCH-EXTENSION: FEAT_ECV +// ARCH-EXTENSION: FEAT_ETE +// ARCH-EXTENSION: FEAT_FCMA +// ARCH-EXTENSION: FEAT_FGT +// ARCH-EXTENSION: FEAT_FP +// ARCH-EXTENSION: FEAT_FP16 +// ARCH-EXTENSION: FEAT_FRINTTS +// ARCH-EXTENSION: FEAT_FlagM +// ARCH-EXTENSION: FEAT_FlagM2 +// ARCH-EXTENSION: FEAT_I8MM +// ARCH-EXTENSION: FEAT_JSCVT +// ARCH-EXTENSION: FEAT_LOR +// ARCH-EXTENSION: FEAT_LRCPC +// ARCH-EXTENSION: FEAT_LRCPC2 +// ARCH-EXTENSION: FEAT_LSE +// ARCH-EXTENSION: FEAT_LSE2 +// ARCH-EXTENSION: FEAT_MEC +// ARCH-EXTENSION: FEAT_MPAM +// ARCH-EXTENSION: FEAT_NV, FEAT_NV2 +// ARCH-EXTENSION: FEAT_PAN +// ARCH-EXTENSION: FEAT_PAN2 +// ARCH-EXTENSION: FEAT_PAuth +// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1 +// ARCH-EXTENSION: FEAT_RDM +// ARCH-EXTENSION: FEAT_RME +// ARCH-EXTENSION: FEAT_SB +// ARCH-EXTENSION: FEAT_SEL2 +// ARCH-EXTENSION: FEAT_SPECRES +// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2 +// ARCH-EXTENSION: FEAT_SVE +// ARCH-EXTENSION: FEAT_SVE2 +// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE +// ARCH-EXTENSION: FEAT_TRBE +// ARCH-EXTENSION: FEAT_TRF +// ARCH-EXTENSION: FEAT_UAO +// ARCH-EXTENSION: FEAT_VHE diff --git a/clang/test/Driver/aarch64-v92a.c b/clang/test/Driver/aarch64-v92a.c index ee644cc6f3c620..6088a69312dc4c 100644 --- a/clang/test/Driver/aarch64-v92a.c +++ b/clang/test/Driver/aarch64-v92a.c @@ -13,3 +13,58 @@ // RUN: %clang --target=aarch64_be -mbig-endian -march=armv9.2a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV92A-BE %s // RUN: %clang --target=aarch64_be -mbig-endian -march=armv9.2-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV92A-BE %s // GENERICV92A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9.2a"{{.*}} "-target-feature" "+sve" "-target-feature" "+sve2" + +// ===== Architecture extensions ===== + +// RUN: %if aarch64-registered-target %{ %clang -target aarch64 -march=armv9.2-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s %} +// ARCH-EXTENSION: FEAT_AMUv1 +// ARCH-EXTENSION: FEAT_AMUv1p1 +// ARCH-EXTENSION: FEAT_AdvSIMD +// ARCH-EXTENSION: FEAT_BF16 +// ARCH-EXTENSION: FEAT_BTI +// ARCH-EXTENSION: FEAT_CCIDX +// ARCH-EXTENSION: FEAT_CRC32 +// ARCH-EXTENSION: FEAT_CSV2_2 +// ARCH-EXTENSION: FEAT_DIT +// ARCH-EXTENSION: FEAT_DPB +// ARCH-EXTENSION: FEAT_DPB2 +// ARCH-EXTENSION: FEAT_DotProd +// ARCH-EXTENSION: FEAT_ECV +// ARCH-EXTENSION: FEAT_ETE +// ARCH-EXTENSION: FEAT_FCMA +// ARCH-EXTENSION: FEAT_FGT +// ARCH-EXTENSION: FEAT_FP +// ARCH-EXTENSION: FEAT_FP16 +// ARCH-EXTENSION: FEAT_FRINTTS +// ARCH-EXTENSION: FEAT_FlagM +// ARCH-EXTENSION: FEAT_FlagM2 +// ARCH-EXTENSION: FEAT_HCX +// ARCH-EXTENSION: FEAT_I8MM +// ARCH-EXTENSION: FEAT_JSCVT +// ARCH-EXTENSION: FEAT_LOR +// ARCH-EXTENSION: FEAT_LRCPC +// ARCH-EXTENSION: FEAT_LRCPC2 +// ARCH-EXTENSION: FEAT_LSE +// ARCH-EXTENSION: FEAT_LSE2 +// ARCH-EXTENSION: FEAT_MEC +// ARCH-EXTENSION: FEAT_MPAM +// ARCH-EXTENSION: FEAT_NV, FEAT_NV2 +// ARCH-EXTENSION: FEAT_PAN +// ARCH-EXTENSION: FEAT_PAN2 +// ARCH-EXTENSION: FEAT_PAuth +// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1 +// ARCH-EXTENSION: FEAT_RDM +// ARCH-EXTENSION: FEAT_RME +// ARCH-EXTENSION: FEAT_SB +// ARCH-EXTENSION: FEAT_SEL2 +// ARCH-EXTENSION: FEAT_SPECRES +// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2 +// ARCH-EXTENSION: FEAT_SVE +// ARCH-EXTENSION: FEAT_SVE2 +// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE +// ARCH-EXTENSION: FEAT_TRBE +// ARCH-EXTENSION: FEAT_TRF +// ARCH-EXTENSION: FEAT_UAO +// ARCH-EXTENSION: FEAT_VHE +// ARCH-EXTENSION: FEAT_WFxT +// ARCH-EXTENSION: FEAT_XS diff --git a/clang/test/Driver/aarch64-v93a.c b/clang/test/Driver/aarch64-v93a.c index 817559e28ccf47..5db3034078ea80 100644 --- a/clang/test/Driver/aarch64-v93a.c +++ b/clang/test/Driver/aarch64-v93a.c @@ -13,3 +13,61 @@ // RUN: %clang --target=aarch64_be -mbig-endian -march=armv9.3a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV93A-BE %s // RUN: %clang --target=aarch64_be -mbig-endian -march=armv9.3-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV93A-BE %s // GENERICV93A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9.3a" + +// ===== Architecture extensions ===== + +// RUN: %if aarch64-registered-target %{ %clang -target aarch64 -march=armv9.3-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s %} +// ARCH-EXTENSION: FEAT_AMUv1 +// ARCH-EXTENSION: FEAT_AMUv1p1 +// ARCH-EXTENSION: FEAT_AdvSIMD +// ARCH-EXTENSION: FEAT_BF16 +// ARCH-EXTENSION: FEAT_BTI +// ARCH-EXTENSION: FEAT_CCIDX +// ARCH-EXTENSION: FEAT_CRC32 +// ARCH-EXTENSION: FEAT_CSV2_2 +// ARCH-EXTENSION: FEAT_DIT +// ARCH-EXTENSION: FEAT_DPB +// ARCH-EXTENSION: FEAT_DPB2 +// ARCH-EXTENSION: FEAT_DotProd +// ARCH-EXTENSION: FEAT_ECV +// ARCH-EXTENSION: FEAT_ETE +// ARCH-EXTENSION: FEAT_FCMA +// ARCH-EXTENSION: FEAT_FGT +// ARCH-EXTENSION: FEAT_FP +// ARCH-EXTENSION: FEAT_FP16 +// ARCH-EXTENSION: FEAT_FRINTTS +// ARCH-EXTENSION: FEAT_FlagM +// ARCH-EXTENSION: FEAT_FlagM2 +// ARCH-EXTENSION: FEAT_HBC +// ARCH-EXTENSION: FEAT_HCX +// ARCH-EXTENSION: FEAT_I8MM +// ARCH-EXTENSION: FEAT_JSCVT +// ARCH-EXTENSION: FEAT_LOR +// ARCH-EXTENSION: FEAT_LRCPC +// ARCH-EXTENSION: FEAT_LRCPC2 +// ARCH-EXTENSION: FEAT_LSE +// ARCH-EXTENSION: FEAT_LSE2 +// ARCH-EXTENSION: FEAT_MEC +// ARCH-EXTENSION: FEAT_MOPS +// ARCH-EXTENSION: FEAT_MPAM +// ARCH-EXTENSION: FEAT_NMI, FEAT_GICv3_NMI +// ARCH-EXTENSION: FEAT_NV, FEAT_NV2 +// ARCH-EXTENSION: FEAT_PAN +// ARCH-EXTENSION: FEAT_PAN2 +// ARCH-EXTENSION: FEAT_PAuth +// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1 +// ARCH-EXTENSION: FEAT_RDM +// ARCH-EXTENSION: FEAT_RME +// ARCH-EXTENSION: FEAT_SB +// ARCH-EXTENSION: FEAT_SEL2 +// ARCH-EXTENSION: FEAT_SPECRES +// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2 +// ARCH-EXTENSION: FEAT_SVE +// ARCH-EXTENSION: FEAT_SVE2 +// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE +// ARCH-EXTENSION: FEAT_TRBE +// ARCH-EXTENSION: FEAT_TRF +// ARCH-EXTENSION: FEAT_UAO +// ARCH-EXTENSION: FEAT_VHE +// ARCH-EXTENSION: FEAT_WFxT +// ARCH-EXTENSION: FEAT_XS diff --git a/clang/test/Driver/aarch64-v94a.c b/clang/test/Driver/aarch64-v94a.c index 9998cc8a4a2160..d9f991fc95d3d5 100644 --- a/clang/test/Driver/aarch64-v94a.c +++ b/clang/test/Driver/aarch64-v94a.c @@ -13,3 +13,67 @@ // RUN: %clang --target=aarch64_be -mbig-endian -march=armv9.4a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV94A-BE %s // RUN: %clang --target=aarch64_be -mbig-endian -march=armv9.4-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV94A-BE %s // GENERICV94A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9.4a" + +// ===== Architecture extensions ===== + +// RUN: %if aarch64-registered-target %{ %clang -target aarch64 -march=armv9.4-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s %} +// ARCH-EXTENSION: FEAT_AMUv1 +// ARCH-EXTENSION: FEAT_AMUv1p1 +// ARCH-EXTENSION: FEAT_AdvSIMD +// ARCH-EXTENSION: FEAT_BF16 +// ARCH-EXTENSION: FEAT_BTI +// ARCH-EXTENSION: FEAT_CCIDX +// ARCH-EXTENSION: FEAT_CHK +// ARCH-EXTENSION: FEAT_CLRBHB +// ARCH-EXTENSION: FEAT_CRC32 +// ARCH-EXTENSION: FEAT_CSSC +// ARCH-EXTENSION: FEAT_CSV2_2 +// ARCH-EXTENSION: FEAT_DIT +// ARCH-EXTENSION: FEAT_DPB +// ARCH-EXTENSION: FEAT_DPB2 +// ARCH-EXTENSION: FEAT_DotProd +// ARCH-EXTENSION: FEAT_ECV +// ARCH-EXTENSION: FEAT_ETE +// ARCH-EXTENSION: FEAT_FCMA +// ARCH-EXTENSION: FEAT_FGT +// ARCH-EXTENSION: FEAT_FP +// ARCH-EXTENSION: FEAT_FP16 +// ARCH-EXTENSION: FEAT_FRINTTS +// ARCH-EXTENSION: FEAT_FlagM +// ARCH-EXTENSION: FEAT_FlagM2 +// ARCH-EXTENSION: FEAT_HBC +// ARCH-EXTENSION: FEAT_HCX +// ARCH-EXTENSION: FEAT_I8MM +// ARCH-EXTENSION: FEAT_JSCVT +// ARCH-EXTENSION: FEAT_LOR +// ARCH-EXTENSION: FEAT_LRCPC +// ARCH-EXTENSION: FEAT_LRCPC2 +// ARCH-EXTENSION: FEAT_LSE +// ARCH-EXTENSION: FEAT_LSE2 +// ARCH-EXTENSION: FEAT_MEC +// ARCH-EXTENSION: FEAT_MOPS +// ARCH-EXTENSION: FEAT_MPAM +// ARCH-EXTENSION: FEAT_NMI, FEAT_GICv3_NMI +// ARCH-EXTENSION: FEAT_NV, FEAT_NV2 +// ARCH-EXTENSION: FEAT_PAN +// ARCH-EXTENSION: FEAT_PAN2 +// ARCH-EXTENSION: FEAT_PAuth +// ARCH-EXTENSION: FEAT_PRFMSLC +// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1 +// ARCH-EXTENSION: FEAT_RASv2 +// ARCH-EXTENSION: FEAT_RDM +// ARCH-EXTENSION: FEAT_RME +// ARCH-EXTENSION: FEAT_SB +// ARCH-EXTENSION: FEAT_SEL2 +// ARCH-EXTENSION: FEAT_SPECRES +// ARCH-EXTENSION: FEAT_SPECRES2 +// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2 +// ARCH-EXTENSION: FEAT_SVE +// ARCH-EXTENSION: FEAT_SVE2 +// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE +// ARCH-EXTENSION: FEAT_TRBE +// ARCH-EXTENSION: FEAT_TRF +// ARCH-EXTENSION: FEAT_UAO +// ARCH-EXTENSION: FEAT_VHE +// ARCH-EXTENSION: FEAT_WFxT +// ARCH-EXTENSION: FEAT_XS diff --git a/clang/test/Driver/aarch64-v95a.c b/clang/test/Driver/aarch64-v95a.c index 62878f2127626e..e3e97d2bef13f9 100644 --- a/clang/test/Driver/aarch64-v95a.c +++ b/clang/test/Driver/aarch64-v95a.c @@ -25,3 +25,70 @@ // RUN: %clang -target aarch64 -march=armv9.5a+tlbiw -### -c %s 2>&1 | FileCheck -check-prefix=V95A-TLBIW %s // RUN: %clang -target aarch64 -march=armv9.5-a+tlbiw -### -c %s 2>&1 | FileCheck -check-prefix=V95A-TLBIW %s // V95A-TLBIW: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9.5a"{{.*}} "-target-feature" "+tlbiw" + +// ===== Architecture extensions ===== + +// RUN: %if aarch64-registered-target %{ %clang -target aarch64 -march=armv9.5-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s %} +// ARCH-EXTENSION: FEAT_AMUv1 +// ARCH-EXTENSION: FEAT_AMUv1p1 +// ARCH-EXTENSION: FEAT_AdvSIMD +// ARCH-EXTENSION: FEAT_BF16 +// ARCH-EXTENSION: FEAT_BTI +// ARCH-EXTENSION: FEAT_CCIDX +// ARCH-EXTENSION: FEAT_CHK +// ARCH-EXTENSION: FEAT_CLRBHB +// ARCH-EXTENSION: FEAT_CPA +// ARCH-EXTENSION: FEAT_CRC32 +// ARCH-EXTENSION: FEAT_CSSC +// ARCH-EXTENSION: FEAT_CSV2_2 +// ARCH-EXTENSION: FEAT_DIT +// ARCH-EXTENSION: FEAT_DPB +// ARCH-EXTENSION: FEAT_DPB2 +// ARCH-EXTENSION: FEAT_DotProd +// ARCH-EXTENSION: FEAT_ECV +// ARCH-EXTENSION: FEAT_ETE +// ARCH-EXTENSION: FEAT_FAMINMAX +// ARCH-EXTENSION: FEAT_FCMA +// ARCH-EXTENSION: FEAT_FGT +// ARCH-EXTENSION: FEAT_FP +// ARCH-EXTENSION: FEAT_FP16 +// ARCH-EXTENSION: FEAT_FRINTTS +// ARCH-EXTENSION: FEAT_FlagM +// ARCH-EXTENSION: FEAT_FlagM2 +// ARCH-EXTENSION: FEAT_HBC +// ARCH-EXTENSION: FEAT_HCX +// ARCH-EXTENSION: FEAT_I8MM +// ARCH-EXTENSION: FEAT_JSCVT +// ARCH-EXTENSION: FEAT_LOR +// ARCH-EXTENSION: FEAT_LRCPC +// ARCH-EXTENSION: FEAT_LRCPC2 +// ARCH-EXTENSION: FEAT_LSE +// ARCH-EXTENSION: FEAT_LSE2 +// ARCH-EXTENSION: FEAT_LUT +// ARCH-EXTENSION: FEAT_MEC +// ARCH-EXTENSION: FEAT_MOPS +// ARCH-EXTENSION: FEAT_MPAM +// ARCH-EXTENSION: FEAT_NMI, FEAT_GICv3_NMI +// ARCH-EXTENSION: FEAT_NV, FEAT_NV2 +// ARCH-EXTENSION: FEAT_PAN +// ARCH-EXTENSION: FEAT_PAN2 +// ARCH-EXTENSION: FEAT_PAuth +// ARCH-EXTENSION: FEAT_PRFMSLC +// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1 +// ARCH-EXTENSION: FEAT_RASv2 +// ARCH-EXTENSION: FEAT_RDM +// ARCH-EXTENSION: FEAT_RME +// ARCH-EXTENSION: FEAT_SB +// ARCH-EXTENSION: FEAT_SEL2 +// ARCH-EXTENSION: FEAT_SPECRES +// ARCH-EXTENSION: FEAT_SPECRES2 +// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2 +// ARCH-EXTENSION: FEAT_SVE +// ARCH-EXTENSION: FEAT_SVE2 +// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE +// ARCH-EXTENSION: FEAT_TRBE +// ARCH-EXTENSION: FEAT_TRF +// ARCH-EXTENSION: FEAT_UAO +// ARCH-EXTENSION: FEAT_VHE +// ARCH-EXTENSION: FEAT_WFxT +// ARCH-EXTENSION: FEAT_XS diff --git a/clang/test/Driver/aarch64-v9a.c b/clang/test/Driver/aarch64-v9a.c new file mode 100644 index 00000000000000..f85e1c409010d5 --- /dev/null +++ b/clang/test/Driver/aarch64-v9a.c @@ -0,0 +1,62 @@ +// RUN: %clang --target=aarch64 -march=armv9a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A %s +// RUN: %clang --target=aarch64 -march=armv9-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A %s +// RUN: %clang --target=aarch64 -mlittle-endian -march=armv9a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A %s +// RUN: %clang --target=aarch64 -mlittle-endian -march=armv9-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A %s +// RUN: %clang --target=aarch64_be -mlittle-endian -march=armv9a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A %s +// RUN: %clang --target=aarch64_be -mlittle-endian -march=armv9-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A %s +// GENERICV9A: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9a"{{.*}} "-target-feature" "+sve" "-target-feature" "+sve2" + +// RUN: %clang --target=aarch64_be -march=armv9a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-BE %s +// RUN: %clang --target=aarch64_be -march=armv9-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-BE %s +// RUN: %clang --target=aarch64 -mbig-endian -march=armv9a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-BE %s +// RUN: %clang --target=aarch64 -mbig-endian -march=armv9-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-BE %s +// RUN: %clang --target=aarch64_be -mbig-endian -march=armv9a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-BE %s +// RUN: %clang --target=aarch64_be -mbig-endian -march=armv9-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-BE %s +// GENERICV9A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9a"{{.*}} "-target-feature" "+sve" "-target-feature" "+sve2" + +// ===== Architecture extensions ===== + +// RUN: %if aarch64-registered-target %{ %clang -target aarch64 -march=armv9-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s %} +// ARCH-EXTENSION: FEAT_AMUv1 +// ARCH-EXTENSION: FEAT_AdvSIMD +// ARCH-EXTENSION: FEAT_BTI +// ARCH-EXTENSION: FEAT_CCIDX +// ARCH-EXTENSION: FEAT_CRC32 +// ARCH-EXTENSION: FEAT_CSV2_2 +// ARCH-EXTENSION: FEAT_DIT +// ARCH-EXTENSION: FEAT_DPB +// ARCH-EXTENSION: FEAT_DPB2 +// ARCH-EXTENSION: FEAT_DotProd +// ARCH-EXTENSION: FEAT_ETE +// ARCH-EXTENSION: FEAT_FCMA +// ARCH-EXTENSION: FEAT_FP +// ARCH-EXTENSION: FEAT_FP16 +// ARCH-EXTENSION: FEAT_FRINTTS +// ARCH-EXTENSION: FEAT_FlagM +// ARCH-EXTENSION: FEAT_FlagM2 +// ARCH-EXTENSION: FEAT_JSCVT +// ARCH-EXTENSION: FEAT_LOR +// ARCH-EXTENSION: FEAT_LRCPC +// ARCH-EXTENSION: FEAT_LRCPC2 +// ARCH-EXTENSION: FEAT_LSE +// ARCH-EXTENSION: FEAT_LSE2 +// ARCH-EXTENSION: FEAT_MEC +// ARCH-EXTENSION: FEAT_MPAM +// ARCH-EXTENSION: FEAT_NV, FEAT_NV2 +// ARCH-EXTENSION: FEAT_PAN +// ARCH-EXTENSION: FEAT_PAN2 +// ARCH-EXTENSION: FEAT_PAuth +// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1 +// ARCH-EXTENSION: FEAT_RDM +// ARCH-EXTENSION: FEAT_RME +// ARCH-EXTENSION: FEAT_SB +// ARCH-EXTENSION: FEAT_SEL2 +// ARCH-EXTENSION: FEAT_SPECRES +// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2 +// ARCH-EXTENSION: FEAT_SVE +// ARCH-EXTENSION: FEAT_SVE2 +// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE +// ARCH-EXTENSION: FEAT_TRBE +// ARCH-EXTENSION: FEAT_TRF +// ARCH-EXTENSION: FEAT_UAO +// ARCH-EXTENSION: FEAT_VHE diff --git a/clang/test/Driver/cuda-arch-translation.cu b/clang/test/Driver/cuda-arch-translation.cu index ff97f2dbda6c57..e96191cc9d4183 100644 --- a/clang/test/Driver/cuda-arch-translation.cu +++ b/clang/test/Driver/cuda-arch-translation.cu @@ -59,6 +59,8 @@ // RUN: | FileCheck -check-prefixes=HIP,GFX900 %s // RUN: %clang -x hip -### --target=x86_64-linux-gnu -c --cuda-gpu-arch=gfx902 -nogpuinc -nogpulib %s 2>&1 \ // RUN: | FileCheck -check-prefixes=HIP,GFX902 %s +// RUN: %clang -x hip -### --target=x86_64-linux-gnu -c --cuda-gpu-arch=amdgcnspirv -nogpuinc -nogpulib %s 2>&1 \ +// RUN: | FileCheck -check-prefixes=HIP,SPIRV %s // CUDA: ptxas // CUDA-SAME: -m64 @@ -95,3 +97,4 @@ // GFX810:-targets=host-x86_64-unknown-linux,hipv4-amdgcn-amd-amdhsa--gfx810 // GFX900:-targets=host-x86_64-unknown-linux,hipv4-amdgcn-amd-amdhsa--gfx900 // GFX902:-targets=host-x86_64-unknown-linux,hipv4-amdgcn-amd-amdhsa--gfx902 +// SPIRV:-targets=host-x86_64-unknown-linux,hip-spirv64-amd-amdhsa--amdgcnspirv diff --git a/clang/test/Driver/print-supported-extensions.c b/clang/test/Driver/print-supported-extensions.c index 17894fc0f7ee0b..b9b16352f8295b 100644 --- a/clang/test/Driver/print-supported-extensions.c +++ b/clang/test/Driver/print-supported-extensions.c @@ -4,8 +4,8 @@ // RUN: %if aarch64-registered-target %{ %clang --target=aarch64-linux-gnu \ // RUN: --print-supported-extensions 2>&1 | FileCheck %s --check-prefix AARCH64 %} // AARCH64: All available -march extensions for AArch64 -// AARCH64: Name Description -// AARCH64: aes Enable AES support (FEAT_AES, FEAT_PMULL) +// AARCH64: Name Architecture Feature(s) Description +// AARCH64: aes FEAT_AES, FEAT_PMULL Enable AES support // RUN: %if riscv-registered-target %{ %clang --target=riscv64-linux-gnu \ // RUN: --print-supported-extensions 2>&1 | FileCheck %s --check-prefix RISCV %} diff --git a/clang/test/Driver/x86-target-features.c b/clang/test/Driver/x86-target-features.c index 3022ed1250d590..6773571556bd42 100644 --- a/clang/test/Driver/x86-target-features.c +++ b/clang/test/Driver/x86-target-features.c @@ -423,8 +423,8 @@ // RUN: %clang -target x86_64-unknown-linux-gnu -mno-apxf -mapxf %s -### -o %t.o 2>&1 | FileCheck -check-prefix=APXF %s // RUN: %clang -target x86_64-unknown-linux-gnu -mapxf -mno-apxf %s -### -o %t.o 2>&1 | FileCheck -check-prefix=NO-APXF %s // -// APXF: "-target-feature" "+egpr" "-target-feature" "+push2pop2" "-target-feature" "+ppx" "-target-feature" "+ndd" "-target-feature" "+ccmp" "-target-feature" "+nf" -// NO-APXF: "-target-feature" "-egpr" "-target-feature" "-push2pop2" "-target-feature" "-ppx" "-target-feature" "-ndd" "-target-feature" "-ccmp" "-target-feature" "-nf" +// APXF: "-target-feature" "+egpr" "-target-feature" "+push2pop2" "-target-feature" "+ppx" "-target-feature" "+ndd" "-target-feature" "+ccmp" "-target-feature" "+nf" "-target-feature" "+cf" +// NO-APXF: "-target-feature" "-egpr" "-target-feature" "-push2pop2" "-target-feature" "-ppx" "-target-feature" "-ndd" "-target-feature" "-ccmp" "-target-feature" "-nf" "-target-feature" "-cf" // RUN: %clang -target x86_64-unknown-linux-gnu -mapx-features=egpr %s -### -o %t.o 2>&1 | FileCheck -check-prefix=EGPR %s // RUN: %clang -target x86_64-unknown-linux-gnu -mapx-features=push2pop2 %s -### -o %t.o 2>&1 | FileCheck -check-prefix=PUSH2POP2 %s @@ -433,6 +433,7 @@ // RUN: %clang -target x86_64-unknown-linux-gnu -mapx-features=ccmp %s -### -o %t.o 2>&1 | FileCheck -check-prefix=CCMP %s // RUN: %clang -target x86_64-unknown-linux-gnu -mapx-features=nf %s -### -o %t.o 2>&1 | FileCheck -check-prefix=NF %s // RUN: %clang -target x86_64-unknown-linux-gnu -mapx-features=cf %s -### -o %t.o 2>&1 | FileCheck -check-prefix=CF %s +// RUN: %clang -target x86_64-unknown-linux-gnu -mapx-features=zu %s -### -o %t.o 2>&1 | FileCheck -check-prefix=ZU %s // EGPR: "-target-feature" "+egpr" // PUSH2POP2: "-target-feature" "+push2pop2" // PPX: "-target-feature" "+ppx" @@ -440,6 +441,7 @@ // CCMP: "-target-feature" "+ccmp" // NF: "-target-feature" "+nf" // CF: "-target-feature" "+cf" +// ZU: "-target-feature" "+zu" // RUN: %clang -target x86_64-unknown-linux-gnu -mapx-features=egpr,ndd %s -### -o %t.o 2>&1 | FileCheck -check-prefix=EGPR-NDD %s // RUN: %clang -target x86_64-unknown-linux-gnu -mapx-features=egpr -mapx-features=ndd %s -### -o %t.o 2>&1 | FileCheck -check-prefix=EGPR-NDD %s diff --git a/clang/test/Frontend/embed-bitcode.ll b/clang/test/Frontend/embed-bitcode.ll index 9b8632d04dd985..0959af48ad24af 100644 --- a/clang/test/Frontend/embed-bitcode.ll +++ b/clang/test/Frontend/embed-bitcode.ll @@ -10,6 +10,9 @@ ; RUN: %clang_cc1 -triple aarch64 -emit-llvm \ ; RUN: -fembed-bitcode=all -x ir %s -o - \ ; RUN: | FileCheck %s -check-prefix=CHECK-ELF +; RUN: %clang_cc1 -triple spirv64-amd-amdhsa -emit-llvm \ +; RUN: -fembed-bitcode=all -x ir %s -o - \ +; RUN: | FileCheck %s -check-prefix=CHECK-ELF ; check .bc input ; RUN: %clang_cc1 -triple thumbv7-apple-ios8.0.0 -emit-llvm-bc \ diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test index 99732694f72a5f..28df04c5e33ef4 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -201,6 +201,7 @@ // CHECK-NEXT: Uninitialized (SubjectMatchRule_variable_is_local) // CHECK-NEXT: UnsafeBufferUsage (SubjectMatchRule_function) // CHECK-NEXT: UseHandle (SubjectMatchRule_variable_is_parameter) +// CHECK-NEXT: VTablePointerAuthentication (SubjectMatchRule_record) // CHECK-NEXT: VecReturn (SubjectMatchRule_record) // CHECK-NEXT: VecTypeHint (SubjectMatchRule_function) // CHECK-NEXT: WarnUnused (SubjectMatchRule_record) diff --git a/clang/test/Misc/target-invalid-cpu-note.c b/clang/test/Misc/target-invalid-cpu-note.c index 1a9063ee5a2574..a5f9ffa21220a9 100644 --- a/clang/test/Misc/target-invalid-cpu-note.c +++ b/clang/test/Misc/target-invalid-cpu-note.c @@ -5,11 +5,11 @@ // RUN: not %clang_cc1 -triple arm64--- -target-cpu not-a-cpu -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix AARCH64 // AARCH64: error: unknown target CPU 'not-a-cpu' -// AARCH64-NEXT: note: valid target CPU values are: generic, cortex-a35, cortex-a34, cortex-a53, cortex-a55, cortex-a510, cortex-a520, cortex-a520ae, cortex-a57, cortex-a65, cortex-a65ae, cortex-a72, cortex-a73, cortex-a75, cortex-a76, cortex-a76ae, cortex-a77, cortex-a78, cortex-a78ae, cortex-a78c, cortex-a710, cortex-a715, cortex-a720, cortex-a720ae, cortex-a725, cortex-r82, cortex-r82ae, cortex-x1, cortex-x1c, cortex-x2, cortex-x3, cortex-x4, cortex-x925, neoverse-e1, neoverse-n1, neoverse-n2, neoverse-n3, neoverse-512tvb, neoverse-v1, neoverse-v2, neoverse-v3, neoverse-v3ae, exynos-m3, exynos-m4, exynos-m5, falkor, saphira, kryo, thunderx, thunderxt88, thunderxt81, thunderxt83, thunderx2t99, thunderx3t110, tsv110, cyclone, apple-a7, apple-a8, apple-a9, apple-a10, apple-a11, apple-a12, apple-s4, apple-s5, apple-a13, apple-a14, apple-m1, apple-a15, apple-m2, apple-a16, apple-m3, apple-a17, apple-m4, a64fx, carmel, ampere1, ampere1a, ampere1b, oryon-1, cobalt-100, grace{{$}} +// AARCH64-NEXT: note: valid target CPU values are: a64fx, ampere1, ampere1a, ampere1b, apple-a10, apple-a11, apple-a12, apple-a13, apple-a14, apple-a15, apple-a16, apple-a17, apple-a7, apple-a8, apple-a9, apple-m1, apple-m2, apple-m3, apple-m4, apple-s4, apple-s5, carmel, cobalt-100, cortex-a34, cortex-a35, cortex-a510, cortex-a520, cortex-a520ae, cortex-a53, cortex-a55, cortex-a57, cortex-a65, cortex-a65ae, cortex-a710, cortex-a715, cortex-a72, cortex-a720, cortex-a720ae, cortex-a725, cortex-a73, cortex-a75, cortex-a76, cortex-a76ae, cortex-a77, cortex-a78, cortex-a78ae, cortex-a78c, cortex-r82, cortex-r82ae, cortex-x1, cortex-x1c, cortex-x2, cortex-x3, cortex-x4, cortex-x925, cyclone, exynos-m3, exynos-m4, exynos-m5, falkor, generic, grace, kryo, neoverse-512tvb, neoverse-e1, neoverse-n1, neoverse-n2, neoverse-n3, neoverse-v1, neoverse-v2, neoverse-v3, neoverse-v3ae, oryon-1, saphira, thunderx, thunderx2t99, thunderx3t110, thunderxt81, thunderxt83, thunderxt88, tsv110{{$}} // RUN: not %clang_cc1 -triple arm64--- -tune-cpu not-a-cpu -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix TUNE_AARCH64 // TUNE_AARCH64: error: unknown target CPU 'not-a-cpu' -// TUNE_AARCH64-NEXT: note: valid target CPU values are: generic, cortex-a35, cortex-a34, cortex-a53, cortex-a55, cortex-a510, cortex-a520, cortex-a520ae, cortex-a57, cortex-a65, cortex-a65ae, cortex-a72, cortex-a73, cortex-a75, cortex-a76, cortex-a76ae, cortex-a77, cortex-a78, cortex-a78ae, cortex-a78c, cortex-a710, cortex-a715, cortex-a720, cortex-a720ae, cortex-a725, cortex-r82, cortex-r82ae, cortex-x1, cortex-x1c, cortex-x2, cortex-x3, cortex-x4, cortex-x925, neoverse-e1, neoverse-n1, neoverse-n2, neoverse-n3, neoverse-512tvb, neoverse-v1, neoverse-v2, neoverse-v3, neoverse-v3ae, exynos-m3, exynos-m4, exynos-m5, falkor, saphira, kryo, thunderx, thunderxt88, thunderxt81, thunderxt83, thunderx2t99, thunderx3t110, tsv110, cyclone, apple-a7, apple-a8, apple-a9, apple-a10, apple-a11, apple-a12, apple-s4, apple-s5, apple-a13, apple-a14, apple-m1, apple-a15, apple-m2, apple-a16, apple-m3, apple-a17, apple-m4, a64fx, carmel, ampere1, ampere1a, ampere1b, oryon-1, cobalt-100, grace{{$}} +// TUNE_AARCH64-NEXT: note: valid target CPU values are: a64fx, ampere1, ampere1a, ampere1b, apple-a10, apple-a11, apple-a12, apple-a13, apple-a14, apple-a15, apple-a16, apple-a17, apple-a7, apple-a8, apple-a9, apple-m1, apple-m2, apple-m3, apple-m4, apple-s4, apple-s5, carmel, cobalt-100, cortex-a34, cortex-a35, cortex-a510, cortex-a520, cortex-a520ae, cortex-a53, cortex-a55, cortex-a57, cortex-a65, cortex-a65ae, cortex-a710, cortex-a715, cortex-a72, cortex-a720, cortex-a720ae, cortex-a725, cortex-a73, cortex-a75, cortex-a76, cortex-a76ae, cortex-a77, cortex-a78, cortex-a78ae, cortex-a78c, cortex-r82, cortex-r82ae, cortex-x1, cortex-x1c, cortex-x2, cortex-x3, cortex-x4, cortex-x925, cyclone, exynos-m3, exynos-m4, exynos-m5, falkor, generic, grace, kryo, neoverse-512tvb, neoverse-e1, neoverse-n1, neoverse-n2, neoverse-n3, neoverse-v1, neoverse-v2, neoverse-v3, neoverse-v3ae, oryon-1, saphira, thunderx, thunderx2t99, thunderx3t110, thunderxt81, thunderxt83, thunderxt88, tsv110{{$}} // RUN: not %clang_cc1 -triple i386--- -target-cpu not-a-cpu -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix X86 // X86: error: unknown target CPU 'not-a-cpu' @@ -29,7 +29,7 @@ // RUN: not %clang_cc1 -triple nvptx--- -target-cpu not-a-cpu -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix NVPTX // NVPTX: error: unknown target CPU 'not-a-cpu' -// NVPTX-NEXT: note: valid target CPU values are: sm_20, sm_21, sm_30, sm_32, sm_35, sm_37, sm_50, sm_52, sm_53, sm_60, sm_61, sm_62, sm_70, sm_72, sm_75, sm_80, sm_86, sm_87, sm_89, sm_90, sm_90a, gfx600, gfx601, gfx602, gfx700, gfx701, gfx702, gfx703, gfx704, gfx705, gfx801, gfx802, gfx803, gfx805, gfx810, gfx9-generic, gfx900, gfx902, gfx904, gfx906, gfx908, gfx909, gfx90a, gfx90c, gfx940, gfx941, gfx942, gfx10-1-generic, gfx1010, gfx1011, gfx1012, gfx1013, gfx10-3-generic, gfx1030, gfx1031, gfx1032, gfx1033, gfx1034, gfx1035, gfx1036, gfx11-generic, gfx1100, gfx1101, gfx1102, gfx1103, gfx1150, gfx1151, gfx1152, gfx12-generic, gfx1200, gfx1201{{$}} +// NVPTX-NEXT: note: valid target CPU values are: sm_20, sm_21, sm_30, sm_32, sm_35, sm_37, sm_50, sm_52, sm_53, sm_60, sm_61, sm_62, sm_70, sm_72, sm_75, sm_80, sm_86, sm_87, sm_89, sm_90, sm_90a, gfx600, gfx601, gfx602, gfx700, gfx701, gfx702, gfx703, gfx704, gfx705, gfx801, gfx802, gfx803, gfx805, gfx810, gfx9-generic, gfx900, gfx902, gfx904, gfx906, gfx908, gfx909, gfx90a, gfx90c, gfx940, gfx941, gfx942, gfx10-1-generic, gfx1010, gfx1011, gfx1012, gfx1013, gfx10-3-generic, gfx1030, gfx1031, gfx1032, gfx1033, gfx1034, gfx1035, gfx1036, gfx11-generic, gfx1100, gfx1101, gfx1102, gfx1103, gfx1150, gfx1151, gfx1152, gfx12-generic, gfx1200, gfx1201, amdgcnspirv{{$}} // RUN: not %clang_cc1 -triple r600--- -target-cpu not-a-cpu -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix R600 // R600: error: unknown target CPU 'not-a-cpu' diff --git a/clang/test/Misc/warning-flags.c b/clang/test/Misc/warning-flags.c index dd73331913c6f6..ae14720959a0ef 100644 --- a/clang/test/Misc/warning-flags.c +++ b/clang/test/Misc/warning-flags.c @@ -18,10 +18,9 @@ This test serves two purposes: The list of warnings below should NEVER grow. It should gradually shrink to 0. -CHECK: Warnings without flags (66): +CHECK: Warnings without flags (65): CHECK-NEXT: ext_expected_semi_decl_list -CHECK-NEXT: ext_explicit_specialization_storage_class CHECK-NEXT: ext_missing_whitespace_after_macro_name CHECK-NEXT: ext_new_paren_array_nonconst CHECK-NEXT: ext_plain_complex diff --git a/clang/test/Modules/forward-friend.cppm b/clang/test/Modules/forward-friend.cppm new file mode 100644 index 00000000000000..dfadf4fcc1dae9 --- /dev/null +++ b/clang/test/Modules/forward-friend.cppm @@ -0,0 +1,22 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: cd %t +// +// RUN: %clang_cc1 -std=c++20 %t/m.cppm -fsyntax-only -verify + +//--- foo.h + +template +static void foo(U...) noexcept; + +class A { + template + friend void foo(U...) noexcept; +}; + +//--- m.cppm +// expected-no-diagnostics +module; +#include "foo.h" +export module m; +export using ::A; diff --git a/clang/test/Modules/no-eager-load.cppm b/clang/test/Modules/no-eager-load.cppm index 8a2c7656bca2b4..c9eddaaed15552 100644 --- a/clang/test/Modules/no-eager-load.cppm +++ b/clang/test/Modules/no-eager-load.cppm @@ -44,6 +44,9 @@ void use() { // expected-note@* {{but in 'a' found a different body}} } +// expected-error@a.cppm:* {{declaration 'foo' attached to named module 'a' can't be attached to other modules}} +// expected-note@b.cppm:* {{}} + //--- h.cppm export module h; export import a; @@ -55,3 +58,6 @@ void use() { foo(); // expected-error@* {{'foo' has different definitions in different modules;}} // expected-note@* {{but in 'a' found a different body}} } + +// expected-error@a.cppm:* {{declaration 'foo' attached to named module 'a' can't be attached to other modules}} +// expected-note@b.cppm:* {{}} diff --git a/clang/test/Modules/no-external-identifier-id.cppm b/clang/test/Modules/no-external-identifier-id.cppm new file mode 100644 index 00000000000000..25825ef67ad91f --- /dev/null +++ b/clang/test/Modules/no-external-identifier-id.cppm @@ -0,0 +1,37 @@ +// Testing that we won't record the identifier ID from external modules. +// +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: cd %t +// +// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-module-interface -o %t/a.pcm +// RUN: %clang_cc1 -std=c++20 %t/b.cppm -emit-module-interface -o %t/b.pcm \ +// RUN: -fmodule-file=a=%t/a.pcm +// RUN: llvm-bcanalyzer --dump --disable-histogram %t/b.pcm | FileCheck %t/b.cppm +// +// RUN: %clang_cc1 -std=c++20 %t/a.v1.cppm -emit-module-interface -o %t/a.v1.pcm +// RUN: %clang_cc1 -std=c++20 %t/b.cppm -emit-module-interface -o %t/b.v1.pcm \ +// RUN: -fmodule-file=a=%t/a.v1.pcm +// RUN: diff %t/b.pcm %t/b.v1.pcm &> /dev/null + +//--- a.cppm +export module a; +export inline int a() { + int foo = 43; + return foo; +} + +//--- b.cppm +export module b; +import a; +export inline int b() { + int foo = 43; + return foo; +} + +// CHECK: /dev/null + +//--- a.cppm +export module a; +export int a(); + +//--- b.cppm +export module b; +import a; +export int b(); + +// CHECK: diff --git a/clang/test/Modules/no-transitive-decl-change-2.cppm b/clang/test/Modules/no-transitive-decl-change-2.cppm new file mode 100644 index 00000000000000..fe29d9169201d6 --- /dev/null +++ b/clang/test/Modules/no-transitive-decl-change-2.cppm @@ -0,0 +1,28 @@ +// Test that adding a new unused decl within reduced BMI may not produce a transitive change. +// +// RUN: rm -rf %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 -emit-reduced-module-interface %t/A.cppm -o %t/A.pcm +// RUN: %clang_cc1 -std=c++20 -emit-reduced-module-interface %t/B.cppm -o %t/B.pcm \ +// RUN: -fmodule-file=A=%t/A.pcm +// +// RUN: %clang_cc1 -std=c++20 -emit-reduced-module-interface %t/A.v1.cppm -o %t/A.v1.pcm +// RUN: %clang_cc1 -std=c++20 -emit-reduced-module-interface %t/B.cppm -o %t/B.v1.pcm \ +// RUN: -fmodule-file=A=%t/A.v1.pcm +// +// RUN: diff %t/B.pcm %t/B.v1.pcm &> /dev/null + +//--- A.cppm +export module A; +export int a() { return 44; } + +//--- A.v1.cppm +export module A; +int a_impl() { return 48; } +export int a() { return a_impl(); } + +//--- B.cppm +export module B; +import A; +export int b() { return a(); } diff --git a/clang/test/Modules/same-decl-in-different-modules.cppm b/clang/test/Modules/same-decl-in-different-modules.cppm new file mode 100644 index 00000000000000..2e8e90f7cd8e95 --- /dev/null +++ b/clang/test/Modules/same-decl-in-different-modules.cppm @@ -0,0 +1,42 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 %t/mod1.cppm -emit-module-interface -o %t/mod1.pcm +// RUN: %clang_cc1 -std=c++20 %t/mod2.cppm -emit-module-interface -o %t/mod2.pcm +// RUN: %clang_cc1 -std=c++20 %t/test.cc -fprebuilt-module-path=%t -fsyntax-only -verify + +//--- mod1.cppm +export module mod1; +export int v; +export void func(); +export class A {}; +export template +struct S {}; + +//--- mod2.cppm +export module mod2; +export int v; +export void func(); +export class A; +export template +struct S {}; + +//--- test.cc +import mod1; +import mod2; +void test() { + int value = v; + func(); + A a; + S s; +} + +// expected-error@mod1.cppm:* {{declaration 'v' attached to named module 'mod1' can't be attached to other modules}} +// expected-note@mod2.cppm:* {{}} +// expected-error@mod1.cppm:* {{declaration 'func' attached to named module 'mod1' can't be attached to other modules}} +// expected-note@mod2.cppm:* {{}} +// expected-error@mod1.cppm:* {{declaration 'A' attached to named module 'mod1' can't be attached to other modules}} +// expected-note@mod2.cppm:* {{}} +// expected-error@mod1.cppm:* 1+{{declaration 'S' attached to named module 'mod1' can't be attached to other modules}} +// expected-note@mod2.cppm:* 1+{{}} diff --git a/clang/test/OpenMP/Inputs/nesting_of_regions.cpp b/clang/test/OpenMP/Inputs/nesting_of_regions.cpp index e671f9b0cf4123..969ddfcce4cb0e 100644 --- a/clang/test/OpenMP/Inputs/nesting_of_regions.cpp +++ b/clang/test/OpenMP/Inputs/nesting_of_regions.cpp @@ -4880,6 +4880,12 @@ void foo() { #pragma omp teams // expected-note {{nested teams construct here}} ++a; } +#pragma omp target // expected-error {{target construct with nested teams region contains statements outside of the teams construct}} + { +#pragma omp teams // expected-note {{nested teams construct here}} + ++a; + ++a; // expected-note {{statement outside teams construct here}} + } #pragma omp target // expected-error {{target construct with nested teams region contains statements outside of the teams construct}} { while (0) // expected-note {{statement outside teams construct here}} @@ -14133,6 +14139,12 @@ void foo() { #pragma omp teams // expected-note {{nested teams construct here}} ++a; } +#pragma omp target // expected-error {{target construct with nested teams region contains statements outside of the teams construct}} + { +#pragma omp teams // expected-note {{nested teams construct here}} + ++a; + ++a; // expected-note {{statement outside teams construct here}} + } #pragma omp target { #pragma omp taskloop diff --git a/clang/test/OpenMP/declare_variant_clauses_messages.cpp b/clang/test/OpenMP/declare_variant_clauses_messages.cpp index 2a9e5385c9ca64..284e49bbd21b4c 100644 --- a/clang/test/OpenMP/declare_variant_clauses_messages.cpp +++ b/clang/test/OpenMP/declare_variant_clauses_messages.cpp @@ -186,6 +186,16 @@ void vararg_bar2(const char *fmt) { return; } // expected-error@+1 {{variant in '#pragma omp declare variant' with type 'void (float *, float *, int *, omp_interop_t)' (aka 'void (float *, float *, int *, void *)') is incompatible with type 'void (float *, float *, int *)'}} #pragma omp declare variant(foo_v4) match(construct={dispatch}) +// expected-error@+3 {{incorrect adjust_args type, expected 'need_device_ptr' or 'nothing'}} +#pragma omp declare variant(foo_v1) \ + match(construct={dispatch}, device={arch(arm)}) \ + adjust_args(badaaop:AAA,BBB) + +// expected-error@+3 {{incorrect adjust_args type, expected 'need_device_ptr' or 'nothing'}} +#pragma omp declare variant(foo_v1) \ + match(construct={dispatch}, device={arch(arm)}) \ + adjust_args(badaaop AAA,BBB) + #endif // _OPENMP >= 202011 #if _OPENMP < 202011 // OpenMP 5.0 or lower // expected-error@+2 {{expected 'match' clause on 'omp declare variant' directive}} diff --git a/clang/test/OpenMP/nvptx_target_parallel_reduction_codegen.cpp b/clang/test/OpenMP/nvptx_target_parallel_reduction_codegen.cpp index c077b58f614fa1..0753573c73bce8 100644 --- a/clang/test/OpenMP/nvptx_target_parallel_reduction_codegen.cpp +++ b/clang/test/OpenMP/nvptx_target_parallel_reduction_codegen.cpp @@ -223,7 +223,6 @@ int bar(int n){ // CHECK-64-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8 // CHECK-64-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 // CHECK-64-NEXT: [[DOTCNT_ADDR:%.*]] = alloca i32, align 4 -// CHECK-64-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-64-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK-64-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK-64-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() @@ -239,6 +238,7 @@ int bar(int n){ // CHECK-64-NEXT: [[TMP8:%.*]] = icmp ult i32 [[TMP7]], 2 // CHECK-64-NEXT: br i1 [[TMP8]], label [[BODY:%.*]], label [[EXIT:%.*]] // CHECK-64: body: +// CHECK-64-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-64-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2:[0-9]+]], i32 [[TMP2]]) // CHECK-64-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK-64-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] @@ -253,11 +253,12 @@ int bar(int n){ // CHECK-64: else: // CHECK-64-NEXT: br label [[IFCONT]] // CHECK-64: ifcont: +// CHECK-64-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-64-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-64-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK-64-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP14]] // CHECK-64-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// CHECK-64: then2: +// CHECK-64: then3: // CHECK-64-NEXT: [[TMP15:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK-64-NEXT: [[TMP16:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP6]], i64 0, i64 0 // CHECK-64-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 8 @@ -265,9 +266,9 @@ int bar(int n){ // CHECK-64-NEXT: [[TMP19:%.*]] = load volatile i32, ptr addrspace(3) [[TMP15]], align 4 // CHECK-64-NEXT: store i32 [[TMP19]], ptr [[TMP18]], align 4 // CHECK-64-NEXT: br label [[IFCONT4:%.*]] -// CHECK-64: else3: +// CHECK-64: else4: // CHECK-64-NEXT: br label [[IFCONT4]] -// CHECK-64: ifcont4: +// CHECK-64: ifcont5: // CHECK-64-NEXT: [[TMP20:%.*]] = add nsw i32 [[TMP7]], 1 // CHECK-64-NEXT: store i32 [[TMP20]], ptr [[DOTCNT_ADDR]], align 4 // CHECK-64-NEXT: br label [[PRECOND]] @@ -445,7 +446,6 @@ int bar(int n){ // CHECK-64-NEXT: entry: // CHECK-64-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8 // CHECK-64-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 -// CHECK-64-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-64-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK-64-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK-64-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() @@ -454,6 +454,7 @@ int bar(int n){ // CHECK-64-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() // CHECK-64-NEXT: [[NVPTX_WARP_ID:%.*]] = ashr i32 [[TMP5]], 5 // CHECK-64-NEXT: [[TMP6:%.*]] = load ptr, ptr [[DOTADDR]], align 8 +// CHECK-64-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-64-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-64-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK-64-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] @@ -467,47 +468,50 @@ int bar(int n){ // CHECK-64: else: // CHECK-64-NEXT: br label [[IFCONT]] // CHECK-64: ifcont: +// CHECK-64-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-64-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-64-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK-64-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP11]] // CHECK-64-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// CHECK-64: then2: +// CHECK-64: then3: // CHECK-64-NEXT: [[TMP12:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK-64-NEXT: [[TMP13:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i64 0, i64 0 // CHECK-64-NEXT: [[TMP14:%.*]] = load ptr, ptr [[TMP13]], align 8 // CHECK-64-NEXT: [[TMP15:%.*]] = load volatile i8, ptr addrspace(3) [[TMP12]], align 1 // CHECK-64-NEXT: store i8 [[TMP15]], ptr [[TMP14]], align 1 // CHECK-64-NEXT: br label [[IFCONT4:%.*]] -// CHECK-64: else3: +// CHECK-64: else4: // CHECK-64-NEXT: br label [[IFCONT4]] -// CHECK-64: ifcont4: +// CHECK-64: ifcont5: +// CHECK-64-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-64-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-64-NEXT: [[WARP_MASTER5:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK-64-NEXT: br i1 [[WARP_MASTER5]], label [[THEN6:%.*]], label [[ELSE7:%.*]] -// CHECK-64: then6: +// CHECK-64: then8: // CHECK-64-NEXT: [[TMP16:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i64 0, i64 1 // CHECK-64-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 8 // CHECK-64-NEXT: [[TMP18:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[NVPTX_WARP_ID]] // CHECK-64-NEXT: [[TMP19:%.*]] = load i32, ptr [[TMP17]], align 4 // CHECK-64-NEXT: store volatile i32 [[TMP19]], ptr addrspace(3) [[TMP18]], align 4 // CHECK-64-NEXT: br label [[IFCONT8:%.*]] -// CHECK-64: else7: +// CHECK-64: else9: // CHECK-64-NEXT: br label [[IFCONT8]] -// CHECK-64: ifcont8: +// CHECK-64: ifcont10: +// CHECK-64-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-64-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-64-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK-64-NEXT: [[IS_ACTIVE_THREAD9:%.*]] = icmp ult i32 [[TMP3]], [[TMP20]] // CHECK-64-NEXT: br i1 [[IS_ACTIVE_THREAD9]], label [[THEN10:%.*]], label [[ELSE11:%.*]] -// CHECK-64: then10: +// CHECK-64: then13: // CHECK-64-NEXT: [[TMP21:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK-64-NEXT: [[TMP22:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i64 0, i64 1 // CHECK-64-NEXT: [[TMP23:%.*]] = load ptr, ptr [[TMP22]], align 8 // CHECK-64-NEXT: [[TMP24:%.*]] = load volatile i32, ptr addrspace(3) [[TMP21]], align 4 // CHECK-64-NEXT: store i32 [[TMP24]], ptr [[TMP23]], align 4 // CHECK-64-NEXT: br label [[IFCONT12:%.*]] -// CHECK-64: else11: +// CHECK-64: else14: // CHECK-64-NEXT: br label [[IFCONT12]] -// CHECK-64: ifcont12: +// CHECK-64: ifcont15: // CHECK-64-NEXT: ret void // // @@ -698,7 +702,6 @@ int bar(int n){ // CHECK-64-NEXT: entry: // CHECK-64-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8 // CHECK-64-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 -// CHECK-64-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-64-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK-64-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK-64-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() @@ -707,6 +710,7 @@ int bar(int n){ // CHECK-64-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() // CHECK-64-NEXT: [[NVPTX_WARP_ID:%.*]] = ashr i32 [[TMP5]], 5 // CHECK-64-NEXT: [[TMP6:%.*]] = load ptr, ptr [[DOTADDR]], align 8 +// CHECK-64-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-64-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-64-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK-64-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] @@ -720,47 +724,50 @@ int bar(int n){ // CHECK-64: else: // CHECK-64-NEXT: br label [[IFCONT]] // CHECK-64: ifcont: +// CHECK-64-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-64-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-64-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK-64-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP11]] // CHECK-64-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// CHECK-64: then2: +// CHECK-64: then3: // CHECK-64-NEXT: [[TMP12:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK-64-NEXT: [[TMP13:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i64 0, i64 0 // CHECK-64-NEXT: [[TMP14:%.*]] = load ptr, ptr [[TMP13]], align 8 // CHECK-64-NEXT: [[TMP15:%.*]] = load volatile i32, ptr addrspace(3) [[TMP12]], align 4 // CHECK-64-NEXT: store i32 [[TMP15]], ptr [[TMP14]], align 4 // CHECK-64-NEXT: br label [[IFCONT4:%.*]] -// CHECK-64: else3: +// CHECK-64: else4: // CHECK-64-NEXT: br label [[IFCONT4]] -// CHECK-64: ifcont4: +// CHECK-64: ifcont5: +// CHECK-64-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-64-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-64-NEXT: [[WARP_MASTER5:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK-64-NEXT: br i1 [[WARP_MASTER5]], label [[THEN6:%.*]], label [[ELSE7:%.*]] -// CHECK-64: then6: +// CHECK-64: then8: // CHECK-64-NEXT: [[TMP16:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i64 0, i64 1 // CHECK-64-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 8 // CHECK-64-NEXT: [[TMP18:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[NVPTX_WARP_ID]] // CHECK-64-NEXT: [[TMP19:%.*]] = load i16, ptr [[TMP17]], align 2 // CHECK-64-NEXT: store volatile i16 [[TMP19]], ptr addrspace(3) [[TMP18]], align 2 // CHECK-64-NEXT: br label [[IFCONT8:%.*]] -// CHECK-64: else7: +// CHECK-64: else9: // CHECK-64-NEXT: br label [[IFCONT8]] -// CHECK-64: ifcont8: +// CHECK-64: ifcont10: +// CHECK-64-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-64-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-64-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK-64-NEXT: [[IS_ACTIVE_THREAD9:%.*]] = icmp ult i32 [[TMP3]], [[TMP20]] // CHECK-64-NEXT: br i1 [[IS_ACTIVE_THREAD9]], label [[THEN10:%.*]], label [[ELSE11:%.*]] -// CHECK-64: then10: +// CHECK-64: then13: // CHECK-64-NEXT: [[TMP21:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK-64-NEXT: [[TMP22:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i64 0, i64 1 // CHECK-64-NEXT: [[TMP23:%.*]] = load ptr, ptr [[TMP22]], align 8 // CHECK-64-NEXT: [[TMP24:%.*]] = load volatile i16, ptr addrspace(3) [[TMP21]], align 2 // CHECK-64-NEXT: store i16 [[TMP24]], ptr [[TMP23]], align 2 // CHECK-64-NEXT: br label [[IFCONT12:%.*]] -// CHECK-64: else11: +// CHECK-64: else14: // CHECK-64-NEXT: br label [[IFCONT12]] -// CHECK-64: ifcont12: +// CHECK-64: ifcont15: // CHECK-64-NEXT: ret void // // @@ -890,7 +897,6 @@ int bar(int n){ // CHECK-32-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 4 // CHECK-32-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 // CHECK-32-NEXT: [[DOTCNT_ADDR:%.*]] = alloca i32, align 4 -// CHECK-32-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 4 // CHECK-32-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK-32-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() @@ -906,6 +912,7 @@ int bar(int n){ // CHECK-32-NEXT: [[TMP8:%.*]] = icmp ult i32 [[TMP7]], 2 // CHECK-32-NEXT: br i1 [[TMP8]], label [[BODY:%.*]], label [[EXIT:%.*]] // CHECK-32: body: +// CHECK-32-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2:[0-9]+]], i32 [[TMP2]]) // CHECK-32-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK-32-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] @@ -920,11 +927,12 @@ int bar(int n){ // CHECK-32: else: // CHECK-32-NEXT: br label [[IFCONT]] // CHECK-32: ifcont: +// CHECK-32-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-32-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK-32-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP14]] // CHECK-32-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// CHECK-32: then2: +// CHECK-32: then3: // CHECK-32-NEXT: [[TMP15:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK-32-NEXT: [[TMP16:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP6]], i32 0, i32 0 // CHECK-32-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 4 @@ -932,9 +940,9 @@ int bar(int n){ // CHECK-32-NEXT: [[TMP19:%.*]] = load volatile i32, ptr addrspace(3) [[TMP15]], align 4 // CHECK-32-NEXT: store i32 [[TMP19]], ptr [[TMP18]], align 4 // CHECK-32-NEXT: br label [[IFCONT4:%.*]] -// CHECK-32: else3: +// CHECK-32: else4: // CHECK-32-NEXT: br label [[IFCONT4]] -// CHECK-32: ifcont4: +// CHECK-32: ifcont5: // CHECK-32-NEXT: [[TMP20:%.*]] = add nsw i32 [[TMP7]], 1 // CHECK-32-NEXT: store i32 [[TMP20]], ptr [[DOTCNT_ADDR]], align 4 // CHECK-32-NEXT: br label [[PRECOND]] @@ -1112,7 +1120,6 @@ int bar(int n){ // CHECK-32-NEXT: entry: // CHECK-32-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 4 // CHECK-32-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 -// CHECK-32-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 4 // CHECK-32-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK-32-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() @@ -1121,6 +1128,7 @@ int bar(int n){ // CHECK-32-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() // CHECK-32-NEXT: [[NVPTX_WARP_ID:%.*]] = ashr i32 [[TMP5]], 5 // CHECK-32-NEXT: [[TMP6:%.*]] = load ptr, ptr [[DOTADDR]], align 4 +// CHECK-32-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-32-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK-32-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] @@ -1134,47 +1142,50 @@ int bar(int n){ // CHECK-32: else: // CHECK-32-NEXT: br label [[IFCONT]] // CHECK-32: ifcont: +// CHECK-32-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-32-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK-32-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP11]] // CHECK-32-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// CHECK-32: then2: +// CHECK-32: then3: // CHECK-32-NEXT: [[TMP12:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK-32-NEXT: [[TMP13:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 0 // CHECK-32-NEXT: [[TMP14:%.*]] = load ptr, ptr [[TMP13]], align 4 // CHECK-32-NEXT: [[TMP15:%.*]] = load volatile i8, ptr addrspace(3) [[TMP12]], align 1 // CHECK-32-NEXT: store i8 [[TMP15]], ptr [[TMP14]], align 1 // CHECK-32-NEXT: br label [[IFCONT4:%.*]] -// CHECK-32: else3: +// CHECK-32: else4: // CHECK-32-NEXT: br label [[IFCONT4]] -// CHECK-32: ifcont4: +// CHECK-32: ifcont5: +// CHECK-32-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-32-NEXT: [[WARP_MASTER5:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK-32-NEXT: br i1 [[WARP_MASTER5]], label [[THEN6:%.*]], label [[ELSE7:%.*]] -// CHECK-32: then6: +// CHECK-32: then8: // CHECK-32-NEXT: [[TMP16:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 1 // CHECK-32-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 4 // CHECK-32-NEXT: [[TMP18:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[NVPTX_WARP_ID]] // CHECK-32-NEXT: [[TMP19:%.*]] = load i32, ptr [[TMP17]], align 4 // CHECK-32-NEXT: store volatile i32 [[TMP19]], ptr addrspace(3) [[TMP18]], align 4 // CHECK-32-NEXT: br label [[IFCONT8:%.*]] -// CHECK-32: else7: +// CHECK-32: else9: // CHECK-32-NEXT: br label [[IFCONT8]] -// CHECK-32: ifcont8: +// CHECK-32: ifcont10: +// CHECK-32-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-32-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK-32-NEXT: [[IS_ACTIVE_THREAD9:%.*]] = icmp ult i32 [[TMP3]], [[TMP20]] // CHECK-32-NEXT: br i1 [[IS_ACTIVE_THREAD9]], label [[THEN10:%.*]], label [[ELSE11:%.*]] -// CHECK-32: then10: +// CHECK-32: then13: // CHECK-32-NEXT: [[TMP21:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK-32-NEXT: [[TMP22:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 1 // CHECK-32-NEXT: [[TMP23:%.*]] = load ptr, ptr [[TMP22]], align 4 // CHECK-32-NEXT: [[TMP24:%.*]] = load volatile i32, ptr addrspace(3) [[TMP21]], align 4 // CHECK-32-NEXT: store i32 [[TMP24]], ptr [[TMP23]], align 4 // CHECK-32-NEXT: br label [[IFCONT12:%.*]] -// CHECK-32: else11: +// CHECK-32: else14: // CHECK-32-NEXT: br label [[IFCONT12]] -// CHECK-32: ifcont12: +// CHECK-32: ifcont15: // CHECK-32-NEXT: ret void // // @@ -1365,7 +1376,6 @@ int bar(int n){ // CHECK-32-NEXT: entry: // CHECK-32-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 4 // CHECK-32-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 -// CHECK-32-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 4 // CHECK-32-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK-32-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() @@ -1374,6 +1384,7 @@ int bar(int n){ // CHECK-32-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() // CHECK-32-NEXT: [[NVPTX_WARP_ID:%.*]] = ashr i32 [[TMP5]], 5 // CHECK-32-NEXT: [[TMP6:%.*]] = load ptr, ptr [[DOTADDR]], align 4 +// CHECK-32-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-32-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK-32-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] @@ -1387,47 +1398,50 @@ int bar(int n){ // CHECK-32: else: // CHECK-32-NEXT: br label [[IFCONT]] // CHECK-32: ifcont: +// CHECK-32-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-32-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK-32-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP11]] // CHECK-32-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// CHECK-32: then2: +// CHECK-32: then3: // CHECK-32-NEXT: [[TMP12:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK-32-NEXT: [[TMP13:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 0 // CHECK-32-NEXT: [[TMP14:%.*]] = load ptr, ptr [[TMP13]], align 4 // CHECK-32-NEXT: [[TMP15:%.*]] = load volatile i32, ptr addrspace(3) [[TMP12]], align 4 // CHECK-32-NEXT: store i32 [[TMP15]], ptr [[TMP14]], align 4 // CHECK-32-NEXT: br label [[IFCONT4:%.*]] -// CHECK-32: else3: +// CHECK-32: else4: // CHECK-32-NEXT: br label [[IFCONT4]] -// CHECK-32: ifcont4: +// CHECK-32: ifcont5: +// CHECK-32-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-32-NEXT: [[WARP_MASTER5:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK-32-NEXT: br i1 [[WARP_MASTER5]], label [[THEN6:%.*]], label [[ELSE7:%.*]] -// CHECK-32: then6: +// CHECK-32: then8: // CHECK-32-NEXT: [[TMP16:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 1 // CHECK-32-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 4 // CHECK-32-NEXT: [[TMP18:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[NVPTX_WARP_ID]] // CHECK-32-NEXT: [[TMP19:%.*]] = load i16, ptr [[TMP17]], align 2 // CHECK-32-NEXT: store volatile i16 [[TMP19]], ptr addrspace(3) [[TMP18]], align 2 // CHECK-32-NEXT: br label [[IFCONT8:%.*]] -// CHECK-32: else7: +// CHECK-32: else9: // CHECK-32-NEXT: br label [[IFCONT8]] -// CHECK-32: ifcont8: +// CHECK-32: ifcont10: +// CHECK-32-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-32-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK-32-NEXT: [[IS_ACTIVE_THREAD9:%.*]] = icmp ult i32 [[TMP3]], [[TMP20]] // CHECK-32-NEXT: br i1 [[IS_ACTIVE_THREAD9]], label [[THEN10:%.*]], label [[ELSE11:%.*]] -// CHECK-32: then10: +// CHECK-32: then13: // CHECK-32-NEXT: [[TMP21:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK-32-NEXT: [[TMP22:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 1 // CHECK-32-NEXT: [[TMP23:%.*]] = load ptr, ptr [[TMP22]], align 4 // CHECK-32-NEXT: [[TMP24:%.*]] = load volatile i16, ptr addrspace(3) [[TMP21]], align 2 // CHECK-32-NEXT: store i16 [[TMP24]], ptr [[TMP23]], align 2 // CHECK-32-NEXT: br label [[IFCONT12:%.*]] -// CHECK-32: else11: +// CHECK-32: else14: // CHECK-32-NEXT: br label [[IFCONT12]] -// CHECK-32: ifcont12: +// CHECK-32: ifcont15: // CHECK-32-NEXT: ret void // // @@ -1557,7 +1571,6 @@ int bar(int n){ // CHECK-32-EX-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 4 // CHECK-32-EX-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 // CHECK-32-EX-NEXT: [[DOTCNT_ADDR:%.*]] = alloca i32, align 4 -// CHECK-32-EX-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-EX-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 4 // CHECK-32-EX-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK-32-EX-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() @@ -1573,6 +1586,7 @@ int bar(int n){ // CHECK-32-EX-NEXT: [[TMP8:%.*]] = icmp ult i32 [[TMP7]], 2 // CHECK-32-EX-NEXT: br i1 [[TMP8]], label [[BODY:%.*]], label [[EXIT:%.*]] // CHECK-32-EX: body: +// CHECK-32-EX-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-EX-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2:[0-9]+]], i32 [[TMP2]]) // CHECK-32-EX-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK-32-EX-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] @@ -1587,11 +1601,12 @@ int bar(int n){ // CHECK-32-EX: else: // CHECK-32-EX-NEXT: br label [[IFCONT]] // CHECK-32-EX: ifcont: +// CHECK-32-EX-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-EX-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-32-EX-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK-32-EX-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP14]] // CHECK-32-EX-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// CHECK-32-EX: then2: +// CHECK-32-EX: then3: // CHECK-32-EX-NEXT: [[TMP15:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK-32-EX-NEXT: [[TMP16:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP6]], i32 0, i32 0 // CHECK-32-EX-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 4 @@ -1599,9 +1614,9 @@ int bar(int n){ // CHECK-32-EX-NEXT: [[TMP19:%.*]] = load volatile i32, ptr addrspace(3) [[TMP15]], align 4 // CHECK-32-EX-NEXT: store i32 [[TMP19]], ptr [[TMP18]], align 4 // CHECK-32-EX-NEXT: br label [[IFCONT4:%.*]] -// CHECK-32-EX: else3: +// CHECK-32-EX: else4: // CHECK-32-EX-NEXT: br label [[IFCONT4]] -// CHECK-32-EX: ifcont4: +// CHECK-32-EX: ifcont5: // CHECK-32-EX-NEXT: [[TMP20:%.*]] = add nsw i32 [[TMP7]], 1 // CHECK-32-EX-NEXT: store i32 [[TMP20]], ptr [[DOTCNT_ADDR]], align 4 // CHECK-32-EX-NEXT: br label [[PRECOND]] @@ -1779,7 +1794,6 @@ int bar(int n){ // CHECK-32-EX-NEXT: entry: // CHECK-32-EX-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 4 // CHECK-32-EX-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 -// CHECK-32-EX-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-EX-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 4 // CHECK-32-EX-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK-32-EX-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() @@ -1788,6 +1802,7 @@ int bar(int n){ // CHECK-32-EX-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() // CHECK-32-EX-NEXT: [[NVPTX_WARP_ID:%.*]] = ashr i32 [[TMP5]], 5 // CHECK-32-EX-NEXT: [[TMP6:%.*]] = load ptr, ptr [[DOTADDR]], align 4 +// CHECK-32-EX-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-EX-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-32-EX-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK-32-EX-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] @@ -1801,47 +1816,50 @@ int bar(int n){ // CHECK-32-EX: else: // CHECK-32-EX-NEXT: br label [[IFCONT]] // CHECK-32-EX: ifcont: +// CHECK-32-EX-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-EX-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-32-EX-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK-32-EX-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP11]] // CHECK-32-EX-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// CHECK-32-EX: then2: +// CHECK-32-EX: then3: // CHECK-32-EX-NEXT: [[TMP12:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK-32-EX-NEXT: [[TMP13:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 0 // CHECK-32-EX-NEXT: [[TMP14:%.*]] = load ptr, ptr [[TMP13]], align 4 // CHECK-32-EX-NEXT: [[TMP15:%.*]] = load volatile i8, ptr addrspace(3) [[TMP12]], align 1 // CHECK-32-EX-NEXT: store i8 [[TMP15]], ptr [[TMP14]], align 1 // CHECK-32-EX-NEXT: br label [[IFCONT4:%.*]] -// CHECK-32-EX: else3: +// CHECK-32-EX: else4: // CHECK-32-EX-NEXT: br label [[IFCONT4]] -// CHECK-32-EX: ifcont4: +// CHECK-32-EX: ifcont5: +// CHECK-32-EX-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-EX-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-32-EX-NEXT: [[WARP_MASTER5:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK-32-EX-NEXT: br i1 [[WARP_MASTER5]], label [[THEN6:%.*]], label [[ELSE7:%.*]] -// CHECK-32-EX: then6: +// CHECK-32-EX: then8: // CHECK-32-EX-NEXT: [[TMP16:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 1 // CHECK-32-EX-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 4 // CHECK-32-EX-NEXT: [[TMP18:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[NVPTX_WARP_ID]] // CHECK-32-EX-NEXT: [[TMP19:%.*]] = load i32, ptr [[TMP17]], align 4 // CHECK-32-EX-NEXT: store volatile i32 [[TMP19]], ptr addrspace(3) [[TMP18]], align 4 // CHECK-32-EX-NEXT: br label [[IFCONT8:%.*]] -// CHECK-32-EX: else7: +// CHECK-32-EX: else9: // CHECK-32-EX-NEXT: br label [[IFCONT8]] -// CHECK-32-EX: ifcont8: +// CHECK-32-EX: ifcont10: +// CHECK-32-EX-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-EX-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-32-EX-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK-32-EX-NEXT: [[IS_ACTIVE_THREAD9:%.*]] = icmp ult i32 [[TMP3]], [[TMP20]] // CHECK-32-EX-NEXT: br i1 [[IS_ACTIVE_THREAD9]], label [[THEN10:%.*]], label [[ELSE11:%.*]] -// CHECK-32-EX: then10: +// CHECK-32-EX: then13: // CHECK-32-EX-NEXT: [[TMP21:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK-32-EX-NEXT: [[TMP22:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 1 // CHECK-32-EX-NEXT: [[TMP23:%.*]] = load ptr, ptr [[TMP22]], align 4 // CHECK-32-EX-NEXT: [[TMP24:%.*]] = load volatile i32, ptr addrspace(3) [[TMP21]], align 4 // CHECK-32-EX-NEXT: store i32 [[TMP24]], ptr [[TMP23]], align 4 // CHECK-32-EX-NEXT: br label [[IFCONT12:%.*]] -// CHECK-32-EX: else11: +// CHECK-32-EX: else14: // CHECK-32-EX-NEXT: br label [[IFCONT12]] -// CHECK-32-EX: ifcont12: +// CHECK-32-EX: ifcont15: // CHECK-32-EX-NEXT: ret void // // @@ -2032,7 +2050,6 @@ int bar(int n){ // CHECK-32-EX-NEXT: entry: // CHECK-32-EX-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 4 // CHECK-32-EX-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 -// CHECK-32-EX-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-EX-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 4 // CHECK-32-EX-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK-32-EX-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() @@ -2041,6 +2058,7 @@ int bar(int n){ // CHECK-32-EX-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() // CHECK-32-EX-NEXT: [[NVPTX_WARP_ID:%.*]] = ashr i32 [[TMP5]], 5 // CHECK-32-EX-NEXT: [[TMP6:%.*]] = load ptr, ptr [[DOTADDR]], align 4 +// CHECK-32-EX-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-EX-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-32-EX-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK-32-EX-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] @@ -2054,46 +2072,49 @@ int bar(int n){ // CHECK-32-EX: else: // CHECK-32-EX-NEXT: br label [[IFCONT]] // CHECK-32-EX: ifcont: +// CHECK-32-EX-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-EX-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-32-EX-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK-32-EX-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP11]] // CHECK-32-EX-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// CHECK-32-EX: then2: +// CHECK-32-EX: then3: // CHECK-32-EX-NEXT: [[TMP12:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK-32-EX-NEXT: [[TMP13:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 0 // CHECK-32-EX-NEXT: [[TMP14:%.*]] = load ptr, ptr [[TMP13]], align 4 // CHECK-32-EX-NEXT: [[TMP15:%.*]] = load volatile i32, ptr addrspace(3) [[TMP12]], align 4 // CHECK-32-EX-NEXT: store i32 [[TMP15]], ptr [[TMP14]], align 4 // CHECK-32-EX-NEXT: br label [[IFCONT4:%.*]] -// CHECK-32-EX: else3: +// CHECK-32-EX: else4: // CHECK-32-EX-NEXT: br label [[IFCONT4]] -// CHECK-32-EX: ifcont4: +// CHECK-32-EX: ifcont5: +// CHECK-32-EX-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-EX-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-32-EX-NEXT: [[WARP_MASTER5:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK-32-EX-NEXT: br i1 [[WARP_MASTER5]], label [[THEN6:%.*]], label [[ELSE7:%.*]] -// CHECK-32-EX: then6: +// CHECK-32-EX: then8: // CHECK-32-EX-NEXT: [[TMP16:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 1 // CHECK-32-EX-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 4 // CHECK-32-EX-NEXT: [[TMP18:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[NVPTX_WARP_ID]] // CHECK-32-EX-NEXT: [[TMP19:%.*]] = load i16, ptr [[TMP17]], align 2 // CHECK-32-EX-NEXT: store volatile i16 [[TMP19]], ptr addrspace(3) [[TMP18]], align 2 // CHECK-32-EX-NEXT: br label [[IFCONT8:%.*]] -// CHECK-32-EX: else7: +// CHECK-32-EX: else9: // CHECK-32-EX-NEXT: br label [[IFCONT8]] -// CHECK-32-EX: ifcont8: +// CHECK-32-EX: ifcont10: +// CHECK-32-EX-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-32-EX-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-32-EX-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK-32-EX-NEXT: [[IS_ACTIVE_THREAD9:%.*]] = icmp ult i32 [[TMP3]], [[TMP20]] // CHECK-32-EX-NEXT: br i1 [[IS_ACTIVE_THREAD9]], label [[THEN10:%.*]], label [[ELSE11:%.*]] -// CHECK-32-EX: then10: +// CHECK-32-EX: then13: // CHECK-32-EX-NEXT: [[TMP21:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK-32-EX-NEXT: [[TMP22:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 1 // CHECK-32-EX-NEXT: [[TMP23:%.*]] = load ptr, ptr [[TMP22]], align 4 // CHECK-32-EX-NEXT: [[TMP24:%.*]] = load volatile i16, ptr addrspace(3) [[TMP21]], align 2 // CHECK-32-EX-NEXT: store i16 [[TMP24]], ptr [[TMP23]], align 2 // CHECK-32-EX-NEXT: br label [[IFCONT12:%.*]] -// CHECK-32-EX: else11: +// CHECK-32-EX: else14: // CHECK-32-EX-NEXT: br label [[IFCONT12]] -// CHECK-32-EX: ifcont12: +// CHECK-32-EX: ifcont15: // CHECK-32-EX-NEXT: ret void // diff --git a/clang/test/OpenMP/nvptx_target_parallel_reduction_codegen_tbaa_PR46146.cpp b/clang/test/OpenMP/nvptx_target_parallel_reduction_codegen_tbaa_PR46146.cpp index fac42732022ad8..7b37480856ca25 100644 --- a/clang/test/OpenMP/nvptx_target_parallel_reduction_codegen_tbaa_PR46146.cpp +++ b/clang/test/OpenMP/nvptx_target_parallel_reduction_codegen_tbaa_PR46146.cpp @@ -36,14 +36,14 @@ void test() { // CHECK1-NEXT: [[DYN_PTR_ADDR:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: [[DOTZERO_ADDR:%.*]] = alloca i32, align 4 // CHECK1-NEXT: [[DOTTHREADID_TEMP_:%.*]] = alloca i32, align 4 -// CHECK1-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR]], align 8, !tbaa [[TBAA10:![0-9]+]] +// CHECK1-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR]], align 8 // CHECK1-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_target_init(ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z17complex_reductionIfEvv_l16_kernel_environment, ptr [[DYN_PTR]]) // CHECK1-NEXT: [[EXEC_USER_CODE:%.*]] = icmp eq i32 [[TMP0]], -1 // CHECK1-NEXT: br i1 [[EXEC_USER_CODE]], label [[USER_CODE_ENTRY:%.*]], label [[WORKER_EXIT:%.*]] // CHECK1: user_code.entry: // CHECK1-NEXT: [[TMP1:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1:[0-9]+]]) // CHECK1-NEXT: store i32 0, ptr [[DOTZERO_ADDR]], align 4 -// CHECK1-NEXT: store i32 [[TMP1]], ptr [[DOTTHREADID_TEMP_]], align 4, !tbaa [[TBAA14:![0-9]+]] +// CHECK1-NEXT: store i32 [[TMP1]], ptr [[DOTTHREADID_TEMP_]], align 4 // CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z17complex_reductionIfEvv_l16_omp_outlined(ptr [[DOTTHREADID_TEMP_]], ptr [[DOTZERO_ADDR]]) #[[ATTR4:[0-9]+]] // CHECK1-NEXT: call void @__kmpc_target_deinit() // CHECK1-NEXT: ret void @@ -66,78 +66,78 @@ void test() { // CHECK1-NEXT: [[REF_TMP:%.*]] = alloca float, align 4 // CHECK1-NEXT: [[REF_TMP2:%.*]] = alloca float, align 4 // CHECK1-NEXT: [[CAPTURED_VARS_ADDRS:%.*]] = alloca [3 x ptr], align 8 -// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8 +// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8 // CHECK1-NEXT: [[ISTART:%.*]] = call align 16 ptr @__kmpc_alloc_shared(i64 4) // CHECK1-NEXT: [[IEND:%.*]] = call align 16 ptr @__kmpc_alloc_shared(i64 4) // CHECK1-NEXT: [[PARTIAL_SUM:%.*]] = call align 16 ptr @__kmpc_alloc_shared(i64 8) // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTOMP_IV]]) #[[ATTR4]] // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTOMP_LB]]) #[[ATTR4]] -// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTOMP_UB]]) #[[ATTR4]] -// CHECK1-NEXT: store i32 99, ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 99, ptr [[DOTOMP_UB]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTOMP_STRIDE]]) #[[ATTR4]] -// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTOMP_IS_LAST]]) #[[ATTR4]] -// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[IB]]) #[[ATTR4]] // CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8 -// CHECK1-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4 // CHECK1-NEXT: call void @__kmpc_distribute_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP1]], i32 92, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1) -// CHECK1-NEXT: [[TMP2:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP2:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 // CHECK1-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP2]], 99 // CHECK1-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] // CHECK1: cond.true: // CHECK1-NEXT: br label [[COND_END:%.*]] // CHECK1: cond.false: -// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 // CHECK1-NEXT: br label [[COND_END]] // CHECK1: cond.end: // CHECK1-NEXT: [[COND:%.*]] = phi i32 [ 99, [[COND_TRUE]] ], [ [[TMP3]], [[COND_FALSE]] ] -// CHECK1-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: store i32 [[TMP4]], ptr [[DOTOMP_IV]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4 +// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4 +// CHECK1-NEXT: store i32 [[TMP4]], ptr [[DOTOMP_IV]], align 4 // CHECK1-NEXT: br label [[OMP_INNER_FOR_COND:%.*]] // CHECK1: omp.inner.for.cond: -// CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 +// CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 // CHECK1-NEXT: [[CMP1:%.*]] = icmp sle i32 [[TMP5]], [[TMP6]] // CHECK1-NEXT: br i1 [[CMP1]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_COND_CLEANUP:%.*]] // CHECK1: omp.inner.for.cond.cleanup: // CHECK1-NEXT: br label [[OMP_INNER_FOR_END:%.*]] // CHECK1: omp.inner.for.body: -// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 // CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1 // CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]] -// CHECK1-NEXT: store i32 [[ADD]], ptr [[IB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[ADD]], ptr [[IB]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[REF_TMP]]) #[[ATTR4]] -// CHECK1-NEXT: store float 0.000000e+00, ptr [[REF_TMP]], align 4, !tbaa [[TBAA16:![0-9]+]] +// CHECK1-NEXT: store float 0.000000e+00, ptr [[REF_TMP]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[REF_TMP2]]) #[[ATTR4]] -// CHECK1-NEXT: store float 0.000000e+00, ptr [[REF_TMP2]], align 4, !tbaa [[TBAA16]] +// CHECK1-NEXT: store float 0.000000e+00, ptr [[REF_TMP2]], align 4 // CHECK1-NEXT: call void @_ZNSt7complexIfEC1ERKfS2_(ptr nonnull align 4 dereferenceable(8) [[PARTIAL_SUM]], ptr nonnull align 4 dereferenceable(4) [[REF_TMP]], ptr nonnull align 4 dereferenceable(4) [[REF_TMP2]]) #[[ATTR12:[0-9]+]] // CHECK1-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr [[REF_TMP2]]) #[[ATTR4]] // CHECK1-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr [[REF_TMP]]) #[[ATTR4]] -// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[IB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[IB]], align 4 // CHECK1-NEXT: [[MUL3:%.*]] = mul nsw i32 [[TMP8]], 4 -// CHECK1-NEXT: store i32 [[MUL3]], ptr [[ISTART]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[IB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[MUL3]], ptr [[ISTART]], align 4 +// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[IB]], align 4 // CHECK1-NEXT: [[ADD4:%.*]] = add nsw i32 [[TMP9]], 1 // CHECK1-NEXT: [[MUL5:%.*]] = mul nsw i32 [[ADD4]], 4 -// CHECK1-NEXT: store i32 [[MUL5]], ptr [[IEND]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[MUL5]], ptr [[IEND]], align 4 // CHECK1-NEXT: [[TMP10:%.*]] = getelementptr inbounds [3 x ptr], ptr [[CAPTURED_VARS_ADDRS]], i64 0, i64 0 -// CHECK1-NEXT: store ptr [[ISTART]], ptr [[TMP10]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store ptr [[ISTART]], ptr [[TMP10]], align 8 // CHECK1-NEXT: [[TMP11:%.*]] = getelementptr inbounds [3 x ptr], ptr [[CAPTURED_VARS_ADDRS]], i64 0, i64 1 -// CHECK1-NEXT: store ptr [[IEND]], ptr [[TMP11]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store ptr [[IEND]], ptr [[TMP11]], align 8 // CHECK1-NEXT: [[TMP12:%.*]] = getelementptr inbounds [3 x ptr], ptr [[CAPTURED_VARS_ADDRS]], i64 0, i64 2 -// CHECK1-NEXT: store ptr [[PARTIAL_SUM]], ptr [[TMP12]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store ptr [[PARTIAL_SUM]], ptr [[TMP12]], align 8 // CHECK1-NEXT: call void @__kmpc_parallel_51(ptr @[[GLOB1]], i32 [[TMP1]], i32 1, i32 -1, i32 -1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z17complex_reductionIfEvv_l16_omp_outlined_omp_outlined, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z17complex_reductionIfEvv_l16_omp_outlined_omp_outlined_wrapper, ptr [[CAPTURED_VARS_ADDRS]], i64 3) // CHECK1-NEXT: br label [[OMP_BODY_CONTINUE:%.*]] // CHECK1: omp.body.continue: // CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]] // CHECK1: omp.inner.for.inc: -// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 // CHECK1-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP13]], 1 -// CHECK1-NEXT: store i32 [[ADD6]], ptr [[DOTOMP_IV]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[ADD6]], ptr [[DOTOMP_IV]], align 4 // CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]] // CHECK1: omp.inner.for.end: // CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]] @@ -161,9 +161,9 @@ void test() { // CHECK1-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: [[__RE_ADDR:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: [[__IM_ADDR:%.*]] = alloca ptr, align 8 -// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: store ptr [[__RE]], ptr [[__RE_ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: store ptr [[__IM]], ptr [[__IM_ADDR]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8 +// CHECK1-NEXT: store ptr [[__RE]], ptr [[__RE_ADDR]], align 8 +// CHECK1-NEXT: store ptr [[__IM]], ptr [[__IM_ADDR]], align 8 // CHECK1-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 // CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[__RE_ADDR]], align 8 // CHECK1-NEXT: [[TMP1:%.*]] = load ptr, ptr [[__IM_ADDR]], align 8 @@ -197,79 +197,79 @@ void test() { // CHECK1-NEXT: [[REF_TMP15:%.*]] = alloca float, align 4 // CHECK1-NEXT: [[REF_TMP16:%.*]] = alloca float, align 4 // CHECK1-NEXT: [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [1 x ptr], align 8 -// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: store ptr [[ISTART]], ptr [[ISTART_ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: store ptr [[IEND]], ptr [[IEND_ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: store ptr [[PARTIAL_SUM]], ptr [[PARTIAL_SUM_ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ISTART_ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: [[TMP1:%.*]] = load ptr, ptr [[IEND_ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[PARTIAL_SUM_ADDR]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8 +// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8 +// CHECK1-NEXT: store ptr [[ISTART]], ptr [[ISTART_ADDR]], align 8 +// CHECK1-NEXT: store ptr [[IEND]], ptr [[IEND_ADDR]], align 8 +// CHECK1-NEXT: store ptr [[PARTIAL_SUM]], ptr [[PARTIAL_SUM_ADDR]], align 8 +// CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ISTART_ADDR]], align 8 +// CHECK1-NEXT: [[TMP1:%.*]] = load ptr, ptr [[IEND_ADDR]], align 8 +// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[PARTIAL_SUM_ADDR]], align 8 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTOMP_IV]]) #[[ATTR4]] // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTCAPTURE_EXPR_]]) #[[ATTR4]] -// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP0]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: store i32 [[TMP3]], ptr [[DOTCAPTURE_EXPR_]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP0]], align 4 +// CHECK1-NEXT: store i32 [[TMP3]], ptr [[DOTCAPTURE_EXPR_]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTCAPTURE_EXPR_1]]) #[[ATTR4]] -// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP1]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR_1]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP1]], align 4 +// CHECK1-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR_1]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTCAPTURE_EXPR_2]]) #[[ATTR4]] -// CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4 +// CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4 // CHECK1-NEXT: [[SUB:%.*]] = sub i32 [[TMP5]], [[TMP6]] // CHECK1-NEXT: [[SUB3:%.*]] = sub i32 [[SUB]], 1 // CHECK1-NEXT: [[ADD:%.*]] = add i32 [[SUB3]], 1 // CHECK1-NEXT: [[DIV:%.*]] = udiv i32 [[ADD]], 1 // CHECK1-NEXT: [[SUB4:%.*]] = sub i32 [[DIV]], 1 -// CHECK1-NEXT: store i32 [[SUB4]], ptr [[DOTCAPTURE_EXPR_2]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[SUB4]], ptr [[DOTCAPTURE_EXPR_2]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[I]]) #[[ATTR4]] -// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: store i32 [[TMP7]], ptr [[I]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4 +// CHECK1-NEXT: store i32 [[TMP7]], ptr [[I]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr [[I]]) #[[ATTR4]] -// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4 +// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4 // CHECK1-NEXT: [[CMP:%.*]] = icmp slt i32 [[TMP8]], [[TMP9]] // CHECK1-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]] // CHECK1: omp.precond.then: // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTOMP_LB]]) #[[ATTR4]] -// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTOMP_UB]]) #[[ATTR4]] -// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_2]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: store i32 [[TMP10]], ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_2]], align 4 +// CHECK1-NEXT: store i32 [[TMP10]], ptr [[DOTOMP_UB]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTOMP_STRIDE]]) #[[ATTR4]] -// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTOMP_IS_LAST]]) #[[ATTR4]] -// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[PARTIAL_SUM5]]) #[[ATTR4]] // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[REF_TMP]]) #[[ATTR4]] -// CHECK1-NEXT: store float 0.000000e+00, ptr [[REF_TMP]], align 4, !tbaa [[TBAA16]] +// CHECK1-NEXT: store float 0.000000e+00, ptr [[REF_TMP]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[REF_TMP6]]) #[[ATTR4]] -// CHECK1-NEXT: store float 0.000000e+00, ptr [[REF_TMP6]], align 4, !tbaa [[TBAA16]] +// CHECK1-NEXT: store float 0.000000e+00, ptr [[REF_TMP6]], align 4 // CHECK1-NEXT: call void @_ZNSt7complexIfEC1ERKfS2_(ptr nonnull align 4 dereferenceable(8) [[PARTIAL_SUM5]], ptr nonnull align 4 dereferenceable(4) [[REF_TMP]], ptr nonnull align 4 dereferenceable(4) [[REF_TMP6]]) #[[ATTR12]] // CHECK1-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr [[REF_TMP6]]) #[[ATTR4]] // CHECK1-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr [[REF_TMP]]) #[[ATTR4]] // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[I7]]) #[[ATTR4]] // CHECK1-NEXT: [[TMP11:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8 -// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[TMP11]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[TMP11]], align 4 // CHECK1-NEXT: call void @__kmpc_for_static_init_4u(ptr @[[GLOB3:[0-9]+]], i32 [[TMP12]], i32 33, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1) // CHECK1-NEXT: br label [[OMP_DISPATCH_COND:%.*]] // CHECK1: omp.dispatch.cond: -// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_2]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 +// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_2]], align 4 // CHECK1-NEXT: [[CMP8:%.*]] = icmp ugt i32 [[TMP13]], [[TMP14]] // CHECK1-NEXT: br i1 [[CMP8]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] // CHECK1: cond.true: -// CHECK1-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_2]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_2]], align 4 // CHECK1-NEXT: br label [[COND_END:%.*]] // CHECK1: cond.false: -// CHECK1-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 // CHECK1-NEXT: br label [[COND_END]] // CHECK1: cond.end: // CHECK1-NEXT: [[COND:%.*]] = phi i32 [ [[TMP15]], [[COND_TRUE]] ], [ [[TMP16]], [[COND_FALSE]] ] -// CHECK1-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: store i32 [[TMP17]], ptr [[DOTOMP_IV]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4 +// CHECK1-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4 +// CHECK1-NEXT: store i32 [[TMP17]], ptr [[DOTOMP_IV]], align 4 +// CHECK1-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 +// CHECK1-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 // CHECK1-NEXT: [[ADD9:%.*]] = add i32 [[TMP19]], 1 // CHECK1-NEXT: [[CMP10:%.*]] = icmp ult i32 [[TMP18]], [[ADD9]] // CHECK1-NEXT: br i1 [[CMP10]], label [[OMP_DISPATCH_BODY:%.*]], label [[OMP_DISPATCH_CLEANUP:%.*]] @@ -278,28 +278,28 @@ void test() { // CHECK1: omp.dispatch.body: // CHECK1-NEXT: br label [[OMP_INNER_FOR_COND:%.*]] // CHECK1: omp.inner.for.cond: -// CHECK1-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP21:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 +// CHECK1-NEXT: [[TMP21:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 // CHECK1-NEXT: [[ADD11:%.*]] = add i32 [[TMP21]], 1 // CHECK1-NEXT: [[CMP12:%.*]] = icmp ult i32 [[TMP20]], [[ADD11]] // CHECK1-NEXT: br i1 [[CMP12]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_COND_CLEANUP:%.*]] // CHECK1: omp.inner.for.cond.cleanup: // CHECK1-NEXT: br label [[OMP_INNER_FOR_END:%.*]] // CHECK1: omp.inner.for.body: -// CHECK1-NEXT: [[TMP22:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP23:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP22:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4 +// CHECK1-NEXT: [[TMP23:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 // CHECK1-NEXT: [[MUL:%.*]] = mul i32 [[TMP23]], 1 // CHECK1-NEXT: [[ADD13:%.*]] = add i32 [[TMP22]], [[MUL]] -// CHECK1-NEXT: store i32 [[ADD13]], ptr [[I7]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[ADD13]], ptr [[I7]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[REF_TMP14]]) #[[ATTR4]] // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[REF_TMP15]]) #[[ATTR4]] -// CHECK1-NEXT: [[TMP24:%.*]] = load i32, ptr [[I7]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP24:%.*]] = load i32, ptr [[I7]], align 4 // CHECK1-NEXT: [[CONV:%.*]] = sitofp i32 [[TMP24]] to float -// CHECK1-NEXT: store float [[CONV]], ptr [[REF_TMP15]], align 4, !tbaa [[TBAA16]] +// CHECK1-NEXT: store float [[CONV]], ptr [[REF_TMP15]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[REF_TMP16]]) #[[ATTR4]] -// CHECK1-NEXT: [[TMP25:%.*]] = load i32, ptr [[I7]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP25:%.*]] = load i32, ptr [[I7]], align 4 // CHECK1-NEXT: [[CONV17:%.*]] = sitofp i32 [[TMP25]] to float -// CHECK1-NEXT: store float [[CONV17]], ptr [[REF_TMP16]], align 4, !tbaa [[TBAA16]] +// CHECK1-NEXT: store float [[CONV17]], ptr [[REF_TMP16]], align 4 // CHECK1-NEXT: call void @_ZNSt7complexIfEC1ERKfS2_(ptr nonnull align 4 dereferenceable(8) [[REF_TMP14]], ptr nonnull align 4 dereferenceable(4) [[REF_TMP15]], ptr nonnull align 4 dereferenceable(4) [[REF_TMP16]]) #[[ATTR12]] // CHECK1-NEXT: [[CALL:%.*]] = call nonnull align 4 dereferenceable(8) ptr @_ZNSt7complexIfEpLIfEERS0_RKS_IT_E(ptr nonnull align 4 dereferenceable(8) [[PARTIAL_SUM5]], ptr nonnull align 4 dereferenceable(8) [[REF_TMP14]]) #[[ATTR12]] // CHECK1-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr [[REF_TMP16]]) #[[ATTR4]] @@ -309,25 +309,25 @@ void test() { // CHECK1: omp.body.continue: // CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]] // CHECK1: omp.inner.for.inc: -// CHECK1-NEXT: [[TMP26:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP26:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 // CHECK1-NEXT: [[ADD18:%.*]] = add i32 [[TMP26]], 1 -// CHECK1-NEXT: store i32 [[ADD18]], ptr [[DOTOMP_IV]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[ADD18]], ptr [[DOTOMP_IV]], align 4 // CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]] // CHECK1: omp.inner.for.end: // CHECK1-NEXT: br label [[OMP_DISPATCH_INC:%.*]] // CHECK1: omp.dispatch.inc: -// CHECK1-NEXT: [[TMP27:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP28:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP27:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4 +// CHECK1-NEXT: [[TMP28:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4 // CHECK1-NEXT: [[ADD19:%.*]] = add i32 [[TMP27]], [[TMP28]] -// CHECK1-NEXT: store i32 [[ADD19]], ptr [[DOTOMP_LB]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP29:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP30:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[ADD19]], ptr [[DOTOMP_LB]], align 4 +// CHECK1-NEXT: [[TMP29:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 +// CHECK1-NEXT: [[TMP30:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4 // CHECK1-NEXT: [[ADD20:%.*]] = add i32 [[TMP29]], [[TMP30]] -// CHECK1-NEXT: store i32 [[ADD20]], ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[ADD20]], ptr [[DOTOMP_UB]], align 4 // CHECK1-NEXT: br label [[OMP_DISPATCH_COND]] // CHECK1: omp.dispatch.end: // CHECK1-NEXT: [[TMP31:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8 -// CHECK1-NEXT: [[TMP32:%.*]] = load i32, ptr [[TMP31]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP32:%.*]] = load i32, ptr [[TMP31]], align 4 // CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB3]], i32 [[TMP32]]) // CHECK1-NEXT: [[TMP33:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i64 0, i64 0 // CHECK1-NEXT: store ptr [[PARTIAL_SUM5]], ptr [[TMP33]], align 8 @@ -358,53 +358,53 @@ void test() { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: [[__C_ADDR:%.*]] = alloca ptr, align 8 -// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: store ptr [[__C]], ptr [[__C_ADDR]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8 +// CHECK1-NEXT: store ptr [[__C]], ptr [[__C_ADDR]], align 8 // CHECK1-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 -// CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[__C_ADDR]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[__C_ADDR]], align 8 // CHECK1-NEXT: [[CALL:%.*]] = call float @_ZNKSt7complexIfE4realEv(ptr nonnull align 4 dereferenceable(8) [[TMP0]]) #[[ATTR12]] // CHECK1-NEXT: [[__RE_:%.*]] = getelementptr inbounds %"class.std::complex", ptr [[THIS1]], i32 0, i32 0 -// CHECK1-NEXT: [[TMP1:%.*]] = load float, ptr [[__RE_]], align 4, !tbaa [[TBAA18:![0-9]+]] +// CHECK1-NEXT: [[TMP1:%.*]] = load float, ptr [[__RE_]], align 4 // CHECK1-NEXT: [[ADD:%.*]] = fadd float [[TMP1]], [[CALL]] -// CHECK1-NEXT: store float [[ADD]], ptr [[__RE_]], align 4, !tbaa [[TBAA18]] -// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[__C_ADDR]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store float [[ADD]], ptr [[__RE_]], align 4 +// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[__C_ADDR]], align 8 // CHECK1-NEXT: [[CALL2:%.*]] = call float @_ZNKSt7complexIfE4imagEv(ptr nonnull align 4 dereferenceable(8) [[TMP2]]) #[[ATTR12]] // CHECK1-NEXT: [[__IM_:%.*]] = getelementptr inbounds %"class.std::complex", ptr [[THIS1]], i32 0, i32 1 -// CHECK1-NEXT: [[TMP3:%.*]] = load float, ptr [[__IM_]], align 4, !tbaa [[TBAA20:![0-9]+]] +// CHECK1-NEXT: [[TMP3:%.*]] = load float, ptr [[__IM_]], align 4 // CHECK1-NEXT: [[ADD3:%.*]] = fadd float [[TMP3]], [[CALL2]] -// CHECK1-NEXT: store float [[ADD3]], ptr [[__IM_]], align 4, !tbaa [[TBAA20]] +// CHECK1-NEXT: store float [[ADD3]], ptr [[__IM_]], align 4 // CHECK1-NEXT: ret ptr [[THIS1]] // // // CHECK1-LABEL: define {{[^@]+}}@_omp_reduction_shuffle_and_reduce_func -// CHECK1-SAME: (ptr [[TMP0:%.*]], i16 signext [[TMP1:%.*]], i16 signext [[TMP2:%.*]], i16 signext [[TMP3:%.*]]) #[[ATTR7:[0-9]+]] { +// CHECK1-SAME: (ptr noundef [[TMP0:%.*]], i16 noundef signext [[TMP1:%.*]], i16 noundef signext [[TMP2:%.*]], i16 noundef signext [[TMP3:%.*]]) #[[ATTR7:[0-9]+]] { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca i16, align 2 // CHECK1-NEXT: [[DOTADDR2:%.*]] = alloca i16, align 2 // CHECK1-NEXT: [[DOTADDR3:%.*]] = alloca i16, align 2 // CHECK1-NEXT: [[DOTOMP_REDUCTION_REMOTE_REDUCE_LIST:%.*]] = alloca [1 x ptr], align 8 -// CHECK1-NEXT: [[DOTOMP_REDUCTION_ELEMENT:%.*]] = alloca %"class.std::complex", align 4 -// CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: store i16 [[TMP1]], ptr [[DOTADDR1]], align 2, !tbaa [[TBAA21:![0-9]+]] -// CHECK1-NEXT: store i16 [[TMP2]], ptr [[DOTADDR2]], align 2, !tbaa [[TBAA21]] -// CHECK1-NEXT: store i16 [[TMP3]], ptr [[DOTADDR3]], align 2, !tbaa [[TBAA21]] -// CHECK1-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: [[TMP5:%.*]] = load i16, ptr [[DOTADDR1]], align 2, !tbaa [[TBAA21]] -// CHECK1-NEXT: [[TMP6:%.*]] = load i16, ptr [[DOTADDR2]], align 2, !tbaa [[TBAA21]] -// CHECK1-NEXT: [[TMP7:%.*]] = load i16, ptr [[DOTADDR3]], align 2, !tbaa [[TBAA21]] +// CHECK1-NEXT: [[DOTOMP_REDUCTION_ELEMENT:%.*]] = alloca %"class.std::complex", align 8 +// CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 +// CHECK1-NEXT: store i16 [[TMP1]], ptr [[DOTADDR1]], align 2 +// CHECK1-NEXT: store i16 [[TMP2]], ptr [[DOTADDR2]], align 2 +// CHECK1-NEXT: store i16 [[TMP3]], ptr [[DOTADDR3]], align 2 +// CHECK1-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTADDR]], align 8 +// CHECK1-NEXT: [[TMP5:%.*]] = load i16, ptr [[DOTADDR1]], align 2 +// CHECK1-NEXT: [[TMP6:%.*]] = load i16, ptr [[DOTADDR2]], align 2 +// CHECK1-NEXT: [[TMP7:%.*]] = load i16, ptr [[DOTADDR3]], align 2 // CHECK1-NEXT: [[TMP8:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP4]], i64 0, i64 0 // CHECK1-NEXT: [[TMP9:%.*]] = load ptr, ptr [[TMP8]], align 8 // CHECK1-NEXT: [[TMP10:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_REMOTE_REDUCE_LIST]], i64 0, i64 0 // CHECK1-NEXT: [[TMP11:%.*]] = getelementptr %"class.std::complex", ptr [[TMP9]], i64 1 -// CHECK1-NEXT: [[TMP12:%.*]] = load i64, ptr [[TMP9]], align 4 +// CHECK1-NEXT: [[TMP12:%.*]] = load i64, ptr [[TMP9]], align 8 // CHECK1-NEXT: [[TMP13:%.*]] = call i32 @__kmpc_get_warp_size() // CHECK1-NEXT: [[TMP14:%.*]] = trunc i32 [[TMP13]] to i16 // CHECK1-NEXT: [[TMP15:%.*]] = call i64 @__kmpc_shuffle_int64(i64 [[TMP12]], i16 [[TMP6]], i16 [[TMP14]]) -// CHECK1-NEXT: store i64 [[TMP15]], ptr [[DOTOMP_REDUCTION_ELEMENT]], align 4 +// CHECK1-NEXT: store i64 [[TMP15]], ptr [[DOTOMP_REDUCTION_ELEMENT]], align 8 // CHECK1-NEXT: [[TMP16:%.*]] = getelementptr i64, ptr [[TMP9]], i64 1 // CHECK1-NEXT: [[TMP17:%.*]] = getelementptr i64, ptr [[DOTOMP_REDUCTION_ELEMENT]], i64 1 -// CHECK1-NEXT: store ptr [[DOTOMP_REDUCTION_ELEMENT]], ptr [[TMP10]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store ptr [[DOTOMP_REDUCTION_ELEMENT]], ptr [[TMP10]], align 8 // CHECK1-NEXT: [[TMP18:%.*]] = icmp eq i16 [[TMP7]], 0 // CHECK1-NEXT: [[TMP19:%.*]] = icmp eq i16 [[TMP7]], 1 // CHECK1-NEXT: [[TMP20:%.*]] = icmp ult i16 [[TMP5]], [[TMP6]] @@ -433,7 +433,7 @@ void test() { // CHECK1-NEXT: [[TMP34:%.*]] = load ptr, ptr [[TMP33]], align 8 // CHECK1-NEXT: [[TMP35:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP4]], i64 0, i64 0 // CHECK1-NEXT: [[TMP36:%.*]] = load ptr, ptr [[TMP35]], align 8 -// CHECK1-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[TMP36]], ptr align 4 [[TMP34]], i64 8, i1 false), !tbaa.struct [[TBAA_STRUCT23:![0-9]+]] +// CHECK1-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[TMP36]], ptr align 8 [[TMP34]], i64 8, i1 false) // CHECK1-NEXT: br label [[IFCONT6:%.*]] // CHECK1: else5: // CHECK1-NEXT: br label [[IFCONT6]] @@ -442,33 +442,33 @@ void test() { // // // CHECK1-LABEL: define {{[^@]+}}@_omp_reduction_inter_warp_copy_func -// CHECK1-SAME: (ptr [[TMP0:%.*]], i32 [[TMP1:%.*]]) #[[ATTR7]] { +// CHECK1-SAME: (ptr noundef [[TMP0:%.*]], i32 noundef [[TMP1:%.*]]) #[[ATTR7]] { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 // CHECK1-NEXT: [[DOTCNT_ADDR:%.*]] = alloca i32, align 4 -// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) -// CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 +// CHECK1-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK1-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() // CHECK1-NEXT: [[TMP4:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() // CHECK1-NEXT: [[NVPTX_LANE_ID:%.*]] = and i32 [[TMP4]], 31 // CHECK1-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() // CHECK1-NEXT: [[NVPTX_WARP_ID:%.*]] = ashr i32 [[TMP5]], 5 // CHECK1-NEXT: [[TMP6:%.*]] = load ptr, ptr [[DOTADDR]], align 8 -// CHECK1-NEXT: store i32 0, ptr [[DOTCNT_ADDR]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 0, ptr [[DOTCNT_ADDR]], align 4 // CHECK1-NEXT: br label [[PRECOND:%.*]] // CHECK1: precond: -// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCNT_ADDR]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCNT_ADDR]], align 4 // CHECK1-NEXT: [[TMP8:%.*]] = icmp ult i32 [[TMP7]], 2 // CHECK1-NEXT: br i1 [[TMP8]], label [[BODY:%.*]], label [[EXIT:%.*]] // CHECK1: body: +// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK1-NEXT: call void @__kmpc_barrier(ptr @[[GLOB4:[0-9]+]], i32 [[TMP2]]) // CHECK1-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK1-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] // CHECK1: then: // CHECK1-NEXT: [[TMP9:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP6]], i64 0, i64 0 -// CHECK1-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP9]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP9]], align 8 // CHECK1-NEXT: [[TMP11:%.*]] = getelementptr i32, ptr [[TMP10]], i32 [[TMP7]] // CHECK1-NEXT: [[TMP12:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[NVPTX_WARP_ID]] // CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[TMP11]], align 4 @@ -477,46 +477,47 @@ void test() { // CHECK1: else: // CHECK1-NEXT: br label [[IFCONT]] // CHECK1: ifcont: +// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK1-NEXT: call void @__kmpc_barrier(ptr @[[GLOB4]], i32 [[TMP2]]) -// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTADDR1]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK1-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP14]] // CHECK1-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// CHECK1: then2: +// CHECK1: then3: // CHECK1-NEXT: [[TMP15:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK1-NEXT: [[TMP16:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP6]], i64 0, i64 0 -// CHECK1-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 8 // CHECK1-NEXT: [[TMP18:%.*]] = getelementptr i32, ptr [[TMP17]], i32 [[TMP7]] -// CHECK1-NEXT: [[TMP19:%.*]] = load volatile i32, ptr addrspace(3) [[TMP15]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: store i32 [[TMP19]], ptr [[TMP18]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP19:%.*]] = load volatile i32, ptr addrspace(3) [[TMP15]], align 4 +// CHECK1-NEXT: store i32 [[TMP19]], ptr [[TMP18]], align 4 // CHECK1-NEXT: br label [[IFCONT4:%.*]] -// CHECK1: else3: +// CHECK1: else4: // CHECK1-NEXT: br label [[IFCONT4]] -// CHECK1: ifcont4: +// CHECK1: ifcont5: // CHECK1-NEXT: [[TMP20:%.*]] = add nsw i32 [[TMP7]], 1 -// CHECK1-NEXT: store i32 [[TMP20]], ptr [[DOTCNT_ADDR]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[TMP20]], ptr [[DOTCNT_ADDR]], align 4 // CHECK1-NEXT: br label [[PRECOND]] // CHECK1: exit: // CHECK1-NEXT: ret void // // // CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z17complex_reductionIfEvv_l16_omp_outlined_omp_outlined_wrapper -// CHECK1-SAME: (i16 zeroext [[TMP0:%.*]], i32 [[TMP1:%.*]]) #[[ATTR7]] { +// CHECK1-SAME: (i16 zeroext [[TMP0:%.*]], i32 [[TMP1:%.*]]) #[[ATTR8:[0-9]+]] { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[DOTADDR:%.*]] = alloca i16, align 2 // CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 // CHECK1-NEXT: [[DOTZERO_ADDR:%.*]] = alloca i32, align 4 // CHECK1-NEXT: [[GLOBAL_ARGS:%.*]] = alloca ptr, align 8 -// CHECK1-NEXT: store i16 [[TMP0]], ptr [[DOTADDR]], align 2, !tbaa [[TBAA21]] -// CHECK1-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i16 [[TMP0]], ptr [[DOTADDR]], align 2 +// CHECK1-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK1-NEXT: store i32 0, ptr [[DOTZERO_ADDR]], align 4 // CHECK1-NEXT: call void @__kmpc_get_shared_variables(ptr [[GLOBAL_ARGS]]) // CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[GLOBAL_ARGS]], align 8 // CHECK1-NEXT: [[TMP3:%.*]] = getelementptr inbounds ptr, ptr [[TMP2]], i64 0 -// CHECK1-NEXT: [[TMP4:%.*]] = load ptr, ptr [[TMP3]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: [[TMP4:%.*]] = load ptr, ptr [[TMP3]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = getelementptr inbounds ptr, ptr [[TMP2]], i64 1 -// CHECK1-NEXT: [[TMP6:%.*]] = load ptr, ptr [[TMP5]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: [[TMP6:%.*]] = load ptr, ptr [[TMP5]], align 8 // CHECK1-NEXT: [[TMP7:%.*]] = getelementptr inbounds ptr, ptr [[TMP2]], i64 2 -// CHECK1-NEXT: [[TMP8:%.*]] = load ptr, ptr [[TMP7]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: [[TMP8:%.*]] = load ptr, ptr [[TMP7]], align 8 // CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z17complex_reductionIfEvv_l16_omp_outlined_omp_outlined(ptr [[DOTADDR1]], ptr [[DOTZERO_ADDR]], ptr [[TMP4]], ptr [[TMP6]], ptr [[TMP8]]) #[[ATTR4]] // CHECK1-NEXT: ret void // @@ -527,14 +528,14 @@ void test() { // CHECK1-NEXT: [[DYN_PTR_ADDR:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: [[DOTZERO_ADDR:%.*]] = alloca i32, align 4 // CHECK1-NEXT: [[DOTTHREADID_TEMP_:%.*]] = alloca i32, align 4 -// CHECK1-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR]], align 8 // CHECK1-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_target_init(ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z17complex_reductionIdEvv_l16_kernel_environment, ptr [[DYN_PTR]]) // CHECK1-NEXT: [[EXEC_USER_CODE:%.*]] = icmp eq i32 [[TMP0]], -1 // CHECK1-NEXT: br i1 [[EXEC_USER_CODE]], label [[USER_CODE_ENTRY:%.*]], label [[WORKER_EXIT:%.*]] // CHECK1: user_code.entry: // CHECK1-NEXT: [[TMP1:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK1-NEXT: store i32 0, ptr [[DOTZERO_ADDR]], align 4 -// CHECK1-NEXT: store i32 [[TMP1]], ptr [[DOTTHREADID_TEMP_]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[TMP1]], ptr [[DOTTHREADID_TEMP_]], align 4 // CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z17complex_reductionIdEvv_l16_omp_outlined(ptr [[DOTTHREADID_TEMP_]], ptr [[DOTZERO_ADDR]]) #[[ATTR4]] // CHECK1-NEXT: call void @__kmpc_target_deinit() // CHECK1-NEXT: ret void @@ -557,78 +558,78 @@ void test() { // CHECK1-NEXT: [[REF_TMP:%.*]] = alloca double, align 8 // CHECK1-NEXT: [[REF_TMP2:%.*]] = alloca double, align 8 // CHECK1-NEXT: [[CAPTURED_VARS_ADDRS:%.*]] = alloca [3 x ptr], align 8 -// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8 +// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8 // CHECK1-NEXT: [[ISTART:%.*]] = call align 16 ptr @__kmpc_alloc_shared(i64 4) // CHECK1-NEXT: [[IEND:%.*]] = call align 16 ptr @__kmpc_alloc_shared(i64 4) // CHECK1-NEXT: [[PARTIAL_SUM:%.*]] = call align 16 ptr @__kmpc_alloc_shared(i64 16) // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTOMP_IV]]) #[[ATTR4]] // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTOMP_LB]]) #[[ATTR4]] -// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTOMP_UB]]) #[[ATTR4]] -// CHECK1-NEXT: store i32 99, ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 99, ptr [[DOTOMP_UB]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTOMP_STRIDE]]) #[[ATTR4]] -// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTOMP_IS_LAST]]) #[[ATTR4]] -// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[IB]]) #[[ATTR4]] // CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8 -// CHECK1-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP1:%.*]] = load i32, ptr [[TMP0]], align 4 // CHECK1-NEXT: call void @__kmpc_distribute_static_init_4(ptr @[[GLOB2]], i32 [[TMP1]], i32 92, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1) -// CHECK1-NEXT: [[TMP2:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP2:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 // CHECK1-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP2]], 99 // CHECK1-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] // CHECK1: cond.true: // CHECK1-NEXT: br label [[COND_END:%.*]] // CHECK1: cond.false: -// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 // CHECK1-NEXT: br label [[COND_END]] // CHECK1: cond.end: // CHECK1-NEXT: [[COND:%.*]] = phi i32 [ 99, [[COND_TRUE]] ], [ [[TMP3]], [[COND_FALSE]] ] -// CHECK1-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: store i32 [[TMP4]], ptr [[DOTOMP_IV]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4 +// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4 +// CHECK1-NEXT: store i32 [[TMP4]], ptr [[DOTOMP_IV]], align 4 // CHECK1-NEXT: br label [[OMP_INNER_FOR_COND:%.*]] // CHECK1: omp.inner.for.cond: -// CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 +// CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 // CHECK1-NEXT: [[CMP1:%.*]] = icmp sle i32 [[TMP5]], [[TMP6]] // CHECK1-NEXT: br i1 [[CMP1]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_COND_CLEANUP:%.*]] // CHECK1: omp.inner.for.cond.cleanup: // CHECK1-NEXT: br label [[OMP_INNER_FOR_END:%.*]] // CHECK1: omp.inner.for.body: -// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 // CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1 // CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]] -// CHECK1-NEXT: store i32 [[ADD]], ptr [[IB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[ADD]], ptr [[IB]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[REF_TMP]]) #[[ATTR4]] -// CHECK1-NEXT: store double 0.000000e+00, ptr [[REF_TMP]], align 8, !tbaa [[TBAA24:![0-9]+]] +// CHECK1-NEXT: store double 0.000000e+00, ptr [[REF_TMP]], align 8 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[REF_TMP2]]) #[[ATTR4]] -// CHECK1-NEXT: store double 0.000000e+00, ptr [[REF_TMP2]], align 8, !tbaa [[TBAA24]] +// CHECK1-NEXT: store double 0.000000e+00, ptr [[REF_TMP2]], align 8 // CHECK1-NEXT: call void @_ZNSt7complexIdEC1ERKdS2_(ptr nonnull align 8 dereferenceable(16) [[PARTIAL_SUM]], ptr nonnull align 8 dereferenceable(8) [[REF_TMP]], ptr nonnull align 8 dereferenceable(8) [[REF_TMP2]]) #[[ATTR12]] // CHECK1-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[REF_TMP2]]) #[[ATTR4]] // CHECK1-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[REF_TMP]]) #[[ATTR4]] -// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[IB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[IB]], align 4 // CHECK1-NEXT: [[MUL3:%.*]] = mul nsw i32 [[TMP8]], 4 -// CHECK1-NEXT: store i32 [[MUL3]], ptr [[ISTART]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[IB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[MUL3]], ptr [[ISTART]], align 4 +// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[IB]], align 4 // CHECK1-NEXT: [[ADD4:%.*]] = add nsw i32 [[TMP9]], 1 // CHECK1-NEXT: [[MUL5:%.*]] = mul nsw i32 [[ADD4]], 4 -// CHECK1-NEXT: store i32 [[MUL5]], ptr [[IEND]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[MUL5]], ptr [[IEND]], align 4 // CHECK1-NEXT: [[TMP10:%.*]] = getelementptr inbounds [3 x ptr], ptr [[CAPTURED_VARS_ADDRS]], i64 0, i64 0 -// CHECK1-NEXT: store ptr [[ISTART]], ptr [[TMP10]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store ptr [[ISTART]], ptr [[TMP10]], align 8 // CHECK1-NEXT: [[TMP11:%.*]] = getelementptr inbounds [3 x ptr], ptr [[CAPTURED_VARS_ADDRS]], i64 0, i64 1 -// CHECK1-NEXT: store ptr [[IEND]], ptr [[TMP11]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store ptr [[IEND]], ptr [[TMP11]], align 8 // CHECK1-NEXT: [[TMP12:%.*]] = getelementptr inbounds [3 x ptr], ptr [[CAPTURED_VARS_ADDRS]], i64 0, i64 2 -// CHECK1-NEXT: store ptr [[PARTIAL_SUM]], ptr [[TMP12]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store ptr [[PARTIAL_SUM]], ptr [[TMP12]], align 8 // CHECK1-NEXT: call void @__kmpc_parallel_51(ptr @[[GLOB1]], i32 [[TMP1]], i32 1, i32 -1, i32 -1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z17complex_reductionIdEvv_l16_omp_outlined_omp_outlined, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z17complex_reductionIdEvv_l16_omp_outlined_omp_outlined_wrapper, ptr [[CAPTURED_VARS_ADDRS]], i64 3) // CHECK1-NEXT: br label [[OMP_BODY_CONTINUE:%.*]] // CHECK1: omp.body.continue: // CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]] // CHECK1: omp.inner.for.inc: -// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 // CHECK1-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP13]], 1 -// CHECK1-NEXT: store i32 [[ADD6]], ptr [[DOTOMP_IV]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[ADD6]], ptr [[DOTOMP_IV]], align 4 // CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]] // CHECK1: omp.inner.for.end: // CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]] @@ -652,9 +653,9 @@ void test() { // CHECK1-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: [[__RE_ADDR:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: [[__IM_ADDR:%.*]] = alloca ptr, align 8 -// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: store ptr [[__RE]], ptr [[__RE_ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: store ptr [[__IM]], ptr [[__IM_ADDR]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8 +// CHECK1-NEXT: store ptr [[__RE]], ptr [[__RE_ADDR]], align 8 +// CHECK1-NEXT: store ptr [[__IM]], ptr [[__IM_ADDR]], align 8 // CHECK1-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 // CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[__RE_ADDR]], align 8 // CHECK1-NEXT: [[TMP1:%.*]] = load ptr, ptr [[__IM_ADDR]], align 8 @@ -688,79 +689,79 @@ void test() { // CHECK1-NEXT: [[REF_TMP15:%.*]] = alloca double, align 8 // CHECK1-NEXT: [[REF_TMP16:%.*]] = alloca double, align 8 // CHECK1-NEXT: [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [1 x ptr], align 8 -// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: store ptr [[ISTART]], ptr [[ISTART_ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: store ptr [[IEND]], ptr [[IEND_ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: store ptr [[PARTIAL_SUM]], ptr [[PARTIAL_SUM_ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ISTART_ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: [[TMP1:%.*]] = load ptr, ptr [[IEND_ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[PARTIAL_SUM_ADDR]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8 +// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8 +// CHECK1-NEXT: store ptr [[ISTART]], ptr [[ISTART_ADDR]], align 8 +// CHECK1-NEXT: store ptr [[IEND]], ptr [[IEND_ADDR]], align 8 +// CHECK1-NEXT: store ptr [[PARTIAL_SUM]], ptr [[PARTIAL_SUM_ADDR]], align 8 +// CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ISTART_ADDR]], align 8 +// CHECK1-NEXT: [[TMP1:%.*]] = load ptr, ptr [[IEND_ADDR]], align 8 +// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[PARTIAL_SUM_ADDR]], align 8 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTOMP_IV]]) #[[ATTR4]] // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTCAPTURE_EXPR_]]) #[[ATTR4]] -// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP0]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: store i32 [[TMP3]], ptr [[DOTCAPTURE_EXPR_]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP0]], align 4 +// CHECK1-NEXT: store i32 [[TMP3]], ptr [[DOTCAPTURE_EXPR_]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTCAPTURE_EXPR_1]]) #[[ATTR4]] -// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP1]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR_1]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP1]], align 4 +// CHECK1-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR_1]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTCAPTURE_EXPR_2]]) #[[ATTR4]] -// CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4 +// CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4 // CHECK1-NEXT: [[SUB:%.*]] = sub i32 [[TMP5]], [[TMP6]] // CHECK1-NEXT: [[SUB3:%.*]] = sub i32 [[SUB]], 1 // CHECK1-NEXT: [[ADD:%.*]] = add i32 [[SUB3]], 1 // CHECK1-NEXT: [[DIV:%.*]] = udiv i32 [[ADD]], 1 // CHECK1-NEXT: [[SUB4:%.*]] = sub i32 [[DIV]], 1 -// CHECK1-NEXT: store i32 [[SUB4]], ptr [[DOTCAPTURE_EXPR_2]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[SUB4]], ptr [[DOTCAPTURE_EXPR_2]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[I]]) #[[ATTR4]] -// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: store i32 [[TMP7]], ptr [[I]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4 +// CHECK1-NEXT: store i32 [[TMP7]], ptr [[I]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr [[I]]) #[[ATTR4]] -// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4 +// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4 // CHECK1-NEXT: [[CMP:%.*]] = icmp slt i32 [[TMP8]], [[TMP9]] // CHECK1-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]] // CHECK1: omp.precond.then: // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTOMP_LB]]) #[[ATTR4]] -// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTOMP_UB]]) #[[ATTR4]] -// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_2]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: store i32 [[TMP10]], ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_2]], align 4 +// CHECK1-NEXT: store i32 [[TMP10]], ptr [[DOTOMP_UB]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTOMP_STRIDE]]) #[[ATTR4]] -// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[DOTOMP_IS_LAST]]) #[[ATTR4]] -// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 16, ptr [[PARTIAL_SUM5]]) #[[ATTR4]] // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[REF_TMP]]) #[[ATTR4]] -// CHECK1-NEXT: store double 0.000000e+00, ptr [[REF_TMP]], align 8, !tbaa [[TBAA24]] +// CHECK1-NEXT: store double 0.000000e+00, ptr [[REF_TMP]], align 8 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[REF_TMP6]]) #[[ATTR4]] -// CHECK1-NEXT: store double 0.000000e+00, ptr [[REF_TMP6]], align 8, !tbaa [[TBAA24]] +// CHECK1-NEXT: store double 0.000000e+00, ptr [[REF_TMP6]], align 8 // CHECK1-NEXT: call void @_ZNSt7complexIdEC1ERKdS2_(ptr nonnull align 8 dereferenceable(16) [[PARTIAL_SUM5]], ptr nonnull align 8 dereferenceable(8) [[REF_TMP]], ptr nonnull align 8 dereferenceable(8) [[REF_TMP6]]) #[[ATTR12]] // CHECK1-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[REF_TMP6]]) #[[ATTR4]] // CHECK1-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[REF_TMP]]) #[[ATTR4]] // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[I7]]) #[[ATTR4]] // CHECK1-NEXT: [[TMP11:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8 -// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[TMP11]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[TMP11]], align 4 // CHECK1-NEXT: call void @__kmpc_for_static_init_4u(ptr @[[GLOB3]], i32 [[TMP12]], i32 33, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1) // CHECK1-NEXT: br label [[OMP_DISPATCH_COND:%.*]] // CHECK1: omp.dispatch.cond: -// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_2]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 +// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_2]], align 4 // CHECK1-NEXT: [[CMP8:%.*]] = icmp ugt i32 [[TMP13]], [[TMP14]] // CHECK1-NEXT: br i1 [[CMP8]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] // CHECK1: cond.true: -// CHECK1-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_2]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_2]], align 4 // CHECK1-NEXT: br label [[COND_END:%.*]] // CHECK1: cond.false: -// CHECK1-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 // CHECK1-NEXT: br label [[COND_END]] // CHECK1: cond.end: // CHECK1-NEXT: [[COND:%.*]] = phi i32 [ [[TMP15]], [[COND_TRUE]] ], [ [[TMP16]], [[COND_FALSE]] ] -// CHECK1-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: store i32 [[TMP17]], ptr [[DOTOMP_IV]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4 +// CHECK1-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4 +// CHECK1-NEXT: store i32 [[TMP17]], ptr [[DOTOMP_IV]], align 4 +// CHECK1-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 +// CHECK1-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 // CHECK1-NEXT: [[ADD9:%.*]] = add i32 [[TMP19]], 1 // CHECK1-NEXT: [[CMP10:%.*]] = icmp ult i32 [[TMP18]], [[ADD9]] // CHECK1-NEXT: br i1 [[CMP10]], label [[OMP_DISPATCH_BODY:%.*]], label [[OMP_DISPATCH_CLEANUP:%.*]] @@ -769,28 +770,28 @@ void test() { // CHECK1: omp.dispatch.body: // CHECK1-NEXT: br label [[OMP_INNER_FOR_COND:%.*]] // CHECK1: omp.inner.for.cond: -// CHECK1-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP21:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 +// CHECK1-NEXT: [[TMP21:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 // CHECK1-NEXT: [[ADD11:%.*]] = add i32 [[TMP21]], 1 // CHECK1-NEXT: [[CMP12:%.*]] = icmp ult i32 [[TMP20]], [[ADD11]] // CHECK1-NEXT: br i1 [[CMP12]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_COND_CLEANUP:%.*]] // CHECK1: omp.inner.for.cond.cleanup: // CHECK1-NEXT: br label [[OMP_INNER_FOR_END:%.*]] // CHECK1: omp.inner.for.body: -// CHECK1-NEXT: [[TMP22:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP23:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP22:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4 +// CHECK1-NEXT: [[TMP23:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 // CHECK1-NEXT: [[MUL:%.*]] = mul i32 [[TMP23]], 1 // CHECK1-NEXT: [[ADD13:%.*]] = add i32 [[TMP22]], [[MUL]] -// CHECK1-NEXT: store i32 [[ADD13]], ptr [[I7]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[ADD13]], ptr [[I7]], align 4 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 16, ptr [[REF_TMP14]]) #[[ATTR4]] // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[REF_TMP15]]) #[[ATTR4]] -// CHECK1-NEXT: [[TMP24:%.*]] = load i32, ptr [[I7]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP24:%.*]] = load i32, ptr [[I7]], align 4 // CHECK1-NEXT: [[CONV:%.*]] = sitofp i32 [[TMP24]] to double -// CHECK1-NEXT: store double [[CONV]], ptr [[REF_TMP15]], align 8, !tbaa [[TBAA24]] +// CHECK1-NEXT: store double [[CONV]], ptr [[REF_TMP15]], align 8 // CHECK1-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[REF_TMP16]]) #[[ATTR4]] -// CHECK1-NEXT: [[TMP25:%.*]] = load i32, ptr [[I7]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP25:%.*]] = load i32, ptr [[I7]], align 4 // CHECK1-NEXT: [[CONV17:%.*]] = sitofp i32 [[TMP25]] to double -// CHECK1-NEXT: store double [[CONV17]], ptr [[REF_TMP16]], align 8, !tbaa [[TBAA24]] +// CHECK1-NEXT: store double [[CONV17]], ptr [[REF_TMP16]], align 8 // CHECK1-NEXT: call void @_ZNSt7complexIdEC1ERKdS2_(ptr nonnull align 8 dereferenceable(16) [[REF_TMP14]], ptr nonnull align 8 dereferenceable(8) [[REF_TMP15]], ptr nonnull align 8 dereferenceable(8) [[REF_TMP16]]) #[[ATTR12]] // CHECK1-NEXT: [[CALL:%.*]] = call nonnull align 8 dereferenceable(16) ptr @_ZNSt7complexIdEpLIdEERS0_RKS_IT_E(ptr nonnull align 8 dereferenceable(16) [[PARTIAL_SUM5]], ptr nonnull align 8 dereferenceable(16) [[REF_TMP14]]) #[[ATTR12]] // CHECK1-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[REF_TMP16]]) #[[ATTR4]] @@ -800,25 +801,25 @@ void test() { // CHECK1: omp.body.continue: // CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]] // CHECK1: omp.inner.for.inc: -// CHECK1-NEXT: [[TMP26:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP26:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4 // CHECK1-NEXT: [[ADD18:%.*]] = add i32 [[TMP26]], 1 -// CHECK1-NEXT: store i32 [[ADD18]], ptr [[DOTOMP_IV]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[ADD18]], ptr [[DOTOMP_IV]], align 4 // CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]] // CHECK1: omp.inner.for.end: // CHECK1-NEXT: br label [[OMP_DISPATCH_INC:%.*]] // CHECK1: omp.dispatch.inc: -// CHECK1-NEXT: [[TMP27:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP28:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP27:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4 +// CHECK1-NEXT: [[TMP28:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4 // CHECK1-NEXT: [[ADD19:%.*]] = add i32 [[TMP27]], [[TMP28]] -// CHECK1-NEXT: store i32 [[ADD19]], ptr [[DOTOMP_LB]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP29:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: [[TMP30:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[ADD19]], ptr [[DOTOMP_LB]], align 4 +// CHECK1-NEXT: [[TMP29:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4 +// CHECK1-NEXT: [[TMP30:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4 // CHECK1-NEXT: [[ADD20:%.*]] = add i32 [[TMP29]], [[TMP30]] -// CHECK1-NEXT: store i32 [[ADD20]], ptr [[DOTOMP_UB]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[ADD20]], ptr [[DOTOMP_UB]], align 4 // CHECK1-NEXT: br label [[OMP_DISPATCH_COND]] // CHECK1: omp.dispatch.end: // CHECK1-NEXT: [[TMP31:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8 -// CHECK1-NEXT: [[TMP32:%.*]] = load i32, ptr [[TMP31]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP32:%.*]] = load i32, ptr [[TMP31]], align 4 // CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB3]], i32 [[TMP32]]) // CHECK1-NEXT: [[TMP33:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i64 0, i64 0 // CHECK1-NEXT: store ptr [[PARTIAL_SUM5]], ptr [[TMP33]], align 8 @@ -849,26 +850,26 @@ void test() { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: [[__C_ADDR:%.*]] = alloca ptr, align 8 -// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: store ptr [[__C]], ptr [[__C_ADDR]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8 +// CHECK1-NEXT: store ptr [[__C]], ptr [[__C_ADDR]], align 8 // CHECK1-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 -// CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[__C_ADDR]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[__C_ADDR]], align 8 // CHECK1-NEXT: [[CALL:%.*]] = call double @_ZNKSt7complexIdE4realEv(ptr nonnull align 8 dereferenceable(16) [[TMP0]]) #[[ATTR12]] // CHECK1-NEXT: [[__RE_:%.*]] = getelementptr inbounds %"class.std::complex.0", ptr [[THIS1]], i32 0, i32 0 -// CHECK1-NEXT: [[TMP1:%.*]] = load double, ptr [[__RE_]], align 8, !tbaa [[TBAA26:![0-9]+]] +// CHECK1-NEXT: [[TMP1:%.*]] = load double, ptr [[__RE_]], align 8 // CHECK1-NEXT: [[ADD:%.*]] = fadd double [[TMP1]], [[CALL]] -// CHECK1-NEXT: store double [[ADD]], ptr [[__RE_]], align 8, !tbaa [[TBAA26]] -// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[__C_ADDR]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store double [[ADD]], ptr [[__RE_]], align 8 +// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[__C_ADDR]], align 8 // CHECK1-NEXT: [[CALL2:%.*]] = call double @_ZNKSt7complexIdE4imagEv(ptr nonnull align 8 dereferenceable(16) [[TMP2]]) #[[ATTR12]] // CHECK1-NEXT: [[__IM_:%.*]] = getelementptr inbounds %"class.std::complex.0", ptr [[THIS1]], i32 0, i32 1 -// CHECK1-NEXT: [[TMP3:%.*]] = load double, ptr [[__IM_]], align 8, !tbaa [[TBAA28:![0-9]+]] +// CHECK1-NEXT: [[TMP3:%.*]] = load double, ptr [[__IM_]], align 8 // CHECK1-NEXT: [[ADD3:%.*]] = fadd double [[TMP3]], [[CALL2]] -// CHECK1-NEXT: store double [[ADD3]], ptr [[__IM_]], align 8, !tbaa [[TBAA28]] +// CHECK1-NEXT: store double [[ADD3]], ptr [[__IM_]], align 8 // CHECK1-NEXT: ret ptr [[THIS1]] // // // CHECK1-LABEL: define {{[^@]+}}@_omp_reduction_shuffle_and_reduce_func1 -// CHECK1-SAME: (ptr [[TMP0:%.*]], i16 signext [[TMP1:%.*]], i16 signext [[TMP2:%.*]], i16 signext [[TMP3:%.*]]) #[[ATTR7]] { +// CHECK1-SAME: (ptr noundef [[TMP0:%.*]], i16 noundef signext [[TMP1:%.*]], i16 noundef signext [[TMP2:%.*]], i16 noundef signext [[TMP3:%.*]]) #[[ATTR7]] { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca i16, align 2 @@ -876,14 +877,14 @@ void test() { // CHECK1-NEXT: [[DOTADDR3:%.*]] = alloca i16, align 2 // CHECK1-NEXT: [[DOTOMP_REDUCTION_REMOTE_REDUCE_LIST:%.*]] = alloca [1 x ptr], align 8 // CHECK1-NEXT: [[DOTOMP_REDUCTION_ELEMENT:%.*]] = alloca %"class.std::complex.0", align 8 -// CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: store i16 [[TMP1]], ptr [[DOTADDR1]], align 2, !tbaa [[TBAA21]] -// CHECK1-NEXT: store i16 [[TMP2]], ptr [[DOTADDR2]], align 2, !tbaa [[TBAA21]] -// CHECK1-NEXT: store i16 [[TMP3]], ptr [[DOTADDR3]], align 2, !tbaa [[TBAA21]] -// CHECK1-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: [[TMP5:%.*]] = load i16, ptr [[DOTADDR1]], align 2, !tbaa [[TBAA21]] -// CHECK1-NEXT: [[TMP6:%.*]] = load i16, ptr [[DOTADDR2]], align 2, !tbaa [[TBAA21]] -// CHECK1-NEXT: [[TMP7:%.*]] = load i16, ptr [[DOTADDR3]], align 2, !tbaa [[TBAA21]] +// CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 +// CHECK1-NEXT: store i16 [[TMP1]], ptr [[DOTADDR1]], align 2 +// CHECK1-NEXT: store i16 [[TMP2]], ptr [[DOTADDR2]], align 2 +// CHECK1-NEXT: store i16 [[TMP3]], ptr [[DOTADDR3]], align 2 +// CHECK1-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTADDR]], align 8 +// CHECK1-NEXT: [[TMP5:%.*]] = load i16, ptr [[DOTADDR1]], align 2 +// CHECK1-NEXT: [[TMP6:%.*]] = load i16, ptr [[DOTADDR2]], align 2 +// CHECK1-NEXT: [[TMP7:%.*]] = load i16, ptr [[DOTADDR3]], align 2 // CHECK1-NEXT: [[TMP8:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP4]], i64 0, i64 0 // CHECK1-NEXT: [[TMP9:%.*]] = load ptr, ptr [[TMP8]], align 8 // CHECK1-NEXT: [[TMP10:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_REMOTE_REDUCE_LIST]], i64 0, i64 0 @@ -908,7 +909,7 @@ void test() { // CHECK1-NEXT: [[TMP24]] = getelementptr i64, ptr [[TMP13]], i64 1 // CHECK1-NEXT: br label [[DOTSHUFFLE_PRE_COND]] // CHECK1: .shuffle.exit: -// CHECK1-NEXT: store ptr [[DOTOMP_REDUCTION_ELEMENT]], ptr [[TMP10]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store ptr [[DOTOMP_REDUCTION_ELEMENT]], ptr [[TMP10]], align 8 // CHECK1-NEXT: [[TMP25:%.*]] = icmp eq i16 [[TMP7]], 0 // CHECK1-NEXT: [[TMP26:%.*]] = icmp eq i16 [[TMP7]], 1 // CHECK1-NEXT: [[TMP27:%.*]] = icmp ult i16 [[TMP5]], [[TMP6]] @@ -937,7 +938,7 @@ void test() { // CHECK1-NEXT: [[TMP41:%.*]] = load ptr, ptr [[TMP40]], align 8 // CHECK1-NEXT: [[TMP42:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP4]], i64 0, i64 0 // CHECK1-NEXT: [[TMP43:%.*]] = load ptr, ptr [[TMP42]], align 8 -// CHECK1-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[TMP43]], ptr align 8 [[TMP41]], i64 16, i1 false), !tbaa.struct [[TBAA_STRUCT29:![0-9]+]] +// CHECK1-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[TMP43]], ptr align 8 [[TMP41]], i64 16, i1 false) // CHECK1-NEXT: br label [[IFCONT6:%.*]] // CHECK1: else5: // CHECK1-NEXT: br label [[IFCONT6]] @@ -946,33 +947,33 @@ void test() { // // // CHECK1-LABEL: define {{[^@]+}}@_omp_reduction_inter_warp_copy_func2 -// CHECK1-SAME: (ptr [[TMP0:%.*]], i32 [[TMP1:%.*]]) #[[ATTR7]] { +// CHECK1-SAME: (ptr noundef [[TMP0:%.*]], i32 noundef [[TMP1:%.*]]) #[[ATTR7]] { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 // CHECK1-NEXT: [[DOTCNT_ADDR:%.*]] = alloca i32, align 4 -// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) -// CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 +// CHECK1-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK1-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() // CHECK1-NEXT: [[TMP4:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() // CHECK1-NEXT: [[NVPTX_LANE_ID:%.*]] = and i32 [[TMP4]], 31 // CHECK1-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() // CHECK1-NEXT: [[NVPTX_WARP_ID:%.*]] = ashr i32 [[TMP5]], 5 // CHECK1-NEXT: [[TMP6:%.*]] = load ptr, ptr [[DOTADDR]], align 8 -// CHECK1-NEXT: store i32 0, ptr [[DOTCNT_ADDR]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 0, ptr [[DOTCNT_ADDR]], align 4 // CHECK1-NEXT: br label [[PRECOND:%.*]] // CHECK1: precond: -// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCNT_ADDR]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCNT_ADDR]], align 4 // CHECK1-NEXT: [[TMP8:%.*]] = icmp ult i32 [[TMP7]], 4 // CHECK1-NEXT: br i1 [[TMP8]], label [[BODY:%.*]], label [[EXIT:%.*]] // CHECK1: body: +// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK1-NEXT: call void @__kmpc_barrier(ptr @[[GLOB4]], i32 [[TMP2]]) // CHECK1-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK1-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] // CHECK1: then: // CHECK1-NEXT: [[TMP9:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP6]], i64 0, i64 0 -// CHECK1-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP9]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP9]], align 8 // CHECK1-NEXT: [[TMP11:%.*]] = getelementptr i32, ptr [[TMP10]], i32 [[TMP7]] // CHECK1-NEXT: [[TMP12:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[NVPTX_WARP_ID]] // CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[TMP11]], align 4 @@ -981,46 +982,47 @@ void test() { // CHECK1: else: // CHECK1-NEXT: br label [[IFCONT]] // CHECK1: ifcont: +// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK1-NEXT: call void @__kmpc_barrier(ptr @[[GLOB4]], i32 [[TMP2]]) -// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTADDR1]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK1-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP14]] // CHECK1-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// CHECK1: then2: +// CHECK1: then3: // CHECK1-NEXT: [[TMP15:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK1-NEXT: [[TMP16:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP6]], i64 0, i64 0 -// CHECK1-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 8 // CHECK1-NEXT: [[TMP18:%.*]] = getelementptr i32, ptr [[TMP17]], i32 [[TMP7]] -// CHECK1-NEXT: [[TMP19:%.*]] = load volatile i32, ptr addrspace(3) [[TMP15]], align 4, !tbaa [[TBAA14]] -// CHECK1-NEXT: store i32 [[TMP19]], ptr [[TMP18]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: [[TMP19:%.*]] = load volatile i32, ptr addrspace(3) [[TMP15]], align 4 +// CHECK1-NEXT: store i32 [[TMP19]], ptr [[TMP18]], align 4 // CHECK1-NEXT: br label [[IFCONT4:%.*]] -// CHECK1: else3: +// CHECK1: else4: // CHECK1-NEXT: br label [[IFCONT4]] -// CHECK1: ifcont4: +// CHECK1: ifcont5: // CHECK1-NEXT: [[TMP20:%.*]] = add nsw i32 [[TMP7]], 1 -// CHECK1-NEXT: store i32 [[TMP20]], ptr [[DOTCNT_ADDR]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i32 [[TMP20]], ptr [[DOTCNT_ADDR]], align 4 // CHECK1-NEXT: br label [[PRECOND]] // CHECK1: exit: // CHECK1-NEXT: ret void // // // CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z17complex_reductionIdEvv_l16_omp_outlined_omp_outlined_wrapper -// CHECK1-SAME: (i16 zeroext [[TMP0:%.*]], i32 [[TMP1:%.*]]) #[[ATTR7]] { +// CHECK1-SAME: (i16 zeroext [[TMP0:%.*]], i32 [[TMP1:%.*]]) #[[ATTR8]] { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[DOTADDR:%.*]] = alloca i16, align 2 // CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 // CHECK1-NEXT: [[DOTZERO_ADDR:%.*]] = alloca i32, align 4 // CHECK1-NEXT: [[GLOBAL_ARGS:%.*]] = alloca ptr, align 8 -// CHECK1-NEXT: store i16 [[TMP0]], ptr [[DOTADDR]], align 2, !tbaa [[TBAA21]] -// CHECK1-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4, !tbaa [[TBAA14]] +// CHECK1-NEXT: store i16 [[TMP0]], ptr [[DOTADDR]], align 2 +// CHECK1-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK1-NEXT: store i32 0, ptr [[DOTZERO_ADDR]], align 4 // CHECK1-NEXT: call void @__kmpc_get_shared_variables(ptr [[GLOBAL_ARGS]]) // CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[GLOBAL_ARGS]], align 8 // CHECK1-NEXT: [[TMP3:%.*]] = getelementptr inbounds ptr, ptr [[TMP2]], i64 0 -// CHECK1-NEXT: [[TMP4:%.*]] = load ptr, ptr [[TMP3]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: [[TMP4:%.*]] = load ptr, ptr [[TMP3]], align 8 // CHECK1-NEXT: [[TMP5:%.*]] = getelementptr inbounds ptr, ptr [[TMP2]], i64 1 -// CHECK1-NEXT: [[TMP6:%.*]] = load ptr, ptr [[TMP5]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: [[TMP6:%.*]] = load ptr, ptr [[TMP5]], align 8 // CHECK1-NEXT: [[TMP7:%.*]] = getelementptr inbounds ptr, ptr [[TMP2]], i64 2 -// CHECK1-NEXT: [[TMP8:%.*]] = load ptr, ptr [[TMP7]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: [[TMP8:%.*]] = load ptr, ptr [[TMP7]], align 8 // CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z17complex_reductionIdEvv_l16_omp_outlined_omp_outlined(ptr [[DOTADDR1]], ptr [[DOTZERO_ADDR]], ptr [[TMP4]], ptr [[TMP6]], ptr [[TMP8]]) #[[ATTR4]] // CHECK1-NEXT: ret void // @@ -1031,18 +1033,18 @@ void test() { // CHECK1-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: [[__RE_ADDR:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: [[__IM_ADDR:%.*]] = alloca ptr, align 8 -// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: store ptr [[__RE]], ptr [[__RE_ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: store ptr [[__IM]], ptr [[__IM_ADDR]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8 +// CHECK1-NEXT: store ptr [[__RE]], ptr [[__RE_ADDR]], align 8 +// CHECK1-NEXT: store ptr [[__IM]], ptr [[__IM_ADDR]], align 8 // CHECK1-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 // CHECK1-NEXT: [[__RE_:%.*]] = getelementptr inbounds %"class.std::complex", ptr [[THIS1]], i32 0, i32 0 -// CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[__RE_ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: [[TMP1:%.*]] = load float, ptr [[TMP0]], align 4, !tbaa [[TBAA16]] -// CHECK1-NEXT: store float [[TMP1]], ptr [[__RE_]], align 4, !tbaa [[TBAA18]] +// CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[__RE_ADDR]], align 8 +// CHECK1-NEXT: [[TMP1:%.*]] = load float, ptr [[TMP0]], align 4 +// CHECK1-NEXT: store float [[TMP1]], ptr [[__RE_]], align 4 // CHECK1-NEXT: [[__IM_:%.*]] = getelementptr inbounds %"class.std::complex", ptr [[THIS1]], i32 0, i32 1 -// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[__IM_ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: [[TMP3:%.*]] = load float, ptr [[TMP2]], align 4, !tbaa [[TBAA16]] -// CHECK1-NEXT: store float [[TMP3]], ptr [[__IM_]], align 4, !tbaa [[TBAA20]] +// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[__IM_ADDR]], align 8 +// CHECK1-NEXT: [[TMP3:%.*]] = load float, ptr [[TMP2]], align 4 +// CHECK1-NEXT: store float [[TMP3]], ptr [[__IM_]], align 4 // CHECK1-NEXT: ret void // // @@ -1050,10 +1052,10 @@ void test() { // CHECK1-SAME: (ptr nonnull align 4 dereferenceable(8) [[THIS:%.*]]) #[[ATTR6]] comdat align 2 { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 -// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8 // CHECK1-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 // CHECK1-NEXT: [[__RE_:%.*]] = getelementptr inbounds %"class.std::complex", ptr [[THIS1]], i32 0, i32 0 -// CHECK1-NEXT: [[TMP0:%.*]] = load float, ptr [[__RE_]], align 4, !tbaa [[TBAA18]] +// CHECK1-NEXT: [[TMP0:%.*]] = load float, ptr [[__RE_]], align 4 // CHECK1-NEXT: ret float [[TMP0]] // // @@ -1061,10 +1063,10 @@ void test() { // CHECK1-SAME: (ptr nonnull align 4 dereferenceable(8) [[THIS:%.*]]) #[[ATTR6]] comdat align 2 { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 -// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8 // CHECK1-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 // CHECK1-NEXT: [[__IM_:%.*]] = getelementptr inbounds %"class.std::complex", ptr [[THIS1]], i32 0, i32 1 -// CHECK1-NEXT: [[TMP0:%.*]] = load float, ptr [[__IM_]], align 4, !tbaa [[TBAA20]] +// CHECK1-NEXT: [[TMP0:%.*]] = load float, ptr [[__IM_]], align 4 // CHECK1-NEXT: ret float [[TMP0]] // // @@ -1074,18 +1076,18 @@ void test() { // CHECK1-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: [[__RE_ADDR:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: [[__IM_ADDR:%.*]] = alloca ptr, align 8 -// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: store ptr [[__RE]], ptr [[__RE_ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: store ptr [[__IM]], ptr [[__IM_ADDR]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8 +// CHECK1-NEXT: store ptr [[__RE]], ptr [[__RE_ADDR]], align 8 +// CHECK1-NEXT: store ptr [[__IM]], ptr [[__IM_ADDR]], align 8 // CHECK1-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 // CHECK1-NEXT: [[__RE_:%.*]] = getelementptr inbounds %"class.std::complex.0", ptr [[THIS1]], i32 0, i32 0 -// CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[__RE_ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: [[TMP1:%.*]] = load double, ptr [[TMP0]], align 8, !tbaa [[TBAA24]] -// CHECK1-NEXT: store double [[TMP1]], ptr [[__RE_]], align 8, !tbaa [[TBAA26]] +// CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[__RE_ADDR]], align 8 +// CHECK1-NEXT: [[TMP1:%.*]] = load double, ptr [[TMP0]], align 8 +// CHECK1-NEXT: store double [[TMP1]], ptr [[__RE_]], align 8 // CHECK1-NEXT: [[__IM_:%.*]] = getelementptr inbounds %"class.std::complex.0", ptr [[THIS1]], i32 0, i32 1 -// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[__IM_ADDR]], align 8, !tbaa [[TBAA10]] -// CHECK1-NEXT: [[TMP3:%.*]] = load double, ptr [[TMP2]], align 8, !tbaa [[TBAA24]] -// CHECK1-NEXT: store double [[TMP3]], ptr [[__IM_]], align 8, !tbaa [[TBAA28]] +// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[__IM_ADDR]], align 8 +// CHECK1-NEXT: [[TMP3:%.*]] = load double, ptr [[TMP2]], align 8 +// CHECK1-NEXT: store double [[TMP3]], ptr [[__IM_]], align 8 // CHECK1-NEXT: ret void // // @@ -1093,10 +1095,10 @@ void test() { // CHECK1-SAME: (ptr nonnull align 8 dereferenceable(16) [[THIS:%.*]]) #[[ATTR6]] comdat align 2 { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 -// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8 // CHECK1-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 // CHECK1-NEXT: [[__RE_:%.*]] = getelementptr inbounds %"class.std::complex.0", ptr [[THIS1]], i32 0, i32 0 -// CHECK1-NEXT: [[TMP0:%.*]] = load double, ptr [[__RE_]], align 8, !tbaa [[TBAA26]] +// CHECK1-NEXT: [[TMP0:%.*]] = load double, ptr [[__RE_]], align 8 // CHECK1-NEXT: ret double [[TMP0]] // // @@ -1104,9 +1106,9 @@ void test() { // CHECK1-SAME: (ptr nonnull align 8 dereferenceable(16) [[THIS:%.*]]) #[[ATTR6]] comdat align 2 { // CHECK1-NEXT: entry: // CHECK1-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 -// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8, !tbaa [[TBAA10]] +// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8 // CHECK1-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 // CHECK1-NEXT: [[__IM_:%.*]] = getelementptr inbounds %"class.std::complex.0", ptr [[THIS1]], i32 0, i32 1 -// CHECK1-NEXT: [[TMP0:%.*]] = load double, ptr [[__IM_]], align 8, !tbaa [[TBAA28]] +// CHECK1-NEXT: [[TMP0:%.*]] = load double, ptr [[__IM_]], align 8 // CHECK1-NEXT: ret double [[TMP0]] // diff --git a/clang/test/OpenMP/nvptx_teams_reduction_codegen.cpp b/clang/test/OpenMP/nvptx_teams_reduction_codegen.cpp index 360a780c75383c..350b6f761e573a 100644 --- a/clang/test/OpenMP/nvptx_teams_reduction_codegen.cpp +++ b/clang/test/OpenMP/nvptx_teams_reduction_codegen.cpp @@ -182,7 +182,6 @@ int bar(int n){ // CHECK1-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 // CHECK1-NEXT: [[DOTCNT_ADDR:%.*]] = alloca i32, align 4 -// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK1-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() @@ -198,6 +197,7 @@ int bar(int n){ // CHECK1-NEXT: [[TMP8:%.*]] = icmp ult i32 [[TMP7]], 2 // CHECK1-NEXT: br i1 [[TMP8]], label [[BODY:%.*]], label [[EXIT:%.*]] // CHECK1: body: +// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK1-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2:[0-9]+]], i32 [[TMP2]]) // CHECK1-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK1-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] @@ -212,11 +212,12 @@ int bar(int n){ // CHECK1: else: // CHECK1-NEXT: br label [[IFCONT]] // CHECK1: ifcont: +// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK1-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK1-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP14]] // CHECK1-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// CHECK1: then2: +// CHECK1: then3: // CHECK1-NEXT: [[TMP15:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK1-NEXT: [[TMP16:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP6]], i64 0, i64 0 // CHECK1-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 8 @@ -224,9 +225,9 @@ int bar(int n){ // CHECK1-NEXT: [[TMP19:%.*]] = load volatile i32, ptr addrspace(3) [[TMP15]], align 4 // CHECK1-NEXT: store i32 [[TMP19]], ptr [[TMP18]], align 4 // CHECK1-NEXT: br label [[IFCONT4:%.*]] -// CHECK1: else3: +// CHECK1: else4: // CHECK1-NEXT: br label [[IFCONT4]] -// CHECK1: ifcont4: +// CHECK1: ifcont5: // CHECK1-NEXT: [[TMP20:%.*]] = add nsw i32 [[TMP7]], 1 // CHECK1-NEXT: store i32 [[TMP20]], ptr [[DOTCNT_ADDR]], align 4 // CHECK1-NEXT: br label [[PRECOND]] @@ -496,7 +497,6 @@ int bar(int n){ // CHECK1-NEXT: entry: // CHECK1-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 -// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK1-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() @@ -505,6 +505,7 @@ int bar(int n){ // CHECK1-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() // CHECK1-NEXT: [[NVPTX_WARP_ID:%.*]] = ashr i32 [[TMP5]], 5 // CHECK1-NEXT: [[TMP6:%.*]] = load ptr, ptr [[DOTADDR]], align 8 +// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK1-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK1-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK1-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] @@ -518,47 +519,50 @@ int bar(int n){ // CHECK1: else: // CHECK1-NEXT: br label [[IFCONT]] // CHECK1: ifcont: +// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK1-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK1-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP11]] // CHECK1-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// CHECK1: then2: +// CHECK1: then3: // CHECK1-NEXT: [[TMP12:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK1-NEXT: [[TMP13:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i64 0, i64 0 // CHECK1-NEXT: [[TMP14:%.*]] = load ptr, ptr [[TMP13]], align 8 // CHECK1-NEXT: [[TMP15:%.*]] = load volatile i8, ptr addrspace(3) [[TMP12]], align 1 // CHECK1-NEXT: store i8 [[TMP15]], ptr [[TMP14]], align 1 // CHECK1-NEXT: br label [[IFCONT4:%.*]] -// CHECK1: else3: +// CHECK1: else4: // CHECK1-NEXT: br label [[IFCONT4]] -// CHECK1: ifcont4: +// CHECK1: ifcont5 +// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK1-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK1-NEXT: [[WARP_MASTER5:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK1-NEXT: br i1 [[WARP_MASTER5]], label [[THEN6:%.*]], label [[ELSE7:%.*]] -// CHECK1: then6: +// CHECK1: then8: // CHECK1-NEXT: [[TMP16:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i64 0, i64 1 // CHECK1-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 8 // CHECK1-NEXT: [[TMP18:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[NVPTX_WARP_ID]] // CHECK1-NEXT: [[TMP19:%.*]] = load i32, ptr [[TMP17]], align 4 // CHECK1-NEXT: store volatile i32 [[TMP19]], ptr addrspace(3) [[TMP18]], align 4 // CHECK1-NEXT: br label [[IFCONT8:%.*]] -// CHECK1: else7: +// CHECK1: else9: // CHECK1-NEXT: br label [[IFCONT8]] -// CHECK1: ifcont8: +// CHECK1: ifcont10: +// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK1-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK1-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK1-NEXT: [[IS_ACTIVE_THREAD9:%.*]] = icmp ult i32 [[TMP3]], [[TMP20]] // CHECK1-NEXT: br i1 [[IS_ACTIVE_THREAD9]], label [[THEN10:%.*]], label [[ELSE11:%.*]] -// CHECK1: then10: +// CHECK1: then13: // CHECK1-NEXT: [[TMP21:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK1-NEXT: [[TMP22:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i64 0, i64 1 // CHECK1-NEXT: [[TMP23:%.*]] = load ptr, ptr [[TMP22]], align 8 // CHECK1-NEXT: [[TMP24:%.*]] = load volatile i32, ptr addrspace(3) [[TMP21]], align 4 // CHECK1-NEXT: store i32 [[TMP24]], ptr [[TMP23]], align 4 // CHECK1-NEXT: br label [[IFCONT12:%.*]] -// CHECK1: else11: +// CHECK1: else14: // CHECK1-NEXT: br label [[IFCONT12]] -// CHECK1: ifcont12: +// CHECK1: ifcont15: // CHECK1-NEXT: ret void // // @@ -579,7 +583,7 @@ int bar(int n){ // CHECK1-NEXT: [[TMP8:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_0:%.*]], ptr [[TMP4]], i32 [[TMP5]] // CHECK1-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_0]], ptr [[TMP8]], i32 0, i32 0 // CHECK1-NEXT: [[TMP9:%.*]] = load i8, ptr [[TMP7]], align 1 -// CHECK1-NEXT: store i8 [[TMP9]], ptr [[C]], align 4 +// CHECK1-NEXT: store i8 [[TMP9]], ptr [[C]], align 1 // CHECK1-NEXT: [[TMP10:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP3]], i64 0, i64 1 // CHECK1-NEXT: [[TMP11:%.*]] = load ptr, ptr [[TMP10]], align 8 // CHECK1-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_0]], ptr [[TMP4]], i32 [[TMP5]] @@ -630,7 +634,7 @@ int bar(int n){ // CHECK1-NEXT: [[TMP7:%.*]] = load ptr, ptr [[TMP6]], align 8 // CHECK1-NEXT: [[TMP8:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_0:%.*]], ptr [[TMP4]], i32 [[TMP5]] // CHECK1-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_0]], ptr [[TMP8]], i32 0, i32 0 -// CHECK1-NEXT: [[TMP9:%.*]] = load i8, ptr [[C]], align 4 +// CHECK1-NEXT: [[TMP9:%.*]] = load i8, ptr [[C]], align 1 // CHECK1-NEXT: store i8 [[TMP9]], ptr [[TMP7]], align 1 // CHECK1-NEXT: [[TMP10:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP3]], i64 0, i64 1 // CHECK1-NEXT: [[TMP11:%.*]] = load ptr, ptr [[TMP10]], align 8 @@ -909,7 +913,6 @@ int bar(int n){ // CHECK1-NEXT: entry: // CHECK1-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 -// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK1-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() @@ -918,6 +921,7 @@ int bar(int n){ // CHECK1-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() // CHECK1-NEXT: [[NVPTX_WARP_ID:%.*]] = ashr i32 [[TMP5]], 5 // CHECK1-NEXT: [[TMP6:%.*]] = load ptr, ptr [[DOTADDR]], align 8 +// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK1-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK1-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK1-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] @@ -931,47 +935,50 @@ int bar(int n){ // CHECK1: else: // CHECK1-NEXT: br label [[IFCONT]] // CHECK1: ifcont: +// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK1-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK1-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP11]] // CHECK1-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// CHECK1: then2: +// CHECK1: then3: // CHECK1-NEXT: [[TMP12:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK1-NEXT: [[TMP13:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i64 0, i64 0 // CHECK1-NEXT: [[TMP14:%.*]] = load ptr, ptr [[TMP13]], align 8 // CHECK1-NEXT: [[TMP15:%.*]] = load volatile i32, ptr addrspace(3) [[TMP12]], align 4 // CHECK1-NEXT: store i32 [[TMP15]], ptr [[TMP14]], align 4 // CHECK1-NEXT: br label [[IFCONT4:%.*]] -// CHECK1: else3: +// CHECK1: else4: // CHECK1-NEXT: br label [[IFCONT4]] -// CHECK1: ifcont4: +// CHECK1: ifcont5: +// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK1-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK1-NEXT: [[WARP_MASTER5:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK1-NEXT: br i1 [[WARP_MASTER5]], label [[THEN6:%.*]], label [[ELSE7:%.*]] -// CHECK1: then6: +// CHECK1: then8: // CHECK1-NEXT: [[TMP16:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i64 0, i64 1 // CHECK1-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 8 // CHECK1-NEXT: [[TMP18:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[NVPTX_WARP_ID]] // CHECK1-NEXT: [[TMP19:%.*]] = load i16, ptr [[TMP17]], align 2 // CHECK1-NEXT: store volatile i16 [[TMP19]], ptr addrspace(3) [[TMP18]], align 2 // CHECK1-NEXT: br label [[IFCONT8:%.*]] -// CHECK1: else7: +// CHECK1: else9: // CHECK1-NEXT: br label [[IFCONT8]] -// CHECK1: ifcont8: +// CHECK1: ifcont10: +// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK1-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK1-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK1-NEXT: [[IS_ACTIVE_THREAD9:%.*]] = icmp ult i32 [[TMP3]], [[TMP20]] // CHECK1-NEXT: br i1 [[IS_ACTIVE_THREAD9]], label [[THEN10:%.*]], label [[ELSE11:%.*]] -// CHECK1: then10: +// CHECK1: then13: // CHECK1-NEXT: [[TMP21:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK1-NEXT: [[TMP22:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i64 0, i64 1 // CHECK1-NEXT: [[TMP23:%.*]] = load ptr, ptr [[TMP22]], align 8 // CHECK1-NEXT: [[TMP24:%.*]] = load volatile i16, ptr addrspace(3) [[TMP21]], align 2 // CHECK1-NEXT: store i16 [[TMP24]], ptr [[TMP23]], align 2 // CHECK1-NEXT: br label [[IFCONT12:%.*]] -// CHECK1: else11: +// CHECK1: else14: // CHECK1-NEXT: br label [[IFCONT12]] -// CHECK1: ifcont12: +// CHECK1: ifcont15: // CHECK1-NEXT: ret void // // @@ -1067,7 +1074,6 @@ int bar(int n){ // CHECK1-NEXT: entry: // CHECK1-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8 // CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 -// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK1-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK1-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() @@ -1076,6 +1082,7 @@ int bar(int n){ // CHECK1-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() // CHECK1-NEXT: [[NVPTX_WARP_ID:%.*]] = ashr i32 [[TMP5]], 5 // CHECK1-NEXT: [[TMP6:%.*]] = load ptr, ptr [[DOTADDR]], align 8 +// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK1-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK1-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK1-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] @@ -1089,47 +1096,50 @@ int bar(int n){ // CHECK1: else: // CHECK1-NEXT: br label [[IFCONT]] // CHECK1: ifcont: +// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK1-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK1-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP11]] // CHECK1-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// CHECK1: then2: +// CHECK1: then3: // CHECK1-NEXT: [[TMP12:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK1-NEXT: [[TMP13:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i64 0, i64 0 // CHECK1-NEXT: [[TMP14:%.*]] = load ptr, ptr [[TMP13]], align 8 // CHECK1-NEXT: [[TMP15:%.*]] = load volatile i32, ptr addrspace(3) [[TMP12]], align 4 // CHECK1-NEXT: store i32 [[TMP15]], ptr [[TMP14]], align 4 // CHECK1-NEXT: br label [[IFCONT4:%.*]] -// CHECK1: else3: +// CHECK1: else4: // CHECK1-NEXT: br label [[IFCONT4]] -// CHECK1: ifcont4: +// CHECK1: ifcont5: +// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK1-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK1-NEXT: [[WARP_MASTER5:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK1-NEXT: br i1 [[WARP_MASTER5]], label [[THEN6:%.*]], label [[ELSE7:%.*]] -// CHECK1: then6: +// CHECK1: then8: // CHECK1-NEXT: [[TMP16:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i64 0, i64 1 // CHECK1-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 8 // CHECK1-NEXT: [[TMP18:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[NVPTX_WARP_ID]] // CHECK1-NEXT: [[TMP19:%.*]] = load i16, ptr [[TMP17]], align 2 // CHECK1-NEXT: store volatile i16 [[TMP19]], ptr addrspace(3) [[TMP18]], align 2 // CHECK1-NEXT: br label [[IFCONT8:%.*]] -// CHECK1: else7: +// CHECK1: else9: // CHECK1-NEXT: br label [[IFCONT8]] -// CHECK1: ifcont8: +// CHECK1: ifcont10: +// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK1-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK1-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK1-NEXT: [[IS_ACTIVE_THREAD9:%.*]] = icmp ult i32 [[TMP3]], [[TMP20]] // CHECK1-NEXT: br i1 [[IS_ACTIVE_THREAD9]], label [[THEN10:%.*]], label [[ELSE11:%.*]] -// CHECK1: then10: +// CHECK1: then13: // CHECK1-NEXT: [[TMP21:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK1-NEXT: [[TMP22:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i64 0, i64 1 // CHECK1-NEXT: [[TMP23:%.*]] = load ptr, ptr [[TMP22]], align 8 // CHECK1-NEXT: [[TMP24:%.*]] = load volatile i16, ptr addrspace(3) [[TMP21]], align 2 // CHECK1-NEXT: store i16 [[TMP24]], ptr [[TMP23]], align 2 // CHECK1-NEXT: br label [[IFCONT12:%.*]] -// CHECK1: else11: +// CHECK1: else14: // CHECK1-NEXT: br label [[IFCONT12]] -// CHECK1: ifcont12: +// CHECK1: ifcont15: // CHECK1-NEXT: ret void // // @@ -1156,7 +1166,7 @@ int bar(int n){ // CHECK1-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_2]], ptr [[TMP4]], i32 [[TMP5]] // CHECK1-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_2]], ptr [[TMP12]], i32 0, i32 1 // CHECK1-NEXT: [[TMP13:%.*]] = load i16, ptr [[TMP11]], align 2 -// CHECK1-NEXT: store i16 [[TMP13]], ptr [[B]], align 4 +// CHECK1-NEXT: store i16 [[TMP13]], ptr [[B]], align 2 // CHECK1-NEXT: ret void // // @@ -1207,7 +1217,7 @@ int bar(int n){ // CHECK1-NEXT: [[TMP11:%.*]] = load ptr, ptr [[TMP10]], align 8 // CHECK1-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_2]], ptr [[TMP4]], i32 [[TMP5]] // CHECK1-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_2]], ptr [[TMP12]], i32 0, i32 1 -// CHECK1-NEXT: [[TMP13:%.*]] = load i16, ptr [[B]], align 4 +// CHECK1-NEXT: [[TMP13:%.*]] = load i16, ptr [[B]], align 2 // CHECK1-NEXT: store i16 [[TMP13]], ptr [[TMP11]], align 2 // CHECK1-NEXT: ret void // @@ -1369,7 +1379,6 @@ int bar(int n){ // CHECK2-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 4 // CHECK2-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 // CHECK2-NEXT: [[DOTCNT_ADDR:%.*]] = alloca i32, align 4 -// CHECK2-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK2-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 4 // CHECK2-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK2-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() @@ -1385,6 +1394,7 @@ int bar(int n){ // CHECK2-NEXT: [[TMP8:%.*]] = icmp ult i32 [[TMP7]], 2 // CHECK2-NEXT: br i1 [[TMP8]], label [[BODY:%.*]], label [[EXIT:%.*]] // CHECK2: body: +// CHECK2-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK2-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2:[0-9]+]], i32 [[TMP2]]) // CHECK2-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK2-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] @@ -1399,11 +1409,12 @@ int bar(int n){ // CHECK2: else: // CHECK2-NEXT: br label [[IFCONT]] // CHECK2: ifcont: +// CHECK2-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK2-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK2-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK2-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP14]] // CHECK2-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// CHECK2: then2: +// CHECK2: then3: // CHECK2-NEXT: [[TMP15:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK2-NEXT: [[TMP16:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP6]], i32 0, i32 0 // CHECK2-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 4 @@ -1411,9 +1422,9 @@ int bar(int n){ // CHECK2-NEXT: [[TMP19:%.*]] = load volatile i32, ptr addrspace(3) [[TMP15]], align 4 // CHECK2-NEXT: store i32 [[TMP19]], ptr [[TMP18]], align 4 // CHECK2-NEXT: br label [[IFCONT4:%.*]] -// CHECK2: else3: +// CHECK2: else4: // CHECK2-NEXT: br label [[IFCONT4]] -// CHECK2: ifcont4: +// CHECK2: ifcont5: // CHECK2-NEXT: [[TMP20:%.*]] = add nsw i32 [[TMP7]], 1 // CHECK2-NEXT: store i32 [[TMP20]], ptr [[DOTCNT_ADDR]], align 4 // CHECK2-NEXT: br label [[PRECOND]] @@ -1683,7 +1694,6 @@ int bar(int n){ // CHECK2-NEXT: entry: // CHECK2-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 4 // CHECK2-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 -// CHECK2-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK2-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 4 // CHECK2-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK2-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() @@ -1692,6 +1702,7 @@ int bar(int n){ // CHECK2-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() // CHECK2-NEXT: [[NVPTX_WARP_ID:%.*]] = ashr i32 [[TMP5]], 5 // CHECK2-NEXT: [[TMP6:%.*]] = load ptr, ptr [[DOTADDR]], align 4 +// CHECK2-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK2-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK2-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK2-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] @@ -1705,47 +1716,50 @@ int bar(int n){ // CHECK2: else: // CHECK2-NEXT: br label [[IFCONT]] // CHECK2: ifcont: +// CHECK2-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK2-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK2-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK2-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP11]] // CHECK2-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// CHECK2: then2: +// CHECK2: then3: // CHECK2-NEXT: [[TMP12:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK2-NEXT: [[TMP13:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 0 // CHECK2-NEXT: [[TMP14:%.*]] = load ptr, ptr [[TMP13]], align 4 // CHECK2-NEXT: [[TMP15:%.*]] = load volatile i8, ptr addrspace(3) [[TMP12]], align 1 // CHECK2-NEXT: store i8 [[TMP15]], ptr [[TMP14]], align 1 // CHECK2-NEXT: br label [[IFCONT4:%.*]] -// CHECK2: else3: +// CHECK2: else4: // CHECK2-NEXT: br label [[IFCONT4]] -// CHECK2: ifcont4: +// CHECK2: ifcont5: +// CHECK2-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK2-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK2-NEXT: [[WARP_MASTER5:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK2-NEXT: br i1 [[WARP_MASTER5]], label [[THEN6:%.*]], label [[ELSE7:%.*]] -// CHECK2: then6: +// CHECK2: then8: // CHECK2-NEXT: [[TMP16:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 1 // CHECK2-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 4 // CHECK2-NEXT: [[TMP18:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[NVPTX_WARP_ID]] // CHECK2-NEXT: [[TMP19:%.*]] = load i32, ptr [[TMP17]], align 4 // CHECK2-NEXT: store volatile i32 [[TMP19]], ptr addrspace(3) [[TMP18]], align 4 // CHECK2-NEXT: br label [[IFCONT8:%.*]] -// CHECK2: else7: +// CHECK2: else9: // CHECK2-NEXT: br label [[IFCONT8]] -// CHECK2: ifcont8: +// CHECK2: ifcont10: +// CHECK2-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK2-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK2-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK2-NEXT: [[IS_ACTIVE_THREAD9:%.*]] = icmp ult i32 [[TMP3]], [[TMP20]] // CHECK2-NEXT: br i1 [[IS_ACTIVE_THREAD9]], label [[THEN10:%.*]], label [[ELSE11:%.*]] -// CHECK2: then10: +// CHECK2: then13: // CHECK2-NEXT: [[TMP21:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK2-NEXT: [[TMP22:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 1 // CHECK2-NEXT: [[TMP23:%.*]] = load ptr, ptr [[TMP22]], align 4 // CHECK2-NEXT: [[TMP24:%.*]] = load volatile i32, ptr addrspace(3) [[TMP21]], align 4 // CHECK2-NEXT: store i32 [[TMP24]], ptr [[TMP23]], align 4 // CHECK2-NEXT: br label [[IFCONT12:%.*]] -// CHECK2: else11: +// CHECK2: else14: // CHECK2-NEXT: br label [[IFCONT12]] -// CHECK2: ifcont12: +// CHECK2: ifcont15: // CHECK2-NEXT: ret void // // @@ -1766,7 +1780,7 @@ int bar(int n){ // CHECK2-NEXT: [[TMP8:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_0:%.*]], ptr [[TMP4]], i32 [[TMP5]] // CHECK2-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_0]], ptr [[TMP8]], i32 0, i32 0 // CHECK2-NEXT: [[TMP9:%.*]] = load i8, ptr [[TMP7]], align 1 -// CHECK2-NEXT: store i8 [[TMP9]], ptr [[C]], align 4 +// CHECK2-NEXT: store i8 [[TMP9]], ptr [[C]], align 1 // CHECK2-NEXT: [[TMP10:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP3]], i32 0, i32 1 // CHECK2-NEXT: [[TMP11:%.*]] = load ptr, ptr [[TMP10]], align 4 // CHECK2-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_0]], ptr [[TMP4]], i32 [[TMP5]] @@ -1817,7 +1831,7 @@ int bar(int n){ // CHECK2-NEXT: [[TMP7:%.*]] = load ptr, ptr [[TMP6]], align 4 // CHECK2-NEXT: [[TMP8:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_0:%.*]], ptr [[TMP4]], i32 [[TMP5]] // CHECK2-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_0]], ptr [[TMP8]], i32 0, i32 0 -// CHECK2-NEXT: [[TMP9:%.*]] = load i8, ptr [[C]], align 4 +// CHECK2-NEXT: [[TMP9:%.*]] = load i8, ptr [[C]], align 1 // CHECK2-NEXT: store i8 [[TMP9]], ptr [[TMP7]], align 1 // CHECK2-NEXT: [[TMP10:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP3]], i32 0, i32 1 // CHECK2-NEXT: [[TMP11:%.*]] = load ptr, ptr [[TMP10]], align 4 @@ -2096,7 +2110,6 @@ int bar(int n){ // CHECK2-NEXT: entry: // CHECK2-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 4 // CHECK2-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 -// CHECK2-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK2-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 4 // CHECK2-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK2-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() @@ -2105,6 +2118,7 @@ int bar(int n){ // CHECK2-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() // CHECK2-NEXT: [[NVPTX_WARP_ID:%.*]] = ashr i32 [[TMP5]], 5 // CHECK2-NEXT: [[TMP6:%.*]] = load ptr, ptr [[DOTADDR]], align 4 +// CHECK2-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK2-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK2-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK2-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] @@ -2118,47 +2132,50 @@ int bar(int n){ // CHECK2: else: // CHECK2-NEXT: br label [[IFCONT]] // CHECK2: ifcont: +// CHECK2-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK2-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK2-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK2-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP11]] // CHECK2-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// CHECK2: then2: +// CHECK2: then3: // CHECK2-NEXT: [[TMP12:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK2-NEXT: [[TMP13:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 0 // CHECK2-NEXT: [[TMP14:%.*]] = load ptr, ptr [[TMP13]], align 4 // CHECK2-NEXT: [[TMP15:%.*]] = load volatile i32, ptr addrspace(3) [[TMP12]], align 4 // CHECK2-NEXT: store i32 [[TMP15]], ptr [[TMP14]], align 4 // CHECK2-NEXT: br label [[IFCONT4:%.*]] -// CHECK2: else3: +// CHECK2: else4: // CHECK2-NEXT: br label [[IFCONT4]] -// CHECK2: ifcont4: +// CHECK2: ifcont5: +// CHECK2-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK2-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK2-NEXT: [[WARP_MASTER5:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK2-NEXT: br i1 [[WARP_MASTER5]], label [[THEN6:%.*]], label [[ELSE7:%.*]] -// CHECK2: then6: +// CHECK2: then8: // CHECK2-NEXT: [[TMP16:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 1 // CHECK2-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 4 // CHECK2-NEXT: [[TMP18:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[NVPTX_WARP_ID]] // CHECK2-NEXT: [[TMP19:%.*]] = load i16, ptr [[TMP17]], align 2 // CHECK2-NEXT: store volatile i16 [[TMP19]], ptr addrspace(3) [[TMP18]], align 2 // CHECK2-NEXT: br label [[IFCONT8:%.*]] -// CHECK2: else7: +// CHECK2: else9: // CHECK2-NEXT: br label [[IFCONT8]] -// CHECK2: ifcont8: +// CHECK2: ifcont10: +// CHECK2-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK2-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK2-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK2-NEXT: [[IS_ACTIVE_THREAD9:%.*]] = icmp ult i32 [[TMP3]], [[TMP20]] // CHECK2-NEXT: br i1 [[IS_ACTIVE_THREAD9]], label [[THEN10:%.*]], label [[ELSE11:%.*]] -// CHECK2: then10: +// CHECK2: then13: // CHECK2-NEXT: [[TMP21:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK2-NEXT: [[TMP22:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 1 // CHECK2-NEXT: [[TMP23:%.*]] = load ptr, ptr [[TMP22]], align 4 // CHECK2-NEXT: [[TMP24:%.*]] = load volatile i16, ptr addrspace(3) [[TMP21]], align 2 // CHECK2-NEXT: store i16 [[TMP24]], ptr [[TMP23]], align 2 // CHECK2-NEXT: br label [[IFCONT12:%.*]] -// CHECK2: else11: +// CHECK2: else14: // CHECK2-NEXT: br label [[IFCONT12]] -// CHECK2: ifcont12: +// CHECK2: ifcont15: // CHECK2-NEXT: ret void // // @@ -2254,7 +2271,6 @@ int bar(int n){ // CHECK2-NEXT: entry: // CHECK2-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 4 // CHECK2-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 -// CHECK2-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK2-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 4 // CHECK2-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK2-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() @@ -2263,6 +2279,7 @@ int bar(int n){ // CHECK2-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() // CHECK2-NEXT: [[NVPTX_WARP_ID:%.*]] = ashr i32 [[TMP5]], 5 // CHECK2-NEXT: [[TMP6:%.*]] = load ptr, ptr [[DOTADDR]], align 4 +// CHECK2-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK2-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK2-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK2-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] @@ -2276,47 +2293,50 @@ int bar(int n){ // CHECK2: else: // CHECK2-NEXT: br label [[IFCONT]] // CHECK2: ifcont: +// CHECK2-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK2-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK2-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK2-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP11]] // CHECK2-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// CHECK2: then2: +// CHECK2: then3: // CHECK2-NEXT: [[TMP12:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK2-NEXT: [[TMP13:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 0 // CHECK2-NEXT: [[TMP14:%.*]] = load ptr, ptr [[TMP13]], align 4 // CHECK2-NEXT: [[TMP15:%.*]] = load volatile i32, ptr addrspace(3) [[TMP12]], align 4 // CHECK2-NEXT: store i32 [[TMP15]], ptr [[TMP14]], align 4 // CHECK2-NEXT: br label [[IFCONT4:%.*]] -// CHECK2: else3: +// CHECK2: else4: // CHECK2-NEXT: br label [[IFCONT4]] -// CHECK2: ifcont4: +// CHECK2: ifcont5: +// CHECK2-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK2-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK2-NEXT: [[WARP_MASTER5:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK2-NEXT: br i1 [[WARP_MASTER5]], label [[THEN6:%.*]], label [[ELSE7:%.*]] -// CHECK2: then6: +// CHECK2: then8: // CHECK2-NEXT: [[TMP16:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 1 // CHECK2-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 4 // CHECK2-NEXT: [[TMP18:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[NVPTX_WARP_ID]] // CHECK2-NEXT: [[TMP19:%.*]] = load i16, ptr [[TMP17]], align 2 // CHECK2-NEXT: store volatile i16 [[TMP19]], ptr addrspace(3) [[TMP18]], align 2 // CHECK2-NEXT: br label [[IFCONT8:%.*]] -// CHECK2: else7: +// CHECK2: else9: // CHECK2-NEXT: br label [[IFCONT8]] -// CHECK2: ifcont8: +// CHECK2: ifcont10: +// CHECK2-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK2-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK2-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK2-NEXT: [[IS_ACTIVE_THREAD9:%.*]] = icmp ult i32 [[TMP3]], [[TMP20]] // CHECK2-NEXT: br i1 [[IS_ACTIVE_THREAD9]], label [[THEN10:%.*]], label [[ELSE11:%.*]] -// CHECK2: then10: +// CHECK2: then13: // CHECK2-NEXT: [[TMP21:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK2-NEXT: [[TMP22:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 1 // CHECK2-NEXT: [[TMP23:%.*]] = load ptr, ptr [[TMP22]], align 4 // CHECK2-NEXT: [[TMP24:%.*]] = load volatile i16, ptr addrspace(3) [[TMP21]], align 2 // CHECK2-NEXT: store i16 [[TMP24]], ptr [[TMP23]], align 2 // CHECK2-NEXT: br label [[IFCONT12:%.*]] -// CHECK2: else11: +// CHECK2: else14: // CHECK2-NEXT: br label [[IFCONT12]] -// CHECK2: ifcont12: +// CHECK2: ifcont15: // CHECK2-NEXT: ret void // // @@ -2343,7 +2363,7 @@ int bar(int n){ // CHECK2-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_2]], ptr [[TMP4]], i32 [[TMP5]] // CHECK2-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_2]], ptr [[TMP12]], i32 0, i32 1 // CHECK2-NEXT: [[TMP13:%.*]] = load i16, ptr [[TMP11]], align 2 -// CHECK2-NEXT: store i16 [[TMP13]], ptr [[B]], align 4 +// CHECK2-NEXT: store i16 [[TMP13]], ptr [[B]], align 2 // CHECK2-NEXT: ret void // // @@ -2394,7 +2414,7 @@ int bar(int n){ // CHECK2-NEXT: [[TMP11:%.*]] = load ptr, ptr [[TMP10]], align 4 // CHECK2-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_2]], ptr [[TMP4]], i32 [[TMP5]] // CHECK2-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_2]], ptr [[TMP12]], i32 0, i32 1 -// CHECK2-NEXT: [[TMP13:%.*]] = load i16, ptr [[B]], align 4 +// CHECK2-NEXT: [[TMP13:%.*]] = load i16, ptr [[B]], align 2 // CHECK2-NEXT: store i16 [[TMP13]], ptr [[TMP11]], align 2 // CHECK2-NEXT: ret void // @@ -2556,7 +2576,6 @@ int bar(int n){ // CHECK3-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 4 // CHECK3-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 // CHECK3-NEXT: [[DOTCNT_ADDR:%.*]] = alloca i32, align 4 -// CHECK3-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK3-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 4 // CHECK3-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK3-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() @@ -2572,6 +2591,7 @@ int bar(int n){ // CHECK3-NEXT: [[TMP8:%.*]] = icmp ult i32 [[TMP7]], 2 // CHECK3-NEXT: br i1 [[TMP8]], label [[BODY:%.*]], label [[EXIT:%.*]] // CHECK3: body: +// CHECK3-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK3-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2:[0-9]+]], i32 [[TMP2]]) // CHECK3-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK3-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] @@ -2586,11 +2606,12 @@ int bar(int n){ // CHECK3: else: // CHECK3-NEXT: br label [[IFCONT]] // CHECK3: ifcont: +// CHECK3-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK3-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK3-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK3-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP14]] // CHECK3-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// CHECK3: then2: +// CHECK3: then3: // CHECK3-NEXT: [[TMP15:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK3-NEXT: [[TMP16:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP6]], i32 0, i32 0 // CHECK3-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 4 @@ -2598,9 +2619,9 @@ int bar(int n){ // CHECK3-NEXT: [[TMP19:%.*]] = load volatile i32, ptr addrspace(3) [[TMP15]], align 4 // CHECK3-NEXT: store i32 [[TMP19]], ptr [[TMP18]], align 4 // CHECK3-NEXT: br label [[IFCONT4:%.*]] -// CHECK3: else3: +// CHECK3: else4: // CHECK3-NEXT: br label [[IFCONT4]] -// CHECK3: ifcont4: +// CHECK3: ifcont5: // CHECK3-NEXT: [[TMP20:%.*]] = add nsw i32 [[TMP7]], 1 // CHECK3-NEXT: store i32 [[TMP20]], ptr [[DOTCNT_ADDR]], align 4 // CHECK3-NEXT: br label [[PRECOND]] @@ -2870,7 +2891,6 @@ int bar(int n){ // CHECK3-NEXT: entry: // CHECK3-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 4 // CHECK3-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 -// CHECK3-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK3-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 4 // CHECK3-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK3-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() @@ -2879,6 +2899,7 @@ int bar(int n){ // CHECK3-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() // CHECK3-NEXT: [[NVPTX_WARP_ID:%.*]] = ashr i32 [[TMP5]], 5 // CHECK3-NEXT: [[TMP6:%.*]] = load ptr, ptr [[DOTADDR]], align 4 +// CHECK3-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK3-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK3-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK3-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] @@ -2892,47 +2913,50 @@ int bar(int n){ // CHECK3: else: // CHECK3-NEXT: br label [[IFCONT]] // CHECK3: ifcont: +// CHECK3-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK3-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK3-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK3-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP11]] // CHECK3-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// CHECK3: then2: +// CHECK3: then3: // CHECK3-NEXT: [[TMP12:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK3-NEXT: [[TMP13:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 0 // CHECK3-NEXT: [[TMP14:%.*]] = load ptr, ptr [[TMP13]], align 4 // CHECK3-NEXT: [[TMP15:%.*]] = load volatile i8, ptr addrspace(3) [[TMP12]], align 1 // CHECK3-NEXT: store i8 [[TMP15]], ptr [[TMP14]], align 1 // CHECK3-NEXT: br label [[IFCONT4:%.*]] -// CHECK3: else3: +// CHECK3: else4: // CHECK3-NEXT: br label [[IFCONT4]] -// CHECK3: ifcont4: +// CHECK3: ifcont5: +// CHECK3-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK3-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK3-NEXT: [[WARP_MASTER5:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK3-NEXT: br i1 [[WARP_MASTER5]], label [[THEN6:%.*]], label [[ELSE7:%.*]] -// CHECK3: then6: +// CHECK3: then8: // CHECK3-NEXT: [[TMP16:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 1 // CHECK3-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 4 // CHECK3-NEXT: [[TMP18:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[NVPTX_WARP_ID]] // CHECK3-NEXT: [[TMP19:%.*]] = load i32, ptr [[TMP17]], align 4 // CHECK3-NEXT: store volatile i32 [[TMP19]], ptr addrspace(3) [[TMP18]], align 4 // CHECK3-NEXT: br label [[IFCONT8:%.*]] -// CHECK3: else7: +// CHECK3: else9: // CHECK3-NEXT: br label [[IFCONT8]] -// CHECK3: ifcont8: +// CHECK3: ifcont10: +// CHECK3-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK3-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK3-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK3-NEXT: [[IS_ACTIVE_THREAD9:%.*]] = icmp ult i32 [[TMP3]], [[TMP20]] // CHECK3-NEXT: br i1 [[IS_ACTIVE_THREAD9]], label [[THEN10:%.*]], label [[ELSE11:%.*]] -// CHECK3: then10: +// CHECK3: then13: // CHECK3-NEXT: [[TMP21:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK3-NEXT: [[TMP22:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 1 // CHECK3-NEXT: [[TMP23:%.*]] = load ptr, ptr [[TMP22]], align 4 // CHECK3-NEXT: [[TMP24:%.*]] = load volatile i32, ptr addrspace(3) [[TMP21]], align 4 // CHECK3-NEXT: store i32 [[TMP24]], ptr [[TMP23]], align 4 // CHECK3-NEXT: br label [[IFCONT12:%.*]] -// CHECK3: else11: +// CHECK3: else14: // CHECK3-NEXT: br label [[IFCONT12]] -// CHECK3: ifcont12: +// CHECK3: ifcont15: // CHECK3-NEXT: ret void // // @@ -2953,7 +2977,7 @@ int bar(int n){ // CHECK3-NEXT: [[TMP8:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_0:%.*]], ptr [[TMP4]], i32 [[TMP5]] // CHECK3-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_0]], ptr [[TMP8]], i32 0, i32 0 // CHECK3-NEXT: [[TMP9:%.*]] = load i8, ptr [[TMP7]], align 1 -// CHECK3-NEXT: store i8 [[TMP9]], ptr [[C]], align 4 +// CHECK3-NEXT: store i8 [[TMP9]], ptr [[C]], align 1 // CHECK3-NEXT: [[TMP10:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP3]], i32 0, i32 1 // CHECK3-NEXT: [[TMP11:%.*]] = load ptr, ptr [[TMP10]], align 4 // CHECK3-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_0]], ptr [[TMP4]], i32 [[TMP5]] @@ -3004,7 +3028,7 @@ int bar(int n){ // CHECK3-NEXT: [[TMP7:%.*]] = load ptr, ptr [[TMP6]], align 4 // CHECK3-NEXT: [[TMP8:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_0:%.*]], ptr [[TMP4]], i32 [[TMP5]] // CHECK3-NEXT: [[C:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_0]], ptr [[TMP8]], i32 0, i32 0 -// CHECK3-NEXT: [[TMP9:%.*]] = load i8, ptr [[C]], align 4 +// CHECK3-NEXT: [[TMP9:%.*]] = load i8, ptr [[C]], align 1 // CHECK3-NEXT: store i8 [[TMP9]], ptr [[TMP7]], align 1 // CHECK3-NEXT: [[TMP10:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP3]], i32 0, i32 1 // CHECK3-NEXT: [[TMP11:%.*]] = load ptr, ptr [[TMP10]], align 4 @@ -3283,7 +3307,6 @@ int bar(int n){ // CHECK3-NEXT: entry: // CHECK3-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 4 // CHECK3-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 -// CHECK3-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK3-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 4 // CHECK3-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK3-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() @@ -3292,6 +3315,7 @@ int bar(int n){ // CHECK3-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() // CHECK3-NEXT: [[NVPTX_WARP_ID:%.*]] = ashr i32 [[TMP5]], 5 // CHECK3-NEXT: [[TMP6:%.*]] = load ptr, ptr [[DOTADDR]], align 4 +// CHECK3-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK3-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK3-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK3-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] @@ -3305,47 +3329,50 @@ int bar(int n){ // CHECK3: else: // CHECK3-NEXT: br label [[IFCONT]] // CHECK3: ifcont: +// CHECK3-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK3-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK3-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK3-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP11]] // CHECK3-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// CHECK3: then2: +// CHECK3: then3: // CHECK3-NEXT: [[TMP12:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK3-NEXT: [[TMP13:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 0 // CHECK3-NEXT: [[TMP14:%.*]] = load ptr, ptr [[TMP13]], align 4 // CHECK3-NEXT: [[TMP15:%.*]] = load volatile i32, ptr addrspace(3) [[TMP12]], align 4 // CHECK3-NEXT: store i32 [[TMP15]], ptr [[TMP14]], align 4 // CHECK3-NEXT: br label [[IFCONT4:%.*]] -// CHECK3: else3: +// CHECK3: else4: // CHECK3-NEXT: br label [[IFCONT4]] -// CHECK3: ifcont4: +// CHECK3: ifcont5: +// CHECK3-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK3-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK3-NEXT: [[WARP_MASTER5:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK3-NEXT: br i1 [[WARP_MASTER5]], label [[THEN6:%.*]], label [[ELSE7:%.*]] -// CHECK3: then6: +// CHECK3: then8: // CHECK3-NEXT: [[TMP16:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 1 // CHECK3-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 4 // CHECK3-NEXT: [[TMP18:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[NVPTX_WARP_ID]] // CHECK3-NEXT: [[TMP19:%.*]] = load i16, ptr [[TMP17]], align 2 // CHECK3-NEXT: store volatile i16 [[TMP19]], ptr addrspace(3) [[TMP18]], align 2 // CHECK3-NEXT: br label [[IFCONT8:%.*]] -// CHECK3: else7: +// CHECK3: else9: // CHECK3-NEXT: br label [[IFCONT8]] -// CHECK3: ifcont8: +// CHECK3: ifcont10: +// CHECK3-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK3-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK3-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK3-NEXT: [[IS_ACTIVE_THREAD9:%.*]] = icmp ult i32 [[TMP3]], [[TMP20]] // CHECK3-NEXT: br i1 [[IS_ACTIVE_THREAD9]], label [[THEN10:%.*]], label [[ELSE11:%.*]] -// CHECK3: then10: +// CHECK3: then13: // CHECK3-NEXT: [[TMP21:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK3-NEXT: [[TMP22:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 1 // CHECK3-NEXT: [[TMP23:%.*]] = load ptr, ptr [[TMP22]], align 4 // CHECK3-NEXT: [[TMP24:%.*]] = load volatile i16, ptr addrspace(3) [[TMP21]], align 2 // CHECK3-NEXT: store i16 [[TMP24]], ptr [[TMP23]], align 2 // CHECK3-NEXT: br label [[IFCONT12:%.*]] -// CHECK3: else11: +// CHECK3: else14: // CHECK3-NEXT: br label [[IFCONT12]] -// CHECK3: ifcont12: +// CHECK3: ifcont15: // CHECK3-NEXT: ret void // // @@ -3441,7 +3468,6 @@ int bar(int n){ // CHECK3-NEXT: entry: // CHECK3-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 4 // CHECK3-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 -// CHECK3-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK3-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 4 // CHECK3-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK3-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() @@ -3450,6 +3476,7 @@ int bar(int n){ // CHECK3-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() // CHECK3-NEXT: [[NVPTX_WARP_ID:%.*]] = ashr i32 [[TMP5]], 5 // CHECK3-NEXT: [[TMP6:%.*]] = load ptr, ptr [[DOTADDR]], align 4 +// CHECK3-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK3-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK3-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK3-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] @@ -3463,47 +3490,50 @@ int bar(int n){ // CHECK3: else: // CHECK3-NEXT: br label [[IFCONT]] // CHECK3: ifcont: +// CHECK3-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK3-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK3-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK3-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP11]] // CHECK3-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// CHECK3: then2: +// CHECK3: then3: // CHECK3-NEXT: [[TMP12:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK3-NEXT: [[TMP13:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 0 // CHECK3-NEXT: [[TMP14:%.*]] = load ptr, ptr [[TMP13]], align 4 // CHECK3-NEXT: [[TMP15:%.*]] = load volatile i32, ptr addrspace(3) [[TMP12]], align 4 // CHECK3-NEXT: store i32 [[TMP15]], ptr [[TMP14]], align 4 // CHECK3-NEXT: br label [[IFCONT4:%.*]] -// CHECK3: else3: +// CHECK3: else4: // CHECK3-NEXT: br label [[IFCONT4]] -// CHECK3: ifcont4: +// CHECK3: ifcont5: +// CHECK3-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK3-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK3-NEXT: [[WARP_MASTER5:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK3-NEXT: br i1 [[WARP_MASTER5]], label [[THEN6:%.*]], label [[ELSE7:%.*]] -// CHECK3: then6: +// CHECK3: then8: // CHECK3-NEXT: [[TMP16:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 1 // CHECK3-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 4 // CHECK3-NEXT: [[TMP18:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[NVPTX_WARP_ID]] // CHECK3-NEXT: [[TMP19:%.*]] = load i16, ptr [[TMP17]], align 2 // CHECK3-NEXT: store volatile i16 [[TMP19]], ptr addrspace(3) [[TMP18]], align 2 // CHECK3-NEXT: br label [[IFCONT8:%.*]] -// CHECK3: else7: +// CHECK3: else9: // CHECK3-NEXT: br label [[IFCONT8]] -// CHECK3: ifcont8: +// CHECK3: ifcont10: +// CHECK3-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK3-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK3-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK3-NEXT: [[IS_ACTIVE_THREAD9:%.*]] = icmp ult i32 [[TMP3]], [[TMP20]] // CHECK3-NEXT: br i1 [[IS_ACTIVE_THREAD9]], label [[THEN10:%.*]], label [[ELSE11:%.*]] -// CHECK3: then10: +// CHECK3: then13: // CHECK3-NEXT: [[TMP21:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK3-NEXT: [[TMP22:%.*]] = getelementptr inbounds [2 x ptr], ptr [[TMP6]], i32 0, i32 1 // CHECK3-NEXT: [[TMP23:%.*]] = load ptr, ptr [[TMP22]], align 4 // CHECK3-NEXT: [[TMP24:%.*]] = load volatile i16, ptr addrspace(3) [[TMP21]], align 2 // CHECK3-NEXT: store i16 [[TMP24]], ptr [[TMP23]], align 2 // CHECK3-NEXT: br label [[IFCONT12:%.*]] -// CHECK3: else11: +// CHECK3: else14: // CHECK3-NEXT: br label [[IFCONT12]] -// CHECK3: ifcont12: +// CHECK3: ifcont15: // CHECK3-NEXT: ret void // // @@ -3530,7 +3560,7 @@ int bar(int n){ // CHECK3-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_2]], ptr [[TMP4]], i32 [[TMP5]] // CHECK3-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_2]], ptr [[TMP12]], i32 0, i32 1 // CHECK3-NEXT: [[TMP13:%.*]] = load i16, ptr [[TMP11]], align 2 -// CHECK3-NEXT: store i16 [[TMP13]], ptr [[B]], align 4 +// CHECK3-NEXT: store i16 [[TMP13]], ptr [[B]], align 2 // CHECK3-NEXT: ret void // // @@ -3581,7 +3611,7 @@ int bar(int n){ // CHECK3-NEXT: [[TMP11:%.*]] = load ptr, ptr [[TMP10]], align 4 // CHECK3-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_2]], ptr [[TMP4]], i32 [[TMP5]] // CHECK3-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY_2]], ptr [[TMP12]], i32 0, i32 1 -// CHECK3-NEXT: [[TMP13:%.*]] = load i16, ptr [[B]], align 4 +// CHECK3-NEXT: [[TMP13:%.*]] = load i16, ptr [[B]], align 2 // CHECK3-NEXT: store i16 [[TMP13]], ptr [[TMP11]], align 2 // CHECK3-NEXT: ret void // diff --git a/clang/test/OpenMP/reduction_complex.c b/clang/test/OpenMP/reduction_complex.c new file mode 100644 index 00000000000000..e00caa8f90fdf7 --- /dev/null +++ b/clang/test/OpenMP/reduction_complex.c @@ -0,0 +1,96 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --include-generated-funcs --replace-value-regex "__omp_offloading_[0-9a-z]+_[0-9a-z]+" "reduction_size[.].+[.]" "pl_cond[.].+[.|,]" --prefix-filecheck-ir-name _ +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-cuda-mode -x c++ \ +// RUN: -triple powerpc64le-unknown-unknown \ +// RUN: -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o \ +// RUN: %t-ppc-host.bc + +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-cuda-mode -x c++ \ +// RUN: -triple nvptx64-unknown-unknown -DCUA \ +// RUN: -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s \ +// RUN: -fopenmp-is-target-device -fopenmp-host-ir-file-path %t-ppc-host.bc \ +// RUN: -o - | FileCheck %s --check-prefix CHECK + +// expected-no-diagnostics +int foo() { + int i; + int j; + _Complex float sum = 0; + +#pragma omp target teams loop reduction(+:sum) collapse(2) bind(parallel) order(concurrent) lastprivate(j) map(tofrom:sum) + + for(i=0; i<10; i++) + for(j=0; j<10; j++) + sum += i; + + return 0; +} +// CHECK-LABEL: define {{[^@]+}}@_omp_reduction_shuffle_and_reduce_func +// CHECK-SAME: (ptr noundef [[TMP0:%.*]], i16 noundef signext [[TMP1:%.*]], i16 noundef signext [[TMP2:%.*]], i16 noundef signext [[TMP3:%.*]]) #[[ATTR2:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: %[[VAL_228:.*]] = alloca ptr, align 8 +// CHECK-NEXT: %[[VAL_229:.*]] = alloca i16, align 2 +// CHECK-NEXT: %[[VAL_230:.*]] = alloca i16, align 2 +// CHECK-NEXT: %[[VAL_231:.*]] = alloca i16, align 2 +// CHECK-NEXT: %[[VAL_232:.*]] = alloca [1 x ptr], align 8 +// CHECK-NEXT: %[[VAL_233:.*]] = alloca { float, float }, align 8 +// CHECK-NEXT: store ptr %[[VAL_234:.*]], ptr %[[VAL_228]], align 8 +// CHECK-NEXT: store i16 %[[VAL_235:.*]], ptr %[[VAL_229]], align 2 +// CHECK-NEXT: store i16 %[[VAL_236:.*]], ptr %[[VAL_230]], align 2 +// CHECK-NEXT: store i16 %[[VAL_237:.*]], ptr %[[VAL_231]], align 2 +// CHECK-NEXT: %[[VAL_238:.*]] = load ptr, ptr %[[VAL_228]], align 8 +// CHECK-NEXT: %[[VAL_239:.*]] = load i16, ptr %[[VAL_229]], align 2 +// CHECK-NEXT: %[[VAL_240:.*]] = load i16, ptr %[[VAL_230]], align 2 +// CHECK-NEXT: %[[VAL_241:.*]] = load i16, ptr %[[VAL_231]], align 2 +// CHECK-NEXT: %[[VAL_242:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_238]], i64 0, i64 0 +// CHECK-NEXT: %[[VAL_243:.*]] = load ptr, ptr %[[VAL_242]], align 8 +// CHECK-NEXT: %[[VAL_244:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_232]], i64 0, i64 0 +// CHECK-NEXT: %[[VAL_245:.*]] = getelementptr { float, float }, ptr %[[VAL_243]], i64 1 +// CHECK-NEXT: %[[VAL_246:.*]] = load i64, ptr %[[VAL_243]], align 8 +// CHECK-NEXT: %[[VAL_247:.*]] = call i32 @__kmpc_get_warp_size() +// CHECK-NEXT: %[[VAL_248:.*]] = trunc i32 %[[VAL_247]] to i16 +// CHECK-NEXT: %[[VAL_249:.*]] = call i64 @__kmpc_shuffle_int64(i64 %[[VAL_246]], i16 %[[VAL_240]], i16 %[[VAL_248]]) +// CHECK-NEXT: store i64 %[[VAL_249]], ptr %[[VAL_233]], align 8 +// CHECK-NEXT: %[[VAL_250:.*]] = getelementptr i64, ptr %[[VAL_243]], i64 1 +// CHECK-NEXT: %[[VAL_251:.*]] = getelementptr i64, ptr %[[VAL_233]], i64 1 +// CHECK-NEXT: store ptr %[[VAL_233]], ptr %[[VAL_244]], align 8 +// CHECK-NEXT: %[[VAL_252:.*]] = icmp eq i16 %[[VAL_241]], 0 +// CHECK-NEXT: %[[VAL_253:.*]] = icmp eq i16 %[[VAL_241]], 1 +// CHECK-NEXT: %[[VAL_254:.*]] = icmp ult i16 %[[VAL_239]], %[[VAL_240]] +// CHECK-NEXT: %[[VAL_255:.*]] = and i1 %[[VAL_253]], %[[VAL_254]] +// CHECK-NEXT: %[[VAL_256:.*]] = icmp eq i16 %[[VAL_241]], 2 +// CHECK-NEXT: %[[VAL_257:.*]] = and i16 %[[VAL_239]], 1 +// CHECK-NEXT: %[[VAL_258:.*]] = icmp eq i16 %[[VAL_257]], 0 +// CHECK-NEXT: %[[VAL_259:.*]] = and i1 %[[VAL_256]], %[[VAL_258]] +// CHECK-NEXT: %[[VAL_260:.*]] = icmp sgt i16 %[[VAL_240]], 0 +// CHECK-NEXT: %[[VAL_261:.*]] = and i1 %[[VAL_259]], %[[VAL_260]] +// CHECK-NEXT: %[[VAL_262:.*]] = or i1 %[[VAL_252]], %[[VAL_255]] +// CHECK-NEXT: %[[VAL_263:.*]] = or i1 %[[VAL_262]], %[[VAL_261]] +// CHECK-NEXT: br i1 %[[VAL_263]], label %[[VAL_264:.*]], label %[[VAL_265:.*]] +// CHECK: then: ; preds = %[[VAL_266:.*]] +// CHECK-NEXT: call void @"{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3foov_l{{[0-9]+}}_omp_outlined_omp_outlined_omp$reduction$reduction_func"(ptr %[[VAL_238]], ptr %[[VAL_232]]) #2 +// CHECK-NEXT: br label %[[VAL_267:.*]] +// CHECK: else: ; preds = %[[VAL_266]] +// CHECK-NEXT: br label %[[VAL_267]] +// CHECK: ifcont: ; preds = %[[VAL_265]], %[[VAL_264]] +// CHECK-NEXT: %[[VAL_268:.*]] = icmp eq i16 %[[VAL_241]], 1 +// CHECK-NEXT: %[[VAL_269:.*]] = icmp uge i16 %[[VAL_239]], %[[VAL_240]] +// CHECK-NEXT: %[[VAL_270:.*]] = and i1 %[[VAL_268]], %[[VAL_269]] +// CHECK-NEXT: br i1 %[[VAL_270]], label %[[VAL_271:.*]], label %[[VAL_272:.*]] +// CHECK: then4: ; preds = %[[VAL_267]] +// CHECK-NEXT: %[[VAL_273:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_232]], i64 0, i64 0 +// CHECK-NEXT: %[[VAL_274:.*]] = load ptr, ptr %[[VAL_273]], align 8 +// CHECK-NEXT: %[[VAL_275:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_238]], i64 0, i64 0 +// CHECK-NEXT: %[[VAL_276:.*]] = load ptr, ptr %[[VAL_275]], align 8 +// CHECK-NEXT: %[[VAL_277:.*]] = getelementptr inbounds { float, float }, ptr %[[VAL_274]], i32 0, i32 0 +// CHECK-NEXT: %[[VAL_278:.*]] = load float, ptr %[[VAL_277]], align 4 +// CHECK-NEXT: %[[VAL_279:.*]] = getelementptr inbounds { float, float }, ptr %[[VAL_274]], i32 0, i32 1 +// CHECK-NEXT: %[[VAL_280:.*]] = load float, ptr %[[VAL_279]], align 4 +// CHECK-NEXT: %[[VAL_281:.*]] = getelementptr inbounds { float, float }, ptr %[[VAL_276]], i32 0, i32 0 +// CHECK-NEXT: %[[VAL_282:.*]] = getelementptr inbounds { float, float }, ptr %[[VAL_276]], i32 0, i32 1 +// CHECK-NEXT: store float %[[VAL_278]], ptr %[[VAL_281]], align 4 +// CHECK-NEXT: store float %[[VAL_280]], ptr %[[VAL_282]], align 4 +// CHECK-NEXT: br label %[[VAL_283:.*]] +// CHECK: else7: ; preds = %[[VAL_267]] +// CHECK-NEXT: br label %[[VAL_283]] +// CHECK: ifcont8: ; preds = %[[VAL_272]], %[[VAL_271]] +// CHECK-NEXT: ret void diff --git a/clang/test/OpenMP/reduction_implicit_map.cpp b/clang/test/OpenMP/reduction_implicit_map.cpp index 765e90bcba8531..78aca56acca308 100644 --- a/clang/test/OpenMP/reduction_implicit_map.cpp +++ b/clang/test/OpenMP/reduction_implicit_map.cpp @@ -233,7 +233,6 @@ int main() // CHECK-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8 // CHECK-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4 // CHECK-NEXT: [[DOTCNT_ADDR:%.*]] = alloca i32, align 4 -// CHECK-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8 // CHECK-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1]], align 4 // CHECK-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() @@ -249,6 +248,7 @@ int main() // CHECK-NEXT: [[TMP8:%.*]] = icmp ult i32 [[TMP7]], 2 // CHECK-NEXT: br i1 [[TMP8]], label [[BODY:%.*]], label [[EXIT:%.*]] // CHECK: body: +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2:[0-9]+]], i32 [[TMP2]]) // CHECK-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // CHECK-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] @@ -263,11 +263,12 @@ int main() // CHECK: else: // CHECK-NEXT: br label [[IFCONT]] // CHECK: ifcont: +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]]) // CHECK-NEXT: call void @__kmpc_barrier(ptr @[[GLOB2]], i32 [[TMP2]]) // CHECK-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTADDR1]], align 4 // CHECK-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP14]] // CHECK-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// CHECK: then2: +// CHECK: then3: // CHECK-NEXT: [[TMP15:%.*]] = getelementptr inbounds [32 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // CHECK-NEXT: [[TMP16:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP6]], i64 0, i64 0 // CHECK-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 8 @@ -275,9 +276,9 @@ int main() // CHECK-NEXT: [[TMP19:%.*]] = load volatile i32, ptr addrspace(3) [[TMP15]], align 4 // CHECK-NEXT: store i32 [[TMP19]], ptr [[TMP18]], align 4 // CHECK-NEXT: br label [[IFCONT4:%.*]] -// CHECK: else3: +// CHECK: else4: // CHECK-NEXT: br label [[IFCONT4]] -// CHECK: ifcont4: +// CHECK: ifcont5: // CHECK-NEXT: [[TMP20:%.*]] = add nsw i32 [[TMP7]], 1 // CHECK-NEXT: store i32 [[TMP20]], ptr [[DOTCNT_ADDR]], align 4 // CHECK-NEXT: br label [[PRECOND]] diff --git a/clang/test/OpenMP/target_teams_generic_loop_codegen.cpp b/clang/test/OpenMP/target_teams_generic_loop_codegen.cpp index 3f752ac663f412..e05b3209f9eff2 100644 --- a/clang/test/OpenMP/target_teams_generic_loop_codegen.cpp +++ b/clang/test/OpenMP/target_teams_generic_loop_codegen.cpp @@ -85,6 +85,7 @@ int foo() { // IR-GPU-NEXT: [[J_CASTED:%.*]] = alloca i64, align 8, addrspace(5) // IR-GPU-NEXT: [[CAPTURED_VARS_ADDRS:%.*]] = alloca [4 x ptr], align 8, addrspace(5) // IR-GPU-NEXT: [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [1 x ptr], align 8, addrspace(5) +// IR-GPU-NEXT: [[DOTOMP_REDUCTION_RED_LIST_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_REDUCTION_RED_LIST]] to ptr // IR-GPU-NEXT: [[DOTGLOBAL_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTGLOBAL_TID__ADDR]] to ptr // IR-GPU-NEXT: [[DOTBOUND_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTBOUND_TID__ADDR]] to ptr // IR-GPU-NEXT: [[J_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J_ADDR]] to ptr @@ -102,7 +103,6 @@ int foo() { // IR-GPU-NEXT: [[J4_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J4]] to ptr // IR-GPU-NEXT: [[J_CASTED_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J_CASTED]] to ptr // IR-GPU-NEXT: [[CAPTURED_VARS_ADDRS_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[CAPTURED_VARS_ADDRS]] to ptr -// IR-GPU-NEXT: [[DOTOMP_REDUCTION_RED_LIST_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_REDUCTION_RED_LIST]] to ptr // IR-GPU-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8 // IR-GPU-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR_ASCAST]], align 8 // IR-GPU-NEXT: store i64 [[J]], ptr [[J_ADDR_ASCAST]], align 8 @@ -258,6 +258,7 @@ int foo() { // IR-GPU-NEXT: [[I:%.*]] = alloca i32, align 4, addrspace(5) // IR-GPU-NEXT: [[J5:%.*]] = alloca i32, align 4, addrspace(5) // IR-GPU-NEXT: [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [1 x ptr], align 8, addrspace(5) +// IR-GPU-NEXT: [[DOTOMP_REDUCTION_RED_LIST_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_REDUCTION_RED_LIST]] to ptr // IR-GPU-NEXT: [[DOTGLOBAL_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTGLOBAL_TID__ADDR]] to ptr // IR-GPU-NEXT: [[DOTBOUND_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTBOUND_TID__ADDR]] to ptr // IR-GPU-NEXT: [[DOTPREVIOUS_LB__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTPREVIOUS_LB__ADDR]] to ptr @@ -275,7 +276,6 @@ int foo() { // IR-GPU-NEXT: [[SUM4_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[SUM4]] to ptr // IR-GPU-NEXT: [[I_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[I]] to ptr // IR-GPU-NEXT: [[J5_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J5]] to ptr -// IR-GPU-NEXT: [[DOTOMP_REDUCTION_RED_LIST_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_REDUCTION_RED_LIST]] to ptr // IR-GPU-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8 // IR-GPU-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR_ASCAST]], align 8 // IR-GPU-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR_ASCAST]], align 8 @@ -399,12 +399,12 @@ int foo() { // IR-GPU-NEXT: [[DOTADDR3:%.*]] = alloca i16, align 2, addrspace(5) // IR-GPU-NEXT: [[DOTOMP_REDUCTION_REMOTE_REDUCE_LIST:%.*]] = alloca [1 x ptr], align 8, addrspace(5) // IR-GPU-NEXT: [[DOTOMP_REDUCTION_ELEMENT:%.*]] = alloca [10 x [10 x i32]], align 4, addrspace(5) +// IR-GPU-NEXT: [[DOTOMP_REDUCTION_ELEMENT_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_REDUCTION_ELEMENT]] to ptr // IR-GPU-NEXT: [[DOTADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR]] to ptr // IR-GPU-NEXT: [[DOTADDR1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR1]] to ptr // IR-GPU-NEXT: [[DOTADDR2_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR2]] to ptr // IR-GPU-NEXT: [[DOTADDR3_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR3]] to ptr // IR-GPU-NEXT: [[DOTOMP_REDUCTION_REMOTE_REDUCE_LIST_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_REDUCTION_REMOTE_REDUCE_LIST]] to ptr -// IR-GPU-NEXT: [[DOTOMP_REDUCTION_ELEMENT_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_REDUCTION_ELEMENT]] to ptr // IR-GPU-NEXT: store ptr [[TMP0]], ptr [[DOTADDR_ASCAST]], align 8 // IR-GPU-NEXT: store i16 [[TMP1]], ptr [[DOTADDR1_ASCAST]], align 2 // IR-GPU-NEXT: store i16 [[TMP2]], ptr [[DOTADDR2_ASCAST]], align 2 @@ -480,10 +480,9 @@ int foo() { // IR-GPU-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8, addrspace(5) // IR-GPU-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4, addrspace(5) // IR-GPU-NEXT: [[DOTCNT_ADDR:%.*]] = alloca i32, align 4, addrspace(5) -// IR-GPU-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr addrspacecast (ptr addrspace(1) @[[GLOB1]] to ptr)) +// IR-GPU-NEXT: [[DOTCNT_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCNT_ADDR]] to ptr // IR-GPU-NEXT: [[DOTADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR]] to ptr // IR-GPU-NEXT: [[DOTADDR1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR1]] to ptr -// IR-GPU-NEXT: [[DOTCNT_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCNT_ADDR]] to ptr // IR-GPU-NEXT: store ptr [[TMP0]], ptr [[DOTADDR_ASCAST]], align 8 // IR-GPU-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1_ASCAST]], align 4 // IR-GPU-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() @@ -499,6 +498,7 @@ int foo() { // IR-GPU-NEXT: [[TMP8:%.*]] = icmp ult i32 [[TMP7]], 100 // IR-GPU-NEXT: br i1 [[TMP8]], label [[BODY:%.*]], label [[EXIT:%.*]] // IR-GPU: body: +// IR-GPU-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr addrspacecast (ptr addrspace(1) @[[GLOB1]] to ptr)) // IR-GPU-NEXT: call void @__kmpc_barrier(ptr addrspacecast (ptr addrspace(1) @[[GLOB4:[0-9]+]] to ptr), i32 [[TMP2]]) // IR-GPU-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // IR-GPU-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] @@ -513,11 +513,12 @@ int foo() { // IR-GPU: else: // IR-GPU-NEXT: br label [[IFCONT]] // IR-GPU: ifcont: +// IR-GPU-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr addrspacecast (ptr addrspace(1) @[[GLOB1]] to ptr)) // IR-GPU-NEXT: call void @__kmpc_barrier(ptr addrspacecast (ptr addrspace(1) @[[GLOB4]] to ptr), i32 [[TMP2]]) // IR-GPU-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTADDR1_ASCAST]], align 4 // IR-GPU-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP14]] // IR-GPU-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// IR-GPU: then2: +// IR-GPU: then3: // IR-GPU-NEXT: [[TMP15:%.*]] = getelementptr inbounds [64 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // IR-GPU-NEXT: [[TMP16:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP6]], i64 0, i64 0 // IR-GPU-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 8 @@ -525,9 +526,9 @@ int foo() { // IR-GPU-NEXT: [[TMP19:%.*]] = load volatile i32, ptr addrspace(3) [[TMP15]], align 4 // IR-GPU-NEXT: store i32 [[TMP19]], ptr [[TMP18]], align 4 // IR-GPU-NEXT: br label [[IFCONT4:%.*]] -// IR-GPU: else3: +// IR-GPU: else4: // IR-GPU-NEXT: br label [[IFCONT4]] -// IR-GPU: ifcont4: +// IR-GPU: ifcont5: // IR-GPU-NEXT: [[TMP20:%.*]] = add nsw i32 [[TMP7]], 1 // IR-GPU-NEXT: store i32 [[TMP20]], ptr [[DOTCNT_ADDR_ASCAST]], align 4 // IR-GPU-NEXT: br label [[PRECOND]] @@ -544,12 +545,12 @@ int foo() { // IR-GPU-NEXT: [[DOTADDR3:%.*]] = alloca i16, align 2, addrspace(5) // IR-GPU-NEXT: [[DOTOMP_REDUCTION_REMOTE_REDUCE_LIST:%.*]] = alloca [1 x ptr], align 8, addrspace(5) // IR-GPU-NEXT: [[DOTOMP_REDUCTION_ELEMENT:%.*]] = alloca [10 x [10 x i32]], align 4, addrspace(5) +// IR-GPU-NEXT: [[DOTOMP_REDUCTION_ELEMENT_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_REDUCTION_ELEMENT]] to ptr // IR-GPU-NEXT: [[DOTADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR]] to ptr // IR-GPU-NEXT: [[DOTADDR1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR1]] to ptr // IR-GPU-NEXT: [[DOTADDR2_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR2]] to ptr // IR-GPU-NEXT: [[DOTADDR3_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR3]] to ptr // IR-GPU-NEXT: [[DOTOMP_REDUCTION_REMOTE_REDUCE_LIST_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_REDUCTION_REMOTE_REDUCE_LIST]] to ptr -// IR-GPU-NEXT: [[DOTOMP_REDUCTION_ELEMENT_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_REDUCTION_ELEMENT]] to ptr // IR-GPU-NEXT: store ptr [[TMP0]], ptr [[DOTADDR_ASCAST]], align 8 // IR-GPU-NEXT: store i16 [[TMP1]], ptr [[DOTADDR1_ASCAST]], align 2 // IR-GPU-NEXT: store i16 [[TMP2]], ptr [[DOTADDR2_ASCAST]], align 2 @@ -625,10 +626,9 @@ int foo() { // IR-GPU-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8, addrspace(5) // IR-GPU-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4, addrspace(5) // IR-GPU-NEXT: [[DOTCNT_ADDR:%.*]] = alloca i32, align 4, addrspace(5) -// IR-GPU-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr addrspacecast (ptr addrspace(1) @[[GLOB1]] to ptr)) +// IR-GPU-NEXT: [[DOTCNT_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCNT_ADDR]] to ptr // IR-GPU-NEXT: [[DOTADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR]] to ptr // IR-GPU-NEXT: [[DOTADDR1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR1]] to ptr -// IR-GPU-NEXT: [[DOTCNT_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCNT_ADDR]] to ptr // IR-GPU-NEXT: store ptr [[TMP0]], ptr [[DOTADDR_ASCAST]], align 8 // IR-GPU-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1_ASCAST]], align 4 // IR-GPU-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block() @@ -644,6 +644,7 @@ int foo() { // IR-GPU-NEXT: [[TMP8:%.*]] = icmp ult i32 [[TMP7]], 100 // IR-GPU-NEXT: br i1 [[TMP8]], label [[BODY:%.*]], label [[EXIT:%.*]] // IR-GPU: body: +// IR-GPU-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr addrspacecast (ptr addrspace(1) @[[GLOB1]] to ptr)) // IR-GPU-NEXT: call void @__kmpc_barrier(ptr addrspacecast (ptr addrspace(1) @[[GLOB4]] to ptr), i32 [[TMP2]]) // IR-GPU-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0 // IR-GPU-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]] @@ -658,11 +659,12 @@ int foo() { // IR-GPU: else: // IR-GPU-NEXT: br label [[IFCONT]] // IR-GPU: ifcont: +// IR-GPU-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr addrspacecast (ptr addrspace(1) @[[GLOB1]] to ptr)) // IR-GPU-NEXT: call void @__kmpc_barrier(ptr addrspacecast (ptr addrspace(1) @[[GLOB4]] to ptr), i32 [[TMP2]]) // IR-GPU-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTADDR1_ASCAST]], align 4 // IR-GPU-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP14]] // IR-GPU-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]] -// IR-GPU: then2: +// IR-GPU: then3: // IR-GPU-NEXT: [[TMP15:%.*]] = getelementptr inbounds [64 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]] // IR-GPU-NEXT: [[TMP16:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP6]], i64 0, i64 0 // IR-GPU-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 8 @@ -670,9 +672,9 @@ int foo() { // IR-GPU-NEXT: [[TMP19:%.*]] = load volatile i32, ptr addrspace(3) [[TMP15]], align 4 // IR-GPU-NEXT: store i32 [[TMP19]], ptr [[TMP18]], align 4 // IR-GPU-NEXT: br label [[IFCONT4:%.*]] -// IR-GPU: else3: +// IR-GPU: else4: // IR-GPU-NEXT: br label [[IFCONT4]] -// IR-GPU: ifcont4: +// IR-GPU: ifcont5: // IR-GPU-NEXT: [[TMP20:%.*]] = add nsw i32 [[TMP7]], 1 // IR-GPU-NEXT: store i32 [[TMP20]], ptr [[DOTCNT_ADDR_ASCAST]], align 4 // IR-GPU-NEXT: br label [[PRECOND]] diff --git a/clang/test/PCH/cxx2a-requires-expr.cpp b/clang/test/PCH/cxx2a-requires-expr.cpp index 7f8f258a0f8f3c..936f6016854638 100644 --- a/clang/test/PCH/cxx2a-requires-expr.cpp +++ b/clang/test/PCH/cxx2a-requires-expr.cpp @@ -22,3 +22,20 @@ bool f() { requires C || (C || C); }; } + +namespace trailing_requires_expression { + +template requires C && C2 +// CHECK: template requires C && C2 void g(); +void g(); + +template requires C || C2 +// CHECK: template requires C || C2 constexpr int h = sizeof(T); +constexpr int h = sizeof(T); + +template requires C +// CHECK: template requires C class i { +// CHECK-NEXT: }; +class i {}; + +} diff --git a/clang/test/Parser/cxx2a-concepts-requires-expr.cpp b/clang/test/Parser/cxx2a-concepts-requires-expr.cpp index 971591afb08dba..5755844a323d2c 100644 --- a/clang/test/Parser/cxx2a-concepts-requires-expr.cpp +++ b/clang/test/Parser/cxx2a-concepts-requires-expr.cpp @@ -83,7 +83,7 @@ bool r23 = requires { typename identity::temp; }; template bool r24 = requires { typename identity::template temp; - typename identity::template temp; // expected-error{{expected an identifier or template-id after '::'}} + typename identity::template temp; // expected-error{{template argument list is expected after a name prefixed by the template keyword}} }; bool r25 = requires { ; }; diff --git a/clang/test/ParserHLSL/bitfields.hlsl b/clang/test/ParserHLSL/bitfields.hlsl new file mode 100644 index 00000000000000..307d1143a068e2 --- /dev/null +++ b/clang/test/ParserHLSL/bitfields.hlsl @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -ast-dump -x hlsl -o - %s | FileCheck %s + + +struct MyBitFields { + // CHECK: FieldDecl 0x{{[0-9a-f]+}} col:16 referenced field1 'unsigned int' + // CHECK:-ConstantExpr 0x{{[0-9a-f]+}} 'int' + // CHECK:-value: Int 3 + // CHECK:-IntegerLiteral 0x{{[0-9a-f]+}} 'int' 3 + unsigned int field1 : 3; // 3 bits for field1 + + // CHECK:FieldDecl 0x{{[0-9a-f]+}} col:16 referenced field2 'unsigned int' + // CHECK:-ConstantExpr 0x{{[0-9a-f]+}} 'int' + // CHECK:-value: Int 4 + // CHECK:-IntegerLiteral 0x{{[0-9a-f]+}} 'int' 4 + unsigned int field2 : 4; // 4 bits for field2 + + // CHECK:FieldDecl 0x{{[0-9a-f]+}} col:7 field3 'int' + // CHECK:-ConstantExpr 0x{{[0-9a-f]+}} 'int' + // CHECK:-value: Int 5 + // CHECK:-IntegerLiteral 0x{{[0-9a-f]+}} 'int' 5 + int field3 : 5; // 5 bits for field3 (signed) +}; + + + +[numthreads(1,1,1)] +void main() { + MyBitFields m; + m.field1 = 4; + m.field2 = m.field1*2; +} \ No newline at end of file diff --git a/clang/test/ParserHLSL/hlsl_annotations_on_struct_members.hlsl b/clang/test/ParserHLSL/hlsl_annotations_on_struct_members.hlsl new file mode 100644 index 00000000000000..2eebc920388b5b --- /dev/null +++ b/clang/test/ParserHLSL/hlsl_annotations_on_struct_members.hlsl @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s | FileCheck %s + +// tests that hlsl annotations are properly parsed when applied on field decls, +// and that the annotation gets properly placed on the AST. + +struct Eg9{ + // CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} col:8 implicit struct Eg9 + // CHECK: FieldDecl 0x{{[0-9a-f]+}} col:16 referenced a 'unsigned int' + // CHECK: -HLSLSV_DispatchThreadIDAttr 0x{{[0-9a-f]+}} + unsigned int a : SV_DispatchThreadID; +}; +Eg9 e9; + + +RWBuffer In : register(u1); + + +[numthreads(1,1,1)] +void main() { + In[0] = e9.a; +} diff --git a/clang/test/Preprocessor/aarch64-target-features.c b/clang/test/Preprocessor/aarch64-target-features.c index 6f359461dea885..71cc36acf3f0e1 100644 --- a/clang/test/Preprocessor/aarch64-target-features.c +++ b/clang/test/Preprocessor/aarch64-target-features.c @@ -315,37 +315,37 @@ // RUN: %clang -target aarch64 -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-THUNDERX2T99 %s // RUN: %clang -target aarch64 -mcpu=a64fx -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-A64FX %s // RUN: %clang -target aarch64 -mcpu=carmel -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-CARMEL %s -// CHECK-MCPU-APPLE-A7: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8a" "-target-feature" "+aes"{{.*}} "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon" -// CHECK-MCPU-APPLE-A10: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8a" "-target-feature" "+aes"{{.*}} "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon" -// CHECK-MCPU-APPLE-A11: "-cc1"{{.*}} "-triple" "aarch64{{.*}}"{{.*}}"-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon" -// CHECK-MCPU-APPLE-A12: "-cc1"{{.*}} "-triple" "aarch64"{{.*}} "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.3a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+complxnum" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon" -// CHECK-MCPU-A34: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon" -// CHECK-MCPU-APPLE-A13: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "apple-a13" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.4a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+complxnum" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+sha3" "-target-feature" "+neon" -// CHECK-MCPU-A35: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon" -// CHECK-MCPU-A53: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon" -// CHECK-MCPU-A57: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon" -// CHECK-MCPU-A72: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon" -// CHECK-MCPU-CORTEX-A73: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon" -// CHECK-MCPU-CORTEX-R82: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8r" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+complxnum" "-target-feature" "+flagm" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+predres" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sb" "-target-feature" "+neon" "-target-feature" "+ssbs" -// CHECK-MCPU-M3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon" -// CHECK-MCPU-M4: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon" -// CHECK-MCPU-KRYO: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon" -// CHECK-MCPU-THUNDERX2T99: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon" -// CHECK-MCPU-A64FX: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+complxnum" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon" "-target-feature" "+sve" -// CHECK-MCPU-CARMEL: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon" +// CHECK-MCPU-APPLE-A7: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2" +// CHECK-MCPU-APPLE-A10: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+lor" "-target-feature" "+neon" "-target-feature" "+pan" "-target-feature" "+perfmon" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+vh" +// CHECK-MCPU-APPLE-A11: "-cc1"{{.*}} "-triple" "aarch64{{.*}}"{{.*}}"-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2" +// CHECK-MCPU-APPLE-A12: "-cc1"{{.*}} "-triple" "aarch64"{{.*}} "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.3a" "-target-feature" "+aes" "-target-feature" "+complxnum" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2" +// CHECK-MCPU-A34: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2" +// CHECK-MCPU-APPLE-A13: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.4a" "-target-feature" "+aes" "-target-feature" "+complxnum" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+fp-armv8" "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+sha3" +// CHECK-MCPU-A35: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2" +// CHECK-MCPU-A53: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2" +// CHECK-MCPU-A57: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2" +// CHECK-MCPU-A72: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2" +// CHECK-MCPU-CORTEX-A73: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2" +// CHECK-MCPU-CORTEX-R82: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8r" "-target-feature" "+ccdp" "-target-feature" "+complxnum" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+flagm" "-target-feature" "+fp-armv8" "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+predres" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sb" "-target-feature" "+ssbs" +// CHECK-MCPU-M3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2" +// CHECK-MCPU-M4: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2" +// CHECK-MCPU-KRYO: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2" +// CHECK-MCPU-THUNDERX2T99: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+rdm" "-target-feature" "+sha2 +// CHECK-MCPU-A64FX: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+complxnum" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+sve" +// CHECK-MCPU-CARMEL: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2" // RUN: %clang -target x86_64-apple-macosx -arch arm64 -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-ARCH-ARM64 %s -// CHECK-ARCH-ARM64: "-target-cpu" "apple-m1" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.4a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+complxnum" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+predres" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sb" "-target-feature" "+sha2" "-target-feature" "+sha3" "-target-feature" "+neon" "-target-feature" "+ssbs" +// CHECK-ARCH-ARM64: "-target-cpu" "apple-m1" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.4a" "-target-feature" "+aes" "-target-feature" "+altnzcv" "-target-feature" "+ccdp" "-target-feature" "+complxnum" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+fp-armv8" "-target-feature" "+fp16fml" "-target-feature" "+fptoint" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+predres" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sb" "-target-feature" "+sha2" "-target-feature" "+sha3" "-target-feature" "+specrestrict" "-target-feature" "+ssbs" // RUN: %clang -target x86_64-apple-macosx -arch arm64_32 -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-ARCH-ARM64_32 %s -// CHECK-ARCH-ARM64_32: "-target-cpu" "apple-s4" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.3a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+complxnum" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon" +// CHECK-ARCH-ARM64_32: "-target-cpu" "apple-s4" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.3a" "-target-feature" "+aes" "-target-feature" "+complxnum" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2" // RUN: %clang -target aarch64 -march=armv8-a+fp+simd+crc+crypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-1 %s // RUN: %clang -target aarch64 -march=armv8-a+nofp+nosimd+nocrc+nocrypto+fp+simd+crc+crypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-1 %s // RUN: %clang -target aarch64 -march=armv8-a+nofp+nosimd+nocrc+nocrypto -mabi=aapcs-soft -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-2 %s // RUN: %clang -target aarch64 -march=armv8-a+fp+simd+crc+crypto+nofp+nosimd+nocrc+nocrypto -mabi=aapcs-soft -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-2 %s // RUN: %clang -target aarch64 -march=armv8-a+nosimd -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-3 %s -// CHECK-MARCH-1: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+crypto" "-target-feature" "+fp-armv8" "-target-feature" "+sha2" "-target-feature" "+neon" +// CHECK-MARCH-1: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+crypto" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+sha2" // CHECK-MARCH-2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "-fp-armv8"{{.*}} "-target-feature" "-neon" // CHECK-MARCH-3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "-neon" @@ -463,8 +463,8 @@ // RUN: %clang -target aarch64 -mcpu=GENERIC+nocrc+CRC -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-2 %s // RUN: %clang -target aarch64 -mcpu=cortex-a53+noSIMD -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-3 %s // CHECK-MCPU-1: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "-aes"{{.*}} "-target-feature" "-sha2" -// CHECK-MCPU-2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" -// CHECK-MCPU-3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "-aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "-sha2" "-target-feature" "-neon" +// CHECK-MCPU-2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+crc"{{.*}} "-target-feature" "+fp-armv8"{{.*}} "-target-feature" "+neon" +// CHECK-MCPU-3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "-aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "-neon" "-target-feature" "+perfmon" "-target-feature" "-sha2" // RUN: %clang -target aarch64 -mcpu=cyclone+nocrc+nocrypto -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-MARCH %s // RUN: %clang -target aarch64 -march=armv8-a -mcpu=cyclone+nocrc+nocrypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-MARCH %s @@ -492,9 +492,9 @@ // RUN: %clang -target aarch64 -march=ARMV8.1A+CRYPTO -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V81A-FEATURE-1 %s // RUN: %clang -target aarch64 -march=Armv8.1a+NOcrypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V81A-FEATURE-2 %s // RUN: %clang -target aarch64 -march=armv8.1a+noSIMD -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V81A-FEATURE-3 %s -// CHECK-V81A-FEATURE-1: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+crypto" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon" -// CHECK-V81A-FEATURE-2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "+rdm" "-target-feature" "+neon" -// CHECK-V81A-FEATURE-3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "-rdm" "-target-feature" "-neon" +// CHECK-V81A-FEATURE-1: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+crypto" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+rdm" "-target-feature" "+sha2" +// CHECK-V81A-FEATURE-2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+rdm" +// CHECK-V81A-FEATURE-3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "-neon" "-target-feature" "-rdm" // ================== Check Memory Tagging Extensions (MTE). // RUN: %clang -target arm64-none-linux-gnu -march=armv8.5-a+memtag -x c -E -dM %s -o - 2>&1 | FileCheck -check-prefix=CHECK-MEMTAG %s diff --git a/clang/test/Preprocessor/embed_weird.cpp b/clang/test/Preprocessor/embed_weird.cpp index a90d3bc330538b..31b622c848d6a9 100644 --- a/clang/test/Preprocessor/embed_weird.cpp +++ b/clang/test/Preprocessor/embed_weird.cpp @@ -1,7 +1,9 @@ -// RUN: printf "\0" > %S/Inputs/null_byte.bin -// RUN: %clang_cc1 %s -fsyntax-only --embed-dir=%S/Inputs -verify=expected,cxx -Wno-c23-extensions -// RUN: %clang_cc1 -x c -std=c23 %s -fsyntax-only --embed-dir=%S/Inputs -verify=expected,c -// RUN: rm %S/Inputs/null_byte.bin +// RUN: rm -rf %t && mkdir -p %t/media +// RUN: cp %S/Inputs/single_byte.txt %S/Inputs/jk.txt %S/Inputs/numbers.txt %t/ +// RUN: cp %S/Inputs/media/empty %t/media/ +// RUN: printf "\0" > %t/null_byte.bin +// RUN: %clang_cc1 %s -fsyntax-only --embed-dir=%t -verify=expected,cxx -Wno-c23-extensions +// RUN: %clang_cc1 -x c -std=c23 %s -fsyntax-only --embed-dir=%t -verify=expected,c #embed ; diff --git a/clang/test/Preprocessor/predefined-win-macros.c b/clang/test/Preprocessor/predefined-win-macros.c index 14e2f584bd0938..7d29e45c7d5ac6 100644 --- a/clang/test/Preprocessor/predefined-win-macros.c +++ b/clang/test/Preprocessor/predefined-win-macros.c @@ -116,6 +116,7 @@ // CHECK-X86-MINGW: #define WINNT 1 // CHECK-X86-MINGW: #define _WIN32 1 // CHECK-X86-MINGW-NOT: #define _WIN64 1 +// CHECK-X86-MINGW: #define __GXX_TYPEINFO_EQUALITY_INLINE 0 // RUN: %clang_cc1 -triple thumbv7-windows-gnu %s -E -dM -o - \ // RUN: | FileCheck -match-full-lines %s --check-prefix=CHECK-ARM-MINGW @@ -125,6 +126,7 @@ // CHECK-ARM-MINGW: #define WINNT 1 // CHECK-ARM-MINGW: #define _WIN32 1 // CHECK-ARM-MINGW-NOT: #define _WIN64 1 +// CHECK-ARM-MINGW: #define __GXX_TYPEINFO_EQUALITY_INLINE 0 // RUN: %clang_cc1 -triple x86_64-windows-gnu %s -E -dM -o - \ // RUN: | FileCheck -match-full-lines %s --check-prefix=CHECK-AMD64-MINGW @@ -134,6 +136,7 @@ // CHECK-AMD64-MINGW: #define WINNT 1 // CHECK-AMD64-MINGW: #define _WIN32 1 // CHECK-AMD64-MINGW: #define _WIN64 1 +// CHECK-AMD64-MINGW: #define __GXX_TYPEINFO_EQUALITY_INLINE 0 // RUN: %clang_cc1 -triple aarch64-windows-gnu %s -E -dM -o - \ // RUN: | FileCheck -match-full-lines %s --check-prefix=CHECK-ARM64-MINGW @@ -145,6 +148,7 @@ // CHECK-ARM64-MINGW: #define _WIN32 1 // CHECK-ARM64-MINGW: #define _WIN64 1 // CHECK-ARM64-MINGW: #define __GCC_ASM_FLAG_OUTPUTS__ 1 +// CHECK-ARM64-MINGW: #define __GXX_TYPEINFO_EQUALITY_INLINE 0 // CHECK-ARM64-MINGW: #define __aarch64__ 1 // RUN: %clang_cc1 -triple arm64ec-windows-gnu %s -E -dM -o - \ @@ -157,6 +161,7 @@ // CHECK-ARM64EC-MINGW: #define _WIN32 1 // CHECK-ARM64EC-MINGW: #define _WIN64 1 // CHECK-ARM64EC-MINGW: #define __GCC_ASM_FLAG_OUTPUTS__ 1 +// CHECK-ARM64EC-MINGW: #define __GXX_TYPEINFO_EQUALITY_INLINE 0 // CHECK-ARM64EC-MINGW-NOT: #define __aarch64__ 1 // CHECK-ARM64EC-MINGW: #define __amd64 1 // CHECK-ARM64EC-MINGW: #define __amd64__ 1 diff --git a/clang/test/Preprocessor/riscv-target-features.c b/clang/test/Preprocessor/riscv-target-features.c index d7935af532dfa1..4dccbfa3b8a1ae 100644 --- a/clang/test/Preprocessor/riscv-target-features.c +++ b/clang/test/Preprocessor/riscv-target-features.c @@ -1683,44 +1683,44 @@ // CHECK-ZICFISS-EXT: __riscv_zicfiss 4000{{$}} // RUN: %clang --target=riscv32 -menable-experimental-extensions \ -// RUN: -march=rv32i_ssnpm0p8 -E -dM %s \ +// RUN: -march=rv32i_ssnpm1p0 -E -dM %s \ // RUN: -o - | FileCheck --check-prefix=CHECK-SSNPM-EXT %s // RUN: %clang --target=riscv64 -menable-experimental-extensions \ -// RUN: -march=rv64i_ssnpm0p8 -E -dM %s \ +// RUN: -march=rv64i_ssnpm1p0 -E -dM %s \ // RUN: -o - | FileCheck --check-prefix=CHECK-SSNPM-EXT %s -// CHECK-SSNPM-EXT: __riscv_ssnpm 8000{{$}} +// CHECK-SSNPM-EXT: __riscv_ssnpm 1000000{{$}} // RUN: %clang --target=riscv32 -menable-experimental-extensions \ -// RUN: -march=rv32i_smnpm0p8 -E -dM %s \ +// RUN: -march=rv32i_smnpm1p0 -E -dM %s \ // RUN: -o - | FileCheck --check-prefix=CHECK-SMNPM-EXT %s // RUN: %clang --target=riscv64 -menable-experimental-extensions \ -// RUN: -march=rv64i_smnpm0p8 -E -dM %s \ +// RUN: -march=rv64i_smnpm1p0 -E -dM %s \ // RUN: -o - | FileCheck --check-prefix=CHECK-SMNPM-EXT %s -// CHECK-SMNPM-EXT: __riscv_smnpm 8000{{$}} +// CHECK-SMNPM-EXT: __riscv_smnpm 1000000{{$}} // RUN: %clang --target=riscv32 -menable-experimental-extensions \ -// RUN: -march=rv32i_smmpm0p8 -E -dM %s \ +// RUN: -march=rv32i_smmpm1p0 -E -dM %s \ // RUN: -o - | FileCheck --check-prefix=CHECK-SMMPM-EXT %s // RUN: %clang --target=riscv64 -menable-experimental-extensions \ -// RUN: -march=rv64i_smmpm0p8 -E -dM %s \ +// RUN: -march=rv64i_smmpm1p0 -E -dM %s \ // RUN: -o - | FileCheck --check-prefix=CHECK-SMMPM-EXT %s -// CHECK-SMMPM-EXT: __riscv_smmpm 8000{{$}} +// CHECK-SMMPM-EXT: __riscv_smmpm 1000000{{$}} // RUN: %clang --target=riscv32 -menable-experimental-extensions \ -// RUN: -march=rv32i_sspm0p8 -E -dM %s \ +// RUN: -march=rv32i_sspm1p0 -E -dM %s \ // RUN: -o - | FileCheck --check-prefix=CHECK-SSPM-EXT %s // RUN: %clang --target=riscv64 -menable-experimental-extensions \ -// RUN: -march=rv64i_sspm0p8 -E -dM %s \ +// RUN: -march=rv64i_sspm1p0 -E -dM %s \ // RUN: -o - | FileCheck --check-prefix=CHECK-SSPM-EXT %s -// CHECK-SSPM-EXT: __riscv_sspm 8000{{$}} +// CHECK-SSPM-EXT: __riscv_sspm 1000000{{$}} // RUN: %clang --target=riscv32 -menable-experimental-extensions \ -// RUN: -march=rv32i_supm0p8 -E -dM %s \ +// RUN: -march=rv32i_supm1p0 -E -dM %s \ // RUN: -o - | FileCheck --check-prefix=CHECK-SUPM-EXT %s // RUN: %clang --target=riscv64 -menable-experimental-extensions \ -// RUN: -march=rv64i_supm0p8 -E -dM %s \ +// RUN: -march=rv64i_supm1p0 -E -dM %s \ // RUN: -o - | FileCheck --check-prefix=CHECK-SUPM-EXT %s -// CHECK-SUPM-EXT: __riscv_supm 8000{{$}} +// CHECK-SUPM-EXT: __riscv_supm 1000000{{$}} // RUN: %clang --target=riscv32 -menable-experimental-extensions \ // RUN: -march=rv32i_ssqosid1p0 -E -dM %s \ diff --git a/clang/test/Preprocessor/x86_target_features.c b/clang/test/Preprocessor/x86_target_features.c index 3e63e2c77fddf9..6e9c968273a466 100644 --- a/clang/test/Preprocessor/x86_target_features.c +++ b/clang/test/Preprocessor/x86_target_features.c @@ -754,7 +754,8 @@ // RUN: %clang -target x86_64-unknown-unknown -march=x86-64 -mapx-features=ccmp -x c -E -dM -o - %s | FileCheck --check-prefix=CCMP %s // RUN: %clang -target x86_64-unknown-unknown -march=x86-64 -mapx-features=nf -x c -E -dM -o - %s | FileCheck --check-prefix=NF %s // RUN: %clang -target x86_64-unknown-unknown -march=x86-64 -mapx-features=cf -x c -E -dM -o - %s | FileCheck --check-prefix=CF %s -// RUN: %clang -target x86_64-unknown-unknown -march=x86-64 -mapxf -x c -E -dM -o - %s | FileCheck --check-prefixes=EGPR,PUSH2POP2,PPX,NDD,CCMP,NF,APXF %s +// RUN: %clang -target x86_64-unknown-unknown -march=x86-64 -mapx-features=zu -x c -E -dM -o - %s | FileCheck --check-prefix=ZU %s +// RUN: %clang -target x86_64-unknown-unknown -march=x86-64 -mapxf -x c -E -dM -o - %s | FileCheck --check-prefixes=EGPR,PUSH2POP2,PPX,NDD,CCMP,NF,CF,APXF %s // APXF: #define __APX_F__ 1 // CCMP: #define __CCMP__ 1 // CF: #define __CF__ 1 @@ -763,6 +764,7 @@ // NF: #define __NF__ 1 // PPX: #define __PPX__ 1 // PUSH2POP2: #define __PUSH2POP2__ 1 +// ZU: #define __ZU__ 1 // RUN: %clang -target x86_64-unknown-unknown -march=x86-64 -mapx-inline-asm-use-gpr32 -x c -E -dM -o - %s | FileCheck --check-prefixes=NOUSEGPR32 %s // RUN: %clang -target x86_64-unknown-unknown -march=x86-64 -mapx-features=egpr -mapx-inline-asm-use-gpr32 -x c -E -dM -o - %s | FileCheck --check-prefixes=USEGPR32 %s diff --git a/clang/test/Sema/aarch64-sme2p1-intrinsics/acle_sme2p1_imm.cpp b/clang/test/Sema/aarch64-sme2p1-intrinsics/acle_sme2p1_imm.cpp new file mode 100644 index 00000000000000..06b1e8301ce49d --- /dev/null +++ b/clang/test/Sema/aarch64-sme2p1-intrinsics/acle_sme2p1_imm.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu \ +// RUN: -target-feature +sme -target-feature +sme2p1 -target-feature +bf16 -fsyntax-only -verify %s + +// REQUIRES: aarch64-registered-target + +#include + +void tests_readz_tile_to_vector_single(uint32_t slice) __arm_streaming __arm_inout("za") { + svreadz_hor_za8_s8(-1, slice); // expected-error {{argument value 18446744073709551615 is outside the valid range [0, 0]}} + svreadz_hor_za16_s16(-1, slice); // expected-error {{argument value 18446744073709551615 is outside the valid range [0, 1]}} + svreadz_hor_za32_s32(-1, slice); // expected-error {{argument value 18446744073709551615 is outside the valid range [0, 3]}} + svreadz_hor_za64_s64(-1, slice); // expected-error {{argument value 18446744073709551615 is outside the valid range [0, 7]}} + svreadz_hor_za128_s8(-1, slice); // expected-error {{argument value 18446744073709551615 is outside the valid range [0, 15]}} + svreadz_hor_za128_s16(-1, slice); // expected-error {{argument value 18446744073709551615 is outside the valid range [0, 15]}} + svreadz_hor_za128_s32(-1, slice); // expected-error {{argument value 18446744073709551615 is outside the valid range [0, 15]}} + svreadz_hor_za128_s64(-1, slice); // expected-error {{argument value 18446744073709551615 is outside the valid range [0, 15]}} + svreadz_hor_za128_bf16(-1, slice); // expected-error {{argument value 18446744073709551615 is outside the valid range [0, 15]}} + return; +} + + diff --git a/clang/test/Sema/aarch64-sve-intrinsics/acle_sve_bfloat.cpp b/clang/test/Sema/aarch64-sve-intrinsics/acle_sve_bfloat.cpp index 95baf9f77fb14e..fcdd0516ed5a9d 100644 --- a/clang/test/Sema/aarch64-sve-intrinsics/acle_sve_bfloat.cpp +++ b/clang/test/Sema/aarch64-sve-intrinsics/acle_sve_bfloat.cpp @@ -6,23 +6,23 @@ void test_bfloat(svbool_t pg, uint64_t u64, int64_t i64, const bfloat16_t *const_bf16_ptr, bfloat16_t *bf16_ptr, svbfloat16_t bf16, svbfloat16x2_t bf16x2, svbfloat16x3_t bf16x3, svbfloat16x4_t bf16x4) { - // expected-error@+1 {{'svcreate2_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svcreate2_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svcreate2_bf16(bf16, bf16); - // expected-error@+1 {{'svcreate3_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svcreate3_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svcreate3_bf16(bf16, bf16, bf16); - // expected-error@+1 {{'svcreate4_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svcreate4_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svcreate4_bf16(bf16, bf16, bf16, bf16); - // expected-error@+1 {{'svget2_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svget2_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svget2_bf16(bf16x2, 1); - // expected-error@+1 {{'svget3_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svget3_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svget3_bf16(bf16x3, 1); - // expected-error@+1 {{'svget4_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svget4_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svget4_bf16(bf16x4, 1); - // expected-error@+1 {{'svld1_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svld1_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svld1_bf16(pg, const_bf16_ptr); - // expected-error@+1 {{'svld1_vnum_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svld1_vnum_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svld1_vnum_bf16(pg, const_bf16_ptr, i64); - // expected-error@+1 {{'svld1rq_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svld1rq_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svld1rq_bf16(pg, const_bf16_ptr); // expected-error@+1 {{'svldff1_bf16' needs target feature sve,bf16}} svldff1_bf16(pg, const_bf16_ptr); @@ -32,55 +32,55 @@ void test_bfloat(svbool_t pg, uint64_t u64, int64_t i64, const bfloat16_t *const svldnf1_bf16(pg, const_bf16_ptr); // expected-error@+1 {{'svldnf1_vnum_bf16' needs target feature sve,bf16}} svldnf1_vnum_bf16(pg, const_bf16_ptr, i64); - // expected-error@+1 {{'svldnt1_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svldnt1_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svldnt1_bf16(pg, const_bf16_ptr); - // expected-error@+1 {{'svldnt1_vnum_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svldnt1_vnum_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svldnt1_vnum_bf16(pg, const_bf16_ptr, i64); - // expected-error@+1 {{'svrev_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svrev_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svrev_bf16(bf16); - // expected-error@+1 {{'svset2_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svset2_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svset2_bf16(bf16x2, 1, bf16); - // expected-error@+1 {{'svset3_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svset3_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svset3_bf16(bf16x3, 1, bf16); - // expected-error@+1 {{'svset4_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svset4_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svset4_bf16(bf16x4, 1, bf16); - // expected-error@+1 {{'svst1_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svst1_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svst1_bf16(pg, bf16_ptr, bf16); - // expected-error@+1 {{'svst1_vnum_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svst1_vnum_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svst1_vnum_bf16(pg, bf16_ptr, i64, bf16); - // expected-error@+1 {{'svstnt1_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svstnt1_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svstnt1_bf16(pg, bf16_ptr, bf16); - // expected-error@+1 {{'svstnt1_vnum_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svstnt1_vnum_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svstnt1_vnum_bf16(pg, bf16_ptr, i64, bf16); - // expected-error@+1 {{'svtrn1_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svtrn1_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svtrn1_bf16(bf16, bf16); // expected-error@+1 {{'svtrn1q_bf16' needs target feature sve,bf16}} svtrn1q_bf16(bf16, bf16); - // expected-error@+1 {{'svtrn2_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svtrn2_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svtrn2_bf16(bf16, bf16); // expected-error@+1 {{'svtrn2q_bf16' needs target feature sve,bf16}} svtrn2q_bf16(bf16, bf16); - // expected-error@+1 {{'svundef_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svundef_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svundef_bf16(); - // expected-error@+1 {{'svundef2_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svundef2_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svundef2_bf16(); - // expected-error@+1 {{'svundef3_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svundef3_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svundef3_bf16(); - // expected-error@+1 {{'svundef4_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svundef4_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svundef4_bf16(); - // expected-error@+1 {{'svuzp1_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svuzp1_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svuzp1_bf16(bf16, bf16); // expected-error@+1 {{'svuzp1q_bf16' needs target feature sve,bf16}} svuzp1q_bf16(bf16, bf16); - // expected-error@+1 {{'svuzp2_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svuzp2_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svuzp2_bf16(bf16, bf16); // expected-error@+1 {{'svuzp2q_bf16' needs target feature sve,bf16}} svuzp2q_bf16(bf16, bf16); - // expected-error@+1 {{'svzip1_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svzip1_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svzip1_bf16(bf16, bf16); // expected-error@+1 {{'svzip1q_bf16' needs target feature sve,bf16}} svzip1q_bf16(bf16, bf16); - // expected-error@+1 {{'svzip2_bf16' needs target feature (sve|sme),bf16}} + // expected-error@+1 {{'svzip2_bf16' needs target feature (sve,bf16)|(sme,bf16)}} svzip2_bf16(bf16, bf16); // expected-error@+1 {{'svzip2q_bf16' needs target feature sve,bf16}} svzip2q_bf16(bf16, bf16); diff --git a/clang/test/Sema/aarch64-sve2-intrinsics/acle_sve2_bfloat.cpp b/clang/test/Sema/aarch64-sve2-intrinsics/acle_sve2_bfloat.cpp index bed86be606b104..bb72a3eaf60eca 100644 --- a/clang/test/Sema/aarch64-sve2-intrinsics/acle_sve2_bfloat.cpp +++ b/clang/test/Sema/aarch64-sve2-intrinsics/acle_sve2_bfloat.cpp @@ -14,16 +14,16 @@ void test_bfloat(const bfloat16_t *const_bf16_ptr, svbfloat16_t bf16, svbfloat16x2_t bf16x2) { - // expected-error@+2 {{'svwhilerw_bf16' needs target feature (sve2|sme),bf16}} - // overload-error@+1 {{'svwhilerw' needs target feature (sve2|sme),bf16}} + // expected-error@+2 {{'svwhilerw_bf16' needs target feature (sve2,bf16)|(sme,bf16)}} + // overload-error@+1 {{'svwhilerw' needs target feature (sve2,bf16)|(sme,bf16)}} SVE_ACLE_FUNC(svwhilerw,_bf16,,)(const_bf16_ptr, const_bf16_ptr); - // expected-error@+2 {{'svtbx_bf16' needs target feature (sve2|sme),bf16}} - // overload-error@+1 {{'svtbx' needs target feature (sve2|sme),bf16}} + // expected-error@+2 {{'svtbx_bf16' needs target feature (sve2,bf16)|(sme,bf16)}} + // overload-error@+1 {{'svtbx' needs target feature (sve2,bf16)|(sme,bf16)}} SVE_ACLE_FUNC(svtbx,_bf16,,)(bf16, bf16, svundef_u16()); - // expected-error@+2 {{'svtbl2_bf16' needs target feature (sve2|sme),bf16}} - // overload-error@+1 {{'svtbl2' needs target feature (sve2|sme),bf16}} + // expected-error@+2 {{'svtbl2_bf16' needs target feature (sve2,bf16)|(sme,bf16)}} + // overload-error@+1 {{'svtbl2' needs target feature (sve2,bf16)|(sme,bf16)}} SVE_ACLE_FUNC(svtbl2,_bf16,,)(bf16x2, svundef_u16()); - // expected-error@+2 {{'svwhilewr_bf16' needs target feature (sve2|sme),bf16}} - // overload-error@+1 {{'svwhilewr' needs target feature (sve2|sme),bf16}} + // expected-error@+2 {{'svwhilewr_bf16' needs target feature (sve2,bf16)|(sme,bf16)}} + // overload-error@+1 {{'svwhilewr' needs target feature (sve2,bf16)|(sme,bf16)}} SVE_ACLE_FUNC(svwhilewr,_bf16,,)(const_bf16_ptr, const_bf16_ptr); } diff --git a/clang/test/Sema/arm-vector-types-support.c b/clang/test/Sema/arm-vector-types-support.c index ed5f5ba175a94a..8b8c9634631d05 100644 --- a/clang/test/Sema/arm-vector-types-support.c +++ b/clang/test/Sema/arm-vector-types-support.c @@ -1,7 +1,8 @@ -// RUN: %clang_cc1 %s -triple armv7 -fsyntax-only -verify -// RUN: %clang_cc1 %s -triple aarch64 -fsyntax-only -verify -// RUN: %clang_cc1 %s -triple aarch64 -target-feature -fp-armv8 -target-abi aapcs-soft -fsyntax-only -verify +// RUN: %clang_cc1 %s -triple armv8.1m.main -fsyntax-only -verify +// RUN: %clang_cc1 %s -triple aarch64 -fsyntax-only -verify=sve-type +// RUN: %clang_cc1 %s -triple aarch64 -target-feature -fp-armv8 -target-abi aapcs-soft -fsyntax-only -verify=sve-type -typedef __attribute__((neon_vector_type(2))) int int32x2_t; // expected-error{{'neon_vector_type' attribute is not supported on targets missing 'neon', 'mve', 'sve' or 'sme'; specify an appropriate -march= or -mcpu=}} -typedef __attribute__((neon_polyvector_type(16))) short poly8x16_t; // expected-error{{'neon_polyvector_type' attribute is not supported on targets missing 'neon' or 'mve'; specify an appropriate -march= or -mcpu=}} +typedef __attribute__((neon_vector_type(2))) int int32x2_t; // expected-error{{on M-profile architectures 'neon_vector_type' attribute is not supported on targets missing 'mve'; specify an appropriate -march= or -mcpu=}} +typedef __attribute__((neon_polyvector_type(16))) unsigned char poly8x16_t; // expected-error{{on M-profile architectures 'neon_polyvector_type' attribute is not supported on targets missing 'mve'; specify an appropriate -march= or -mcpu=}} typedef __attribute__((arm_sve_vector_bits(256))) void nosveflag; // expected-error{{'arm_sve_vector_bits' attribute is not supported on targets missing 'sve'; specify an appropriate -march= or -mcpu=}} + // sve-type-error@-1{{'arm_sve_vector_bits' attribute is not supported on targets missing 'sve'; specify an appropriate -march= or -mcpu=}} diff --git a/clang/test/Sema/atomic-ops.c b/clang/test/Sema/atomic-ops.c index 2024b81ce6aec3..9b82d82ff82697 100644 --- a/clang/test/Sema/atomic-ops.c +++ b/clang/test/Sema/atomic-ops.c @@ -671,6 +671,36 @@ void zeroSizeArgError(struct Z *a, struct Z *b, struct Z *c) { } +struct IncompleteTy IncA, IncB, IncC; // expected-error 3{{tentative definition has type 'struct IncompleteTy' that is never completed}} \ + // expected-note 27{{forward declaration of 'struct IncompleteTy'}} +void incompleteTypeArgError() { + __atomic_exchange(&IncB, &IncB, &IncC, memory_order_relaxed); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}} + __atomic_exchange(&IncB, &IncB, &IncC, memory_order_acq_rel); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}} + __atomic_exchange(&IncB, &IncB, &IncC, memory_order_acquire); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}} + __atomic_exchange(&IncB, &IncB, &IncC, memory_order_consume); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}} + __atomic_exchange(&IncB, &IncB, &IncC, memory_order_release); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}} + __atomic_exchange(&IncB, &IncB, &IncC, memory_order_seq_cst); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}} + __atomic_load(&IncA, &IncB, memory_order_relaxed); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}} + __atomic_load(&IncA, &IncB, memory_order_acq_rel); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}} + __atomic_load(&IncA, &IncB, memory_order_acquire); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}} + __atomic_load(&IncA, &IncB, memory_order_consume); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}} + __atomic_load(&IncA, &IncB, memory_order_release); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}} + __atomic_load(&IncA, &IncB, memory_order_seq_cst); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}} + __atomic_store(&IncA, &IncB, memory_order_relaxed); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}} + __atomic_store(&IncA, &IncB, memory_order_acq_rel); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}} + __atomic_store(&IncA, &IncB, memory_order_acquire); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}} + __atomic_store(&IncA, &IncB, memory_order_consume); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}} + __atomic_store(&IncA, &IncB, memory_order_release); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}} + __atomic_store(&IncA, &IncB, memory_order_seq_cst); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}} + __atomic_compare_exchange(&IncA, &IncB, &IncC, 0, memory_order_relaxed, memory_order_relaxed); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}} + __atomic_compare_exchange(&IncA, &IncB, &IncC, 0, memory_order_acq_rel, memory_order_acq_rel); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}} + __atomic_compare_exchange(&IncA, &IncB, &IncC, 0, memory_order_acquire, memory_order_acquire); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}} + __atomic_compare_exchange(&IncA, &IncB, &IncC, 0, memory_order_consume, memory_order_consume); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}} + __atomic_compare_exchange(&IncA, &IncB, &IncC, 0, memory_order_release, memory_order_release); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}} + __atomic_compare_exchange(&IncA, &IncB, &IncC, 0, memory_order_seq_cst, memory_order_seq_cst); // expected-error {{incomplete type 'struct IncompleteTy' where a complete type is required}} + +} + void nullPointerWarning(void) { volatile _Atomic(int) vai; _Atomic(int) ai; diff --git a/clang/test/Sema/attr-capabilities.c b/clang/test/Sema/attr-capabilities.c index 5138803bd5eb7a..91a43c79d5b917 100644 --- a/clang/test/Sema/attr-capabilities.c +++ b/clang/test/Sema/attr-capabilities.c @@ -54,14 +54,14 @@ void Func18(void) __attribute__((release_capability())) {} // expected-warning { void Func19(void) __attribute__((release_shared_capability())) {} // expected-warning {{'release_shared_capability' attribute without capability arguments can only be applied to non-static methods of a class}} void Func20(void) __attribute__((release_generic_capability())) {} // expected-warning {{'release_generic_capability' attribute without capability arguments can only be applied to non-static methods of a class}} -void Func21(void) __attribute__((try_acquire_capability(1))) {} // expected-warning {{'try_acquire_capability' attribute without capability arguments can only be applied to non-static methods of a class}} -void Func22(void) __attribute__((try_acquire_shared_capability(1))) {} // expected-warning {{'try_acquire_shared_capability' attribute without capability arguments can only be applied to non-static methods of a class}} +int Func21(void) __attribute__((try_acquire_capability(1))) {} // expected-warning {{'try_acquire_capability' attribute without capability arguments can only be applied to non-static methods of a class}} +int Func22(void) __attribute__((try_acquire_shared_capability(1))) {} // expected-warning {{'try_acquire_shared_capability' attribute without capability arguments can only be applied to non-static methods of a class}} -void Func23(void) __attribute__((try_acquire_capability(1, GUI))) {} -void Func24(void) __attribute__((try_acquire_shared_capability(1, GUI))) {} +int Func23(void) __attribute__((try_acquire_capability(1, GUI))) {} +int Func24(void) __attribute__((try_acquire_shared_capability(1, GUI))) {} -void Func25(void) __attribute__((try_acquire_capability())) {} // expected-error {{'try_acquire_capability' attribute takes at least 1 argument}} -void Func26(void) __attribute__((try_acquire_shared_capability())) {} // expected-error {{'try_acquire_shared_capability' attribute takes at least 1 argument}} +int Func25(void) __attribute__((try_acquire_capability())) {} // expected-error {{'try_acquire_capability' attribute takes at least 1 argument}} +int Func26(void) __attribute__((try_acquire_shared_capability())) {} // expected-error {{'try_acquire_shared_capability' attribute takes at least 1 argument}} // Test that boolean logic works with capability attributes void Func27(void) __attribute__((requires_capability(!GUI))); diff --git a/clang/test/Sema/attr-nonblocking-sema.c b/clang/test/Sema/attr-nonblocking-sema.c new file mode 100644 index 00000000000000..0647e47febef20 --- /dev/null +++ b/clang/test/Sema/attr-nonblocking-sema.c @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c89 %s + +// Tests for a few cases involving C functions without prototypes. + +void noproto() __attribute__((nonblocking)) // expected-error {{'nonblocking' function must have a prototype}} +{ +} + +// This will succeed +void noproto(void) __attribute__((blocking)); + +// A redeclaration isn't any different - a prototype is required. +void f1(void); +void f1() __attribute__((nonblocking)); // expected-error {{'nonblocking' function must have a prototype}} diff --git a/clang/test/Sema/attr-nonblocking-sema.cpp b/clang/test/Sema/attr-nonblocking-sema.cpp new file mode 100644 index 00000000000000..38bf2ac8f8a4cc --- /dev/null +++ b/clang/test/Sema/attr-nonblocking-sema.cpp @@ -0,0 +1,183 @@ +// RUN: %clang_cc1 -fsyntax-only -fblocks -fcxx-exceptions -verify %s +// RUN: %clang_cc1 -fsyntax-only -fblocks -verify -x c -std=c23 %s + +#if !__has_attribute(nonblocking) +#error "the 'nonblocking' attribute is not available" +#endif + +// --- ATTRIBUTE SYNTAX: SUBJECTS --- + +int nl_var [[clang::nonblocking]]; // expected-warning {{'nonblocking' only applies to function types; type here is 'int'}} +struct nl_struct {} [[clang::nonblocking]]; // expected-warning {{attribute 'nonblocking' is ignored, place it after "struct" to apply attribute to type declaration}} +struct [[clang::nonblocking]] nl_struct2 {}; // expected-error {{'nonblocking' attribute cannot be applied to a declaration}} + +// Positive case +typedef void (*fo)() [[clang::nonblocking]]; +void (*read_me_and_weep( + int val, void (*func)(int) [[clang::nonblocking]]) + [[clang::nonblocking]]) (int) + [[clang::nonblocking]]; + +// --- ATTRIBUTE SYNTAX: ARGUMENT COUNT --- +void nargs_1() [[clang::nonblocking(1, 2)]]; // expected-error {{'nonblocking' attribute takes no more than 1 argument}} +void nargs_2() [[clang::nonallocating(1, 2)]]; // expected-error {{'nonallocating' attribute takes no more than 1 argument}} +void nargs_3() [[clang::blocking(1)]]; // expected-error {{'blocking' attribute takes no arguments}} +void nargs_4() [[clang::allocating(1)]]; // expected-error {{'allocating' attribute takes no arguments}} + +// --- ATTRIBUTE SYNTAX: COMBINATIONS --- +// Check invalid combinations of nonblocking/nonallocating attributes + +void nl_true_false_1() [[clang::nonblocking(true)]] [[clang::blocking]]; // expected-error {{'blocking' and 'nonblocking' attributes are not compatible}} +void nl_true_false_2() [[clang::blocking]] [[clang::nonblocking(true)]]; // expected-error {{'nonblocking' and 'blocking' attributes are not compatible}} + +void nl_true_false_3() [[clang::nonblocking, clang::blocking]]; // expected-error {{'blocking' and 'nonblocking' attributes are not compatible}} +void nl_true_false_4() [[clang::blocking, clang::nonblocking]]; // expected-error {{'nonblocking' and 'blocking' attributes are not compatible}} + +void na_true_false_1() [[clang::nonallocating(true)]] [[clang::allocating]]; // expected-error {{'allocating' and 'nonallocating' attributes are not compatible}} +void na_true_false_2() [[clang::allocating]] [[clang::nonallocating(true)]]; // expected-error {{'nonallocating' and 'allocating' attributes are not compatible}} + +void na_true_false_3() [[clang::nonallocating, clang::allocating]]; // expected-error {{'allocating' and 'nonallocating' attributes are not compatible}} +void na_true_false_4() [[clang::allocating, clang::nonallocating]]; // expected-error {{'nonallocating' and 'allocating' attributes are not compatible}} + +void nl_true_na_true_1() [[clang::nonblocking]] [[clang::nonallocating]]; +void nl_true_na_true_2() [[clang::nonallocating]] [[clang::nonblocking]]; + +void nl_true_na_false_1() [[clang::nonblocking]] [[clang::allocating]]; // expected-error {{'allocating' and 'nonblocking' attributes are not compatible}} +void nl_true_na_false_2() [[clang::allocating]] [[clang::nonblocking]]; // expected-error {{'nonblocking' and 'allocating' attributes are not compatible}} + +void nl_false_na_true_1() [[clang::blocking]] [[clang::nonallocating]]; +void nl_false_na_true_2() [[clang::nonallocating]] [[clang::blocking]]; + +void nl_false_na_false_1() [[clang::blocking]] [[clang::allocating]]; +void nl_false_na_false_2() [[clang::allocating]] [[clang::blocking]]; + +// --- TYPE CONVERSIONS --- + +void unannotated(); +void nonblocking() [[clang::nonblocking]]; +void nonallocating() [[clang::nonallocating]]; +void type_conversions() +{ + // It's fine to remove a performance constraint. + void (*fp_plain)(); + + fp_plain = nullptr; + fp_plain = unannotated; + fp_plain = nonblocking; + fp_plain = nonallocating; + + // Adding/spoofing nonblocking is unsafe. + void (*fp_nonblocking)() [[clang::nonblocking]]; + fp_nonblocking = nullptr; + fp_nonblocking = nonblocking; + fp_nonblocking = unannotated; // expected-warning {{attribute 'nonblocking' should not be added via type conversion}} + fp_nonblocking = nonallocating; // expected-warning {{attribute 'nonblocking' should not be added via type conversion}} + + // Adding/spoofing nonallocating is unsafe. + void (*fp_nonallocating)() [[clang::nonallocating]]; + fp_nonallocating = nullptr; + fp_nonallocating = nonallocating; + fp_nonallocating = nonblocking; // no warning because nonblocking includes nonallocating fp_nonallocating = unannotated; + fp_nonallocating = unannotated; // expected-warning {{attribute 'nonallocating' should not be added via type conversion}} +} + +#ifdef __cplusplus +struct PTMF { + void unannotated(); + void nonblocking() [[clang::nonblocking]]; + void nonallocating() [[clang::nonallocating]]; +}; + +void type_conversions_ptmf() +{ + // It's fine to remove a performance constraint. + void (PTMF::*ptmf_plain)() = nullptr; + + ptmf_plain = &PTMF::unannotated; + ptmf_plain = &PTMF::nonblocking; + ptmf_plain = &PTMF::nonallocating; + + // Adding/spoofing nonblocking is unsafe. + void (PTMF::*fp_nonblocking)() [[clang::nonblocking]] = nullptr; + fp_nonblocking = &PTMF::nonblocking; + fp_nonblocking = &PTMF::unannotated; // expected-warning {{attribute 'nonblocking' should not be added via type conversion}} + fp_nonblocking = &PTMF::nonallocating; // expected-warning {{attribute 'nonblocking' should not be added via type conversion}} + + // Adding/spoofing nonallocating is unsafe. + void (PTMF::*fp_nonallocating)() [[clang::nonallocating]] = nullptr; + fp_nonallocating = &PTMF::nonallocating; + fp_nonallocating = &PTMF::nonblocking; // no warning because nonblocking includes nonallocating fp_nonallocating = unannotated; + fp_nonallocating = &PTMF::unannotated; // expected-warning {{attribute 'nonallocating' should not be added via type conversion}} +} + +// There was a bug: noexcept and nonblocking could be individually removed in conversion, but not both +void type_conversions_2() +{ + auto receives_fp = [](void (*fp)()) { + }; + + auto ne = +[]() noexcept {}; + auto nl = +[]() [[clang::nonblocking]] {}; + auto nl_ne = +[]() noexcept [[clang::nonblocking]] {}; + + receives_fp(ne); + receives_fp(nl); + receives_fp(nl_ne); +} +#endif + +// --- VIRTUAL METHODS --- +// Attributes propagate to overridden methods, so no diagnostics except for conflicts. +// Check this in the syntax tests too. +#ifdef __cplusplus +struct Base { + virtual void f1(); + virtual void nonblocking() noexcept [[clang::nonblocking]]; + virtual void nonallocating() noexcept [[clang::nonallocating]]; + virtual void f2() [[clang::nonallocating]]; // expected-note {{previous declaration is here}} +}; + +struct Derived : public Base { + void f1() [[clang::nonblocking]] override; + void nonblocking() noexcept override; + void nonallocating() noexcept override; + void f2() [[clang::allocating]] override; // expected-warning {{effects conflict when merging declarations; kept 'allocating', discarded 'nonallocating'}} +}; +#endif // __cplusplus + +// --- REDECLARATIONS --- + +void f2(); +void f2() [[clang::nonblocking]]; // expected-note {{previous declaration is here}} +void f2(); // expected-warning {{attribute 'nonblocking' on function does not match previous declaration}} +// Note: we verify that the attribute is actually seen during the constraints tests. + +void f3() [[clang::blocking]]; // expected-note {{previous declaration is here}} +void f3() [[clang::nonblocking]]; // expected-warning {{effects conflict when merging declarations; kept 'blocking', discarded 'nonblocking'}} + +// --- OVERLOADS --- +#ifdef __cplusplus +struct S { + void foo(); // expected-note {{previous declaration is here}} + void foo() [[clang::nonblocking]]; // expected-error {{class member cannot be redeclared}} +}; +#endif // __cplusplus + +// --- COMPUTED NONBLOCKING --- +void f4() [[clang::nonblocking(__builtin_memset)]] {} // expected-error {{nonblocking attribute requires an integer constant}} + +#ifdef __cplusplus +// Unexpanded parameter pack +template +void f5() [[clang::nonblocking(val /* NO ... here */)]] {} // expected-error {{expression contains unexpanded parameter pack 'val'}} + +void f6() { f5(); } + +template +void ambiguous() [[clang::nonblocking(B)]] [[clang::blocking]]; // expected-note {{candidate template ignored: substitution failure [with B = true]: 'blocking' and 'nonblocking' attributes are not compatible}} + +void f7() { + ambiguous(); // expected-error {{no matching function for call to 'ambiguous'}} + ambiguous(); +} +#endif // __cplusplus diff --git a/clang/test/Sema/attr-nonblocking-syntax.cpp b/clang/test/Sema/attr-nonblocking-syntax.cpp new file mode 100644 index 00000000000000..644ed754b04daa --- /dev/null +++ b/clang/test/Sema/attr-nonblocking-syntax.cpp @@ -0,0 +1,216 @@ +// RUN: %clang_cc1 %s -ast-dump -fblocks | FileCheck %s + +// Make sure that the attribute gets parsed and attached to the correct AST elements. + +#pragma clang diagnostic ignored "-Wunused-variable" + +// ========================================================================================= +// Square brackets, true + +namespace square_brackets { + +// 1. On the type of the FunctionDecl +void nl_function() [[clang::nonblocking]]; +// CHECK: FunctionDecl {{.*}} nl_function 'void () __attribute__((nonblocking))' + +// 2. On the type of the VarDecl holding a function pointer +void (*nl_func_a)() [[clang::nonblocking]]; +// CHECK: VarDecl {{.*}} nl_func_a 'void (*)() __attribute__((nonblocking))' + +// 3. On the type of the ParmVarDecl of a function parameter +static void nlReceiver(void (*nl_func)() [[clang::nonblocking]]); +// CHECK: ParmVarDecl {{.*}} nl_func 'void (*)() __attribute__((nonblocking))' + +// 4. As an AttributedType within the nested types of a typedef +typedef void (*nl_fp_type)() [[clang::nonblocking]]; +// CHECK: TypedefDecl {{.*}} nl_fp_type 'void (*)() __attribute__((nonblocking))' +using nl_fp_talias = void (*)() [[clang::nonblocking]]; +// CHECK: TypeAliasDecl {{.*}} nl_fp_talias 'void (*)() __attribute__((nonblocking))' + +// 5. From a typedef or typealias, on a VarDecl +nl_fp_type nl_fp_var1; +// CHECK: VarDecl {{.*}} nl_fp_var1 'nl_fp_type':'void (*)() __attribute__((nonblocking))' +nl_fp_talias nl_fp_var2; +// CHECK: VarDecl {{.*}} nl_fp_var2 'nl_fp_talias':'void (*)() __attribute__((nonblocking))' + +// 6. On type of a FieldDecl +struct Struct { + void (*nl_func_field)() [[clang::nonblocking]]; +// CHECK: FieldDecl {{.*}} nl_func_field 'void (*)() __attribute__((nonblocking))' +}; + +// nonallocating should NOT be subsumed into nonblocking +void nl1() [[clang::nonblocking]] [[clang::nonallocating]]; +// CHECK: FunctionDecl {{.*}} nl1 'void () __attribute__((nonblocking)) __attribute__((nonallocating))' + +void nl2() [[clang::nonallocating]] [[clang::nonblocking]]; +// CHECK: FunctionDecl {{.*}} nl2 'void () __attribute__((nonblocking)) __attribute__((nonallocating))' + +decltype(nl1) nl3; +// CHECK: FunctionDecl {{.*}} nl3 'decltype(nl1)':'void () __attribute__((nonblocking)) __attribute__((nonallocating))' + +// Attribute propagates from base class virtual method to overrides. +struct Base { + virtual void nb_method() [[clang::nonblocking]]; +}; +struct Derived : public Base { + void nb_method() override; + // CHECK: CXXMethodDecl {{.*}} nb_method 'void () __attribute__((nonblocking))' +}; + +// Dependent expression +template +struct Dependent { + void nb_method2() [[clang::nonblocking(V)]]; + // CHECK: CXXMethodDecl {{.*}} nb_method2 'void () __attribute__((nonblocking(V)))' +}; + +// --- Blocks --- + +// On the type of the VarDecl holding a BlockDecl +void (^nl_block1)() [[clang::nonblocking]] = ^() [[clang::nonblocking]] {}; +// CHECK: VarDecl {{.*}} nl_block1 'void (^)() __attribute__((nonblocking))' + +int (^nl_block2)() [[clang::nonblocking]] = ^() [[clang::nonblocking]] { return 0; }; +// CHECK: VarDecl {{.*}} nl_block2 'int (^)() __attribute__((nonblocking))' + +// The operand of the CallExpr is an ImplicitCastExpr of a DeclRefExpr -> nl_block which hold the attribute +static void blockCaller() { nl_block1(); } +// CHECK: DeclRefExpr {{.*}} 'nl_block1' 'void (^)() __attribute__((nonblocking))' + +// --- Lambdas --- + +// On the operator() of a lambda's CXXMethodDecl +auto nl_lambda = []() [[clang::nonblocking]] {}; +// CHECK: CXXMethodDecl {{.*}} operator() 'void () const __attribute__((nonblocking))' inline + +// ========================================================================================= +// Square brackets, false + +void nl_func_false() [[clang::blocking]]; +// CHECK: FunctionDecl {{.*}} nl_func_false 'void () __attribute__((blocking))' + +auto nl_lambda_false = []() [[clang::blocking]] {}; +// CHECK: CXXMethodDecl {{.*}} operator() 'void () const __attribute__((blocking))' + +} // namespace square_brackets + +// ========================================================================================= +// GNU-style attribute, true + +namespace gnu_style { + +// 1. On the type of the FunctionDecl +void nl_function() __attribute__((nonblocking)); +// CHECK: FunctionDecl {{.*}} nl_function 'void () __attribute__((nonblocking))' + +// 1a. Alternate placement on the FunctionDecl +__attribute__((nonblocking)) void nl_function(); +// CHECK: FunctionDecl {{.*}} nl_function 'void () __attribute__((nonblocking))' + +// 2. On the type of the VarDecl holding a function pointer +void (*nl_func_a)() __attribute__((nonblocking)); +// CHECK: VarDecl {{.*}} nl_func_a 'void (*)() __attribute__((nonblocking))' + +// 2a. Alternate attribute placement on VarDecl +__attribute__((nonblocking)) void (*nl_func_b)(); +// CHECK: VarDecl {{.*}} nl_func_b 'void (*)() __attribute__((nonblocking))' + +// 3. On the type of the ParmVarDecl of a function parameter +static void nlReceiver(void (*nl_func)() __attribute__((nonblocking))); +// CHECK: ParmVarDecl {{.*}} nl_func 'void (*)() __attribute__((nonblocking))' + +// 4. As an AttributedType within the nested types of a typedef +// Note different placement from square brackets for the typealias. +typedef void (*nl_fp_type)() __attribute__((nonblocking)); +// CHECK: TypedefDecl {{.*}} nl_fp_type 'void (*)() __attribute__((nonblocking))' +using nl_fp_talias = __attribute__((nonblocking)) void (*)(); +// CHECK: TypeAliasDecl {{.*}} nl_fp_talias 'void (*)() __attribute__((nonblocking))' + +// 5. From a typedef or typealias, on a VarDecl +nl_fp_type nl_fp_var1; +// CHECK: VarDecl {{.*}} nl_fp_var1 'nl_fp_type':'void (*)() __attribute__((nonblocking))' +nl_fp_talias nl_fp_var2; +// CHECK: VarDecl {{.*}} nl_fp_var2 'nl_fp_talias':'void (*)() __attribute__((nonblocking))' + +// 6. On type of a FieldDecl +struct Struct { + void (*nl_func_field)() __attribute__((nonblocking)); +// CHECK: FieldDecl {{.*}} nl_func_field 'void (*)() __attribute__((nonblocking))' +}; + +} // namespace gnu_style + +// ========================================================================================= +// nonallocating and allocating - quick checks because the code paths are generally +// identical after parsing. + +void na_function() [[clang::nonallocating]]; +// CHECK: FunctionDecl {{.*}} na_function 'void () __attribute__((nonallocating))' + +void na_true_function() [[clang::nonallocating(true)]]; +// CHECK: FunctionDecl {{.*}} na_true_function 'void () __attribute__((nonallocating))' + +void na_false_function() [[clang::nonallocating(false)]]; +// CHECK: FunctionDecl {{.*}} na_false_function 'void () __attribute__((allocating))' + +void alloc_function() [[clang::allocating]]; +// CHECK: FunctionDecl {{.*}} alloc_function 'void () __attribute__((allocating))' + + +// ========================================================================================= +// Non-blocking with an expression parameter + +void t0() [[clang::nonblocking(1 - 1)]]; +// CHECK: FunctionDecl {{.*}} t0 'void () __attribute__((blocking))' +void t1() [[clang::nonblocking(1 + 1)]]; +// CHECK: FunctionDecl {{.*}} t1 'void () __attribute__((nonblocking))' + +template +struct ValueDependent { + void nb_method() [[clang::nonblocking(V)]]; +}; + +void t3() [[clang::nonblocking]] +{ + ValueDependent x1; + x1.nb_method(); +// CHECK: ClassTemplateSpecializationDecl {{.*}} ValueDependent +// CHECK: TemplateArgument integral 'false' +// CHECK: CXXMethodDecl {{.*}} nb_method 'void () __attribute__((blocking))' + + ValueDependent x2; + x2.nb_method(); +// CHECK: ClassTemplateSpecializationDecl {{.*}} ValueDependent +// CHECK: TemplateArgument integral 'true' +// CHECK: CXXMethodDecl {{.*}} nb_method 'void () __attribute__((nonblocking))' +} + +template +struct TypeDependent { + void td_method() [[clang::nonblocking(X::is_nb)]]; +}; + +struct NBPolicyTrue { + static constexpr bool is_nb = true; +}; + +struct NBPolicyFalse { + static constexpr bool is_nb = false; +}; + +void t4() +{ + TypeDependent x1; + x1.td_method(); +// CHECK: ClassTemplateSpecializationDecl {{.*}} TypeDependent +// CHECK: TemplateArgument type 'NBPolicyFalse' +// CHECK: CXXMethodDecl {{.*}} td_method 'void () __attribute__((blocking))' + + TypeDependent x2; + x2.td_method(); +// CHECK: ClassTemplateSpecializationDecl {{.*}} TypeDependent +// CHECK: TemplateArgument type 'NBPolicyTrue' +// CHECK: CXXMethodDecl {{.*}} td_method 'void () __attribute__((nonblocking))' +} + diff --git a/clang/test/Sema/preserve-none-call-conv.c b/clang/test/Sema/preserve-none-call-conv.c index 4508095863de5c..678fa7d5317e55 100644 --- a/clang/test/Sema/preserve-none-call-conv.c +++ b/clang/test/Sema/preserve-none-call-conv.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 %s -fsyntax-only -triple x86_64-unknown-unknown -verify +// RUN: %clang_cc1 %s -fsyntax-only -triple aarch64-unknown-unknown -verify typedef void typedef_fun_t(int); diff --git a/clang/test/Sema/ptrauth.c b/clang/test/Sema/ptrauth.c index cd069881793c5d..fc1ae954fa36be 100644 --- a/clang/test/Sema/ptrauth.c +++ b/clang/test/Sema/ptrauth.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple arm64-apple-ios -fsyntax-only -verify -fptrauth-intrinsics %s +// RUN: %clang_cc1 -triple arm64-apple-ios -fsyntax-only -verify -fptrauth-intrinsics %s -fexperimental-new-constant-interpreter #if __has_feature(ptrauth_intrinsics) #warning Pointer authentication enabled! diff --git a/clang/test/SemaCUDA/neon-attrs.cu b/clang/test/SemaCUDA/neon-attrs.cu deleted file mode 100644 index 129056741ac9a4..00000000000000 --- a/clang/test/SemaCUDA/neon-attrs.cu +++ /dev/null @@ -1,22 +0,0 @@ -// CPU-side compilation on ARM with neon enabled (no errors expected). -// RUN: %clang_cc1 -triple arm64-linux-gnu -target-feature +neon -aux-triple nvptx64 -x cuda -fsyntax-only -verify=quiet %s - -// CPU-side compilation on ARM with neon disabled. -// RUN: %clang_cc1 -triple arm64-linux-gnu -target-feature -neon -aux-triple nvptx64 -x cuda -fsyntax-only -verify %s - -// GPU-side compilation on ARM (no errors expected). -// RUN: %clang_cc1 -triple nvptx64 -aux-triple arm64-linux-gnu -fcuda-is-device -x cuda -fsyntax-only -verify=quiet %s - -// Regular C++ compilation on ARM with neon enabled (no errors expected). -// RUN: %clang_cc1 -triple arm64-linux-gnu -target-feature +neon -x c++ -fsyntax-only -verify=quiet %s - -// Regular C++ compilation on ARM with neon disabled. -// RUN: %clang_cc1 -triple arm64-linux-gnu -target-feature -neon -x c++ -fsyntax-only -verify %s - -// quiet-no-diagnostics -typedef __attribute__((neon_vector_type(4))) float float32x4_t; -// expected-error@-1 {{'neon_vector_type' attribute is not supported on targets missing 'neon', 'mve', 'sve' or 'sme'}} -// expect -typedef unsigned char poly8_t; -typedef __attribute__((neon_polyvector_type(8))) poly8_t poly8x8_t; -// expected-error@-1 {{'neon_polyvector_type' attribute is not supported on targets missing 'neon' or 'mve'}} diff --git a/clang/test/SemaCXX/atomic-ops.cpp b/clang/test/SemaCXX/atomic-ops.cpp index 213161364f5852..30d829d1e97d79 100644 --- a/clang/test/SemaCXX/atomic-ops.cpp +++ b/clang/test/SemaCXX/atomic-ops.cpp @@ -7,3 +7,18 @@ void PR28623() { void helper(char); // expected-note{{target}} __atomic_store_n(helper, 0, 0); // expected-error{{reference to overloaded function could not be resolved}} } + +template +struct X { + char arr[1]; +}; + +extern X* p, *q; + +// They should be accepted. +void f() { + __atomic_exchange(p, p, q, __ATOMIC_RELAXED); + __atomic_load(p, p, __ATOMIC_RELAXED); + __atomic_store(p, p, __ATOMIC_RELAXED); + __atomic_compare_exchange(p, p, q, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED); +} diff --git a/clang/test/SemaCXX/coroutine-vla.cpp b/clang/test/SemaCXX/coroutine-vla.cpp index 176e35f346e2b4..996c89025e2ad1 100644 --- a/clang/test/SemaCXX/coroutine-vla.cpp +++ b/clang/test/SemaCXX/coroutine-vla.cpp @@ -16,6 +16,12 @@ struct promise void unhandled_exception(); }; +// Test that we won't report the error incorrectly. +void bar(int n) { + int array[n]; + return; +} + coroutine foo(int n) { int array[n]; // expected-error {{variable length arrays in a coroutine are not supported}} co_return; diff --git a/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp b/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp index 74aa7cb2abe836..41b4f6dc308d9d 100644 --- a/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp +++ b/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s -fexperimental-new-constant-interpreter // RUN: %clang_cc1 -std=c++11 -fsyntax-only -DUNION_TEST -verify %s #ifdef UNION_TEST diff --git a/clang/test/SemaCXX/lambda-call.cpp b/clang/test/SemaCXX/lambda-call.cpp new file mode 100644 index 00000000000000..2c5b8b9a4b176b --- /dev/null +++ b/clang/test/SemaCXX/lambda-call.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -std=c++23 -verify -fsyntax-only %s + +namespace GH96205 { + +void f() { + auto l = [](this auto& self, int) -> void { self("j"); }; // expected-error {{no matching function for call to object of type}} \ + // expected-note {{no known conversion from 'const char[2]' to 'int'}} + l(3); // expected-note {{requested here}} +} + +} diff --git a/clang/test/SemaCXX/ptrauth-incomplete-virtual-member-function-return-arg-type.cpp b/clang/test/SemaCXX/ptrauth-incomplete-virtual-member-function-return-arg-type.cpp new file mode 100644 index 00000000000000..41bbba0e832fda --- /dev/null +++ b/clang/test/SemaCXX/ptrauth-incomplete-virtual-member-function-return-arg-type.cpp @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -std=c++17 -Wno-vla -fsyntax-only -verify -fptrauth-intrinsics -fptrauth-calls %s + +struct Incomplete0; // expected-note 3 {{forward declaration of 'Incomplete0'}} + +template +struct Incomplete1; // expected-note {{template is declared here}} + +struct Complete0 { +}; + +template +struct Complete1 { +}; + +struct S { + virtual int foo(); + virtual Incomplete0 virtual0(); // expected-note 2 {{'Incomplete0' is incomplete}} + virtual void virtual1(Incomplete1); // expected-note {{'Incomplete1' is incomplete}} + virtual Complete0 virtual2(); + virtual Complete1 virtual3(); + Incomplete0 nonvirtual0(); + template + void m0() { + (void)&S::virtual0; // expected-error {{incomplete type 'Incomplete0'}} expected-note {{cannot take an address of a virtual}} + } +}; + +template +struct S2 { + virtual Incomplete0 virtual0() noexcept(T); // expected-note {{'Incomplete0' is incomplete}} + + void m0() { + (void)&S2::virtual0; + } + + void m1() { + (void)&S2::virtual0; // expected-error {{incomplete type 'Incomplete0'}} expected-note {{cannot take an address of a virtual}} + } +}; + +void test_incomplete_virtual_member_function_return_arg_type() { + (void)&S::virtual0; // expected-error {{incomplete type 'Incomplete0}} expected-note {{cannot take an address of a virtual member function}} + (void)&S::virtual1; // expected-error {{implicit instantiation of undefined template 'Incomplete1'}} expected-note {{cannot take an address of a virtual member function}} + (void)&S::virtual2; + (void)&S::virtual3; + (void)&S::nonvirtual0; + int s = sizeof(&S::virtual0); + S2().m1(); // expected-note {{in instantiation of}} +} + diff --git a/clang/test/SemaCXX/verbose-trap.cpp b/clang/test/SemaCXX/verbose-trap.cpp new file mode 100644 index 00000000000000..2503f9860d9c34 --- /dev/null +++ b/clang/test/SemaCXX/verbose-trap.cpp @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fcxx-exceptions -verify %s +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -verify %s + +#if !__has_builtin(__builtin_verbose_trap) +#error +#endif + +constexpr char const* constCat1 = "cat"; +char const* const constCat2 = "cat"; +char const constCat3[] = "cat"; + +constexpr char const* constMsg1 = "hello"; +char const* const constMsg2 = "hello"; +char const constMsg3[] = "hello"; + +template +void f(const char * arg) { + __builtin_verbose_trap("cat1", "Arbitrary string literals can be used!"); + __builtin_verbose_trap(" cat1 ", "Argument_must_not_be_null"); + __builtin_verbose_trap("cat" "egory1", "hello" "world"); + __builtin_verbose_trap(constCat1, constMsg1); + __builtin_verbose_trap(constCat2, constMsg2); + __builtin_verbose_trap("", ""); + __builtin_verbose_trap(); // expected-error {{too few arguments}} + __builtin_verbose_trap(""); // expected-error {{too few arguments}} + __builtin_verbose_trap("", "", ""); // expected-error {{too many arguments}} + __builtin_verbose_trap("", 0); // expected-error {{argument to __builtin_verbose_trap must be a pointer to a constant string}} + __builtin_verbose_trap(1, ""); // expected-error {{cannot initialize a parameter of type 'const char *' with an rvalue of type 'int'}} + __builtin_verbose_trap(arg, ""); // expected-error {{argument to __builtin_verbose_trap must be a pointer to a constant string}} + __builtin_verbose_trap("cat$1", "hel$lo"); // expected-error 2 {{argument to __builtin_verbose_trap must not contain $}} + __builtin_verbose_trap(category, reason); + __builtin_verbose_trap(u8"cat1", u8"hello"); +#if __cplusplus >= 202002L + // FIXME: Accept c++20 u8 string literals. + // expected-error@-3 {{cannot initialize a parameter of type 'const char *' with an lvalue of type 'const char8_t[5]'}} +#endif + __builtin_verbose_trap("", "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"); +} + +template +void f2() { + __builtin_verbose_trap(category, 1); // expected-error {{cannot initialize a parameter of type 'const char *' with an rvalue of type 'int'}} +} + +void test() { + f(nullptr); +} diff --git a/clang/test/SemaCXX/vtable_pointer_authentication_attribute.cpp b/clang/test/SemaCXX/vtable_pointer_authentication_attribute.cpp new file mode 100644 index 00000000000000..3a3386196fbfa5 --- /dev/null +++ b/clang/test/SemaCXX/vtable_pointer_authentication_attribute.cpp @@ -0,0 +1,225 @@ +// RUN: %clang_cc1 -fsyntax-only -triple arm64-apple-ios -verify -fptrauth-calls -std=c++2a %s + +namespace basic { + +#define authenticated(a, b, c...) [[clang::ptrauth_vtable_pointer(a, b, c)]] + +// Basic sanity tests +#define TEST_AUTH(name, auth...) \ + struct [[clang::ptrauth_vtable_pointer(auth)]] name { \ + virtual ~name() {} \ + } + +TEST_AUTH(NoParams); +// expected-error@-1{{'ptrauth_vtable_pointer' attribute takes at least 3 arguments}} +TEST_AUTH(NoAuth, no_authentication, default_address_discrimination, default_extra_discrimination); +TEST_AUTH(InvalidKey, wat, default_address_discrimination, default_extra_discrimination); +// expected-error@-1{{invalid authentication key 'wat'}} +TEST_AUTH(InvalidAddressDiscrimination, no_authentication, wat, default_extra_discrimination); +// expected-error@-1{{invalid address discrimination mode 'wat'}} +TEST_AUTH(InvalidExtraDiscrimination, no_authentication, default_address_discrimination, wat); +// expected-error@-1{{invalid extra discrimination selection 'wat'}} +TEST_AUTH(InvalidNoCustomDiscrimination, no_authentication, default_address_discrimination, custom_discrimination); +// expected-error@-1{{missing custom discrimination}} +TEST_AUTH(InvalidCustomDiscrimination, no_authentication, default_address_discrimination, custom_discrimination, wat); +// expected-error@-1{{invalid custom discrimination}} +TEST_AUTH(Default, default_key, default_address_discrimination, default_extra_discrimination); +TEST_AUTH(InvalidDefaultExtra, default_key, default_address_discrimination, default_extra_discrimination, 1); +// expected-error@-1{{'ptrauth_vtable_pointer' attribute takes no more than 3 arguments}} +TEST_AUTH(ProcessDependentKey, process_dependent, default_address_discrimination, default_extra_discrimination); +TEST_AUTH(ProcessIndependentKey, process_independent, default_address_discrimination, default_extra_discrimination); +TEST_AUTH(DefaultAddressDiscrimination, process_independent, default_address_discrimination, default_extra_discrimination); +TEST_AUTH(NoAddressDiscrimination, process_independent, no_address_discrimination, default_extra_discrimination); +TEST_AUTH(AddressDiscrimination, process_independent, address_discrimination, default_extra_discrimination); +TEST_AUTH(DefaultExtraDiscrimination, process_independent, default_address_discrimination, default_extra_discrimination); +TEST_AUTH(NoExtraDiscrimination, process_independent, default_address_discrimination, no_extra_discrimination); +TEST_AUTH(TypeExtraDiscrimination, process_independent, default_address_discrimination, type_discrimination); +TEST_AUTH(InvalidCustomExtraDiscrimination, process_independent, default_address_discrimination, custom_discrimination); +// expected-error@-1{{missing custom discrimination}} +TEST_AUTH(ValidCustomExtraDiscrimination, process_independent, default_address_discrimination, custom_discrimination, 1); + +// Basic valid authentication configuration +#define generic_authenticated \ + authenticated(process_independent, address_discrimination, type_discrimination) + +struct generic_authenticated ForwardDecl; + +struct generic_authenticated generic_authenticated InvalidDuplicateAttribute { + // expected-error@-1{{multiple vtable pointer authentication policies on 'InvalidDuplicateAttribute'}} + virtual ~InvalidDuplicateAttribute(){}; +}; +struct generic_authenticated ValidPolymorphic { + virtual ~ValidPolymorphic(){}; +}; +struct generic_authenticated InvalidMonomorphic { // expected-error{{cannot set vtable pointer authentication on monomorphic type 'InvalidMonomorphic'}} +}; +struct ValidMonomorphic { +}; + +struct ValidSubclass : ValidPolymorphic {}; +struct generic_authenticated InvalidSubclass : ValidPolymorphic {}; // expected-error{{cannot set vtable pointer authentication on 'InvalidSubclass' which is a subclass of polymorphic type 'ValidPolymorphic'}} + +// Awful template time +template +struct generic_authenticated ExplicitlyAuthedMonomorphicTemplateClass : T {}; +// expected-error@-1{{cannot set vtable pointer authentication on 'ExplicitlyAuthedMonomorphicTemplateClass' which is a subclass of polymorphic type 'ValidPolymorphic'}} +// expected-error@-2{{cannot set vtable pointer authentication on monomorphic type 'ExplicitlyAuthedMonomorphicTemplateClass'}} +template +struct generic_authenticated ExplicitlyAuthedPolymorphicTemplateClass : T { // expected-error{{cannot set vtable pointer authentication on 'ExplicitlyAuthedPolymorphicTemplateClass' which is a subclass of polymorphic type 'ValidPolymorphic'}} + virtual ~ExplicitlyAuthedPolymorphicTemplateClass(){}; +}; +template +struct UnauthedMonomorphicTemplateClass : T {}; +template +struct UnauthedPolymorphicTemplateClass : T { + virtual ~UnauthedPolymorphicTemplateClass(){}; +}; + +ExplicitlyAuthedMonomorphicTemplateClass test1; +// expected-note@-1{{in instantiation of template class 'basic::ExplicitlyAuthedMonomorphicTemplateClass' requested here}} +ExplicitlyAuthedMonomorphicTemplateClass test2; +// expected-note@-1{{in instantiation of template class 'basic::ExplicitlyAuthedMonomorphicTemplateClass' requested here}} +ExplicitlyAuthedPolymorphicTemplateClass test3; +// expected-note@-1{{in instantiation of template class 'basic::ExplicitlyAuthedPolymorphicTemplateClass' requested here}} +ExplicitlyAuthedPolymorphicTemplateClass test4; + +UnauthedMonomorphicTemplateClass test5; +UnauthedMonomorphicTemplateClass test6; +UnauthedPolymorphicTemplateClass test7; +UnauthedPolymorphicTemplateClass test8; + +// Just use a different policy from the generic macro to verify we won't complain +// about the insanity +struct authenticated(process_independent, no_address_discrimination, type_discrimination) SecondAuthenticatedPolymorphic { + virtual ~SecondAuthenticatedPolymorphic(){}; +}; +struct UnauthenticatedPolymorphic { + virtual ~UnauthenticatedPolymorphic(){}; +}; + +struct MultipleParents1 : ValidPolymorphic, SecondAuthenticatedPolymorphic, UnauthenticatedPolymorphic {}; +struct MultipleParents2 : UnauthenticatedPolymorphic, ValidPolymorphic, SecondAuthenticatedPolymorphic {}; +struct generic_authenticated InvalidMultipleParents : UnauthenticatedPolymorphic, ValidPolymorphic, SecondAuthenticatedPolymorphic {}; +// expected-error@-1{{cannot set vtable pointer authentication on 'InvalidMultipleParents' which is a subclass of polymorphic type 'UnauthenticatedPolymorphic'}} + +template +struct generic_authenticated ExplicitlyAuthedPolymorphicTemplateClassNoBase { + virtual ~ExplicitlyAuthedPolymorphicTemplateClassNoBase(); +}; + +ExplicitlyAuthedPolymorphicTemplateClassNoBase v; + +struct ValidSubclassOfTemplate : ExplicitlyAuthedPolymorphicTemplateClassNoBase { +}; + +struct generic_authenticated InvalidSubclassOfTemplate : ExplicitlyAuthedPolymorphicTemplateClassNoBase { + // expected-error@-1{{cannot set vtable pointer authentication on 'InvalidSubclassOfTemplate' which is a subclass of polymorphic type 'ExplicitlyAuthedPolymorphicTemplateClassNoBase'}} +}; + +template +struct generic_authenticated ExplicitlyAuthedMonomorphicTemplateClassNoBase { + // expected-error@-1{{cannot set vtable pointer authentication on monomorphic type 'ExplicitlyAuthedMonomorphicTemplateClassNoBase'}} + // expected-error@-2{{cannot set vtable pointer authentication on monomorphic type 'ExplicitlyAuthedMonomorphicTemplateClassNoBase'}} +}; + +ExplicitlyAuthedMonomorphicTemplateClassNoBase X; +// expected-note@-1{{in instantiation of template class 'basic::ExplicitlyAuthedMonomorphicTemplateClassNoBase' requested here}} + +template +struct generic_authenticated ExplicitlyAuthedTemplateClassValidBase : ValidMonomorphic { + // expected-error@-1{{cannot set vtable pointer authentication on monomorphic type 'ExplicitlyAuthedTemplateClassValidBase'}} + // expected-error@-2{{cannot set vtable pointer authentication on monomorphic type 'ExplicitlyAuthedTemplateClassValidBase'}} +}; + +ExplicitlyAuthedTemplateClassValidBase Y; +// expected-note@-1{{in instantiation of template class 'basic::ExplicitlyAuthedTemplateClassValidBase' requested here}} + +template +struct generic_authenticated ExplicitlyAuthedTemplateClassInvalidBase : ValidPolymorphic { + // expected-error@-1{{cannot set vtable pointer authentication on 'ExplicitlyAuthedTemplateClassInvalidBase' which is a subclass of polymorphic type 'ValidPolymorphic'}} + // expected-error@-2{{cannot set vtable pointer authentication on 'ExplicitlyAuthedTemplateClassInvalidBase' which is a subclass of polymorphic type 'ValidPolymorphic'}} +}; + +ExplicitlyAuthedTemplateClassInvalidBase Z; +// expected-note@-1{{in instantiation of template class 'basic::ExplicitlyAuthedTemplateClassInvalidBase' requested here}} + +template +class generic_authenticated TestPolymorphicTemplateSpecialization; + +template <> +class TestPolymorphicTemplateSpecialization { + MissingDecl *zl; + // expected-error@-1 {{unknown type name 'MissingDecl'}} +public: + virtual ~TestPolymorphicTemplateSpecialization(); +}; +template +class generic_authenticated TestPolymorphicTemplateSpecialization +// expected-error@-1 {{cannot set vtable pointer authentication on monomorphic type 'TestPolymorphicTemplateSpecialization'}} +// expected-error@-2 {{cannot set vtable pointer authentication on monomorphic type 'TestPolymorphicTemplateSpecialization'}} +{ +}; + +TestPolymorphicTemplateSpecialization b; +TestPolymorphicTemplateSpecialization b2; +// expected-note@-1 {{in instantiation of template class 'basic::TestPolymorphicTemplateSpecialization' requested here}} + +template class generic_authenticated TestMonomorphic {}; +// expected-error@-1 {{cannot set vtable pointer authentication on monomorphic type 'TestMonomorphic'}} +// expected-error@-2 {{cannot set vtable pointer authentication on monomorphic type 'TestMonomorphic'}} + +template <> class generic_authenticated TestMonomorphic { +public: + virtual ~TestMonomorphic(); +}; + +struct TestMonomorphicSubclass : TestMonomorphic { +}; +template struct generic_authenticated TestMonomorphicSubclass2 : TestMonomorphic { + // expected-error@-1 {{cannot set vtable pointer authentication on 'TestMonomorphicSubclass2' which is a subclass of polymorphic type 'TestMonomorphic'}} + // expected-error@-2 {{cannot set vtable pointer authentication on monomorphic type 'TestMonomorphicSubclass2'}} + // expected-note@-3 {{in instantiation of template class 'basic::TestMonomorphic' requested here}} +}; + +TestMonomorphicSubclass tms_1; +TestMonomorphicSubclass2 tms2_1; +// expected-note@-1 {{in instantiation of template class 'basic::TestMonomorphicSubclass2' requested here}} +TestMonomorphicSubclass2 tms2_2; +// expected-note@-1 {{in instantiation of template class 'basic::TestMonomorphicSubclass2' requested here}} +// expected-note@-2 {{in instantiation of template class 'basic::TestMonomorphicSubclass2' requested here}} + +template +class generic_authenticated dependent_type { + // expected-error@-1 {{cannot set vtable pointer authentication on monomorphic type 'dependent_type'}} + static constexpr unsigned small_object_size = 1; + char _model[small_object_size]; +}; + +template +class generic_authenticated dependent_type2 : public T... { + // expected-error@-1 {{cannot set vtable pointer authentication on 'dependent_type2' which is a subclass of polymorphic type 'Foo'}} + static constexpr unsigned small_object_size = 1; + char _model[small_object_size]; +}; + +struct Foo { + virtual ~Foo(); +}; + +dependent_type2 thing; +// expected-note@-1 {{in instantiation of template class 'basic::dependent_type2' requested here}} + +template +class task; +template struct alignedthing { + char buffer[align]; +}; + +template +class generic_authenticated task { + // expected-error@-1 {{cannot set vtable pointer authentication on monomorphic type 'task'}} + static constexpr __SIZE_TYPE__ small_object_size = 256; + alignedthing _model; +}; + +} // namespace basic diff --git a/clang/test/SemaCXX/warn-explicit-specialization-storage-class.cpp b/clang/test/SemaCXX/warn-explicit-specialization-storage-class.cpp new file mode 100644 index 00000000000000..5d9ace292dc06c --- /dev/null +++ b/clang/test/SemaCXX/warn-explicit-specialization-storage-class.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -triple i686-pc-linux-gnu -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple i686-pc-linux-gnu -fsyntax-only -Wno-explicit-specialization-storage-class -verify=expnone %s + +// expnone-no-diagnostics + +struct A { + template + static constexpr int x = 0; + + template<> + static constexpr int x = 1; // expected-warning{{explicit specialization cannot have a storage class}} +}; + +template +static constexpr int x = 0; + +template<> +static constexpr int x = 1; // expected-warning{{explicit specialization cannot have a storage class}} diff --git a/clang/test/SemaCXX/warn-thread-safety-analysis.cpp b/clang/test/SemaCXX/warn-thread-safety-analysis.cpp index 73cc946ca0ce1c..a6ddf028e1fadb 100644 --- a/clang/test/SemaCXX/warn-thread-safety-analysis.cpp +++ b/clang/test/SemaCXX/warn-thread-safety-analysis.cpp @@ -1954,6 +1954,125 @@ struct TestTryLock { } // end namespace TrylockTest +// Regression test for trylock attributes with an enumerator success argument. +// Prior versions of the analysis silently failed to evaluate success arguments +// that were neither `CXXBoolLiteralExpr` nor `IntegerLiteral` and assumed the +// value was false. +namespace TrylockSuccessEnumFalseNegative { + +enum TrylockResult { Failure = 0, Success = 1 }; + +class LOCKABLE Mutex { +public: + TrylockResult TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(Success); + void Unlock() EXCLUSIVE_UNLOCK_FUNCTION(); +}; + +class TrylockTest { + Mutex mu_; + int a_ GUARDED_BY(mu_) = 0; + + void test_bool_expression() { + if (!mu_.TryLock()) { // expected-note {{mutex acquired here}} + a_++; // expected-warning {{writing variable 'a_' requires holding mutex 'mu_' exclusively}} + mu_.Unlock(); // expected-warning {{releasing mutex 'mu_' that was not held}} + } + } // expected-warning {{mutex 'mu_' is not held on every path through here}} +}; +} // namespace TrylockSuccessEnumFalseNegative + +// This test demonstrates that the analysis does not distinguish between +// different non-zero enumerators. +namespace TrylockFalseNegativeWhenEnumHasMultipleFailures { + +enum TrylockResult { Failure1 = 0, Failure2, Success }; + +class LOCKABLE Mutex { +public: + TrylockResult TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(Success); + void Unlock() EXCLUSIVE_UNLOCK_FUNCTION(); +}; + +class TrylockTest { + Mutex mu_; + int a_ GUARDED_BY(mu_) = 0; + + void test_eq_success() { + if (mu_.TryLock() == Success) { + a_++; + mu_.Unlock(); + } + } + + void test_bool_expression() { + // This branch checks whether the trylock function returned a non-zero + // value. This satisfies the analysis, but fails to account for `Failure2`. + // From the analysis's perspective, `Failure2` and `Success` are equivalent! + if (mu_.TryLock()) { + a_++; + mu_.Unlock(); + } + } +}; +} // namespace TrylockSuccessEnumMultipleFailureModesFalseNegative + + +// This test demonstrates that the analysis does not detect when all enumerators +// are positive, and thus incapable of representing a failure. +namespace TrylockSuccessEnumNoZeroFalseNegative { + +enum TrylockResult { Failure = 1, Success = 2 }; + +class LOCKABLE Mutex { +public: + TrylockResult TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(Success); + void Unlock() EXCLUSIVE_UNLOCK_FUNCTION(); +}; + +class TrylockTest { + Mutex mu_; + int a_ GUARDED_BY(mu_) = 0; + + void test_bool_expression() { + // This branch checks whether the trylock function returned a non-zero value + // This satisfies the analysis, but is actually incorrect because `Failure` + // and `Success` are both non-zero. + if (mu_.TryLock()) { + a_++; + mu_.Unlock(); + } + } +}; +} // namespace TrylockSuccessEnumNoZeroFalseNegative + + +// Demonstrate a mutex with a trylock function that conditionally vends a +// pointer to guarded data. +namespace TrylockFunctionReturnPointer { + +class LOCKABLE OwningMutex { +public: + int *TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true); + void Unlock() EXCLUSIVE_UNLOCK_FUNCTION(); + +private: + int guarded_ GUARDED_BY(this) = 0; +}; + +class TrylockTest { + OwningMutex mu_; + + void test_ptr_return() { + if (int *p = mu_.TryLock()) { + *p = 0; + mu_.Unlock(); + } + } +}; + +} // namespace TrylockFunctionReturnPointer + + namespace TestTemplateAttributeInstantiation { class Foo1 { @@ -3657,8 +3776,8 @@ class Foo { int a GUARDED_BY(mu_); bool c; - int tryLockMutexI() EXCLUSIVE_TRYLOCK_FUNCTION(1, mu_); - Mutex* tryLockMutexP() EXCLUSIVE_TRYLOCK_FUNCTION(1, mu_); + int tryLockMutexI() EXCLUSIVE_TRYLOCK_FUNCTION(1, mu_); + Mutex *tryLockMutexP() EXCLUSIVE_TRYLOCK_FUNCTION(1, mu_); void unlock() UNLOCK_FUNCTION(mu_); void test1(); diff --git a/clang/test/SemaCXX/warn-thread-safety-parsing.cpp b/clang/test/SemaCXX/warn-thread-safety-parsing.cpp index 0c5b0cc85897be..4921a75b84e398 100644 --- a/clang/test/SemaCXX/warn-thread-safety-parsing.cpp +++ b/clang/test/SemaCXX/warn-thread-safety-parsing.cpp @@ -716,15 +716,17 @@ int slf_function_bad_7() SHARED_LOCK_FUNCTION(0); // \ #error "Should support exclusive_trylock_function attribute" #endif -// takes a mandatory boolean or integer argument specifying the retval -// plus an optional list of locks (vars/fields) +// The attribute takes a mandatory boolean or integer argument specifying the +// retval plus an optional list of locks (vars/fields). The annotated function's +// return type should be boolean or integer. void etf_function() __attribute__((exclusive_trylock_function)); // \ // expected-error {{'exclusive_trylock_function' attribute takes at least 1 argument}} -void etf_function_args() EXCLUSIVE_TRYLOCK_FUNCTION(1, mu2); +void etf_function_args() EXCLUSIVE_TRYLOCK_FUNCTION(1, mu2); // \ + // expected-error {{'exclusive_trylock_function' attribute only applies to functions that return bool, integer, or a pointer type}} -void etf_function_arg() EXCLUSIVE_TRYLOCK_FUNCTION(1); // \ +int etf_function_arg() EXCLUSIVE_TRYLOCK_FUNCTION(1); // \ // expected-warning {{'exclusive_trylock_function' attribute without capability arguments can only be applied to non-static methods of a class}} int etf_testfn(int y) EXCLUSIVE_TRYLOCK_FUNCTION(1); // \ @@ -743,10 +745,23 @@ class EtfFoo { private: int test_field EXCLUSIVE_TRYLOCK_FUNCTION(1); // \ // expected-warning {{'exclusive_trylock_function' attribute only applies to functions}} - void test_method() EXCLUSIVE_TRYLOCK_FUNCTION(1); // \ + bool test_method() EXCLUSIVE_TRYLOCK_FUNCTION(1); // \ // expected-warning {{'exclusive_trylock_function' attribute without capability arguments refers to 'this', but 'EtfFoo' isn't annotated with 'capability' or 'scoped_lockable' attribute}} }; +// It does not make sense to annotate constructors/destructors as exclusive +// trylock functions because they cannot return a value. See +// . +class EtfConstructorDestructor { + EtfConstructorDestructor() EXCLUSIVE_TRYLOCK_FUNCTION(1, mu); // \ + // expected-error {{'exclusive_trylock_function' attribute only applies to functions that return bool, integer, or a pointer type}} + + ~EtfConstructorDestructor() EXCLUSIVE_TRYLOCK_FUNCTION(1, mu); // \ + // expected-error {{'exclusive_trylock_function' attribute only applies to functions that return bool, integer, or a pointer type}} + + Mutex mu; +}; + class EXCLUSIVE_TRYLOCK_FUNCTION(1) EtfTestClass { // \ // expected-warning {{'exclusive_trylock_function' attribute only applies to functions}} }; @@ -756,7 +771,68 @@ void etf_fun_params(int lvar EXCLUSIVE_TRYLOCK_FUNCTION(1)); // \ // Check argument parsing. -// legal attribute arguments +int global_int = 0; +int* etf_fun_with_global_ptr_success() EXCLUSIVE_TRYLOCK_FUNCTION(&global_int, &mu1); //\ + // expected-error {{'exclusive_trylock_function' attribute requires parameter 1 to be nullptr or a bool, int, or enum literal}} + +#ifdef CPP11 +constexpr int kTrylockSuccess = 1; +int etf_succ_constexpr() EXCLUSIVE_TRYLOCK_FUNCTION(kTrylockSuccess, mu2); // \ + // expected-error {{'exclusive_trylock_function' attribute requires parameter 1 to be nullptr or a bool, int, or enum literal}} + +int success_value_non_constant = 1; + +bool etf_succ_variable() EXCLUSIVE_TRYLOCK_FUNCTION(success_value_non_constant, mu2); //\ + // expected-error {{attribute requires parameter 1 to be nullptr or a bool, int, or enum literal}} +#endif + + +// Legal permutations of the first argument and function return type. +struct TrylockResult; + +#ifdef CPP11 +int* etf_fun_with_nullptr_success() EXCLUSIVE_TRYLOCK_FUNCTION(nullptr, &mu1); +#endif + +#ifndef __cplusplus +int* etf_fun_with_nullptr_success() EXCLUSIVE_TRYLOCK_FUNCTION(NULL, &mu1); +#endif + +int etf_succ_1_ret_i() EXCLUSIVE_TRYLOCK_FUNCTION(1, mu2); +bool etf_succ_1_ret_b() EXCLUSIVE_TRYLOCK_FUNCTION(1, mu2); +TrylockResult *etf_succ_1_ret_p() EXCLUSIVE_TRYLOCK_FUNCTION(1, mu2); + +int etf_succ_true_ret_i() EXCLUSIVE_TRYLOCK_FUNCTION(true, mu2); +bool etf_succ_true_ret_b() EXCLUSIVE_TRYLOCK_FUNCTION(true, mu2); +TrylockResult *etf_succ_true_ret_p() EXCLUSIVE_TRYLOCK_FUNCTION(true, mu2); + +int etf_succ_false_ret_i() EXCLUSIVE_TRYLOCK_FUNCTION(false, mu2); +bool etf_succ_false_ret_b() EXCLUSIVE_TRYLOCK_FUNCTION(false, mu2); +TrylockResult *etf_succ_false_ret_p() EXCLUSIVE_TRYLOCK_FUNCTION(false, mu2); + +enum TrylockSuccessEnum { TrylockNotAcquired = 0, TrylockAcquired }; +int etf_succ_enum_ret_i() EXCLUSIVE_TRYLOCK_FUNCTION(TrylockAcquired, mu2); +bool etf_succ_enum_ret_b() EXCLUSIVE_TRYLOCK_FUNCTION(TrylockAcquired, mu2); +TrylockResult *etf_succ_enum_ret_p() + EXCLUSIVE_TRYLOCK_FUNCTION(TrylockAcquired, mu2); + +#ifdef CPP11 +enum class TrylockSuccessEnumClass { NotAcquired = 0, Acquired}; +int etf_succ_enum_class_ret_i() + EXCLUSIVE_TRYLOCK_FUNCTION(TrylockSuccessEnumClass::Acquired, mu2); +bool etf_succ_enum_class_ret_b() + EXCLUSIVE_TRYLOCK_FUNCTION(TrylockSuccessEnumClass::Acquired, mu2); +TrylockResult *etf_succ_enum_class_ret_p() + EXCLUSIVE_TRYLOCK_FUNCTION(TrylockSuccessEnumClass::Acquired, mu2); +#endif + +// Demonstrate that we do not detect enum type mismatches between the success +// argument and the function's return type. +enum SomeOtherEnum { Foo = 1 }; +TrylockSuccessEnum etf_succ_enum_mismatch() + EXCLUSIVE_TRYLOCK_FUNCTION(Foo, mu2); + +// legal capability attribute arguments int etf_function_1() EXCLUSIVE_TRYLOCK_FUNCTION(1, muWrapper.mu); int etf_function_2() EXCLUSIVE_TRYLOCK_FUNCTION(1, muDoubleWrapper.muWrapper->mu); int etf_function_3() EXCLUSIVE_TRYLOCK_FUNCTION(1, muWrapper.getMu()); @@ -768,14 +844,13 @@ int etf_functetfn_8() EXCLUSIVE_TRYLOCK_FUNCTION(1, muPointer); int etf_function_9() EXCLUSIVE_TRYLOCK_FUNCTION(true); // \ // expected-warning {{'exclusive_trylock_function' attribute without capability arguments can only be applied to non-static methods of a class}} - // illegal attribute arguments int etf_function_bad_1() EXCLUSIVE_TRYLOCK_FUNCTION(mu1); // \ - // expected-error {{'exclusive_trylock_function' attribute requires parameter 1 to be int or bool}} + // expected-error {{'exclusive_trylock_function' attribute requires parameter 1 to be nullptr or a bool, int, or enum literal}} int etf_function_bad_2() EXCLUSIVE_TRYLOCK_FUNCTION("mu"); // \ - // expected-error {{'exclusive_trylock_function' attribute requires parameter 1 to be int or bool}} + // expected-error {{'exclusive_trylock_function' attribute requires parameter 1 to be nullptr or a bool, int, or enum literal}} int etf_function_bad_3() EXCLUSIVE_TRYLOCK_FUNCTION(muDoublePointer); // \ - // expected-error {{'exclusive_trylock_function' attribute requires parameter 1 to be int or bool}} + // expected-error {{'exclusive_trylock_function' attribute requires parameter 1 to be nullptr or a bool, int, or enum literal}} int etf_function_bad_4() EXCLUSIVE_TRYLOCK_FUNCTION(1, "mu"); // \ // expected-warning {{ignoring 'exclusive_trylock_function' attribute because its argument is invalid}} @@ -799,9 +874,9 @@ int etf_function_bad_6() EXCLUSIVE_TRYLOCK_FUNCTION(1, umu); // \ void stf_function() __attribute__((shared_trylock_function)); // \ // expected-error {{'shared_trylock_function' attribute takes at least 1 argument}} -void stf_function_args() SHARED_TRYLOCK_FUNCTION(1, mu2); +bool stf_function_args() SHARED_TRYLOCK_FUNCTION(1, mu2); -void stf_function_arg() SHARED_TRYLOCK_FUNCTION(1); // \ +bool stf_function_arg() SHARED_TRYLOCK_FUNCTION(1); // \ // expected-warning {{'shared_trylock_function' attribute without capability arguments can only be applied to non-static methods of a class}} int stf_testfn(int y) SHARED_TRYLOCK_FUNCTION(1); // \ @@ -824,7 +899,7 @@ class StfFoo { private: int test_field SHARED_TRYLOCK_FUNCTION(1); // \ // expected-warning {{'shared_trylock_function' attribute only applies to functions}} - void test_method() SHARED_TRYLOCK_FUNCTION(1); // \ + bool test_method() SHARED_TRYLOCK_FUNCTION(1); // \ // expected-warning {{'shared_trylock_function' attribute without capability arguments refers to 'this', but 'StfFoo' isn't annotated with 'capability' or 'scoped_lockable' attribute}} }; @@ -849,11 +924,11 @@ int stf_function_9() SHARED_TRYLOCK_FUNCTION(true); // \ // illegal attribute arguments int stf_function_bad_1() SHARED_TRYLOCK_FUNCTION(mu1); // \ - // expected-error {{'shared_trylock_function' attribute requires parameter 1 to be int or bool}} + // expected-error {{'shared_trylock_function' attribute requires parameter 1 to be nullptr or a bool, int, or enum literal}} int stf_function_bad_2() SHARED_TRYLOCK_FUNCTION("mu"); // \ - // expected-error {{'shared_trylock_function' attribute requires parameter 1 to be int or bool}} + // expected-error {{'shared_trylock_function' attribute requires parameter 1 to be nullptr or a bool, int, or enum literal}} int stf_function_bad_3() SHARED_TRYLOCK_FUNCTION(muDoublePointer); // \ - // expected-error {{'shared_trylock_function' attribute requires parameter 1 to be int or bool}} + // expected-error {{'shared_trylock_function' attribute requires parameter 1 to be nullptr or a bool, int, or enum literal}} int stf_function_bad_4() SHARED_TRYLOCK_FUNCTION(1, "mu"); // \ // expected-warning {{ignoring 'shared_trylock_function' attribute because its argument is invalid}} diff --git a/clang/test/SemaHLSL/Semantics/invalid_entry_parameter.hlsl b/clang/test/SemaHLSL/Semantics/invalid_entry_parameter.hlsl index bf8027d029882d..bc3cf8bc51daf4 100644 --- a/clang/test/SemaHLSL/Semantics/invalid_entry_parameter.hlsl +++ b/clang/test/SemaHLSL/Semantics/invalid_entry_parameter.hlsl @@ -23,8 +23,7 @@ void foo() { } struct ST2 { -// expected-error@+1 {{use of undeclared identifier 'SV_DispatchThreadID'}} +// expected-warning@+1 {{'SV_DispatchThreadID' attribute only applies to parameters and non-static data members}} static uint X : SV_DispatchThreadID; -// expected-error@+1 {{use of undeclared identifier 'SV_DispatchThreadID'}} uint s : SV_DispatchThreadID; }; diff --git a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl index 95774472aaea08..2f8aa098db701a 100644 --- a/clang/test/SemaHLSL/resource_binding_attr_error.hlsl +++ b/clang/test/SemaHLSL/resource_binding_attr_error.hlsl @@ -55,6 +55,6 @@ void bar(RWBuffer U : register(u3)) { struct S { // FIXME: generate better error when support semantic on struct field. // See https://github.com/llvm/llvm-project/issues/57889. - // expected-error@+1 {{expected expression}} + // expected-warning@+1 {{'register' attribute only applies to cbuffer/tbuffer and external global variables}} RWBuffer U : register(u3); }; diff --git a/clang/test/SemaOpenCL/builtins-amdgcn-raw-buffer-store-error.cl b/clang/test/SemaOpenCL/builtins-amdgcn-raw-buffer-store-error.cl new file mode 100644 index 00000000000000..356c031640483f --- /dev/null +++ b/clang/test/SemaOpenCL/builtins-amdgcn-raw-buffer-store-error.cl @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -triple amdgcn-unknown-unknown -target-cpu verde -S -verify -o - %s +// REQUIRES: amdgpu-registered-target + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + +typedef char i8; +typedef short i16; +typedef int i32; +typedef int i64 __attribute__((ext_vector_type(2))); +typedef int i96 __attribute__((ext_vector_type(3))); +typedef int i128 __attribute__((ext_vector_type(4))); + +void test_amdgcn_raw_ptr_buffer_store_b8(i8 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset, int aux) { + __builtin_amdgcn_raw_buffer_store_b8(vdata, rsrc, /*offset=*/0, /*soffset=*/0, aux); //expected-error{{argument to '__builtin_amdgcn_raw_buffer_store_b8' must be a constant integer}} +} + +void test_amdgcn_raw_ptr_buffer_store_b16(i16 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset, int aux) { + __builtin_amdgcn_raw_buffer_store_b16(vdata, rsrc, /*offset=*/0, /*soffset=*/0, aux); //expected-error{{argument to '__builtin_amdgcn_raw_buffer_store_b16' must be a constant integer}} +} + +void test_amdgcn_raw_ptr_buffer_store_b32(i32 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset, int aux) { + __builtin_amdgcn_raw_buffer_store_b32(vdata, rsrc, /*offset=*/0, /*soffset=*/0, aux); //expected-error{{argument to '__builtin_amdgcn_raw_buffer_store_b32' must be a constant integer}} +} + +void test_amdgcn_raw_ptr_buffer_store_b64(i64 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset, int aux) { + __builtin_amdgcn_raw_buffer_store_b64(vdata, rsrc, /*offset=*/0, /*soffset=*/0, aux); //expected-error{{argument to '__builtin_amdgcn_raw_buffer_store_b64' must be a constant integer}} +} + +void test_amdgcn_raw_ptr_buffer_store_b96(i96 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset, int aux) { + __builtin_amdgcn_raw_buffer_store_b96(vdata, rsrc, /*offset=*/0, /*soffset=*/0, aux); //expected-error{{argument to '__builtin_amdgcn_raw_buffer_store_b96' must be a constant integer}} +} + +void test_amdgcn_raw_ptr_buffer_store_b128(i128 vdata, __amdgpu_buffer_rsrc_t rsrc, int offset, int soffset, int aux) { + __builtin_amdgcn_raw_buffer_store_b128(vdata, rsrc, /*offset=*/0, /*soffset=*/0, aux); //expected-error{{argument to '__builtin_amdgcn_raw_buffer_store_b128' must be a constant integer}} +} diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp index cdfe8cfbd93799..9027076119cf94 100644 --- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp +++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp @@ -224,9 +224,8 @@ Error executeCommands(StringRef ExecutablePath, ArrayRef Args) { if (!DryRun) if (sys::ExecuteAndWait(ExecutablePath, Args)) - return createStringError(inconvertibleErrorCode(), - "'" + sys::path::filename(ExecutablePath) + "'" + - " failed"); + return createStringError( + "'%s' failed", sys::path::filename(ExecutablePath).str().c_str()); return Error::success(); } @@ -259,7 +258,6 @@ Error relocateOffloadSection(const ArgList &Args, StringRef Output) { Args.getLastArgValue(OPT_host_triple_EQ, sys::getDefaultTargetTriple())); if (Triple.isOSWindows()) return createStringError( - inconvertibleErrorCode(), "Relocatable linking is not supported on COFF targets"); Expected ObjcopyPath = @@ -272,8 +270,7 @@ Error relocateOffloadSection(const ArgList &Args, StringRef Output) { auto BufferOrErr = DryRun ? MemoryBuffer::getMemBuffer("") : MemoryBuffer::getFileOrSTDIN(Output); if (!BufferOrErr) - return createStringError(inconvertibleErrorCode(), "Failed to open %s", - Output.str().c_str()); + return createStringError("Failed to open %s", Output.str().c_str()); std::string Suffix = "_" + getHash((*BufferOrErr)->getBuffer()); SmallVector ObjcopyArgs = { @@ -492,8 +489,7 @@ Expected clang(ArrayRef InputFiles, const ArgList &Args) { file_magic Magic; if (auto EC = identify_magic(Arg->getValue(), Magic)) - return createStringError(inconvertibleErrorCode(), - "Failed to open %s", Arg->getValue()); + return createStringError("Failed to open %s", Arg->getValue()); if (Magic != file_magic::archive && Magic != file_magic::elf_shared_object) continue; @@ -568,9 +564,8 @@ Expected linkDevice(ArrayRef InputFiles, case Triple::systemz: return generic::clang(InputFiles, Args); default: - return createStringError(inconvertibleErrorCode(), - Triple.getArchName() + - " linking is not supported"); + return createStringError(Triple.getArchName() + + " linking is not supported"); } } @@ -881,15 +876,13 @@ Error linkBitcodeFiles(SmallVectorImpl &InputFiles, return Err; if (LTOError) - return createStringError(inconvertibleErrorCode(), - "Errors encountered inside the LTO pipeline."); + return createStringError("Errors encountered inside the LTO pipeline."); // If we are embedding bitcode we only need the intermediate output. bool SingleOutput = Files.size() == 1; if (Args.hasArg(OPT_embed_bitcode)) { if (BitcodeOutput.size() != 1 || !SingleOutput) - return createStringError(inconvertibleErrorCode(), - "Cannot embed bitcode with multiple files."); + return createStringError("Cannot embed bitcode with multiple files."); OutputFiles.push_back(Args.MakeArgString(BitcodeOutput.front())); return Error::success(); } @@ -936,7 +929,7 @@ Expected compileModule(Module &M, OffloadKind Kind) { std::string Msg; const Target *T = TargetRegistry::lookupTarget(M.getTargetTriple(), Msg); if (!T) - return createStringError(inconvertibleErrorCode(), Msg); + return createStringError(Msg); auto Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple(M.getTargetTriple())); @@ -966,8 +959,7 @@ Expected compileModule(Module &M, OffloadKind Kind) { CodeGenPasses.add(new TargetLibraryInfoWrapperPass(TLII)); if (TM->addPassesToEmitFile(CodeGenPasses, *OS, nullptr, CodeGenFileType::ObjectFile)) - return createStringError(inconvertibleErrorCode(), - "Failed to execute host backend"); + return createStringError("Failed to execute host backend"); CodeGenPasses.run(M); return *TempFileOrErr; @@ -1012,9 +1004,8 @@ wrapDeviceImages(ArrayRef> Buffers, return std::move(Err); break; default: - return createStringError(inconvertibleErrorCode(), - getOffloadKindName(Kind) + - " wrapping is not supported"); + return createStringError(getOffloadKindName(Kind) + + " wrapping is not supported"); } if (Args.hasArg(OPT_print_wrapped_module)) @@ -1109,9 +1100,8 @@ bundleLinkedOutput(ArrayRef Images, const ArgList &Args, case OFK_HIP: return bundleHIP(Images, Args); default: - return createStringError(inconvertibleErrorCode(), - getOffloadKindName(Kind) + - " bundling is not supported"); + return createStringError(getOffloadKindName(Kind) + + " bundling is not supported"); } } @@ -1209,7 +1199,7 @@ Expected> linkAndWrapDeviceFiles( StringSaver Saver(Alloc); auto BaseArgs = Tbl.parseArgs(Argc, Argv, OPT_INVALID, Saver, [](StringRef Err) { - reportError(createStringError(inconvertibleErrorCode(), Err)); + reportError(createStringError(Err)); }); auto LinkerArgs = getLinkerArgs(Input, BaseArgs); @@ -1510,9 +1500,8 @@ getDeviceInput(const ArgList &Args) { : std::string(Arg->getValue()); if (!Filename && Arg->getOption().matches(OPT_library)) - reportError(createStringError(inconvertibleErrorCode(), - "unable to find library -l%s", - Arg->getValue())); + reportError( + createStringError("unable to find library -l%s", Arg->getValue())); if (!Filename || !sys::fs::exists(*Filename) || sys::fs::is_directory(*Filename)) @@ -1646,7 +1635,7 @@ int main(int Argc, char **Argv) { BumpPtrAllocator Alloc; StringSaver Saver(Alloc); auto Args = Tbl.parseArgs(Argc, Argv, OPT_INVALID, Saver, [&](StringRef Err) { - reportError(createStringError(inconvertibleErrorCode(), Err)); + reportError(createStringError(Err)); }); if (Args.hasArg(OPT_help) || Args.hasArg(OPT_help_hidden)) { @@ -1691,9 +1680,9 @@ int main(int Argc, char **Argv) { if (auto *Arg = Args.getLastArg(OPT_wrapper_jobs)) { unsigned Threads = 0; if (!llvm::to_integer(Arg->getValue(), Threads) || Threads == 0) - reportError(createStringError( - inconvertibleErrorCode(), "%s: expected a positive integer, got '%s'", - Arg->getSpelling().data(), Arg->getValue())); + reportError(createStringError("%s: expected a positive integer, got '%s'", + Arg->getSpelling().data(), + Arg->getValue())); parallel::strategy = hardware_concurrency(Threads); } diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp index 2aebc6d3c01782..3c0599c2e51491 100644 --- a/clang/tools/driver/cc1_main.cpp +++ b/clang/tools/driver/cc1_main.cpp @@ -26,6 +26,7 @@ #include "clang/Frontend/Utils.h" #include "clang/FrontendTool/Utils.h" #include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Config/llvm-config.h" #include "llvm/LinkAllPasses.h" #include "llvm/MC/MCSubtargetInfo.h" @@ -148,7 +149,7 @@ static int PrintSupportedExtensions(std::string TargetStr) { if (MachineTriple.isRISCV()) llvm::riscvExtensionsHelp(DescMap); else if (MachineTriple.isAArch64()) - llvm::AArch64::PrintSupportedExtensions(DescMap); + llvm::AArch64::PrintSupportedExtensions(); else if (MachineTriple.isARM()) llvm::ARM::PrintSupportedExtensions(DescMap); else { @@ -161,6 +162,45 @@ static int PrintSupportedExtensions(std::string TargetStr) { return 0; } +static int PrintEnabledExtensions(const TargetOptions& TargetOpts) { + std::string Error; + const llvm::Target *TheTarget = + llvm::TargetRegistry::lookupTarget(TargetOpts.Triple, Error); + if (!TheTarget) { + llvm::errs() << Error; + return 1; + } + + // Create a target machine using the input features, the triple information + // and a dummy instance of llvm::TargetOptions. Note that this is _not_ the + // same as the `clang::TargetOptions` instance we have access to here. + llvm::TargetOptions BackendOptions; + std::string FeaturesStr = llvm::join(TargetOpts.FeaturesAsWritten, ","); + std::unique_ptr TheTargetMachine( + TheTarget->createTargetMachine(TargetOpts.Triple, TargetOpts.CPU, FeaturesStr, BackendOptions, std::nullopt)); + const llvm::Triple &MachineTriple = TheTargetMachine->getTargetTriple(); + const llvm::MCSubtargetInfo *MCInfo = TheTargetMachine->getMCSubtargetInfo(); + + // Extract the feature names that are enabled for the given target. + // We do that by capturing the key from the set of SubtargetFeatureKV entries + // provided by MCSubtargetInfo, which match the '-target-feature' values. + const std::vector Features = + MCInfo->getEnabledProcessorFeatures(); + std::set EnabledFeatureNames; + for (const llvm::SubtargetFeatureKV &feature : Features) + EnabledFeatureNames.insert(feature.Key); + + if (!MachineTriple.isAArch64()) { + // The option was already checked in Driver::HandleImmediateArgs, + // so we do not expect to get here if we are not a supported architecture. + assert(0 && "Unhandled triple for --print-enabled-extensions option."); + return 1; + } + llvm::AArch64::printEnabledExtensions(EnabledFeatureNames); + + return 0; +} + int cc1_main(ArrayRef Argv, const char *Argv0, void *MainAddr) { ensureSufficientStack(); @@ -204,6 +244,10 @@ int cc1_main(ArrayRef Argv, const char *Argv0, void *MainAddr) { if (Clang->getFrontendOpts().PrintSupportedExtensions) return PrintSupportedExtensions(Clang->getTargetOpts().Triple); + // --print-enabled-extensions takes priority over the actual compilation. + if (Clang->getFrontendOpts().PrintEnabledExtensions) + return PrintEnabledExtensions(Clang->getTargetOpts()); + // Infer the builtin include path if unspecified. if (Clang->getHeaderSearchOpts().UseBuiltinIncludes && Clang->getHeaderSearchOpts().ResourceDir.empty()) diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp index 92f9bae6cb064b..4c33546de6f923 100644 --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -7851,7 +7851,7 @@ TEST_P(ImportAttributes, ImportAcquireCapability) { TEST_P(ImportAttributes, ImportTryAcquireCapability) { TryAcquireCapabilityAttr *FromAttr, *ToAttr; importAttr( - "void test(int A1, int A2) __attribute__((try_acquire_capability(1, A1, " + "bool test(int A1, int A2) __attribute__((try_acquire_capability(1, A1, " "A2)));", FromAttr, ToAttr); checkImported(FromAttr->getSuccessValue(), ToAttr->getSuccessValue()); @@ -7948,7 +7948,7 @@ TEST_P(ImportAttributes, ImportAssertSharedLock) { TEST_P(ImportAttributes, ImportExclusiveTrylockFunction) { ExclusiveTrylockFunctionAttr *FromAttr, *ToAttr; importAttr( - "void test(int A1, int A2) __attribute__((exclusive_trylock_function(1, " + "bool test(int A1, int A2) __attribute__((exclusive_trylock_function(1, " "A1, A2)));", FromAttr, ToAttr); checkImported(FromAttr->getSuccessValue(), ToAttr->getSuccessValue()); @@ -7958,7 +7958,7 @@ TEST_P(ImportAttributes, ImportExclusiveTrylockFunction) { TEST_P(ImportAttributes, ImportSharedTrylockFunction) { SharedTrylockFunctionAttr *FromAttr, *ToAttr; importAttr( - "void test(int A1, int A2) __attribute__((shared_trylock_function(1, A1, " + "bool test(int A1, int A2) __attribute__((shared_trylock_function(1, A1, " "A2)));", FromAttr, ToAttr); checkImported(FromAttr->getSuccessValue(), ToAttr->getSuccessValue()); diff --git a/clang/unittests/AST/MatchVerifier.h b/clang/unittests/AST/MatchVerifier.h index da1e351da4a096..60bb4a8716ae8c 100644 --- a/clang/unittests/AST/MatchVerifier.h +++ b/clang/unittests/AST/MatchVerifier.h @@ -209,7 +209,7 @@ class LocationVerifier : public MatchVerifier { << ">, found <"; Loc.print(Msg, *Result.SourceManager); Msg << '>'; - this->setFailure(Msg.str()); + this->setFailure(MsgStr); } } @@ -256,7 +256,7 @@ class RangeVerifier : public MatchVerifier { Msg << '-'; End.print(Msg, *Result.SourceManager); Msg << '>'; - this->setFailure(Msg.str()); + this->setFailure(MsgStr); } } @@ -282,12 +282,12 @@ class DumpVerifier : public MatchVerifier { llvm::raw_string_ostream Dump(DumpStr); Node.dump(Dump, *Result.Context); - if (Dump.str().find(ExpectSubstring) == std::string::npos) { + if (DumpStr.find(ExpectSubstring) == std::string::npos) { std::string MsgStr; llvm::raw_string_ostream Msg(MsgStr); Msg << "Expected dump substring <" << ExpectSubstring << ">, found <" - << Dump.str() << '>'; - this->setFailure(Msg.str()); + << DumpStr << '>'; + this->setFailure(MsgStr); } } @@ -309,12 +309,12 @@ class PrintVerifier : public MatchVerifier { llvm::raw_string_ostream Print(PrintStr); Node.print(Print, Result.Context->getPrintingPolicy()); - if (Print.str() != ExpectString) { + if (PrintStr != ExpectString) { std::string MsgStr; llvm::raw_string_ostream Msg(MsgStr); Msg << "Expected pretty print <" << ExpectString << ">, found <" - << Print.str() << '>'; - this->setFailure(Msg.str()); + << PrintStr << '>'; + this->setFailure(MsgStr); } } diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index cfbc64c77b0cc4..e743eefa5d4585 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -3789,36 +3789,51 @@ TEST(TransferTest, AddrOfReference) { TEST(TransferTest, Preincrement) { std::string Code = R"( void target(int I) { + (void)0; // [[before]] int &IRef = ++I; - // [[p]] + // [[after]] } )"; runDataflow( Code, [](const llvm::StringMap> &Results, ASTContext &ASTCtx) { - const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); + const Environment &EnvBefore = + getEnvironmentAtAnnotation(Results, "before"); + const Environment &EnvAfter = + getEnvironmentAtAnnotation(Results, "after"); - EXPECT_EQ(&getLocForDecl(ASTCtx, Env, "IRef"), - &getLocForDecl(ASTCtx, Env, "I")); + EXPECT_EQ(&getLocForDecl(ASTCtx, EnvAfter, "IRef"), + &getLocForDecl(ASTCtx, EnvBefore, "I")); + + const ValueDecl *IDecl = findValueDecl(ASTCtx, "I"); + EXPECT_NE(EnvBefore.getValue(*IDecl), nullptr); + EXPECT_EQ(EnvAfter.getValue(*IDecl), nullptr); }); } TEST(TransferTest, Postincrement) { std::string Code = R"( void target(int I) { + (void)0; // [[before]] int OldVal = I++; - // [[p]] + // [[after]] } )"; runDataflow( Code, [](const llvm::StringMap> &Results, ASTContext &ASTCtx) { - const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); + const Environment &EnvBefore = + getEnvironmentAtAnnotation(Results, "before"); + const Environment &EnvAfter = + getEnvironmentAtAnnotation(Results, "after"); + + EXPECT_EQ(&getValueForDecl(ASTCtx, EnvBefore, "I"), + &getValueForDecl(ASTCtx, EnvAfter, "OldVal")); - EXPECT_EQ(&getValueForDecl(ASTCtx, Env, "OldVal"), - &getValueForDecl(ASTCtx, Env, "I")); + const ValueDecl *IDecl = findValueDecl(ASTCtx, "I"); + EXPECT_EQ(EnvAfter.getValue(*IDecl), nullptr); }); } diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp index aded3ed2a6596e..2466677a3740d3 100644 --- a/clang/unittests/Format/ConfigParseTest.cpp +++ b/clang/unittests/Format/ConfigParseTest.cpp @@ -178,8 +178,9 @@ TEST(ConfigParseTest, ParsesConfigurationBools) { CHECK_PARSE_BOOL(IndentWrappedFunctionNames); CHECK_PARSE_BOOL(InsertBraces); CHECK_PARSE_BOOL(InsertNewlineAtEOF); - CHECK_PARSE_BOOL(KeepEmptyLinesAtEOF); - CHECK_PARSE_BOOL(KeepEmptyLinesAtTheStartOfBlocks); + CHECK_PARSE_BOOL_FIELD(KeepEmptyLines.AtEndOfFile, "KeepEmptyLinesAtEOF"); + CHECK_PARSE_BOOL_FIELD(KeepEmptyLines.AtStartOfBlock, + "KeepEmptyLinesAtTheStartOfBlocks"); CHECK_PARSE_BOOL(ObjCSpaceAfterProperty); CHECK_PARSE_BOOL(ObjCSpaceBeforeProtocolList); CHECK_PARSE_BOOL(Cpp11BracedListStyle); @@ -226,6 +227,9 @@ TEST(ConfigParseTest, ParsesConfigurationBools) { CHECK_PARSE_NESTED_BOOL(BraceWrapping, SplitEmptyFunction); CHECK_PARSE_NESTED_BOOL(BraceWrapping, SplitEmptyRecord); CHECK_PARSE_NESTED_BOOL(BraceWrapping, SplitEmptyNamespace); + CHECK_PARSE_NESTED_BOOL(KeepEmptyLines, AtEndOfFile); + CHECK_PARSE_NESTED_BOOL(KeepEmptyLines, AtStartOfBlock); + CHECK_PARSE_NESTED_BOOL(KeepEmptyLines, AtStartOfFile); CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, AfterControlStatements); CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, AfterForeachMacros); CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index db1decb20d626b..5276e79d759812 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -45,6 +45,10 @@ TEST_F(FormatTest, FormatsGlobalStatementsAt0) { verifyFormat("\nint i;", " \n\t \v \f int i;"); verifyFormat("int i;\nint j;", " int i; int j;"); verifyFormat("int i;\nint j;", " int i;\n int j;"); + + auto Style = getLLVMStyle(); + Style.KeepEmptyLines.AtStartOfFile = false; + verifyFormat("int i;", " \n\t \v \f int i;", Style); } TEST_F(FormatTest, FormatsUnwrappedLinesAtFirstFormat) { @@ -163,7 +167,7 @@ TEST_F(FormatTest, RemovesEmptyLines) { auto CustomStyle = getLLVMStyle(); CustomStyle.BreakBeforeBraces = FormatStyle::BS_Custom; CustomStyle.BraceWrapping.AfterNamespace = true; - CustomStyle.KeepEmptyLinesAtTheStartOfBlocks = false; + CustomStyle.KeepEmptyLines.AtStartOfBlock = false; verifyFormat("namespace N\n" "{\n" "\n" @@ -389,7 +393,7 @@ TEST_F(FormatTest, RemovesEmptyLines) { Style.BreakBeforeBraces = FormatStyle::BS_Custom; Style.BraceWrapping.AfterClass = true; Style.BraceWrapping.AfterFunction = true; - Style.KeepEmptyLinesAtTheStartOfBlocks = false; + Style.KeepEmptyLines.AtStartOfBlock = false; verifyFormat("class Foo\n" "{\n" @@ -21956,6 +21960,11 @@ TEST_F(FormatTest, HandlesUTF8BOM) { verifyFormat("\xef\xbb\xbf"); verifyFormat("\xef\xbb\xbf#include "); verifyFormat("\xef\xbb\xbf\n#include "); + + auto Style = getLLVMStyle(); + Style.KeepEmptyLines.AtStartOfFile = false; + verifyFormat("\xef\xbb\xbf#include ", + "\xef\xbb\xbf\n#include ", Style); } // FIXME: Encode Cyrillic and CJK characters below to appease MS compilers. @@ -27230,7 +27239,7 @@ TEST_F(FormatTest, InsertNewlineAtEOF) { TEST_F(FormatTest, KeepEmptyLinesAtEOF) { FormatStyle Style = getLLVMStyle(); - Style.KeepEmptyLinesAtEOF = true; + Style.KeepEmptyLines.AtEndOfFile = true; const StringRef Code{"int i;\n\n"}; verifyNoChange(Code, Style); diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp index d3b310fe59527a..5d83d8a0c44295 100644 --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -567,6 +567,24 @@ TEST_F(TokenAnnotatorTest, UnderstandsGreaterAfterTemplateCloser) { EXPECT_TOKEN(Tokens[8], tok::greater, TT_BinaryOperator); } +TEST_F(TokenAnnotatorTest, UnderstandsTernaryInTemplate) { + // IsExpression = false + auto Tokens = annotate("foo();"); + ASSERT_EQ(Tokens.size(), 12u) << Tokens; + EXPECT_TOKEN(Tokens[1], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[3], tok::question, TT_ConditionalExpr); + EXPECT_TOKEN(Tokens[5], tok::colon, TT_ConditionalExpr); + EXPECT_TOKEN(Tokens[7], tok::greater, TT_TemplateCloser); + + // IsExpression = true + Tokens = annotate("return foo();"); + ASSERT_EQ(Tokens.size(), 13u) << Tokens; + EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[4], tok::question, TT_ConditionalExpr); + EXPECT_TOKEN(Tokens[6], tok::colon, TT_ConditionalExpr); + EXPECT_TOKEN(Tokens[8], tok::greater, TT_TemplateCloser); +} + TEST_F(TokenAnnotatorTest, UnderstandsNonTemplateAngleBrackets) { auto Tokens = annotate("return a < b && c > d;"); ASSERT_EQ(Tokens.size(), 10u) << Tokens; diff --git a/clang/unittests/Interpreter/InterpreterTest.cpp b/clang/unittests/Interpreter/InterpreterTest.cpp index bbd854149d5f59..29c5ead60b81e0 100644 --- a/clang/unittests/Interpreter/InterpreterTest.cpp +++ b/clang/unittests/Interpreter/InterpreterTest.cpp @@ -101,7 +101,7 @@ TEST_F(InterpreterTest, Errors) { auto Interp = createInterpreter(ExtraArgs, DiagPrinter.get()); auto Err = Interp->Parse("intentional_error v1 = 42; ").takeError(); using ::testing::HasSubstr; - EXPECT_THAT(DiagnosticsOS.str(), + EXPECT_THAT(DiagnosticOutput, HasSubstr("error: unknown type name 'intentional_error'")); EXPECT_EQ("Parsing failed.", llvm::toString(std::move(Err))); @@ -186,7 +186,7 @@ static std::string MangleName(NamedDecl *ND) { std::string mangledName; llvm::raw_string_ostream RawStr(mangledName); MangleC->mangleName(ND, RawStr); - return RawStr.str(); + return mangledName; } TEST_F(InterpreterTest, FindMangledNameSymbol) { diff --git a/clang/unittests/Tooling/RangeSelectorTest.cpp b/clang/unittests/Tooling/RangeSelectorTest.cpp index 03ab66235e43c6..1bccf899f3f196 100644 --- a/clang/unittests/Tooling/RangeSelectorTest.cpp +++ b/clang/unittests/Tooling/RangeSelectorTest.cpp @@ -651,6 +651,48 @@ TEST(RangeSelectorTest, CallArgsErrors) { Failed(withTypeErrorMessage("stmt"))); } +TEST(RangeSelectorTest, ConstructExprArgs) { + const StringRef Code = R"cc( + struct C { + C(int, int); + }; + C f() { + return C(1, 2); + } + )cc"; + const char *ID = "id"; + TestMatch Match = matchCode(Code, cxxTemporaryObjectExpr().bind(ID)); + EXPECT_THAT_EXPECTED(select(constructExprArgs(ID), Match), HasValue("1, 2")); +} + +TEST(RangeSelectorTest, ConstructExprBracedArgs) { + const StringRef Code = R"cc( + struct C { + C(int, int); + }; + C f() { + return {1, 2}; + } + )cc"; + const char *ID = "id"; + TestMatch Match = matchCode(Code, cxxConstructExpr().bind(ID)); + EXPECT_THAT_EXPECTED(select(constructExprArgs(ID), Match), HasValue("1, 2")); +} + +TEST(RangeSelectorTest, ConstructExprNoArgs) { + const StringRef Code = R"cc( + struct C { + C(); + }; + C f() { + return C(); + } + )cc"; + const char *ID = "id"; + TestMatch Match = matchCode(Code, cxxTemporaryObjectExpr().bind(ID)); + EXPECT_THAT_EXPECTED(select(constructExprArgs(ID), Match), HasValue("")); +} + TEST(RangeSelectorTest, StatementsOp) { StringRef Code = R"cc( void g(); diff --git a/clang/unittests/Tooling/RecursiveASTVisitorTests/DeductionGuide.cpp b/clang/unittests/Tooling/RecursiveASTVisitorTests/DeductionGuide.cpp index 274f275ea66a9d..cd4bf0eb7bd5a7 100644 --- a/clang/unittests/Tooling/RecursiveASTVisitorTests/DeductionGuide.cpp +++ b/clang/unittests/Tooling/RecursiveASTVisitorTests/DeductionGuide.cpp @@ -22,7 +22,7 @@ class DeductionGuideVisitor std::string Storage; llvm::raw_string_ostream Stream(Storage); D->print(Stream); - Match(Stream.str(), D->getLocation()); + Match(Storage, D->getLocation()); return true; } diff --git a/clang/unittests/Tooling/ReplacementsYamlTest.cpp b/clang/unittests/Tooling/ReplacementsYamlTest.cpp index 3328d9bad55c71..9558d7270159f7 100644 --- a/clang/unittests/Tooling/ReplacementsYamlTest.cpp +++ b/clang/unittests/Tooling/ReplacementsYamlTest.cpp @@ -43,7 +43,7 @@ TEST(ReplacementsYamlTest, serializesReplacements) { " Length: 2\n" " ReplacementText: 'replacement #2'\n" "...\n", - YamlContentStream.str().c_str()); + YamlContent.c_str()); } TEST(ReplacementsYamlTest, serializesNewLines) { @@ -67,7 +67,7 @@ TEST(ReplacementsYamlTest, serializesNewLines) { " Length: 0\n" " ReplacementText: \"#include \\n\"\n" "...\n", - YamlContentStream.str().c_str()); + YamlContent.c_str()); } TEST(ReplacementsYamlTest, deserializesReplacements) { diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index 307334a65b1fe2..7bf6091e63d185 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -2578,6 +2578,32 @@ static void emitClangAttrIdentifierArgList(RecordKeeper &Records, raw_ostream &O OS << "#endif // CLANG_ATTR_IDENTIFIER_ARG_LIST\n\n"; } +// Emits the indexed-argument-is-identifier property for attributes. +static void emitClangAttrStrictIdentifierArgAtIndexList(RecordKeeper &Records, + raw_ostream &OS) { + OS << "#if defined(CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST)\n"; + std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); + + for (const auto *Attr : Attrs) { + if (!Attr->getValueAsBit("StrictEnumParameters")) + continue; + // Determine whether the first argument is an identifier. + std::vector Args = Attr->getValueAsListOfDefs("Args"); + uint64_t enumAtIndex = 0; + for (size_t i = 0; i < Args.size(); i++) { + enumAtIndex |= ((uint64_t)isIdentifierArgument(Args[0])) << i; + } + if (!enumAtIndex) + continue; + + // All these spellings take an identifier argument. + forEachUniqueSpelling(*Attr, [&](const FlattenedSpelling &S) { + OS << ".Case(\"" << S.name() << "\", " << enumAtIndex << "ull)\n"; + }); + } + OS << "#endif // CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST\n\n"; +} + static bool keywordThisIsaIdentifierInArgument(const Record *Arg) { return !Arg->getSuperClasses().empty() && llvm::StringSwitch( @@ -4959,6 +4985,7 @@ void EmitClangAttrParserStringSwitches(RecordKeeper &Records, raw_ostream &OS) { emitClangAttrTypeArgList(Records, OS); emitClangAttrLateParsedList(Records, OS); emitClangAttrLateParsedExperimentalList(Records, OS); + emitClangAttrStrictIdentifierArgAtIndexList(Records, OS); } void EmitClangAttrSubjectMatchRulesParserStringSwitches(RecordKeeper &Records, diff --git a/clang/utils/TableGen/NeonEmitter.cpp b/clang/utils/TableGen/NeonEmitter.cpp index 56f1fdf9ef574f..626031d38cf003 100644 --- a/clang/utils/TableGen/NeonEmitter.cpp +++ b/clang/utils/TableGen/NeonEmitter.cpp @@ -2370,10 +2370,6 @@ void NeonEmitter::run(raw_ostream &OS) { "Please use -mfloat-abi=softfp or -mfloat-abi=hard\"\n"; OS << "#else\n\n"; - OS << "#if !defined(__ARM_NEON)\n"; - OS << "#error \"NEON support not enabled\"\n"; - OS << "#else\n\n"; - OS << "#include \n\n"; OS << "#include \n"; @@ -2450,7 +2446,6 @@ void NeonEmitter::run(raw_ostream &OS) { OS << "#undef __ai\n\n"; OS << "#endif /* if !defined(__ARM_NEON) */\n"; OS << "#endif /* ifndef __ARM_FP */\n"; - OS << "#endif /* __ARM_NEON_H */\n"; } /// run - Read the records in arm_fp16.td and output arm_fp16.h. arm_fp16.h diff --git a/clang/utils/TableGen/SveEmitter.cpp b/clang/utils/TableGen/SveEmitter.cpp index c41c812ab9707a..caedd5978a87c0 100644 --- a/clang/utils/TableGen/SveEmitter.cpp +++ b/clang/utils/TableGen/SveEmitter.cpp @@ -165,7 +165,7 @@ class Intrinsic { ClassKind Class; /// The architectural #ifdef guard. - std::string Guard; + std::string SVEGuard, SMEGuard; // The merge suffix such as _m, _x or _z. std::string MergeSuffix; @@ -184,7 +184,8 @@ class Intrinsic { Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy, StringRef MergeSuffix, uint64_t MemoryElementTy, StringRef LLVMName, uint64_t Flags, ArrayRef ImmChecks, TypeSpec BT, - ClassKind Class, SVEEmitter &Emitter, StringRef Guard); + ClassKind Class, SVEEmitter &Emitter, StringRef SVEGuard, + StringRef SMEGuard); ~Intrinsic()=default; @@ -194,7 +195,27 @@ class Intrinsic { TypeSpec getBaseTypeSpec() const { return BaseTypeSpec; } SVEType getBaseType() const { return BaseType; } - StringRef getGuard() const { return Guard; } + StringRef getSVEGuard() const { return SVEGuard; } + StringRef getSMEGuard() const { return SMEGuard; } + void printGuard(raw_ostream &OS) const { + if (!SVEGuard.empty() && SMEGuard.empty()) + OS << SVEGuard; + else if (SVEGuard.empty() && !SMEGuard.empty()) + OS << SMEGuard; + else { + if (SVEGuard.find(",") != std::string::npos || + SVEGuard.find("|") != std::string::npos) + OS << "(" << SVEGuard << ")"; + else + OS << SVEGuard; + OS << "|"; + if (SMEGuard.find(",") != std::string::npos || + SMEGuard.find("|") != std::string::npos) + OS << "(" << SMEGuard << ")"; + else + OS << SMEGuard; + } + } ClassKind getClassKind() const { return Class; } SVEType getReturnType() const { return Types[0]; } @@ -943,11 +964,12 @@ Intrinsic::Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy, StringRef MergeSuffix, uint64_t MemoryElementTy, StringRef LLVMName, uint64_t Flags, ArrayRef Checks, TypeSpec BT, ClassKind Class, - SVEEmitter &Emitter, StringRef Guard) + SVEEmitter &Emitter, StringRef SVEGuard, + StringRef SMEGuard) : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()), - BaseTypeSpec(BT), Class(Class), Guard(Guard.str()), - MergeSuffix(MergeSuffix.str()), BaseType(BT, 'd'), Flags(Flags), - ImmChecks(Checks.begin(), Checks.end()) { + BaseTypeSpec(BT), Class(Class), SVEGuard(SVEGuard.str()), + SMEGuard(SMEGuard.str()), MergeSuffix(MergeSuffix.str()), + BaseType(BT, 'd'), Flags(Flags), ImmChecks(Checks.begin(), Checks.end()) { // Types[0] is the return value. for (unsigned I = 0; I < (getNumParams() + 1); ++I) { char Mod; @@ -1147,7 +1169,8 @@ void SVEEmitter::createIntrinsic( StringRef Name = R->getValueAsString("Name"); StringRef Proto = R->getValueAsString("Prototype"); StringRef Types = R->getValueAsString("Types"); - StringRef Guard = R->getValueAsString("TargetGuard"); + StringRef SVEGuard = R->getValueAsString("SVETargetGuard"); + StringRef SMEGuard = R->getValueAsString("SMETargetGuard"); StringRef LLVMName = R->getValueAsString("LLVMIntrinsic"); uint64_t Merge = R->getValueAsInt("Merge"); StringRef MergeSuffix = R->getValueAsString("MergeSuffix"); @@ -1203,13 +1226,13 @@ void SVEEmitter::createIntrinsic( Out.push_back(std::make_unique( Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, ImmChecks, - TS, ClassS, *this, Guard)); + TS, ClassS, *this, SVEGuard, SMEGuard)); // Also generate the short-form (e.g. svadd_m) for the given type-spec. if (Intrinsic::isOverloadedIntrinsic(Name)) Out.push_back(std::make_unique( Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, - ImmChecks, TS, ClassG, *this, Guard)); + ImmChecks, TS, ClassG, *this, SVEGuard, SMEGuard)); } } @@ -1229,9 +1252,9 @@ void SVEEmitter::createCoreHeaderIntrinsics(raw_ostream &OS, [](const std::unique_ptr &A, const std::unique_ptr &B) { auto ToTuple = [](const std::unique_ptr &I) { - return std::make_tuple(I->getGuard(), - (unsigned)I->getClassKind(), - I->getName()); + return std::make_tuple( + I->getSVEGuard().str() + I->getSMEGuard().str(), + (unsigned)I->getClassKind(), I->getName()); }; return ToTuple(A) < ToTuple(B); }); @@ -1434,10 +1457,12 @@ void SVEEmitter::createBuiltins(raw_ostream &OS) { for (auto &Def : Defs) { // Only create BUILTINs for non-overloaded intrinsics, as overloaded // declarations only live in the header file. - if (Def->getClassKind() != ClassG) + if (Def->getClassKind() != ClassG) { OS << "TARGET_BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \"" - << Def->getBuiltinTypeStr() << "\", \"n\", \"" << Def->getGuard() - << "\")\n"; + << Def->getBuiltinTypeStr() << "\", \"n\", \""; + Def->printGuard(OS); + OS << "\")\n"; + } } // Add reinterpret functions. @@ -1638,10 +1663,12 @@ void SVEEmitter::createSMEBuiltins(raw_ostream &OS) { for (auto &Def : Defs) { // Only create BUILTINs for non-overloaded intrinsics, as overloaded // declarations only live in the header file. - if (Def->getClassKind() != ClassG) + if (Def->getClassKind() != ClassG) { OS << "TARGET_BUILTIN(__builtin_sme_" << Def->getMangledName() << ", \"" - << Def->getBuiltinTypeStr() << "\", \"n\", \"" << Def->getGuard() - << "\")\n"; + << Def->getBuiltinTypeStr() << "\", \"n\", \""; + Def->printGuard(OS); + OS << "\")\n"; + } } OS << "#endif\n\n"; @@ -1783,9 +1810,9 @@ void SVEEmitter::createStreamingAttrs(raw_ostream &OS, ACLEKind Kind) { getEnumValueForFlag("IsStreamingCompatible"); for (auto &Def : Defs) { - if (!Def->isFlagSet(VerifyRuntimeMode) && Def->getGuard().contains("sve") && - Def->getGuard().contains("sme")) - llvm_unreachable("Missing VerifyRuntimeMode flag"); + if (!Def->isFlagSet(VerifyRuntimeMode) && !Def->getSVEGuard().empty() && + !Def->getSMEGuard().empty()) + report_fatal_error("Missing VerifyRuntimeMode flag"); if (Def->isFlagSet(IsStreamingFlag)) StreamingMap["ArmStreaming"].insert(Def->getMangledName()); diff --git a/clang/www/c_status.html b/clang/www/c_status.html index d71d4c216f7447..84cd8e836006c9 100644 --- a/clang/www/c_status.html +++ b/clang/www/c_status.html @@ -57,12 +57,12 @@

C Support in Clang

C11 -std=c11 - Probably + Partial C17 -std=c17 - Maybe? + Partial C23 @@ -425,7 +425,7 @@

C11 implementation status

Extending the lifetime of temporary objects (factored approach) N1285 - Unknown + No Requiring signed char to have no padding bits @@ -457,11 +457,6 @@

C11 implementation status

N1349 Unknown - - FLT_EVAL_METHOD issues (first change only) - N1353 - Unknown - _Bool bit-fields N1356 @@ -493,11 +488,6 @@

C11 implementation status

N1367 Unknown - - FLT_EVAL_METHOD and return - N1382 - Unknown - Floating-point to int/_Bool conversions N1391 @@ -609,11 +599,6 @@

C11 implementation status

N1532 Yes - - Synthesis re _Atomic - N1537 - Unknown - Clarification for wide evaluation N1531 @@ -652,11 +637,6 @@

C23 implementation status

N2186 Unknown - - Clarifying the restrict Keyword v2 - N2660 - Unknown - Harmonizing static_assert with C++ N2665 @@ -673,7 +653,7 @@

C23 implementation status

Clang 9 - TS 18661 Integration + TS 18661 Integration N2314 @@ -707,6 +687,10 @@

C23 implementation status

N2755 Unknown + + N2931 + Unknown + Preprocessor line numbers unspecified N2322 @@ -762,11 +746,8 @@

C23 implementation status

Clang 15 - - *_IS_IEC_60559 feature test macros - N2379 - Unknown - + Annex F.8 update for implementation extensions and rounding N2384 @@ -999,7 +980,7 @@

C23 implementation status

Clarification for max exponent macros N2843 - Unknown + Subsumed by N2882 Clarification about expression transformations @@ -1040,7 +1021,7 @@

C23 implementation status

Disambiguate the storage class of some compound literals N2819 - Unknown + No Add annotations for unreachable control flow v2 @@ -1109,11 +1090,6 @@

C23 implementation status

N2930 Clang 16 - - Type annex tgmath narrowing macros with integer args v2 - N2931 - Unknown - Revise spelling of keywords v7 N2934 @@ -1194,7 +1170,7 @@

C23 implementation status

Comma ommission and deletion (__VA_OPT__) N3033 - Unknown + Clang 12 Underspecified object definitions diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index 65dd31a0fb802c..8f21a7c9f8737d 100755 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -204,6 +204,27 @@

C++2c implementation status

P2893R3 No + + + constexpr placement new + P2747R2 + No + + + Deleting a Pointer to an Incomplete Type Should be Ill-formed + P3144R2 + No + + + Ordering of constraints involving fold expressions + P2963R3 + No + + + Structured binding declaration as a condition + P0963R3 + No + @@ -247,7 +268,7 @@

C++23 implementation status

Allow duplicate attributes - P2156R1 + P2156R1 (DR) Clang 13 @@ -267,7 +288,7 @@

C++23 implementation status

C++ identifier syntax using UAX 31 - P1949R7 + P1949R7 (DR) Clang 14 @@ -287,11 +308,11 @@

C++23 implementation status

Change scope of lambda trailing-return-type - P2036R3 + P2036R3 (DR) Clang 17 - P2579R0 + P2579R0 (DR) Multidimensional subscript operator @@ -352,12 +373,12 @@

C++23 implementation status

The Equality Operator You Are Looking For - P2468R2 + P2468R2 (DR) Clang 16 De-deprecating volatile compound operations - P2327R1 + P2327R1 (DR) Clang 15 @@ -422,12 +443,12 @@

C++23 implementation status

char8_t Compatibility and Portability Fix - P2513R3 + P2513R3 (DR) Clang 16 Relax requirements on wchar_t to match existing practices - P2460R2 + P2460R2 (DR) Yes @@ -563,7 +584,7 @@

C++20 implementation status

P2103R0 - P2493R0 + P2493R0 (DR) P2092R0 diff --git a/clang/www/get_involved.html b/clang/www/get_involved.html index 3fc688837d0bc0..99fa03abb6234d 100755 --- a/clang/www/get_involved.html +++ b/clang/www/get_involved.html @@ -126,6 +126,12 @@

Contributing Extensions to Clang

extension is not broken by ongoing maintenance in Clang. The test suite should be complete enough that another compiler vendor could conceivably validate their implementation of the feature against it. + +
  • A support story for other impacted projects within the monorepo: If the + extension can impact other parts of the project (libc++, lldb, compiler-rt, + etc), the proposal needs to document the impact for these projects to fully + support the extension and what level of support is expected. The impacted + project communities need to agree with that plan.
  • diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake index 75e4d3677703ad..7037bf89d65327 100644 --- a/compiler-rt/cmake/config-ix.cmake +++ b/compiler-rt/cmake/config-ix.cmake @@ -837,7 +837,7 @@ else() endif() if (COMPILER_RT_HAS_SANITIZER_COMMON AND SAFESTACK_SUPPORTED_ARCH AND - OS_NAME MATCHES "Linux|FreeBSD|NetBSD") + OS_NAME MATCHES "Linux|FreeBSD|NetBSD|SunOS") set(COMPILER_RT_HAS_SAFESTACK TRUE) else() set(COMPILER_RT_HAS_SAFESTACK FALSE) diff --git a/compiler-rt/include/profile/MIBEntryDef.inc b/compiler-rt/include/profile/MIBEntryDef.inc index 794163ae10386c..58c1fc4de4aba5 100644 --- a/compiler-rt/include/profile/MIBEntryDef.inc +++ b/compiler-rt/include/profile/MIBEntryDef.inc @@ -51,3 +51,5 @@ MIBEntryDef(MaxAccessDensity = 22, MaxAccessDensity, uint32_t) MIBEntryDef(TotalLifetimeAccessDensity = 23, TotalLifetimeAccessDensity, uint64_t) MIBEntryDef(MinLifetimeAccessDensity = 24, MinLifetimeAccessDensity, uint32_t) MIBEntryDef(MaxLifetimeAccessDensity = 25, MaxLifetimeAccessDensity, uint32_t) +MIBEntryDef(AccessHistogramSize = 26, AccessHistogramSize, uint32_t) +MIBEntryDef(AccessHistogram = 27, AccessHistogram, uintptr_t) \ No newline at end of file diff --git a/compiler-rt/include/profile/MemProfData.inc b/compiler-rt/include/profile/MemProfData.inc index b82a4baf6dd74e..3dc88478fb93a0 100644 --- a/compiler-rt/include/profile/MemProfData.inc +++ b/compiler-rt/include/profile/MemProfData.inc @@ -33,7 +33,11 @@ (uint64_t)'o' << 24 | (uint64_t)'f' << 16 | (uint64_t)'r' << 8 | (uint64_t)129) // The version number of the raw binary format. -#define MEMPROF_RAW_VERSION 3ULL +#define MEMPROF_RAW_VERSION 4ULL + +// Currently supported versions. +#define MEMPROF_RAW_SUPPORTED_VERSIONS \ + { 3ULL, 4ULL } #define MEMPROF_BUILDID_MAX_SIZE 32ULL @@ -119,7 +123,8 @@ MemInfoBlock() { } MemInfoBlock(uint32_t Size, uint64_t AccessCount, uint32_t AllocTs, - uint32_t DeallocTs, uint32_t AllocCpu, uint32_t DeallocCpu) + uint32_t DeallocTs, uint32_t AllocCpu, uint32_t DeallocCpu, + uintptr_t Histogram, uint32_t HistogramSize) : MemInfoBlock() { AllocCount = 1U; TotalAccessCount = AccessCount; @@ -149,6 +154,8 @@ MemInfoBlock(uint32_t Size, uint64_t AccessCount, uint32_t AllocTs, AllocCpuId = AllocCpu; DeallocCpuId = DeallocCpu; NumMigratedCpu = AllocCpuId != DeallocCpuId; + AccessHistogramSize = HistogramSize; + AccessHistogram = Histogram; } void Merge(const MemInfoBlock &newMIB) { @@ -194,6 +201,24 @@ void Merge(const MemInfoBlock &newMIB) { NumSameDeallocCpu += DeallocCpuId == newMIB.DeallocCpuId; AllocCpuId = newMIB.AllocCpuId; DeallocCpuId = newMIB.DeallocCpuId; + + // For merging histograms, we always keep the longer histogram, and add + // values of shorter histogram to larger one. + uintptr_t ShorterHistogram; + uint32_t ShorterHistogramSize; + if (newMIB.AccessHistogramSize > AccessHistogramSize) { + ShorterHistogram = AccessHistogram; + ShorterHistogramSize = AccessHistogramSize; + // Swap histogram of current to larger histogram + AccessHistogram = newMIB.AccessHistogram; + AccessHistogramSize = newMIB.AccessHistogramSize; + } else { + ShorterHistogram = newMIB.AccessHistogram; + ShorterHistogramSize = newMIB.AccessHistogramSize; + } + for (size_t i = 0; i < ShorterHistogramSize; ++i) { + ((uint64_t *)AccessHistogram)[i] += ((uint64_t *)ShorterHistogram)[i]; + } } #ifdef _MSC_VER diff --git a/compiler-rt/lib/asan/asan_globals.cpp b/compiler-rt/lib/asan/asan_globals.cpp index 6ac64c4b776bbb..d413b1ebc9fc0e 100644 --- a/compiler-rt/lib/asan/asan_globals.cpp +++ b/compiler-rt/lib/asan/asan_globals.cpp @@ -344,8 +344,8 @@ void __asan_unregister_image_globals(uptr *flag) { } void __asan_register_elf_globals(uptr *flag, void *start, void *stop) { - if (*flag) return; - if (!start) return; + if (*flag || start == stop) + return; CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global)); __asan_global *globals_start = (__asan_global*)start; __asan_global *globals_stop = (__asan_global*)stop; @@ -354,8 +354,8 @@ void __asan_register_elf_globals(uptr *flag, void *start, void *stop) { } void __asan_unregister_elf_globals(uptr *flag, void *start, void *stop) { - if (!*flag) return; - if (!start) return; + if (!*flag || start == stop) + return; CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global)); __asan_global *globals_start = (__asan_global*)start; __asan_global *globals_stop = (__asan_global*)stop; diff --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp index 6d1360e104975f..f8f86a766b204f 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cpp +++ b/compiler-rt/lib/asan/asan_interceptors.cpp @@ -333,7 +333,7 @@ INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret, } # endif -DEFINE_REAL_PTHREAD_FUNCTIONS +DEFINE_INTERNAL_PTHREAD_FUNCTIONS #endif // ASAN_INTERCEPT_PTHREAD_CREATE #if ASAN_INTERCEPT_SWAPCONTEXT diff --git a/compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp b/compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp index 5f41e1eb8a4b47..a5f1ecd4b26add 100644 --- a/compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp +++ b/compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp @@ -52,12 +52,12 @@ void GuardedPoolAllocator::init(const options::Options &Opts) { Opts.MaxSimultaneousAllocations == 0) return; - Check(Opts.SampleRate >= 0, "GWP-ASan Error: SampleRate is < 0."); - Check(Opts.SampleRate < (1 << 30), "GWP-ASan Error: SampleRate is >= 2^30."); - Check(Opts.MaxSimultaneousAllocations >= 0, + check(Opts.SampleRate >= 0, "GWP-ASan Error: SampleRate is < 0."); + check(Opts.SampleRate < (1 << 30), "GWP-ASan Error: SampleRate is >= 2^30."); + check(Opts.MaxSimultaneousAllocations >= 0, "GWP-ASan Error: MaxSimultaneousAllocations is < 0."); - Check(SingletonPtr == nullptr, + check(SingletonPtr == nullptr, "There's already a live GuardedPoolAllocator!"); SingletonPtr = this; Backtrace = Opts.Backtrace; diff --git a/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_fuchsia.cpp b/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_fuchsia.cpp index ca5231a235f5c0..3f39402652a998 100644 --- a/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_fuchsia.cpp +++ b/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_fuchsia.cpp @@ -24,13 +24,13 @@ void *GuardedPoolAllocator::map(size_t Size, const char *Name) const { assert((Size % State.PageSize) == 0); zx_handle_t Vmo; zx_status_t Status = _zx_vmo_create(Size, 0, &Vmo); - Check(Status == ZX_OK, "Failed to create Vmo"); + check(Status == ZX_OK, "Failed to create Vmo"); _zx_object_set_property(Vmo, ZX_PROP_NAME, Name, strlen(Name)); zx_vaddr_t Addr; Status = _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_ALLOW_FAULTS, 0, Vmo, 0, Size, &Addr); - Check(Status == ZX_OK, "Vmo mapping failed"); + check(Status == ZX_OK, "Vmo mapping failed"); _zx_handle_close(Vmo); return reinterpret_cast(Addr); } @@ -40,7 +40,7 @@ void GuardedPoolAllocator::unmap(void *Ptr, size_t Size) const { assert((Size % State.PageSize) == 0); zx_status_t Status = _zx_vmar_unmap(_zx_vmar_root_self(), reinterpret_cast(Ptr), Size); - Check(Status == ZX_OK, "Vmo unmapping failed"); + check(Status == ZX_OK, "Vmo unmapping failed"); } void *GuardedPoolAllocator::reserveGuardedPool(size_t Size) { @@ -50,7 +50,7 @@ void *GuardedPoolAllocator::reserveGuardedPool(size_t Size) { _zx_vmar_root_self(), ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC, 0, Size, &GuardedPagePoolPlatformData.Vmar, &Addr); - Check(Status == ZX_OK, "Failed to reserve guarded pool allocator memory"); + check(Status == ZX_OK, "Failed to reserve guarded pool allocator memory"); _zx_object_set_property(GuardedPagePoolPlatformData.Vmar, ZX_PROP_NAME, kGwpAsanGuardPageName, strlen(kGwpAsanGuardPageName)); return reinterpret_cast(Addr); @@ -59,8 +59,8 @@ void *GuardedPoolAllocator::reserveGuardedPool(size_t Size) { void GuardedPoolAllocator::unreserveGuardedPool() { const zx_handle_t Vmar = GuardedPagePoolPlatformData.Vmar; assert(Vmar != ZX_HANDLE_INVALID && Vmar != _zx_vmar_root_self()); - Check(_zx_vmar_destroy(Vmar) == ZX_OK, "Failed to destroy a vmar"); - Check(_zx_handle_close(Vmar) == ZX_OK, "Failed to close a vmar"); + check(_zx_vmar_destroy(Vmar) == ZX_OK, "Failed to destroy a vmar"); + check(_zx_handle_close(Vmar) == ZX_OK, "Failed to close a vmar"); GuardedPagePoolPlatformData.Vmar = ZX_HANDLE_INVALID; } @@ -69,7 +69,7 @@ void GuardedPoolAllocator::allocateInGuardedPool(void *Ptr, size_t Size) const { assert((Size % State.PageSize) == 0); zx_handle_t Vmo; zx_status_t Status = _zx_vmo_create(Size, 0, &Vmo); - Check(Status == ZX_OK, "Failed to create vmo"); + check(Status == ZX_OK, "Failed to create vmo"); _zx_object_set_property(Vmo, ZX_PROP_NAME, kGwpAsanAliveSlotName, strlen(kGwpAsanAliveSlotName)); const zx_handle_t Vmar = GuardedPagePoolPlatformData.Vmar; @@ -81,7 +81,7 @@ void GuardedPoolAllocator::allocateInGuardedPool(void *Ptr, size_t Size) const { ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_ALLOW_FAULTS | ZX_VM_SPECIFIC, Offset, Vmo, 0, Size, &P); - Check(Status == ZX_OK, "Vmo mapping failed"); + check(Status == ZX_OK, "Vmo mapping failed"); _zx_handle_close(Vmo); } @@ -93,7 +93,7 @@ void GuardedPoolAllocator::deallocateInGuardedPool(void *Ptr, assert(Vmar != ZX_HANDLE_INVALID && Vmar != _zx_vmar_root_self()); const zx_status_t Status = _zx_vmar_unmap(Vmar, reinterpret_cast(Ptr), Size); - Check(Status == ZX_OK, "Vmar unmapping failed"); + check(Status == ZX_OK, "Vmar unmapping failed"); } size_t GuardedPoolAllocator::getPlatformPageSize() { diff --git a/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp b/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp index c036ebe3efcc02..549e31acb176d3 100644 --- a/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp +++ b/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp @@ -46,7 +46,7 @@ void *GuardedPoolAllocator::map(size_t Size, const char *Name) const { assert((Size % State.PageSize) == 0); void *Ptr = mmap(nullptr, Size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - Check(Ptr != MAP_FAILED, "Failed to map guarded pool allocator memory"); + check(Ptr != MAP_FAILED, "Failed to map guarded pool allocator memory"); MaybeSetMappingName(Ptr, Size, Name); return Ptr; } @@ -54,7 +54,7 @@ void *GuardedPoolAllocator::map(size_t Size, const char *Name) const { void GuardedPoolAllocator::unmap(void *Ptr, size_t Size) const { assert((reinterpret_cast(Ptr) % State.PageSize) == 0); assert((Size % State.PageSize) == 0); - Check(munmap(Ptr, Size) == 0, + check(munmap(Ptr, Size) == 0, "Failed to unmap guarded pool allocator memory."); } @@ -62,7 +62,7 @@ void *GuardedPoolAllocator::reserveGuardedPool(size_t Size) { assert((Size % State.PageSize) == 0); void *Ptr = mmap(nullptr, Size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - Check(Ptr != MAP_FAILED, "Failed to reserve guarded pool allocator memory"); + check(Ptr != MAP_FAILED, "Failed to reserve guarded pool allocator memory"); MaybeSetMappingName(Ptr, Size, kGwpAsanGuardPageName); return Ptr; } @@ -75,7 +75,7 @@ void GuardedPoolAllocator::unreserveGuardedPool() { void GuardedPoolAllocator::allocateInGuardedPool(void *Ptr, size_t Size) const { assert((reinterpret_cast(Ptr) % State.PageSize) == 0); assert((Size % State.PageSize) == 0); - Check(mprotect(Ptr, Size, PROT_READ | PROT_WRITE) == 0, + check(mprotect(Ptr, Size, PROT_READ | PROT_WRITE) == 0, "Failed to allocate in guarded pool allocator memory"); MaybeSetMappingName(Ptr, Size, kGwpAsanAliveSlotName); } @@ -87,7 +87,7 @@ void GuardedPoolAllocator::deallocateInGuardedPool(void *Ptr, // mmap() a PROT_NONE page over the address to release it to the system, if // we used mprotect() here the system would count pages in the quarantine // against the RSS. - Check(mmap(Ptr, Size, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, + check(mmap(Ptr, Size, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0) != MAP_FAILED, "Failed to deallocate in guarded pool allocator memory"); MaybeSetMappingName(Ptr, Size, kGwpAsanGuardPageName); diff --git a/compiler-rt/lib/gwp_asan/utilities.h b/compiler-rt/lib/gwp_asan/utilities.h index d8bc0e491a3d2e..76e5df2e3eb8f8 100644 --- a/compiler-rt/lib/gwp_asan/utilities.h +++ b/compiler-rt/lib/gwp_asan/utilities.h @@ -18,7 +18,7 @@ namespace gwp_asan { void die(const char *Message); // Checks that `Condition` is true, otherwise dies with `Message`. -GWP_ASAN_ALWAYS_INLINE void Check(bool Condition, const char *Message) { +GWP_ASAN_ALWAYS_INLINE void check(bool Condition, const char *Message) { if (Condition) return; die(Message); diff --git a/compiler-rt/lib/hwasan/hwasan_interceptors.cpp b/compiler-rt/lib/hwasan/hwasan_interceptors.cpp index 08ae435b8214ae..c10b5c158548e9 100644 --- a/compiler-rt/lib/hwasan/hwasan_interceptors.cpp +++ b/compiler-rt/lib/hwasan/hwasan_interceptors.cpp @@ -334,7 +334,7 @@ INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret, } # endif -DEFINE_REAL_PTHREAD_FUNCTIONS +DEFINE_INTERNAL_PTHREAD_FUNCTIONS DEFINE_REAL(int, vfork,) DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork,) diff --git a/compiler-rt/lib/lsan/lsan_interceptors.cpp b/compiler-rt/lib/lsan/lsan_interceptors.cpp index 1fd0010f9ea936..6df4b6865b3794 100644 --- a/compiler-rt/lib/lsan/lsan_interceptors.cpp +++ b/compiler-rt/lib/lsan/lsan_interceptors.cpp @@ -525,7 +525,7 @@ INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret, # define LSAN_MAYBE_INTERCEPT_TIMEDJOIN # endif // SANITIZER_INTERCEPT_TIMEDJOIN -DEFINE_REAL_PTHREAD_FUNCTIONS +DEFINE_INTERNAL_PTHREAD_FUNCTIONS INTERCEPTOR(void, _exit, int status) { if (status == 0 && HasReportedLeaks()) status = common_flags()->exitcode; diff --git a/compiler-rt/lib/memprof/memprof_allocator.cpp b/compiler-rt/lib/memprof/memprof_allocator.cpp index 35e941228525a8..19b2b901068246 100644 --- a/compiler-rt/lib/memprof/memprof_allocator.cpp +++ b/compiler-rt/lib/memprof/memprof_allocator.cpp @@ -34,6 +34,10 @@ #include #include +#define MAX_HISTOGRAM_PRINT_SIZE 32U + +extern bool __memprof_histogram; + namespace __memprof { namespace { using ::llvm::memprof::MemInfoBlock; @@ -68,6 +72,14 @@ void Print(const MemInfoBlock &M, const u64 id, bool print_terse) { "cpu: %u, num same dealloc_cpu: %u\n", M.NumMigratedCpu, M.NumLifetimeOverlaps, M.NumSameAllocCpu, M.NumSameDeallocCpu); + Printf("AccessCountHistogram[%u]: ", M.AccessHistogramSize); + uint32_t PrintSize = M.AccessHistogramSize > MAX_HISTOGRAM_PRINT_SIZE + ? MAX_HISTOGRAM_PRINT_SIZE + : M.AccessHistogramSize; + for (size_t i = 0; i < PrintSize; ++i) { + Printf("%llu ", ((uint64_t *)M.AccessHistogram)[i]); + } + Printf("\n"); } } } // namespace @@ -216,6 +228,17 @@ u64 GetShadowCount(uptr p, u32 size) { return count; } +// Accumulates the access count from the shadow for the given pointer and size. +// See memprof_mapping.h for an overview on histogram counters. +u64 GetShadowCountHistogram(uptr p, u32 size) { + u8 *shadow = (u8 *)HISTOGRAM_MEM_TO_SHADOW(p); + u8 *shadow_end = (u8 *)HISTOGRAM_MEM_TO_SHADOW(p + size); + u64 count = 0; + for (; shadow <= shadow_end; shadow++) + count += *shadow; + return count; +} + // Clears the shadow counters (when memory is allocated). void ClearShadow(uptr addr, uptr size) { CHECK(AddrIsAlignedByGranularity(addr)); @@ -223,8 +246,16 @@ void ClearShadow(uptr addr, uptr size) { CHECK(AddrIsAlignedByGranularity(addr + size)); CHECK(AddrIsInMem(addr + size - SHADOW_GRANULARITY)); CHECK(REAL(memset)); - uptr shadow_beg = MEM_TO_SHADOW(addr); - uptr shadow_end = MEM_TO_SHADOW(addr + size - SHADOW_GRANULARITY) + 1; + uptr shadow_beg; + uptr shadow_end; + if (__memprof_histogram) { + shadow_beg = HISTOGRAM_MEM_TO_SHADOW(addr); + shadow_end = HISTOGRAM_MEM_TO_SHADOW(addr + size); + } else { + shadow_beg = MEM_TO_SHADOW(addr); + shadow_end = MEM_TO_SHADOW(addr + size - SHADOW_GRANULARITY) + 1; + } + if (shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) { REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg); } else { @@ -279,6 +310,44 @@ struct Allocator { Print(Value->mib, Key, bool(Arg)); } + // See memprof_mapping.h for an overview on histogram counters. + static MemInfoBlock CreateNewMIB(uptr p, MemprofChunk *m, u64 user_size) { + if (__memprof_histogram) { + return CreateNewMIBWithHistogram(p, m, user_size); + } else { + return CreateNewMIBWithoutHistogram(p, m, user_size); + } + } + + static MemInfoBlock CreateNewMIBWithHistogram(uptr p, MemprofChunk *m, + u64 user_size) { + + u64 c = GetShadowCountHistogram(p, user_size); + long curtime = GetTimestamp(); + uint32_t HistogramSize = + RoundUpTo(user_size, HISTOGRAM_GRANULARITY) / HISTOGRAM_GRANULARITY; + uintptr_t Histogram = + (uintptr_t)InternalAlloc(HistogramSize * sizeof(uint64_t)); + memset((void *)Histogram, 0, HistogramSize * sizeof(uint64_t)); + for (size_t i = 0; i < HistogramSize; ++i) { + u8 Counter = + *((u8 *)HISTOGRAM_MEM_TO_SHADOW(p + HISTOGRAM_GRANULARITY * i)); + ((uint64_t *)Histogram)[i] = (uint64_t)Counter; + } + MemInfoBlock newMIB(user_size, c, m->timestamp_ms, curtime, m->cpu_id, + GetCpuId(), Histogram, HistogramSize); + return newMIB; + } + + static MemInfoBlock CreateNewMIBWithoutHistogram(uptr p, MemprofChunk *m, + u64 user_size) { + u64 c = GetShadowCount(p, user_size); + long curtime = GetTimestamp(); + MemInfoBlock newMIB(user_size, c, m->timestamp_ms, curtime, m->cpu_id, + GetCpuId(), 0, 0); + return newMIB; + } + void FinishAndWrite() { if (print_text && common_flags()->print_module_map) DumpProcessMap(); @@ -319,10 +388,7 @@ struct Allocator { if (!m) return; uptr user_beg = ((uptr)m) + kChunkHeaderSize; - u64 c = GetShadowCount(user_beg, user_requested_size); - long curtime = GetTimestamp(); - MemInfoBlock newMIB(user_requested_size, c, m->timestamp_ms, curtime, - m->cpu_id, GetCpuId()); + MemInfoBlock newMIB = CreateNewMIB(user_beg, m, user_requested_size); InsertOrMerge(m->alloc_context_id, newMIB, A->MIBMap); }, this); @@ -451,11 +517,7 @@ struct Allocator { atomic_exchange(&m->user_requested_size, 0, memory_order_acquire); if (memprof_inited && atomic_load_relaxed(&constructed) && !atomic_load_relaxed(&destructing)) { - u64 c = GetShadowCount(p, user_requested_size); - long curtime = GetTimestamp(); - - MemInfoBlock newMIB(user_requested_size, c, m->timestamp_ms, curtime, - m->cpu_id, GetCpuId()); + MemInfoBlock newMIB = this->CreateNewMIB(p, m, user_requested_size); InsertOrMerge(m->alloc_context_id, newMIB, MIBMap); } diff --git a/compiler-rt/lib/memprof/memprof_flags.inc b/compiler-rt/lib/memprof/memprof_flags.inc index ee0760ddc302a6..7c5dc091f79351 100644 --- a/compiler-rt/lib/memprof/memprof_flags.inc +++ b/compiler-rt/lib/memprof/memprof_flags.inc @@ -38,4 +38,4 @@ MEMPROF_FLAG(bool, allocator_frees_and_returns_null_on_realloc_zero, true, MEMPROF_FLAG(bool, print_text, false, "If set, prints the heap profile in text format. Else use the raw binary serialization format.") MEMPROF_FLAG(bool, print_terse, false, - "If set, prints memory profile in a terse format. Only applicable if print_text = true.") + "If set, prints memory profile in a terse format. Only applicable if print_text = true.") \ No newline at end of file diff --git a/compiler-rt/lib/memprof/memprof_interceptors.cpp b/compiler-rt/lib/memprof/memprof_interceptors.cpp index a267f6d3d6717b..53ee4e953419b5 100644 --- a/compiler-rt/lib/memprof/memprof_interceptors.cpp +++ b/compiler-rt/lib/memprof/memprof_interceptors.cpp @@ -166,7 +166,7 @@ INTERCEPTOR(int, pthread_join, void *t, void **arg) { return REAL(pthread_join)(t, arg); } -DEFINE_REAL_PTHREAD_FUNCTIONS +DEFINE_INTERNAL_PTHREAD_FUNCTIONS INTERCEPTOR(char *, index, const char *string, int c) ALIAS(WRAP(strchr)); diff --git a/compiler-rt/lib/memprof/memprof_mapping.h b/compiler-rt/lib/memprof/memprof_mapping.h index 1cc0836834cdf0..fef8acfcfc9219 100644 --- a/compiler-rt/lib/memprof/memprof_mapping.h +++ b/compiler-rt/lib/memprof/memprof_mapping.h @@ -22,7 +22,6 @@ static const u64 kDefaultShadowScale = 3; #define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE) #define MEMPROF_ALIGNMENT 32 - namespace __memprof { extern uptr kHighMemEnd; // Initialized in __memprof_init. @@ -37,6 +36,34 @@ extern uptr kHighMemEnd; // Initialized in __memprof_init. #define MEM_TO_SHADOW(mem) \ ((((mem) & SHADOW_MASK) >> SHADOW_SCALE) + (SHADOW_OFFSET)) +// Histogram shadow memory is laid different to the standard configuration: + +// 8 bytes +// +---+---+---+ +---+---+---+ +---+---+---+ +// Memory | a | | b | | c | +// +---+---+---+ +---+---+---+ +---+---+---+ + +// +---+ +---+ +---+ +// Shadow | a | | b | | c | +// +---+ +---+ +---+ +// 1 byte +// +// Where we have a 1 byte counter for each 8 bytes. HISTOGRAM_MEM_TO_SHADOW +// translates a memory address to the address of its corresponding shadow +// counter memory address. The same data is still provided in MIB whether +// histograms are used or not. Total access counts per allocations are +// computed by summing up all individual 1 byte counters. This can incur an +// accuracy penalty. + +#define HISTOGRAM_GRANULARITY 8U + +#define HISTOGRAM_MAX_COUNTER 255U + +#define HISTOGRAM_SHADOW_MASK ~(HISTOGRAM_GRANULARITY - 1) + +#define HISTOGRAM_MEM_TO_SHADOW(mem) \ + ((((mem) & HISTOGRAM_SHADOW_MASK) >> SHADOW_SCALE) + (SHADOW_OFFSET)) + #define SHADOW_ENTRY_SIZE (MEM_GRANULARITY >> SHADOW_SCALE) #define kLowMemBeg 0 @@ -108,6 +135,14 @@ inline void RecordAccess(uptr a) { (*shadow_address)++; } +inline void RecordAccessHistogram(uptr a) { + CHECK_EQ(SHADOW_ENTRY_SIZE, 8); + u8 *shadow_address = (u8 *)HISTOGRAM_MEM_TO_SHADOW(a); + if (*shadow_address < HISTOGRAM_MAX_COUNTER) { + (*shadow_address)++; + } +} + } // namespace __memprof #endif // MEMPROF_MAPPING_H diff --git a/compiler-rt/lib/memprof/memprof_mibmap.cpp b/compiler-rt/lib/memprof/memprof_mibmap.cpp index 32f0796c8f241a..a49ed8bf4fd64f 100644 --- a/compiler-rt/lib/memprof/memprof_mibmap.cpp +++ b/compiler-rt/lib/memprof/memprof_mibmap.cpp @@ -30,7 +30,18 @@ void InsertOrMerge(const uptr Id, const MemInfoBlock &Block, MIBMapTy &Map) { } else { LockedMemInfoBlock *lmib = *h; SpinMutexLock lock(&lmib->mutex); + uintptr_t ShorterHistogram; + if (Block.AccessHistogramSize > lmib->mib.AccessHistogramSize) + ShorterHistogram = lmib->mib.AccessHistogram; + else + ShorterHistogram = Block.AccessHistogram; + lmib->mib.Merge(Block); + // The larger histogram is kept and the shorter histogram is discarded after + // adding the counters to the larger historam. Free only the shorter + // Histogram + if (Block.AccessHistogramSize > 0 || lmib->mib.AccessHistogramSize > 0) + InternalFree((void *)ShorterHistogram); } } diff --git a/compiler-rt/lib/memprof/memprof_rawprofile.cpp b/compiler-rt/lib/memprof/memprof_rawprofile.cpp index fa92fa0e4b53e9..a897648584828b 100644 --- a/compiler-rt/lib/memprof/memprof_rawprofile.cpp +++ b/compiler-rt/lib/memprof/memprof_rawprofile.cpp @@ -146,24 +146,38 @@ void SerializeStackToBuffer(const Vector &StackIds, // ---------- MIB Entry 0 // Alloc Count // ... +// ---- AccessHistogram Entry 0 +// ... +// ---- AccessHistogram Entry AccessHistogramSize - 1 // ---------- MIB Entry 1 // Alloc Count // ... +// ---- AccessHistogram Entry 0 +// ... +// ---- AccessHistogram Entry AccessHistogramSize - 1 // ---------- void SerializeMIBInfoToBuffer(MIBMapTy &MIBMap, const Vector &StackIds, const u64 ExpectedNumBytes, char *&Buffer) { char *Ptr = Buffer; const u64 NumEntries = StackIds.Size(); Ptr = WriteBytes(NumEntries, Ptr); - for (u64 i = 0; i < NumEntries; i++) { const u64 Key = StackIds[i]; MIBMapTy::Handle h(&MIBMap, Key, /*remove=*/true, /*create=*/false); CHECK(h.exists()); Ptr = WriteBytes(Key, Ptr); + // FIXME: We unnecessarily serialize the AccessHistogram pointer. Adding a + // serialization schema will fix this issue. See also FIXME in + // deserialization. Ptr = WriteBytes((*h)->mib, Ptr); + for (u64 j = 0; j < (*h)->mib.AccessHistogramSize; ++j) { + u64 HistogramEntry = ((u64 *)((*h)->mib.AccessHistogram))[j]; + Ptr = WriteBytes(HistogramEntry, Ptr); + } + if ((*h)->mib.AccessHistogramSize > 0) { + InternalFree((void *)((*h)->mib.AccessHistogram)); + } } - CHECK(ExpectedNumBytes >= static_cast(Ptr - Buffer) && "Expected num bytes != actual bytes written"); } @@ -192,7 +206,15 @@ void SerializeMIBInfoToBuffer(MIBMapTy &MIBMap, const Vector &StackIds, // ---------- MIB Entry // Alloc Count // ... -// ---------- +// ---- AccessHistogram Entry 0 +// ... +// ---- AccessHistogram Entry AccessHistogramSize - 1 +// ---------- MIB Entry 1 +// Alloc Count +// ... +// ---- AccessHistogram Entry 0 +// ... +// ---- AccessHistogram Entry AccessHistogramSize - 1 // Optional Padding Bytes // ---------- Stack Info // Num Entries @@ -218,13 +240,26 @@ u64 SerializeToRawProfile(MIBMapTy &MIBMap, ArrayRef Modules, const u64 NumMIBInfoBytes = RoundUpTo( sizeof(u64) + StackIds.Size() * (sizeof(u64) + sizeof(MemInfoBlock)), 8); + // Get Number of AccessHistogram entries in total + u64 TotalAccessHistogramEntries = 0; + MIBMap.ForEach( + [](const uptr Key, UNUSED LockedMemInfoBlock *const &MIB, void *Arg) { + u64 *TotalAccessHistogramEntries = (u64 *)Arg; + *TotalAccessHistogramEntries += MIB->mib.AccessHistogramSize; + }, + reinterpret_cast(&TotalAccessHistogramEntries)); + const u64 NumHistogramBytes = + RoundUpTo(TotalAccessHistogramEntries * sizeof(uint64_t), 8); + const u64 NumStackBytes = RoundUpTo(StackSizeBytes(StackIds), 8); // Ensure that the profile is 8b aligned. We allow for some optional padding // at the end so that any subsequent profile serialized to the same file does // not incur unaligned accesses. - const u64 TotalSizeBytes = RoundUpTo( - sizeof(Header) + NumSegmentBytes + NumStackBytes + NumMIBInfoBytes, 8); + const u64 TotalSizeBytes = + RoundUpTo(sizeof(Header) + NumSegmentBytes + NumStackBytes + + NumMIBInfoBytes + NumHistogramBytes, + 8); // Allocate the memory for the entire buffer incl. info blocks. Buffer = (char *)InternalAlloc(TotalSizeBytes); @@ -235,14 +270,16 @@ u64 SerializeToRawProfile(MIBMapTy &MIBMap, ArrayRef Modules, static_cast(TotalSizeBytes), sizeof(Header), sizeof(Header) + NumSegmentBytes, - sizeof(Header) + NumSegmentBytes + NumMIBInfoBytes}; + sizeof(Header) + NumSegmentBytes + NumMIBInfoBytes + + NumHistogramBytes}; Ptr = WriteBytes(header, Ptr); SerializeSegmentsToBuffer(Modules, NumSegmentBytes, Ptr); Ptr += NumSegmentBytes; - SerializeMIBInfoToBuffer(MIBMap, StackIds, NumMIBInfoBytes, Ptr); - Ptr += NumMIBInfoBytes; + SerializeMIBInfoToBuffer(MIBMap, StackIds, + NumMIBInfoBytes + NumHistogramBytes, Ptr); + Ptr += NumMIBInfoBytes + NumHistogramBytes; SerializeStackToBuffer(StackIds, NumStackBytes, Ptr); diff --git a/compiler-rt/lib/memprof/memprof_rtl.cpp b/compiler-rt/lib/memprof/memprof_rtl.cpp index 0a63f813848eef..a87e8cefd6c40f 100644 --- a/compiler-rt/lib/memprof/memprof_rtl.cpp +++ b/compiler-rt/lib/memprof/memprof_rtl.cpp @@ -32,6 +32,9 @@ uptr __memprof_shadow_memory_dynamic_address; // Global interface symbol. // Allow the user to specify a profile output file via the binary. SANITIZER_WEAK_ATTRIBUTE char __memprof_profile_filename[1]; +// Share ClHistogram compiler flag with runtime. +SANITIZER_WEAK_ATTRIBUTE bool __memprof_histogram; + namespace __memprof { static void MemprofDie() { @@ -75,12 +78,23 @@ uptr kHighMemEnd; // exported functions #define MEMPROF_MEMORY_ACCESS_CALLBACK_BODY() __memprof::RecordAccess(addr); +#define MEMPROF_MEMORY_ACCESS_CALLBACK_BODY_HIST() \ + __memprof::RecordAccessHistogram(addr); #define MEMPROF_MEMORY_ACCESS_CALLBACK(type) \ extern "C" NOINLINE INTERFACE_ATTRIBUTE void __memprof_##type(uptr addr) { \ MEMPROF_MEMORY_ACCESS_CALLBACK_BODY() \ } +#define MEMPROF_MEMORY_ACCESS_CALLBACK_HIST(type) \ + extern "C" NOINLINE INTERFACE_ATTRIBUTE void __memprof_hist_##type( \ + uptr addr) { \ + MEMPROF_MEMORY_ACCESS_CALLBACK_BODY_HIST() \ + } + +MEMPROF_MEMORY_ACCESS_CALLBACK_HIST(load) +MEMPROF_MEMORY_ACCESS_CALLBACK_HIST(store) + MEMPROF_MEMORY_ACCESS_CALLBACK(load) MEMPROF_MEMORY_ACCESS_CALLBACK(store) @@ -260,11 +274,20 @@ void __memprof_record_access(void const volatile *addr) { __memprof::RecordAccess((uptr)addr); } +void __memprof_record_access_hist(void const volatile *addr) { + __memprof::RecordAccessHistogram((uptr)addr); +} + void __memprof_record_access_range(void const volatile *addr, uptr size) { for (uptr a = (uptr)addr; a < (uptr)addr + size; a += kWordSize) __memprof::RecordAccess(a); } +void __memprof_record_access_range_hist(void const volatile *addr, uptr size) { + for (uptr a = (uptr)addr; a < (uptr)addr + size; a += kWordSize) + __memprof::RecordAccessHistogram(a); +} + extern "C" SANITIZER_INTERFACE_ATTRIBUTE u16 __sanitizer_unaligned_load16(const uu16 *p) { __memprof_record_access(p); diff --git a/compiler-rt/lib/memprof/tests/rawprofile.cpp b/compiler-rt/lib/memprof/tests/rawprofile.cpp index c5dfdca890be91..5764af9ce8afb5 100644 --- a/compiler-rt/lib/memprof/tests/rawprofile.cpp +++ b/compiler-rt/lib/memprof/tests/rawprofile.cpp @@ -95,7 +95,7 @@ TEST(MemProf, Basic) { // sizeof(MemInfoBlock) contains stack id + MeminfoBlock. EXPECT_EQ(StackOffset - MIBOffset, 8 + 2 * (8 + sizeof(MemInfoBlock))); - EXPECT_EQ(StackOffset, 408ULL); + EXPECT_EQ(StackOffset, 432ULL); // We expect 2 stack entries, with 5 frames - 8b for total count, // 2 * (8b for id, 8b for frame count and 5*8b for fake frames). // Since this is the last section, there may be additional padding at the end diff --git a/compiler-rt/lib/msan/msan_interceptors.cpp b/compiler-rt/lib/msan/msan_interceptors.cpp index 9abf2406332588..789b739b41189a 100644 --- a/compiler-rt/lib/msan/msan_interceptors.cpp +++ b/compiler-rt/lib/msan/msan_interceptors.cpp @@ -1226,7 +1226,7 @@ INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **retval, } #endif -DEFINE_REAL_PTHREAD_FUNCTIONS +DEFINE_INTERNAL_PTHREAD_FUNCTIONS extern char *tzname[2]; diff --git a/compiler-rt/lib/profile/InstrProfilingFile.c b/compiler-rt/lib/profile/InstrProfilingFile.c index 54ee59c30722f0..1c58584d2d4f73 100644 --- a/compiler-rt/lib/profile/InstrProfilingFile.c +++ b/compiler-rt/lib/profile/InstrProfilingFile.c @@ -210,10 +210,9 @@ COMPILER_RT_VISIBILITY extern intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR; #define WIN_SYM_PREFIX #endif #pragma comment( \ - linker, \ - "/alternatename:" WIN_SYM_PREFIX INSTR_PROF_QUOTE( \ - INSTR_PROF_PROFILE_COUNTER_BIAS_VAR) "=" WIN_SYM_PREFIX \ - INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR)) + linker, "/alternatename:" WIN_SYM_PREFIX INSTR_PROF_QUOTE( \ + INSTR_PROF_PROFILE_COUNTER_BIAS_VAR) "=" WIN_SYM_PREFIX \ + INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR)) #else COMPILER_RT_VISIBILITY extern intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR __attribute__((weak, alias(INSTR_PROF_QUOTE( diff --git a/compiler-rt/lib/safestack/safestack_platform.h b/compiler-rt/lib/safestack/safestack_platform.h index 2b1fc139baa90a..d4b2e2ef7391c8 100644 --- a/compiler-rt/lib/safestack/safestack_platform.h +++ b/compiler-rt/lib/safestack/safestack_platform.h @@ -25,8 +25,9 @@ #include #include -#if !(SANITIZER_NETBSD || SANITIZER_FREEBSD || SANITIZER_LINUX) -#error "Support for your platform has not been implemented" +#if !(SANITIZER_NETBSD || SANITIZER_FREEBSD || SANITIZER_LINUX || \ + SANITIZER_SOLARIS) +# error "Support for your platform has not been implemented" #endif #if SANITIZER_NETBSD @@ -39,6 +40,10 @@ extern "C" void *__mmap(void *, size_t, int, int, int, int, off_t); #include #endif +#if SANITIZER_SOLARIS +# include +#endif + namespace safestack { #if SANITIZER_NETBSD @@ -73,6 +78,8 @@ inline ThreadId GetTid() { long Tid; thr_self(&Tid); return Tid; +#elif SANITIZER_SOLARIS + return thr_self(); #else return syscall(SYS_gettid); #endif @@ -83,6 +90,12 @@ inline int TgKill(pid_t pid, ThreadId tid, int sig) { DEFINE__REAL(int, _lwp_kill, int a, int b); (void)pid; return _REAL(_lwp_kill, tid, sig); +#elif SANITIZER_SOLARIS +# ifdef SYS_lwp_kill + return syscall(SYS_lwp_kill, tid, sig); +# else + return -1; +# endif #elif SANITIZER_FREEBSD return syscall(SYS_thr_kill2, pid, tid, sig); #else @@ -96,6 +109,9 @@ inline void *Mmap(void *addr, size_t length, int prot, int flags, int fd, return __mmap(addr, length, prot, flags, fd, 0, offset); #elif SANITIZER_FREEBSD && (defined(__aarch64__) || defined(__x86_64__)) return (void *)__syscall(SYS_mmap, addr, length, prot, flags, fd, offset); +#elif SANITIZER_SOLARIS + return (void *)(uintptr_t)syscall(SYS_mmap, addr, length, prot, flags, fd, + offset); #else return (void *)syscall(SYS_mmap, addr, length, prot, flags, fd, offset); #endif diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp index 7b74bb1a7e0f3c..a174ae7be991d0 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cpp @@ -87,8 +87,8 @@ void MaybeStartBackgroudThread() { if (!common_flags()->hard_rss_limit_mb && !common_flags()->soft_rss_limit_mb && !common_flags()->heap_profile) return; - if (!&real_pthread_create) { - VPrintf(1, "%s: real_pthread_create undefined\n", SanitizerToolName); + if (!&internal_pthread_create) { + VPrintf(1, "%s: internal_pthread_create undefined\n", SanitizerToolName); return; // Can't spawn the thread anyway. } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp index bf2002b6b3de63..12df3ef73da4bc 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp @@ -1845,18 +1845,18 @@ HandleSignalMode GetHandleSignalMode(int signum) { # if !SANITIZER_GO void *internal_start_thread(void *(*func)(void *arg), void *arg) { - if (&real_pthread_create == 0) + if (&internal_pthread_create == 0) return nullptr; // Start the thread with signals blocked, otherwise it can steal user signals. ScopedBlockSignals block(nullptr); void *th; - real_pthread_create(&th, nullptr, func, arg); + internal_pthread_create(&th, nullptr, func, arg); return th; } void internal_join_thread(void *th) { - if (&real_pthread_join) - real_pthread_join(th, nullptr); + if (&internal_pthread_join) + internal_pthread_join(th, nullptr); } # else void *internal_start_thread(void *(*func)(void *), void *arg) { return 0; } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix.h b/compiler-rt/lib/sanitizer_common/sanitizer_posix.h index c5811dffea94b5..14617e4771bec4 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix.h @@ -74,21 +74,21 @@ int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, // These functions call appropriate pthread_ functions directly, bypassing // the interceptor. They are weak and may not be present in some tools. SANITIZER_WEAK_ATTRIBUTE -int real_pthread_create(void *th, void *attr, void *(*callback)(void *), - void *param); +int internal_pthread_create(void *th, void *attr, void *(*callback)(void *), + void *param); SANITIZER_WEAK_ATTRIBUTE -int real_pthread_join(void *th, void **ret); - -#define DEFINE_REAL_PTHREAD_FUNCTIONS \ - namespace __sanitizer { \ - int real_pthread_create(void *th, void *attr, void *(*callback)(void *), \ - void *param) { \ - return REAL(pthread_create)(th, attr, callback, param); \ - } \ - int real_pthread_join(void *th, void **ret) { \ - return REAL(pthread_join(th, ret)); \ - } \ - } // namespace __sanitizer +int internal_pthread_join(void *th, void **ret); + +# define DEFINE_INTERNAL_PTHREAD_FUNCTIONS \ + namespace __sanitizer { \ + int internal_pthread_create(void *th, void *attr, \ + void *(*callback)(void *), void *param) { \ + return REAL(pthread_create)(th, attr, callback, param); \ + } \ + int internal_pthread_join(void *th, void **ret) { \ + return REAL(pthread_join(th, ret)); \ + } \ + } // namespace __sanitizer int internal_pthread_attr_getstack(void *attr, void **addr, uptr *size); diff --git a/compiler-rt/lib/scudo/standalone/tests/secondary_test.cpp b/compiler-rt/lib/scudo/standalone/tests/secondary_test.cpp index e74930148f25ee..5685a9335316d1 100644 --- a/compiler-rt/lib/scudo/standalone/tests/secondary_test.cpp +++ b/compiler-rt/lib/scudo/standalone/tests/secondary_test.cpp @@ -190,30 +190,31 @@ TEST_F(MapAllocatorTest, SecondaryIterate) { Str.output(); } -TEST_F(MapAllocatorTest, SecondaryOptions) { - // Test options that are only meaningful if the secondary cache is enabled. - if (Allocator->canCache(0U)) { - // Attempt to set a maximum number of entries higher than the array size. - EXPECT_TRUE( - Allocator->setOption(scudo::Option::MaxCacheEntriesCount, 4096U)); - // Attempt to set an invalid (negative) number of entries - EXPECT_FALSE(Allocator->setOption(scudo::Option::MaxCacheEntriesCount, -1)); - // Various valid combinations. - EXPECT_TRUE(Allocator->setOption(scudo::Option::MaxCacheEntriesCount, 4U)); - EXPECT_TRUE( - Allocator->setOption(scudo::Option::MaxCacheEntrySize, 1UL << 20)); - EXPECT_TRUE(Allocator->canCache(1UL << 18)); - EXPECT_TRUE( - Allocator->setOption(scudo::Option::MaxCacheEntrySize, 1UL << 17)); - EXPECT_FALSE(Allocator->canCache(1UL << 18)); - EXPECT_TRUE(Allocator->canCache(1UL << 16)); - EXPECT_TRUE(Allocator->setOption(scudo::Option::MaxCacheEntriesCount, 0U)); - EXPECT_FALSE(Allocator->canCache(1UL << 16)); - EXPECT_TRUE(Allocator->setOption(scudo::Option::MaxCacheEntriesCount, 4U)); - EXPECT_TRUE( - Allocator->setOption(scudo::Option::MaxCacheEntrySize, 1UL << 20)); - EXPECT_TRUE(Allocator->canCache(1UL << 16)); - } +TEST_F(MapAllocatorTest, SecondaryCacheOptions) { + if (!Allocator->canCache(0U)) + TEST_SKIP("Secondary Cache disabled"); + + // Attempt to set a maximum number of entries higher than the array size. + EXPECT_TRUE(Allocator->setOption(scudo::Option::MaxCacheEntriesCount, 4096U)); + + // Attempt to set an invalid (negative) number of entries + EXPECT_FALSE(Allocator->setOption(scudo::Option::MaxCacheEntriesCount, -1)); + + // Various valid combinations. + EXPECT_TRUE(Allocator->setOption(scudo::Option::MaxCacheEntriesCount, 4U)); + EXPECT_TRUE( + Allocator->setOption(scudo::Option::MaxCacheEntrySize, 1UL << 20)); + EXPECT_TRUE(Allocator->canCache(1UL << 18)); + EXPECT_TRUE( + Allocator->setOption(scudo::Option::MaxCacheEntrySize, 1UL << 17)); + EXPECT_FALSE(Allocator->canCache(1UL << 18)); + EXPECT_TRUE(Allocator->canCache(1UL << 16)); + EXPECT_TRUE(Allocator->setOption(scudo::Option::MaxCacheEntriesCount, 0U)); + EXPECT_FALSE(Allocator->canCache(1UL << 16)); + EXPECT_TRUE(Allocator->setOption(scudo::Option::MaxCacheEntriesCount, 4U)); + EXPECT_TRUE( + Allocator->setOption(scudo::Option::MaxCacheEntrySize, 1UL << 20)); + EXPECT_TRUE(Allocator->canCache(1UL << 16)); } struct MapAllocatorWithReleaseTest : public MapAllocatorTest { diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp index 94adea777cafd9..034ae3d322b56b 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp @@ -1088,7 +1088,18 @@ TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) { return res; } -DEFINE_REAL_PTHREAD_FUNCTIONS +// DEFINE_INTERNAL_PTHREAD_FUNCTIONS +namespace __sanitizer { +int internal_pthread_create(void *th, void *attr, void *(*callback)(void *), + void *param) { + ScopedIgnoreInterceptors ignore; + return REAL(pthread_create)(th, attr, callback, param); +} +int internal_pthread_join(void *th, void **ret) { + ScopedIgnoreInterceptors ignore; + return REAL(pthread_join(th, ret)); +} +} // namespace __sanitizer TSAN_INTERCEPTOR(int, pthread_detach, void *th) { SCOPED_INTERCEPTOR_RAW(pthread_detach, th); diff --git a/compiler-rt/lib/tsan/rtl/tsan_mman.cpp b/compiler-rt/lib/tsan/rtl/tsan_mman.cpp index 6f118e0979e2de..e129e9af272f5f 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_mman.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_mman.cpp @@ -9,17 +9,19 @@ // This file is a part of ThreadSanitizer (TSan), a race detector. // //===----------------------------------------------------------------------===// +#include "tsan_mman.h" + #include "sanitizer_common/sanitizer_allocator_checks.h" #include "sanitizer_common/sanitizer_allocator_interface.h" #include "sanitizer_common/sanitizer_allocator_report.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_errno.h" #include "sanitizer_common/sanitizer_placement_new.h" +#include "sanitizer_common/sanitizer_stackdepot.h" +#include "tsan_flags.h" #include "tsan_interface.h" -#include "tsan_mman.h" -#include "tsan_rtl.h" #include "tsan_report.h" -#include "tsan_flags.h" +#include "tsan_rtl.h" namespace __tsan { @@ -115,12 +117,21 @@ ScopedGlobalProcessor::~ScopedGlobalProcessor() { gp->mtx.Unlock(); } -void AllocatorLock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS { +void AllocatorLockBeforeFork() SANITIZER_NO_THREAD_SAFETY_ANALYSIS { global_proc()->internal_alloc_mtx.Lock(); InternalAllocatorLock(); -} - -void AllocatorUnlock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS { +#if !SANITIZER_APPLE + // OS X allocates from hooks, see 6a3958247a. + allocator()->ForceLock(); + StackDepotLockBeforeFork(); +#endif +} + +void AllocatorUnlockAfterFork(bool child) SANITIZER_NO_THREAD_SAFETY_ANALYSIS { +#if !SANITIZER_APPLE + StackDepotUnlockAfterFork(child); + allocator()->ForceUnlock(); +#endif InternalAllocatorUnlock(); global_proc()->internal_alloc_mtx.Unlock(); } diff --git a/compiler-rt/lib/tsan/rtl/tsan_mman.h b/compiler-rt/lib/tsan/rtl/tsan_mman.h index 2095f28c0253e4..f01bbc4d15718f 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_mman.h +++ b/compiler-rt/lib/tsan/rtl/tsan_mman.h @@ -24,8 +24,8 @@ void ReplaceSystemMalloc(); void AllocatorProcStart(Processor *proc); void AllocatorProcFinish(Processor *proc); void AllocatorPrintStats(); -void AllocatorLock(); -void AllocatorUnlock(); +void AllocatorLockBeforeFork(); +void AllocatorUnlockAfterFork(bool child); void GlobalProcessorLock(); void GlobalProcessorUnlock(); diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp index fd9441dfcb53cb..e5ebb65754b327 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp @@ -35,8 +35,10 @@ extern "C" void __tsan_resume() { __tsan_resumed = 1; } +#if SANITIZER_APPLE SANITIZER_WEAK_DEFAULT_IMPL void __tsan_test_only_on_fork() {} +#endif namespace __tsan { @@ -813,7 +815,7 @@ void ForkBefore(ThreadState* thr, uptr pc) SANITIZER_NO_THREAD_SAFETY_ANALYSIS { ctx->thread_registry.Lock(); ctx->slot_mtx.Lock(); ScopedErrorReportLock::Lock(); - AllocatorLock(); + AllocatorLockBeforeFork(); // Suppress all reports in the pthread_atfork callbacks. // Reports will deadlock on the report_mtx. // We could ignore sync operations as well, @@ -828,14 +830,17 @@ void ForkBefore(ThreadState* thr, uptr pc) SANITIZER_NO_THREAD_SAFETY_ANALYSIS { // Disables memory write in OnUserAlloc/Free. thr->ignore_reads_and_writes++; +# if SANITIZER_APPLE __tsan_test_only_on_fork(); +# endif } -static void ForkAfter(ThreadState* thr) SANITIZER_NO_THREAD_SAFETY_ANALYSIS { +static void ForkAfter(ThreadState* thr, + bool child) SANITIZER_NO_THREAD_SAFETY_ANALYSIS { thr->suppress_reports--; // Enabled in ForkBefore. thr->ignore_interceptors--; thr->ignore_reads_and_writes--; - AllocatorUnlock(); + AllocatorUnlockAfterFork(child); ScopedErrorReportLock::Unlock(); ctx->slot_mtx.Unlock(); ctx->thread_registry.Unlock(); @@ -845,10 +850,10 @@ static void ForkAfter(ThreadState* thr) SANITIZER_NO_THREAD_SAFETY_ANALYSIS { GlobalProcessorUnlock(); } -void ForkParentAfter(ThreadState* thr, uptr pc) { ForkAfter(thr); } +void ForkParentAfter(ThreadState* thr, uptr pc) { ForkAfter(thr, false); } void ForkChildAfter(ThreadState* thr, uptr pc, bool start_thread) { - ForkAfter(thr); + ForkAfter(thr, true); u32 nthread = ctx->thread_registry.OnFork(thr->tid); VPrintf(1, "ThreadSanitizer: forked new process with pid %d," diff --git a/compiler-rt/test/lit.common.cfg.py b/compiler-rt/test/lit.common.cfg.py index 64b9a9d025e7b5..70bf43e2fac593 100644 --- a/compiler-rt/test/lit.common.cfg.py +++ b/compiler-rt/test/lit.common.cfg.py @@ -586,21 +586,18 @@ def get_macos_aligned_version(macos_vers): for vers in min_macos_deployment_target_substitutions: flag = config.apple_platform_min_deployment_target_flag major, minor = get_macos_aligned_version(vers) - if "mtargetos" in flag: + apple_device = "" + sim = "" + if "target" in flag: + apple_device = config.apple_platform.split("sim")[0] sim = "-simulator" if "sim" in config.apple_platform else "" - config.substitutions.append( - ( - "%%min_macos_deployment_target=%s.%s" % vers, - "{}{}.{}{}".format(flag, major, minor, sim), - ) - ) - else: - config.substitutions.append( - ( - "%%min_macos_deployment_target=%s.%s" % vers, - "{}={}.{}".format(flag, major, minor), - ) + + config.substitutions.append( + ( + "%%min_macos_deployment_target=%s.%s" % vers, + "{}={}{}.{}{}".format(flag, apple_device, major, minor, sim), ) + ) else: for vers in min_macos_deployment_target_substitutions: config.substitutions.append(("%%min_macos_deployment_target=%s.%s" % vers, "")) diff --git a/compiler-rt/test/metadata/common.h b/compiler-rt/test/metadata/common.h index af0e00902628e0..d9c26872b614fa 100644 --- a/compiler-rt/test/metadata/common.h +++ b/compiler-rt/test/metadata/common.h @@ -46,7 +46,7 @@ const char *meta_start; const char *meta_end; const char *atomics_start; const char *atomics_end; -}; // namespace +} // namespace extern "C" { void __sanitizer_metadata_covered_add(uint32_t version, const char *start, diff --git a/compiler-rt/test/profile/Linux/instrprof-vtable-value-prof.cpp b/compiler-rt/test/profile/Linux/instrprof-vtable-value-prof.cpp index e51805bdf923cb..efb24751da5ffe 100644 --- a/compiler-rt/test/profile/Linux/instrprof-vtable-value-prof.cpp +++ b/compiler-rt/test/profile/Linux/instrprof-vtable-value-prof.cpp @@ -1,63 +1,65 @@ -// REQUIRES: lld-available +// REQUIRES: lld, lld-available // Building the instrumented binary will fail because lld doesn't support // big-endian ELF for PPC (aka ABI 1). // ld.lld: error: /lib/../lib64/Scrt1.o: ABI version 1 is not supported // UNSUPPORTED: ppc && host-byteorder-big-endian -// RUN: %clangxx_pgogen -fuse-ld=lld -O2 -g -fprofile-generate=. -mllvm -enable-vtable-value-profiling %s -o %t-test -// RUN: env LLVM_PROFILE_FILE=%t-test.profraw %t-test +// RUN: rm -rf %t && mkdir %t && cd %t + +// RUN: %clangxx_pgogen -fuse-ld=lld -O2 -fprofile-generate=. -mllvm -enable-vtable-value-profiling %s -o test +// RUN: env LLVM_PROFILE_FILE=test.profraw ./test // Show vtable profiles from raw profile. -// RUN: llvm-profdata show --function=main --ic-targets --show-vtables %t-test.profraw | FileCheck %s --check-prefixes=COMMON,RAW +// RUN: llvm-profdata show --function=main --ic-targets --show-vtables test.profraw | FileCheck %s --check-prefixes=COMMON,RAW // Generate indexed profile from raw profile and show the data. -// RUN: llvm-profdata merge %t-test.profraw -o %t-test.profdata -// RUN: llvm-profdata show --function=main --ic-targets --show-vtables %t-test.profdata | FileCheck %s --check-prefixes=COMMON,INDEXED +// RUN: llvm-profdata merge --keep-vtable-symbols test.profraw -o test.profdata +// RUN: llvm-profdata show --function=main --ic-targets --show-vtables test.profdata | FileCheck %s --check-prefixes=COMMON,INDEXED // Generate text profile from raw and indexed profiles respectively and show the data. -// RUN: llvm-profdata merge --text %t-test.profraw -o %t-raw.proftext -// RUN: llvm-profdata show --function=main --ic-targets --show-vtables --text %t-raw.proftext | FileCheck %s --check-prefix=ICTEXT -// RUN: llvm-profdata merge --text %t-test.profdata -o %t-indexed.proftext -// RUN: llvm-profdata show --function=main --ic-targets --show-vtables --text %t-indexed.proftext | FileCheck %s --check-prefix=ICTEXT +// RUN: llvm-profdata merge --keep-vtable-symbols --text test.profraw -o raw.proftext +// RUN: llvm-profdata show --function=main --ic-targets --show-vtables --text raw.proftext | FileCheck %s --check-prefix=ICTEXT +// RUN: llvm-profdata merge --keep-vtable-symbols --text test.profdata -o indexed.proftext +// RUN: llvm-profdata show --function=main --ic-targets --show-vtables --text indexed.proftext | FileCheck %s --check-prefix=ICTEXT // Generate indexed profile from text profiles and show the data -// RUN: llvm-profdata merge --binary %t-raw.proftext -o %t-text.profraw -// RUN: llvm-profdata show --function=main --ic-targets --show-vtables %t-text.profraw | FileCheck %s --check-prefixes=COMMON,INDEXED -// RUN: llvm-profdata merge --binary %t-indexed.proftext -o %t-text.profdata -// RUN: llvm-profdata show --function=main --ic-targets --show-vtables %t-text.profdata | FileCheck %s --check-prefixes=COMMON,INDEXED +// RUN: llvm-profdata merge --keep-vtable-symbols --binary raw.proftext -o text.profraw +// RUN: llvm-profdata show --function=main --ic-targets --show-vtables text.profraw | FileCheck %s --check-prefixes=COMMON,INDEXED +// RUN: llvm-profdata merge --keep-vtable-symbols --binary indexed.proftext -o text.profdata +// RUN: llvm-profdata show --function=main --ic-targets --show-vtables text.profdata | FileCheck %s --check-prefixes=COMMON,INDEXED // COMMON: Counters: // COMMON-NEXT: main: -// COMMON-NEXT: Hash: 0x0f9a16fe6d398548 -// COMMON-NEXT: Counters: 2 +// COMMON-NEXT: Hash: 0x068617320ec408a0 +// COMMON-NEXT: Counters: 4 // COMMON-NEXT: Indirect Call Site Count: 2 // COMMON-NEXT: Number of instrumented vtables: 2 // RAW: Indirect Target Results: -// RAW-NEXT: [ 0, _ZN8Derived15func1Eii, 250 ] (25.00%) -// RAW-NEXT: [ 0, {{.*}}instrprof-vtable-value-prof.cpp;_ZN12_GLOBAL__N_18Derived25func1Eii, 750 ] (75.00%) -// RAW-NEXT: [ 1, _ZN8Derived15func2Eii, 250 ] (25.00%) -// RAW-NEXT: [ 1, {{.*}}instrprof-vtable-value-prof.cpp;_ZN12_GLOBAL__N_18Derived25func2Eii, 750 ] (75.00%) +// RAW-NEXT: [ 0, _ZN8Derived14funcEii, 50 ] (25.00%) +// RAW-NEXT: [ 0, {{.*}}instrprof-vtable-value-prof.cpp;_ZN12_GLOBAL__N_18Derived24funcEii, 150 ] (75.00%) +// RAW-NEXT: [ 1, _ZN8Derived1D0Ev, 250 ] (25.00%) +// RAW-NEXT: [ 1, {{.*}}instrprof-vtable-value-prof.cpp;_ZN12_GLOBAL__N_18Derived2D0Ev, 750 ] (75.00%) // RAW-NEXT: VTable Results: -// RAW-NEXT: [ 0, _ZTV8Derived1, 250 ] (25.00%) -// RAW-NEXT: [ 0, {{.*}}instrprof-vtable-value-prof.cpp;_ZTVN12_GLOBAL__N_18Derived2E, 750 ] (75.00%) +// RAW-NEXT: [ 0, _ZTV8Derived1, 50 ] (25.00%) +// RAW-NEXT: [ 0, {{.*}}instrprof-vtable-value-prof.cpp;_ZTVN12_GLOBAL__N_18Derived2E, 150 ] (75.00%) // RAW-NEXT: [ 1, _ZTV8Derived1, 250 ] (25.00%) // RAW-NEXT: [ 1, {{.*}}instrprof-vtable-value-prof.cpp;_ZTVN12_GLOBAL__N_18Derived2E, 750 ] (75.00%) // INDEXED: Indirect Target Results: -// INDEXED-NEXT: [ 0, {{.*}}instrprof-vtable-value-prof.cpp;_ZN12_GLOBAL__N_18Derived25func1Eii, 750 ] (75.00%) -// INDEXED-NEXT: [ 0, _ZN8Derived15func1Eii, 250 ] (25.00%) -// INDEXED-NEXT: [ 1, {{.*}}instrprof-vtable-value-prof.cpp;_ZN12_GLOBAL__N_18Derived25func2Eii, 750 ] (75.00%) -// INDEXED-NEXT: [ 1, _ZN8Derived15func2Eii, 250 ] (25.00%) +// INDEXED-NEXT: [ 0, {{.*}}instrprof-vtable-value-prof.cpp;_ZN12_GLOBAL__N_18Derived24funcEii, 150 ] (75.00%) +// INDEXED-NEXT: [ 0, _ZN8Derived14funcEii, 50 ] (25.00%) +// INDEXED-NEXT: [ 1, {{.*}}instrprof-vtable-value-prof.cpp;_ZN12_GLOBAL__N_18Derived2D0Ev, 750 ] (75.00%) +// INDEXED-NEXT: [ 1, _ZN8Derived1D0Ev, 250 ] (25.00%) // INDEXED-NEXT: VTable Results: -// INDEXED-NEXT: [ 0, {{.*}}instrprof-vtable-value-prof.cpp;_ZTVN12_GLOBAL__N_18Derived2E, 750 ] (75.00%) -// INDEXED-NEXT: [ 0, _ZTV8Derived1, 250 ] (25.00%) +// INDEXED-NEXT: [ 0, {{.*}}instrprof-vtable-value-prof.cpp;_ZTVN12_GLOBAL__N_18Derived2E, 150 ] (75.00%) +// INDEXED-NEXT: [ 0, _ZTV8Derived1, 50 ] (25.00%) // INDEXED-NEXT: [ 1, {{.*}}instrprof-vtable-value-prof.cpp;_ZTVN12_GLOBAL__N_18Derived2E, 750 ] (75.00%) // INDEXED-NEXT: [ 1, _ZTV8Derived1, 250 ] (25.00%) // COMMON: Instrumentation level: IR entry_first = 0 // COMMON-NEXT: Functions shown: 1 -// COMMON-NEXT: Total functions: 6 +// COMMON-NEXT: Total functions: 7 // COMMON-NEXT: Maximum function count: 1000 -// COMMON-NEXT: Maximum internal block count: 250 +// COMMON-NEXT: Maximum internal block count: 1000 // COMMON-NEXT: Statistics for indirect call sites profile: // COMMON-NEXT: Total number of sites: 2 // COMMON-NEXT: Total number of sites with values: 2 @@ -76,11 +78,13 @@ // ICTEXT: :ir // ICTEXT: main // ICTEXT: # Func Hash: -// ICTEXT: 1124236338992350536 +// ICTEXT: 470088714870327456 // ICTEXT: # Num Counters: -// ICTEXT: 2 +// ICTEXT: 4 // ICTEXT: # Counter Values: // ICTEXT: 1000 +// ICTEXT: 1000 +// ICTEXT: 200 // ICTEXT: 1 // ICTEXT: # Num Value Kinds: // ICTEXT: 2 @@ -89,41 +93,98 @@ // ICTEXT: # NumValueSites: // ICTEXT: 2 // ICTEXT: 2 -// ICTEXT: {{.*}}instrprof-vtable-value-prof.cpp;_ZN12_GLOBAL__N_18Derived25func1Eii:750 -// ICTEXT: _ZN8Derived15func1Eii:250 +// ICTEXT: {{.*}}instrprof-vtable-value-prof.cpp;_ZN12_GLOBAL__N_18Derived24funcEii:150 +// ICTEXT: _ZN8Derived14funcEii:50 // ICTEXT: 2 -// ICTEXT: {{.*}}instrprof-vtable-value-prof.cpp;_ZN12_GLOBAL__N_18Derived25func2Eii:750 -// ICTEXT: _ZN8Derived15func2Eii:250 +// ICTEXT: {{.*}}instrprof-vtable-value-prof.cpp;_ZN12_GLOBAL__N_18Derived2D0Ev:750 +// ICTEXT: _ZN8Derived1D0Ev:250 // ICTEXT: # ValueKind = IPVK_VTableTarget: // ICTEXT: 2 // ICTEXT: # NumValueSites: // ICTEXT: 2 // ICTEXT: 2 -// ICTEXT: {{.*}}instrprof-vtable-value-prof.cpp;_ZTVN12_GLOBAL__N_18Derived2E:750 -// ICTEXT: _ZTV8Derived1:250 +// ICTEXT: {{.*}}instrprof-vtable-value-prof.cpp;_ZTVN12_GLOBAL__N_18Derived2E:150 +// ICTEXT: _ZTV8Derived1:50 // ICTEXT: 2 // ICTEXT: {{.*}}instrprof-vtable-value-prof.cpp;_ZTVN12_GLOBAL__N_18Derived2E:750 // ICTEXT: _ZTV8Derived1:250 +// Test indirect call promotion transformation using vtable profiles. +// - Build with `-g` to enable debug information. +// - In real world settings, ICP pass is disabled in prelink pipeline. In +// the postlink pipeline, ICP is enabled after whole-program-devirtualization +// pass. Do the same thing in this test. +// - Enable `-fwhole-program-vtables` generate type metadata and intrinsics. +// - Enable `-fno-split-lto-unit` and `-Wl,-lto-whole-program-visibility` to +// preserve type intrinsics for ICP pass. +// RUN: %clangxx -m64 -fprofile-use=test.profdata -Wl,--lto-whole-program-visibility \ +// RUN: -mllvm -disable-icp=true -Wl,-mllvm,-disable-icp=false -fuse-ld=lld \ +// RUN: -g -flto=thin -fwhole-program-vtables -fno-split-lto-unit -O2 \ +// RUN: -mllvm -enable-vtable-value-profiling -Wl,-mllvm,-enable-vtable-value-profiling \ +// RUN: -mllvm -enable-vtable-profile-use \ +// RUN: -Wl,-mllvm,-enable-vtable-profile-use -Rpass=pgo-icall-prom \ +// RUN: -Wl,-mllvm,-print-after=pgo-icall-prom \ +// RUN: -Wl,-mllvm,-filter-print-funcs=main %s 2>&1 \ +// RUN: | FileCheck %s --check-prefixes=REMARK,IR --implicit-check-not="!VP" + +// For the indirect call site `ptr->func` +// REMARK: instrprof-vtable-value-prof.cpp:205:19: Promote indirect call to _ZN12_GLOBAL__N_18Derived24funcEii with count 150 out of 200, sink 1 instruction(s) and compare 1 vtable(s): {_ZTVN12_GLOBAL__N_18Derived2E} +// REMARK: instrprof-vtable-value-prof.cpp:205:19: Promote indirect call to _ZN8Derived14funcEii with count 50 out of 50, sink 1 instruction(s) and compare 1 vtable(s): {_ZTV8Derived1} +// +// For the indirect call site `delete ptr` +// REMARK: instrprof-vtable-value-prof.cpp:207:5: Promote indirect call to _ZN12_GLOBAL__N_18Derived2D0Ev with count 750 out of 1000, sink 2 instruction(s) and compare 1 vtable(s): {_ZTVN12_GLOBAL__N_18Derived2E} +// REMARK: instrprof-vtable-value-prof.cpp:207:5: Promote indirect call to _ZN8Derived1D0Ev with count 250 out of 250, sink 2 instruction(s) and compare 1 vtable(s): {_ZTV8Derived1} + +// The IR matchers for indirect callsite `ptr->func`. +// IR-LABEL: @main +// IR: [[OBJ:%.*]] = {{.*}}call {{.*}} @_Z10createTypei +// IR: [[VTABLE:%.*]] = load ptr, ptr [[OBJ]] +// IR: [[CMP1:%.*]] = icmp eq ptr [[VTABLE]], getelementptr inbounds (i8, ptr @_ZTVN12_GLOBAL__N_18Derived2E, i32 16) +// IR: br i1 [[CMP1]], label %[[BB1:.*]], label %[[BB2:[a-zA-Z0-9_.]+]], +// +// IR: [[BB1]]: +// IR: [[RESBB1:%.*]] = {{.*}}call {{.*}} @_ZN12_GLOBAL__N_18Derived24funcEii +// IR: br label %[[MERGE0:[a-zA-Z0-9_.]+]] +// +// IR: [[BB2]]: +// IR: [[CMP2:%.*]] = icmp eq ptr [[VTABLE]], getelementptr inbounds (i8, ptr @_ZTV8Derived1, i32 16) +// IR: br i1 [[CMP2]], label %[[BB3:.*]], label %[[BB4:[a-zA-Z0-9_.]+]], +// +// IR: [[BB3]]: +// IR: [[RESBB3:%.*]] = {{.*}}call {{.*}} @_ZN8Derived14funcEii +// IR: br label %[[MERGE1:[a-zA-Z0-9_.]+]], +// +// IR: [[BB4]]: +// IR: [[FUNCPTR:%.*]] = load ptr, ptr [[VTABLE]] +// IR: [[RESBB4:%.*]] = {{.*}}call {{.*}} [[FUNCPTR]] +// IR: br label %[[MERGE1]] +// +// IR: [[MERGE1]]: +// IR: [[RES1:%.*]] = phi i32 [ [[RESBB4]], %[[BB4]] ], [ [[RESBB3]], %[[BB3]] ] +// IR: br label %[[MERGE0]] +// +// IR: [[MERGE0]]: +// IR: [[RES2:%.*]] = phi i32 [ [[RES1]], %[[MERGE1]] ], [ [[RESBB1]], %[[BB1]] ] #include #include class Base { public: - virtual int func1(int a, int b) = 0; - virtual int func2(int a, int b) = 0; + virtual int func(int a, int b) = 0; + + virtual ~Base() {}; }; class Derived1 : public Base { public: - int func1(int a, int b) override { return a + b; } + int func(int a, int b) override { return a * b; } - int func2(int a, int b) override { return a * b; } + ~Derived1() {} }; namespace { class Derived2 : public Base { public: - int func1(int a, int b) override { return a - b; } + int func(int a, int b) override { return a * (a - b); } - int func2(int a, int b) override { return a * (a - b); } + ~Derived2() {} }; } // namespace __attribute__((noinline)) Base *createType(int a) { @@ -140,7 +201,10 @@ int main(int argc, char **argv) { int a = rand(); int b = rand(); Base *ptr = createType(i); - sum += ptr->func1(a, b) + ptr->func2(b, a); + if (i % 5 == 0) + sum += ptr->func(b, a); + + delete ptr; } printf("sum is %d\n", sum); return 0; diff --git a/compiler-rt/test/sanitizer_common/TestCases/Posix/fork_threaded.c b/compiler-rt/test/sanitizer_common/TestCases/Posix/fork_threaded.c index 13240234a1c79b..27b67db0c0a38c 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/Posix/fork_threaded.c +++ b/compiler-rt/test/sanitizer_common/TestCases/Posix/fork_threaded.c @@ -6,9 +6,6 @@ // FIXME: It probably hangs on this platform. // UNSUPPORTED: ppc -// FIXME: TSAN does not lock allocator. -// UNSUPPORTED: tsan - // FIXME: False stack overflow report // UNSUPPORTED: android && asan diff --git a/compiler-rt/test/tsan/Linux/fork_deadlock.cpp b/compiler-rt/test/tsan/Darwin/fork_deadlock.cpp similarity index 96% rename from compiler-rt/test/tsan/Linux/fork_deadlock.cpp rename to compiler-rt/test/tsan/Darwin/fork_deadlock.cpp index 952507032df65d..2a5b81cae24490 100644 --- a/compiler-rt/test/tsan/Linux/fork_deadlock.cpp +++ b/compiler-rt/test/tsan/Darwin/fork_deadlock.cpp @@ -1,3 +1,6 @@ +// TODO(#96597): fix and reenable +// UNSUPPORTED: darwin + // RUN: %clangxx_tsan -O1 %s -o %t && %env_tsan_opts=atexit_sleep_ms=0 %run %t 2>&1 | FileCheck %s // This test models what happens on Mac when fork diff --git a/flang/docs/Intrinsics.md b/flang/docs/Intrinsics.md index 8853d4d9e1c79c..d1f7cd8372e243 100644 --- a/flang/docs/Intrinsics.md +++ b/flang/docs/Intrinsics.md @@ -893,16 +893,17 @@ used in constant expressions have currently no folding support at all. ##### `CMDSTAT`: - Synchronous execution: - - -2: No error condition occurs, but `WAIT` is present with the value `false`, and the processor does not support asynchronous execution. - - -1: The processor does not support command line execution. + - -2: `ASYNC_NO_SUPPORT_ERR` - No error condition occurs, but `WAIT` is present with the value `false`, and the processor does not support asynchronous execution. + - -1: `NO_SUPPORT_ERR` - The processor does not support command line execution. (system returns -1 with errno `ENOENT`) + - 0: `CMD_EXECUTED` - Command executed with no error. - \+ (positive value): An error condition occurs. - - 1: Fork Error (occurs only on POSIX-compatible systems). - - 2: Execution Error (command exits with status -1). - - 3: Invalid Command Error (determined by the exit code depending on the system). - - On Windows: exit code is 1. - - On POSIX-compatible systems: exit code is 127 or 126. - - 4: Signal error (either stopped or killed by signal, occurs only on POSIX-compatible systems). - - 0: Otherwise. + - 1: `FORK_ERR` - Fork Error (occurs only on POSIX-compatible systems). + - 2: `EXECL_ERR` - Execution Error (system returns -1 with other errno). + - 3: `COMMAND_EXECUTION_ERR` - Invalid Command Error (exit code 1). + - 4: `COMMAND_CANNOT_EXECUTE_ERR` - Command Cannot Execute Error (Linux exit code 126). + - 5: `COMMAND_NOT_FOUND_ERR` - Command Not Found Error (Linux exit code 127). + - 6: `INVALID_CL_ERR` - Invalid Command Line Error (covers all other non-zero exit codes). + - 7: `SIGNAL_ERR` - Signal error (either stopped or killed by signal, occurs only on POSIX-compatible systems). - Asynchronous execution: - 0 will always be assigned. diff --git a/flang/include/flang/Evaluate/characteristics.h b/flang/include/flang/Evaluate/characteristics.h index 9695c665d0cb5d..11533a7259b055 100644 --- a/flang/include/flang/Evaluate/characteristics.h +++ b/flang/include/flang/Evaluate/characteristics.h @@ -55,8 +55,8 @@ std::optional DistinguishableOpOrAssign( // Shapes of function results and dummy arguments have to have // the same rank, the same deferred dimensions, and the same // values for explicit dimensions when constant. -bool ShapesAreCompatible( - const Shape &, const Shape &, bool *possibleWarning = nullptr); +bool ShapesAreCompatible(const std::optional &, + const std::optional &, bool *possibleWarning = nullptr); class TypeAndShape { public: @@ -64,17 +64,17 @@ class TypeAndShape { Attr, AssumedRank, AssumedShape, AssumedSize, DeferredShape, Coarray) using Attrs = common::EnumSet; - explicit TypeAndShape(DynamicType t) : type_{t} { AcquireLEN(); } - TypeAndShape(DynamicType t, int rank) : type_{t}, shape_(rank) { + explicit TypeAndShape(DynamicType t) : type_{t}, shape_{Shape{}} { + AcquireLEN(); + } + TypeAndShape(DynamicType t, int rank) : type_{t}, shape_{Shape(rank)} { AcquireLEN(); } TypeAndShape(DynamicType t, Shape &&s) : type_{t}, shape_{std::move(s)} { AcquireLEN(); } TypeAndShape(DynamicType t, std::optional &&s) : type_{t} { - if (s) { - shape_ = std::move(*s); - } + shape_ = std::move(s); AcquireLEN(); } DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(TypeAndShape) @@ -172,11 +172,12 @@ class TypeAndShape { LEN_ = std::move(len); return *this; } - const Shape &shape() const { return shape_; } + const std::optional &shape() const { return shape_; } const Attrs &attrs() const { return attrs_; } int corank() const { return corank_; } - int Rank() const { return GetRank(shape_); } + // Return -1 for assumed-rank as a safety. + int Rank() const { return shape_ ? GetRank(*shape_) : -1; } // Can sequence association apply to this argument? bool CanBeSequenceAssociated() const { @@ -211,7 +212,7 @@ class TypeAndShape { protected: DynamicType type_; std::optional> LEN_; - Shape shape_; + std::optional shape_; Attrs attrs_; int corank_{0}; }; diff --git a/flang/include/flang/Evaluate/shape.h b/flang/include/flang/Evaluate/shape.h index 1294c92a01abb6..e33044c0d34e56 100644 --- a/flang/include/flang/Evaluate/shape.h +++ b/flang/include/flang/Evaluate/shape.h @@ -46,6 +46,13 @@ Constant AsConstantShape(const ConstantSubscripts &); ConstantSubscripts AsConstantExtents(const Constant &); std::optional AsConstantExtents( FoldingContext &, const Shape &); +inline std::optional AsConstantExtents( + FoldingContext &foldingContext, const std::optional &maybeShape) { + if (maybeShape) { + return AsConstantExtents(foldingContext, *maybeShape); + } + return std::nullopt; +} Shape AsShape(const ConstantSubscripts &); std::optional AsShape(const std::optional &); @@ -121,6 +128,12 @@ MaybeExtentExpr CountTrips( // Computes SIZE() == PRODUCT(shape) MaybeExtentExpr GetSize(Shape &&); ConstantSubscript GetSize(const ConstantSubscripts &); +inline MaybeExtentExpr GetSize(const std::optional &maybeShape) { + if (maybeShape) { + return GetSize(Shape(*maybeShape)); + } + return std::nullopt; +} // Utility predicate: does an expression reference any implied DO index? bool ContainsAnyImpliedDoIndex(const ExtentExpr &); diff --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h index 340325b59c0abb..625f9e5f6576fc 100644 --- a/flang/include/flang/Evaluate/tools.h +++ b/flang/include/flang/Evaluate/tools.h @@ -98,6 +98,9 @@ template bool IsAssumedRank(const Expr &expr) { template bool IsAssumedRank(const std::optional &x) { return x && IsAssumedRank(*x); } +template bool IsAssumedRank(const A *x) { + return x && IsAssumedRank(*x); +} // Predicate: true when an expression is a coarray (corank > 0) bool IsCoarray(const ActualArgument &); diff --git a/flang/include/flang/Lower/AbstractConverter.h b/flang/include/flang/Lower/AbstractConverter.h index f43dfd8343ece5..daded9091780e2 100644 --- a/flang/include/flang/Lower/AbstractConverter.h +++ b/flang/include/flang/Lower/AbstractConverter.h @@ -17,6 +17,7 @@ #include "flang/Lower/LoweringOptions.h" #include "flang/Lower/PFTDefs.h" #include "flang/Optimizer/Builder/BoxValue.h" +#include "flang/Optimizer/Dialect/FIRAttr.h" #include "flang/Semantics/symbol.h" #include "mlir/IR/Builders.h" #include "mlir/IR/BuiltinOps.h" @@ -126,8 +127,8 @@ class AbstractConverter { const Fortran::semantics::Symbol &sym, mlir::OpBuilder::InsertPoint *copyAssignIP = nullptr) = 0; - virtual void copyVar(mlir::Location loc, mlir::Value dst, - mlir::Value src) = 0; + virtual void copyVar(mlir::Location loc, mlir::Value dst, mlir::Value src, + fir::FortranVariableFlagsEnum attrs) = 0; /// For a given symbol, check if it is present in the inner-most /// level of the symbol map. diff --git a/flang/include/flang/Lower/BoxAnalyzer.h b/flang/include/flang/Lower/BoxAnalyzer.h index 3b8e2455ff273b..8eca7d66a71bf3 100644 --- a/flang/include/flang/Lower/BoxAnalyzer.h +++ b/flang/include/flang/Lower/BoxAnalyzer.h @@ -97,7 +97,7 @@ struct ScalarDynamicDerived : ScalarSym { : ScalarSym{sym}, lens{std::move(lens)} {} private: - llvm::SmallVector lens; + llvm::SmallVector lens; }; struct LBoundsAndShape { diff --git a/flang/include/flang/Optimizer/Transforms/Passes.h b/flang/include/flang/Optimizer/Transforms/Passes.h index 1ca1539e76fc63..df709645c01b0b 100644 --- a/flang/include/flang/Optimizer/Transforms/Passes.h +++ b/flang/include/flang/Optimizer/Transforms/Passes.h @@ -57,6 +57,8 @@ namespace fir { #define GEN_PASS_DECL_OMPFUNCTIONFILTERING #define GEN_PASS_DECL_VSCALEATTR #define GEN_PASS_DECL_FUNCTIONATTR +#define GEN_PASS_DECL_CONSTANTARGUMENTGLOBALISATIONOPT + #include "flang/Optimizer/Transforms/Passes.h.inc" std::unique_ptr createAffineDemotionPass(); diff --git a/flang/include/flang/Optimizer/Transforms/Passes.td b/flang/include/flang/Optimizer/Transforms/Passes.td index 27aee5650e75d5..b3ed9acad36df4 100644 --- a/flang/include/flang/Optimizer/Transforms/Passes.td +++ b/flang/include/flang/Optimizer/Transforms/Passes.td @@ -251,6 +251,15 @@ def MemoryAllocationOpt : Pass<"memory-allocation-opt", "mlir::func::FuncOp"> { ]; } +// This needs to be a "mlir::ModuleOp" pass, because it inserts global constants +def ConstantArgumentGlobalisationOpt : Pass<"constant-argument-globalisation-opt", "mlir::ModuleOp"> { + let summary = "Convert constant function arguments to global constants."; + let description = [{ + Convert scalar literals of function arguments to global constants. + }]; + let dependentDialects = [ "fir::FIROpsDialect" ]; +} + def StackArrays : Pass<"stack-arrays", "mlir::ModuleOp"> { let summary = "Move local array allocations from heap memory into stack memory"; let description = [{ diff --git a/flang/include/flang/Parser/preprocessor.h b/flang/include/flang/Parser/preprocessor.h index c3076435be5f0b..57690dd226f628 100644 --- a/flang/include/flang/Parser/preprocessor.h +++ b/flang/include/flang/Parser/preprocessor.h @@ -82,6 +82,7 @@ class Preprocessor { bool IsNameDefined(const CharBlock &); bool IsFunctionLikeDefinition(const CharBlock &); bool AnyDefinitions() const { return !definitions_.empty(); } + bool InConditional() const { return !ifStack_.empty(); } // When called with partialFunctionLikeMacro not null, MacroReplacement() // and ReplaceMacros() handle an unclosed function-like macro reference diff --git a/flang/include/flang/Runtime/pointer.h b/flang/include/flang/Runtime/pointer.h index 6ceb70ebb676d0..704144f08114f2 100644 --- a/flang/include/flang/Runtime/pointer.h +++ b/flang/include/flang/Runtime/pointer.h @@ -115,6 +115,11 @@ bool RTDECL(PointerIsAssociated)(const Descriptor &); bool RTDECL(PointerIsAssociatedWith)( const Descriptor &, const Descriptor *target); +// Fortran POINTERs are allocated with an extra validation word after their +// payloads in order to detect erroneous deallocations later. +RT_API_ATTRS void *AllocateValidatedPointerPayload(std::size_t); +RT_API_ATTRS bool ValidatePointerPayload(const ISO::CFI_cdesc_t &); + } // extern "C" } // namespace Fortran::runtime #endif // FORTRAN_RUNTIME_POINTER_H_ diff --git a/flang/include/flang/Tools/CLOptions.inc b/flang/include/flang/Tools/CLOptions.inc index bb4347d0e82c8f..7f2910c5cfd3c3 100644 --- a/flang/include/flang/Tools/CLOptions.inc +++ b/flang/include/flang/Tools/CLOptions.inc @@ -25,6 +25,10 @@ static llvm::cl::opt disable##DOName("disable-" DOOption, \ llvm::cl::desc("disable " DODescription " pass"), llvm::cl::init(false), \ llvm::cl::Hidden) +#define EnableOption(EOName, EOOption, EODescription) \ + static llvm::cl::opt enable##EOName("enable-" EOOption, \ + llvm::cl::desc("enable " EODescription " pass"), llvm::cl::init(false), \ + llvm::cl::Hidden) /// Shared option in tools to control whether dynamically sized array /// allocations should always be on the heap. @@ -86,6 +90,8 @@ DisableOption(BoxedProcedureRewrite, "boxed-procedure-rewrite", DisableOption(ExternalNameConversion, "external-name-interop", "convert names with external convention"); +EnableOption(ConstantArgumentGlobalisation, "constant-argument-globalisation", + "the local constant argument to global constant conversion"); using PassConstructor = std::unique_ptr(); @@ -270,6 +276,8 @@ inline void createDefaultFIROptimizerPassPipeline( // These passes may increase code size. pm.addPass(fir::createSimplifyIntrinsics()); pm.addPass(fir::createAlgebraicSimplificationPass(config)); + if (enableConstantArgumentGlobalisation) + pm.addPass(fir::createConstantArgumentGlobalisationOpt()); } if (pc.LoopVersioning) diff --git a/flang/lib/Evaluate/characteristics.cpp b/flang/lib/Evaluate/characteristics.cpp index a0ce190b90e926..70e24d6e82eb8e 100644 --- a/flang/lib/Evaluate/characteristics.cpp +++ b/flang/lib/Evaluate/characteristics.cpp @@ -39,13 +39,16 @@ static void CopyAttrs(const semantics::Symbol &src, A &dst, // Shapes of function results and dummy arguments have to have // the same rank, the same deferred dimensions, and the same // values for explicit dimensions when constant. -bool ShapesAreCompatible( - const Shape &x, const Shape &y, bool *possibleWarning) { - if (x.size() != y.size()) { +bool ShapesAreCompatible(const std::optional &x, + const std::optional &y, bool *possibleWarning) { + if (!x || !y) { + return !x && !y; + } + if (x->size() != y->size()) { return false; } - auto yIter{y.begin()}; - for (const auto &xDim : x) { + auto yIter{y->begin()}; + for (const auto &xDim : *x) { const auto &yDim{*yIter++}; if (xDim && yDim) { if (auto equiv{AreEquivalentInInterface(*xDim, *yDim)}) { @@ -178,9 +181,11 @@ bool TypeAndShape::IsCompatibleWith(parser::ContextualMessages &messages, thatIs, that.AsFortran(), thisIs, AsFortran()); return false; } - return omitShapeConformanceCheck || - CheckConformance(messages, shape_, that.shape_, flags, thisIs, thatIs) - .value_or(true /*fail only when nonconformance is known now*/); + return omitShapeConformanceCheck || (!shape_ && !that.shape_) || + (shape_ && that.shape_ && + CheckConformance( + messages, *shape_, *that.shape_, flags, thisIs, thatIs) + .value_or(true /*fail only when nonconformance is known now*/)); } std::optional> TypeAndShape::MeasureElementSizeInBytes( @@ -201,11 +206,11 @@ std::optional> TypeAndShape::MeasureElementSizeInBytes( std::optional> TypeAndShape::MeasureSizeInBytes( FoldingContext &foldingContext) const { - if (auto elements{GetSize(Shape{shape_})}) { + if (auto elements{GetSize(shape_)}) { // Sizes of arrays (even with single elements) are multiples of // their alignments. if (auto elementBytes{ - MeasureElementSizeInBytes(foldingContext, GetRank(shape_) > 0)}) { + MeasureElementSizeInBytes(foldingContext, Rank() > 0)}) { return Fold( foldingContext, std::move(*elements) * std::move(*elementBytes)); } @@ -254,10 +259,12 @@ std::string TypeAndShape::AsFortran() const { llvm::raw_ostream &TypeAndShape::Dump(llvm::raw_ostream &o) const { o << type_.AsFortran(LEN_ ? LEN_->AsFortran() : ""); attrs_.Dump(o, EnumToString); - if (!shape_.empty()) { + if (!shape_) { + o << " dimension(..)"; + } else if (!shape_->empty()) { o << " dimension"; char sep{'('}; - for (const auto &expr : shape_) { + for (const auto &expr : *shape_) { o << sep; sep = ','; if (expr) { @@ -1112,6 +1119,7 @@ bool FunctionResult::CanBeReturnedViaImplicitInterface( static std::optional AreIncompatibleFunctionResultShapes( const Shape &x, const Shape &y) { + // Function results cannot be assumed-rank, hence the non optional arguments. int rank{GetRank(x)}; if (int yrank{GetRank(y)}; yrank != rank) { return "rank "s + std::to_string(rank) + " vs " + std::to_string(yrank); @@ -1147,7 +1155,8 @@ bool FunctionResult::IsCompatibleWith( } } else if (!attrs.test(Attr::Allocatable) && !attrs.test(Attr::Pointer) && (details = AreIncompatibleFunctionResultShapes( - ifaceTypeShape->shape(), actualTypeShape->shape()))) { + ifaceTypeShape->shape().value(), + actualTypeShape->shape().value()))) { if (whyNot) { *whyNot = "function results have distinct extents (" + *details + ')'; } diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp index a4b152c60a72fc..342aac4dd5d53e 100644 --- a/flang/lib/Evaluate/check-expression.cpp +++ b/flang/lib/Evaluate/check-expression.cpp @@ -419,7 +419,7 @@ std::optional> NonPointerInitializationExpr(const Symbol &symbol, if (converted) { auto folded{Fold(context, std::move(*converted))}; if (IsActuallyConstant(folded)) { - int symRank{GetRank(symTS->shape())}; + int symRank{symTS->Rank()}; if (IsImpliedShape(symbol)) { if (folded.Rank() == symRank) { return ArrayConstantBoundChanger{ @@ -442,7 +442,8 @@ std::optional> NonPointerInitializationExpr(const Symbol &symbol, context, GetRawLowerBounds(context, NamedEntity{symbol}))} .Expand(std::move(folded)); } else if (auto resultShape{GetShape(context, folded)}) { - if (CheckConformance(context.messages(), symTS->shape(), + CHECK(symTS->shape()); // Assumed-ranks cannot be initialized. + if (CheckConformance(context.messages(), *symTS->shape(), *resultShape, CheckConformanceFlags::None, "initialized object", "initialization expression") .value_or(false /*fail if not known now to conform*/)) { @@ -649,7 +650,8 @@ class CheckSpecificationExprHelper return std::holds_alternative( dummy.u); })}; - if (iter != procChars->dummyArguments.end()) { + if (iter != procChars->dummyArguments.end() && + ultimate.name().ToString() != "__builtin_c_funloc") { return "reference to function '"s + ultimate.name().ToString() + "' with dummy procedure argument '" + iter->name + '\''; } diff --git a/flang/lib/Evaluate/fold-integer.cpp b/flang/lib/Evaluate/fold-integer.cpp index b76b9d49b58238..981cdff7f350b1 100644 --- a/flang/lib/Evaluate/fold-integer.cpp +++ b/flang/lib/Evaluate/fold-integer.cpp @@ -1116,14 +1116,25 @@ Expr> FoldIntrinsicFunction( return FoldMaxvalMinval( context, std::move(funcRef), RelationalOperator::LT, T::Scalar::HUGE()); } else if (name == "mod") { + bool badPConst{false}; + if (auto *pExpr{UnwrapExpr>(args[1])}) { + *pExpr = Fold(context, std::move(*pExpr)); + if (auto pConst{GetScalarConstantValue(*pExpr)}; pConst && + pConst->IsZero() && + context.languageFeatures().ShouldWarn( + common::UsageWarning::FoldingAvoidsRuntimeCrash)) { + context.messages().Say("MOD: P argument is zero"_warn_en_US); + badPConst = true; + } + } return FoldElementalIntrinsic(context, std::move(funcRef), ScalarFuncWithContext( - [](FoldingContext &context, const Scalar &x, + [badPConst](FoldingContext &context, const Scalar &x, const Scalar &y) -> Scalar { auto quotRem{x.DivideSigned(y)}; if (context.languageFeatures().ShouldWarn( common::UsageWarning::FoldingAvoidsRuntimeCrash)) { - if (quotRem.divisionByZero) { + if (!badPConst && quotRem.divisionByZero) { context.messages().Say("mod() by zero"_warn_en_US); } else if (quotRem.overflow) { context.messages().Say("mod() folding overflowed"_warn_en_US); @@ -1132,12 +1143,23 @@ Expr> FoldIntrinsicFunction( return quotRem.remainder; })); } else if (name == "modulo") { + bool badPConst{false}; + if (auto *pExpr{UnwrapExpr>(args[1])}) { + *pExpr = Fold(context, std::move(*pExpr)); + if (auto pConst{GetScalarConstantValue(*pExpr)}; pConst && + pConst->IsZero() && + context.languageFeatures().ShouldWarn( + common::UsageWarning::FoldingAvoidsRuntimeCrash)) { + context.messages().Say("MODULO: P argument is zero"_warn_en_US); + badPConst = true; + } + } return FoldElementalIntrinsic(context, std::move(funcRef), - ScalarFuncWithContext([](FoldingContext &context, + ScalarFuncWithContext([badPConst](FoldingContext &context, const Scalar &x, const Scalar &y) -> Scalar { auto result{x.MODULO(y)}; - if (result.overflow && + if (!badPConst && result.overflow && context.languageFeatures().ShouldWarn( common::UsageWarning::FoldingException)) { context.messages().Say("modulo() folding overflowed"_warn_en_US); diff --git a/flang/lib/Evaluate/fold-real.cpp b/flang/lib/Evaluate/fold-real.cpp index f71addcc4094ac..69c7a924cc1c35 100644 --- a/flang/lib/Evaluate/fold-real.cpp +++ b/flang/lib/Evaluate/fold-real.cpp @@ -303,41 +303,72 @@ Expr> FoldIntrinsicFunction( context, std::move(funcRef), RelationalOperator::LT, T::Scalar::HUGE()); } else if (name == "mod") { CHECK(args.size() == 2); + bool badPConst{false}; + if (auto *pExpr{UnwrapExpr>(args[1])}) { + *pExpr = Fold(context, std::move(*pExpr)); + if (auto pConst{GetScalarConstantValue(*pExpr)}; pConst && + pConst->IsZero() && + context.languageFeatures().ShouldWarn( + common::UsageWarning::FoldingAvoidsRuntimeCrash)) { + context.messages().Say("MOD: P argument is zero"_warn_en_US); + badPConst = true; + } + } return FoldElementalIntrinsic(context, std::move(funcRef), - ScalarFunc( - [&context](const Scalar &x, const Scalar &y) -> Scalar { - auto result{x.MOD(y)}; - if (result.flags.test(RealFlag::DivideByZero) && - context.languageFeatures().ShouldWarn( - common::UsageWarning::FoldingAvoidsRuntimeCrash)) { - context.messages().Say( - "second argument to MOD must not be zero"_warn_en_US); - } - return result.value; - })); + ScalarFunc([&context, badPConst](const Scalar &x, + const Scalar &y) -> Scalar { + auto result{x.MOD(y)}; + if (!badPConst && result.flags.test(RealFlag::DivideByZero) && + context.languageFeatures().ShouldWarn( + common::UsageWarning::FoldingAvoidsRuntimeCrash)) { + context.messages().Say( + "second argument to MOD must not be zero"_warn_en_US); + } + return result.value; + })); } else if (name == "modulo") { CHECK(args.size() == 2); + bool badPConst{false}; + if (auto *pExpr{UnwrapExpr>(args[1])}) { + *pExpr = Fold(context, std::move(*pExpr)); + if (auto pConst{GetScalarConstantValue(*pExpr)}; pConst && + pConst->IsZero() && + context.languageFeatures().ShouldWarn( + common::UsageWarning::FoldingAvoidsRuntimeCrash)) { + context.messages().Say("MODULO: P argument is zero"_warn_en_US); + badPConst = true; + } + } return FoldElementalIntrinsic(context, std::move(funcRef), - ScalarFunc( - [&context](const Scalar &x, const Scalar &y) -> Scalar { - auto result{x.MODULO(y)}; - if (result.flags.test(RealFlag::DivideByZero) && - context.languageFeatures().ShouldWarn( - common::UsageWarning::FoldingAvoidsRuntimeCrash)) { - context.messages().Say( - "second argument to MODULO must not be zero"_warn_en_US); - } - return result.value; - })); + ScalarFunc([&context, badPConst](const Scalar &x, + const Scalar &y) -> Scalar { + auto result{x.MODULO(y)}; + if (!badPConst && result.flags.test(RealFlag::DivideByZero) && + context.languageFeatures().ShouldWarn( + common::UsageWarning::FoldingAvoidsRuntimeCrash)) { + context.messages().Say( + "second argument to MODULO must not be zero"_warn_en_US); + } + return result.value; + })); } else if (name == "nearest") { - if (const auto *sExpr{UnwrapExpr>(args[1])}) { + if (auto *sExpr{UnwrapExpr>(args[1])}) { + *sExpr = Fold(context, std::move(*sExpr)); return common::visit( [&](const auto &sVal) { using TS = ResultType; + bool badSConst{false}; + if (auto sConst{GetScalarConstantValue(sVal)}; sConst && + sConst->IsZero() && + context.languageFeatures().ShouldWarn( + common::UsageWarning::FoldingValueChecks)) { + context.messages().Say("NEAREST: S argument is zero"_warn_en_US); + badSConst = true; + } return FoldElementalIntrinsic(context, std::move(funcRef), ScalarFunc([&](const Scalar &x, const Scalar &s) -> Scalar { - if (s.IsZero() && + if (!badSConst && s.IsZero() && context.languageFeatures().ShouldWarn( common::UsageWarning::FoldingValueChecks)) { context.messages().Say( diff --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp index 2733f994576a45..80752d02b5baf4 100644 --- a/flang/lib/Evaluate/intrinsics.cpp +++ b/flang/lib/Evaluate/intrinsics.cpp @@ -1113,6 +1113,7 @@ static const SpecificIntrinsicInterface specificIntrinsicFunction[]{ {{"ddim", {{"x", DoublePrecision}, {"y", DoublePrecision}}, DoublePrecision}, "dim"}, + {{"derf", {{"x", DoublePrecision}}, DoublePrecision}, "erf"}, {{"dexp", {{"x", DoublePrecision}}, DoublePrecision}, "exp"}, {{"dfloat", {{"a", AnyInt}}, DoublePrecision}, "real", true}, {{"dim", {{"x", DefaultReal}, {"y", DefaultReal}}, DefaultReal}}, diff --git a/flang/lib/Evaluate/shape.cpp b/flang/lib/Evaluate/shape.cpp index 5cf48b240eca62..c62d0cb0ff29dd 100644 --- a/flang/lib/Evaluate/shape.cpp +++ b/flang/lib/Evaluate/shape.cpp @@ -1037,7 +1037,7 @@ auto GetShapeHelper::operator()(const ProcedureRef &call) const -> Result { } else if (context_) { if (auto moldTypeAndShape{characteristics::TypeAndShape::Characterize( call.arguments().at(1), *context_)}) { - if (GetRank(moldTypeAndShape->shape()) == 0) { + if (moldTypeAndShape->Rank() == 0) { // SIZE= is absent and MOLD= is scalar: result is scalar return ScalarShape(); } else { diff --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp index b2a50ab9b6b833..a5f4faa0cef8fc 100644 --- a/flang/lib/Evaluate/tools.cpp +++ b/flang/lib/Evaluate/tools.cpp @@ -82,6 +82,8 @@ auto IsVariableHelper::operator()(const Symbol &symbol) const -> Result { const Symbol &ultimate{symbol.GetUltimate()}; return !IsNamedConstant(ultimate) && (ultimate.has() || + (ultimate.has() && + ultimate.attrs().test(semantics::Attr::TARGET)) || ultimate.has()); } auto IsVariableHelper::operator()(const Component &x) const -> Result { diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index 404d1f6d39446b..50f58843ec70bd 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -757,10 +757,16 @@ class FirConverter : public Fortran::lower::AbstractConverter { }); } - void copyVar(mlir::Location loc, mlir::Value dst, - mlir::Value src) override final { + void copyVar(mlir::Location loc, mlir::Value dst, mlir::Value src, + fir::FortranVariableFlagsEnum attrs) override final { + bool isAllocatable = + bitEnumContainsAny(attrs, fir::FortranVariableFlagsEnum::allocatable); + bool isPointer = + bitEnumContainsAny(attrs, fir::FortranVariableFlagsEnum::pointer); + copyVarHLFIR(loc, Fortran::lower::SymbolBox::Intrinsic{dst}, - Fortran::lower::SymbolBox::Intrinsic{src}); + Fortran::lower::SymbolBox::Intrinsic{src}, isAllocatable, + isPointer); } void copyHostAssociateVar( @@ -1089,6 +1095,28 @@ class FirConverter : public Fortran::lower::AbstractConverter { void copyVarHLFIR(mlir::Location loc, Fortran::lower::SymbolBox dst, Fortran::lower::SymbolBox src) { assert(lowerToHighLevelFIR()); + + bool isBoxAllocatable = dst.match( + [](const fir::MutableBoxValue &box) { return box.isAllocatable(); }, + [](const fir::FortranVariableOpInterface &box) { + return fir::FortranVariableOpInterface(box).isAllocatable(); + }, + [](const auto &box) { return false; }); + + bool isBoxPointer = dst.match( + [](const fir::MutableBoxValue &box) { return box.isPointer(); }, + [](const fir::FortranVariableOpInterface &box) { + return fir::FortranVariableOpInterface(box).isPointer(); + }, + [](const auto &box) { return false; }); + + copyVarHLFIR(loc, dst, src, isBoxAllocatable, isBoxPointer); + } + + void copyVarHLFIR(mlir::Location loc, Fortran::lower::SymbolBox dst, + Fortran::lower::SymbolBox src, bool isAllocatable, + bool isPointer) { + assert(lowerToHighLevelFIR()); hlfir::Entity lhs{dst.getAddr()}; hlfir::Entity rhs{src.getAddr()}; // Temporary_lhs is set to true in hlfir.assign below to avoid user @@ -1105,21 +1133,7 @@ class FirConverter : public Fortran::lower::AbstractConverter { /*temporary_lhs=*/true); }; - bool isBoxAllocatable = dst.match( - [](const fir::MutableBoxValue &box) { return box.isAllocatable(); }, - [](const fir::FortranVariableOpInterface &box) { - return fir::FortranVariableOpInterface(box).isAllocatable(); - }, - [](const auto &box) { return false; }); - - bool isBoxPointer = dst.match( - [](const fir::MutableBoxValue &box) { return box.isPointer(); }, - [](const fir::FortranVariableOpInterface &box) { - return fir::FortranVariableOpInterface(box).isPointer(); - }, - [](const auto &box) { return false; }); - - if (isBoxAllocatable) { + if (isAllocatable) { // Deep copy allocatable if it is allocated. // Note that when allocated, the RHS is already allocated with the LHS // shape for copy on entry in createHostAssociateVarClone. @@ -1134,7 +1148,7 @@ class FirConverter : public Fortran::lower::AbstractConverter { copyData(lhs, rhs); }) .end(); - } else if (isBoxPointer) { + } else if (isPointer) { // Set LHS target to the target of RHS (do not copy the RHS // target data into the LHS target storage). auto loadVal = builder->create(loc, rhs); diff --git a/flang/lib/Lower/CallInterface.cpp b/flang/lib/Lower/CallInterface.cpp index 30f985804d2ae7..c0ef96adc20c3e 100644 --- a/flang/lib/Lower/CallInterface.cpp +++ b/flang/lib/Lower/CallInterface.cpp @@ -177,9 +177,10 @@ mlir::Location Fortran::lower::CallerInterface::getCalleeLocation() const { // explicit. static Fortran::evaluate::characteristics::DummyDataObject asImplicitArg(Fortran::evaluate::characteristics::DummyDataObject &&dummy) { - Fortran::evaluate::Shape shape = - dummy.type.attrs().none() ? dummy.type.shape() - : Fortran::evaluate::Shape(dummy.type.Rank()); + std::optional shape = + dummy.type.attrs().none() + ? dummy.type.shape() + : std::make_optional(dummy.type.Rank()); return Fortran::evaluate::characteristics::DummyDataObject( Fortran::evaluate::characteristics::TypeAndShape(dummy.type.type(), std::move(shape))); @@ -1308,18 +1309,17 @@ class Fortran::lower::CallInterfaceImpl { // with the shape (may contain unknown extents) for arrays. std::optional getBounds( const Fortran::evaluate::characteristics::TypeAndShape &typeAndShape) { - using ShapeAttr = Fortran::evaluate::characteristics::TypeAndShape::Attr; - if (typeAndShape.shape().empty() && - !typeAndShape.attrs().test(ShapeAttr::AssumedRank)) + if (typeAndShape.shape() && typeAndShape.shape()->empty()) return std::nullopt; fir::SequenceType::Shape bounds; - for (const std::optional &extent : - typeAndShape.shape()) { - fir::SequenceType::Extent bound = fir::SequenceType::getUnknownExtent(); - if (std::optional i = toInt64(extent)) - bound = *i; - bounds.emplace_back(bound); - } + if (typeAndShape.shape()) + for (const std::optional &extent : + *typeAndShape.shape()) { + fir::SequenceType::Extent bound = fir::SequenceType::getUnknownExtent(); + if (std::optional i = toInt64(extent)) + bound = *i; + bounds.emplace_back(bound); + } return bounds; } std::optional diff --git a/flang/lib/Lower/DirectivesCommon.h b/flang/lib/Lower/DirectivesCommon.h index f0af5f982c14f5..e8d6bb591e3617 100644 --- a/flang/lib/Lower/DirectivesCommon.h +++ b/flang/lib/Lower/DirectivesCommon.h @@ -718,7 +718,6 @@ gatherBoundsOrBoundValues(fir::FirOpBuilder &builder, mlir::Location loc, template llvm::SmallVector genBoundsOpsFromBox(fir::FirOpBuilder &builder, mlir::Location loc, - Fortran::lower::AbstractConverter &converter, fir::ExtendedValue dataExv, Fortran::lower::AddrAndBoundsInfo &info) { llvm::SmallVector bounds; @@ -778,7 +777,6 @@ genBoundsOpsFromBox(fir::FirOpBuilder &builder, mlir::Location loc, template llvm::SmallVector genBaseBoundsOps(fir::FirOpBuilder &builder, mlir::Location loc, - Fortran::lower::AbstractConverter &converter, fir::ExtendedValue dataExv, bool isAssumedSize) { mlir::Type idxTy = builder.getIndexType(); mlir::Type boundTy = builder.getType(); @@ -1163,7 +1161,7 @@ AddrAndBoundsInfo gatherDataOperandAddrAndBounds( info.rawInput = info.addr; if (mlir::isa(fir::unwrapRefType(info.addr.getType()))) bounds = genBaseBoundsOps(builder, operandLocation, - converter, compExv, + compExv, /*isAssumedSize=*/false); asFortran << designator.AsFortran(); @@ -1189,7 +1187,7 @@ AddrAndBoundsInfo gatherDataOperandAddrAndBounds( info.addr = boxAddrOp.getVal(); info.rawInput = info.addr; bounds = genBoundsOpsFromBox( - builder, operandLocation, converter, compExv, info); + builder, operandLocation, compExv, info); } } else { if (detail::getRef(designator)) { @@ -1206,13 +1204,13 @@ AddrAndBoundsInfo gatherDataOperandAddrAndBounds( if (mlir::isa( fir::unwrapRefType(info.addr.getType()))) { bounds = genBoundsOpsFromBox( - builder, operandLocation, converter, dataExv, info); + builder, operandLocation, dataExv, info); } bool dataExvIsAssumedSize = Fortran::semantics::IsAssumedSizeArray(symRef->get().GetUltimate()); if (mlir::isa(fir::unwrapRefType(info.addr.getType()))) bounds = genBaseBoundsOps( - builder, operandLocation, converter, dataExv, dataExvIsAssumedSize); + builder, operandLocation, dataExv, dataExvIsAssumedSize); asFortran << symRef->get().name().ToString(); } else { // Unsupported llvm::report_fatal_error("Unsupported type of OpenACC operand"); diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp index 27eea2b133b3cf..f78cd0f9df1a18 100644 --- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp +++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp @@ -394,6 +394,28 @@ bool ClauseProcessor::processNumThreads( return false; } +bool ClauseProcessor::processOrder(mlir::omp::OrderClauseOps &result) const { + using Order = omp::clause::Order; + if (auto *clause = findUniqueClause()) { + fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); + result.orderAttr = mlir::omp::ClauseOrderKindAttr::get( + firOpBuilder.getContext(), mlir::omp::ClauseOrderKind::Concurrent); + const auto &modifier = + std::get>(clause->t); + if (modifier && *modifier == Order::OrderModifier::Unconstrained) { + result.orderModAttr = mlir::omp::OrderModifierAttr::get( + firOpBuilder.getContext(), mlir::omp::OrderModifier::unconstrained); + } else { + // "If order-modifier is not unconstrained, the behavior is as if the + // reproducible modifier is present." + result.orderModAttr = mlir::omp::OrderModifierAttr::get( + firOpBuilder.getContext(), mlir::omp::OrderModifier::reproducible); + } + return true; + } + return false; +} + bool ClauseProcessor::processOrdered( mlir::omp::OrderedClauseOps &result) const { if (auto *clause = findUniqueClause()) { @@ -729,7 +751,7 @@ createCopyFunc(mlir::Location loc, lower::AbstractConverter &converter, auto declSrc = builder.create( loc, funcOp.getArgument(1), copyFuncName + "_src", shape, typeparams, /*dummy_scope=*/nullptr, attrs); - converter.copyVar(loc, declDst.getBase(), declSrc.getBase()); + converter.copyVar(loc, declDst.getBase(), declSrc.getBase(), varAttrs); builder.create(loc); return funcOp; } @@ -1005,7 +1027,8 @@ bool ClauseProcessor::processReduction( // Copy local lists into the output. llvm::copy(reductionVars, std::back_inserter(result.reductionVars)); - llvm::copy(reduceVarByRef, std::back_inserter(result.reduceVarByRef)); + llvm::copy(reduceVarByRef, + std::back_inserter(result.reductionVarsByRef)); llvm::copy(reductionDeclSymbols, std::back_inserter(result.reductionDeclSymbols)); diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.h b/flang/lib/Lower/OpenMP/ClauseProcessor.h index 5c9ab8baf82dd5..53571ae5abc204 100644 --- a/flang/lib/Lower/OpenMP/ClauseProcessor.h +++ b/flang/lib/Lower/OpenMP/ClauseProcessor.h @@ -77,6 +77,7 @@ class ClauseProcessor { mlir::omp::NumTeamsClauseOps &result) const; bool processNumThreads(lower::StatementContext &stmtCtx, mlir::omp::NumThreadsClauseOps &result) const; + bool processOrder(mlir::omp::OrderClauseOps &result) const; bool processOrdered(mlir::omp::OrderedClauseOps &result) const; bool processPriority(lower::StatementContext &stmtCtx, mlir::omp::PriorityClauseOps &result) const; diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp index 7d75e6f67dc1bc..22c41fce31723d 100644 --- a/flang/lib/Lower/OpenMP/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP/OpenMP.cpp @@ -776,6 +776,33 @@ static void genBodyOfTargetDataOp( } } +// This generates intermediate common block member accesses within a region +// and then rebinds the members symbol to the intermediate accessors we have +// generated so that subsequent code generation will utilise these instead. +// +// When the scope changes, the bindings to the intermediate accessors should +// be dropped in place of the original symbol bindings. +// +// This is for utilisation with TargetOp. +static void genIntermediateCommonBlockAccessors( + Fortran::lower::AbstractConverter &converter, + const mlir::Location ¤tLocation, mlir::Region ®ion, + llvm::ArrayRef mapSyms) { + for (auto [argIndex, argSymbol] : llvm::enumerate(mapSyms)) { + if (auto *details = + argSymbol->detailsIf()) { + for (auto obj : details->objects()) { + auto targetCBMemberBind = Fortran::lower::genCommonBlockMember( + converter, currentLocation, *obj, region.getArgument(argIndex)); + fir::ExtendedValue sexv = converter.getSymbolExtendedValue(*obj); + fir::ExtendedValue targetCBExv = + getExtendedValue(sexv, targetCBMemberBind); + converter.bindSymbol(*obj, targetCBExv); + } + } + } +} + // This functions creates a block for the body of the targetOp's region. It adds // all the symbols present in mapSymbols as block arguments to this block. static void @@ -955,6 +982,16 @@ genBodyOfTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable, // Create the insertion point after the marker. firOpBuilder.setInsertionPointAfter(undefMarker.getDefiningOp()); + // If we map a common block using it's symbol e.g. map(tofrom: /common_block/) + // and accessing it's members within the target region, there is a large + // chance we will end up with uses external to the region accessing the common + // resolve these, we do so by generating new common block member accesses + // within the region, binding them to the member symbol for the scope of the + // region so that subsequent code generation within the region will utilise + // our new member accesses we have created. + genIntermediateCommonBlockAccessors(converter, currentLocation, region, + mapSyms); + if (ConstructQueue::iterator next = std::next(item); next != queue.end()) { genOMPDispatch(converter, symTable, semaCtx, eval, currentLocation, queue, next); @@ -1000,6 +1037,7 @@ static void genDistributeClauses(lower::AbstractConverter &converter, ClauseProcessor cp(converter, semaCtx, clauses); cp.processAllocate(clauseOps); cp.processDistSchedule(stmtCtx, clauseOps); + cp.processOrder(clauseOps); // TODO Support delayed privatization. } @@ -1072,13 +1110,14 @@ static void genSimdClauses(lower::AbstractConverter &converter, ClauseProcessor cp(converter, semaCtx, clauses); cp.processAligned(clauseOps); cp.processIf(llvm::omp::Directive::OMPD_simd, clauseOps); + cp.processOrder(clauseOps); cp.processReduction(loc, clauseOps); cp.processSafelen(clauseOps); cp.processSimdlen(clauseOps); // TODO Support delayed privatization. - cp.processTODO(loc, llvm::omp::Directive::OMPD_simd); + cp.processTODO( + loc, llvm::omp::Directive::OMPD_simd); } static void genSingleClauses(lower::AbstractConverter &converter, @@ -1243,12 +1282,13 @@ static void genWsloopClauses( llvm::SmallVectorImpl &reductionSyms) { ClauseProcessor cp(converter, semaCtx, clauses); cp.processNowait(clauseOps); + cp.processOrder(clauseOps); cp.processOrdered(clauseOps); cp.processReduction(loc, clauseOps, &reductionTypes, &reductionSyms); cp.processSchedule(stmtCtx, clauseOps); // TODO Support delayed privatization. - cp.processTODO( + cp.processTODO( loc, llvm::omp::Directive::OMPD_do); } @@ -1670,6 +1710,13 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable, if (dsp.getAllSymbolsToPrivatize().contains(&sym)) return; + // if the symbol is part of an already mapped common block, do not make a + // map for it. + if (const Fortran::semantics::Symbol *common = + Fortran::semantics::FindCommonBlockContaining(sym.GetUltimate())) + if (llvm::find(mapSyms, common) != mapSyms.end()) + return; + if (llvm::find(mapSyms, &sym) == mapSyms.end()) { mlir::Value baseOp = converter.getSymbolAddress(sym); if (!baseOp) @@ -1691,15 +1738,14 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable, fir::unwrapRefType(info.addr.getType()))) bounds = lower::genBoundsOpsFromBox( - firOpBuilder, converter.getCurrentLocation(), converter, dataExv, - info); + firOpBuilder, converter.getCurrentLocation(), dataExv, info); if (mlir::isa( fir::unwrapRefType(info.addr.getType()))) { bool dataExvIsAssumedSize = semantics::IsAssumedSizeArray(sym.GetUltimate()); bounds = lower::genBaseBoundsOps( - firOpBuilder, converter.getCurrentLocation(), converter, dataExv, + firOpBuilder, converter.getCurrentLocation(), dataExv, dataExvIsAssumedSize); } @@ -1979,8 +2025,8 @@ static void genCompositeDoSimd(lower::AbstractConverter &converter, ConstructQueue::iterator item) { ClauseProcessor cp(converter, semaCtx, item->clauses); cp.processTODO( - loc, llvm::omp::OMPD_do_simd); + clause::Safelen, clause::Simdlen>(loc, + llvm::omp::OMPD_do_simd); // TODO: Add support for vectorization - add vectorization hints inside loop // body. // OpenMP standard does not specify the length of vector instructions. diff --git a/flang/lib/Optimizer/Transforms/CMakeLists.txt b/flang/lib/Optimizer/Transforms/CMakeLists.txt index 149afdf601c936..94d94398d696ad 100644 --- a/flang/lib/Optimizer/Transforms/CMakeLists.txt +++ b/flang/lib/Optimizer/Transforms/CMakeLists.txt @@ -6,6 +6,7 @@ add_flang_library(FIRTransforms AnnotateConstant.cpp AssumedRankOpConversion.cpp CharacterConversion.cpp + ConstantArgumentGlobalisation.cpp ControlFlowConverter.cpp ArrayValueCopy.cpp ExternalNameConversion.cpp diff --git a/flang/lib/Optimizer/Transforms/ConstantArgumentGlobalisation.cpp b/flang/lib/Optimizer/Transforms/ConstantArgumentGlobalisation.cpp new file mode 100644 index 00000000000000..f7074a79a8a8d7 --- /dev/null +++ b/flang/lib/Optimizer/Transforms/ConstantArgumentGlobalisation.cpp @@ -0,0 +1,185 @@ +//===- ConstantArgumentGlobalisation.cpp ----------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Dialect/FIRDialect.h" +#include "flang/Optimizer/Dialect/FIROps.h" +#include "flang/Optimizer/Dialect/FIRType.h" +#include "flang/Optimizer/Transforms/Passes.h" +#include "mlir/Dialect/Func/IR/FuncOps.h" +#include "mlir/IR/Diagnostics.h" +#include "mlir/IR/Dominance.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Transforms/GreedyPatternRewriteDriver.h" + +namespace fir { +#define GEN_PASS_DEF_CONSTANTARGUMENTGLOBALISATIONOPT +#include "flang/Optimizer/Transforms/Passes.h.inc" +} // namespace fir + +#define DEBUG_TYPE "flang-constant-argument-globalisation-opt" + +namespace { +unsigned uniqueLitId = 1; + +class CallOpRewriter : public mlir::OpRewritePattern { +protected: + const mlir::DominanceInfo &di; + +public: + using OpRewritePattern::OpRewritePattern; + + CallOpRewriter(mlir::MLIRContext *ctx, const mlir::DominanceInfo &_di) + : OpRewritePattern(ctx), di(_di) {} + + mlir::LogicalResult + matchAndRewrite(fir::CallOp callOp, + mlir::PatternRewriter &rewriter) const override { + LLVM_DEBUG(llvm::dbgs() << "Processing call op: " << callOp << "\n"); + auto module = callOp->getParentOfType(); + bool needUpdate = false; + fir::FirOpBuilder builder(rewriter, module); + llvm::SmallVector newOperands; + llvm::SmallVector> allocas; + for (const mlir::Value &a : callOp.getArgs()) { + auto alloca = mlir::dyn_cast_or_null(a.getDefiningOp()); + // We can convert arguments that are alloca, and that has + // the value by reference attribute. All else is just added + // to the argument list. + if (!alloca || !alloca->hasAttr(fir::getAdaptToByRefAttrName())) { + newOperands.push_back(a); + continue; + } + + mlir::Type varTy = alloca.getInType(); + assert(!fir::hasDynamicSize(varTy) && + "only expect statically sized scalars to be by value"); + + // Find immediate store with const argument + mlir::Operation *store = nullptr; + for (mlir::Operation *s : alloca->getUsers()) { + if (mlir::isa(s) && di.dominates(s, callOp)) { + // We can only deal with ONE store - if already found one, + // set to nullptr and exit the loop. + if (store) { + store = nullptr; + break; + } + store = s; + } + } + + // If we didn't find any store, or multiple stores, add argument as is + // and move on. + if (!store) { + newOperands.push_back(a); + continue; + } + + LLVM_DEBUG(llvm::dbgs() << " found store " << *store << "\n"); + + mlir::Operation *definingOp = store->getOperand(0).getDefiningOp(); + // If not a constant, add to operands and move on. + if (!mlir::isa(definingOp)) { + // Unable to remove alloca arg + newOperands.push_back(a); + continue; + } + + LLVM_DEBUG(llvm::dbgs() << " found define " << *definingOp << "\n"); + + std::string globalName = + "_global_const_." + std::to_string(uniqueLitId++); + assert(!builder.getNamedGlobal(globalName) && + "We should have a unique name here"); + + if (std::find_if(allocas.begin(), allocas.end(), [alloca](auto x) { + return x.first == alloca; + }) == allocas.end()) { + allocas.push_back(std::make_pair(alloca, store)); + } + + auto loc = callOp.getLoc(); + fir::GlobalOp global = builder.createGlobalConstant( + loc, varTy, globalName, + [&](fir::FirOpBuilder &builder) { + mlir::Operation *cln = definingOp->clone(); + builder.insert(cln); + mlir::Value val = + builder.createConvert(loc, varTy, cln->getResult(0)); + builder.create(loc, val); + }, + builder.createInternalLinkage()); + mlir::Value addr = builder.create(loc, global.resultType(), + global.getSymbol()); + newOperands.push_back(addr); + needUpdate = true; + } + + if (needUpdate) { + auto loc = callOp.getLoc(); + llvm::SmallVector newResultTypes; + newResultTypes.append(callOp.getResultTypes().begin(), + callOp.getResultTypes().end()); + fir::CallOp newOp = builder.create( + loc, newResultTypes, + callOp.getCallee().has_value() ? callOp.getCallee().value() + : mlir::SymbolRefAttr{}, + newOperands); + // Copy all the attributes from the old to new op. + newOp->setAttrs(callOp->getAttrs()); + rewriter.replaceOp(callOp, newOp); + + for (auto a : allocas) { + if (a.first->hasOneUse()) { + // If the alloca is only used for a store and the call operand, the + // store is no longer required. + rewriter.eraseOp(a.second); + rewriter.eraseOp(a.first); + } + } + LLVM_DEBUG(llvm::dbgs() << "global constant for " << callOp << " as " + << newOp << '\n'); + return mlir::success(); + } + + // Failure here just means "we couldn't do the conversion", which is + // perfectly acceptable to the upper layers of this function. + return mlir::failure(); + } +}; + +// this pass attempts to convert immediate scalar literals in function calls +// to global constants to allow transformations such as Dead Argument +// Elimination +class ConstantArgumentGlobalisationOpt + : public fir::impl::ConstantArgumentGlobalisationOptBase< + ConstantArgumentGlobalisationOpt> { +public: + ConstantArgumentGlobalisationOpt() = default; + + void runOnOperation() override { + mlir::ModuleOp mod = getOperation(); + mlir::DominanceInfo *di = &getAnalysis(); + auto *context = &getContext(); + mlir::RewritePatternSet patterns(context); + mlir::GreedyRewriteConfig config; + config.enableRegionSimplification = + mlir::GreedySimplifyRegionLevel::Disabled; + config.strictMode = mlir::GreedyRewriteStrictness::ExistingOps; + + patterns.insert(context, *di); + if (mlir::failed(mlir::applyPatternsAndFoldGreedily( + mod, std::move(patterns), config))) { + mlir::emitError(mod.getLoc(), + "error in constant globalisation optimization\n"); + signalPassFailure(); + } + } +}; +} // namespace diff --git a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp index 407ecc8e327b48..71cfee6d735aea 100644 --- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp +++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp @@ -61,9 +61,11 @@ DebugTypeGenerator::DebugTypeGenerator(mlir::ModuleOp m) // descriptors like lower_bound and extent for each dimension. mlir::Type llvmDimsType = getDescFieldTypeModel()(context); mlir::Type llvmPtrType = getDescFieldTypeModel()(context); + mlir::Type llvmLenType = getDescFieldTypeModel()(context); dimsOffset = getComponentOffset(*dl, context, llvmDimsType); dimsSize = dl->getTypeSize(llvmDimsType); ptrSize = dl->getTypeSize(llvmPtrType); + lenOffset = getComponentOffset(*dl, context, llvmLenType); } static mlir::LLVM::DITypeAttr genBasicType(mlir::MLIRContext *context, @@ -192,10 +194,8 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertSequenceType( mlir::LLVM::DITypeAttr DebugTypeGenerator::convertCharacterType( fir::CharacterType charTy, mlir::LLVM::DIFileAttr fileAttr, - mlir::LLVM::DIScopeAttr scope, mlir::Location loc) { + mlir::LLVM::DIScopeAttr scope, mlir::Location loc, bool hasDescriptor) { mlir::MLIRContext *context = module.getContext(); - if (!charTy.hasConstantLen()) - return genPlaceholderType(context); // DWARF 5 says the following about the character encoding in 5.1.1.2. // "DW_ATE_ASCII and DW_ATE_UCS specify encodings for the Fortran 2003 @@ -205,16 +205,38 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertCharacterType( if (charTy.getFKind() != 1) encoding = llvm::dwarf::DW_ATE_UCS; + uint64_t sizeInBits = 0; + mlir::LLVM::DIExpressionAttr lenExpr = nullptr; + mlir::LLVM::DIExpressionAttr locExpr = nullptr; + + if (hasDescriptor) { + llvm::SmallVector ops; + auto addOp = [&](unsigned opc, llvm::ArrayRef vals) { + ops.push_back(mlir::LLVM::DIExpressionElemAttr::get(context, opc, vals)); + }; + addOp(llvm::dwarf::DW_OP_push_object_address, {}); + addOp(llvm::dwarf::DW_OP_plus_uconst, {lenOffset}); + lenExpr = mlir::LLVM::DIExpressionAttr::get(context, ops); + ops.clear(); + + addOp(llvm::dwarf::DW_OP_push_object_address, {}); + addOp(llvm::dwarf::DW_OP_deref, {}); + locExpr = mlir::LLVM::DIExpressionAttr::get(context, ops); + } else if (charTy.hasConstantLen()) { + sizeInBits = + charTy.getLen() * kindMapping.getCharacterBitsize(charTy.getFKind()); + } else { + return genPlaceholderType(context); + } + // FIXME: Currently the DIStringType in llvm does not have the option to set // type of the underlying character. This restricts out ability to represent // string with non-default characters. Please see issue #95440 for more // details. return mlir::LLVM::DIStringTypeAttr::get( context, llvm::dwarf::DW_TAG_string_type, - mlir::StringAttr::get(context, ""), - charTy.getLen() * kindMapping.getCharacterBitsize(charTy.getFKind()), - /*alignInBits=*/0, /*stringLength=*/nullptr, - /*stringLengthExp=*/nullptr, /*stringLocationExp=*/nullptr, encoding); + mlir::StringAttr::get(context, ""), sizeInBits, /*alignInBits=*/0, + /*stringLength=*/nullptr, lenExpr, locExpr, encoding); } mlir::LLVM::DITypeAttr DebugTypeGenerator::convertPointerLikeType( @@ -229,6 +251,9 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertPointerLikeType( if (auto seqTy = mlir::dyn_cast_or_null(elTy)) return convertBoxedSequenceType(seqTy, fileAttr, scope, loc, genAllocated, genAssociated); + if (auto charTy = mlir::dyn_cast_or_null(elTy)) + return convertCharacterType(charTy, fileAttr, scope, loc, + /*hasDescriptor=*/true); mlir::LLVM::DITypeAttr elTyAttr = convertType(elTy, fileAttr, scope, loc); @@ -274,7 +299,8 @@ DebugTypeGenerator::convertType(mlir::Type Ty, mlir::LLVM::DIFileAttr fileAttr, } else if (auto seqTy = mlir::dyn_cast_or_null(Ty)) { return convertSequenceType(seqTy, fileAttr, scope, loc); } else if (auto charTy = mlir::dyn_cast_or_null(Ty)) { - return convertCharacterType(charTy, fileAttr, scope, loc); + return convertCharacterType(charTy, fileAttr, scope, loc, + /*hasDescriptor=*/false); } else if (auto boxTy = mlir::dyn_cast_or_null(Ty)) { auto elTy = boxTy.getElementType(); if (auto seqTy = mlir::dyn_cast_or_null(elTy)) @@ -284,6 +310,10 @@ DebugTypeGenerator::convertType(mlir::Type Ty, mlir::LLVM::DIFileAttr fileAttr, return convertPointerLikeType(heapTy.getElementType(), fileAttr, scope, loc, /*genAllocated=*/true, /*genAssociated=*/false); + if (auto ptrTy = mlir::dyn_cast_or_null(elTy)) + return convertPointerLikeType(ptrTy.getElementType(), fileAttr, scope, + loc, /*genAllocated=*/false, + /*genAssociated=*/true); return genPlaceholderType(context); } else { // FIXME: These types are currently unhandled. We are generating a diff --git a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.h b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.h index 7816363e988214..ec881e8be7cadc 100644 --- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.h +++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.h @@ -48,7 +48,8 @@ class DebugTypeGenerator { mlir::LLVM::DITypeAttr convertCharacterType(fir::CharacterType charTy, mlir::LLVM::DIFileAttr fileAttr, mlir::LLVM::DIScopeAttr scope, - mlir::Location loc); + mlir::Location loc, + bool hasDescriptor); mlir::LLVM::DITypeAttr convertPointerLikeType(mlir::Type elTy, mlir::LLVM::DIFileAttr fileAttr, @@ -60,6 +61,7 @@ class DebugTypeGenerator { std::uint64_t dimsSize; std::uint64_t dimsOffset; std::uint64_t ptrSize; + std::uint64_t lenOffset; }; } // namespace fir diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp index 2a6ecfbb0830ec..ca6a8239992441 100644 --- a/flang/lib/Parser/prescan.cpp +++ b/flang/lib/Parser/prescan.cpp @@ -105,13 +105,15 @@ void Prescanner::Statement() { NextLine(); return; case LineClassification::Kind::ConditionalCompilationDirective: - case LineClassification::Kind::DefinitionDirective: - case LineClassification::Kind::PreprocessorDirective: + case LineClassification::Kind::IncludeDirective: preprocessor_.Directive(TokenizePreprocessorDirective(), *this); + afterPreprocessingDirective_ = true; + skipLeadingAmpersand_ |= !inFixedForm_; return; - case LineClassification::Kind::IncludeDirective: + case LineClassification::Kind::PreprocessorDirective: + case LineClassification::Kind::DefinitionDirective: preprocessor_.Directive(TokenizePreprocessorDirective(), *this); - afterIncludeDirective_ = true; + // Don't set afterPreprocessingDirective_ return; case LineClassification::Kind::CompilerDirective: { directiveSentinel_ = line.sentinel; @@ -171,15 +173,17 @@ void Prescanner::Statement() { NextChar(); } LabelField(tokens); - } else if (skipLeadingAmpersand_) { - skipLeadingAmpersand_ = false; - const char *p{SkipWhiteSpace(at_)}; - if (p < limit_ && *p == '&') { - column_ += ++p - at_; - at_ = p; - } } else { - SkipSpaces(); + if (skipLeadingAmpersand_) { + skipLeadingAmpersand_ = false; + const char *p{SkipWhiteSpace(at_)}; + if (p < limit_ && *p == '&') { + column_ += ++p - at_; + at_ = p; + } + } else { + SkipSpaces(); + } // Check for a leading identifier that might be a keyword macro // that will expand to anything indicating a non-source line, like // a comment marker or directive sentinel. If so, disable line @@ -289,13 +293,14 @@ void Prescanner::CheckAndEmitLine( tokens.CheckBadFortranCharacters( messages_, *this, disableSourceContinuation_); // Parenthesis nesting check does not apply while any #include is - // active, nor on the lines before and after a top-level #include. + // active, nor on the lines before and after a top-level #include, + // nor before or after conditional source. // Applications play shenanigans with line continuation before and - // after #include'd subprogram argument lists. + // after #include'd subprogram argument lists and conditional source. if (!isNestedInIncludeDirective_ && !omitNewline_ && - !afterIncludeDirective_ && tokens.BadlyNestedParentheses()) { - if (inFixedForm_ && nextLine_ < limit_ && - IsPreprocessorDirectiveLine(nextLine_)) { + !afterPreprocessingDirective_ && tokens.BadlyNestedParentheses() && + !preprocessor_.InConditional()) { + if (nextLine_ < limit_ && IsPreprocessorDirectiveLine(nextLine_)) { // don't complain } else { tokens.CheckBadParentheses(messages_); @@ -306,7 +311,7 @@ void Prescanner::CheckAndEmitLine( omitNewline_ = false; } else { cooked_.Put('\n', newlineProvenance); - afterIncludeDirective_ = false; + afterPreprocessingDirective_ = false; } } @@ -353,10 +358,11 @@ void Prescanner::LabelField(TokenSequence &token) { ++column_; } if (badColumn && !preprocessor_.IsNameDefined(token.CurrentOpenToken())) { - if (prescannerNesting_ > 0 && *badColumn == 6 && - cooked_.BufferedBytes() == firstCookedCharacterOffset_) { - // This is the first source line in #included text or conditional - // code under #if. + if ((prescannerNesting_ > 0 && *badColumn == 6 && + cooked_.BufferedBytes() == firstCookedCharacterOffset_) || + afterPreprocessingDirective_) { + // This is the first source line in #include'd text or conditional + // code under #if, or the first source line after such. // If it turns out that the preprocessed text begins with a // fixed form continuation line, the newline at the end // of the latest source line beforehand will be deleted in @@ -465,7 +471,7 @@ bool Prescanner::MustSkipToEndOfLine() const { if (inFixedForm_ && column_ > fixedFormColumnLimit_ && !tabInCurrentLine_) { return true; // skip over ignored columns in right margin (73:80) } else if (*at_ == '!' && !inCharLiteral_) { - return true; // inline comment goes to end of source line + return !IsCompilerDirectiveSentinel(at_); } else { return false; } @@ -599,7 +605,7 @@ bool Prescanner::NextToken(TokenSequence &tokens) { char previous{at_ <= start_ ? ' ' : at_[-1]}; NextChar(); SkipSpaces(); - if (*at_ == '\n') { + if (*at_ == '\n' && !omitNewline_) { // Discard white space at the end of a line. } else if (!inPreprocessorDirective_ && (previous == '(' || *at_ == '(' || *at_ == ')')) { @@ -814,6 +820,41 @@ void Prescanner::QuotedCharacterLiteral( } break; } + // Here's a weird edge case. When there's a two or more following + // continuation lines at this point, and the entire significant part of + // the next continuation line is the name of a keyword macro, replace + // it in the character literal with its definition. Example: + // #define FOO foo + // subroutine subr() bind(c, name="my_& + // &FOO& + // &_bar") ... + // produces a binding name of "my_foo_bar". + while (at_[1] == '&' && nextLine_ < limit_ && !InFixedFormSource()) { + const char *idStart{nextLine_}; + if (const char *amper{SkipWhiteSpace(nextLine_)}; *amper == '&') { + idStart = amper + 1; + } + if (IsLegalIdentifierStart(*idStart)) { + std::size_t idLen{1}; + for (; IsLegalInIdentifier(idStart[idLen]); ++idLen) { + } + if (idStart[idLen] == '&') { + CharBlock id{idStart, idLen}; + if (preprocessor_.IsNameDefined(id)) { + TokenSequence ppTokens; + ppTokens.Put(id, GetProvenance(idStart)); + if (auto replaced{ + preprocessor_.MacroReplacement(ppTokens, *this)}) { + tokens.Put(*replaced); + at_ = &idStart[idLen - 1]; + NextLine(); + continue; // try again on the next line + } + } + } + } + break; + } end = at_ + 1; NextChar(); if (*at_ == quote && !isEscaped) { @@ -1069,6 +1110,17 @@ bool Prescanner::SkipCommentLine(bool afterAmpersand) { return true; } else if (inPreprocessorDirective_) { return false; + } else if (afterAmpersand && + (lineClass.kind == + LineClassification::Kind::ConditionalCompilationDirective || + lineClass.kind == LineClassification::Kind::DefinitionDirective || + lineClass.kind == LineClassification::Kind::PreprocessorDirective || + lineClass.kind == LineClassification::Kind::IncludeDirective || + lineClass.kind == LineClassification::Kind::IncludeLine)) { + SkipToEndOfLine(); + omitNewline_ = true; + skipLeadingAmpersand_ = true; + return false; } else if (lineClass.kind == LineClassification::Kind::ConditionalCompilationDirective || lineClass.kind == LineClassification::Kind::PreprocessorDirective) { @@ -1080,13 +1132,6 @@ bool Prescanner::SkipCommentLine(bool afterAmpersand) { // continued line). preprocessor_.Directive(TokenizePreprocessorDirective(), *this); return true; - } else if (afterAmpersand && - (lineClass.kind == LineClassification::Kind::IncludeDirective || - lineClass.kind == LineClassification::Kind::IncludeLine)) { - SkipToEndOfLine(); - omitNewline_ = true; - skipLeadingAmpersand_ = true; - return false; } else { return false; } @@ -1335,32 +1380,12 @@ Prescanner::IsFixedFormCompilerDirectiveLine(const char *start) const { std::optional Prescanner::IsFreeFormCompilerDirectiveLine(const char *start) const { - char sentinel[8]; - const char *p{SkipWhiteSpace(start)}; - if (*p++ != '!') { - return std::nullopt; - } - for (std::size_t j{0}; j + 1 < sizeof sentinel; ++p, ++j) { - if (*p == '\n') { - break; - } - if (*p == ' ' || *p == '\t' || *p == '&') { - if (j == 0) { - break; - } - sentinel[j] = '\0'; - p = SkipWhiteSpace(p + 1); - if (*p == '!') { - break; - } - if (const char *sp{IsCompilerDirectiveSentinel(sentinel, j)}) { - std::size_t offset = p - start; - return {LineClassification{ - LineClassification::Kind::CompilerDirective, offset, sp}}; - } - break; + if (const char *p{SkipWhiteSpace(start)}; p && *p++ == '!') { + if (auto maybePair{IsCompilerDirectiveSentinel(p)}) { + auto offset{static_cast(maybePair->second - start)}; + return {LineClassification{LineClassification::Kind::CompilerDirective, + offset, maybePair->first}}; } - sentinel[j] = ToLowerCaseLetter(*p); } return std::nullopt; } @@ -1405,6 +1430,28 @@ const char *Prescanner::IsCompilerDirectiveSentinel(CharBlock token) const { return end > p && IsCompilerDirectiveSentinel(p, end - p) ? p : nullptr; } +std::optional> +Prescanner::IsCompilerDirectiveSentinel(const char *p) const { + char sentinel[8]; + for (std::size_t j{0}; j + 1 < sizeof sentinel && *p != '\n'; ++p, ++j) { + if (*p == ' ' || *p == '\t' || *p == '&') { + if (j > 0) { + sentinel[j] = '\0'; + p = SkipWhiteSpace(p + 1); + if (*p != '!') { + if (const char *sp{IsCompilerDirectiveSentinel(sentinel, j)}) { + return std::make_pair(sp, p); + } + } + } + break; + } else { + sentinel[j] = ToLowerCaseLetter(*p); + } + } + return std::nullopt; +} + constexpr bool IsDirective(const char *match, const char *dir) { for (; *match; ++match) { if (*match != ToLowerCaseLetter(*dir++)) { diff --git a/flang/lib/Parser/prescan.h b/flang/lib/Parser/prescan.h index b6f6d2ca439ee7..a64df5377e7e03 100644 --- a/flang/lib/Parser/prescan.h +++ b/flang/lib/Parser/prescan.h @@ -74,6 +74,9 @@ class Prescanner { const char *IsCompilerDirectiveSentinel(const char *, std::size_t) const; const char *IsCompilerDirectiveSentinel(CharBlock) const; + // 'first' is the sentinel, 'second' is beginning of payload + std::optional> + IsCompilerDirectiveSentinel(const char *p) const; template Message &Say(A &&...a) { return messages_.Say(std::forward(a)...); @@ -214,7 +217,7 @@ class Prescanner { int prescannerNesting_{0}; int continuationLines_{0}; bool isPossibleMacroCall_{false}; - bool afterIncludeDirective_{false}; + bool afterPreprocessingDirective_{false}; bool disableSourceContinuation_{false}; Provenance startProvenance_; diff --git a/flang/lib/Parser/token-sequence.cpp b/flang/lib/Parser/token-sequence.cpp index 133e60ba4f0098..c73bca1df33de3 100644 --- a/flang/lib/Parser/token-sequence.cpp +++ b/flang/lib/Parser/token-sequence.cpp @@ -266,7 +266,7 @@ TokenSequence &TokenSequence::ClipComment( if (std::size_t blanks{tok.CountLeadingBlanks()}; blanks < tok.size() && tok[blanks] == '!') { // Retain active compiler directive sentinels (e.g. "!dir$") - for (std::size_t k{j + 1}; k < tokens && tok.size() < blanks + 5; ++k) { + for (std::size_t k{j + 1}; k < tokens && tok.size() <= blanks + 5; ++k) { if (tok.begin() + tok.size() == TokenAt(k).begin()) { tok.ExtendToCover(TokenAt(k)); } else { @@ -274,12 +274,9 @@ TokenSequence &TokenSequence::ClipComment( } } bool isSentinel{false}; - if (tok.size() == blanks + 5) { - char sentinel[4]; - for (int k{0}; k < 4; ++k) { - sentinel[k] = ToLowerCaseLetter(tok[blanks + k + 1]); - } - isSentinel = prescanner.IsCompilerDirectiveSentinel(sentinel, 4); + if (tok.size() > blanks + 5) { + isSentinel = prescanner.IsCompilerDirectiveSentinel(&tok[blanks + 1]) + .has_value(); } if (isSentinel) { } else if (skipFirst) { diff --git a/flang/lib/Semantics/check-allocate.cpp b/flang/lib/Semantics/check-allocate.cpp index b4c5660670579d..a4fa72b03ca18f 100644 --- a/flang/lib/Semantics/check-allocate.cpp +++ b/flang/lib/Semantics/check-allocate.cpp @@ -539,7 +539,7 @@ bool AllocationCheckerHelper::RunChecks(SemanticsContext &context) { // Shape related checks if (ultimate_ && evaluate::IsAssumedRank(*ultimate_)) { context.Say(name_.source, - "An assumed-rank object may not appear in an ALLOCATE statement"_err_en_US); + "An assumed-rank dummy argument may not appear in an ALLOCATE statement"_err_en_US); return false; } if (ultimate_ && IsAssumedSizeArray(*ultimate_) && context.AnyFatalError()) { diff --git a/flang/lib/Semantics/check-call.cpp b/flang/lib/Semantics/check-call.cpp index 72576942e62cb3..8fe90eedc913f9 100644 --- a/flang/lib/Semantics/check-call.cpp +++ b/flang/lib/Semantics/check-call.cpp @@ -67,11 +67,9 @@ static void CheckImplicitInterfaceArg(evaluate::ActualArgument &arg, messages.Say( "Coarray argument requires an explicit interface"_err_en_US); } - if (const auto *details{symbol.detailsIf()}) { - if (details->IsAssumedRank()) { - messages.Say( - "Assumed rank argument requires an explicit interface"_err_en_US); - } + if (evaluate::IsAssumedRank(symbol)) { + messages.Say( + "Assumed rank argument requires an explicit interface"_err_en_US); } if (symbol.attrs().test(Attr::ASYNCHRONOUS)) { messages.Say( @@ -143,8 +141,8 @@ static void CheckCharacterActual(evaluate::Expr &actual, bool canAssociate{CanAssociateWithStorageSequence(dummy)}; if (dummy.type.Rank() > 0 && canAssociate) { // Character storage sequence association (F'2023 15.5.2.12p4) - if (auto dummySize{evaluate::ToInt64(evaluate::Fold(foldingContext, - evaluate::GetSize(evaluate::Shape{dummy.type.shape()})))}) { + if (auto dummySize{evaluate::ToInt64(evaluate::Fold( + foldingContext, evaluate::GetSize(dummy.type.shape())))}) { auto dummyChars{*dummySize * *dummyLength}; if (actualType.Rank() == 0) { evaluate::DesignatorFolder folder{ @@ -183,8 +181,7 @@ static void CheckCharacterActual(evaluate::Expr &actual, } } else { // actual.type.Rank() > 0 if (auto actualSize{evaluate::ToInt64(evaluate::Fold( - foldingContext, - evaluate::GetSize(evaluate::Shape(actualType.shape()))))}; + foldingContext, evaluate::GetSize(actualType.shape())))}; actualSize && *actualSize * *actualLength < *dummySize * *dummyLength && (extentErrors || @@ -251,7 +248,7 @@ static void ConvertIntegerActual(evaluate::Expr &actual, if (dummyType.type().category() == TypeCategory::Integer && actualType.type().category() == TypeCategory::Integer && dummyType.type().kind() != actualType.type().kind() && - GetRank(dummyType.shape()) == 0 && GetRank(actualType.shape()) == 0 && + dummyType.Rank() == 0 && actualType.Rank() == 0 && !evaluate::IsVariable(actual)) { auto converted{ evaluate::ConvertToType(dummyType.type(), std::move(actual))}; @@ -387,10 +384,10 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy, // if the actual argument is an array or array element designator, // and the dummy is an array, but not assumed-shape or an INTENT(IN) // pointer that's standing in for an assumed-shape dummy. - } else { + } else if (dummy.type.shape() && actualType.shape()) { // Let CheckConformance accept actual scalars; storage association // cases are checked here below. - CheckConformance(messages, dummy.type.shape(), actualType.shape(), + CheckConformance(messages, *dummy.type.shape(), *actualType.shape(), dummyIsAllocatableOrPointer ? evaluate::CheckConformanceFlags::None : evaluate::CheckConformanceFlags::RightScalarExpandable, @@ -579,8 +576,8 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy, CanAssociateWithStorageSequence(dummy) && !dummy.attrs.test( characteristics::DummyDataObject::Attr::DeducedFromActual)) { - if (auto dummySize{evaluate::ToInt64(evaluate::Fold(foldingContext, - evaluate::GetSize(evaluate::Shape{dummy.type.shape()})))}) { + if (auto dummySize{evaluate::ToInt64(evaluate::Fold( + foldingContext, evaluate::GetSize(dummy.type.shape())))}) { if (actualRank == 0 && !actualIsAssumedRank) { if (evaluate::IsArrayElement(actual)) { // Actual argument is a scalar array element @@ -622,8 +619,8 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy, } } } else { // actualRank > 0 || actualIsAssumedRank - if (auto actualSize{evaluate::ToInt64(evaluate::Fold(foldingContext, - evaluate::GetSize(evaluate::Shape(actualType.shape()))))}; + if (auto actualSize{evaluate::ToInt64(evaluate::Fold( + foldingContext, evaluate::GetSize(actualType.shape())))}; actualSize && *actualSize < *dummySize && (extentErrors || context.ShouldWarn(common::UsageWarning::ShortArrayActual))) { diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp index 4bb625bfbc2cae..dae40502792004 100644 --- a/flang/lib/Semantics/check-declarations.cpp +++ b/flang/lib/Semantics/check-declarations.cpp @@ -252,8 +252,7 @@ void CheckHelper::Check(const Symbol &symbol) { &symbol == &symbol.GetUltimate()) { if (context_.ShouldWarn(common::LanguageFeature::LongNames)) { WarnIfNotInModuleFile(symbol.name(), - "%s has length %d, which is greater than the maximum name length " - "%d"_port_en_US, + "%s has length %d, which is greater than the maximum name length %d"_port_en_US, symbol.name(), symbol.name().size(), common::maxNameLen); } } @@ -354,7 +353,10 @@ void CheckHelper::Check(const Symbol &symbol) { messages_.Say( "A pure subprogram may not have a variable with the VOLATILE attribute"_err_en_US); } - if (IsProcedure(symbol) && !IsPureProcedure(symbol) && IsDummy(symbol)) { + if (innermostSymbol_ && innermostSymbol_->name() == "__builtin_c_funloc") { + // The intrinsic procedure C_FUNLOC() gets a pass on this check. + } else if (IsProcedure(symbol) && !IsPureProcedure(symbol) && + IsDummy(symbol)) { messages_.Say( "A dummy procedure of a pure subprogram must be pure"_err_en_US); } @@ -463,12 +465,12 @@ void CheckHelper::Check(const Symbol &symbol) { symbol.name()); } } - if (IsProcedure(symbol) && !symbol.HasExplicitInterface()) { + if (IsProcedure(symbol)) { if (IsAllocatable(symbol)) { messages_.Say( - "Procedure '%s' may not be ALLOCATABLE without an explicit interface"_err_en_US, - symbol.name()); - } else if (symbol.Rank() > 0) { + "Procedure '%s' may not be ALLOCATABLE"_err_en_US, symbol.name()); + } + if (!symbol.HasExplicitInterface() && symbol.Rank() > 0) { messages_.Say( "Procedure '%s' may not be an array without an explicit interface"_err_en_US, symbol.name()); @@ -1325,6 +1327,13 @@ class SubprogramMatchHelper { bool CheckSameAttrs(const Symbol &, const Symbol &, ATTRS, ATTRS); bool ShapesAreCompatible(const DummyDataObject &, const DummyDataObject &); evaluate::Shape FoldShape(const evaluate::Shape &); + std::optional FoldShape( + const std::optional &shape) { + if (shape) { + return FoldShape(*shape); + } + return std::nullopt; + } std::string AsFortran(DummyDataObject::Attr attr) { return parser::ToUpperCaseLetters(DummyDataObject::EnumToString(attr)); } diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp index 803c655b3174fe..2202639a92e43d 100644 --- a/flang/lib/Semantics/expression.cpp +++ b/flang/lib/Semantics/expression.cpp @@ -141,7 +141,7 @@ class ArgumentAnalyzer { } void Analyze(const parser::Variable &); void Analyze(const parser::ActualArgSpec &, bool isSubroutine); - void ConvertBOZ(std::optional &thisType, std::size_t i, + void ConvertBOZ(std::optional *thisType, std::size_t, std::optional otherType); bool IsIntrinsicRelational( @@ -153,6 +153,7 @@ class ArgumentAnalyzer { bool CheckConformance(); bool CheckAssignmentConformance(); bool CheckForNullPointer(const char *where = "as an operand here"); + bool CheckForAssumedRank(const char *where = "as an operand here"); // Find and return a user-defined operator or report an error. // The provided message is used if there is no such operator. @@ -3200,6 +3201,7 @@ const Assignment *ExpressionAnalyzer::Analyze(const parser::AssignmentStmt &x) { if (!procRef) { analyzer.CheckForNullPointer( "in a non-pointer intrinsic assignment statement"); + analyzer.CheckForAssumedRank("in an assignment statement"); const Expr &lhs{analyzer.GetExpr(0)}; if (auto dyType{lhs.GetType()}; dyType && dyType->IsPolymorphic()) { // 10.2.1.2p1(1) @@ -3394,6 +3396,7 @@ static MaybeExpr NumericUnaryHelper(ExpressionAnalyzer &context, if (!analyzer.fatalErrors()) { if (analyzer.IsIntrinsicNumeric(opr)) { analyzer.CheckForNullPointer(); + analyzer.CheckForAssumedRank(); if (opr == NumericOperator::Add) { return analyzer.MoveExpr(0); } else { @@ -3428,6 +3431,7 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::NOT &x) { if (!analyzer.fatalErrors()) { if (analyzer.IsIntrinsicLogical()) { analyzer.CheckForNullPointer(); + analyzer.CheckForAssumedRank(); return AsGenericExpr( LogicalNegation(std::get>(analyzer.MoveExpr(0).u))); } else { @@ -3476,6 +3480,7 @@ MaybeExpr NumericBinaryHelper(ExpressionAnalyzer &context, NumericOperator opr, if (!analyzer.fatalErrors()) { if (analyzer.IsIntrinsicNumeric(opr)) { analyzer.CheckForNullPointer(); + analyzer.CheckForAssumedRank(); analyzer.CheckConformance(); return NumericOperation(context.GetContextualMessages(), analyzer.MoveExpr(0), analyzer.MoveExpr(1), @@ -3525,6 +3530,7 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Concat &x) { if (!analyzer.fatalErrors()) { if (analyzer.IsIntrinsicConcat()) { analyzer.CheckForNullPointer(); + analyzer.CheckForAssumedRank(); return common::visit( [&](auto &&x, auto &&y) -> MaybeExpr { using T = ResultType; @@ -3567,11 +3573,12 @@ MaybeExpr RelationHelper(ExpressionAnalyzer &context, RelationalOperator opr, if (!analyzer.fatalErrors()) { std::optional leftType{analyzer.GetType(0)}; std::optional rightType{analyzer.GetType(1)}; - analyzer.ConvertBOZ(leftType, 0, rightType); - analyzer.ConvertBOZ(rightType, 1, leftType); + analyzer.ConvertBOZ(&leftType, 0, rightType); + analyzer.ConvertBOZ(&rightType, 1, leftType); if (leftType && rightType && analyzer.IsIntrinsicRelational(opr, *leftType, *rightType)) { analyzer.CheckForNullPointer("as a relational operand"); + analyzer.CheckForAssumedRank("as a relational operand"); return AsMaybeExpr(Relate(context.GetContextualMessages(), opr, analyzer.MoveExpr(0), analyzer.MoveExpr(1))); } else { @@ -3617,6 +3624,7 @@ MaybeExpr LogicalBinaryHelper(ExpressionAnalyzer &context, LogicalOperator opr, if (!analyzer.fatalErrors()) { if (analyzer.IsIntrinsicLogical()) { analyzer.CheckForNullPointer("as a logical operand"); + analyzer.CheckForAssumedRank("as a logical operand"); return AsGenericExpr(BinaryLogicalOperation(opr, std::get>(analyzer.MoveExpr(0).u), std::get>(analyzer.MoveExpr(1).u))); @@ -4330,6 +4338,18 @@ bool ArgumentAnalyzer::CheckForNullPointer(const char *where) { return true; } +bool ArgumentAnalyzer::CheckForAssumedRank(const char *where) { + for (const std::optional &arg : actuals_) { + if (arg && IsAssumedRank(arg->UnwrapExpr())) { + context_.Say(source_, + "An assumed-rank dummy argument is not allowed %s"_err_en_US, where); + fatalErrors_ = true; + return false; + } + } + return true; +} + MaybeExpr ArgumentAnalyzer::TryDefinedOp( const char *opr, parser::MessageFixedText error, bool isUserOp) { if (AnyUntypedOrMissingOperand()) { @@ -4404,7 +4424,7 @@ MaybeExpr ArgumentAnalyzer::TryDefinedOp( context_.Say( "Operands of %s are not conformable; have rank %d and rank %d"_err_en_US, ToUpperCase(opr), actuals_[0]->Rank(), actuals_[1]->Rank()); - } else if (CheckForNullPointer()) { + } else if (CheckForNullPointer() && CheckForAssumedRank()) { context_.Say(error, ToUpperCase(opr), TypeAsFortran(0), TypeAsFortran(1)); } return result; @@ -4468,9 +4488,22 @@ std::optional ArgumentAnalyzer::TryDefinedAssignment() { // allocatable (the explicit conversion would prevent the propagation of the // right hand side if it is a variable). Lowering will deal with the // conversion in this case. - if (lhsType && rhsType && - (!IsAllocatableDesignator(lhs) || context_.inWhereBody())) { - AddAssignmentConversion(*lhsType, *rhsType); + if (lhsType) { + if (rhsType) { + if (!IsAllocatableDesignator(lhs) || context_.inWhereBody()) { + AddAssignmentConversion(*lhsType, *rhsType); + } + } else { + if (lhsType->category() == TypeCategory::Integer || + lhsType->category() == TypeCategory::Real) { + ConvertBOZ(nullptr, 1, lhsType); + } + if (IsBOZLiteral(1)) { + context_.Say( + "Right-hand side of this assignment may not be BOZ"_err_en_US); + fatalErrors_ = true; + } + } } if (!fatalErrors_) { CheckAssignmentConformance(); @@ -4699,7 +4732,7 @@ int ArgumentAnalyzer::GetRank(std::size_t i) const { // otherType. If it's REAL convert to REAL, otherwise convert to INTEGER. // Note that IBM supports comparing BOZ literals to CHARACTER operands. That // is not currently supported. -void ArgumentAnalyzer::ConvertBOZ(std::optional &thisType, +void ArgumentAnalyzer::ConvertBOZ(std::optional *thisType, std::size_t i, std::optional otherType) { if (IsBOZLiteral(i)) { Expr &&argExpr{MoveExpr(i)}; @@ -4709,13 +4742,17 @@ void ArgumentAnalyzer::ConvertBOZ(std::optional &thisType, MaybeExpr realExpr{ ConvertToKind(kind, std::move(*boz))}; actuals_[i] = std::move(*realExpr); - thisType.emplace(TypeCategory::Real, kind); + if (thisType) { + thisType->emplace(TypeCategory::Real, kind); + } } else { int kind{context_.context().GetDefaultKind(TypeCategory::Integer)}; MaybeExpr intExpr{ ConvertToKind(kind, std::move(*boz))}; actuals_[i] = std::move(*intExpr); - thisType.emplace(TypeCategory::Integer, kind); + if (thisType) { + thisType->emplace(TypeCategory::Integer, kind); + } } } } diff --git a/flang/lib/Semantics/pointer-assignment.cpp b/flang/lib/Semantics/pointer-assignment.cpp index 077072060e9b11..6c634c64131917 100644 --- a/flang/lib/Semantics/pointer-assignment.cpp +++ b/flang/lib/Semantics/pointer-assignment.cpp @@ -148,6 +148,9 @@ bool PointerAssignmentChecker::CheckLeftHandSide(const SomeExpr &lhs) { msg->Attach(std::move(*whyNot)); } return false; + } else if (evaluate::IsAssumedRank(lhs)) { + Say("The left-hand side of a pointer assignment must not be an assumed-rank dummy argument"_err_en_US); + return false; } else { return true; } @@ -333,8 +336,8 @@ bool PointerAssignmentChecker::Check(const evaluate::Designator &d) { } else if (!isBoundsRemapping_ && !lhsType_->attrs().test(TypeAndShape::Attr::AssumedRank)) { - int lhsRank{evaluate::GetRank(lhsType_->shape())}; - int rhsRank{evaluate::GetRank(rhsType->shape())}; + int lhsRank{lhsType_->Rank()}; + int rhsRank{rhsType->Rank()}; if (lhsRank != rhsRank) { msg = MessageFormattedText{ "Pointer has rank %d but target has rank %d"_err_en_US, lhsRank, diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp index d4fe668b92ec93..88822974e0134e 100644 --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -661,8 +661,8 @@ class ScopeHandler : public ImplicitRulesVisitor { void MakeExternal(Symbol &); // C815 duplicated attribute checking; returns false on error - bool CheckDuplicatedAttr(SourceName, const Symbol &, Attr); - bool CheckDuplicatedAttrs(SourceName, const Symbol &, Attrs); + bool CheckDuplicatedAttr(SourceName, Symbol &, Attr); + bool CheckDuplicatedAttrs(SourceName, Symbol &, Attrs); void SetExplicitAttr(Symbol &symbol, Attr attr) const { symbol.attrs().set(attr); @@ -1087,6 +1087,58 @@ class DeclarationVisitor : public ArraySpecVisitor, void NoteScalarSpecificationArgument(const Symbol &symbol) { mustBeScalar_.emplace(symbol); } + // Declare an object or procedure entity. + // T is one of: EntityDetails, ObjectEntityDetails, ProcEntityDetails + template + Symbol &DeclareEntity(const parser::Name &name, Attrs attrs) { + Symbol &symbol{MakeSymbol(name, attrs)}; + if (context().HasError(symbol) || symbol.has()) { + return symbol; // OK or error already reported + } else if (symbol.has()) { + symbol.set_details(T{}); + return symbol; + } else if (auto *details{symbol.detailsIf()}) { + symbol.set_details(T{std::move(*details)}); + return symbol; + } else if (std::is_same_v && + (symbol.has() || + symbol.has())) { + return symbol; // OK + } else if (auto *details{symbol.detailsIf()}) { + Say(name.source, + "'%s' is use-associated from module '%s' and cannot be re-declared"_err_en_US, + name.source, GetUsedModule(*details).name()); + } else if (auto *details{symbol.detailsIf()}) { + if (details->kind() == SubprogramKind::Module) { + Say2(name, + "Declaration of '%s' conflicts with its use as module procedure"_err_en_US, + symbol, "Module procedure definition"_en_US); + } else if (details->kind() == SubprogramKind::Internal) { + Say2(name, + "Declaration of '%s' conflicts with its use as internal procedure"_err_en_US, + symbol, "Internal procedure definition"_en_US); + } else { + DIE("unexpected kind"); + } + } else if (std::is_same_v && + symbol.has()) { + SayWithDecl( + name, symbol, "'%s' is already declared as a procedure"_err_en_US); + } else if (std::is_same_v && + symbol.has()) { + if (FindCommonBlockContaining(symbol)) { + SayWithDecl(name, symbol, + "'%s' may not be a procedure as it is in a COMMON block"_err_en_US); + } else { + SayWithDecl( + name, symbol, "'%s' is already declared as an object"_err_en_US); + } + } else if (!CheckPossibleBadForwardRef(symbol)) { + SayAlreadyDeclared(name, symbol); + } + context().SetError(symbol); + return symbol; + } private: // The attribute corresponding to the statement containing an ObjectDecl @@ -1151,59 +1203,6 @@ class DeclarationVisitor : public ArraySpecVisitor, bool PassesLocalityChecks( const parser::Name &name, Symbol &symbol, Symbol::Flag flag); bool CheckForHostAssociatedImplicit(const parser::Name &); - - // Declare an object or procedure entity. - // T is one of: EntityDetails, ObjectEntityDetails, ProcEntityDetails - template - Symbol &DeclareEntity(const parser::Name &name, Attrs attrs) { - Symbol &symbol{MakeSymbol(name, attrs)}; - if (context().HasError(symbol) || symbol.has()) { - return symbol; // OK or error already reported - } else if (symbol.has()) { - symbol.set_details(T{}); - return symbol; - } else if (auto *details{symbol.detailsIf()}) { - symbol.set_details(T{std::move(*details)}); - return symbol; - } else if (std::is_same_v && - (symbol.has() || - symbol.has())) { - return symbol; // OK - } else if (auto *details{symbol.detailsIf()}) { - Say(name.source, - "'%s' is use-associated from module '%s' and cannot be re-declared"_err_en_US, - name.source, GetUsedModule(*details).name()); - } else if (auto *details{symbol.detailsIf()}) { - if (details->kind() == SubprogramKind::Module) { - Say2(name, - "Declaration of '%s' conflicts with its use as module procedure"_err_en_US, - symbol, "Module procedure definition"_en_US); - } else if (details->kind() == SubprogramKind::Internal) { - Say2(name, - "Declaration of '%s' conflicts with its use as internal procedure"_err_en_US, - symbol, "Internal procedure definition"_en_US); - } else { - DIE("unexpected kind"); - } - } else if (std::is_same_v && - symbol.has()) { - SayWithDecl( - name, symbol, "'%s' is already declared as a procedure"_err_en_US); - } else if (std::is_same_v && - symbol.has()) { - if (FindCommonBlockContaining(symbol)) { - SayWithDecl(name, symbol, - "'%s' may not be a procedure as it is in a COMMON block"_err_en_US); - } else { - SayWithDecl( - name, symbol, "'%s' is already declared as an object"_err_en_US); - } - } else if (!CheckPossibleBadForwardRef(symbol)) { - SayAlreadyDeclared(name, symbol); - } - context().SetError(symbol); - return symbol; - } bool HasCycle(const Symbol &, const Symbol *interface); bool MustBeScalar(const Symbol &symbol) const { return mustBeScalar_.find(symbol) != mustBeScalar_.end(); @@ -1624,6 +1623,7 @@ class ResolveNamesVisitor : public virtual ScopeHandler, void PreSpecificationConstruct(const parser::SpecificationConstruct &); void CreateCommonBlockSymbols(const parser::CommonStmt &); + void CreateObjectSymbols(const std::list &, Attr); void CreateGeneric(const parser::GenericSpec &); void FinishSpecificationPart(const std::list &); void AnalyzeStmtFunctionStmt(const parser::StmtFunctionStmt &); @@ -2806,12 +2806,13 @@ void ScopeHandler::MakeExternal(Symbol &symbol) { } bool ScopeHandler::CheckDuplicatedAttr( - SourceName name, const Symbol &symbol, Attr attr) { + SourceName name, Symbol &symbol, Attr attr) { if (attr == Attr::SAVE) { // checked elsewhere } else if (symbol.attrs().test(attr)) { // C815 if (symbol.implicitAttrs().test(attr)) { // Implied attribute is now confirmed explicitly + symbol.implicitAttrs().reset(attr); } else { Say(name, "%s attribute was already specified on '%s'"_err_en_US, EnumToString(attr), name); @@ -2822,7 +2823,7 @@ bool ScopeHandler::CheckDuplicatedAttr( } bool ScopeHandler::CheckDuplicatedAttrs( - SourceName name, const Symbol &symbol, Attrs attrs) { + SourceName name, Symbol &symbol, Attrs attrs) { bool ok{true}; attrs.IterateOverMembers( [&](Attr x) { ok &= CheckDuplicatedAttr(name, symbol, x); }); @@ -5032,6 +5033,10 @@ Symbol &DeclarationVisitor::DeclareUnknownEntity( charInfo_.length.reset(); if (symbol.attrs().test(Attr::EXTERNAL)) { ConvertToProcEntity(symbol); + } else if (symbol.attrs().HasAny(Attrs{Attr::ALLOCATABLE, + Attr::ASYNCHRONOUS, Attr::CONTIGUOUS, Attr::PARAMETER, + Attr::SAVE, Attr::TARGET, Attr::VALUE, Attr::VOLATILE})) { + ConvertToObjectEntity(symbol); } if (attrs.test(Attr::BIND_C)) { SetBindNameOn(symbol); @@ -8551,11 +8556,19 @@ void ResolveNamesVisitor::PreSpecificationConstruct( } }, [&](const parser::Statement &y) { - if (const auto *commonStmt{parser::Unwrap(y)}) { - CreateCommonBlockSymbols(*commonStmt); - } + common::visit( + common::visitors{ + [&](const common::Indirection &z) { + CreateCommonBlockSymbols(z.value()); + }, + [&](const common::Indirection &z) { + CreateObjectSymbols(z.value().v, Attr::TARGET); + }, + [](const auto &) {}, + }, + y.statement.u); }, - [&](const auto &) {}, + [](const auto &) {}, }, spec.u); } @@ -8575,6 +8588,15 @@ void ResolveNamesVisitor::CreateCommonBlockSymbols( } } +void ResolveNamesVisitor::CreateObjectSymbols( + const std::list &decls, Attr attr) { + for (const parser::ObjectDecl &decl : decls) { + SetImplicitAttr(DeclareEntity( + std::get(decl.t), Attrs{}), + attr); + } +} + void ResolveNamesVisitor::CreateGeneric(const parser::GenericSpec &x) { auto info{GenericSpecInfo{x}}; SourceName symbolName{info.symbolName()}; diff --git a/flang/lib/Semantics/runtime-type-info.cpp b/flang/lib/Semantics/runtime-type-info.cpp index 15ea34c66dba52..8939dc4499ec43 100644 --- a/flang/lib/Semantics/runtime-type-info.cpp +++ b/flang/lib/Semantics/runtime-type-info.cpp @@ -748,7 +748,7 @@ evaluate::StructureConstructor RuntimeTableBuilder::DescribeComponent( symbol, foldingContext)}; CHECK(typeAndShape.has_value()); auto dyType{typeAndShape->type()}; - const auto &shape{typeAndShape->shape()}; + int rank{typeAndShape->Rank()}; AddValue(values, componentSchema_, "name"s, SaveNameAsPointerTarget(scope, symbol.name().ToString())); AddValue(values, componentSchema_, "category"s, @@ -830,7 +830,6 @@ evaluate::StructureConstructor RuntimeTableBuilder::DescribeComponent( SomeExpr{evaluate::NullPointer{}}); } // Shape information - int rank{evaluate::GetRank(shape)}; AddValue(values, componentSchema_, "rank"s, IntExpr<1>(rank)); if (rank > 0 && !IsAllocatable(symbol) && !IsPointer(symbol)) { std::vector bounds; @@ -1143,7 +1142,7 @@ void RuntimeTableBuilder::DescribeSpecialProc( isArgDescriptorSet |= 1; } else { which = scalarFinalEnum_; - if (int rank{evaluate::GetRank(typeAndShape.shape())}; rank > 0) { + if (int rank{typeAndShape.Rank()}; rank > 0) { which = IntExpr<1>(ToInt64(which).value() + rank); if (dummyData.IsPassedByDescriptor(proc->IsBindC())) { argThatMightBeDescriptor = 1; diff --git a/flang/module/__fortran_builtins.f90 b/flang/module/__fortran_builtins.f90 index b33d843710127b..44b0f17339cd96 100644 --- a/flang/module/__fortran_builtins.f90 +++ b/flang/module/__fortran_builtins.f90 @@ -182,7 +182,10 @@ __builtin_c_ptr_ne = x%__address /= y%__address end function - function __builtin_c_funloc(x) + ! Semantics has some special-case code that allows c_funloc() + ! to appear in a specification expression and exempts it + ! from the requirement that "x" be a pure dummy procedure. + pure function __builtin_c_funloc(x) type(__builtin_c_funptr) :: __builtin_c_funloc external :: x __builtin_c_funloc = __builtin_c_funptr(loc(x)) diff --git a/flang/runtime/ISO_Fortran_binding.cpp b/flang/runtime/ISO_Fortran_binding.cpp index 99ba3aa56feee2..fe22026f31f55f 100644 --- a/flang/runtime/ISO_Fortran_binding.cpp +++ b/flang/runtime/ISO_Fortran_binding.cpp @@ -13,6 +13,7 @@ #include "terminator.h" #include "flang/ISO_Fortran_binding_wrapper.h" #include "flang/Runtime/descriptor.h" +#include "flang/Runtime/pointer.h" #include "flang/Runtime/type-code.h" #include @@ -75,7 +76,7 @@ RT_API_ATTRS int CFI_allocate(CFI_cdesc_t *descriptor, dim->sm = byteSize; byteSize *= extent; } - void *p{byteSize ? std::malloc(byteSize) : std::malloc(1)}; + void *p{runtime::AllocateValidatedPointerPayload(byteSize)}; if (!p && byteSize) { return CFI_ERROR_MEM_ALLOCATION; } @@ -91,8 +92,11 @@ RT_API_ATTRS int CFI_deallocate(CFI_cdesc_t *descriptor) { if (descriptor->version != CFI_VERSION) { return CFI_INVALID_DESCRIPTOR; } - if (descriptor->attribute != CFI_attribute_allocatable && - descriptor->attribute != CFI_attribute_pointer) { + if (descriptor->attribute == CFI_attribute_pointer) { + if (!runtime::ValidatePointerPayload(*descriptor)) { + return CFI_INVALID_DESCRIPTOR; + } + } else if (descriptor->attribute != CFI_attribute_allocatable) { // Non-interoperable object return CFI_INVALID_DESCRIPTOR; } diff --git a/flang/runtime/descriptor.cpp b/flang/runtime/descriptor.cpp index d8b51f1be0c5cb..9b04cb4f8d0d05 100644 --- a/flang/runtime/descriptor.cpp +++ b/flang/runtime/descriptor.cpp @@ -199,7 +199,16 @@ RT_API_ATTRS int Descriptor::Destroy( } } -RT_API_ATTRS int Descriptor::Deallocate() { return ISO::CFI_deallocate(&raw_); } +RT_API_ATTRS int Descriptor::Deallocate() { + ISO::CFI_cdesc_t &descriptor{raw()}; + if (!descriptor.base_addr) { + return CFI_ERROR_BASE_ADDR_NULL; + } else { + std::free(descriptor.base_addr); + descriptor.base_addr = nullptr; + return CFI_SUCCESS; + } +} RT_API_ATTRS bool Descriptor::DecrementSubscripts( SubscriptValue *subscript, const int *permutation) const { diff --git a/flang/runtime/execute.cpp b/flang/runtime/execute.cpp index 0f5bc5059e21dc..c7f8f386d81f4f 100644 --- a/flang/runtime/execute.cpp +++ b/flang/runtime/execute.cpp @@ -13,8 +13,10 @@ #include "tools.h" #include "flang/Runtime/descriptor.h" #include +#include #include #include + #ifdef _WIN32 #include "flang/Common/windows-include.h" #else @@ -32,13 +34,16 @@ namespace Fortran::runtime { // and the processor does not support asynchronous execution. Otherwise it is // assigned the value 0 enum CMD_STAT { - ASYNC_NO_SUPPORT_ERR = -2, - NO_SUPPORT_ERR = -1, - CMD_EXECUTED = 0, - FORK_ERR = 1, - EXECL_ERR = 2, - INVALID_CL_ERR = 3, - SIGNAL_ERR = 4 + ASYNC_NO_SUPPORT_ERR = -2, // system returns -1 with ENOENT + NO_SUPPORT_ERR = -1, // Linux setsid() returns -1 + CMD_EXECUTED = 0, // command executed with no error + FORK_ERR = 1, // Linux fork() returns < 0 + EXECL_ERR = 2, // system returns -1 with other errno + COMMAND_EXECUTION_ERR = 3, // exit code 1 + COMMAND_CANNOT_EXECUTE_ERR = 4, // Linux exit code 126 + COMMAND_NOT_FOUND_ERR = 5, // Linux exit code 127 + INVALID_CL_ERR = 6, // cover all other non-zero exit code + SIGNAL_ERR = 7 }; // Override CopyCharsToDescriptor in tools.h, pass string directly @@ -62,24 +67,86 @@ void CheckAndStoreIntToDescriptor( // If a condition occurs that would assign a nonzero value to CMDSTAT but // the CMDSTAT variable is not present, error termination is initiated. -int TerminationCheck(int status, const Descriptor *cmdstat, +std::int64_t TerminationCheck(std::int64_t status, const Descriptor *cmdstat, const Descriptor *cmdmsg, Terminator &terminator) { + // On both Windows and Linux, errno is set when system returns -1. if (status == -1) { - if (!cmdstat) { - terminator.Crash("Execution error with system status code: %d", status); + // On Windows, ENOENT means the command interpreter can't be found. + // On Linux, system calls execl with filepath "/bin/sh", ENOENT means the + // file pathname does not exist. + if (errno == ENOENT) { + if (!cmdstat) { + terminator.Crash("Command line execution is not supported, system " + "returns -1 with errno ENOENT."); + } else { + StoreIntToDescriptor(cmdstat, NO_SUPPORT_ERR, terminator); + CheckAndCopyCharsToDescriptor(cmdmsg, + "Command line execution is not supported, system returns -1 with " + "errno ENOENT."); + } } else { - StoreIntToDescriptor(cmdstat, EXECL_ERR, terminator); - CheckAndCopyCharsToDescriptor(cmdmsg, "Execution error"); + char err_buffer[30]; + char msg[]{"Execution error with system status code: -1, errno: "}; +#ifdef _WIN32 + if (strerror_s(err_buffer, sizeof(err_buffer), errno) != 0) +#else + if (strerror_r(errno, err_buffer, sizeof(err_buffer)) != 0) +#endif + terminator.Crash("errno to char msg failed."); + char *newMsg{static_cast(AllocateMemoryOrCrash( + terminator, std::strlen(msg) + std::strlen(err_buffer) + 1))}; + std::strcat(newMsg, err_buffer); + + if (!cmdstat) { + terminator.Crash(newMsg); + } else { + StoreIntToDescriptor(cmdstat, EXECL_ERR, terminator); + CheckAndCopyCharsToDescriptor(cmdmsg, newMsg); + } + FreeMemory(newMsg); } } + #ifdef _WIN32 // On WIN32 API std::system returns exit status directly - int exitStatusVal{status}; - if (exitStatusVal == 1) { + std::int64_t exitStatusVal{status}; + if (exitStatusVal != 0) { + if (!cmdstat) { + terminator.Crash( + "Invalid command quit with exit status code: %d", exitStatusVal); + } else { + StoreIntToDescriptor(cmdstat, INVALID_CL_ERR, terminator); + CheckAndCopyCharsToDescriptor(cmdmsg, "Invalid command line"); + } + } #else - int exitStatusVal{WEXITSTATUS(status)}; - if (exitStatusVal == 127 || exitStatusVal == 126) { -#endif + std::int64_t exitStatusVal{WEXITSTATUS(status)}; + if (exitStatusVal == 1) { + if (!cmdstat) { + terminator.Crash("Command line execution failed with exit code: 1."); + } else { + StoreIntToDescriptor(cmdstat, COMMAND_EXECUTION_ERR, terminator); + CheckAndCopyCharsToDescriptor( + cmdmsg, "Command line execution failed with exit code: 1."); + } + } else if (exitStatusVal == 126) { + if (!cmdstat) { + terminator.Crash("Command cannot be executed with exit code: 126."); + } else { + StoreIntToDescriptor(cmdstat, COMMAND_CANNOT_EXECUTE_ERR, terminator); + CheckAndCopyCharsToDescriptor( + cmdmsg, "Command cannot be executed with exit code: 126."); + } + } else if (exitStatusVal == 127) { + if (!cmdstat) { + terminator.Crash("Command not found with exit code: 127."); + } else { + StoreIntToDescriptor(cmdstat, COMMAND_NOT_FOUND_ERR, terminator); + CheckAndCopyCharsToDescriptor( + cmdmsg, "Command not found with exit code: 127."); + } + // capture all other nonzero exit code + } else if (exitStatusVal != 0) { if (!cmdstat) { terminator.Crash( "Invalid command quit with exit status code: %d", exitStatusVal); @@ -88,23 +155,26 @@ int TerminationCheck(int status, const Descriptor *cmdstat, CheckAndCopyCharsToDescriptor(cmdmsg, "Invalid command line"); } } +#endif + #if defined(WIFSIGNALED) && defined(WTERMSIG) if (WIFSIGNALED(status)) { if (!cmdstat) { - terminator.Crash("killed by signal: %d", WTERMSIG(status)); + terminator.Crash("Killed by signal: %d", WTERMSIG(status)); } else { StoreIntToDescriptor(cmdstat, SIGNAL_ERR, terminator); - CheckAndCopyCharsToDescriptor(cmdmsg, "killed by signal"); + CheckAndCopyCharsToDescriptor(cmdmsg, "Killed by signal"); } } #endif + #if defined(WIFSTOPPED) && defined(WSTOPSIG) if (WIFSTOPPED(status)) { if (!cmdstat) { - terminator.Crash("stopped by signal: %d", WSTOPSIG(status)); + terminator.Crash("Stopped by signal: %d", WSTOPSIG(status)); } else { StoreIntToDescriptor(cmdstat, SIGNAL_ERR, terminator); - CheckAndCopyCharsToDescriptor(cmdmsg, "stopped by signal"); + CheckAndCopyCharsToDescriptor(cmdmsg, "Stopped by signal"); } } #endif @@ -134,8 +204,9 @@ void RTNAME(ExecuteCommandLine)(const Descriptor &command, bool wait, if (wait) { // either wait is not specified or wait is true: synchronous mode - int status{std::system(newCmd)}; - int exitStatusVal{TerminationCheck(status, cmdstat, cmdmsg, terminator)}; + std::int64_t status{std::system(newCmd)}; + std::int64_t exitStatusVal{ + TerminationCheck(status, cmdstat, cmdmsg, terminator)}; // If sync, assigned processor-dependent exit status. Otherwise unchanged CheckAndStoreIntToDescriptor(exitstat, exitStatusVal, terminator); } else { @@ -173,7 +244,7 @@ void RTNAME(ExecuteCommandLine)(const Descriptor &command, bool wait, terminator.Crash( "CreateProcess failed with error code: %lu.", GetLastError()); } else { - StoreIntToDescriptor(cmdstat, (uint32_t)GetLastError(), terminator); + StoreIntToDescriptor(cmdstat, ASYNC_NO_SUPPORT_ERR, terminator); CheckAndCopyCharsToDescriptor(cmdmsg, "CreateProcess failed."); } } @@ -201,7 +272,7 @@ void RTNAME(ExecuteCommandLine)(const Descriptor &command, bool wait, } exit(EXIT_FAILURE); } - int status{std::system(newCmd)}; + std::int64_t status{std::system(newCmd)}; TerminationCheck(status, cmdstat, cmdmsg, terminator); exit(status); } diff --git a/flang/runtime/external-unit.cpp b/flang/runtime/external-unit.cpp index 328c994a180b19..8009151a8a370c 100644 --- a/flang/runtime/external-unit.cpp +++ b/flang/runtime/external-unit.cpp @@ -65,10 +65,17 @@ ExternalFileUnit *ExternalFileUnit::LookUpOrCreateAnonymous(int unit, bool exists{false}; ExternalFileUnit *result{GetUnitMap().LookUpOrCreate(unit, handler, exists)}; if (result && !exists) { - result->OpenAnonymousUnit( - dir == Direction::Input ? OpenStatus::Unknown : OpenStatus::Replace, - Action::ReadWrite, Position::Rewind, Convert::Unknown, handler); - result->isUnformatted = isUnformatted; + if (!result->OpenAnonymousUnit( + dir == Direction::Input ? OpenStatus::Unknown : OpenStatus::Replace, + Action::ReadWrite, Position::Rewind, Convert::Unknown, handler)) { + // fort.N isn't a writable file + if (ExternalFileUnit * closed{LookUpForClose(result->unitNumber())}) { + closed->DestroyClosed(); + } + result = nullptr; + } else { + result->isUnformatted = isUnformatted; + } } return result; } @@ -183,7 +190,7 @@ bool ExternalFileUnit::OpenUnit(Fortran::common::optional status, return impliedClose; } -void ExternalFileUnit::OpenAnonymousUnit( +bool ExternalFileUnit::OpenAnonymousUnit( Fortran::common::optional status, Fortran::common::optional action, Position position, Convert convert, IoErrorHandler &handler) { @@ -193,6 +200,7 @@ void ExternalFileUnit::OpenAnonymousUnit( std::snprintf(path.get(), pathMaxLen, "fort.%d", unitNumber_); OpenUnit(status, action, position, std::move(path), std::strlen(path.get()), convert, handler); + return IsConnected(); } void ExternalFileUnit::CloseUnit(CloseStatus status, IoErrorHandler &handler) { diff --git a/flang/runtime/matmul.cpp b/flang/runtime/matmul.cpp index 543284cb5c3633..8f9b50a549e1fd 100644 --- a/flang/runtime/matmul.cpp +++ b/flang/runtime/matmul.cpp @@ -288,11 +288,25 @@ static inline RT_API_ATTRS void DoMatmul( } SubscriptValue n{x.GetDimension(xRank - 1).Extent()}; if (n != y.GetDimension(0).Extent()) { - terminator.Crash("MATMUL: unacceptable operand shapes (%jdx%jd, %jdx%jd)", - static_cast(x.GetDimension(0).Extent()), - static_cast(n), - static_cast(y.GetDimension(0).Extent()), - static_cast(y.GetDimension(1).Extent())); + // At this point, we know that there's a shape error. There are three + // possibilities, x is rank 1, y is rank 1, or both are rank 2. + if (xRank == 1) { + terminator.Crash("MATMUL: unacceptable operand shapes (%jd, %jdx%jd)", + static_cast(n), + static_cast(y.GetDimension(0).Extent()), + static_cast(y.GetDimension(1).Extent())); + } else if (yRank == 1) { + terminator.Crash("MATMUL: unacceptable operand shapes (%jdx%jd, %jd)", + static_cast(x.GetDimension(0).Extent()), + static_cast(n), + static_cast(y.GetDimension(0).Extent())); + } else { + terminator.Crash("MATMUL: unacceptable operand shapes (%jdx%jd, %jdx%jd)", + static_cast(x.GetDimension(0).Extent()), + static_cast(n), + static_cast(y.GetDimension(0).Extent()), + static_cast(y.GetDimension(1).Extent())); + } } using WriteResult = CppTypeFor(static_cast(p) + byteSize)}; + *footer = ~reinterpret_cast(p); + } + return p; +} + int RTDEF(PointerAllocate)(Descriptor &pointer, bool hasStat, const Descriptor *errMsg, const char *sourceFile, int sourceLine) { Terminator terminator{sourceFile, sourceLine}; @@ -137,22 +154,12 @@ int RTDEF(PointerAllocate)(Descriptor &pointer, bool hasStat, elementBytes = pointer.raw().elem_len = 0; } std::size_t byteSize{pointer.Elements() * elementBytes}; - // Add space for a footer to validate during DEALLOCATE. - constexpr std::size_t align{sizeof(std::uintptr_t)}; - byteSize = ((byteSize + align - 1) / align) * align; - std::size_t total{byteSize + sizeof(std::uintptr_t)}; - void *p{std::malloc(total)}; + void *p{AllocateValidatedPointerPayload(byteSize)}; if (!p) { return ReturnError(terminator, CFI_ERROR_MEM_ALLOCATION, errMsg, hasStat); } pointer.set_base_addr(p); pointer.SetByteStrides(); - // Fill the footer word with the XOR of the ones' complement of - // the base address, which is a value that would be highly unlikely - // to appear accidentally at the right spot. - std::uintptr_t *footer{ - reinterpret_cast(static_cast(p) + byteSize)}; - *footer = ~reinterpret_cast(p); int stat{StatOk}; if (const DescriptorAddendum * addendum{pointer.Addendum()}) { if (const auto *derived{addendum->derivedType()}) { @@ -176,6 +183,27 @@ int RTDEF(PointerAllocateSource)(Descriptor &pointer, const Descriptor &source, return stat; } +static RT_API_ATTRS std::size_t GetByteSize( + const ISO::CFI_cdesc_t &descriptor) { + std::size_t rank{descriptor.rank}; + const ISO::CFI_dim_t *dim{descriptor.dim}; + std::size_t byteSize{descriptor.elem_len}; + for (std::size_t j{0}; j < rank; ++j) { + byteSize *= dim[j].extent; + } + return byteSize; +} + +bool RT_API_ATTRS ValidatePointerPayload(const ISO::CFI_cdesc_t &desc) { + std::size_t byteSize{GetByteSize(desc)}; + constexpr std::size_t align{sizeof(std::uintptr_t)}; + byteSize = ((byteSize + align - 1) / align) * align; + const void *p{desc.base_addr}; + const std::uintptr_t *footer{reinterpret_cast( + static_cast(p) + byteSize)}; + return *footer == ~reinterpret_cast(p); +} + int RTDEF(PointerDeallocate)(Descriptor &pointer, bool hasStat, const Descriptor *errMsg, const char *sourceFile, int sourceLine) { Terminator terminator{sourceFile, sourceLine}; @@ -185,20 +213,9 @@ int RTDEF(PointerDeallocate)(Descriptor &pointer, bool hasStat, if (!pointer.IsAllocated()) { return ReturnError(terminator, StatBaseNull, errMsg, hasStat); } - if (executionEnvironment.checkPointerDeallocation) { - // Validate the footer. This should fail if the pointer doesn't - // span the entire object, or the object was not allocated as a - // pointer. - std::size_t byteSize{pointer.Elements() * pointer.ElementBytes()}; - constexpr std::size_t align{sizeof(std::uintptr_t)}; - byteSize = ((byteSize + align - 1) / align) * align; - void *p{pointer.raw().base_addr}; - std::uintptr_t *footer{ - reinterpret_cast(static_cast(p) + byteSize)}; - if (*footer != ~reinterpret_cast(p)) { - return ReturnError( - terminator, StatBadPointerDeallocation, errMsg, hasStat); - } + if (executionEnvironment.checkPointerDeallocation && + !ValidatePointerPayload(pointer.raw())) { + return ReturnError(terminator, StatBadPointerDeallocation, errMsg, hasStat); } return ReturnError(terminator, pointer.Destroy(/*finalize=*/true, /*destroyPointers=*/true, &terminator), diff --git a/flang/runtime/pseudo-unit.cpp b/flang/runtime/pseudo-unit.cpp index 70e70eec6a77ea..526afd11d916e9 100644 --- a/flang/runtime/pseudo-unit.cpp +++ b/flang/runtime/pseudo-unit.cpp @@ -65,7 +65,7 @@ bool ExternalFileUnit::OpenUnit(Fortran::common::optional status, handler.Crash("%s: unsupported", RT_PRETTY_FUNCTION); } -void ExternalFileUnit::OpenAnonymousUnit(Fortran::common::optional, +bool ExternalFileUnit::OpenAnonymousUnit(Fortran::common::optional, Fortran::common::optional, Position, Convert convert, IoErrorHandler &handler) { handler.Crash("%s: unsupported", RT_PRETTY_FUNCTION); diff --git a/flang/runtime/unit.h b/flang/runtime/unit.h index abd535fd0381de..83f839e205a483 100644 --- a/flang/runtime/unit.h +++ b/flang/runtime/unit.h @@ -134,7 +134,7 @@ class ExternalFileUnit : public ConnectionState, RT_API_ATTRS bool OpenUnit(Fortran::common::optional, Fortran::common::optional, Position, OwningPtr &&path, std::size_t pathLength, Convert, IoErrorHandler &); - RT_API_ATTRS void OpenAnonymousUnit(Fortran::common::optional, + RT_API_ATTRS bool OpenAnonymousUnit(Fortran::common::optional, Fortran::common::optional, Position, Convert, IoErrorHandler &); RT_API_ATTRS void CloseUnit(CloseStatus, IoErrorHandler &); RT_API_ATTRS void DestroyClosed(); diff --git a/flang/test/Driver/target-cpu-features.f90 b/flang/test/Driver/target-cpu-features.f90 index eea7a0f665b34e..e78c3516db45a0 100644 --- a/flang/test/Driver/target-cpu-features.f90 +++ b/flang/test/Driver/target-cpu-features.f90 @@ -31,11 +31,11 @@ ! CHECK-A57: "-fc1" "-triple" "aarch64-unknown-linux-gnu" ! CHECK-A57-SAME: "-target-cpu" "cortex-a57" -! CHECK-A57-SAME: "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon" +! CHECK-A57-SAME: "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2 ! CHECK-A76: "-fc1" "-triple" "aarch64-unknown-linux-gnu" ! CHECK-A76-SAME: "-target-cpu" "cortex-a76" -! CHECK-A76-SAME: "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon" "-target-feature" "+ssbs" +! CHECK-A76-SAME: "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+ssbs" ! CHECK-ARMV9: "-fc1" "-triple" "aarch64-unknown-linux-gnu" ! CHECK-ARMV9-SAME: "-target-cpu" "generic" diff --git a/flang/test/Evaluate/fold-nearest.f90 b/flang/test/Evaluate/fold-nearest.f90 index bd8b020c392ac3..a7366e6d75407e 100644 --- a/flang/test/Evaluate/fold-nearest.f90 +++ b/flang/test/Evaluate/fold-nearest.f90 @@ -28,6 +28,12 @@ module m1 logical, parameter :: test_15 = nearest(negZero, 0.) == minSubnormal logical, parameter :: test_16 = nearest(tiny(1.),-1.) == 1.1754942E-38 logical, parameter :: test_17 = nearest(tiny(1.),1.) == 1.1754945E-38 + contains + subroutine subr(a) + real, intent(in) :: a + !WARN: warning: NEAREST: S argument is zero + print *, nearest(a, 0.) + end end module module m2 diff --git a/flang/test/Evaluate/folding04.f90 b/flang/test/Evaluate/folding04.f90 index 86ae8debd6ef12..c7815b03403608 100644 --- a/flang/test/Evaluate/folding04.f90 +++ b/flang/test/Evaluate/folding04.f90 @@ -32,11 +32,22 @@ module real_tests !WARN: warning: invalid argument on evaluation of intrinsic function or operation real(4), parameter :: nan_r4_acos5 = acos(r4_pinf) TEST_ISNAN(nan_r4_acos5) - !WARN: warning: second argument to MOD must not be zero + !WARN: warning: MOD: P argument is zero real(4), parameter :: nan_r4_mod = mod(3.5, 0.) TEST_ISNAN(nan_r4_mod) !WARN: warning: overflow on evaluation of intrinsic function or operation logical, parameter :: test_exp_overflow = exp(256._4).EQ.r4_pinf + contains + subroutine s1(a,j) + !WARN: warning: MOD: P argument is zero + print *, mod(a, 0.) + !WARN: warning: MODULO: P argument is zero + print *, modulo(a, 0.) + !WARN: warning: MOD: P argument is zero + print *, mod(j, 0.) + !WARN: warning: MODULO: P argument is zero + print *, modulo(j, 0.) + end end module module parentheses diff --git a/flang/test/Evaluate/rewrite06.f90 b/flang/test/Evaluate/rewrite06.f90 index 03eb463fe9bd5d..f27e6256556a9a 100644 --- a/flang/test/Evaluate/rewrite06.f90 +++ b/flang/test/Evaluate/rewrite06.f90 @@ -31,3 +31,9 @@ subroutine test(k) print *, storage_size(return_pdt(k)) end subroutine end module + +subroutine test_assumed_rank(x) + real :: x(..) + !CHECK: PRINT *, sizeof(x) + print *, sizeof(x) +end subroutine diff --git a/flang/test/Fir/boxproc.fir b/flang/test/Fir/boxproc.fir index 834017bff71aa3..9e4ea0bc210775 100644 --- a/flang/test/Fir/boxproc.fir +++ b/flang/test/Fir/boxproc.fir @@ -16,9 +16,7 @@ // CHECK-LABEL: define void @_QPtest_proc_dummy_other(ptr // CHECK-SAME: %[[VAL_0:.*]]) -// CHECK: %[[VAL_1:.*]] = alloca i32, i64 1, align 4 -// CHECK: store i32 4, ptr %[[VAL_1]], align 4 -// CHECK: call void %[[VAL_0]](ptr %[[VAL_1]]) +// CHECK: call void %[[VAL_0]](ptr %{{.*}}) func.func @_QPtest_proc_dummy() { %c0_i32 = arith.constant 0 : i32 diff --git a/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir b/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir index 396fbaeacf39f1..8b62787bb30942 100644 --- a/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir +++ b/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir @@ -1006,3 +1006,77 @@ func.func @omp_map_info_nested_derived_type_explicit_member_conversion(%arg0 : ! } // ----- + +// CHECK-LABEL: llvm.func @omp_map_common_block_using_common_block_symbol + +// CHECK: %[[ADDR_OF:.*]] = llvm.mlir.addressof @var_common_ : !llvm.ptr +// CHECK: %[[CB_MAP:.*]] = omp.map.info var_ptr(%[[ADDR_OF]] : !llvm.ptr, !llvm.array<8 x i8>) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = "var_common"} +// CHECK: omp.target map_entries(%[[CB_MAP]] -> %[[ARG0:.*]] : !llvm.ptr) { +// CHECK: ^bb0(%[[ARG0]]: !llvm.ptr): +// CHECK: %[[VAR_2_OFFSET:.*]] = llvm.mlir.constant(4 : index) : i64 +// CHECK: %[[VAR_1_OFFSET:.*]] = llvm.mlir.constant(0 : index) : i64 +// CHECK: %{{.*}} = llvm.getelementptr %[[ARG0]][%[[VAR_1_OFFSET]]] : (!llvm.ptr, i64) -> !llvm.ptr, i8 +// CHECK: %{{.*}} = llvm.getelementptr %[[ARG0]][%[[VAR_2_OFFSET]]] : (!llvm.ptr, i64) -> !llvm.ptr, i8 + +func.func @omp_map_common_block_using_common_block_symbol() { + %0 = fir.address_of(@var_common_) : !fir.ref> + %1 = omp.map.info var_ptr(%0 : !fir.ref>, !fir.array<8xi8>) map_clauses(tofrom) capture(ByRef) -> !fir.ref> {name = "var_common"} + omp.target map_entries(%1 -> %arg0 : !fir.ref>) { + ^bb0(%arg0: !fir.ref>): + %c4 = arith.constant 4 : index + %c0 = arith.constant 0 : index + %c20_i32 = arith.constant 20 : i32 + %2 = fir.convert %arg0 : (!fir.ref>) -> !fir.ref> + %3 = fir.coordinate_of %2, %c0 : (!fir.ref>, index) -> !fir.ref + %4 = fir.convert %3 : (!fir.ref) -> !fir.ref + %5 = fir.convert %arg0 : (!fir.ref>) -> !fir.ref> + %6 = fir.coordinate_of %5, %c4 : (!fir.ref>, index) -> !fir.ref + %7 = fir.convert %6 : (!fir.ref) -> !fir.ref + %8 = fir.load %4 : !fir.ref + %9 = arith.addi %8, %c20_i32 : i32 + fir.store %9 to %7 : !fir.ref + omp.terminator + } + return +} + +fir.global common @var_common_(dense<0> : vector<8xi8>) {alignment = 4 : i64} : !fir.array<8xi8> + +// ----- + +// CHECK-LABEL: llvm.func @omp_map_common_block_using_common_block_members + +// CHECK: %[[VAR_2_OFFSET:.*]] = llvm.mlir.constant(4 : index) : i64 +// CHECK: %[[VAR_1_OFFSET:.*]] = llvm.mlir.constant(0 : index) : i64 +// CHECK: %[[ADDR_OF:.*]] = llvm.mlir.addressof @var_common_ : !llvm.ptr +// CHECK: %[[VAR_1_CB_GEP:.*]] = llvm.getelementptr %[[ADDR_OF]][%[[VAR_1_OFFSET]]] : (!llvm.ptr, i64) -> !llvm.ptr, i8 +// CHECK: %[[VAR_2_CB_GEP:.*]] = llvm.getelementptr %[[ADDR_OF]][%[[VAR_2_OFFSET]]] : (!llvm.ptr, i64) -> !llvm.ptr, i8 +// CHECK: %[[MAP_CB_VAR_1:.*]] = omp.map.info var_ptr(%[[VAR_1_CB_GEP]] : !llvm.ptr, i32) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = "var1"} +// CHECK: %[[MAP_CB_VAR_2:.*]] = omp.map.info var_ptr(%[[VAR_2_CB_GEP]] : !llvm.ptr, i32) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = "var2"} +// CHECK: omp.target map_entries(%[[MAP_CB_VAR_1]] -> %[[ARG0:.*]], %[[MAP_CB_VAR_2]] -> %[[ARG1:.*]] : !llvm.ptr, !llvm.ptr) { +// CHECK: ^bb0(%[[ARG0]]: !llvm.ptr, %[[ARG1]]: !llvm.ptr): + +func.func @omp_map_common_block_using_common_block_members() { + %c4 = arith.constant 4 : index + %c0 = arith.constant 0 : index + %0 = fir.address_of(@var_common_) : !fir.ref> + %1 = fir.convert %0 : (!fir.ref>) -> !fir.ref> + %2 = fir.coordinate_of %1, %c0 : (!fir.ref>, index) -> !fir.ref + %3 = fir.convert %2 : (!fir.ref) -> !fir.ref + %4 = fir.convert %0 : (!fir.ref>) -> !fir.ref> + %5 = fir.coordinate_of %4, %c4 : (!fir.ref>, index) -> !fir.ref + %6 = fir.convert %5 : (!fir.ref) -> !fir.ref + %7 = omp.map.info var_ptr(%3 : !fir.ref, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref {name = "var1"} + %8 = omp.map.info var_ptr(%6 : !fir.ref, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref {name = "var2"} + omp.target map_entries(%7 -> %arg0, %8 -> %arg1 : !fir.ref, !fir.ref) { + ^bb0(%arg0: !fir.ref, %arg1: !fir.ref): + %c10_i32 = arith.constant 10 : i32 + %9 = fir.load %arg0 : !fir.ref + %10 = arith.muli %9, %c10_i32 : i32 + fir.store %10 to %arg1 : !fir.ref + omp.terminator + } + return +} + +fir.global common @var_common_(dense<0> : vector<8xi8>) {alignment = 4 : i64} : !fir.array<8xi8> diff --git a/flang/test/Integration/OpenMP/map-types-and-sizes.f90 b/flang/test/Integration/OpenMP/map-types-and-sizes.f90 index f3a20690f05a9b..591be0b680a512 100644 --- a/flang/test/Integration/OpenMP/map-types-and-sizes.f90 +++ b/flang/test/Integration/OpenMP/map-types-and-sizes.f90 @@ -231,6 +231,31 @@ subroutine mapType_char !$omp end target end subroutine mapType_char +!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [1 x i64] [i64 8] +!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [1 x i64] [i64 35] +subroutine mapType_common_block + implicit none + common /var_common/ var1, var2 + integer :: var1, var2 +!$omp target map(tofrom: /var_common/) + var1 = var1 + 20 + var2 = var2 + 30 +!$omp end target +end subroutine mapType_common_block + +!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [2 x i64] [i64 4, i64 4] +!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [2 x i64] [i64 35, i64 35] +subroutine mapType_common_block_members + implicit none + common /var_common/ var1, var2 + integer :: var1, var2 + +!$omp target map(tofrom: var1, var2) + var2 = var1 +!$omp end target +end subroutine mapType_common_block_members + + !CHECK-LABEL: define {{.*}} @{{.*}}maptype_ptr_explicit_{{.*}} !CHECK: %[[ALLOCA:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8 }, i64 1, align 8 !CHECK: %[[ALLOCA_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8 }, ptr %[[ALLOCA]], i32 1 @@ -346,3 +371,19 @@ end subroutine mapType_char !CHECK: store ptr %[[ALLOCA]], ptr %[[BASE_PTR_ARR]], align 8 !CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [1 x ptr], ptr %.offload_ptrs, i32 0, i32 0 !CHECK: store ptr %[[ARR_OFF]], ptr %[[OFFLOAD_PTR_ARR]], align 8 + +!CHECK-LABEL: define {{.*}} @{{.*}}maptype_common_block_{{.*}} +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [1 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +!CHECK: store ptr @var_common_, ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [1 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +!CHECK: store ptr @var_common_, ptr %[[OFFLOAD_PTR_ARR]], align 8 + +!CHECK-LABEL: define {{.*}} @{{.*}}maptype_common_block_members_{{.*}} +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [2 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +!CHECK: store ptr @var_common_, ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [2 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +!CHECK: store ptr @var_common_, ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR_1:.*]] = getelementptr inbounds [2 x ptr], ptr %.offload_baseptrs, i32 0, i32 1 +!CHECK: store ptr getelementptr (i8, ptr @var_common_, i64 4), ptr %[[BASE_PTR_ARR_1]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR_1:.*]] = getelementptr inbounds [2 x ptr], ptr %.offload_ptrs, i32 0, i32 1 +!CHECK: store ptr getelementptr (i8, ptr @var_common_, i64 4), ptr %[[OFFLOAD_PTR_ARR_1]], align 8 diff --git a/flang/test/Integration/debug-char-type-1.f90 b/flang/test/Integration/debug-char-type-1.f90 index a0aebd3125c6e6..5068663aa9e28e 100644 --- a/flang/test/Integration/debug-char-type-1.f90 +++ b/flang/test/Integration/debug-char-type-1.f90 @@ -2,6 +2,7 @@ module helper character(len=40) :: str + character(len=:), allocatable :: str2 end module helper program test @@ -11,11 +12,14 @@ program test first = '3.14 = π' second = 'Fortran' str = 'Hello World!' + str2 = 'A quick brown fox jumps over a lazy dog' end program test ! CHECK-DAG: !DIGlobalVariable(name: "str"{{.*}}type: ![[TY40:[0-9]+]]{{.*}}) ! CHECK-DAG: ![[TY40]] = !DIStringType(size: 320, encoding: DW_ATE_ASCII) +! CHECK-DAG: !DIGlobalVariable(name: "str2"{{.*}}type: ![[TY:[0-9]+]]{{.*}}) +! CHECK-DAG: ![[TY]] = !DIStringType(stringLengthExpression: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 8), stringLocationExpression: !DIExpression(DW_OP_push_object_address, DW_OP_deref), encoding: DW_ATE_ASCII) ! CHECK-DAG: !DILocalVariable(name: "first"{{.*}}type: ![[TY8:[0-9]+]]) ! CHECK-DAG: ![[TY8]] = !DIStringType(size: 256, encoding: DW_ATE_UCS) ! CHECK-DAG: !DILocalVariable(name: "second"{{.*}}type: ![[TY10:[0-9]+]]) -! CHECK-DAG: ![[TY10]] = !DIStringType(size: 80, encoding: DW_ATE_ASCII) \ No newline at end of file +! CHECK-DAG: ![[TY10]] = !DIStringType(size: 80, encoding: DW_ATE_ASCII) diff --git a/flang/test/Integration/debug-ptr-type.f90 b/flang/test/Integration/debug-ptr-type.f90 new file mode 100644 index 00000000000000..bff7bcb862b5c3 --- /dev/null +++ b/flang/test/Integration/debug-ptr-type.f90 @@ -0,0 +1,48 @@ +! RUN: %flang_fc1 -emit-llvm -debug-info-kind=standalone %s -o - | FileCheck %s + +subroutine ff(n, m) + implicit none + integer i, j, m, n + real(4), pointer :: par(:, :) + integer, pointer :: psc + integer, pointer :: par2(:) + character(len=16), pointer :: pstr + real(4), target :: ar(4, 5) + integer, target :: sc + integer, target, allocatable :: ar2(:) + character(len=:), target, allocatable :: str + + str = 'Hello' + pstr => str + allocate(ar2(4)) + par2 => ar2 + do i=1,5 + do j=1,4 + ar(j,i) = 0.1 + par2(j) = j + end do + end do + sc = 3 + psc => sc + par => ar + + print *, sc + print *, ar + print *, ar2 + print *, str + print *, psc + print *, par + print *, par2 + print *, pstr +end subroutine ff + + +! CHECK-DAG: ![[INT_TY:[0-9]+]] = !DIBasicType(name: "integer"{{.*}}) +! CHECK-DAG: ![[ELEMS1:[0-9]+]] = !{!{{[0-9]+}}} +! CHECK-DAG: !DILocalVariable(name: "par"{{.*}}type: ![[ARR_TY1:[0-9]+]]) +! CHECK-DAG: ![[ARR_TY1]] = !DICompositeType(tag: DW_TAG_array_type{{.*}}elements: ![[ELEMS2:[0-9]+]], dataLocation: !DIExpression(DW_OP_push_object_address, DW_OP_deref), associated: !DIExpression(DW_OP_push_object_address, DW_OP_deref, DW_OP_lit0, DW_OP_ne)) +! CHECK-DAG: ![[ELEMS2]] = !{!{{[0-9]+}}, !{{[0-9]+}}} +! CHECK-DAG: !DILocalVariable(name: "par2"{{.*}}type: ![[ARR_TY2:[0-9]+]]) +! CHECK-DAG: ![[ARR_TY2]] = !DICompositeType(tag: DW_TAG_array_type{{.*}}, elements: ![[ELEMS1]], dataLocation: !DIExpression(DW_OP_push_object_address, DW_OP_deref), associated: !DIExpression(DW_OP_push_object_address, DW_OP_deref, DW_OP_lit0, DW_OP_ne)) +! CHECK-DAG: !DILocalVariable(name: "psc"{{.*}}type: ![[PTR_TY:[0-9]+]]) +! CHECK-DAG: ![[PTR_TY]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[INT_TY]]{{.*}}) diff --git a/flang/test/Lower/OpenMP/common-block-map.f90 b/flang/test/Lower/OpenMP/common-block-map.f90 new file mode 100644 index 00000000000000..5033129683a8eb --- /dev/null +++ b/flang/test/Lower/OpenMP/common-block-map.f90 @@ -0,0 +1,83 @@ +!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s + +!CHECK: fir.global common @var_common_(dense<0> : vector<8xi8>) {{.*}} : !fir.array<8xi8> +!CHECK: fir.global common @var_common_link_(dense<0> : vector<8xi8>) {{{.*}} omp.declare_target = #omp.declaretarget} : !fir.array<8xi8> + +!CHECK-LABEL: func.func @_QPmap_full_block +!CHECK: %[[CB_ADDR:.*]] = fir.address_of(@var_common_) : !fir.ref> +!CHECK: %[[MAP:.*]] = omp.map.info var_ptr(%[[CB_ADDR]] : !fir.ref>, !fir.array<8xi8>) map_clauses(tofrom) capture(ByRef) -> !fir.ref> {name = "var_common"} +!CHECK: omp.target map_entries(%[[MAP]] -> %[[MAP_ARG:.*]] : !fir.ref>) { +!CHECK: ^bb0(%[[MAP_ARG]]: !fir.ref>): +!CHECK: %[[CONV:.*]] = fir.convert %[[MAP_ARG]] : (!fir.ref>) -> !fir.ref> +!CHECK: %[[INDEX:.*]] = arith.constant 0 : index +!CHECK: %[[COORD:.*]] = fir.coordinate_of %[[CONV]], %[[INDEX]] : (!fir.ref>, index) -> !fir.ref +!CHECK: %[[CONV2:.*]] = fir.convert %[[COORD]] : (!fir.ref) -> !fir.ref +!CHECK: %[[CB_MEMBER_1:.*]]:2 = hlfir.declare %[[CONV2]] {uniq_name = "_QFmap_full_blockEvar1"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[CONV3:.*]] = fir.convert %[[MAP_ARG]] : (!fir.ref>) -> !fir.ref> +!CHECK: %[[INDEX2:.*]] = arith.constant 4 : index +!CHECK: %[[COORD2:.*]] = fir.coordinate_of %[[CONV3]], %[[INDEX2]] : (!fir.ref>, index) -> !fir.ref +!CHECK: %[[CONV4:.*]] = fir.convert %[[COORD2]] : (!fir.ref) -> !fir.ref +!CHECK: %[[CB_MEMBER_2:.*]]:2 = hlfir.declare %[[CONV4]] {uniq_name = "_QFmap_full_blockEvar2"} : (!fir.ref) -> (!fir.ref, !fir.ref) +subroutine map_full_block + implicit none + common /var_common/ var1, var2 + integer :: var1, var2 +!$omp target map(tofrom: /var_common/) + var1 = var1 + 20 + var2 = var2 + 30 +!$omp end target +end + +!CHECK-LABEL: @_QPmap_mix_of_members +!CHECK: %[[COMMON_BLOCK:.*]] = fir.address_of(@var_common_) : !fir.ref> +!CHECK: %[[CB_CONV:.*]] = fir.convert %[[COMMON_BLOCK]] : (!fir.ref>) -> !fir.ref> +!CHECK: %[[INDEX:.*]] = arith.constant 0 : index +!CHECK: %[[COORD:.*]] = fir.coordinate_of %[[CB_CONV]], %[[INDEX]] : (!fir.ref>, index) -> !fir.ref +!CHECK: %[[CONV:.*]] = fir.convert %[[COORD]] : (!fir.ref) -> !fir.ref +!CHECK: %[[CB_MEMBER_1:.*]]:2 = hlfir.declare %[[CONV]] {uniq_name = "_QFmap_mix_of_membersEvar1"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[CB_CONV:.*]] = fir.convert %[[COMMON_BLOCK]] : (!fir.ref>) -> !fir.ref> +!CHECK: %[[INDEX:.*]] = arith.constant 4 : index +!CHECK: %[[COORD:.*]] = fir.coordinate_of %[[CB_CONV]], %[[INDEX]] : (!fir.ref>, index) -> !fir.ref +!CHECK: %[[CONV:.*]] = fir.convert %[[COORD]] : (!fir.ref) -> !fir.ref +!CHECK: %[[CB_MEMBER_2:.*]]:2 = hlfir.declare %[[CONV]] {uniq_name = "_QFmap_mix_of_membersEvar2"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[MAP_EXP:.*]] = omp.map.info var_ptr(%[[CB_MEMBER_2]]#0 : !fir.ref, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref {name = "var2"} +!CHECK: %[[MAP_IMP:.*]] = omp.map.info var_ptr(%[[CB_MEMBER_1]]#1 : !fir.ref, i32) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) -> !fir.ref {name = "var1"} +!CHECK: omp.target map_entries(%[[MAP_EXP]] -> %[[ARG_EXP:.*]], %[[MAP_IMP]] -> %[[ARG_IMP:.*]] : !fir.ref, !fir.ref) { +!CHECK: ^bb0(%[[ARG_EXP]]: !fir.ref, %[[ARG_IMP]]: !fir.ref): +!CHECK: %[[EXP_MEMBER:.*]]:2 = hlfir.declare %[[ARG_EXP]] {uniq_name = "_QFmap_mix_of_membersEvar2"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[IMP_MEMBER:.*]]:2 = hlfir.declare %[[ARG_IMP]] {uniq_name = "_QFmap_mix_of_membersEvar1"} : (!fir.ref) -> (!fir.ref, !fir.ref) +subroutine map_mix_of_members + implicit none + common /var_common/ var1, var2 + integer :: var1, var2 + +!$omp target map(tofrom: var2) + var2 = var1 +!$omp end target +end + +!CHECK-LABEL: @_QQmain +!CHECK: %[[DECL_TAR_CB:.*]] = fir.address_of(@var_common_link_) : !fir.ref> +!CHECK: %[[MAP_DECL_TAR_CB:.*]] = omp.map.info var_ptr(%[[DECL_TAR_CB]] : !fir.ref>, !fir.array<8xi8>) map_clauses(tofrom) capture(ByRef) -> !fir.ref> {name = "var_common_link"} +!CHECK: omp.target map_entries(%[[MAP_DECL_TAR_CB]] -> %[[MAP_DECL_TAR_ARG:.*]] : !fir.ref>) { +!CHECK: ^bb0(%[[MAP_DECL_TAR_ARG]]: !fir.ref>): +!CHECK: %[[CONV:.*]] = fir.convert %[[MAP_DECL_TAR_ARG]] : (!fir.ref>) -> !fir.ref> +!CHECK: %[[INDEX:.*]] = arith.constant 0 : index +!CHECK: %[[COORD:.*]] = fir.coordinate_of %[[CONV]], %[[INDEX]] : (!fir.ref>, index) -> !fir.ref +!CHECK: %[[CONV:.*]] = fir.convert %[[COORD]] : (!fir.ref) -> !fir.ref +!CHECK: %[[MEMBER_ONE:.*]]:2 = hlfir.declare %[[CONV]] {uniq_name = "_QFElink1"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[CONV:.*]] = fir.convert %[[MAP_DECL_TAR_ARG]] : (!fir.ref>) -> !fir.ref> +!CHECK: %[[INDEX:.*]] = arith.constant 4 : index +!CHECK: %[[COORD:.*]] = fir.coordinate_of %[[CONV]], %[[INDEX]] : (!fir.ref>, index) -> !fir.ref +!CHECK: %[[CONV:.*]] = fir.convert %[[COORD]] : (!fir.ref) -> !fir.ref +!CHECK: %[[MEMBER_TWO:.*]]:2 = hlfir.declare %[[CONV]] {uniq_name = "_QFElink2"} : (!fir.ref) -> (!fir.ref, !fir.ref) +program main + implicit none + common /var_common_link/ link1, link2 + integer :: link1, link2 + !$omp declare target link(/var_common_link/) + +!$omp target map(tofrom: /var_common_link/) + link1 = link2 + 20 +!$omp end target +end program diff --git a/flang/test/Lower/OpenMP/copyprivate2.f90 b/flang/test/Lower/OpenMP/copyprivate2.f90 new file mode 100644 index 00000000000000..f10d509d805e29 --- /dev/null +++ b/flang/test/Lower/OpenMP/copyprivate2.f90 @@ -0,0 +1,56 @@ +! Test lowering of COPYPRIVATE with allocatable/pointer variables. +! RUN: %flang_fc1 -emit-hlfir -fopenmp -o - %s 2>&1 | FileCheck %s + +!CHECK-LABEL: func private @_copy_box_ptr_i32( +!CHECK-SAME: %[[ARG0:.*]]: !fir.ref>>, +!CHECK-SAME: %[[ARG1:.*]]: !fir.ref>>) { +!CHECK-NEXT: %[[DST:.*]]:2 = hlfir.declare %[[ARG0]] {fortran_attrs = #fir.var_attrs, +!CHECK-SAME: uniq_name = "_copy_box_ptr_i32_dst"} : (!fir.ref>>) -> +!CHECK-SAME: (!fir.ref>>, !fir.ref>>) +!CHECK-NEXT: %[[SRC:.*]]:2 = hlfir.declare %[[ARG1]] {fortran_attrs = #fir.var_attrs, +!CHECK-SAME: uniq_name = "_copy_box_ptr_i32_src"} : (!fir.ref>>) -> +!CHECK-SAME: (!fir.ref>>, !fir.ref>>) +!CHECK-NEXT: %[[SRC_VAL:.*]] = fir.load %[[SRC]]#0 : !fir.ref>> +!CHECK-NEXT: fir.store %[[SRC_VAL]] to %[[DST]]#0 : !fir.ref>> +!CHECK-NEXT: return +!CHECK-NEXT: } + +!CHECK-LABEL: func private @_copy_box_heap_Uxi32( +!CHECK-SAME: %[[ARG0:.*]]: !fir.ref>>>, +!CHECK-SAME: %[[ARG1:.*]]: !fir.ref>>>) { +!CHECK-NEXT: %[[DST:.*]]:2 = hlfir.declare %[[ARG0]] {fortran_attrs = #fir.var_attrs, +!CHECK-SAME: uniq_name = "_copy_box_heap_Uxi32_dst"} : (!fir.ref>>>) -> +!CHECK-SAME: (!fir.ref>>>, !fir.ref>>>) +!CHECK-NEXT: %[[SRC:.*]]:2 = hlfir.declare %[[ARG1]] {fortran_attrs = #fir.var_attrs, +!CHECK-SAME: uniq_name = "_copy_box_heap_Uxi32_src"} : (!fir.ref>>>) -> +!CHECK-SAME: (!fir.ref>>>, !fir.ref>>>) +!CHECK-NEXT: %[[DST_BOX:.*]] = fir.load %[[DST]]#0 : !fir.ref>>> +!CHECK: fir.if %{{.*}} { +!CHECK-NEXT: %[[SRC_BOX:.*]] = fir.load %[[SRC]]#0 : !fir.ref>>> +!CHECK-NEXT: hlfir.assign %[[SRC_BOX]] to %[[DST_BOX]] temporary_lhs : !fir.box>>, +!CHECK-SAME: !fir.box>> +!CHECK-NEXT: } +!CHECK-NEXT: return +!CHECK-NEXT: } + +!CHECK-LABEL: func @_QPtest_alloc_ptr +!CHECK: omp.parallel { +!CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}} {fortran_attrs = #fir.var_attrs, +!CHECK-SAME: uniq_name = "_QFtest_alloc_ptrEa"} : (!fir.ref>>>) -> +!CHECK-SAME: (!fir.ref>>>, !fir.ref>>>) +!CHECK: %[[P:.*]]:2 = hlfir.declare %{{.*}} {fortran_attrs = #fir.var_attrs, +!CHECK-SAME: uniq_name = "_QFtest_alloc_ptrEp"} : (!fir.ref>>) -> +!CHECK-SAME: (!fir.ref>>, !fir.ref>>) +!CHECK: omp.single copyprivate( +!CHECK-SAME: %[[A]]#0 -> @_copy_box_heap_Uxi32 : !fir.ref>>>, +!CHECK-SAME: %[[P]]#0 -> @_copy_box_ptr_i32 : !fir.ref>>) +!CHEK: } +subroutine test_alloc_ptr() + integer, allocatable :: a(:) + integer, pointer :: p + + !$omp parallel private(a, p) + !$omp single + !$omp end single copyprivate(a, p) + !$omp end parallel +end subroutine diff --git a/flang/test/Lower/OpenMP/order-clause.f90 b/flang/test/Lower/OpenMP/order-clause.f90 new file mode 100644 index 00000000000000..717d9740c56f80 --- /dev/null +++ b/flang/test/Lower/OpenMP/order-clause.f90 @@ -0,0 +1,76 @@ +! This test checks lowering of OpenMP order clause. + +!RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck %s + +!CHECK-LABEL: func.func @_QPsimd_order() { +subroutine simd_order + !CHECK: omp.simd order(reproducible:concurrent) { + !$omp simd order(concurrent) + do i = 1, 10 + end do + !CHECK: omp.simd order(reproducible:concurrent) { + !$omp simd order(reproducible:concurrent) + do i = 1, 10 + end do + !CHECK: omp.simd order(unconstrained:concurrent) { + !$omp simd order(unconstrained:concurrent) + do i = 1, 10 + end do +end subroutine simd_order + +!CHECK-LABEL: func.func @_QPdo_order() { +subroutine do_order + !CHECK: omp.wsloop order(reproducible:concurrent) { + !$omp do order(concurrent) + do i = 1, 10 + end do + !CHECK: omp.wsloop order(reproducible:concurrent) { + !$omp do order(reproducible:concurrent) + do i = 1, 10 + end do + !CHECK: omp.wsloop order(unconstrained:concurrent) { + !$omp do order(unconstrained:concurrent) + do i = 1, 10 + end do +end subroutine do_order + +!CHECK-LABEL: func.func @_QPdo_simd_order() { +subroutine do_simd_order + !CHECK: omp.wsloop order(reproducible:concurrent) { + !$omp do simd order(concurrent) + do i = 1, 10 + end do + !CHECK: omp.wsloop order(reproducible:concurrent) { + !$omp do simd order(reproducible:concurrent) + do i = 1, 10 + end do + !CHECK: omp.wsloop order(unconstrained:concurrent) { + !$omp do simd order(unconstrained:concurrent) + do i = 1, 10 + end do +end subroutine do_simd_order + +!CHECK-LABEL: func.func @_QPdo_simd_order_parallel() { +subroutine do_simd_order_parallel + !CHECK: omp.parallel { + !CHECK: omp.wsloop order(reproducible:concurrent) { + !$omp parallel do simd order(reproducible:concurrent) + do i = 1, 10 + end do +end subroutine do_simd_order_parallel + + +subroutine distribute_order + !CHECK: omp.distribute order(reproducible:concurrent) { + !$omp teams distribute order(concurrent) + do i=1,10 + end do + !CHECK: omp.distribute order(reproducible:concurrent) { + !$omp teams distribute order(reproducible:concurrent) + do i=1,10 + end do + !CHECK: omp.distribute order(unconstrained:concurrent) { + !$omp teams distribute order(unconstrained:concurrent) + do i = 1, 10 + end do +end subroutine diff --git a/flang/test/Lower/character-local-variables.f90 b/flang/test/Lower/character-local-variables.f90 index 0cf61a2623c4e7..d5b959eca1ff63 100644 --- a/flang/test/Lower/character-local-variables.f90 +++ b/flang/test/Lower/character-local-variables.f90 @@ -1,4 +1,6 @@ ! RUN: bbc -hlfir=false %s -o - | FileCheck %s +! RUN: bbc -hlfir=false --enable-constant-argument-globalisation %s -o - \ +! RUN: | FileCheck %s --check-prefix=CHECK-CONST ! Test lowering of local character variables @@ -118,7 +120,8 @@ subroutine assumed_length_param(n) integer :: n ! CHECK: %[[c4:.*]] = arith.constant 4 : i64 ! CHECK: fir.store %[[c4]] to %[[tmp:.*]] : !fir.ref - ! CHECK: fir.call @_QPtake_int(%[[tmp]]) {{.*}}: (!fir.ref) -> () + ! CHECK-CONST: %[[tmp:.*]] = fir.address_of(@_global_const_.{{.*}}) : !fir.ref + ! CHECK-CONST: fir.call @_QPtake_int(%[[tmp]]) {{.*}}: (!fir.ref) -> () call take_int(len(c(n), kind=8)) end diff --git a/flang/test/Preprocessing/cond-contin.F90 b/flang/test/Preprocessing/cond-contin.F90 new file mode 100644 index 00000000000000..9221e34e013f40 --- /dev/null +++ b/flang/test/Preprocessing/cond-contin.F90 @@ -0,0 +1,21 @@ +! RUN: %flang_fc1 -E %s 2>&1 | FileCheck %s +! CHECK: subroutine test(ARG1, FA, FB, ARG2) +! CHECK: end + +subroutine test( & +ARG1, & +! test +#ifndef SWAP +#define ARG1 FA +#define ARG2 FB +#else +#define ARG1 FB +#define ARG2 FA +#endif +ARG1, ARG2, & +! test +#undef ARG1 +#undef ARG2 +&ARG2) +! comment +end diff --git a/flang/test/Preprocessing/inc-contin-1.F b/flang/test/Preprocessing/inc-contin-1.F new file mode 100644 index 00000000000000..7a4e3a0cb0b59b --- /dev/null +++ b/flang/test/Preprocessing/inc-contin-1.F @@ -0,0 +1,6 @@ +! RUN: %flang_fc1 -E %s 2>&1 | FileCheck %s +! CHECK: call t(1 ,.false.) + program main +#include "inc-contin-1.h" + $,.false.) + end diff --git a/flang/test/Preprocessing/inc-contin-1.h b/flang/test/Preprocessing/inc-contin-1.h new file mode 100644 index 00000000000000..d4b6461e75274f --- /dev/null +++ b/flang/test/Preprocessing/inc-contin-1.h @@ -0,0 +1 @@ + call t(1 diff --git a/flang/test/Preprocessing/inc-contin-2.F90 b/flang/test/Preprocessing/inc-contin-2.F90 new file mode 100644 index 00000000000000..3386ee0dfcddc4 --- /dev/null +++ b/flang/test/Preprocessing/inc-contin-2.F90 @@ -0,0 +1,9 @@ +! RUN: %flang_fc1 -E %s 2>&1 | FileCheck %s +! CHECK: print *, 3.14159 +! CHECK: print *, 3. 14159 + program main +#include "inc-contin-2a.h" + &14159 +#include "inc-contin-2b.h" + &14159 + end program main diff --git a/flang/test/Preprocessing/inc-contin-2a.h b/flang/test/Preprocessing/inc-contin-2a.h new file mode 100644 index 00000000000000..24a4fa4830fa3b --- /dev/null +++ b/flang/test/Preprocessing/inc-contin-2a.h @@ -0,0 +1 @@ +print *, 3.& diff --git a/flang/test/Preprocessing/inc-contin-2b.h b/flang/test/Preprocessing/inc-contin-2b.h new file mode 100644 index 00000000000000..b84a464af86e33 --- /dev/null +++ b/flang/test/Preprocessing/inc-contin-2b.h @@ -0,0 +1 @@ +print *, 3. & diff --git a/flang/test/Preprocessing/include-args.F90 b/flang/test/Preprocessing/include-args.F90 index 011e4dba13e730..7c521db666ff9a 100644 --- a/flang/test/Preprocessing/include-args.F90 +++ b/flang/test/Preprocessing/include-args.F90 @@ -1,5 +1,5 @@ ! RUN: %flang -E %s 2>&1 | FileCheck %s -! CHECK: call foo(3.14159) +! CHECK: call foo(3.14159 ) call foo (& #include "args.h" ) diff --git a/flang/test/Preprocessing/kw-in-char.F90 b/flang/test/Preprocessing/kw-in-char.F90 new file mode 100644 index 00000000000000..e8f3a33b8a7498 --- /dev/null +++ b/flang/test/Preprocessing/kw-in-char.F90 @@ -0,0 +1,14 @@ +! RUN: %flang -E %s 2>&1 | FileCheck %s +! CHECK: subroutine test_b_wrapper_c() bind(C, name="test_b_c_f") +#define TEMP_LETTER b +#define VAL c +subroutine test_& +TEMP_LETTER& +_wrapper_& +VAL& + () bind(C, name="test_& + &TEMP_LETTER& + &_& + &VAL& + &_f") +end diff --git a/flang/test/Preprocessing/sentinel-after-semi.F90 b/flang/test/Preprocessing/sentinel-after-semi.F90 new file mode 100644 index 00000000000000..75060ac1db0328 --- /dev/null +++ b/flang/test/Preprocessing/sentinel-after-semi.F90 @@ -0,0 +1,7 @@ +! RUN: %flang_fc1 -fdebug-unparse -fopenacc %s 2>&1 | FileCheck %s +! CHECK: !$ACC DECLARE COPYIN(var) +#define ACCDECLARE(var) integer :: var; \ + !$acc declare copyin(var) +program main + ACCDECLARE(var) +end program diff --git a/flang/test/Semantics/boz-literal-constants.f90 b/flang/test/Semantics/boz-literal-constants.f90 index e6392f6f030e52..ee6919cb9ecd5c 100644 --- a/flang/test/Semantics/boz-literal-constants.f90 +++ b/flang/test/Semantics/boz-literal-constants.f90 @@ -7,7 +7,12 @@ subroutine bozchecks integer :: f, realpart = B"0101", img = B"1111", resint logical :: resbit complex :: rescmplx + character :: reschar real :: dbl, e + type :: dt + integer :: n + end type + type(dt) :: resdt interface subroutine explicit(n, x, c) integer :: n @@ -98,6 +103,17 @@ subroutine explicit(n, x, c) res = REAL(B"1101") + resint = z'ff' ! ok + res = z'3f800000' ! ok + !ERROR: Right-hand side of this assignment may not be BOZ + rescmplx = z'123' + !ERROR: Right-hand side of this assignment may not be BOZ + resbit = z'123' + !ERROR: Right-hand side of this assignment may not be BOZ + reschar = z'123' + !ERROR: Right-hand side of this assignment may not be BOZ + resdt = z'123' + !Ok call explicit(z'deadbeef', o'666', 'a') diff --git a/flang/test/Semantics/c_loc01.f90 b/flang/test/Semantics/c_loc01.f90 index 7c9e2941729938..83b88d2ebd4b0f 100644 --- a/flang/test/Semantics/c_loc01.f90 +++ b/flang/test/Semantics/c_loc01.f90 @@ -4,7 +4,10 @@ module m type haslen(L) integer, len :: L end type + integer, target :: targ contains + subroutine subr + end subroutine test(assumedType, poly, nclen) type(*), target :: assumedType class(*), target :: poly @@ -17,6 +20,8 @@ subroutine test(assumedType, poly, nclen) type(hasLen(1)), target :: clen type(hasLen(*)), target :: nclen character(2), target :: ch + real :: arr1(purefun1(c_loc(targ))) ! ok + real :: arr2(purefun2(c_funloc(subr))) ! ok !ERROR: C_LOC() argument must be a data pointer or target cp = c_loc(notATarget) !ERROR: C_LOC() argument must be a data pointer or target @@ -44,4 +49,12 @@ subroutine test(assumedType, poly, nclen) !ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches operand types TYPE(c_funptr) and TYPE(c_ptr) cfp = cp end + pure integer function purefun1(p) + type(c_ptr), intent(in) :: p + purefun1 = 1 + end + pure integer function purefun2(p) + type(c_funptr), intent(in) :: p + purefun2 = 1 + end end module diff --git a/flang/test/Semantics/call05.f90 b/flang/test/Semantics/call05.f90 index 71f2197067f76c..8a4386e28e2bcc 100644 --- a/flang/test/Semantics/call05.f90 +++ b/flang/test/Semantics/call05.f90 @@ -123,9 +123,7 @@ subroutine test module m2 - !ERROR: Procedure 't3' may not be ALLOCATABLE without an explicit interface character(len=10), allocatable :: t1, t2, t3, t4 - !ERROR: Procedure 't6' may not be ALLOCATABLE without an explicit interface character(len=:), allocatable :: t5, t6, t7, t8(:) character(len=10), pointer :: p1 @@ -189,7 +187,7 @@ subroutine test() !ERROR: ALLOCATABLE dummy argument 'a=' must be associated with an ALLOCATABLE actual argument call sma(t2(:)) - !ERROR: ALLOCATABLE dummy argument 'a=' must be associated with an ALLOCATABLE actual argument + !ERROR: 't3' is not a callable procedure call sma(t3(1)) !ERROR: ALLOCATABLE dummy argument 'a=' must be associated with an ALLOCATABLE actual argument @@ -208,7 +206,7 @@ subroutine test() !ERROR: ALLOCATABLE dummy argument 'a=' must be associated with an ALLOCATABLE actual argument call sma(t5(:)) - !ERROR: ALLOCATABLE dummy argument 'a=' must be associated with an ALLOCATABLE actual argument + !ERROR: 't6' is not a callable procedure call sma(t6(1)) !ERROR: ALLOCATABLE dummy argument 'a=' must be associated with an ALLOCATABLE actual argument diff --git a/flang/test/Semantics/select-rank03.f90 b/flang/test/Semantics/select-rank03.f90 index 8a965e950d3851..77b76f5f584ca2 100644 --- a/flang/test/Semantics/select-rank03.f90 +++ b/flang/test/Semantics/select-rank03.f90 @@ -52,10 +52,12 @@ subroutine allocatables(a) !ERROR: Whole assumed-size array 'a' may not appear here without subscripts a = 1. rank default - !ERROR: An assumed-rank object may not appear in an ALLOCATE statement + !ERROR: An assumed-rank dummy argument may not appear in an ALLOCATE statement allocate(a) deallocate(a) - a = 1. + !ERROR: An assumed-rank dummy argument is not allowed in an assignment statement + !ERROR: An assumed-rank dummy argument is not allowed as an operand here + a = a + 1. end select ! Test nested associations select rank(a) @@ -121,11 +123,13 @@ subroutine pointers(p) !ERROR: Whole assumed-size array 'p' may not appear here without subscripts deallocate(p) rank default - !ERROR: An assumed-rank object may not appear in an ALLOCATE statement + !ERROR: An assumed-rank dummy argument may not appear in an ALLOCATE statement allocate(p) deallocate(p) + !ERROR: The left-hand side of a pointer assignment must not be an assumed-rank dummy argument !ERROR: pointer 'p' associated with object 't0' with incompatible type or shape p => t0 + !ERROR: The left-hand side of a pointer assignment must not be an assumed-rank dummy argument !ERROR: pointer 'p' associated with object 't1' with incompatible type or shape p => t1 end select diff --git a/flang/test/Transforms/constant-argument-globalisation-2.fir b/flang/test/Transforms/constant-argument-globalisation-2.fir new file mode 100644 index 00000000000000..03e08a0dcb914b --- /dev/null +++ b/flang/test/Transforms/constant-argument-globalisation-2.fir @@ -0,0 +1,98 @@ +// RUN: fir-opt --split-input-file --constant-argument-globalisation-opt < %s | FileCheck %s + +module { +// Test for "two conditional writes to the same alloca doesn't get replaced." + func.func @func(%arg0: i32, %arg1: i1) { + %c2_i32 = arith.constant 2 : i32 + %addr = fir.alloca i32 {adapt.valuebyref} + fir.if %arg1 { + fir.store %c2_i32 to %addr : !fir.ref + } else { + fir.store %arg0 to %addr : !fir.ref + } + fir.call @sub2(%addr) : (!fir.ref) -> () + return + } + func.func private @sub2(!fir.ref) + +// CHECK-LABEL: func.func @func +// CHECK-SAME: [[ARG0:%.*]]: i32 +// CHECK-SAME: [[ARG1:%.*]]: i1) +// CHECK: [[CONST:%.*]] = arith.constant +// CHECK: [[ADDR:%.*]] = fir.alloca i32 +// CHECK: fir.if [[ARG1]] +// CHECK: fir.store [[CONST]] to [[ADDR]] +// CHECK: } else { +// CHECK: fir.store [[ARG0]] to [[ADDR]] +// CHECK: fir.call @sub2([[ADDR]]) +// CHECK: return + +} + +// ----- + +module { +// Test for "two writes to the same alloca doesn't get replaced." + func.func @func() { + %c1_i32 = arith.constant 1 : i32 + %c2_i32 = arith.constant 2 : i32 + %addr = fir.alloca i32 {adapt.valuebyref} + fir.store %c1_i32 to %addr : !fir.ref + fir.store %c2_i32 to %addr : !fir.ref + fir.call @sub2(%addr) : (!fir.ref) -> () + return + } + func.func private @sub2(!fir.ref) + +// CHECK-LABEL: func.func @func +// CHECK: [[CONST1:%.*]] = arith.constant +// CHECK: [[CONST2:%.*]] = arith.constant +// CHECK: [[ADDR:%.*]] = fir.alloca i32 +// CHECK: fir.store [[CONST1]] to [[ADDR]] +// CHECK: fir.store [[CONST2]] to [[ADDR]] +// CHECK: fir.call @sub2([[ADDR]]) +// CHECK: return + +} + +// ----- + +module { +// Test for "one write to the the alloca gets replaced." + func.func @func() { + %c1_i32 = arith.constant 1 : i32 + %addr = fir.alloca i32 {adapt.valuebyref} + fir.store %c1_i32 to %addr : !fir.ref + fir.call @sub2(%addr) : (!fir.ref) -> () + return + } + func.func private @sub2(!fir.ref) + +// CHECK-LABEL: func.func @func +// CHECK: [[ADDR:%.*]] = fir.address_of([[EXTR:@.*]]) : !fir.ref +// CHECK: fir.call @sub2([[ADDR]]) +// CHECK: return +// CHECK: fir.global internal [[EXTR]] constant : i32 { +// CHECK: %{{.*}} = arith.constant 1 : i32 +// CHECK: fir.has_value %{{.*}} : i32 +// CHECK: } + +} + +// ----- +// Check that same argument used twice is converted. +module { + func.func @func(%arg0: !fir.ref, %arg1: i1) { + %c2_i32 = arith.constant 2 : i32 + %addr1 = fir.alloca i32 {adapt.valuebyref} + fir.store %c2_i32 to %addr1 : !fir.ref + fir.call @sub1(%addr1, %addr1) : (!fir.ref, !fir.ref) -> () + return + } +} + +// CHECK-LABEL: func.func @func +// CHECK-NEXT: %[[ARG1:.*]] = fir.address_of([[CONST1:@.*]]) : !fir.ref +// CHECK-NEXT: %[[ARG2:.*]] = fir.address_of([[CONST2:@.*]]) : !fir.ref +// CHECK-NEXT: fir.call @sub1(%[[ARG1]], %[[ARG2]]) +// CHECK-NEXT: return diff --git a/flang/test/Transforms/constant-argument-globalisation.fir b/flang/test/Transforms/constant-argument-globalisation.fir new file mode 100644 index 00000000000000..553c3c6c248458 --- /dev/null +++ b/flang/test/Transforms/constant-argument-globalisation.fir @@ -0,0 +1,67 @@ +// RUN: fir-opt --constant-argument-globalisation-opt < %s | FileCheck %s +// RUN: %flang_fc1 -emit-llvm -flang-deprecated-no-hlfir -O2 -o - %s | FileCheck --check-prefix=DISABLE %s +module { + func.func @sub1(%arg0: !fir.ref {fir.bindc_name = "x"}, %arg1: !fir.ref {fir.bindc_name = "y"}) { + %0 = fir.alloca i32 {adapt.valuebyref} + %1 = fir.alloca f64 {adapt.valuebyref} + %2 = fir.alloca f64 {adapt.valuebyref} + %c1_i32 = arith.constant 1 : i32 + %cst = arith.constant 1.000000e+00 : f64 + %cst_0 = arith.constant 0.000000e+00 : f64 + %3 = fir.declare %arg0 {uniq_name = "_QFsub1Ex"} : (!fir.ref) -> !fir.ref + %4 = fir.declare %arg1 {uniq_name = "_QFsub1Ey"} : (!fir.ref) -> !fir.ref + fir.store %cst_0 to %2 : !fir.ref + %false = arith.constant false + fir.store %cst to %1 : !fir.ref + %false_1 = arith.constant false + fir.store %c1_i32 to %0 : !fir.ref + %false_2 = arith.constant false + fir.call @sub2(%2, %1, %3, %4, %0) fastmath : (!fir.ref, !fir.ref, !fir.ref, !fir.ref, !fir.ref) -> () + return + } + func.func private @sub2(!fir.ref, !fir.ref, !fir.ref, !fir.ref, !fir.ref) + +// CHECK-LABEL: func.func @sub1( +// CHECK-SAME: [[ARG0:%.*]]: !fir.ref {{{.*}}}, +// CHECK-SAME: [[ARG1:%.*]]: !fir.ref {{{.*}}}) { +// CHECK: [[X:%.*]] = fir.declare [[ARG0]] {{.*}} +// CHECK: [[Y:%.*]] = fir.declare [[ARG1]] {{.*}} +// CHECK: [[CONST_R0:%.*]] = fir.address_of([[EXTR_0:@.*]]) : !fir.ref +// CHECK: [[CONST_R1:%.*]] = fir.address_of([[EXTR_1:@.*]]) : !fir.ref +// CHECK: [[CONST_I:%.*]] = fir.address_of([[EXTR_2:@.*]]) : !fir.ref +// CHECK: fir.call @sub2([[CONST_R0]], [[CONST_R1]], [[X]], [[Y]], [[CONST_I]]) +// CHECK-SAME: fastmath +// CHECK: return + +// CHECK: fir.global internal [[EXTR_0]] constant : f64 { +// CHECK: %{{.*}} = arith.constant 0.000000e+00 : f64 +// CHECK: fir.has_value %{{.*}} : f64 +// CHECK: } +// CHECK: fir.global internal [[EXTR_1]] constant : f64 { +// CHECK: %{{.*}} = arith.constant 1.000000e+00 : f64 +// CHECK: fir.has_value %{{.*}} : f64 +// CHECK: } +// CHECK: fir.global internal [[EXTR_2]] constant : i32 { +// CHECK: %{{.*}} = arith.constant 1 : i32 +// CHECK: fir.has_value %{{.*}} : i32 +// CHECK: } + +// DISABLE-LABEL: ; ModuleID = +// DISABLE-NOT: @_extruded +// DISABLE: define void @sub1( +// DISABLE-SAME: ptr [[ARG0:%.*]], +// DISABLE-SAME: ptr [[ARG1:%.*]]) +// DISABLE-SAME: { +// DISABLE: [[CONST_R0:%.*]] = alloca double +// DISABLE: [[CONST_R1:%.*]] = alloca double +// DISABLE: [[CONST_I:%.*]] = alloca i32 +// DISABLE: store double 0.0{{.*}}+00, ptr [[CONST_R0]] +// DISABLE: store double 1.0{{.*}}+00, ptr [[CONST_R1]] +// DISABLE: store i32 1, ptr [[CONST_I]] +// DISABLE: call void @sub2(ptr nonnull [[CONST_R0]], +// DISABLE-SAME: ptr nonnull [[CONST_R1]], +// DISABLE-SAME: ptr [[ARG0]], ptr [[ARG1]], +// DISABLE-SAME: ptr nonnull [[CONST_I]]) +// DISABLE: ret void +// DISABLE: } +} diff --git a/flang/test/Transforms/debug-char-type-1.fir b/flang/test/Transforms/debug-char-type-1.fir index cdce3b7b8b3340..630b52d96cb858 100644 --- a/flang/test/Transforms/debug-char-type-1.fir +++ b/flang/test/Transforms/debug-char-type-1.fir @@ -9,6 +9,12 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<>} { %0 = fir.zero_bits !fir.char<4,20> fir.has_value %0 : !fir.char<4,20> } loc(#loc1) + fir.global @_QMhelperEstr3 : !fir.box>> { + %c0 = arith.constant 0 : index + %0 = fir.zero_bits !fir.heap> + %1 = fir.embox %0 typeparams %c0 : (!fir.heap>, index) -> !fir.box>> + fir.has_value %1 : !fir.box>> + } loc(#loc1) } #loc1 = loc("string.f90":1:1) @@ -16,4 +22,5 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<>} { // CHECK-DAG: #llvm.di_global_variable<{{.*}}name = "str1"{{.*}}type = #[[TY1]]{{.*}}> // CHECK-DAG: #[[TY2:.*]] = #llvm.di_string_type // CHECK-DAG: #llvm.di_global_variable<{{.*}}name = "str2"{{.*}}type = #[[TY2]]{{.*}}> - +// CHECK-DAG: #[[TY3:.*]] = #llvm.di_string_type, stringLocationExp = <[DW_OP_push_object_address, DW_OP_deref]>, encoding = DW_ATE_ASCII> +// CHECK-DAG: #llvm.di_global_variable<{{.*}}name = "str3"{{.*}}type = #[[TY3]]{{.*}}> diff --git a/flang/test/Transforms/debug-ptr-type.fir b/flang/test/Transforms/debug-ptr-type.fir new file mode 100644 index 00000000000000..3f6c895ddaf8eb --- /dev/null +++ b/flang/test/Transforms/debug-ptr-type.fir @@ -0,0 +1,40 @@ +// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s | FileCheck %s + +module attributes {dlti.dl_spec = #dlti.dl_spec<>} { + fir.global @_QMhelperEpar : !fir.box>> { + %0 = fir.zero_bits !fir.ptr> + %c0 = arith.constant 0 : index + %1 = fir.shape %c0, %c0 : (index, index) -> !fir.shape<2> + %2 = fir.embox %0(%1) : (!fir.ptr>, !fir.shape<2>) -> !fir.box>> + fir.has_value %2 : !fir.box>> + } loc(#loc1) + fir.global @_QMhelperEpar2 : !fir.box>> { + %0 = fir.zero_bits !fir.ptr> + %c0 = arith.constant 0 : index + %1 = fir.shape %c0 : (index) -> !fir.shape<1> + %2 = fir.embox %0(%1) : (!fir.ptr>, !fir.shape<1>) -> !fir.box>> + fir.has_value %2 : !fir.box>> + } loc(#loc2) + fir.global @_QMhelperEpsc : !fir.box> { + %0 = fir.zero_bits !fir.ptr + %1 = fir.embox %0 : (!fir.ptr) -> !fir.box> + fir.has_value %1 : !fir.box> + } loc(#loc3) + fir.global @_QMmEpstr : !fir.box>> { + %0 = fir.zero_bits !fir.ptr> + %1 = fir.embox %0 : (!fir.ptr>) -> !fir.box>> + fir.has_value %1 : !fir.box>> + } loc(#loc4) +} +#loc1 = loc("test.f90":5:1) +#loc2 = loc("test.f90":6:1) +#loc3 = loc("test.f90":7:1) +#loc4 = loc("test.f90":8:1) + +// CHECK-DAG: #[[INT_TY:.*]] = #llvm.di_basic_type +// CHECK-DAG: #[[ARR1_TY:.*]] = #llvm.di_composite_type, #llvm.di_subrange, dataLocation = {{.*}}, associated = <[DW_OP_push_object_address, DW_OP_deref, DW_OP_lit0, DW_OP_ne]>> +// CHECK-DAG: #[[ARR2_TY:.*]] = #llvm.di_composite_type, dataLocation = {{.*}}, associated = <[DW_OP_push_object_address, DW_OP_deref, DW_OP_lit0, DW_OP_ne]>> +// CHECK-DAG: #[[PTR_TY:.*]] = #llvm.di_derived_type +// CHECK-DAG: #llvm.di_global_variable<{{.*}}name = "par"{{.*}}type = #[[ARR1_TY]]{{.*}}> +// CHECK-DAG: #llvm.di_global_variable<{{.*}}name = "par2"{{.*}}type = #[[ARR2_TY]]{{.*}}> +// CHECK-DAG: #llvm.di_global_variable<{{.*}}name = "psc"{{.*}}type = #[[PTR_TY]]{{.*}}> diff --git a/flang/unittests/Evaluate/intrinsics.cpp b/flang/unittests/Evaluate/intrinsics.cpp index 0bbc7fede699aa..86c471d2c62950 100644 --- a/flang/unittests/Evaluate/intrinsics.cpp +++ b/flang/unittests/Evaluate/intrinsics.cpp @@ -344,6 +344,7 @@ void TestIntrinsics() { TEST(table.GetGenericIntrinsicName("dcos") == "cos"); TEST(table.GetGenericIntrinsicName("dcosh") == "cosh"); TEST(table.GetGenericIntrinsicName("ddim") == "dim"); + TEST(table.GetGenericIntrinsicName("derf") == "erf"); TEST(table.GetGenericIntrinsicName("dexp") == "exp"); TEST(table.GetGenericIntrinsicName("dint") == "aint"); TEST(table.GetGenericIntrinsicName("dlog") == "log"); diff --git a/flang/unittests/Frontend/FrontendActionTest.cpp b/flang/unittests/Frontend/FrontendActionTest.cpp index 123f428cc8b40b..bdf5a23fdbf6a7 100644 --- a/flang/unittests/Frontend/FrontendActionTest.cpp +++ b/flang/unittests/Frontend/FrontendActionTest.cpp @@ -143,7 +143,7 @@ TEST_F(FrontendActionTest, PrintPreprocessedInput) { EXPECT_TRUE(success); EXPECT_TRUE(!outputFileBuffer.empty()); EXPECT_TRUE( - llvm::StringRef(outputFileBuffer.data()).starts_with("program b\n")); + llvm::StringRef(outputFileBuffer.data()).starts_with(" program b\n")); } TEST_F(FrontendActionTest, ParseSyntaxOnly) { diff --git a/flang/unittests/Runtime/CommandTest.cpp b/flang/unittests/Runtime/CommandTest.cpp index 08daa4ba37f26b..20bd7a5b5ff35a 100644 --- a/flang/unittests/Runtime/CommandTest.cpp +++ b/flang/unittests/Runtime/CommandTest.cpp @@ -311,8 +311,8 @@ TEST_F(ZeroArguments, GetCommand) { CheckCommandValue(commandOnlyArgv, 1); } TEST_F(ZeroArguments, ECLValidCommandAndPadSync) { OwningPtr command{CharDescriptor("echo hi")}; bool wait{true}; - OwningPtr exitStat{EmptyIntDescriptor()}; - OwningPtr cmdStat{EmptyIntDescriptor()}; + OwningPtr exitStat{IntDescriptor(404)}; + OwningPtr cmdStat{IntDescriptor(202)}; OwningPtr cmdMsg{CharDescriptor("No change")}; RTNAME(ExecuteCommandLine) @@ -339,40 +339,91 @@ TEST_F(ZeroArguments, ECLValidCommandStatusSetSync) { CheckDescriptorEqStr(cmdMsg.get(), "No change"); } -TEST_F(ZeroArguments, ECLInvalidCommandErrorSync) { - OwningPtr command{CharDescriptor("InvalidCommand")}; +TEST_F(ZeroArguments, ECLGeneralErrorCommandErrorSync) { + OwningPtr command{CharDescriptor("cat GeneralErrorCommand")}; + bool wait{true}; + OwningPtr exitStat{IntDescriptor(404)}; + OwningPtr cmdStat{IntDescriptor(202)}; + OwningPtr cmdMsg{CharDescriptor("cmd msg buffer XXXXXXXXXXXXXX")}; + + RTNAME(ExecuteCommandLine) + (*command.get(), wait, exitStat.get(), cmdStat.get(), cmdMsg.get()); +#ifdef _WIN32 + CheckDescriptorEqInt(exitStat.get(), 1); + CheckDescriptorEqInt(cmdStat.get(), 6); + CheckDescriptorEqStr(cmdMsg.get(), "Invalid command lineXXXXXXXXX"); +#else + CheckDescriptorEqInt(exitStat.get(), 1); + CheckDescriptorEqInt(cmdStat.get(), 3); + CheckDescriptorEqStr(cmdMsg.get(), "Command line execution failed"); +#endif +} + +TEST_F(ZeroArguments, ECLNotExecutedCommandErrorSync) { + OwningPtr command{CharDescriptor( + "touch NotExecutedCommandFile && chmod -x NotExecutedCommandFile && " + "./NotExecutedCommandFile")}; + bool wait{true}; + OwningPtr exitStat{IntDescriptor(404)}; + OwningPtr cmdStat{IntDescriptor(202)}; + OwningPtr cmdMsg{CharDescriptor("cmd msg buffer XXXXXXXX")}; + + RTNAME(ExecuteCommandLine) + (*command.get(), wait, exitStat.get(), cmdStat.get(), cmdMsg.get()); +#ifdef _WIN32 + CheckDescriptorEqInt(exitStat.get(), 1); + CheckDescriptorEqInt(cmdStat.get(), 6); + CheckDescriptorEqStr(cmdMsg.get(), "Invalid command lineXXX"); +#else + CheckDescriptorEqInt(exitStat.get(), 126); + CheckDescriptorEqInt(cmdStat.get(), 4); + CheckDescriptorEqStr(cmdMsg.get(), "Command cannot be execu"); + // removing the file only on Linux (file is not created on Win) + OwningPtr commandClean{ + CharDescriptor("rm -f NotExecutedCommandFile")}; + OwningPtr cmdMsgNoErr{CharDescriptor("No Error")}; + RTNAME(ExecuteCommandLine) + (*commandClean.get(), wait, exitStat.get(), cmdStat.get(), cmdMsgNoErr.get()); + CheckDescriptorEqInt(exitStat.get(), 0); + CheckDescriptorEqStr(cmdMsgNoErr.get(), "No Error"); + CheckDescriptorEqInt(cmdStat.get(), 0); +#endif +} + +TEST_F(ZeroArguments, ECLNotFoundCommandErrorSync) { + OwningPtr command{CharDescriptor("NotFoundCommand")}; bool wait{true}; OwningPtr exitStat{IntDescriptor(404)}; OwningPtr cmdStat{IntDescriptor(202)}; - OwningPtr cmdMsg{CharDescriptor("Message ChangedXXXXXXXXX")}; + OwningPtr cmdMsg{CharDescriptor("unmodified buffer XXXXXXXXX")}; RTNAME(ExecuteCommandLine) (*command.get(), wait, exitStat.get(), cmdStat.get(), cmdMsg.get()); #ifdef _WIN32 - CheckDescriptorEqInt(exitStat.get(), 1); + CheckDescriptorEqInt(exitStat.get(), 1); + CheckDescriptorEqInt(cmdStat.get(), 6); + CheckDescriptorEqStr(cmdMsg.get(), "Invalid command lineXXXXXXX"); #else CheckDescriptorEqInt(exitStat.get(), 127); + CheckDescriptorEqInt(cmdStat.get(), 5); + CheckDescriptorEqStr(cmdMsg.get(), "Command not found with exit"); #endif - CheckDescriptorEqInt(cmdStat.get(), 3); - CheckDescriptorEqStr(cmdMsg.get(), "Invalid command lineXXXX"); } TEST_F(ZeroArguments, ECLInvalidCommandTerminatedSync) { OwningPtr command{CharDescriptor("InvalidCommand")}; bool wait{true}; - OwningPtr exitStat{IntDescriptor(404)}; OwningPtr cmdMsg{CharDescriptor("No Change")}; #ifdef _WIN32 EXPECT_DEATH(RTNAME(ExecuteCommandLine)( - *command.get(), wait, exitStat.get(), nullptr, cmdMsg.get()), + *command.get(), wait, nullptr, nullptr, cmdMsg.get()), "Invalid command quit with exit status code: 1"); #else EXPECT_DEATH(RTNAME(ExecuteCommandLine)( - *command.get(), wait, exitStat.get(), nullptr, cmdMsg.get()), - "Invalid command quit with exit status code: 127"); + *command.get(), wait, nullptr, nullptr, cmdMsg.get()), + "Command not found with exit code: 127."); #endif - CheckDescriptorEqInt(exitStat.get(), 404); CheckDescriptorEqStr(cmdMsg.get(), "No Change"); } @@ -394,13 +445,10 @@ TEST_F(ZeroArguments, ECLValidCommandAndExitStatNoChangeAndCMDStatusSetAsync) { TEST_F(ZeroArguments, ECLInvalidCommandParentNotTerminatedAsync) { OwningPtr command{CharDescriptor("InvalidCommand")}; bool wait{false}; - OwningPtr exitStat{IntDescriptor(404)}; OwningPtr cmdMsg{CharDescriptor("No change")}; EXPECT_NO_FATAL_FAILURE(RTNAME(ExecuteCommandLine)( - *command.get(), wait, exitStat.get(), nullptr, cmdMsg.get())); - - CheckDescriptorEqInt(exitStat.get(), 404); + *command.get(), wait, nullptr, nullptr, cmdMsg.get())); CheckDescriptorEqStr(cmdMsg.get(), "No change"); } diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt index f35471a06a53e5..4ffcd55ba9500f 100644 --- a/libc/CMakeLists.txt +++ b/libc/CMakeLists.txt @@ -401,9 +401,7 @@ if(LLVM_INCLUDE_TESTS) add_subdirectory(fuzzing) endif() -if(LIBC_INCLUDE_BENCHMARKS) - add_subdirectory(benchmarks) -endif() +add_subdirectory(benchmarks) if (LIBC_INCLUDE_DOCS) add_subdirectory(docs) diff --git a/libc/benchmarks/CMakeLists.txt b/libc/benchmarks/CMakeLists.txt index 4978da65850ccb..0cff6eb12c2475 100644 --- a/libc/benchmarks/CMakeLists.txt +++ b/libc/benchmarks/CMakeLists.txt @@ -1,3 +1,13 @@ +if(LIBC_TARGET_OS_IS_GPU) + add_subdirectory(gpu) + return() +endif() + +# The CPU build depends on Google benchmark. +if(NOT LIBC_INCLUDE_BENCHMARKS) + return() +endif() + find_package(Threads) set(LLVM_LINK_COMPONENTS diff --git a/libc/benchmarks/gpu/BenchmarkLogger.cpp b/libc/benchmarks/gpu/BenchmarkLogger.cpp new file mode 100644 index 00000000000000..2e7e8e7600fdb7 --- /dev/null +++ b/libc/benchmarks/gpu/BenchmarkLogger.cpp @@ -0,0 +1,97 @@ +#include "benchmarks/gpu/BenchmarkLogger.h" +#include "src/__support/CPP/string.h" +#include "src/__support/CPP/string_view.h" +#include "src/__support/OSUtil/io.h" // write_to_stderr +#include "src/__support/big_int.h" // is_big_int +#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_INT128 +#include "src/__support/uint128.h" + +#include + +namespace LIBC_NAMESPACE { +namespace benchmarks { + +// cpp::string_view specialization +template <> +BenchmarkLogger & + BenchmarkLogger::operator<< (cpp::string_view str) { + LIBC_NAMESPACE::write_to_stderr(str); + return *this; +} + +// cpp::string specialization +template <> +BenchmarkLogger &BenchmarkLogger::operator<< (cpp::string str) { + return *this << static_cast(str); +} + +// const char* specialization +template <> +BenchmarkLogger &BenchmarkLogger::operator<< (const char *str) { + return *this << cpp::string_view(str); +} + +// char* specialization +template <> BenchmarkLogger &BenchmarkLogger::operator<< (char *str) { + return *this << cpp::string_view(str); +} + +// char specialization +template <> BenchmarkLogger &BenchmarkLogger::operator<<(char ch) { + return *this << cpp::string_view(&ch, 1); +} + +// bool specialization +template <> BenchmarkLogger &BenchmarkLogger::operator<<(bool cond) { + return *this << (cond ? "true" : "false"); +} + +// void * specialization +template <> BenchmarkLogger &BenchmarkLogger::operator<<(void *addr) { + return *this << "0x" << cpp::to_string(reinterpret_cast(addr)); +} + +template BenchmarkLogger &BenchmarkLogger::operator<<(T t) { + if constexpr (is_big_int_v || + (cpp::is_integral_v && cpp::is_unsigned_v && + (sizeof(T) > sizeof(uint64_t)))) { + static_assert(sizeof(T) % 8 == 0, "Unsupported size of UInt"); + const IntegerToString buffer(t); + return *this << buffer.view(); + } else { + return *this << cpp::to_string(t); + } +} + +// is_integral specializations +// char is already specialized to handle character +template BenchmarkLogger &BenchmarkLogger::operator<< (short); +template BenchmarkLogger &BenchmarkLogger::operator<< (int); +template BenchmarkLogger &BenchmarkLogger::operator<< (long); +template BenchmarkLogger &BenchmarkLogger::operator<< (long long); +template BenchmarkLogger & + BenchmarkLogger::operator<< (unsigned char); +template BenchmarkLogger & + BenchmarkLogger::operator<< (unsigned short); +template BenchmarkLogger & + BenchmarkLogger::operator<< (unsigned int); +template BenchmarkLogger & + BenchmarkLogger::operator<< (unsigned long); +template BenchmarkLogger & + BenchmarkLogger::operator<< (unsigned long long); + +#ifdef LIBC_TYPES_HAS_INT128 +template BenchmarkLogger & + BenchmarkLogger::operator<< <__uint128_t>(__uint128_t); +#endif // LIBC_TYPES_HAS_INT128 +template BenchmarkLogger &BenchmarkLogger::operator<< >(UInt<128>); +template BenchmarkLogger &BenchmarkLogger::operator<< >(UInt<192>); +template BenchmarkLogger &BenchmarkLogger::operator<< >(UInt<256>); +template BenchmarkLogger &BenchmarkLogger::operator<< >(UInt<320>); + +// TODO: Add floating point formatting once it's supported by StringStream. + +BenchmarkLogger log; + +} // namespace benchmarks +} // namespace LIBC_NAMESPACE diff --git a/libc/benchmarks/gpu/BenchmarkLogger.h b/libc/benchmarks/gpu/BenchmarkLogger.h new file mode 100644 index 00000000000000..332ff1439e6f57 --- /dev/null +++ b/libc/benchmarks/gpu/BenchmarkLogger.h @@ -0,0 +1,27 @@ +//===-- Utilities to log to standard output during tests --------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_BENCHMARKS_GPU_BENCHMARKLOGGER_H +#define LLVM_LIBC_BENCHMARKS_GPU_BENCHMARKLOGGER_H + +namespace LIBC_NAMESPACE { +namespace benchmarks { + +// A class to log to standard output in the context of hermetic tests. +struct BenchmarkLogger { + constexpr BenchmarkLogger() = default; + template BenchmarkLogger &operator<<(T); +}; + +// A global TestLogger instance to be used in tests. +extern BenchmarkLogger log; + +} // namespace benchmarks +} // namespace LIBC_NAMESPACE + +#endif /* LLVM_LIBC_BENCHMARKS_GPU_BENCHMARKLOGGER_H */ diff --git a/libc/benchmarks/gpu/CMakeLists.txt b/libc/benchmarks/gpu/CMakeLists.txt new file mode 100644 index 00000000000000..d167abcaf2db1c --- /dev/null +++ b/libc/benchmarks/gpu/CMakeLists.txt @@ -0,0 +1,56 @@ +add_subdirectory(timing) + +add_custom_target(gpu-benchmark) + +function(add_benchmark benchmark_name) + cmake_parse_arguments( + "BENCHMARK" + "" # Optional arguments + "" # Single value arguments + "LINK_LIBRARIES" # Multi-value arguments + ${ARGN} + ) + if(NOT libc.src.time.clock IN_LIST TARGET_LLVMLIBC_ENTRYPOINTS) + message(FATAL_ERROR "target does not support clock") + endif() + add_libc_hermetic( + ${benchmark_name} + IS_BENCHMARK + LINK_LIBRARIES + LibcGpuBenchmark.hermetic + ${BENCHMARK_LINK_LIBRARIES} + ${BENCHMARK_UNPARSED_ARGUMENTS} + ) + get_fq_target_name(${benchmark_name} fq_target_name) + add_dependencies(gpu-benchmark ${fq_target_name}) +endfunction(add_benchmark) + +add_unittest_framework_library( + LibcGpuBenchmark + SRCS + LibcGpuBenchmark.cpp + LibcGpuBenchmarkMain.cpp + BenchmarkLogger.cpp + HDRS + LibcGpuBenchmark.h + BenchmarkLogger.h + DEPENDS + libc.src.__support.big_int + libc.src.__support.c_string + libc.src.__support.CPP.string + libc.src.__support.CPP.string_view + libc.src.__support.CPP.type_traits + libc.src.__support.CPP.functional + libc.src.__support.CPP.limits + libc.src.__support.CPP.algorithm + libc.src.__support.fixed_point.fx_rep + libc.src.__support.macros.properties.types + libc.src.__support.OSUtil.osutil + libc.src.__support.uint128 + libc.src.__support.FPUtil.sqrt + libc.src.__support.fixedvector + libc.src.time.clock + libc.benchmarks.gpu.timing.timing +) + +add_subdirectory(src) diff --git a/libc/benchmarks/gpu/LibcGpuBenchmark.cpp b/libc/benchmarks/gpu/LibcGpuBenchmark.cpp new file mode 100644 index 00000000000000..69adb0c95ba768 --- /dev/null +++ b/libc/benchmarks/gpu/LibcGpuBenchmark.cpp @@ -0,0 +1,140 @@ +#include "LibcGpuBenchmark.h" +#include "src/__support/CPP/algorithm.h" +#include "src/__support/CPP/array.h" +#include "src/__support/CPP/string.h" +#include "src/__support/FPUtil/sqrt.h" +#include "src/__support/GPU/utils.h" +#include "src/__support/fixedvector.h" +#include "src/time/gpu/time_utils.h" + +namespace LIBC_NAMESPACE { +namespace benchmarks { + +FixedVector benchmarks; +cpp::array results; + +void Benchmark::add_benchmark(Benchmark *benchmark) { + benchmarks.push_back(benchmark); +} + +BenchmarkResult reduce_results(cpp::array &results) { + BenchmarkResult result; + uint64_t cycles_sum = 0; + double standard_deviation_sum = 0; + uint64_t min = UINT64_MAX; + uint64_t max = 0; + uint32_t samples_sum = 0; + uint32_t iterations_sum = 0; + clock_t time_sum = 0; + uint64_t num_threads = gpu::get_num_threads(); + for (uint64_t i = 0; i < num_threads; i++) { + BenchmarkResult current_result = results[i]; + cycles_sum += current_result.cycles; + standard_deviation_sum += current_result.standard_deviation; + min = cpp::min(min, current_result.min); + max = cpp::max(max, current_result.max); + samples_sum += current_result.samples; + iterations_sum += current_result.total_iterations; + time_sum += current_result.total_time; + } + result.cycles = cycles_sum / num_threads; + result.standard_deviation = standard_deviation_sum / num_threads; + result.min = min; + result.max = max; + result.samples = samples_sum / num_threads; + result.total_iterations = iterations_sum / num_threads; + result.total_time = time_sum / num_threads; + return result; +} + +void Benchmark::run_benchmarks() { + uint64_t id = gpu::get_thread_id(); + gpu::sync_threads(); + + for (Benchmark *benchmark : benchmarks) + results[id] = benchmark->run(); + gpu::sync_threads(); + if (id == 0) { + for (Benchmark *benchmark : benchmarks) { + BenchmarkResult all_results = reduce_results(results); + constexpr auto GREEN = "\033[32m"; + constexpr auto RESET = "\033[0m"; + log << GREEN << "[ RUN ] " << RESET << benchmark->get_name() << '\n'; + log << GREEN << "[ OK ] " << RESET << benchmark->get_name() << ": " + << all_results.cycles << " cycles, " << all_results.min << " min, " + << all_results.max << " max, " << all_results.total_iterations + << " iterations, " << all_results.total_time << " ns, " + << static_cast(all_results.standard_deviation) << " stddev\n"; + } + } + gpu::sync_threads(); +} + +BenchmarkResult benchmark(const BenchmarkOptions &options, + cpp::function wrapper_func) { + BenchmarkResult result; + RuntimeEstimationProgression rep; + uint32_t total_iterations = 0; + uint32_t iterations = options.initial_iterations; + if (iterations < 1u) + iterations = 1; + + uint32_t samples = 0; + uint64_t total_time = 0; + uint64_t best_guess = 0; + uint64_t total_cycles = 0; + uint64_t cycles_squared = 0; + uint64_t min = UINT64_MAX; + uint64_t max = 0; + + uint64_t overhead = UINT64_MAX; + int overhead_iterations = 10; + for (int i = 0; i < overhead_iterations; i++) + overhead = cpp::min(overhead, LIBC_NAMESPACE::overhead()); + + for (uint64_t time_budget = options.max_duration; time_budget >= 0;) { + uint64_t sample_cycles = 0; + const clock_t start = static_cast(clock()); + for (uint32_t i = 0; i < iterations; i++) { + auto wrapper_intermediate = wrapper_func(); + uint64_t result = wrapper_intermediate - overhead; + max = cpp::max(max, result); + min = cpp::min(min, result); + sample_cycles += result; + } + const clock_t end = clock(); + const clock_t duration_ns = + ((end - start) * 1000 * 1000 * 1000) / CLOCKS_PER_SEC; + total_time += duration_ns; + time_budget -= duration_ns; + samples++; + total_cycles += sample_cycles; + cycles_squared += sample_cycles * sample_cycles; + + total_iterations += iterations; + const double change_ratio = + rep.compute_improvement({iterations, sample_cycles}); + best_guess = rep.current_estimation; + + if (samples >= options.max_samples || iterations >= options.max_iterations) + break; + if (total_time >= options.min_duration && samples >= options.min_samples && + change_ratio < options.epsilon) + break; + + iterations *= options.scaling_factor; + } + result.cycles = best_guess; + result.standard_deviation = fputil::sqrt( + static_cast(cycles_squared) / total_iterations - + static_cast(best_guess * best_guess)); + result.min = min; + result.max = max; + result.samples = samples; + result.total_iterations = total_iterations; + result.total_time = total_time; + return result; +}; + +} // namespace benchmarks +} // namespace LIBC_NAMESPACE diff --git a/libc/benchmarks/gpu/LibcGpuBenchmark.h b/libc/benchmarks/gpu/LibcGpuBenchmark.h new file mode 100644 index 00000000000000..59dd5894620808 --- /dev/null +++ b/libc/benchmarks/gpu/LibcGpuBenchmark.h @@ -0,0 +1,108 @@ +#ifndef LLVM_LIBC_BENCHMARKS_LIBC_GPU_BENCHMARK_H +#define LLVM_LIBC_BENCHMARKS_LIBC_GPU_BENCHMARK_H + +#include "benchmarks/gpu/BenchmarkLogger.h" +#include "benchmarks/gpu/timing/timing.h" +#include "src/__support/CPP/functional.h" +#include "src/__support/CPP/limits.h" +#include "src/__support/CPP/string_view.h" +#include "src/time/clock.h" + +#include + +namespace LIBC_NAMESPACE { + +namespace benchmarks { + +struct BenchmarkOptions { + uint32_t initial_iterations = 1; + uint32_t max_iterations = 10000000; + uint32_t min_samples = 4; + uint32_t max_samples = 1000; + uint64_t min_duration = 0; // in nanoseconds (ns) + uint64_t max_duration = 1000 * 1000 * 1000; // 1e9 nanoseconds = 1 second + double epsilon = 0.01; + double scaling_factor = 1.4; +}; + +struct Measurement { + uint32_t iterations = 0; + uint64_t elapsed_cycles = 0; +}; + +class RefinableRuntimeEstimation { + uint64_t total_cycles = 0; + uint32_t total_iterations = 0; + +public: + uint64_t update(const Measurement &M) { + total_cycles += M.elapsed_cycles; + total_iterations += M.iterations; + return total_cycles / total_iterations; + } +}; + +// Tracks the progression of the runtime estimation +class RuntimeEstimationProgression { + RefinableRuntimeEstimation rre; + +public: + uint64_t current_estimation = 0; + + double compute_improvement(const Measurement &M) { + const uint64_t new_estimation = rre.update(M); + double ratio = + (static_cast(current_estimation) / new_estimation) - 1.0; + + // Get absolute value + if (ratio < 0) + ratio *= -1; + + current_estimation = new_estimation; + return ratio; + } +}; + +struct BenchmarkResult { + uint64_t cycles = 0; + double standard_deviation = 0; + uint64_t min = UINT64_MAX; + uint64_t max = 0; + uint32_t samples = 0; + uint32_t total_iterations = 0; + clock_t total_time = 0; +}; + +BenchmarkResult benchmark(const BenchmarkOptions &options, + cpp::function wrapper_func); + +class Benchmark { + const cpp::function func; + const cpp::string_view name; + +public: + Benchmark(cpp::function func, char const *name) + : func(func), name(name) { + add_benchmark(this); + } + + static void run_benchmarks(); + +protected: + static void add_benchmark(Benchmark *benchmark); + +private: + BenchmarkResult run() { + BenchmarkOptions options; + return benchmark(options, func); + } + const cpp::string_view get_name() const { return name; } +}; +} // namespace benchmarks +} // namespace LIBC_NAMESPACE + +#define BENCHMARK(SuiteName, TestName, Func) \ + LIBC_NAMESPACE::benchmarks::Benchmark SuiteName##_##TestName##_Instance( \ + Func, #SuiteName "." #TestName); + +#endif diff --git a/libc/benchmarks/gpu/LibcGpuBenchmarkMain.cpp b/libc/benchmarks/gpu/LibcGpuBenchmarkMain.cpp new file mode 100644 index 00000000000000..97366e55194a90 --- /dev/null +++ b/libc/benchmarks/gpu/LibcGpuBenchmarkMain.cpp @@ -0,0 +1,6 @@ +#include "LibcGpuBenchmark.h" + +extern "C" int main(int argc, char **argv, char **envp) { + LIBC_NAMESPACE::benchmarks::Benchmark::run_benchmarks(); + return 0; +} diff --git a/libc/benchmarks/gpu/src/CMakeLists.txt b/libc/benchmarks/gpu/src/CMakeLists.txt new file mode 100644 index 00000000000000..42eb4f7b5909a8 --- /dev/null +++ b/libc/benchmarks/gpu/src/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(ctype) diff --git a/libc/benchmarks/gpu/src/ctype/CMakeLists.txt b/libc/benchmarks/gpu/src/ctype/CMakeLists.txt new file mode 100644 index 00000000000000..79f01425770da9 --- /dev/null +++ b/libc/benchmarks/gpu/src/ctype/CMakeLists.txt @@ -0,0 +1,21 @@ +add_custom_target(libc-gpu-ctype-benchmarks) + +add_benchmark( + isalnum_benchmark + SUITE + libc-gpu-ctype-benchmarks + SRCS + isalnum_benchmark.cpp + DEPENDS + libc.src.ctype.isalnum +) + +add_benchmark( + isalpha_benchmark + SUITE + libc-gpu-ctype-benchmarks + SRCS + isalpha_benchmark.cpp + DEPENDS + libc.src.ctype.isalpha +) diff --git a/libc/benchmarks/gpu/src/ctype/isalnum_benchmark.cpp b/libc/benchmarks/gpu/src/ctype/isalnum_benchmark.cpp new file mode 100644 index 00000000000000..4050bc0ec77b9f --- /dev/null +++ b/libc/benchmarks/gpu/src/ctype/isalnum_benchmark.cpp @@ -0,0 +1,9 @@ +#include "benchmarks/gpu/LibcGpuBenchmark.h" + +#include "src/ctype/isalnum.h" + +uint64_t BM_IsAlnum() { + char x = 'c'; + return LIBC_NAMESPACE::latency(LIBC_NAMESPACE::isalnum, x); +} +BENCHMARK(LlvmLibcIsAlNumGpuBenchmark, IsAlnumWrapper, BM_IsAlnum); diff --git a/libc/benchmarks/gpu/src/ctype/isalpha_benchmark.cpp b/libc/benchmarks/gpu/src/ctype/isalpha_benchmark.cpp new file mode 100644 index 00000000000000..2038eb89bc77ba --- /dev/null +++ b/libc/benchmarks/gpu/src/ctype/isalpha_benchmark.cpp @@ -0,0 +1,9 @@ +#include "benchmarks/gpu/LibcGpuBenchmark.h" + +#include "src/ctype/isalpha.h" + +uint64_t BM_IsAlpha() { + char x = 'c'; + return LIBC_NAMESPACE::latency(LIBC_NAMESPACE::isalpha, x); +} +BENCHMARK(LlvmLibcIsAlphaGpuBenchmark, IsAlpha, BM_IsAlpha); diff --git a/libc/benchmarks/gpu/timing/CMakeLists.txt b/libc/benchmarks/gpu/timing/CMakeLists.txt new file mode 100644 index 00000000000000..8bbc7e33f122a4 --- /dev/null +++ b/libc/benchmarks/gpu/timing/CMakeLists.txt @@ -0,0 +1,12 @@ +foreach(target nvptx) + add_subdirectory(${target}) + list(APPEND target_gpu_timing libc.benchmarks.gpu.timing.${target}.${target}_timing) +endforeach() + +add_header_library( + timing + HDRS + timing.h + DEPENDS + ${target_gpu_timing} +) diff --git a/libc/benchmarks/gpu/timing/nvptx/CMakeLists.txt b/libc/benchmarks/gpu/timing/nvptx/CMakeLists.txt new file mode 100644 index 00000000000000..9958e16206a410 --- /dev/null +++ b/libc/benchmarks/gpu/timing/nvptx/CMakeLists.txt @@ -0,0 +1,7 @@ +add_header_library( + nvptx_timing + HDRS + timing.h + DEPENDS + libc.src.__support.common +) diff --git a/libc/benchmarks/gpu/timing/nvptx/timing.h b/libc/benchmarks/gpu/timing/nvptx/timing.h new file mode 100644 index 00000000000000..d3851a764c43db --- /dev/null +++ b/libc/benchmarks/gpu/timing/nvptx/timing.h @@ -0,0 +1,99 @@ +//===------------- NVPTX implementation of timing utils ---------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_UTILS_GPU_TIMING_NVPTX +#define LLVM_LIBC_UTILS_GPU_TIMING_NVPTX + +#include "src/__support/GPU/utils.h" +#include "src/__support/common.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +#include + +namespace LIBC_NAMESPACE { + +// Returns the overhead associated with calling the profiling region. This +// allows us to substract the constant-time overhead from the latency to +// obtain a true result. This can vary with system load. +[[gnu::noinline]] static uint64_t overhead() { + volatile uint32_t x = 1; + uint32_t y = x; + uint64_t start = gpu::processor_clock(); + asm("" ::"r"(y), "llr"(start)); + uint32_t result = y; + asm("or.b32 %[v_reg], %[v_reg], 0;" ::[v_reg] "r"(result) :); + uint64_t stop = gpu::processor_clock(); + volatile auto storage = result; + return stop - start; +} + +// Stimulate a simple function and obtain its latency in clock cycles on the +// system. This function cannot be inlined or else it will disturb the very +// delicate balance of hard-coded dependencies. +template +[[gnu::noinline]] static LIBC_INLINE uint64_t latency(F f, T t) { + // We need to store the input somewhere to guarantee that the compiler will + // not constant propagate it and remove the profiling region. + volatile T storage = t; + T arg = storage; + asm("" ::"r"(arg)); + + // Get the current timestamp from the clock. + gpu::memory_fence(); + uint64_t start = gpu::processor_clock(); + + // This forces the compiler to load the input argument and run the clock cycle + // counter before the profiling region. + asm("" ::"r"(arg), "llr"(start)); + + // Run the function under test and return its value. + auto result = f(arg); + + // This inline assembly performs a no-op which forces the result to both be + // used and prevents us from exiting this region before it's complete. + asm("or.b32 %[v_reg], %[v_reg], 0;" ::[v_reg] "r"(result) :); + + // Obtain the current timestamp after running the calculation and force + // ordering. + uint64_t stop = gpu::processor_clock(); + gpu::memory_fence(); + asm("" ::"r"(stop)); + volatile T output = result; + + // Return the time elapsed. + return stop - start; +} + +template +static LIBC_INLINE uint64_t latency(F f, T1 t1, T2 t2) { + volatile T1 storage = t1; + volatile T2 storage2 = t2; + T1 arg = storage; + T2 arg2 = storage2; + asm("" ::"r"(arg), "r"(arg2)); + + gpu::memory_fence(); + uint64_t start = gpu::processor_clock(); + + asm("" ::"r"(arg), "r"(arg2), "llr"(start)); + + auto result = f(arg, arg2); + + asm("or.b32 %[v_reg], %[v_reg], 0;" ::[v_reg] "r"(result) :); + + uint64_t stop = gpu::processor_clock(); + gpu::memory_fence(); + asm("" ::"r"(stop)); + volatile auto output = result; + + return stop - start; +} +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_UTILS_GPU_TIMING_NVPTX diff --git a/libc/benchmarks/gpu/timing/timing.h b/libc/benchmarks/gpu/timing/timing.h new file mode 100644 index 00000000000000..180ea77954ae59 --- /dev/null +++ b/libc/benchmarks/gpu/timing/timing.h @@ -0,0 +1,22 @@ +//===------------- Implementation of GPU timing utils -----------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_UTILS_GPU_TIMING_H +#define LLVM_LIBC_UTILS_GPU_TIMING_H + +#include "src/__support/macros/properties/architectures.h" + +#if defined(LIBC_TARGET_ARCH_IS_AMDGPU) +#error "amdgpu not yet supported" +#elif defined(LIBC_TARGET_ARCH_IS_NVPTX) +#include "nvptx/timing.h" +#else +#error "unsupported platform" +#endif + +#endif // LLVM_LIBC_UTILS_GPU_TIMING_H diff --git a/libc/cmake/modules/LLVMLibCTestRules.cmake b/libc/cmake/modules/LLVMLibCTestRules.cmake index c8d7c8a2b1c7ca..fbeec32883b635 100644 --- a/libc/cmake/modules/LLVMLibCTestRules.cmake +++ b/libc/cmake/modules/LLVMLibCTestRules.cmake @@ -526,12 +526,15 @@ function(add_integration_test test_name) add_dependencies(${INTEGRATION_TEST_SUITE} ${fq_target_name}) endfunction(add_integration_test) -# Rule to add a hermetic test. A hermetic test is one whose executable is fully +# Rule to add a hermetic program. A hermetic program is one whose executable is fully # statically linked and consists of pieces drawn only from LLVM's libc. Nothing, # including the startup objects, come from the system libc. # +# For the GPU, these can be either tests or benchmarks, depending on the value +# of the LINK_LIBRARIES arg. +# # Usage: -# add_libc_hermetic_test( +# add_libc_hermetic( # # SUITE # SRCS [src2.cpp ...] @@ -543,14 +546,14 @@ endfunction(add_integration_test) # LINK_LIBRARIES # LOADER_ARGS # ) -function(add_libc_hermetic_test test_name) +function(add_libc_hermetic test_name) if(NOT TARGET libc.startup.${LIBC_TARGET_OS}.crt1) message(VERBOSE "Skipping ${fq_target_name} as it is not available on ${LIBC_TARGET_OS}.") return() endif() cmake_parse_arguments( "HERMETIC_TEST" - "" # No optional arguments + "IS_BENCHMARK" # Optional arguments "SUITE" # Single value arguments "SRCS;HDRS;DEPENDS;ARGS;ENV;COMPILE_OPTIONS;LINK_LIBRARIES;LOADER_ARGS" # Multi-value arguments ${ARGN} @@ -678,7 +681,6 @@ function(add_libc_hermetic_test test_name) PRIVATE libc.startup.${LIBC_TARGET_OS}.crt1${internal_suffix} ${link_libraries} - LibcTest.hermetic LibcHermeticTestSupport.hermetic # The NVIDIA 'nvlink' linker does not currently support static libraries. $<$>:${fq_target_name}.__libc__>) @@ -714,8 +716,12 @@ function(add_libc_hermetic_test test_name) ) add_dependencies(${HERMETIC_TEST_SUITE} ${fq_target_name}) - add_dependencies(libc-hermetic-tests ${fq_target_name}) -endfunction(add_libc_hermetic_test) + if(NOT ${HERMETIC_TEST_IS_BENCHMARK}) + # If it is a benchmark, it will already have been added to the + # gpu-benchmark target + add_dependencies(libc-hermetic-tests ${fq_target_name}) + endif() +endfunction(add_libc_hermetic) # A convenience function to add both a unit test as well as a hermetic test. function(add_libc_test test_name) @@ -730,7 +736,12 @@ function(add_libc_test test_name) add_libc_unittest(${test_name}.__unit__ ${LIBC_TEST_UNPARSED_ARGUMENTS}) endif() if(LIBC_ENABLE_HERMETIC_TESTS AND NOT LIBC_TEST_UNIT_TEST_ONLY) - add_libc_hermetic_test(${test_name}.__hermetic__ ${LIBC_TEST_UNPARSED_ARGUMENTS}) + add_libc_hermetic( + ${test_name}.__hermetic__ + LINK_LIBRARIES + LibcTest.hermetic + ${LIBC_TEST_UNPARSED_ARGUMENTS} + ) get_fq_target_name(${test_name} fq_test_name) if(TARGET ${fq_test_name}.__hermetic__ AND TARGET ${fq_test_name}.__unit__) # Tests like the file tests perform file operations on disk file. If we diff --git a/libc/cmake/modules/prepare_libc_gpu_build.cmake b/libc/cmake/modules/prepare_libc_gpu_build.cmake index dc8beb14fd7f44..e2a0908023a028 100644 --- a/libc/cmake/modules/prepare_libc_gpu_build.cmake +++ b/libc/cmake/modules/prepare_libc_gpu_build.cmake @@ -16,6 +16,17 @@ if(NOT LLVM_LIBC_FULL_BUILD) "GPU.") endif() +# Set the required flags globally so standard CMake utilities can compile. +if(LIBC_TARGET_TRIPLE) + set(CMAKE_REQUIRED_FLAGS "--target=${LIBC_TARGET_TRIPLE}") +endif() +if(LIBC_TARGET_ARCHITECTURE_IS_AMDGPU) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nogpulib") +elseif(LIBC_TARGET_ARCHITECTURE_IS_NVPTX) + set(CMAKE_REQUIRED_FLAGS + "${CMAKE_REQUIRED_FLAGS} -flto -c -Wno-unused-command-line-argument") +endif() + # Identify the program used to package multiple images into a single binary. get_filename_component(compiler_path ${CMAKE_CXX_COMPILER} DIRECTORY) if(TARGET clang-offload-packager) @@ -56,39 +67,9 @@ endif() set(LIBC_GPU_TEST_ARCHITECTURE "" CACHE STRING "Architecture for the GPU tests") if(LIBC_TARGET_ARCHITECTURE_IS_AMDGPU) - # Identify any locally installed AMD GPUs on the system using 'amdgpu-arch'. - if(TARGET amdgpu-arch) - get_target_property(LIBC_AMDGPU_ARCH amdgpu-arch LOCATION) - else() - find_program(LIBC_AMDGPU_ARCH - NAMES amdgpu-arch NO_DEFAULT_PATH - PATHS ${LLVM_BINARY_DIR}/bin ${compiler_path}) - endif() - if(LIBC_AMDGPU_ARCH) - execute_process(COMMAND ${LIBC_AMDGPU_ARCH} - OUTPUT_VARIABLE arch_tool_output - ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) - if(arch_tool_output MATCHES "^gfx[0-9]+") - set(PLATFORM_HAS_GPU TRUE) - endif() - endif() + check_cxx_compiler_flag(-mcpu=native PLATFORM_HAS_GPU) elseif(LIBC_TARGET_ARCHITECTURE_IS_NVPTX) - # Identify any locally installed NVIDIA GPUs on the system using 'nvptx-arch'. - if(TARGET nvptx-arch) - get_target_property(LIBC_NVPTX_ARCH nvptx-arch LOCATION) - else() - find_program(LIBC_NVPTX_ARCH - NAMES nvptx-arch NO_DEFAULT_PATH - PATHS ${LLVM_BINARY_DIR}/bin ${compiler_path}) - endif() - if(LIBC_NVPTX_ARCH) - execute_process(COMMAND ${LIBC_NVPTX_ARCH} - OUTPUT_VARIABLE arch_tool_output - ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) - if(arch_tool_output MATCHES "^sm_[0-9]+") - set(PLATFORM_HAS_GPU TRUE) - endif() - endif() + check_cxx_compiler_flag(-march=native PLATFORM_HAS_GPU) endif() set(gpu_test_architecture "") diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt index b8e97783c77237..9651939454ccc5 100644 --- a/libc/config/baremetal/arm/entrypoints.txt +++ b/libc/config/baremetal/arm/entrypoints.txt @@ -83,93 +83,93 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.inttypes.strtoumax # stdio.h entrypoints - libc.src.stdio.remove libc.src.stdio.printf libc.src.stdio.putchar - libc.src.stdio.sprintf + libc.src.stdio.remove libc.src.stdio.snprintf + libc.src.stdio.sprintf libc.src.stdio.vprintf - libc.src.stdio.vsprintf libc.src.stdio.vsnprintf + libc.src.stdio.vsprintf # stdbit.h entrypoints - libc.src.stdbit.stdc_leading_zeros_uc - libc.src.stdbit.stdc_leading_zeros_us - libc.src.stdbit.stdc_leading_zeros_ui - libc.src.stdbit.stdc_leading_zeros_ul - libc.src.stdbit.stdc_leading_zeros_ull - libc.src.stdbit.stdc_leading_ones_uc - libc.src.stdbit.stdc_leading_ones_us - libc.src.stdbit.stdc_leading_ones_ui - libc.src.stdbit.stdc_leading_ones_ul - libc.src.stdbit.stdc_leading_ones_ull - libc.src.stdbit.stdc_trailing_zeros_uc - libc.src.stdbit.stdc_trailing_zeros_us - libc.src.stdbit.stdc_trailing_zeros_ui - libc.src.stdbit.stdc_trailing_zeros_ul - libc.src.stdbit.stdc_trailing_zeros_ull - libc.src.stdbit.stdc_trailing_ones_uc - libc.src.stdbit.stdc_trailing_ones_us - libc.src.stdbit.stdc_trailing_ones_ui - libc.src.stdbit.stdc_trailing_ones_ul - libc.src.stdbit.stdc_trailing_ones_ull - libc.src.stdbit.stdc_first_leading_zero_uc - libc.src.stdbit.stdc_first_leading_zero_us - libc.src.stdbit.stdc_first_leading_zero_ui - libc.src.stdbit.stdc_first_leading_zero_ul - libc.src.stdbit.stdc_first_leading_zero_ull + libc.src.stdbit.stdc_bit_ceil_uc + libc.src.stdbit.stdc_bit_ceil_ui + libc.src.stdbit.stdc_bit_ceil_ul + libc.src.stdbit.stdc_bit_ceil_ull + libc.src.stdbit.stdc_bit_ceil_us + libc.src.stdbit.stdc_bit_floor_uc + libc.src.stdbit.stdc_bit_floor_ui + libc.src.stdbit.stdc_bit_floor_ul + libc.src.stdbit.stdc_bit_floor_ull + libc.src.stdbit.stdc_bit_floor_us + libc.src.stdbit.stdc_bit_width_uc + libc.src.stdbit.stdc_bit_width_ui + libc.src.stdbit.stdc_bit_width_ul + libc.src.stdbit.stdc_bit_width_ull + libc.src.stdbit.stdc_bit_width_us + libc.src.stdbit.stdc_count_ones_uc + libc.src.stdbit.stdc_count_ones_ui + libc.src.stdbit.stdc_count_ones_ul + libc.src.stdbit.stdc_count_ones_ull + libc.src.stdbit.stdc_count_ones_us + libc.src.stdbit.stdc_count_zeros_uc + libc.src.stdbit.stdc_count_zeros_ui + libc.src.stdbit.stdc_count_zeros_ul + libc.src.stdbit.stdc_count_zeros_ull + libc.src.stdbit.stdc_count_zeros_us libc.src.stdbit.stdc_first_leading_one_uc - libc.src.stdbit.stdc_first_leading_one_us libc.src.stdbit.stdc_first_leading_one_ui libc.src.stdbit.stdc_first_leading_one_ul libc.src.stdbit.stdc_first_leading_one_ull - libc.src.stdbit.stdc_first_trailing_zero_uc - libc.src.stdbit.stdc_first_trailing_zero_us - libc.src.stdbit.stdc_first_trailing_zero_ui - libc.src.stdbit.stdc_first_trailing_zero_ul - libc.src.stdbit.stdc_first_trailing_zero_ull + libc.src.stdbit.stdc_first_leading_one_us + libc.src.stdbit.stdc_first_leading_zero_uc + libc.src.stdbit.stdc_first_leading_zero_ui + libc.src.stdbit.stdc_first_leading_zero_ul + libc.src.stdbit.stdc_first_leading_zero_ull + libc.src.stdbit.stdc_first_leading_zero_us libc.src.stdbit.stdc_first_trailing_one_uc - libc.src.stdbit.stdc_first_trailing_one_us libc.src.stdbit.stdc_first_trailing_one_ui libc.src.stdbit.stdc_first_trailing_one_ul libc.src.stdbit.stdc_first_trailing_one_ull - libc.src.stdbit.stdc_count_zeros_uc - libc.src.stdbit.stdc_count_zeros_us - libc.src.stdbit.stdc_count_zeros_ui - libc.src.stdbit.stdc_count_zeros_ul - libc.src.stdbit.stdc_count_zeros_ull - libc.src.stdbit.stdc_count_ones_uc - libc.src.stdbit.stdc_count_ones_us - libc.src.stdbit.stdc_count_ones_ui - libc.src.stdbit.stdc_count_ones_ul - libc.src.stdbit.stdc_count_ones_ull + libc.src.stdbit.stdc_first_trailing_one_us + libc.src.stdbit.stdc_first_trailing_zero_uc + libc.src.stdbit.stdc_first_trailing_zero_ui + libc.src.stdbit.stdc_first_trailing_zero_ul + libc.src.stdbit.stdc_first_trailing_zero_ull + libc.src.stdbit.stdc_first_trailing_zero_us libc.src.stdbit.stdc_has_single_bit_uc - libc.src.stdbit.stdc_has_single_bit_us libc.src.stdbit.stdc_has_single_bit_ui libc.src.stdbit.stdc_has_single_bit_ul libc.src.stdbit.stdc_has_single_bit_ull - libc.src.stdbit.stdc_bit_width_uc - libc.src.stdbit.stdc_bit_width_us - libc.src.stdbit.stdc_bit_width_ui - libc.src.stdbit.stdc_bit_width_ul - libc.src.stdbit.stdc_bit_width_ull - libc.src.stdbit.stdc_bit_floor_uc - libc.src.stdbit.stdc_bit_floor_us - libc.src.stdbit.stdc_bit_floor_ui - libc.src.stdbit.stdc_bit_floor_ul - libc.src.stdbit.stdc_bit_floor_ull - libc.src.stdbit.stdc_bit_ceil_uc - libc.src.stdbit.stdc_bit_ceil_us - libc.src.stdbit.stdc_bit_ceil_ui - libc.src.stdbit.stdc_bit_ceil_ul - libc.src.stdbit.stdc_bit_ceil_ull + libc.src.stdbit.stdc_has_single_bit_us + libc.src.stdbit.stdc_leading_ones_uc + libc.src.stdbit.stdc_leading_ones_ui + libc.src.stdbit.stdc_leading_ones_ul + libc.src.stdbit.stdc_leading_ones_ull + libc.src.stdbit.stdc_leading_ones_us + libc.src.stdbit.stdc_leading_zeros_uc + libc.src.stdbit.stdc_leading_zeros_ui + libc.src.stdbit.stdc_leading_zeros_ul + libc.src.stdbit.stdc_leading_zeros_ull + libc.src.stdbit.stdc_leading_zeros_us + libc.src.stdbit.stdc_trailing_ones_uc + libc.src.stdbit.stdc_trailing_ones_ui + libc.src.stdbit.stdc_trailing_ones_ul + libc.src.stdbit.stdc_trailing_ones_ull + libc.src.stdbit.stdc_trailing_ones_us + libc.src.stdbit.stdc_trailing_zeros_uc + libc.src.stdbit.stdc_trailing_zeros_ui + libc.src.stdbit.stdc_trailing_zeros_ul + libc.src.stdbit.stdc_trailing_zeros_ull + libc.src.stdbit.stdc_trailing_zeros_us # stdlib.h entrypoints libc.src.stdlib.abort libc.src.stdlib.abs libc.src.stdlib.aligned_alloc - libc.src.stdlib.atoi libc.src.stdlib.atof + libc.src.stdlib.atoi libc.src.stdlib.atol libc.src.stdlib.atoll libc.src.stdlib.bsearch @@ -211,11 +211,11 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.fenv.fegetexceptflag libc.src.fenv.fegetround libc.src.fenv.feholdexcept + libc.src.fenv.feraiseexcept libc.src.fenv.fesetenv libc.src.fenv.fesetexcept libc.src.fenv.fesetexceptflag libc.src.fenv.fesetround - libc.src.fenv.feraiseexcept libc.src.fenv.fetestexcept libc.src.fenv.fetestexceptflag libc.src.fenv.feupdateenv @@ -228,12 +228,16 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.atan2f libc.src.math.atanf libc.src.math.atanhf + libc.src.math.canonicalize + libc.src.math.canonicalizef + libc.src.math.canonicalizel libc.src.math.ceil libc.src.math.ceilf libc.src.math.ceill libc.src.math.copysign libc.src.math.copysignf libc.src.math.copysignl + libc.src.math.cos libc.src.math.cosf libc.src.math.coshf libc.src.math.erff @@ -242,6 +246,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.exp10f libc.src.math.exp2 libc.src.math.exp2f + libc.src.math.exp2m1f libc.src.math.expf libc.src.math.expm1 libc.src.math.expm1f @@ -258,16 +263,47 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.fmaf libc.src.math.fmax libc.src.math.fmaxf + libc.src.math.fmaximum + libc.src.math.fmaximum_mag + libc.src.math.fmaximum_mag_num + libc.src.math.fmaximum_mag_numf + libc.src.math.fmaximum_mag_numl + libc.src.math.fmaximum_magf + libc.src.math.fmaximum_magl + libc.src.math.fmaximum_num + libc.src.math.fmaximum_numf + libc.src.math.fmaximum_numl + libc.src.math.fmaximumf + libc.src.math.fmaximuml libc.src.math.fmaxl libc.src.math.fmin libc.src.math.fminf + libc.src.math.fminimum + libc.src.math.fminimum_mag + libc.src.math.fminimum_mag_num + libc.src.math.fminimum_mag_numf + libc.src.math.fminimum_mag_numl + libc.src.math.fminimum_magf + libc.src.math.fminimum_magl + libc.src.math.fminimum_num + libc.src.math.fminimum_numf + libc.src.math.fminimum_numl + libc.src.math.fminimumf + libc.src.math.fminimuml libc.src.math.fminl libc.src.math.fmod libc.src.math.fmodf libc.src.math.fmodl + libc.src.math.fmul libc.src.math.frexp libc.src.math.frexpf libc.src.math.frexpl + libc.src.math.fromfp + libc.src.math.fromfpf + libc.src.math.fromfpl + libc.src.math.fromfpx + libc.src.math.fromfpxf + libc.src.math.fromfpxl libc.src.math.hypot libc.src.math.hypotf libc.src.math.ilogb @@ -314,9 +350,15 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.nextafter libc.src.math.nextafterf libc.src.math.nextafterl + libc.src.math.nextdown + libc.src.math.nextdownf + libc.src.math.nextdownl libc.src.math.nexttoward libc.src.math.nexttowardf libc.src.math.nexttowardl + libc.src.math.nextup + libc.src.math.nextupf + libc.src.math.nextupl libc.src.math.powf libc.src.math.remainder libc.src.math.remainderf @@ -328,11 +370,16 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.rintf libc.src.math.rintl libc.src.math.round + libc.src.math.roundeven + libc.src.math.roundevenf + libc.src.math.roundevenl libc.src.math.roundf libc.src.math.roundl libc.src.math.scalbn libc.src.math.scalbnf libc.src.math.scalbnl + libc.src.math.sin + libc.src.math.sincos libc.src.math.sincosf libc.src.math.sinf libc.src.math.sinhf @@ -344,6 +391,12 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.trunc libc.src.math.truncf libc.src.math.truncl + libc.src.math.ufromfp + libc.src.math.ufromfpf + libc.src.math.ufromfpl + libc.src.math.ufromfpx + libc.src.math.ufromfpxf + libc.src.math.ufromfpxl ) if(LIBC_COMPILER_HAS_FIXED_POINT) @@ -352,23 +405,23 @@ if(LIBC_COMPILER_HAS_FIXED_POINT) libc.src.stdfix.abshk libc.src.stdfix.abshr libc.src.stdfix.absk - libc.src.stdfix.absr libc.src.stdfix.abslk libc.src.stdfix.abslr + libc.src.stdfix.absr libc.src.stdfix.exphk libc.src.stdfix.expk libc.src.stdfix.roundhk libc.src.stdfix.roundhr libc.src.stdfix.roundk - libc.src.stdfix.roundr libc.src.stdfix.roundlk libc.src.stdfix.roundlr + libc.src.stdfix.roundr libc.src.stdfix.rounduhk libc.src.stdfix.rounduhr libc.src.stdfix.rounduk - libc.src.stdfix.roundur libc.src.stdfix.roundulk libc.src.stdfix.roundulr + libc.src.stdfix.roundur libc.src.stdfix.sqrtuhk libc.src.stdfix.sqrtuhr libc.src.stdfix.sqrtuk diff --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt index c9070c2691b192..8b37acef259c4f 100644 --- a/libc/config/baremetal/riscv/entrypoints.txt +++ b/libc/config/baremetal/riscv/entrypoints.txt @@ -79,93 +79,93 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.inttypes.strtoumax # stdio.h entrypoints - libc.src.stdio.remove libc.src.stdio.printf libc.src.stdio.putchar - libc.src.stdio.sprintf + libc.src.stdio.remove libc.src.stdio.snprintf + libc.src.stdio.sprintf libc.src.stdio.vprintf - libc.src.stdio.vsprintf libc.src.stdio.vsnprintf + libc.src.stdio.vsprintf # stdbit.h entrypoints - libc.src.stdbit.stdc_leading_zeros_uc - libc.src.stdbit.stdc_leading_zeros_us - libc.src.stdbit.stdc_leading_zeros_ui - libc.src.stdbit.stdc_leading_zeros_ul - libc.src.stdbit.stdc_leading_zeros_ull - libc.src.stdbit.stdc_leading_ones_uc - libc.src.stdbit.stdc_leading_ones_us - libc.src.stdbit.stdc_leading_ones_ui - libc.src.stdbit.stdc_leading_ones_ul - libc.src.stdbit.stdc_leading_ones_ull - libc.src.stdbit.stdc_trailing_zeros_uc - libc.src.stdbit.stdc_trailing_zeros_us - libc.src.stdbit.stdc_trailing_zeros_ui - libc.src.stdbit.stdc_trailing_zeros_ul - libc.src.stdbit.stdc_trailing_zeros_ull - libc.src.stdbit.stdc_trailing_ones_uc - libc.src.stdbit.stdc_trailing_ones_us - libc.src.stdbit.stdc_trailing_ones_ui - libc.src.stdbit.stdc_trailing_ones_ul - libc.src.stdbit.stdc_trailing_ones_ull - libc.src.stdbit.stdc_first_leading_zero_uc - libc.src.stdbit.stdc_first_leading_zero_us - libc.src.stdbit.stdc_first_leading_zero_ui - libc.src.stdbit.stdc_first_leading_zero_ul - libc.src.stdbit.stdc_first_leading_zero_ull + libc.src.stdbit.stdc_bit_ceil_uc + libc.src.stdbit.stdc_bit_ceil_ui + libc.src.stdbit.stdc_bit_ceil_ul + libc.src.stdbit.stdc_bit_ceil_ull + libc.src.stdbit.stdc_bit_ceil_us + libc.src.stdbit.stdc_bit_floor_uc + libc.src.stdbit.stdc_bit_floor_ui + libc.src.stdbit.stdc_bit_floor_ul + libc.src.stdbit.stdc_bit_floor_ull + libc.src.stdbit.stdc_bit_floor_us + libc.src.stdbit.stdc_bit_width_uc + libc.src.stdbit.stdc_bit_width_ui + libc.src.stdbit.stdc_bit_width_ul + libc.src.stdbit.stdc_bit_width_ull + libc.src.stdbit.stdc_bit_width_us + libc.src.stdbit.stdc_count_ones_uc + libc.src.stdbit.stdc_count_ones_ui + libc.src.stdbit.stdc_count_ones_ul + libc.src.stdbit.stdc_count_ones_ull + libc.src.stdbit.stdc_count_ones_us + libc.src.stdbit.stdc_count_zeros_uc + libc.src.stdbit.stdc_count_zeros_ui + libc.src.stdbit.stdc_count_zeros_ul + libc.src.stdbit.stdc_count_zeros_ull + libc.src.stdbit.stdc_count_zeros_us libc.src.stdbit.stdc_first_leading_one_uc - libc.src.stdbit.stdc_first_leading_one_us libc.src.stdbit.stdc_first_leading_one_ui libc.src.stdbit.stdc_first_leading_one_ul libc.src.stdbit.stdc_first_leading_one_ull - libc.src.stdbit.stdc_first_trailing_zero_uc - libc.src.stdbit.stdc_first_trailing_zero_us - libc.src.stdbit.stdc_first_trailing_zero_ui - libc.src.stdbit.stdc_first_trailing_zero_ul - libc.src.stdbit.stdc_first_trailing_zero_ull + libc.src.stdbit.stdc_first_leading_one_us + libc.src.stdbit.stdc_first_leading_zero_uc + libc.src.stdbit.stdc_first_leading_zero_ui + libc.src.stdbit.stdc_first_leading_zero_ul + libc.src.stdbit.stdc_first_leading_zero_ull + libc.src.stdbit.stdc_first_leading_zero_us libc.src.stdbit.stdc_first_trailing_one_uc - libc.src.stdbit.stdc_first_trailing_one_us libc.src.stdbit.stdc_first_trailing_one_ui libc.src.stdbit.stdc_first_trailing_one_ul libc.src.stdbit.stdc_first_trailing_one_ull - libc.src.stdbit.stdc_count_zeros_uc - libc.src.stdbit.stdc_count_zeros_us - libc.src.stdbit.stdc_count_zeros_ui - libc.src.stdbit.stdc_count_zeros_ul - libc.src.stdbit.stdc_count_zeros_ull - libc.src.stdbit.stdc_count_ones_uc - libc.src.stdbit.stdc_count_ones_us - libc.src.stdbit.stdc_count_ones_ui - libc.src.stdbit.stdc_count_ones_ul - libc.src.stdbit.stdc_count_ones_ull + libc.src.stdbit.stdc_first_trailing_one_us + libc.src.stdbit.stdc_first_trailing_zero_uc + libc.src.stdbit.stdc_first_trailing_zero_ui + libc.src.stdbit.stdc_first_trailing_zero_ul + libc.src.stdbit.stdc_first_trailing_zero_ull + libc.src.stdbit.stdc_first_trailing_zero_us libc.src.stdbit.stdc_has_single_bit_uc - libc.src.stdbit.stdc_has_single_bit_us libc.src.stdbit.stdc_has_single_bit_ui libc.src.stdbit.stdc_has_single_bit_ul libc.src.stdbit.stdc_has_single_bit_ull - libc.src.stdbit.stdc_bit_width_uc - libc.src.stdbit.stdc_bit_width_us - libc.src.stdbit.stdc_bit_width_ui - libc.src.stdbit.stdc_bit_width_ul - libc.src.stdbit.stdc_bit_width_ull - libc.src.stdbit.stdc_bit_floor_uc - libc.src.stdbit.stdc_bit_floor_us - libc.src.stdbit.stdc_bit_floor_ui - libc.src.stdbit.stdc_bit_floor_ul - libc.src.stdbit.stdc_bit_floor_ull - libc.src.stdbit.stdc_bit_ceil_uc - libc.src.stdbit.stdc_bit_ceil_us - libc.src.stdbit.stdc_bit_ceil_ui - libc.src.stdbit.stdc_bit_ceil_ul - libc.src.stdbit.stdc_bit_ceil_ull + libc.src.stdbit.stdc_has_single_bit_us + libc.src.stdbit.stdc_leading_ones_uc + libc.src.stdbit.stdc_leading_ones_ui + libc.src.stdbit.stdc_leading_ones_ul + libc.src.stdbit.stdc_leading_ones_ull + libc.src.stdbit.stdc_leading_ones_us + libc.src.stdbit.stdc_leading_zeros_uc + libc.src.stdbit.stdc_leading_zeros_ui + libc.src.stdbit.stdc_leading_zeros_ul + libc.src.stdbit.stdc_leading_zeros_ull + libc.src.stdbit.stdc_leading_zeros_us + libc.src.stdbit.stdc_trailing_ones_uc + libc.src.stdbit.stdc_trailing_ones_ui + libc.src.stdbit.stdc_trailing_ones_ul + libc.src.stdbit.stdc_trailing_ones_ull + libc.src.stdbit.stdc_trailing_ones_us + libc.src.stdbit.stdc_trailing_zeros_uc + libc.src.stdbit.stdc_trailing_zeros_ui + libc.src.stdbit.stdc_trailing_zeros_ul + libc.src.stdbit.stdc_trailing_zeros_ull + libc.src.stdbit.stdc_trailing_zeros_us # stdlib.h entrypoints libc.src.stdlib.abort libc.src.stdlib.abs libc.src.stdlib.aligned_alloc - libc.src.stdlib.atoi libc.src.stdlib.atof + libc.src.stdlib.atoi libc.src.stdlib.atol libc.src.stdlib.atoll libc.src.stdlib.bsearch @@ -207,11 +207,11 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.fenv.fegetexceptflag libc.src.fenv.fegetround libc.src.fenv.feholdexcept + libc.src.fenv.feraiseexcept libc.src.fenv.fesetenv libc.src.fenv.fesetexcept libc.src.fenv.fesetexceptflag libc.src.fenv.fesetround - libc.src.fenv.feraiseexcept libc.src.fenv.fetestexcept libc.src.fenv.fetestexceptflag libc.src.fenv.feupdateenv @@ -224,12 +224,16 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.atan2f libc.src.math.atanf libc.src.math.atanhf + libc.src.math.canonicalize + libc.src.math.canonicalizef + libc.src.math.canonicalizel libc.src.math.ceil libc.src.math.ceilf libc.src.math.ceill libc.src.math.copysign libc.src.math.copysignf libc.src.math.copysignl + libc.src.math.cos libc.src.math.cosf libc.src.math.coshf libc.src.math.erff @@ -238,6 +242,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.exp10f libc.src.math.exp2 libc.src.math.exp2f + libc.src.math.exp2m1f libc.src.math.expf libc.src.math.expm1 libc.src.math.expm1f @@ -254,15 +259,46 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.fmaf libc.src.math.fmax libc.src.math.fmaxf + libc.src.math.fmaximum + libc.src.math.fmaximum_mag + libc.src.math.fmaximum_mag_num + libc.src.math.fmaximum_mag_numf + libc.src.math.fmaximum_mag_numl + libc.src.math.fmaximum_magf + libc.src.math.fmaximum_magl + libc.src.math.fmaximum_num + libc.src.math.fmaximum_numf + libc.src.math.fmaximum_numl + libc.src.math.fmaximumf + libc.src.math.fmaximuml libc.src.math.fmaxl libc.src.math.fmin libc.src.math.fminf + libc.src.math.fminimum + libc.src.math.fminimum_mag + libc.src.math.fminimum_mag_num + libc.src.math.fminimum_mag_numf + libc.src.math.fminimum_mag_numl + libc.src.math.fminimum_magf + libc.src.math.fminimum_magl + libc.src.math.fminimum_num + libc.src.math.fminimum_numf + libc.src.math.fminimum_numl + libc.src.math.fminimumf + libc.src.math.fminimuml libc.src.math.fminl libc.src.math.fmod libc.src.math.fmodf + libc.src.math.fmul libc.src.math.frexp libc.src.math.frexpf libc.src.math.frexpl + libc.src.math.fromfp + libc.src.math.fromfpf + libc.src.math.fromfpl + libc.src.math.fromfpx + libc.src.math.fromfpxf + libc.src.math.fromfpxl libc.src.math.hypot libc.src.math.hypotf libc.src.math.ilogb @@ -309,9 +345,15 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.nextafter libc.src.math.nextafterf libc.src.math.nextafterl + libc.src.math.nextdown + libc.src.math.nextdownf + libc.src.math.nextdownl libc.src.math.nexttoward libc.src.math.nexttowardf libc.src.math.nexttowardl + libc.src.math.nextup + libc.src.math.nextupf + libc.src.math.nextupl libc.src.math.powf libc.src.math.remainder libc.src.math.remainderf @@ -323,11 +365,16 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.rintf libc.src.math.rintl libc.src.math.round + libc.src.math.roundeven + libc.src.math.roundevenf + libc.src.math.roundevenl libc.src.math.roundf libc.src.math.roundl libc.src.math.scalbn libc.src.math.scalbnf libc.src.math.scalbnl + libc.src.math.sin + libc.src.math.sincos libc.src.math.sincosf libc.src.math.sinf libc.src.math.sinhf @@ -339,6 +386,12 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.trunc libc.src.math.truncf libc.src.math.truncl + libc.src.math.ufromfp + libc.src.math.ufromfpf + libc.src.math.ufromfpl + libc.src.math.ufromfpx + libc.src.math.ufromfpxf + libc.src.math.ufromfpxl ) if(LIBC_COMPILER_HAS_FIXED_POINT) @@ -347,23 +400,23 @@ if(LIBC_COMPILER_HAS_FIXED_POINT) libc.src.stdfix.abshk libc.src.stdfix.abshr libc.src.stdfix.absk - libc.src.stdfix.absr libc.src.stdfix.abslk libc.src.stdfix.abslr + libc.src.stdfix.absr libc.src.stdfix.exphk libc.src.stdfix.expk libc.src.stdfix.roundhk libc.src.stdfix.roundhr libc.src.stdfix.roundk - libc.src.stdfix.roundr libc.src.stdfix.roundlk libc.src.stdfix.roundlr + libc.src.stdfix.roundr libc.src.stdfix.rounduhk libc.src.stdfix.rounduhr libc.src.stdfix.rounduk - libc.src.stdfix.roundur libc.src.stdfix.roundulk libc.src.stdfix.roundulr + libc.src.stdfix.roundur libc.src.stdfix.sqrtuhk libc.src.stdfix.sqrtuhr libc.src.stdfix.sqrtuk diff --git a/libc/config/darwin/arm/entrypoints.txt b/libc/config/darwin/arm/entrypoints.txt index e1303265b9ac41..4d5536318724d0 100644 --- a/libc/config/darwin/arm/entrypoints.txt +++ b/libc/config/darwin/arm/entrypoints.txt @@ -130,6 +130,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.ceilf libc.src.math.ceill libc.src.math.coshf + libc.src.math.cos libc.src.math.cosf libc.src.math.erff libc.src.math.exp @@ -224,8 +225,10 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.scalbn libc.src.math.scalbnf libc.src.math.scalbnl + libc.src.math.sincos libc.src.math.sincosf libc.src.math.sinhf + libc.src.math.sin libc.src.math.sinf libc.src.math.sqrt libc.src.math.sqrtf diff --git a/libc/config/gpu/entrypoints.txt b/libc/config/gpu/entrypoints.txt index 2217a696fc5d18..69f1bdb381e161 100644 --- a/libc/config/gpu/entrypoints.txt +++ b/libc/config/gpu/entrypoints.txt @@ -1,10 +1,10 @@ if(LIBC_TARGET_ARCHITECTURE_IS_AMDGPU) set(extra_entrypoints # stdio.h entrypoints - libc.src.stdio.sprintf libc.src.stdio.snprintf - libc.src.stdio.vsprintf + libc.src.stdio.sprintf libc.src.stdio.vsnprintf + libc.src.stdio.vsprintf ) endif() @@ -76,86 +76,90 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.string.strxfrm # stdbit.h entrypoints - libc.src.stdbit.stdc_leading_zeros_uc - libc.src.stdbit.stdc_leading_zeros_us - libc.src.stdbit.stdc_leading_zeros_ui - libc.src.stdbit.stdc_leading_zeros_ul - libc.src.stdbit.stdc_leading_zeros_ull - libc.src.stdbit.stdc_leading_ones_uc - libc.src.stdbit.stdc_leading_ones_us - libc.src.stdbit.stdc_leading_ones_ui - libc.src.stdbit.stdc_leading_ones_ul - libc.src.stdbit.stdc_leading_ones_ull - libc.src.stdbit.stdc_trailing_zeros_uc - libc.src.stdbit.stdc_trailing_zeros_us - libc.src.stdbit.stdc_trailing_zeros_ui - libc.src.stdbit.stdc_trailing_zeros_ul - libc.src.stdbit.stdc_trailing_zeros_ull - libc.src.stdbit.stdc_trailing_ones_uc - libc.src.stdbit.stdc_trailing_ones_us - libc.src.stdbit.stdc_trailing_ones_ui - libc.src.stdbit.stdc_trailing_ones_ul - libc.src.stdbit.stdc_trailing_ones_ull - libc.src.stdbit.stdc_first_leading_zero_uc - libc.src.stdbit.stdc_first_leading_zero_us - libc.src.stdbit.stdc_first_leading_zero_ui - libc.src.stdbit.stdc_first_leading_zero_ul - libc.src.stdbit.stdc_first_leading_zero_ull + libc.src.stdbit.stdc_bit_ceil_uc + libc.src.stdbit.stdc_bit_ceil_ui + libc.src.stdbit.stdc_bit_ceil_ul + libc.src.stdbit.stdc_bit_ceil_ull + libc.src.stdbit.stdc_bit_ceil_us + libc.src.stdbit.stdc_bit_floor_uc + libc.src.stdbit.stdc_bit_floor_ui + libc.src.stdbit.stdc_bit_floor_ul + libc.src.stdbit.stdc_bit_floor_ull + libc.src.stdbit.stdc_bit_floor_us + libc.src.stdbit.stdc_bit_width_uc + libc.src.stdbit.stdc_bit_width_ui + libc.src.stdbit.stdc_bit_width_ul + libc.src.stdbit.stdc_bit_width_ull + libc.src.stdbit.stdc_bit_width_us + libc.src.stdbit.stdc_count_ones_uc + libc.src.stdbit.stdc_count_ones_ui + libc.src.stdbit.stdc_count_ones_ul + libc.src.stdbit.stdc_count_ones_ull + libc.src.stdbit.stdc_count_ones_us + libc.src.stdbit.stdc_count_zeros_uc + libc.src.stdbit.stdc_count_zeros_ui + libc.src.stdbit.stdc_count_zeros_ul + libc.src.stdbit.stdc_count_zeros_ull + libc.src.stdbit.stdc_count_zeros_us libc.src.stdbit.stdc_first_leading_one_uc - libc.src.stdbit.stdc_first_leading_one_us libc.src.stdbit.stdc_first_leading_one_ui libc.src.stdbit.stdc_first_leading_one_ul libc.src.stdbit.stdc_first_leading_one_ull - libc.src.stdbit.stdc_first_trailing_zero_uc - libc.src.stdbit.stdc_first_trailing_zero_us - libc.src.stdbit.stdc_first_trailing_zero_ui - libc.src.stdbit.stdc_first_trailing_zero_ul - libc.src.stdbit.stdc_first_trailing_zero_ull + libc.src.stdbit.stdc_first_leading_one_us + libc.src.stdbit.stdc_first_leading_zero_uc + libc.src.stdbit.stdc_first_leading_zero_ui + libc.src.stdbit.stdc_first_leading_zero_ul + libc.src.stdbit.stdc_first_leading_zero_ull + libc.src.stdbit.stdc_first_leading_zero_us libc.src.stdbit.stdc_first_trailing_one_uc - libc.src.stdbit.stdc_first_trailing_one_us libc.src.stdbit.stdc_first_trailing_one_ui libc.src.stdbit.stdc_first_trailing_one_ul libc.src.stdbit.stdc_first_trailing_one_ull - libc.src.stdbit.stdc_count_zeros_uc - libc.src.stdbit.stdc_count_zeros_us - libc.src.stdbit.stdc_count_zeros_ui - libc.src.stdbit.stdc_count_zeros_ul - libc.src.stdbit.stdc_count_zeros_ull - libc.src.stdbit.stdc_count_ones_uc - libc.src.stdbit.stdc_count_ones_us - libc.src.stdbit.stdc_count_ones_ui - libc.src.stdbit.stdc_count_ones_ul - libc.src.stdbit.stdc_count_ones_ull + libc.src.stdbit.stdc_first_trailing_one_us + libc.src.stdbit.stdc_first_trailing_zero_uc + libc.src.stdbit.stdc_first_trailing_zero_ui + libc.src.stdbit.stdc_first_trailing_zero_ul + libc.src.stdbit.stdc_first_trailing_zero_ull + libc.src.stdbit.stdc_first_trailing_zero_us libc.src.stdbit.stdc_has_single_bit_uc - libc.src.stdbit.stdc_has_single_bit_us libc.src.stdbit.stdc_has_single_bit_ui libc.src.stdbit.stdc_has_single_bit_ul libc.src.stdbit.stdc_has_single_bit_ull - libc.src.stdbit.stdc_bit_width_uc - libc.src.stdbit.stdc_bit_width_us - libc.src.stdbit.stdc_bit_width_ui - libc.src.stdbit.stdc_bit_width_ul - libc.src.stdbit.stdc_bit_width_ull - libc.src.stdbit.stdc_bit_floor_uc - libc.src.stdbit.stdc_bit_floor_us - libc.src.stdbit.stdc_bit_floor_ui - libc.src.stdbit.stdc_bit_floor_ul - libc.src.stdbit.stdc_bit_floor_ull - libc.src.stdbit.stdc_bit_ceil_uc - libc.src.stdbit.stdc_bit_ceil_us - libc.src.stdbit.stdc_bit_ceil_ui - libc.src.stdbit.stdc_bit_ceil_ul - libc.src.stdbit.stdc_bit_ceil_ull + libc.src.stdbit.stdc_has_single_bit_us + libc.src.stdbit.stdc_leading_ones_uc + libc.src.stdbit.stdc_leading_ones_ui + libc.src.stdbit.stdc_leading_ones_ul + libc.src.stdbit.stdc_leading_ones_ull + libc.src.stdbit.stdc_leading_ones_us + libc.src.stdbit.stdc_leading_zeros_uc + libc.src.stdbit.stdc_leading_zeros_ui + libc.src.stdbit.stdc_leading_zeros_ul + libc.src.stdbit.stdc_leading_zeros_ull + libc.src.stdbit.stdc_leading_zeros_us + libc.src.stdbit.stdc_trailing_ones_uc + libc.src.stdbit.stdc_trailing_ones_ui + libc.src.stdbit.stdc_trailing_ones_ul + libc.src.stdbit.stdc_trailing_ones_ull + libc.src.stdbit.stdc_trailing_ones_us + libc.src.stdbit.stdc_trailing_zeros_uc + libc.src.stdbit.stdc_trailing_zeros_ui + libc.src.stdbit.stdc_trailing_zeros_ul + libc.src.stdbit.stdc_trailing_zeros_ull + libc.src.stdbit.stdc_trailing_zeros_us # stdlib.h entrypoints + libc.src.stdlib._Exit + libc.src.stdlib.abort libc.src.stdlib.abs - libc.src.stdlib.atoi + libc.src.stdlib.atexit libc.src.stdlib.atof + libc.src.stdlib.atoi libc.src.stdlib.atol libc.src.stdlib.atoll + libc.src.stdlib.bsearch libc.src.stdlib.div + libc.src.stdlib.exit libc.src.stdlib.labs - libc.src.stdlib.bsearch libc.src.stdlib.ldiv libc.src.stdlib.llabs libc.src.stdlib.lldiv @@ -170,45 +174,41 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.stdlib.strtoll libc.src.stdlib.strtoul libc.src.stdlib.strtoull - libc.src.stdlib._Exit - libc.src.stdlib.atexit - libc.src.stdlib.exit - libc.src.stdlib.abort # Only implemented in the test suite - libc.src.stdlib.malloc libc.src.stdlib.aligned_alloc - libc.src.stdlib.realloc libc.src.stdlib.free + libc.src.stdlib.malloc + libc.src.stdlib.realloc # errno.h entrypoints libc.src.errno.errno # stdio.h entrypoints ${extra_entrypoints} + libc.src.stdio.clearerr + libc.src.stdio.fclose libc.src.stdio.feof libc.src.stdio.ferror - libc.src.stdio.fseek libc.src.stdio.fflush - libc.src.stdio.ftell - libc.src.stdio.clearerr - libc.src.stdio.puts + libc.src.stdio.fgetc + libc.src.stdio.fgets libc.src.stdio.fopen - libc.src.stdio.fclose - libc.src.stdio.fread + libc.src.stdio.fputc libc.src.stdio.fputs + libc.src.stdio.fread + libc.src.stdio.fseek + libc.src.stdio.ftell libc.src.stdio.fwrite - libc.src.stdio.fputc - libc.src.stdio.putc - libc.src.stdio.putchar - libc.src.stdio.fgets - libc.src.stdio.fgetc libc.src.stdio.getc libc.src.stdio.getchar - libc.src.stdio.ungetc + libc.src.stdio.putc + libc.src.stdio.putchar + libc.src.stdio.puts + libc.src.stdio.stderr libc.src.stdio.stdin libc.src.stdio.stdout - libc.src.stdio.stderr + libc.src.stdio.ungetc # inttypes.h entrypoints libc.src.inttypes.imaxabs @@ -236,9 +236,9 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.asinh libc.src.math.asinhf libc.src.math.atan - libc.src.math.atanf libc.src.math.atan2 libc.src.math.atan2f + libc.src.math.atanf libc.src.math.atanh libc.src.math.atanhf libc.src.math.ceil @@ -251,11 +251,11 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.coshf libc.src.math.erf libc.src.math.erff + libc.src.math.exp libc.src.math.exp10 libc.src.math.exp10f libc.src.math.exp2 libc.src.math.exp2f - libc.src.math.exp libc.src.math.expf libc.src.math.expm1 libc.src.math.expm1f @@ -287,13 +287,13 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.llrintf libc.src.math.llround libc.src.math.llroundf + libc.src.math.log libc.src.math.log10 libc.src.math.log10f libc.src.math.log1p libc.src.math.log1pf libc.src.math.log2 libc.src.math.log2f - libc.src.math.log libc.src.math.logf libc.src.math.lrint libc.src.math.lrintf @@ -322,9 +322,9 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.scalbn libc.src.math.scalbnf libc.src.math.sin - libc.src.math.sinf libc.src.math.sincos libc.src.math.sincosf + libc.src.math.sinf libc.src.math.sinh libc.src.math.sinhf libc.src.math.sqrt diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index 63238ec0094fbf..ea89f8bd138d6a 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -92,81 +92,81 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.inttypes.strtoumax # stdbit.h entrypoints - libc.src.stdbit.stdc_leading_zeros_uc - libc.src.stdbit.stdc_leading_zeros_us - libc.src.stdbit.stdc_leading_zeros_ui - libc.src.stdbit.stdc_leading_zeros_ul - libc.src.stdbit.stdc_leading_zeros_ull - libc.src.stdbit.stdc_leading_ones_uc - libc.src.stdbit.stdc_leading_ones_us - libc.src.stdbit.stdc_leading_ones_ui - libc.src.stdbit.stdc_leading_ones_ul - libc.src.stdbit.stdc_leading_ones_ull - libc.src.stdbit.stdc_trailing_zeros_uc - libc.src.stdbit.stdc_trailing_zeros_us - libc.src.stdbit.stdc_trailing_zeros_ui - libc.src.stdbit.stdc_trailing_zeros_ul - libc.src.stdbit.stdc_trailing_zeros_ull - libc.src.stdbit.stdc_trailing_ones_uc - libc.src.stdbit.stdc_trailing_ones_us - libc.src.stdbit.stdc_trailing_ones_ui - libc.src.stdbit.stdc_trailing_ones_ul - libc.src.stdbit.stdc_trailing_ones_ull - libc.src.stdbit.stdc_first_leading_zero_uc - libc.src.stdbit.stdc_first_leading_zero_us - libc.src.stdbit.stdc_first_leading_zero_ui - libc.src.stdbit.stdc_first_leading_zero_ul - libc.src.stdbit.stdc_first_leading_zero_ull + libc.src.stdbit.stdc_bit_ceil_uc + libc.src.stdbit.stdc_bit_ceil_ui + libc.src.stdbit.stdc_bit_ceil_ul + libc.src.stdbit.stdc_bit_ceil_ull + libc.src.stdbit.stdc_bit_ceil_us + libc.src.stdbit.stdc_bit_floor_uc + libc.src.stdbit.stdc_bit_floor_ui + libc.src.stdbit.stdc_bit_floor_ul + libc.src.stdbit.stdc_bit_floor_ull + libc.src.stdbit.stdc_bit_floor_us + libc.src.stdbit.stdc_bit_width_uc + libc.src.stdbit.stdc_bit_width_ui + libc.src.stdbit.stdc_bit_width_ul + libc.src.stdbit.stdc_bit_width_ull + libc.src.stdbit.stdc_bit_width_us + libc.src.stdbit.stdc_count_ones_uc + libc.src.stdbit.stdc_count_ones_ui + libc.src.stdbit.stdc_count_ones_ul + libc.src.stdbit.stdc_count_ones_ull + libc.src.stdbit.stdc_count_ones_us + libc.src.stdbit.stdc_count_zeros_uc + libc.src.stdbit.stdc_count_zeros_ui + libc.src.stdbit.stdc_count_zeros_ul + libc.src.stdbit.stdc_count_zeros_ull + libc.src.stdbit.stdc_count_zeros_us libc.src.stdbit.stdc_first_leading_one_uc - libc.src.stdbit.stdc_first_leading_one_us libc.src.stdbit.stdc_first_leading_one_ui libc.src.stdbit.stdc_first_leading_one_ul libc.src.stdbit.stdc_first_leading_one_ull - libc.src.stdbit.stdc_first_trailing_zero_uc - libc.src.stdbit.stdc_first_trailing_zero_us - libc.src.stdbit.stdc_first_trailing_zero_ui - libc.src.stdbit.stdc_first_trailing_zero_ul - libc.src.stdbit.stdc_first_trailing_zero_ull + libc.src.stdbit.stdc_first_leading_one_us + libc.src.stdbit.stdc_first_leading_zero_uc + libc.src.stdbit.stdc_first_leading_zero_ui + libc.src.stdbit.stdc_first_leading_zero_ul + libc.src.stdbit.stdc_first_leading_zero_ull + libc.src.stdbit.stdc_first_leading_zero_us libc.src.stdbit.stdc_first_trailing_one_uc - libc.src.stdbit.stdc_first_trailing_one_us libc.src.stdbit.stdc_first_trailing_one_ui libc.src.stdbit.stdc_first_trailing_one_ul libc.src.stdbit.stdc_first_trailing_one_ull - libc.src.stdbit.stdc_count_zeros_uc - libc.src.stdbit.stdc_count_zeros_us - libc.src.stdbit.stdc_count_zeros_ui - libc.src.stdbit.stdc_count_zeros_ul - libc.src.stdbit.stdc_count_zeros_ull - libc.src.stdbit.stdc_count_ones_uc - libc.src.stdbit.stdc_count_ones_us - libc.src.stdbit.stdc_count_ones_ui - libc.src.stdbit.stdc_count_ones_ul - libc.src.stdbit.stdc_count_ones_ull + libc.src.stdbit.stdc_first_trailing_one_us + libc.src.stdbit.stdc_first_trailing_zero_uc + libc.src.stdbit.stdc_first_trailing_zero_ui + libc.src.stdbit.stdc_first_trailing_zero_ul + libc.src.stdbit.stdc_first_trailing_zero_ull + libc.src.stdbit.stdc_first_trailing_zero_us libc.src.stdbit.stdc_has_single_bit_uc - libc.src.stdbit.stdc_has_single_bit_us libc.src.stdbit.stdc_has_single_bit_ui libc.src.stdbit.stdc_has_single_bit_ul libc.src.stdbit.stdc_has_single_bit_ull - libc.src.stdbit.stdc_bit_width_uc - libc.src.stdbit.stdc_bit_width_us - libc.src.stdbit.stdc_bit_width_ui - libc.src.stdbit.stdc_bit_width_ul - libc.src.stdbit.stdc_bit_width_ull - libc.src.stdbit.stdc_bit_floor_uc - libc.src.stdbit.stdc_bit_floor_us - libc.src.stdbit.stdc_bit_floor_ui - libc.src.stdbit.stdc_bit_floor_ul - libc.src.stdbit.stdc_bit_floor_ull - libc.src.stdbit.stdc_bit_ceil_uc - libc.src.stdbit.stdc_bit_ceil_us - libc.src.stdbit.stdc_bit_ceil_ui - libc.src.stdbit.stdc_bit_ceil_ul - libc.src.stdbit.stdc_bit_ceil_ull + libc.src.stdbit.stdc_has_single_bit_us + libc.src.stdbit.stdc_leading_ones_uc + libc.src.stdbit.stdc_leading_ones_ui + libc.src.stdbit.stdc_leading_ones_ul + libc.src.stdbit.stdc_leading_ones_ull + libc.src.stdbit.stdc_leading_ones_us + libc.src.stdbit.stdc_leading_zeros_uc + libc.src.stdbit.stdc_leading_zeros_ui + libc.src.stdbit.stdc_leading_zeros_ul + libc.src.stdbit.stdc_leading_zeros_ull + libc.src.stdbit.stdc_leading_zeros_us + libc.src.stdbit.stdc_trailing_ones_uc + libc.src.stdbit.stdc_trailing_ones_ui + libc.src.stdbit.stdc_trailing_ones_ul + libc.src.stdbit.stdc_trailing_ones_ull + libc.src.stdbit.stdc_trailing_ones_us + libc.src.stdbit.stdc_trailing_zeros_uc + libc.src.stdbit.stdc_trailing_zeros_ui + libc.src.stdbit.stdc_trailing_zeros_ul + libc.src.stdbit.stdc_trailing_zeros_ull + libc.src.stdbit.stdc_trailing_zeros_us # stdlib.h entrypoints libc.src.stdlib.abs - libc.src.stdlib.atoi libc.src.stdlib.atof + libc.src.stdlib.atoi libc.src.stdlib.atol libc.src.stdlib.atoll libc.src.stdlib.bsearch @@ -188,37 +188,37 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.stdlib.strtoull # stdlib.h external entrypoints - libc.src.stdlib.malloc - libc.src.stdlib.calloc - libc.src.stdlib.realloc libc.src.stdlib.aligned_alloc + libc.src.stdlib.calloc libc.src.stdlib.free + libc.src.stdlib.malloc + libc.src.stdlib.realloc # stdio.h entrypoints + libc.src.stdio.fdopen + #libc.src.stdio.fscanf libc.src.stdio.remove libc.src.stdio.rename - libc.src.stdio.sprintf libc.src.stdio.snprintf - libc.src.stdio.vsprintf - libc.src.stdio.vsnprintf - libc.src.stdio.fdopen - #libc.src.stdio.sscanf + libc.src.stdio.sprintf #libc.src.stdio.scanf - #libc.src.stdio.fscanf + #libc.src.stdio.sscanf + libc.src.stdio.vsnprintf + libc.src.stdio.vsprintf # sys/mman.h entrypoints libc.src.sys.mman.madvise - libc.src.sys.mman.mmap - libc.src.sys.mman.mprotect - libc.src.sys.mman.munmap - libc.src.sys.mman.posix_madvise libc.src.sys.mman.mincore libc.src.sys.mman.mlock libc.src.sys.mman.mlock2 - libc.src.sys.mman.munlock libc.src.sys.mman.mlockall - libc.src.sys.mman.munlockall + libc.src.sys.mman.mmap + libc.src.sys.mman.mprotect libc.src.sys.mman.msync + libc.src.sys.mman.munlock + libc.src.sys.mman.munlockall + libc.src.sys.mman.munmap + libc.src.sys.mman.posix_madvise libc.src.sys.mman.shm_open libc.src.sys.mman.shm_unlink @@ -267,11 +267,11 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.termios.cfgetospeed libc.src.termios.cfsetispeed libc.src.termios.cfsetospeed - libc.src.termios.tcgetattr - libc.src.termios.tcgetsid libc.src.termios.tcdrain libc.src.termios.tcflow libc.src.termios.tcflush + libc.src.termios.tcgetattr + libc.src.termios.tcgetsid libc.src.termios.tcsendbreak libc.src.termios.tcsetattr @@ -320,11 +320,11 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.fenv.fegetexceptflag libc.src.fenv.fegetround libc.src.fenv.feholdexcept + libc.src.fenv.feraiseexcept libc.src.fenv.fesetenv libc.src.fenv.fesetexcept libc.src.fenv.fesetexceptflag libc.src.fenv.fesetround - libc.src.fenv.feraiseexcept libc.src.fenv.fetestexcept libc.src.fenv.fetestexceptflag libc.src.fenv.feupdateenv @@ -337,21 +337,22 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.atan2f libc.src.math.atanf libc.src.math.atanhf - libc.src.math.copysign - libc.src.math.copysignf - libc.src.math.copysignl libc.src.math.ceil libc.src.math.ceilf libc.src.math.ceill - libc.src.math.coshf + libc.src.math.copysign + libc.src.math.copysignf + libc.src.math.copysignl + libc.src.math.cos libc.src.math.cosf + libc.src.math.coshf libc.src.math.erff libc.src.math.exp - libc.src.math.expf libc.src.math.exp10 libc.src.math.exp10f libc.src.math.exp2 libc.src.math.exp2f + libc.src.math.expf libc.src.math.expm1 libc.src.math.expm1f libc.src.math.fabs @@ -367,38 +368,38 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.fmaf libc.src.math.fmax libc.src.math.fmaxf - libc.src.math.fmaxl - libc.src.math.fmin - libc.src.math.fminf - libc.src.math.fminl libc.src.math.fmaximum - libc.src.math.fmaximumf - libc.src.math.fmaximuml - libc.src.math.fmaximum_num - libc.src.math.fmaximum_numf - libc.src.math.fmaximum_numl libc.src.math.fmaximum_mag - libc.src.math.fmaximum_magf - libc.src.math.fmaximum_magl libc.src.math.fmaximum_mag_num libc.src.math.fmaximum_mag_numf libc.src.math.fmaximum_mag_numl + libc.src.math.fmaximum_magf + libc.src.math.fmaximum_magl + libc.src.math.fmaximum_num + libc.src.math.fmaximum_numf + libc.src.math.fmaximum_numl + libc.src.math.fmaximumf + libc.src.math.fmaximuml + libc.src.math.fmaxl + libc.src.math.fmin + libc.src.math.fminf libc.src.math.fminimum - libc.src.math.fminimumf - libc.src.math.fminimuml - libc.src.math.fminimum_num - libc.src.math.fminimum_numf - libc.src.math.fminimum_numl libc.src.math.fminimum_mag - libc.src.math.fminimum_magf - libc.src.math.fminimum_magl libc.src.math.fminimum_mag_num libc.src.math.fminimum_mag_numf libc.src.math.fminimum_mag_numl - libc.src.math.fmul + libc.src.math.fminimum_magf + libc.src.math.fminimum_magl + libc.src.math.fminimum_num + libc.src.math.fminimum_numf + libc.src.math.fminimum_numl + libc.src.math.fminimumf + libc.src.math.fminimuml + libc.src.math.fminl libc.src.math.fmod libc.src.math.fmodf libc.src.math.fmodl + libc.src.math.fmul libc.src.math.frexp libc.src.math.frexpf libc.src.math.frexpl @@ -413,6 +414,9 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.ilogb libc.src.math.ilogbf libc.src.math.ilogbl + libc.src.math.ldexp + libc.src.math.ldexpf + libc.src.math.ldexpl libc.src.math.llogb libc.src.math.llogbf libc.src.math.llogbl @@ -422,26 +426,23 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.llround libc.src.math.llroundf libc.src.math.llroundl - libc.src.math.lrint - libc.src.math.lrintf - libc.src.math.lrintl - libc.src.math.lround - libc.src.math.lroundf - libc.src.math.lroundl - libc.src.math.ldexp - libc.src.math.ldexpf - libc.src.math.ldexpl + libc.src.math.log libc.src.math.log10 libc.src.math.log10f libc.src.math.log1p libc.src.math.log1pf libc.src.math.log2 libc.src.math.log2f - libc.src.math.log - libc.src.math.logf libc.src.math.logb libc.src.math.logbf libc.src.math.logbl + libc.src.math.logf + libc.src.math.lrint + libc.src.math.lrintf + libc.src.math.lrintl + libc.src.math.lround + libc.src.math.lroundf + libc.src.math.lroundl libc.src.math.modf libc.src.math.modff libc.src.math.modfl @@ -464,11 +465,11 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.nextupf libc.src.math.nextupl libc.src.math.powf - libc.src.math.remainderf libc.src.math.remainder + libc.src.math.remainderf libc.src.math.remainderl - libc.src.math.remquof libc.src.math.remquo + libc.src.math.remquof libc.src.math.remquol libc.src.math.rint libc.src.math.rintf @@ -479,9 +480,11 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.scalbn libc.src.math.scalbnf libc.src.math.scalbnl + libc.src.math.sin + libc.src.math.sincos libc.src.math.sincosf - libc.src.math.sinhf libc.src.math.sinf + libc.src.math.sinhf libc.src.math.sqrt libc.src.math.sqrtf libc.src.math.sqrtl @@ -504,21 +507,24 @@ if(LIBC_TYPES_HAS_FLOAT16) libc.src.math.canonicalizef16 libc.src.math.ceilf16 libc.src.math.copysignf16 + libc.src.math.f16div + libc.src.math.f16divf libc.src.math.f16fmaf + libc.src.math.f16sqrt libc.src.math.f16sqrtf libc.src.math.fabsf16 libc.src.math.fdimf16 libc.src.math.floorf16 libc.src.math.fmaxf16 - libc.src.math.fmaximumf16 - libc.src.math.fmaximum_magf16 libc.src.math.fmaximum_mag_numf16 + libc.src.math.fmaximum_magf16 libc.src.math.fmaximum_numf16 + libc.src.math.fmaximumf16 libc.src.math.fminf16 - libc.src.math.fminimumf16 - libc.src.math.fminimum_magf16 libc.src.math.fminimum_mag_numf16 + libc.src.math.fminimum_magf16 libc.src.math.fminimum_numf16 + libc.src.math.fminimumf16 libc.src.math.frexpf16 libc.src.math.fromfpf16 libc.src.math.fromfpxf16 @@ -544,8 +550,8 @@ if(LIBC_TYPES_HAS_FLOAT16) libc.src.math.remainderf16 libc.src.math.remquof16 libc.src.math.rintf16 - libc.src.math.roundf16 libc.src.math.roundevenf16 + libc.src.math.roundf16 libc.src.math.scalblnf16 libc.src.math.scalbnf16 libc.src.math.setpayloadf16 @@ -567,15 +573,15 @@ if(LIBC_TYPES_HAS_FLOAT128) libc.src.math.fdimf128 libc.src.math.floorf128 libc.src.math.fmaxf128 - libc.src.math.fminf128 - libc.src.math.fmaximumf128 - libc.src.math.fmaximum_numf128 - libc.src.math.fmaximum_magf128 libc.src.math.fmaximum_mag_numf128 - libc.src.math.fminimumf128 - libc.src.math.fminimum_numf128 - libc.src.math.fminimum_magf128 + libc.src.math.fmaximum_magf128 + libc.src.math.fmaximum_numf128 + libc.src.math.fmaximumf128 + libc.src.math.fminf128 libc.src.math.fminimum_mag_numf128 + libc.src.math.fminimum_magf128 + libc.src.math.fminimum_numf128 + libc.src.math.fminimumf128 libc.src.math.fmodf128 libc.src.math.frexpf128 libc.src.math.fromfpf128 @@ -583,9 +589,9 @@ if(LIBC_TYPES_HAS_FLOAT128) libc.src.math.ilogbf128 libc.src.math.ldexpf128 libc.src.math.llogbf128 - libc.src.math.logbf128 libc.src.math.llrintf128 libc.src.math.llroundf128 + libc.src.math.logbf128 libc.src.math.lrintf128 libc.src.math.lroundf128 libc.src.math.modff128 @@ -619,11 +625,11 @@ if(LLVM_LIBC_FULL_BUILD) # pthread.h entrypoints libc.src.pthread.pthread_atfork libc.src.pthread.pthread_attr_destroy - libc.src.pthread.pthread_attr_init libc.src.pthread.pthread_attr_getdetachstate libc.src.pthread.pthread_attr_getguardsize libc.src.pthread.pthread_attr_getstack libc.src.pthread.pthread_attr_getstacksize + libc.src.pthread.pthread_attr_init libc.src.pthread.pthread_attr_setdetachstate libc.src.pthread.pthread_attr_setguardsize libc.src.pthread.pthread_attr_setstack @@ -637,36 +643,36 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.pthread.pthread_join libc.src.pthread.pthread_key_create libc.src.pthread.pthread_key_delete - libc.src.pthread.pthread_self - libc.src.pthread.pthread_setname_np libc.src.pthread.pthread_mutex_destroy libc.src.pthread.pthread_mutex_init libc.src.pthread.pthread_mutex_lock libc.src.pthread.pthread_mutex_unlock libc.src.pthread.pthread_mutexattr_destroy - libc.src.pthread.pthread_mutexattr_init libc.src.pthread.pthread_mutexattr_getpshared libc.src.pthread.pthread_mutexattr_getrobust libc.src.pthread.pthread_mutexattr_gettype + libc.src.pthread.pthread_mutexattr_init libc.src.pthread.pthread_mutexattr_setpshared libc.src.pthread.pthread_mutexattr_setrobust libc.src.pthread.pthread_mutexattr_settype libc.src.pthread.pthread_once + libc.src.pthread.pthread_rwlock_destroy libc.src.pthread.pthread_rwlock_init - libc.src.pthread.pthread_rwlock_tryrdlock libc.src.pthread.pthread_rwlock_rdlock libc.src.pthread.pthread_rwlock_timedrdlock - libc.src.pthread.pthread_rwlock_trywrlock - libc.src.pthread.pthread_rwlock_wrlock libc.src.pthread.pthread_rwlock_timedwrlock + libc.src.pthread.pthread_rwlock_tryrdlock + libc.src.pthread.pthread_rwlock_trywrlock libc.src.pthread.pthread_rwlock_unlock - libc.src.pthread.pthread_rwlock_destroy + libc.src.pthread.pthread_rwlock_wrlock libc.src.pthread.pthread_rwlockattr_destroy libc.src.pthread.pthread_rwlockattr_getkind_np libc.src.pthread.pthread_rwlockattr_getpshared libc.src.pthread.pthread_rwlockattr_init libc.src.pthread.pthread_rwlockattr_setkind_np libc.src.pthread.pthread_rwlockattr_setpshared + libc.src.pthread.pthread_self + libc.src.pthread.pthread_setname_np libc.src.pthread.pthread_setspecific # sched.h entrypoints @@ -676,18 +682,18 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.stdio.clearerr libc.src.stdio.clearerr_unlocked libc.src.stdio.fclose - libc.src.stdio.flockfile libc.src.stdio.feof libc.src.stdio.feof_unlocked libc.src.stdio.ferror libc.src.stdio.ferror_unlocked - libc.src.stdio.fgetc libc.src.stdio.fflush + libc.src.stdio.fgetc libc.src.stdio.fileno + libc.src.stdio.flockfile libc.src.stdio.fopen + libc.src.stdio.fopencookie libc.src.stdio.fputc libc.src.stdio.fputs - libc.src.stdio.fopencookie libc.src.stdio.fread libc.src.stdio.fread_unlocked libc.src.stdio.fseek @@ -699,14 +705,14 @@ if(LLVM_LIBC_FULL_BUILD) #TODO: Look into if fprintf can be enabled for overlay on aarch64 libc.src.stdio.fprintf libc.src.stdio.printf - libc.src.stdio.vfprintf - libc.src.stdio.vprintf libc.src.stdio.putc libc.src.stdio.putchar libc.src.stdio.puts libc.src.stdio.stderr libc.src.stdio.stdin libc.src.stdio.stdout + libc.src.stdio.vfprintf + libc.src.stdio.vprintf # stdlib.h entrypoints libc.src.stdlib._Exit @@ -716,24 +722,24 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.stdlib.getenv # signal.h entrypoints - libc.src.signal.raise libc.src.signal.kill + libc.src.signal.raise libc.src.signal.sigaction + libc.src.signal.sigaddset libc.src.signal.sigaltstack libc.src.signal.sigdelset - libc.src.signal.sigaddset libc.src.signal.sigemptyset - libc.src.signal.sigprocmask libc.src.signal.sigfillset libc.src.signal.signal + libc.src.signal.sigprocmask # search.h entrypoints libc.src.search.hcreate libc.src.search.hcreate_r - libc.src.search.hsearch - libc.src.search.hsearch_r libc.src.search.hdestroy libc.src.search.hdestroy_r + libc.src.search.hsearch + libc.src.search.hsearch_r libc.src.search.insque libc.src.search.remque @@ -762,8 +768,8 @@ if(LLVM_LIBC_FULL_BUILD) # time.h entrypoints libc.src.time.asctime libc.src.time.asctime_r - libc.src.time.clock_gettime libc.src.time.clock + libc.src.time.clock_gettime libc.src.time.difftime libc.src.time.gettimeofday libc.src.time.gmtime @@ -780,9 +786,9 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.unistd.fork libc.src.unistd.getopt libc.src.unistd.optarg + libc.src.unistd.opterr libc.src.unistd.optind libc.src.unistd.optopt - libc.src.unistd.opterr libc.src.unistd.swab # sys/select.h entrypoints diff --git a/libc/config/linux/app.h b/libc/config/linux/app.h index 766cd49e88f6f7..2a3b1560817b8b 100644 --- a/libc/config/linux/app.h +++ b/libc/config/linux/app.h @@ -35,24 +35,6 @@ struct TLSImage { uintptr_t align; }; -#if defined(LIBC_TARGET_ARCH_IS_X86_64) || \ - defined(LIBC_TARGET_ARCH_IS_AARCH64) || \ - defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) -// At the language level, argc is an int. But we use uint64_t as the x86_64 -// ABI specifies it as an 8 byte value. Likewise, in the ARM64 ABI, arguments -// are usually passed in registers. x0 is a doubleword register, so this is -// 64 bit for aarch64 as well. -typedef uintptr_t ArgcType; - -// At the language level, argv is a char** value. However, we use uint64_t as -// ABIs specify the argv vector be an |argc| long array of 8-byte values. -typedef uintptr_t ArgVEntryType; - -typedef uintptr_t EnvironType; -#else -#error "argc and argv types are not defined for the target platform." -#endif - // Linux manpage on `proc(5)` says that the aux vector is an array of // unsigned long pairs. // (see: https://man7.org/linux/man-pages/man5/proc.5.html) @@ -65,7 +47,7 @@ struct AuxEntry { }; struct Args { - ArgcType argc; + uintptr_t argc; // A flexible length array would be more suitable here, but C++ doesn't have // flexible arrays: P1039 proposes to fix this. So, for now we just fake it. @@ -73,7 +55,7 @@ struct Args { // (ISO C 5.1.2.2.1) so one is fine. Also, length of 1 is not really wrong as // |argc| is guaranteed to be atleast 1, and there is an 8-byte null entry at // the end of the argv array. - ArgVEntryType argv[1]; + uintptr_t argv[1]; }; // Data structure which captures properties of a linux application. @@ -87,7 +69,7 @@ struct AppProperties { TLSImage tls; // Environment data. - EnvironType *env_ptr; + uintptr_t *env_ptr; // Auxiliary vector data. AuxEntry *auxv_ptr; diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt index 681d3d2583fd3d..a27a4941534808 100644 --- a/libc/config/linux/arm/entrypoints.txt +++ b/libc/config/linux/arm/entrypoints.txt @@ -20,10 +20,6 @@ set(TARGET_LIBC_ENTRYPOINTS # errno.h entrypoints libc.src.errno.errno - # setjmp.h entrypoints - libc.src.setjmp.longjmp - libc.src.setjmp.setjmp - # string.h entrypoints libc.src.string.bcmp libc.src.string.bcopy @@ -72,81 +68,81 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.inttypes.strtoumax # stdbit.h entrypoints - libc.src.stdbit.stdc_leading_zeros_uc - libc.src.stdbit.stdc_leading_zeros_us - libc.src.stdbit.stdc_leading_zeros_ui - libc.src.stdbit.stdc_leading_zeros_ul - libc.src.stdbit.stdc_leading_zeros_ull - libc.src.stdbit.stdc_leading_ones_uc - libc.src.stdbit.stdc_leading_ones_us - libc.src.stdbit.stdc_leading_ones_ui - libc.src.stdbit.stdc_leading_ones_ul - libc.src.stdbit.stdc_leading_ones_ull - libc.src.stdbit.stdc_trailing_zeros_uc - libc.src.stdbit.stdc_trailing_zeros_us - libc.src.stdbit.stdc_trailing_zeros_ui - libc.src.stdbit.stdc_trailing_zeros_ul - libc.src.stdbit.stdc_trailing_zeros_ull - libc.src.stdbit.stdc_trailing_ones_uc - libc.src.stdbit.stdc_trailing_ones_us - libc.src.stdbit.stdc_trailing_ones_ui - libc.src.stdbit.stdc_trailing_ones_ul - libc.src.stdbit.stdc_trailing_ones_ull - libc.src.stdbit.stdc_first_leading_zero_uc - libc.src.stdbit.stdc_first_leading_zero_us - libc.src.stdbit.stdc_first_leading_zero_ui - libc.src.stdbit.stdc_first_leading_zero_ul - libc.src.stdbit.stdc_first_leading_zero_ull + libc.src.stdbit.stdc_bit_ceil_uc + libc.src.stdbit.stdc_bit_ceil_ui + libc.src.stdbit.stdc_bit_ceil_ul + libc.src.stdbit.stdc_bit_ceil_ull + libc.src.stdbit.stdc_bit_ceil_us + libc.src.stdbit.stdc_bit_floor_uc + libc.src.stdbit.stdc_bit_floor_ui + libc.src.stdbit.stdc_bit_floor_ul + libc.src.stdbit.stdc_bit_floor_ull + libc.src.stdbit.stdc_bit_floor_us + libc.src.stdbit.stdc_bit_width_uc + libc.src.stdbit.stdc_bit_width_ui + libc.src.stdbit.stdc_bit_width_ul + libc.src.stdbit.stdc_bit_width_ull + libc.src.stdbit.stdc_bit_width_us + libc.src.stdbit.stdc_count_ones_uc + libc.src.stdbit.stdc_count_ones_ui + libc.src.stdbit.stdc_count_ones_ul + libc.src.stdbit.stdc_count_ones_ull + libc.src.stdbit.stdc_count_ones_us + libc.src.stdbit.stdc_count_zeros_uc + libc.src.stdbit.stdc_count_zeros_ui + libc.src.stdbit.stdc_count_zeros_ul + libc.src.stdbit.stdc_count_zeros_ull + libc.src.stdbit.stdc_count_zeros_us libc.src.stdbit.stdc_first_leading_one_uc - libc.src.stdbit.stdc_first_leading_one_us libc.src.stdbit.stdc_first_leading_one_ui libc.src.stdbit.stdc_first_leading_one_ul libc.src.stdbit.stdc_first_leading_one_ull - libc.src.stdbit.stdc_first_trailing_zero_uc - libc.src.stdbit.stdc_first_trailing_zero_us - libc.src.stdbit.stdc_first_trailing_zero_ui - libc.src.stdbit.stdc_first_trailing_zero_ul - libc.src.stdbit.stdc_first_trailing_zero_ull + libc.src.stdbit.stdc_first_leading_one_us + libc.src.stdbit.stdc_first_leading_zero_uc + libc.src.stdbit.stdc_first_leading_zero_ui + libc.src.stdbit.stdc_first_leading_zero_ul + libc.src.stdbit.stdc_first_leading_zero_ull + libc.src.stdbit.stdc_first_leading_zero_us libc.src.stdbit.stdc_first_trailing_one_uc - libc.src.stdbit.stdc_first_trailing_one_us libc.src.stdbit.stdc_first_trailing_one_ui libc.src.stdbit.stdc_first_trailing_one_ul libc.src.stdbit.stdc_first_trailing_one_ull - libc.src.stdbit.stdc_count_zeros_uc - libc.src.stdbit.stdc_count_zeros_us - libc.src.stdbit.stdc_count_zeros_ui - libc.src.stdbit.stdc_count_zeros_ul - libc.src.stdbit.stdc_count_zeros_ull - libc.src.stdbit.stdc_count_ones_uc - libc.src.stdbit.stdc_count_ones_us - libc.src.stdbit.stdc_count_ones_ui - libc.src.stdbit.stdc_count_ones_ul - libc.src.stdbit.stdc_count_ones_ull + libc.src.stdbit.stdc_first_trailing_one_us + libc.src.stdbit.stdc_first_trailing_zero_uc + libc.src.stdbit.stdc_first_trailing_zero_ui + libc.src.stdbit.stdc_first_trailing_zero_ul + libc.src.stdbit.stdc_first_trailing_zero_ull + libc.src.stdbit.stdc_first_trailing_zero_us libc.src.stdbit.stdc_has_single_bit_uc - libc.src.stdbit.stdc_has_single_bit_us libc.src.stdbit.stdc_has_single_bit_ui libc.src.stdbit.stdc_has_single_bit_ul libc.src.stdbit.stdc_has_single_bit_ull - libc.src.stdbit.stdc_bit_width_uc - libc.src.stdbit.stdc_bit_width_us - libc.src.stdbit.stdc_bit_width_ui - libc.src.stdbit.stdc_bit_width_ul - libc.src.stdbit.stdc_bit_width_ull - libc.src.stdbit.stdc_bit_floor_uc - libc.src.stdbit.stdc_bit_floor_us - libc.src.stdbit.stdc_bit_floor_ui - libc.src.stdbit.stdc_bit_floor_ul - libc.src.stdbit.stdc_bit_floor_ull - libc.src.stdbit.stdc_bit_ceil_uc - libc.src.stdbit.stdc_bit_ceil_us - libc.src.stdbit.stdc_bit_ceil_ui - libc.src.stdbit.stdc_bit_ceil_ul - libc.src.stdbit.stdc_bit_ceil_ull + libc.src.stdbit.stdc_has_single_bit_us + libc.src.stdbit.stdc_leading_ones_uc + libc.src.stdbit.stdc_leading_ones_ui + libc.src.stdbit.stdc_leading_ones_ul + libc.src.stdbit.stdc_leading_ones_ull + libc.src.stdbit.stdc_leading_ones_us + libc.src.stdbit.stdc_leading_zeros_uc + libc.src.stdbit.stdc_leading_zeros_ui + libc.src.stdbit.stdc_leading_zeros_ul + libc.src.stdbit.stdc_leading_zeros_ull + libc.src.stdbit.stdc_leading_zeros_us + libc.src.stdbit.stdc_trailing_ones_uc + libc.src.stdbit.stdc_trailing_ones_ui + libc.src.stdbit.stdc_trailing_ones_ul + libc.src.stdbit.stdc_trailing_ones_ull + libc.src.stdbit.stdc_trailing_ones_us + libc.src.stdbit.stdc_trailing_zeros_uc + libc.src.stdbit.stdc_trailing_zeros_ui + libc.src.stdbit.stdc_trailing_zeros_ul + libc.src.stdbit.stdc_trailing_zeros_ull + libc.src.stdbit.stdc_trailing_zeros_us # stdlib.h entrypoints libc.src.stdlib.abs - libc.src.stdlib.atoi libc.src.stdlib.atof + libc.src.stdlib.atoi libc.src.stdlib.atol libc.src.stdlib.atoll libc.src.stdlib.bsearch @@ -165,6 +161,11 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.stdlib.strtoul libc.src.stdlib.strtoull + # stdlib.h external entrypoints + libc.src.stdlib.aligned_alloc + libc.src.stdlib.free + libc.src.stdlib.malloc + # sys/mman.h entrypoints libc.src.sys.mman.mmap libc.src.sys.mman.munmap @@ -180,6 +181,14 @@ set(TARGET_LIBC_ENTRYPOINTS ) +if(LLVM_LIBC_FULL_BUILD) + list(APPEND TARGET_LIBC_ENTRYPOINTS + # setjmp.h entrypoints + libc.src.setjmp.longjmp + libc.src.setjmp.setjmp + ) +endif() + set(TARGET_LIBM_ENTRYPOINTS # fenv.h entrypoints libc.src.fenv.feclearexcept @@ -190,11 +199,11 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.fenv.fegetexceptflag libc.src.fenv.fegetround libc.src.fenv.feholdexcept + libc.src.fenv.feraiseexcept libc.src.fenv.fesetenv libc.src.fenv.fesetexcept libc.src.fenv.fesetexceptflag libc.src.fenv.fesetround - libc.src.fenv.feraiseexcept libc.src.fenv.fetestexcept libc.src.fenv.fetestexceptflag libc.src.fenv.feupdateenv @@ -213,6 +222,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.copysign libc.src.math.copysignf libc.src.math.copysignl + libc.src.math.cos libc.src.math.cosf libc.src.math.coshf libc.src.math.erff @@ -237,37 +247,37 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.fmaf libc.src.math.fmax libc.src.math.fmaxf - libc.src.math.fmaxl - libc.src.math.fmin - libc.src.math.fminf - libc.src.math.fminl libc.src.math.fmaximum - libc.src.math.fmaximumf - libc.src.math.fmaximuml - libc.src.math.fmaximum_num - libc.src.math.fmaximum_numf - libc.src.math.fmaximum_numl libc.src.math.fmaximum_mag - libc.src.math.fmaximum_magf - libc.src.math.fmaximum_magl libc.src.math.fmaximum_mag_num libc.src.math.fmaximum_mag_numf libc.src.math.fmaximum_mag_numl + libc.src.math.fmaximum_magf + libc.src.math.fmaximum_magl + libc.src.math.fmaximum_num + libc.src.math.fmaximum_numf + libc.src.math.fmaximum_numl + libc.src.math.fmaximumf + libc.src.math.fmaximuml + libc.src.math.fmaxl + libc.src.math.fmin + libc.src.math.fminf libc.src.math.fminimum - libc.src.math.fminimumf - libc.src.math.fminimuml - libc.src.math.fminimum_num - libc.src.math.fminimum_numf - libc.src.math.fminimum_numl libc.src.math.fminimum_mag - libc.src.math.fminimum_magf - libc.src.math.fminimum_magl libc.src.math.fminimum_mag_num libc.src.math.fminimum_mag_numf libc.src.math.fminimum_mag_numl - libc.src.math.fmul + libc.src.math.fminimum_magf + libc.src.math.fminimum_magl + libc.src.math.fminimum_num + libc.src.math.fminimum_numf + libc.src.math.fminimum_numl + libc.src.math.fminimumf + libc.src.math.fminimuml + libc.src.math.fminl libc.src.math.fmod libc.src.math.fmodf + libc.src.math.fmul libc.src.math.frexp libc.src.math.frexpf libc.src.math.frexpl @@ -348,6 +358,8 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.scalbn libc.src.math.scalbnf libc.src.math.scalbnl + libc.src.math.sin + libc.src.math.sincos libc.src.math.sincosf libc.src.math.sinf libc.src.math.sinhf diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt index e12d6b3957e518..ee8b3d531637e6 100644 --- a/libc/config/linux/riscv/entrypoints.txt +++ b/libc/config/linux/riscv/entrypoints.txt @@ -93,81 +93,81 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.inttypes.strtoumax # stdbit.h entrypoints - libc.src.stdbit.stdc_leading_zeros_uc - libc.src.stdbit.stdc_leading_zeros_us - libc.src.stdbit.stdc_leading_zeros_ui - libc.src.stdbit.stdc_leading_zeros_ul - libc.src.stdbit.stdc_leading_zeros_ull - libc.src.stdbit.stdc_leading_ones_uc - libc.src.stdbit.stdc_leading_ones_us - libc.src.stdbit.stdc_leading_ones_ui - libc.src.stdbit.stdc_leading_ones_ul - libc.src.stdbit.stdc_leading_ones_ull - libc.src.stdbit.stdc_trailing_zeros_uc - libc.src.stdbit.stdc_trailing_zeros_us - libc.src.stdbit.stdc_trailing_zeros_ui - libc.src.stdbit.stdc_trailing_zeros_ul - libc.src.stdbit.stdc_trailing_zeros_ull - libc.src.stdbit.stdc_trailing_ones_uc - libc.src.stdbit.stdc_trailing_ones_us - libc.src.stdbit.stdc_trailing_ones_ui - libc.src.stdbit.stdc_trailing_ones_ul - libc.src.stdbit.stdc_trailing_ones_ull - libc.src.stdbit.stdc_first_leading_zero_uc - libc.src.stdbit.stdc_first_leading_zero_us - libc.src.stdbit.stdc_first_leading_zero_ui - libc.src.stdbit.stdc_first_leading_zero_ul - libc.src.stdbit.stdc_first_leading_zero_ull + libc.src.stdbit.stdc_bit_ceil_uc + libc.src.stdbit.stdc_bit_ceil_ui + libc.src.stdbit.stdc_bit_ceil_ul + libc.src.stdbit.stdc_bit_ceil_ull + libc.src.stdbit.stdc_bit_ceil_us + libc.src.stdbit.stdc_bit_floor_uc + libc.src.stdbit.stdc_bit_floor_ui + libc.src.stdbit.stdc_bit_floor_ul + libc.src.stdbit.stdc_bit_floor_ull + libc.src.stdbit.stdc_bit_floor_us + libc.src.stdbit.stdc_bit_width_uc + libc.src.stdbit.stdc_bit_width_ui + libc.src.stdbit.stdc_bit_width_ul + libc.src.stdbit.stdc_bit_width_ull + libc.src.stdbit.stdc_bit_width_us + libc.src.stdbit.stdc_count_ones_uc + libc.src.stdbit.stdc_count_ones_ui + libc.src.stdbit.stdc_count_ones_ul + libc.src.stdbit.stdc_count_ones_ull + libc.src.stdbit.stdc_count_ones_us + libc.src.stdbit.stdc_count_zeros_uc + libc.src.stdbit.stdc_count_zeros_ui + libc.src.stdbit.stdc_count_zeros_ul + libc.src.stdbit.stdc_count_zeros_ull + libc.src.stdbit.stdc_count_zeros_us libc.src.stdbit.stdc_first_leading_one_uc - libc.src.stdbit.stdc_first_leading_one_us libc.src.stdbit.stdc_first_leading_one_ui libc.src.stdbit.stdc_first_leading_one_ul libc.src.stdbit.stdc_first_leading_one_ull - libc.src.stdbit.stdc_first_trailing_zero_uc - libc.src.stdbit.stdc_first_trailing_zero_us - libc.src.stdbit.stdc_first_trailing_zero_ui - libc.src.stdbit.stdc_first_trailing_zero_ul - libc.src.stdbit.stdc_first_trailing_zero_ull + libc.src.stdbit.stdc_first_leading_one_us + libc.src.stdbit.stdc_first_leading_zero_uc + libc.src.stdbit.stdc_first_leading_zero_ui + libc.src.stdbit.stdc_first_leading_zero_ul + libc.src.stdbit.stdc_first_leading_zero_ull + libc.src.stdbit.stdc_first_leading_zero_us libc.src.stdbit.stdc_first_trailing_one_uc - libc.src.stdbit.stdc_first_trailing_one_us libc.src.stdbit.stdc_first_trailing_one_ui libc.src.stdbit.stdc_first_trailing_one_ul libc.src.stdbit.stdc_first_trailing_one_ull - libc.src.stdbit.stdc_count_zeros_uc - libc.src.stdbit.stdc_count_zeros_us - libc.src.stdbit.stdc_count_zeros_ui - libc.src.stdbit.stdc_count_zeros_ul - libc.src.stdbit.stdc_count_zeros_ull - libc.src.stdbit.stdc_count_ones_uc - libc.src.stdbit.stdc_count_ones_us - libc.src.stdbit.stdc_count_ones_ui - libc.src.stdbit.stdc_count_ones_ul - libc.src.stdbit.stdc_count_ones_ull + libc.src.stdbit.stdc_first_trailing_one_us + libc.src.stdbit.stdc_first_trailing_zero_uc + libc.src.stdbit.stdc_first_trailing_zero_ui + libc.src.stdbit.stdc_first_trailing_zero_ul + libc.src.stdbit.stdc_first_trailing_zero_ull + libc.src.stdbit.stdc_first_trailing_zero_us libc.src.stdbit.stdc_has_single_bit_uc - libc.src.stdbit.stdc_has_single_bit_us libc.src.stdbit.stdc_has_single_bit_ui libc.src.stdbit.stdc_has_single_bit_ul libc.src.stdbit.stdc_has_single_bit_ull - libc.src.stdbit.stdc_bit_width_uc - libc.src.stdbit.stdc_bit_width_us - libc.src.stdbit.stdc_bit_width_ui - libc.src.stdbit.stdc_bit_width_ul - libc.src.stdbit.stdc_bit_width_ull - libc.src.stdbit.stdc_bit_floor_uc - libc.src.stdbit.stdc_bit_floor_us - libc.src.stdbit.stdc_bit_floor_ui - libc.src.stdbit.stdc_bit_floor_ul - libc.src.stdbit.stdc_bit_floor_ull - libc.src.stdbit.stdc_bit_ceil_uc - libc.src.stdbit.stdc_bit_ceil_us - libc.src.stdbit.stdc_bit_ceil_ui - libc.src.stdbit.stdc_bit_ceil_ul - libc.src.stdbit.stdc_bit_ceil_ull + libc.src.stdbit.stdc_has_single_bit_us + libc.src.stdbit.stdc_leading_ones_uc + libc.src.stdbit.stdc_leading_ones_ui + libc.src.stdbit.stdc_leading_ones_ul + libc.src.stdbit.stdc_leading_ones_ull + libc.src.stdbit.stdc_leading_ones_us + libc.src.stdbit.stdc_leading_zeros_uc + libc.src.stdbit.stdc_leading_zeros_ui + libc.src.stdbit.stdc_leading_zeros_ul + libc.src.stdbit.stdc_leading_zeros_ull + libc.src.stdbit.stdc_leading_zeros_us + libc.src.stdbit.stdc_trailing_ones_uc + libc.src.stdbit.stdc_trailing_ones_ui + libc.src.stdbit.stdc_trailing_ones_ul + libc.src.stdbit.stdc_trailing_ones_ull + libc.src.stdbit.stdc_trailing_ones_us + libc.src.stdbit.stdc_trailing_zeros_uc + libc.src.stdbit.stdc_trailing_zeros_ui + libc.src.stdbit.stdc_trailing_zeros_ul + libc.src.stdbit.stdc_trailing_zeros_ull + libc.src.stdbit.stdc_trailing_zeros_us # stdlib.h entrypoints libc.src.stdlib.abs - libc.src.stdlib.atoi libc.src.stdlib.atof + libc.src.stdlib.atoi libc.src.stdlib.atol libc.src.stdlib.atoll libc.src.stdlib.bsearch @@ -189,41 +189,41 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.stdlib.strtoull # stdlib.h external entrypoints - libc.src.stdlib.malloc - libc.src.stdlib.calloc - libc.src.stdlib.realloc libc.src.stdlib.aligned_alloc + libc.src.stdlib.calloc libc.src.stdlib.free + libc.src.stdlib.malloc + libc.src.stdlib.realloc # stdio.h entrypoints + libc.src.stdio.fdopen + libc.src.stdio.fprintf + libc.src.stdio.fscanf + libc.src.stdio.printf libc.src.stdio.remove libc.src.stdio.rename - libc.src.stdio.sprintf + libc.src.stdio.scanf libc.src.stdio.snprintf - libc.src.stdio.fprintf - libc.src.stdio.printf - libc.src.stdio.vsprintf - libc.src.stdio.vsnprintf + libc.src.stdio.sprintf + libc.src.stdio.sscanf libc.src.stdio.vfprintf libc.src.stdio.vprintf - libc.src.stdio.sscanf - libc.src.stdio.scanf - libc.src.stdio.fscanf - libc.src.stdio.fdopen + libc.src.stdio.vsnprintf + libc.src.stdio.vsprintf # sys/mman.h entrypoints libc.src.sys.mman.madvise - libc.src.sys.mman.mmap - libc.src.sys.mman.mprotect - libc.src.sys.mman.munmap - libc.src.sys.mman.posix_madvise libc.src.sys.mman.mincore libc.src.sys.mman.mlock libc.src.sys.mman.mlock2 - libc.src.sys.mman.munlock libc.src.sys.mman.mlockall - libc.src.sys.mman.munlockall + libc.src.sys.mman.mmap + libc.src.sys.mman.mprotect libc.src.sys.mman.msync + libc.src.sys.mman.munlock + libc.src.sys.mman.munlockall + libc.src.sys.mman.munmap + libc.src.sys.mman.posix_madvise libc.src.sys.mman.shm_open libc.src.sys.mman.shm_unlink @@ -272,11 +272,11 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.termios.cfgetospeed libc.src.termios.cfsetispeed libc.src.termios.cfsetospeed - libc.src.termios.tcgetattr - libc.src.termios.tcgetsid libc.src.termios.tcdrain libc.src.termios.tcflow libc.src.termios.tcflush + libc.src.termios.tcgetattr + libc.src.termios.tcgetsid libc.src.termios.tcsendbreak libc.src.termios.tcsetattr @@ -328,11 +328,11 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.fenv.fegetexceptflag libc.src.fenv.fegetround libc.src.fenv.feholdexcept + libc.src.fenv.feraiseexcept libc.src.fenv.fesetenv libc.src.fenv.fesetexcept libc.src.fenv.fesetexceptflag libc.src.fenv.fesetround - libc.src.fenv.feraiseexcept libc.src.fenv.fetestexcept libc.src.fenv.fetestexceptflag libc.src.fenv.feupdateenv @@ -345,21 +345,22 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.atan2f libc.src.math.atanf libc.src.math.atanhf - libc.src.math.copysign - libc.src.math.copysignf - libc.src.math.copysignl libc.src.math.ceil libc.src.math.ceilf libc.src.math.ceill - libc.src.math.coshf + libc.src.math.copysign + libc.src.math.copysignf + libc.src.math.copysignl + libc.src.math.cos libc.src.math.cosf + libc.src.math.coshf libc.src.math.erff libc.src.math.exp - libc.src.math.expf libc.src.math.exp10 libc.src.math.exp10f libc.src.math.exp2 libc.src.math.exp2f + libc.src.math.expf libc.src.math.expm1 libc.src.math.expm1f libc.src.math.fabs @@ -373,40 +374,40 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.floorl libc.src.math.fma libc.src.math.fmaf - libc.src.math.fmin - libc.src.math.fminf - libc.src.math.fminl libc.src.math.fmax libc.src.math.fmaxf - libc.src.math.fmaxl libc.src.math.fmaximum - libc.src.math.fmaximumf - libc.src.math.fmaximuml - libc.src.math.fmaximum_num - libc.src.math.fmaximum_numf - libc.src.math.fmaximum_numl libc.src.math.fmaximum_mag - libc.src.math.fmaximum_magf - libc.src.math.fmaximum_magl libc.src.math.fmaximum_mag_num libc.src.math.fmaximum_mag_numf libc.src.math.fmaximum_mag_numl + libc.src.math.fmaximum_magf + libc.src.math.fmaximum_magl + libc.src.math.fmaximum_num + libc.src.math.fmaximum_numf + libc.src.math.fmaximum_numl + libc.src.math.fmaximumf + libc.src.math.fmaximuml + libc.src.math.fmaxl + libc.src.math.fmin + libc.src.math.fminf libc.src.math.fminimum - libc.src.math.fminimumf - libc.src.math.fminimuml - libc.src.math.fminimum_num - libc.src.math.fminimum_numf - libc.src.math.fminimum_numl libc.src.math.fminimum_mag - libc.src.math.fminimum_magf - libc.src.math.fminimum_magl libc.src.math.fminimum_mag_num libc.src.math.fminimum_mag_numf libc.src.math.fminimum_mag_numl - libc.src.math.fmul + libc.src.math.fminimum_magf + libc.src.math.fminimum_magl + libc.src.math.fminimum_num + libc.src.math.fminimum_numf + libc.src.math.fminimum_numl + libc.src.math.fminimumf + libc.src.math.fminimuml + libc.src.math.fminl libc.src.math.fmod libc.src.math.fmodf libc.src.math.fmodl + libc.src.math.fmul libc.src.math.frexp libc.src.math.frexpf libc.src.math.frexpl @@ -433,17 +434,17 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.llround libc.src.math.llroundf libc.src.math.llroundl + libc.src.math.log libc.src.math.log10 libc.src.math.log10f libc.src.math.log1p libc.src.math.log1pf libc.src.math.log2 libc.src.math.log2f - libc.src.math.log - libc.src.math.logf libc.src.math.logb libc.src.math.logbf libc.src.math.logbl + libc.src.math.logf libc.src.math.lrint libc.src.math.lrintf libc.src.math.lrintl @@ -472,11 +473,11 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.nextupf libc.src.math.nextupl libc.src.math.powf - libc.src.math.remainderf libc.src.math.remainder + libc.src.math.remainderf libc.src.math.remainderl - libc.src.math.remquof libc.src.math.remquo + libc.src.math.remquof libc.src.math.remquol libc.src.math.rint libc.src.math.rintf @@ -487,9 +488,11 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.scalbn libc.src.math.scalbnf libc.src.math.scalbnl + libc.src.math.sin + libc.src.math.sincos libc.src.math.sincosf - libc.src.math.sinhf libc.src.math.sinf + libc.src.math.sinhf libc.src.math.sqrt libc.src.math.sqrtf libc.src.math.sqrtl @@ -515,15 +518,15 @@ if(LIBC_TYPES_HAS_FLOAT128) libc.src.math.fdimf128 libc.src.math.floorf128 libc.src.math.fmaxf128 - libc.src.math.fminf128 - libc.src.math.fmaximumf128 - libc.src.math.fmaximum_numf128 - libc.src.math.fmaximum_magf128 libc.src.math.fmaximum_mag_numf128 - libc.src.math.fminimumf128 - libc.src.math.fminimum_numf128 - libc.src.math.fminimum_magf128 + libc.src.math.fmaximum_magf128 + libc.src.math.fmaximum_numf128 + libc.src.math.fmaximumf128 + libc.src.math.fminf128 libc.src.math.fminimum_mag_numf128 + libc.src.math.fminimum_magf128 + libc.src.math.fminimum_numf128 + libc.src.math.fminimumf128 libc.src.math.fmodf128 libc.src.math.frexpf128 libc.src.math.fromfpf128 @@ -531,9 +534,9 @@ if(LIBC_TYPES_HAS_FLOAT128) libc.src.math.ilogbf128 libc.src.math.ldexpf128 libc.src.math.llogbf128 - libc.src.math.logbf128 libc.src.math.llrintf128 libc.src.math.llroundf128 + libc.src.math.logbf128 libc.src.math.lrintf128 libc.src.math.lroundf128 libc.src.math.modff128 @@ -575,11 +578,11 @@ if(LLVM_LIBC_FULL_BUILD) # pthread.h entrypoints libc.src.pthread.pthread_atfork libc.src.pthread.pthread_attr_destroy - libc.src.pthread.pthread_attr_init libc.src.pthread.pthread_attr_getdetachstate libc.src.pthread.pthread_attr_getguardsize libc.src.pthread.pthread_attr_getstack libc.src.pthread.pthread_attr_getstacksize + libc.src.pthread.pthread_attr_init libc.src.pthread.pthread_attr_setdetachstate libc.src.pthread.pthread_attr_setguardsize libc.src.pthread.pthread_attr_setstack @@ -593,21 +596,21 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.pthread.pthread_join libc.src.pthread.pthread_key_create libc.src.pthread.pthread_key_delete - libc.src.pthread.pthread_self - libc.src.pthread.pthread_setname_np libc.src.pthread.pthread_mutex_destroy libc.src.pthread.pthread_mutex_init libc.src.pthread.pthread_mutex_lock libc.src.pthread.pthread_mutex_unlock libc.src.pthread.pthread_mutexattr_destroy - libc.src.pthread.pthread_mutexattr_init libc.src.pthread.pthread_mutexattr_getpshared libc.src.pthread.pthread_mutexattr_getrobust libc.src.pthread.pthread_mutexattr_gettype + libc.src.pthread.pthread_mutexattr_init libc.src.pthread.pthread_mutexattr_setpshared libc.src.pthread.pthread_mutexattr_setrobust libc.src.pthread.pthread_mutexattr_settype libc.src.pthread.pthread_once + libc.src.pthread.pthread_self + libc.src.pthread.pthread_setname_np libc.src.pthread.pthread_setspecific # sched.h entrypoints @@ -621,20 +624,20 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.stdio.clearerr libc.src.stdio.clearerr_unlocked libc.src.stdio.fclose - libc.src.stdio.flockfile libc.src.stdio.feof libc.src.stdio.feof_unlocked libc.src.stdio.ferror libc.src.stdio.ferror_unlocked + libc.src.stdio.fflush libc.src.stdio.fgetc libc.src.stdio.fgetc_unlocked libc.src.stdio.fgets - libc.src.stdio.fflush libc.src.stdio.fileno + libc.src.stdio.flockfile libc.src.stdio.fopen + libc.src.stdio.fopencookie libc.src.stdio.fputc libc.src.stdio.fputs - libc.src.stdio.fopencookie libc.src.stdio.fread libc.src.stdio.fread_unlocked libc.src.stdio.fseek @@ -664,16 +667,16 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.stdlib.getenv # signal.h entrypoints - libc.src.signal.raise libc.src.signal.kill + libc.src.signal.raise libc.src.signal.sigaction + libc.src.signal.sigaddset libc.src.signal.sigaltstack libc.src.signal.sigdelset - libc.src.signal.sigaddset libc.src.signal.sigemptyset - libc.src.signal.sigprocmask libc.src.signal.sigfillset libc.src.signal.signal + libc.src.signal.sigprocmask # spawn.h entrypoints libc.src.spawn.posix_spawn @@ -686,10 +689,10 @@ if(LLVM_LIBC_FULL_BUILD) # search.h entrypoints libc.src.search.hcreate libc.src.search.hcreate_r - libc.src.search.hsearch - libc.src.search.hsearch_r libc.src.search.hdestroy libc.src.search.hdestroy_r + libc.src.search.hsearch + libc.src.search.hsearch_r libc.src.search.insque libc.src.search.remque @@ -718,8 +721,8 @@ if(LLVM_LIBC_FULL_BUILD) # time.h entrypoints libc.src.time.asctime libc.src.time.asctime_r - libc.src.time.clock_gettime libc.src.time.clock + libc.src.time.clock_gettime libc.src.time.difftime libc.src.time.gettimeofday libc.src.time.gmtime @@ -729,16 +732,16 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.time.time # unistd.h entrypoints + libc.src.unistd.__llvm_libc_syscall libc.src.unistd._exit libc.src.unistd.environ libc.src.unistd.execv libc.src.unistd.fork - libc.src.unistd.__llvm_libc_syscall libc.src.unistd.getopt libc.src.unistd.optarg + libc.src.unistd.opterr libc.src.unistd.optind libc.src.unistd.optopt - libc.src.unistd.opterr libc.src.unistd.swab # sys/select.h entrypoints diff --git a/libc/config/linux/syscall_numbers.h.inc b/libc/config/linux/syscall_numbers.h.inc deleted file mode 100644 index 4a19d9a08875e8..00000000000000 --- a/libc/config/linux/syscall_numbers.h.inc +++ /dev/null @@ -1,2347 +0,0 @@ -//===---------------------- Linux syscall number macros -------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -%%begin() - -#include - -#ifdef __NR_FAST_atomic_update -#define SYS_FAST_atomic_update __NR_FAST_atomic_update -#endif - -#ifdef __NR_FAST_cmpxchg -#define SYS_FAST_cmpxchg __NR_FAST_cmpxchg -#endif - -#ifdef __NR_FAST_cmpxchg64 -#define SYS_FAST_cmpxchg64 __NR_FAST_cmpxchg64 -#endif - -#ifdef __NR__llseek -#define SYS__llseek __NR__llseek -#endif - -#ifdef __NR__newselect -#define SYS__newselect __NR__newselect -#endif - -#ifdef __NR__sysctl -#define SYS__sysctl __NR__sysctl -#endif - -#ifdef __NR_accept -#define SYS_accept __NR_accept -#endif - -#ifdef __NR_accept4 -#define SYS_accept4 __NR_accept4 -#endif - -#ifdef __NR_access -#define SYS_access __NR_access -#endif - -#ifdef __NR_acct -#define SYS_acct __NR_acct -#endif - -#ifdef __NR_acl_get -#define SYS_acl_get __NR_acl_get -#endif - -#ifdef __NR_acl_set -#define SYS_acl_set __NR_acl_set -#endif - -#ifdef __NR_add_key -#define SYS_add_key __NR_add_key -#endif - -#ifdef __NR_adjtimex -#define SYS_adjtimex __NR_adjtimex -#endif - -#ifdef __NR_afs_syscall -#define SYS_afs_syscall __NR_afs_syscall -#endif - -#ifdef __NR_alarm -#define SYS_alarm __NR_alarm -#endif - -#ifdef __NR_alloc_hugepages -#define SYS_alloc_hugepages __NR_alloc_hugepages -#endif - -#ifdef __NR_arch_prctl -#define SYS_arch_prctl __NR_arch_prctl -#endif - -#ifdef __NR_arm_fadvise64_64 -#define SYS_arm_fadvise64_64 __NR_arm_fadvise64_64 -#endif - -#ifdef __NR_arm_sync_file_range -#define SYS_arm_sync_file_range __NR_arm_sync_file_range -#endif - -#ifdef __NR_atomic_barrier -#define SYS_atomic_barrier __NR_atomic_barrier -#endif - -#ifdef __NR_atomic_cmpxchg_32 -#define SYS_atomic_cmpxchg_32 __NR_atomic_cmpxchg_32 -#endif - -#ifdef __NR_attrctl -#define SYS_attrctl __NR_attrctl -#endif - -#ifdef __NR_bdflush -#define SYS_bdflush __NR_bdflush -#endif - -#ifdef __NR_bind -#define SYS_bind __NR_bind -#endif - -#ifdef __NR_bpf -#define SYS_bpf __NR_bpf -#endif - -#ifdef __NR_break -#define SYS_break __NR_break -#endif - -#ifdef __NR_brk -#define SYS_brk __NR_brk -#endif - -#ifdef __NR_cachectl -#define SYS_cachectl __NR_cachectl -#endif - -#ifdef __NR_cacheflush -#define SYS_cacheflush __NR_cacheflush -#endif - -#ifdef __NR_capget -#define SYS_capget __NR_capget -#endif - -#ifdef __NR_capset -#define SYS_capset __NR_capset -#endif - -#ifdef __NR_chdir -#define SYS_chdir __NR_chdir -#endif - -#ifdef __NR_chmod -#define SYS_chmod __NR_chmod -#endif - -#ifdef __NR_chown -#define SYS_chown __NR_chown -#endif - -#ifdef __NR_chown32 -#define SYS_chown32 __NR_chown32 -#endif - -#ifdef __NR_chroot -#define SYS_chroot __NR_chroot -#endif - -#ifdef __NR_clock_adjtime -#define SYS_clock_adjtime __NR_clock_adjtime -#endif - -#ifdef __NR_clock_getres -#define SYS_clock_getres __NR_clock_getres -#endif - -#ifdef __NR_clock_gettime -#define SYS_clock_gettime __NR_clock_gettime -#endif - -#ifdef __NR_clock_gettime64 -#define SYS_clock_gettime64 __NR_clock_gettime64 -#endif - -#ifdef __NR_clock_nanosleep -#define SYS_clock_nanosleep __NR_clock_nanosleep -#endif - -#ifdef __NR_clock_nanosleep_time64 -#define SYS_clock_nanosleep_time64 __NR_clock_nanosleep_time64 -#endif - -#ifdef __NR_clock_settime -#define SYS_clock_settime __NR_clock_settime -#endif - -#ifdef __NR_clone -#define SYS_clone __NR_clone -#endif - -#ifdef __NR_clone2 -#define SYS_clone2 __NR_clone2 -#endif - -#ifdef __NR_close -#define SYS_close __NR_close -#endif - -#ifdef __NR_cmpxchg_badaddr -#define SYS_cmpxchg_badaddr __NR_cmpxchg_badaddr -#endif - -#ifdef __NR_connect -#define SYS_connect __NR_connect -#endif - -#ifdef __NR_copy_file_range -#define SYS_copy_file_range __NR_copy_file_range -#endif - -#ifdef __NR_creat -#define SYS_creat __NR_creat -#endif - -#ifdef __NR_create_module -#define SYS_create_module __NR_create_module -#endif - -#ifdef __NR_delete_module -#define SYS_delete_module __NR_delete_module -#endif - -#ifdef __NR_dipc -#define SYS_dipc __NR_dipc -#endif - -#ifdef __NR_dup -#define SYS_dup __NR_dup -#endif - -#ifdef __NR_dup2 -#define SYS_dup2 __NR_dup2 -#endif - -#ifdef __NR_dup3 -#define SYS_dup3 __NR_dup3 -#endif - -#ifdef __NR_epoll_create -#define SYS_epoll_create __NR_epoll_create -#endif - -#ifdef __NR_epoll_create1 -#define SYS_epoll_create1 __NR_epoll_create1 -#endif - -#ifdef __NR_epoll_ctl -#define SYS_epoll_ctl __NR_epoll_ctl -#endif - -#ifdef __NR_epoll_ctl_old -#define SYS_epoll_ctl_old __NR_epoll_ctl_old -#endif - -#ifdef __NR_epoll_pwait -#define SYS_epoll_pwait __NR_epoll_pwait -#endif - -#ifdef __NR_epoll_pwait2 -#define SYS_epoll_pwait2 __NR_epoll_pwait2 -#endif - -#ifdef __NR_epoll_wait -#define SYS_epoll_wait __NR_epoll_wait -#endif - -#ifdef __NR_epoll_wait_old -#define SYS_epoll_wait_old __NR_epoll_wait_old -#endif - -#ifdef __NR_eventfd -#define SYS_eventfd __NR_eventfd -#endif - -#ifdef __NR_eventfd2 -#define SYS_eventfd2 __NR_eventfd2 -#endif - -#ifdef __NR_exec_with_loader -#define SYS_exec_with_loader __NR_exec_with_loader -#endif - -#ifdef __NR_execv -#define SYS_execv __NR_execv -#endif - -#ifdef __NR_execve -#define SYS_execve __NR_execve -#endif - -#ifdef __NR_execveat -#define SYS_execveat __NR_execveat -#endif - -#ifdef __NR_exit -#define SYS_exit __NR_exit -#endif - -#ifdef __NR_exit_group -#define SYS_exit_group __NR_exit_group -#endif - -#ifdef __NR_faccessat -#define SYS_faccessat __NR_faccessat -#endif - -#ifdef __NR_fadvise64 -#define SYS_fadvise64 __NR_fadvise64 -#endif - -#ifdef __NR_fadvise64_64 -#define SYS_fadvise64_64 __NR_fadvise64_64 -#endif - -#ifdef __NR_fallocate -#define SYS_fallocate __NR_fallocate -#endif - -#ifdef __NR_fanotify_init -#define SYS_fanotify_init __NR_fanotify_init -#endif - -#ifdef __NR_fanotify_mark -#define SYS_fanotify_mark __NR_fanotify_mark -#endif - -#ifdef __NR_fchdir -#define SYS_fchdir __NR_fchdir -#endif - -#ifdef __NR_fchmod -#define SYS_fchmod __NR_fchmod -#endif - -#ifdef __NR_fchmodat -#define SYS_fchmodat __NR_fchmodat -#endif - -#ifdef __NR_fchmodat2 -#define SYS_fchmodat2 __NR_fchmodat2 -#endif - -#ifdef __NR_fchown -#define SYS_fchown __NR_fchown -#endif - -#ifdef __NR_fchown32 -#define SYS_fchown32 __NR_fchown32 -#endif - -#ifdef __NR_fchownat -#define SYS_fchownat __NR_fchownat -#endif - -#ifdef __NR_fcntl -#define SYS_fcntl __NR_fcntl -#endif - -#ifdef __NR_fcntl64 -#define SYS_fcntl64 __NR_fcntl64 -#endif - -#ifdef __NR_fdatasync -#define SYS_fdatasync __NR_fdatasync -#endif - -#ifdef __NR_fgetxattr -#define SYS_fgetxattr __NR_fgetxattr -#endif - -#ifdef __NR_finit_module -#define SYS_finit_module __NR_finit_module -#endif - -#ifdef __NR_flistxattr -#define SYS_flistxattr __NR_flistxattr -#endif - -#ifdef __NR_flock -#define SYS_flock __NR_flock -#endif - -#ifdef __NR_fork -#define SYS_fork __NR_fork -#endif - -#ifdef __NR_free_hugepages -#define SYS_free_hugepages __NR_free_hugepages -#endif - -#ifdef __NR_fremovexattr -#define SYS_fremovexattr __NR_fremovexattr -#endif - -#ifdef __NR_fsetxattr -#define SYS_fsetxattr __NR_fsetxattr -#endif - -#ifdef __NR_fstat -#define SYS_fstat __NR_fstat -#endif - -#ifdef __NR_fstat64 -#define SYS_fstat64 __NR_fstat64 -#endif - -#ifdef __NR_fstatat64 -#define SYS_fstatat64 __NR_fstatat64 -#endif - -#ifdef __NR_fstatfs -#define SYS_fstatfs __NR_fstatfs -#endif - -#ifdef __NR_fstatfs64 -#define SYS_fstatfs64 __NR_fstatfs64 -#endif - -#ifdef __NR_fsync -#define SYS_fsync __NR_fsync -#endif - -#ifdef __NR_ftime -#define SYS_ftime __NR_ftime -#endif - -#ifdef __NR_ftruncate -#define SYS_ftruncate __NR_ftruncate -#endif - -#ifdef __NR_ftruncate64 -#define SYS_ftruncate64 __NR_ftruncate64 -#endif - -#ifdef __NR_futex -#define SYS_futex __NR_futex -#endif - -#ifdef __NR_futex_time64 -#define SYS_futex_time64 __NR_futex_time64 -#endif - -#ifdef __NR_futimesat -#define SYS_futimesat __NR_futimesat -#endif - -#ifdef __NR_get_kernel_syms -#define SYS_get_kernel_syms __NR_get_kernel_syms -#endif - -#ifdef __NR_get_mempolicy -#define SYS_get_mempolicy __NR_get_mempolicy -#endif - -#ifdef __NR_get_robust_list -#define SYS_get_robust_list __NR_get_robust_list -#endif - -#ifdef __NR_get_thread_area -#define SYS_get_thread_area __NR_get_thread_area -#endif - -#ifdef __NR_getcpu -#define SYS_getcpu __NR_getcpu -#endif - -#ifdef __NR_getcwd -#define SYS_getcwd __NR_getcwd -#endif - -#ifdef __NR_getdents -#define SYS_getdents __NR_getdents -#endif - -#ifdef __NR_getdents64 -#define SYS_getdents64 __NR_getdents64 -#endif - -#ifdef __NR_getdomainname -#define SYS_getdomainname __NR_getdomainname -#endif - -#ifdef __NR_getdtablesize -#define SYS_getdtablesize __NR_getdtablesize -#endif - -#ifdef __NR_getegid -#define SYS_getegid __NR_getegid -#endif - -#ifdef __NR_getegid32 -#define SYS_getegid32 __NR_getegid32 -#endif - -#ifdef __NR_geteuid -#define SYS_geteuid __NR_geteuid -#endif - -#ifdef __NR_geteuid32 -#define SYS_geteuid32 __NR_geteuid32 -#endif - -#ifdef __NR_getgid -#define SYS_getgid __NR_getgid -#endif - -#ifdef __NR_getgid32 -#define SYS_getgid32 __NR_getgid32 -#endif - -#ifdef __NR_getgroups -#define SYS_getgroups __NR_getgroups -#endif - -#ifdef __NR_getgroups32 -#define SYS_getgroups32 __NR_getgroups32 -#endif - -#ifdef __NR_gethostname -#define SYS_gethostname __NR_gethostname -#endif - -#ifdef __NR_getitimer -#define SYS_getitimer __NR_getitimer -#endif - -#ifdef __NR_getpagesize -#define SYS_getpagesize __NR_getpagesize -#endif - -#ifdef __NR_getpeername -#define SYS_getpeername __NR_getpeername -#endif - -#ifdef __NR_getpgid -#define SYS_getpgid __NR_getpgid -#endif - -#ifdef __NR_getpgrp -#define SYS_getpgrp __NR_getpgrp -#endif - -#ifdef __NR_getpid -#define SYS_getpid __NR_getpid -#endif - -#ifdef __NR_getpmsg -#define SYS_getpmsg __NR_getpmsg -#endif - -#ifdef __NR_getppid -#define SYS_getppid __NR_getppid -#endif - -#ifdef __NR_getpriority -#define SYS_getpriority __NR_getpriority -#endif - -#ifdef __NR_getrandom -#define SYS_getrandom __NR_getrandom -#endif - -#ifdef __NR_getresgid -#define SYS_getresgid __NR_getresgid -#endif - -#ifdef __NR_getresgid32 -#define SYS_getresgid32 __NR_getresgid32 -#endif - -#ifdef __NR_getresuid -#define SYS_getresuid __NR_getresuid -#endif - -#ifdef __NR_getresuid32 -#define SYS_getresuid32 __NR_getresuid32 -#endif - -#ifdef __NR_getrlimit -#define SYS_getrlimit __NR_getrlimit -#endif - -#ifdef __NR_getrusage -#define SYS_getrusage __NR_getrusage -#endif - -#ifdef __NR_getsid -#define SYS_getsid __NR_getsid -#endif - -#ifdef __NR_getsockname -#define SYS_getsockname __NR_getsockname -#endif - -#ifdef __NR_getsockopt -#define SYS_getsockopt __NR_getsockopt -#endif - -#ifdef __NR_gettid -#define SYS_gettid __NR_gettid -#endif - -#ifdef __NR_gettimeofday -#define SYS_gettimeofday __NR_gettimeofday -#endif - -#ifdef __NR_getuid -#define SYS_getuid __NR_getuid -#endif - -#ifdef __NR_getuid32 -#define SYS_getuid32 __NR_getuid32 -#endif - -#ifdef __NR_getunwind -#define SYS_getunwind __NR_getunwind -#endif - -#ifdef __NR_getxattr -#define SYS_getxattr __NR_getxattr -#endif - -#ifdef __NR_getxgid -#define SYS_getxgid __NR_getxgid -#endif - -#ifdef __NR_getxpid -#define SYS_getxpid __NR_getxpid -#endif - -#ifdef __NR_getxuid -#define SYS_getxuid __NR_getxuid -#endif - -#ifdef __NR_gtty -#define SYS_gtty __NR_gtty -#endif - -#ifdef __NR_idle -#define SYS_idle __NR_idle -#endif - -#ifdef __NR_init_module -#define SYS_init_module __NR_init_module -#endif - -#ifdef __NR_inotify_add_watch -#define SYS_inotify_add_watch __NR_inotify_add_watch -#endif - -#ifdef __NR_inotify_init -#define SYS_inotify_init __NR_inotify_init -#endif - -#ifdef __NR_inotify_init1 -#define SYS_inotify_init1 __NR_inotify_init1 -#endif - -#ifdef __NR_inotify_rm_watch -#define SYS_inotify_rm_watch __NR_inotify_rm_watch -#endif - -#ifdef __NR_io_cancel -#define SYS_io_cancel __NR_io_cancel -#endif - -#ifdef __NR_io_destroy -#define SYS_io_destroy __NR_io_destroy -#endif - -#ifdef __NR_io_getevents -#define SYS_io_getevents __NR_io_getevents -#endif - -#ifdef __NR_io_pgetevents -#define SYS_io_pgetevents __NR_io_pgetevents -#endif - -#ifdef __NR_io_setup -#define SYS_io_setup __NR_io_setup -#endif - -#ifdef __NR_io_submit -#define SYS_io_submit __NR_io_submit -#endif - -#ifdef __NR_ioctl -#define SYS_ioctl __NR_ioctl -#endif - -#ifdef __NR_ioperm -#define SYS_ioperm __NR_ioperm -#endif - -#ifdef __NR_iopl -#define SYS_iopl __NR_iopl -#endif - -#ifdef __NR_ioprio_get -#define SYS_ioprio_get __NR_ioprio_get -#endif - -#ifdef __NR_ioprio_set -#define SYS_ioprio_set __NR_ioprio_set -#endif - -#ifdef __NR_ipc -#define SYS_ipc __NR_ipc -#endif - -#ifdef __NR_kcmp -#define SYS_kcmp __NR_kcmp -#endif - -#ifdef __NR_kern_features -#define SYS_kern_features __NR_kern_features -#endif - -#ifdef __NR_kexec_file_load -#define SYS_kexec_file_load __NR_kexec_file_load -#endif - -#ifdef __NR_kexec_load -#define SYS_kexec_load __NR_kexec_load -#endif - -#ifdef __NR_keyctl -#define SYS_keyctl __NR_keyctl -#endif - -#ifdef __NR_kill -#define SYS_kill __NR_kill -#endif - -#ifdef __NR_lchown -#define SYS_lchown __NR_lchown -#endif - -#ifdef __NR_lchown32 -#define SYS_lchown32 __NR_lchown32 -#endif - -#ifdef __NR_lgetxattr -#define SYS_lgetxattr __NR_lgetxattr -#endif - -#ifdef __NR_link -#define SYS_link __NR_link -#endif - -#ifdef __NR_linkat -#define SYS_linkat __NR_linkat -#endif - -#ifdef __NR_listen -#define SYS_listen __NR_listen -#endif - -#ifdef __NR_listxattr -#define SYS_listxattr __NR_listxattr -#endif - -#ifdef __NR_llistxattr -#define SYS_llistxattr __NR_llistxattr -#endif - -#ifdef __NR_llseek -#define SYS_llseek __NR_llseek -#endif - -#ifdef __NR_lock -#define SYS_lock __NR_lock -#endif - -#ifdef __NR_lookup_dcookie -#define SYS_lookup_dcookie __NR_lookup_dcookie -#endif - -#ifdef __NR_lremovexattr -#define SYS_lremovexattr __NR_lremovexattr -#endif - -#ifdef __NR_lseek -#define SYS_lseek __NR_lseek -#endif - -#ifdef __NR_lsetxattr -#define SYS_lsetxattr __NR_lsetxattr -#endif - -#ifdef __NR_lstat -#define SYS_lstat __NR_lstat -#endif - -#ifdef __NR_lstat64 -#define SYS_lstat64 __NR_lstat64 -#endif - -#ifdef __NR_madvise -#define SYS_madvise __NR_madvise -#endif - -#ifdef __NR_mbind -#define SYS_mbind __NR_mbind -#endif - -#ifdef __NR_membarrier -#define SYS_membarrier __NR_membarrier -#endif - -#ifdef __NR_memfd_create -#define SYS_memfd_create __NR_memfd_create -#endif - -#ifdef __NR_memory_ordering -#define SYS_memory_ordering __NR_memory_ordering -#endif - -#ifdef __NR_migrate_pages -#define SYS_migrate_pages __NR_migrate_pages -#endif - -#ifdef __NR_mincore -#define SYS_mincore __NR_mincore -#endif - -#ifdef __NR_mkdir -#define SYS_mkdir __NR_mkdir -#endif - -#ifdef __NR_mkdirat -#define SYS_mkdirat __NR_mkdirat -#endif - -#ifdef __NR_mknod -#define SYS_mknod __NR_mknod -#endif - -#ifdef __NR_mknodat -#define SYS_mknodat __NR_mknodat -#endif - -#ifdef __NR_mlock -#define SYS_mlock __NR_mlock -#endif - -#ifdef __NR_mlock2 -#define SYS_mlock2 __NR_mlock2 -#endif - -#ifdef __NR_mlockall -#define SYS_mlockall __NR_mlockall -#endif - -#ifdef __NR_mmap -#define SYS_mmap __NR_mmap -#endif - -#ifdef __NR_mmap2 -#define SYS_mmap2 __NR_mmap2 -#endif - -#ifdef __NR_modify_ldt -#define SYS_modify_ldt __NR_modify_ldt -#endif - -#ifdef __NR_mount -#define SYS_mount __NR_mount -#endif - -#ifdef __NR_move_pages -#define SYS_move_pages __NR_move_pages -#endif - -#ifdef __NR_mprotect -#define SYS_mprotect __NR_mprotect -#endif - -#ifdef __NR_mpx -#define SYS_mpx __NR_mpx -#endif - -#ifdef __NR_mq_getsetattr -#define SYS_mq_getsetattr __NR_mq_getsetattr -#endif - -#ifdef __NR_mq_notify -#define SYS_mq_notify __NR_mq_notify -#endif - -#ifdef __NR_mq_open -#define SYS_mq_open __NR_mq_open -#endif - -#ifdef __NR_mq_timedreceive -#define SYS_mq_timedreceive __NR_mq_timedreceive -#endif - -#ifdef __NR_mq_timedsend -#define SYS_mq_timedsend __NR_mq_timedsend -#endif - -#ifdef __NR_mq_unlink -#define SYS_mq_unlink __NR_mq_unlink -#endif - -#ifdef __NR_mremap -#define SYS_mremap __NR_mremap -#endif - -#ifdef __NR_msgctl -#define SYS_msgctl __NR_msgctl -#endif - -#ifdef __NR_msgget -#define SYS_msgget __NR_msgget -#endif - -#ifdef __NR_msgrcv -#define SYS_msgrcv __NR_msgrcv -#endif - -#ifdef __NR_msgsnd -#define SYS_msgsnd __NR_msgsnd -#endif - -#ifdef __NR_msync -#define SYS_msync __NR_msync -#endif - -#ifdef __NR_multiplexer -#define SYS_multiplexer __NR_multiplexer -#endif - -#ifdef __NR_munlock -#define SYS_munlock __NR_munlock -#endif - -#ifdef __NR_munlockall -#define SYS_munlockall __NR_munlockall -#endif - -#ifdef __NR_munmap -#define SYS_munmap __NR_munmap -#endif - -#ifdef __NR_name_to_handle_at -#define SYS_name_to_handle_at __NR_name_to_handle_at -#endif - -#ifdef __NR_nanosleep -#define SYS_nanosleep __NR_nanosleep -#endif - -#ifdef __NR_newfstatat -#define SYS_newfstatat __NR_newfstatat -#endif - -#ifdef __NR_nfsservctl -#define SYS_nfsservctl __NR_nfsservctl -#endif - -#ifdef __NR_ni_syscall -#define SYS_ni_syscall __NR_ni_syscall -#endif - -#ifdef __NR_nice -#define SYS_nice __NR_nice -#endif - -#ifdef __NR_old_adjtimex -#define SYS_old_adjtimex __NR_old_adjtimex -#endif - -#ifdef __NR_oldfstat -#define SYS_oldfstat __NR_oldfstat -#endif - -#ifdef __NR_oldlstat -#define SYS_oldlstat __NR_oldlstat -#endif - -#ifdef __NR_oldolduname -#define SYS_oldolduname __NR_oldolduname -#endif - -#ifdef __NR_oldstat -#define SYS_oldstat __NR_oldstat -#endif - -#ifdef __NR_oldumount -#define SYS_oldumount __NR_oldumount -#endif - -#ifdef __NR_olduname -#define SYS_olduname __NR_olduname -#endif - -#ifdef __NR_open -#define SYS_open __NR_open -#endif - -#ifdef __NR_open_by_handle_at -#define SYS_open_by_handle_at __NR_open_by_handle_at -#endif - -#ifdef __NR_openat -#define SYS_openat __NR_openat -#endif - -#ifdef __NR_osf_adjtime -#define SYS_osf_adjtime __NR_osf_adjtime -#endif - -#ifdef __NR_osf_afs_syscall -#define SYS_osf_afs_syscall __NR_osf_afs_syscall -#endif - -#ifdef __NR_osf_alt_plock -#define SYS_osf_alt_plock __NR_osf_alt_plock -#endif - -#ifdef __NR_osf_alt_setsid -#define SYS_osf_alt_setsid __NR_osf_alt_setsid -#endif - -#ifdef __NR_osf_alt_sigpending -#define SYS_osf_alt_sigpending __NR_osf_alt_sigpending -#endif - -#ifdef __NR_osf_asynch_daemon -#define SYS_osf_asynch_daemon __NR_osf_asynch_daemon -#endif - -#ifdef __NR_osf_audcntl -#define SYS_osf_audcntl __NR_osf_audcntl -#endif - -#ifdef __NR_osf_audgen -#define SYS_osf_audgen __NR_osf_audgen -#endif - -#ifdef __NR_osf_chflags -#define SYS_osf_chflags __NR_osf_chflags -#endif - -#ifdef __NR_osf_execve -#define SYS_osf_execve __NR_osf_execve -#endif - -#ifdef __NR_osf_exportfs -#define SYS_osf_exportfs __NR_osf_exportfs -#endif - -#ifdef __NR_osf_fchflags -#define SYS_osf_fchflags __NR_osf_fchflags -#endif - -#ifdef __NR_osf_fdatasync -#define SYS_osf_fdatasync __NR_osf_fdatasync -#endif - -#ifdef __NR_osf_fpathconf -#define SYS_osf_fpathconf __NR_osf_fpathconf -#endif - -#ifdef __NR_osf_fstat -#define SYS_osf_fstat __NR_osf_fstat -#endif - -#ifdef __NR_osf_fstatfs -#define SYS_osf_fstatfs __NR_osf_fstatfs -#endif - -#ifdef __NR_osf_fstatfs64 -#define SYS_osf_fstatfs64 __NR_osf_fstatfs64 -#endif - -#ifdef __NR_osf_fuser -#define SYS_osf_fuser __NR_osf_fuser -#endif - -#ifdef __NR_osf_getaddressconf -#define SYS_osf_getaddressconf __NR_osf_getaddressconf -#endif - -#ifdef __NR_osf_getdirentries -#define SYS_osf_getdirentries __NR_osf_getdirentries -#endif - -#ifdef __NR_osf_getdomainname -#define SYS_osf_getdomainname __NR_osf_getdomainname -#endif - -#ifdef __NR_osf_getfh -#define SYS_osf_getfh __NR_osf_getfh -#endif - -#ifdef __NR_osf_getfsstat -#define SYS_osf_getfsstat __NR_osf_getfsstat -#endif - -#ifdef __NR_osf_gethostid -#define SYS_osf_gethostid __NR_osf_gethostid -#endif - -#ifdef __NR_osf_getitimer -#define SYS_osf_getitimer __NR_osf_getitimer -#endif - -#ifdef __NR_osf_getlogin -#define SYS_osf_getlogin __NR_osf_getlogin -#endif - -#ifdef __NR_osf_getmnt -#define SYS_osf_getmnt __NR_osf_getmnt -#endif - -#ifdef __NR_osf_getrusage -#define SYS_osf_getrusage __NR_osf_getrusage -#endif - -#ifdef __NR_osf_getsysinfo -#define SYS_osf_getsysinfo __NR_osf_getsysinfo -#endif - -#ifdef __NR_osf_gettimeofday -#define SYS_osf_gettimeofday __NR_osf_gettimeofday -#endif - -#ifdef __NR_osf_kloadcall -#define SYS_osf_kloadcall __NR_osf_kloadcall -#endif - -#ifdef __NR_osf_kmodcall -#define SYS_osf_kmodcall __NR_osf_kmodcall -#endif - -#ifdef __NR_osf_lstat -#define SYS_osf_lstat __NR_osf_lstat -#endif - -#ifdef __NR_osf_memcntl -#define SYS_osf_memcntl __NR_osf_memcntl -#endif - -#ifdef __NR_osf_mincore -#define SYS_osf_mincore __NR_osf_mincore -#endif - -#ifdef __NR_osf_mount -#define SYS_osf_mount __NR_osf_mount -#endif - -#ifdef __NR_osf_mremap -#define SYS_osf_mremap __NR_osf_mremap -#endif - -#ifdef __NR_osf_msfs_syscall -#define SYS_osf_msfs_syscall __NR_osf_msfs_syscall -#endif - -#ifdef __NR_osf_msleep -#define SYS_osf_msleep __NR_osf_msleep -#endif - -#ifdef __NR_osf_mvalid -#define SYS_osf_mvalid __NR_osf_mvalid -#endif - -#ifdef __NR_osf_mwakeup -#define SYS_osf_mwakeup __NR_osf_mwakeup -#endif - -#ifdef __NR_osf_naccept -#define SYS_osf_naccept __NR_osf_naccept -#endif - -#ifdef __NR_osf_nfssvc -#define SYS_osf_nfssvc __NR_osf_nfssvc -#endif - -#ifdef __NR_osf_ngetpeername -#define SYS_osf_ngetpeername __NR_osf_ngetpeername -#endif - -#ifdef __NR_osf_ngetsockname -#define SYS_osf_ngetsockname __NR_osf_ngetsockname -#endif - -#ifdef __NR_osf_nrecvfrom -#define SYS_osf_nrecvfrom __NR_osf_nrecvfrom -#endif - -#ifdef __NR_osf_nrecvmsg -#define SYS_osf_nrecvmsg __NR_osf_nrecvmsg -#endif - -#ifdef __NR_osf_nsendmsg -#define SYS_osf_nsendmsg __NR_osf_nsendmsg -#endif - -#ifdef __NR_osf_ntp_adjtime -#define SYS_osf_ntp_adjtime __NR_osf_ntp_adjtime -#endif - -#ifdef __NR_osf_ntp_gettime -#define SYS_osf_ntp_gettime __NR_osf_ntp_gettime -#endif - -#ifdef __NR_osf_old_creat -#define SYS_osf_old_creat __NR_osf_old_creat -#endif - -#ifdef __NR_osf_old_fstat -#define SYS_osf_old_fstat __NR_osf_old_fstat -#endif - -#ifdef __NR_osf_old_getpgrp -#define SYS_osf_old_getpgrp __NR_osf_old_getpgrp -#endif - -#ifdef __NR_osf_old_killpg -#define SYS_osf_old_killpg __NR_osf_old_killpg -#endif - -#ifdef __NR_osf_old_lstat -#define SYS_osf_old_lstat __NR_osf_old_lstat -#endif - -#ifdef __NR_osf_old_open -#define SYS_osf_old_open __NR_osf_old_open -#endif - -#ifdef __NR_osf_old_sigaction -#define SYS_osf_old_sigaction __NR_osf_old_sigaction -#endif - -#ifdef __NR_osf_old_sigblock -#define SYS_osf_old_sigblock __NR_osf_old_sigblock -#endif - -#ifdef __NR_osf_old_sigreturn -#define SYS_osf_old_sigreturn __NR_osf_old_sigreturn -#endif - -#ifdef __NR_osf_old_sigsetmask -#define SYS_osf_old_sigsetmask __NR_osf_old_sigsetmask -#endif - -#ifdef __NR_osf_old_sigvec -#define SYS_osf_old_sigvec __NR_osf_old_sigvec -#endif - -#ifdef __NR_osf_old_stat -#define SYS_osf_old_stat __NR_osf_old_stat -#endif - -#ifdef __NR_osf_old_vadvise -#define SYS_osf_old_vadvise __NR_osf_old_vadvise -#endif - -#ifdef __NR_osf_old_vtrace -#define SYS_osf_old_vtrace __NR_osf_old_vtrace -#endif - -#ifdef __NR_osf_old_wait -#define SYS_osf_old_wait __NR_osf_old_wait -#endif - -#ifdef __NR_osf_oldquota -#define SYS_osf_oldquota __NR_osf_oldquota -#endif - -#ifdef __NR_osf_pathconf -#define SYS_osf_pathconf __NR_osf_pathconf -#endif - -#ifdef __NR_osf_pid_block -#define SYS_osf_pid_block __NR_osf_pid_block -#endif - -#ifdef __NR_osf_pid_unblock -#define SYS_osf_pid_unblock __NR_osf_pid_unblock -#endif - -#ifdef __NR_osf_plock -#define SYS_osf_plock __NR_osf_plock -#endif - -#ifdef __NR_osf_priocntlset -#define SYS_osf_priocntlset __NR_osf_priocntlset -#endif - -#ifdef __NR_osf_profil -#define SYS_osf_profil __NR_osf_profil -#endif - -#ifdef __NR_osf_proplist_syscall -#define SYS_osf_proplist_syscall __NR_osf_proplist_syscall -#endif - -#ifdef __NR_osf_reboot -#define SYS_osf_reboot __NR_osf_reboot -#endif - -#ifdef __NR_osf_revoke -#define SYS_osf_revoke __NR_osf_revoke -#endif - -#ifdef __NR_osf_sbrk -#define SYS_osf_sbrk __NR_osf_sbrk -#endif - -#ifdef __NR_osf_security -#define SYS_osf_security __NR_osf_security -#endif - -#ifdef __NR_osf_select -#define SYS_osf_select __NR_osf_select -#endif - -#ifdef __NR_osf_set_program_attributes -#define SYS_osf_set_program_attributes __NR_osf_set_program_attributes -#endif - -#ifdef __NR_osf_set_speculative -#define SYS_osf_set_speculative __NR_osf_set_speculative -#endif - -#ifdef __NR_osf_sethostid -#define SYS_osf_sethostid __NR_osf_sethostid -#endif - -#ifdef __NR_osf_setitimer -#define SYS_osf_setitimer __NR_osf_setitimer -#endif - -#ifdef __NR_osf_setlogin -#define SYS_osf_setlogin __NR_osf_setlogin -#endif - -#ifdef __NR_osf_setsysinfo -#define SYS_osf_setsysinfo __NR_osf_setsysinfo -#endif - -#ifdef __NR_osf_settimeofday -#define SYS_osf_settimeofday __NR_osf_settimeofday -#endif - -#ifdef __NR_osf_shmat -#define SYS_osf_shmat __NR_osf_shmat -#endif - -#ifdef __NR_osf_signal -#define SYS_osf_signal __NR_osf_signal -#endif - -#ifdef __NR_osf_sigprocmask -#define SYS_osf_sigprocmask __NR_osf_sigprocmask -#endif - -#ifdef __NR_osf_sigsendset -#define SYS_osf_sigsendset __NR_osf_sigsendset -#endif - -#ifdef __NR_osf_sigstack -#define SYS_osf_sigstack __NR_osf_sigstack -#endif - -#ifdef __NR_osf_sigwaitprim -#define SYS_osf_sigwaitprim __NR_osf_sigwaitprim -#endif - -#ifdef __NR_osf_sstk -#define SYS_osf_sstk __NR_osf_sstk -#endif - -#ifdef __NR_osf_stat -#define SYS_osf_stat __NR_osf_stat -#endif - -#ifdef __NR_osf_statfs -#define SYS_osf_statfs __NR_osf_statfs -#endif - -#ifdef __NR_osf_statfs64 -#define SYS_osf_statfs64 __NR_osf_statfs64 -#endif - -#ifdef __NR_osf_subsys_info -#define SYS_osf_subsys_info __NR_osf_subsys_info -#endif - -#ifdef __NR_osf_swapctl -#define SYS_osf_swapctl __NR_osf_swapctl -#endif - -#ifdef __NR_osf_swapon -#define SYS_osf_swapon __NR_osf_swapon -#endif - -#ifdef __NR_osf_syscall -#define SYS_osf_syscall __NR_osf_syscall -#endif - -#ifdef __NR_osf_sysinfo -#define SYS_osf_sysinfo __NR_osf_sysinfo -#endif - -#ifdef __NR_osf_table -#define SYS_osf_table __NR_osf_table -#endif - -#ifdef __NR_osf_uadmin -#define SYS_osf_uadmin __NR_osf_uadmin -#endif - -#ifdef __NR_osf_usleep_thread -#define SYS_osf_usleep_thread __NR_osf_usleep_thread -#endif - -#ifdef __NR_osf_uswitch -#define SYS_osf_uswitch __NR_osf_uswitch -#endif - -#ifdef __NR_osf_utc_adjtime -#define SYS_osf_utc_adjtime __NR_osf_utc_adjtime -#endif - -#ifdef __NR_osf_utc_gettime -#define SYS_osf_utc_gettime __NR_osf_utc_gettime -#endif - -#ifdef __NR_osf_utimes -#define SYS_osf_utimes __NR_osf_utimes -#endif - -#ifdef __NR_osf_utsname -#define SYS_osf_utsname __NR_osf_utsname -#endif - -#ifdef __NR_osf_wait4 -#define SYS_osf_wait4 __NR_osf_wait4 -#endif - -#ifdef __NR_osf_waitid -#define SYS_osf_waitid __NR_osf_waitid -#endif - -#ifdef __NR_pause -#define SYS_pause __NR_pause -#endif - -#ifdef __NR_pciconfig_iobase -#define SYS_pciconfig_iobase __NR_pciconfig_iobase -#endif - -#ifdef __NR_pciconfig_read -#define SYS_pciconfig_read __NR_pciconfig_read -#endif - -#ifdef __NR_pciconfig_write -#define SYS_pciconfig_write __NR_pciconfig_write -#endif - -#ifdef __NR_perf_event_open -#define SYS_perf_event_open __NR_perf_event_open -#endif - -#ifdef __NR_perfctr -#define SYS_perfctr __NR_perfctr -#endif - -#ifdef __NR_perfmonctl -#define SYS_perfmonctl __NR_perfmonctl -#endif - -#ifdef __NR_personality -#define SYS_personality __NR_personality -#endif - -#ifdef __NR_pipe -#define SYS_pipe __NR_pipe -#endif - -#ifdef __NR_pipe2 -#define SYS_pipe2 __NR_pipe2 -#endif - -#ifdef __NR_pivot_root -#define SYS_pivot_root __NR_pivot_root -#endif - -#ifdef __NR_pkey_alloc -#define SYS_pkey_alloc __NR_pkey_alloc -#endif - -#ifdef __NR_pkey_free -#define SYS_pkey_free __NR_pkey_free -#endif - -#ifdef __NR_pkey_mprotect -#define SYS_pkey_mprotect __NR_pkey_mprotect -#endif - -#ifdef __NR_poll -#define SYS_poll __NR_poll -#endif - -#ifdef __NR_ppoll -#define SYS_ppoll __NR_ppoll -#endif - -#ifdef __NR_prctl -#define SYS_prctl __NR_prctl -#endif - -#ifdef __NR_pread64 -#define SYS_pread64 __NR_pread64 -#endif - -#ifdef __NR_preadv -#define SYS_preadv __NR_preadv -#endif - -#ifdef __NR_preadv2 -#define SYS_preadv2 __NR_preadv2 -#endif - -#ifdef __NR_prlimit64 -#define SYS_prlimit64 __NR_prlimit64 -#endif - -#ifdef __NR_process_vm_readv -#define SYS_process_vm_readv __NR_process_vm_readv -#endif - -#ifdef __NR_process_vm_writev -#define SYS_process_vm_writev __NR_process_vm_writev -#endif - -#ifdef __NR_prof -#define SYS_prof __NR_prof -#endif - -#ifdef __NR_profil -#define SYS_profil __NR_profil -#endif - -#ifdef __NR_pselect6 -#define SYS_pselect6 __NR_pselect6 -#endif - -#ifdef __NR_pselect6_time64 -#define SYS_pselect6_time64 __NR_pselect6_time64 -#endif - -#ifdef __NR_ptrace -#define SYS_ptrace __NR_ptrace -#endif - -#ifdef __NR_putpmsg -#define SYS_putpmsg __NR_putpmsg -#endif - -#ifdef __NR_pwrite64 -#define SYS_pwrite64 __NR_pwrite64 -#endif - -#ifdef __NR_pwritev -#define SYS_pwritev __NR_pwritev -#endif - -#ifdef __NR_pwritev2 -#define SYS_pwritev2 __NR_pwritev2 -#endif - -#ifdef __NR_query_module -#define SYS_query_module __NR_query_module -#endif - -#ifdef __NR_quotactl -#define SYS_quotactl __NR_quotactl -#endif - -#ifdef __NR_read -#define SYS_read __NR_read -#endif - -#ifdef __NR_readahead -#define SYS_readahead __NR_readahead -#endif - -#ifdef __NR_readdir -#define SYS_readdir __NR_readdir -#endif - -#ifdef __NR_readlink -#define SYS_readlink __NR_readlink -#endif - -#ifdef __NR_readlinkat -#define SYS_readlinkat __NR_readlinkat -#endif - -#ifdef __NR_readv -#define SYS_readv __NR_readv -#endif - -#ifdef __NR_reboot -#define SYS_reboot __NR_reboot -#endif - -#ifdef __NR_recv -#define SYS_recv __NR_recv -#endif - -#ifdef __NR_recvfrom -#define SYS_recvfrom __NR_recvfrom -#endif - -#ifdef __NR_recvmmsg -#define SYS_recvmmsg __NR_recvmmsg -#endif - -#ifdef __NR_recvmsg -#define SYS_recvmsg __NR_recvmsg -#endif - -#ifdef __NR_remap_file_pages -#define SYS_remap_file_pages __NR_remap_file_pages -#endif - -#ifdef __NR_removexattr -#define SYS_removexattr __NR_removexattr -#endif - -#ifdef __NR_rename -#define SYS_rename __NR_rename -#endif - -#ifdef __NR_renameat -#define SYS_renameat __NR_renameat -#endif - -#ifdef __NR_renameat2 -#define SYS_renameat2 __NR_renameat2 -#endif - -#ifdef __NR_request_key -#define SYS_request_key __NR_request_key -#endif - -#ifdef __NR_restart_syscall -#define SYS_restart_syscall __NR_restart_syscall -#endif - -#ifdef __NR_rmdir -#define SYS_rmdir __NR_rmdir -#endif - -#ifdef __NR_rseq -#define SYS_rseq __NR_rseq -#endif - -#ifdef __NR_rt_sigaction -#define SYS_rt_sigaction __NR_rt_sigaction -#endif - -#ifdef __NR_rt_sigpending -#define SYS_rt_sigpending __NR_rt_sigpending -#endif - -#ifdef __NR_rt_sigprocmask -#define SYS_rt_sigprocmask __NR_rt_sigprocmask -#endif - -#ifdef __NR_rt_sigqueueinfo -#define SYS_rt_sigqueueinfo __NR_rt_sigqueueinfo -#endif - -#ifdef __NR_rt_sigreturn -#define SYS_rt_sigreturn __NR_rt_sigreturn -#endif - -#ifdef __NR_rt_sigsuspend -#define SYS_rt_sigsuspend __NR_rt_sigsuspend -#endif - -#ifdef __NR_rt_sigtimedwait -#define SYS_rt_sigtimedwait __NR_rt_sigtimedwait -#endif - -#ifdef __NR_rt_tgsigqueueinfo -#define SYS_rt_tgsigqueueinfo __NR_rt_tgsigqueueinfo -#endif - -#ifdef __NR_rtas -#define SYS_rtas __NR_rtas -#endif - -#ifdef __NR_s390_guarded_storage -#define SYS_s390_guarded_storage __NR_s390_guarded_storage -#endif - -#ifdef __NR_s390_pci_mmio_read -#define SYS_s390_pci_mmio_read __NR_s390_pci_mmio_read -#endif - -#ifdef __NR_s390_pci_mmio_write -#define SYS_s390_pci_mmio_write __NR_s390_pci_mmio_write -#endif - -#ifdef __NR_s390_runtime_instr -#define SYS_s390_runtime_instr __NR_s390_runtime_instr -#endif - -#ifdef __NR_s390_sthyi -#define SYS_s390_sthyi __NR_s390_sthyi -#endif - -#ifdef __NR_sched_get_affinity -#define SYS_sched_get_affinity __NR_sched_get_affinity -#endif - -#ifdef __NR_sched_get_priority_max -#define SYS_sched_get_priority_max __NR_sched_get_priority_max -#endif - -#ifdef __NR_sched_get_priority_min -#define SYS_sched_get_priority_min __NR_sched_get_priority_min -#endif - -#ifdef __NR_sched_getaffinity -#define SYS_sched_getaffinity __NR_sched_getaffinity -#endif - -#ifdef __NR_sched_getattr -#define SYS_sched_getattr __NR_sched_getattr -#endif - -#ifdef __NR_sched_getparam -#define SYS_sched_getparam __NR_sched_getparam -#endif - -#ifdef __NR_sched_getscheduler -#define SYS_sched_getscheduler __NR_sched_getscheduler -#endif - -#ifdef __NR_sched_rr_get_interval -#define SYS_sched_rr_get_interval __NR_sched_rr_get_interval -#endif - -#ifdef __NR_sched_rr_get_interval_time64 -#define SYS_sched_rr_get_interval_time64 __NR_sched_rr_get_interval_time64 -#endif - -#ifdef __NR_sched_set_affinity -#define SYS_sched_set_affinity __NR_sched_set_affinity -#endif - -#ifdef __NR_sched_setaffinity -#define SYS_sched_setaffinity __NR_sched_setaffinity -#endif - -#ifdef __NR_sched_setattr -#define SYS_sched_setattr __NR_sched_setattr -#endif - -#ifdef __NR_sched_setparam -#define SYS_sched_setparam __NR_sched_setparam -#endif - -#ifdef __NR_sched_setscheduler -#define SYS_sched_setscheduler __NR_sched_setscheduler -#endif - -#ifdef __NR_sched_yield -#define SYS_sched_yield __NR_sched_yield -#endif - -#ifdef __NR_seccomp -#define SYS_seccomp __NR_seccomp -#endif - -#ifdef __NR_security -#define SYS_security __NR_security -#endif - -#ifdef __NR_select -#define SYS_select __NR_select -#endif - -#ifdef __NR_semctl -#define SYS_semctl __NR_semctl -#endif - -#ifdef __NR_semget -#define SYS_semget __NR_semget -#endif - -#ifdef __NR_semop -#define SYS_semop __NR_semop -#endif - -#ifdef __NR_semtimedop -#define SYS_semtimedop __NR_semtimedop -#endif - -#ifdef __NR_send -#define SYS_send __NR_send -#endif - -#ifdef __NR_sendfile -#define SYS_sendfile __NR_sendfile -#endif - -#ifdef __NR_sendfile64 -#define SYS_sendfile64 __NR_sendfile64 -#endif - -#ifdef __NR_sendmmsg -#define SYS_sendmmsg __NR_sendmmsg -#endif - -#ifdef __NR_sendmsg -#define SYS_sendmsg __NR_sendmsg -#endif - -#ifdef __NR_sendto -#define SYS_sendto __NR_sendto -#endif - -#ifdef __NR_set_mempolicy -#define SYS_set_mempolicy __NR_set_mempolicy -#endif - -#ifdef __NR_set_robust_list -#define SYS_set_robust_list __NR_set_robust_list -#endif - -#ifdef __NR_set_thread_area -#define SYS_set_thread_area __NR_set_thread_area -#endif - -#ifdef __NR_set_tid_address -#define SYS_set_tid_address __NR_set_tid_address -#endif - -#ifdef __NR_setdomainname -#define SYS_setdomainname __NR_setdomainname -#endif - -#ifdef __NR_setfsgid -#define SYS_setfsgid __NR_setfsgid -#endif - -#ifdef __NR_setfsgid32 -#define SYS_setfsgid32 __NR_setfsgid32 -#endif - -#ifdef __NR_setfsuid -#define SYS_setfsuid __NR_setfsuid -#endif - -#ifdef __NR_setfsuid32 -#define SYS_setfsuid32 __NR_setfsuid32 -#endif - -#ifdef __NR_setgid -#define SYS_setgid __NR_setgid -#endif - -#ifdef __NR_setgid32 -#define SYS_setgid32 __NR_setgid32 -#endif - -#ifdef __NR_setgroups -#define SYS_setgroups __NR_setgroups -#endif - -#ifdef __NR_setgroups32 -#define SYS_setgroups32 __NR_setgroups32 -#endif - -#ifdef __NR_sethae -#define SYS_sethae __NR_sethae -#endif - -#ifdef __NR_sethostname -#define SYS_sethostname __NR_sethostname -#endif - -#ifdef __NR_setitimer -#define SYS_setitimer __NR_setitimer -#endif - -#ifdef __NR_setns -#define SYS_setns __NR_setns -#endif - -#ifdef __NR_setpgid -#define SYS_setpgid __NR_setpgid -#endif - -#ifdef __NR_setpgrp -#define SYS_setpgrp __NR_setpgrp -#endif - -#ifdef __NR_setpriority -#define SYS_setpriority __NR_setpriority -#endif - -#ifdef __NR_setregid -#define SYS_setregid __NR_setregid -#endif - -#ifdef __NR_setregid32 -#define SYS_setregid32 __NR_setregid32 -#endif - -#ifdef __NR_setresgid -#define SYS_setresgid __NR_setresgid -#endif - -#ifdef __NR_setresgid32 -#define SYS_setresgid32 __NR_setresgid32 -#endif - -#ifdef __NR_setresuid -#define SYS_setresuid __NR_setresuid -#endif - -#ifdef __NR_setresuid32 -#define SYS_setresuid32 __NR_setresuid32 -#endif - -#ifdef __NR_setreuid -#define SYS_setreuid __NR_setreuid -#endif - -#ifdef __NR_setreuid32 -#define SYS_setreuid32 __NR_setreuid32 -#endif - -#ifdef __NR_setrlimit -#define SYS_setrlimit __NR_setrlimit -#endif - -#ifdef __NR_setsid -#define SYS_setsid __NR_setsid -#endif - -#ifdef __NR_setsockopt -#define SYS_setsockopt __NR_setsockopt -#endif - -#ifdef __NR_settimeofday -#define SYS_settimeofday __NR_settimeofday -#endif - -#ifdef __NR_setuid -#define SYS_setuid __NR_setuid -#endif - -#ifdef __NR_setuid32 -#define SYS_setuid32 __NR_setuid32 -#endif - -#ifdef __NR_setxattr -#define SYS_setxattr __NR_setxattr -#endif - -#ifdef __NR_sgetmask -#define SYS_sgetmask __NR_sgetmask -#endif - -#ifdef __NR_shmat -#define SYS_shmat __NR_shmat -#endif - -#ifdef __NR_shmctl -#define SYS_shmctl __NR_shmctl -#endif - -#ifdef __NR_shmdt -#define SYS_shmdt __NR_shmdt -#endif - -#ifdef __NR_shmget -#define SYS_shmget __NR_shmget -#endif - -#ifdef __NR_shutdown -#define SYS_shutdown __NR_shutdown -#endif - -#ifdef __NR_sigaction -#define SYS_sigaction __NR_sigaction -#endif - -#ifdef __NR_sigaltstack -#define SYS_sigaltstack __NR_sigaltstack -#endif - -#ifdef __NR_signal -#define SYS_signal __NR_signal -#endif - -#ifdef __NR_signalfd -#define SYS_signalfd __NR_signalfd -#endif - -#ifdef __NR_signalfd4 -#define SYS_signalfd4 __NR_signalfd4 -#endif - -#ifdef __NR_sigpending -#define SYS_sigpending __NR_sigpending -#endif - -#ifdef __NR_sigprocmask -#define SYS_sigprocmask __NR_sigprocmask -#endif - -#ifdef __NR_sigreturn -#define SYS_sigreturn __NR_sigreturn -#endif - -#ifdef __NR_sigsuspend -#define SYS_sigsuspend __NR_sigsuspend -#endif - -#ifdef __NR_socket -#define SYS_socket __NR_socket -#endif - -#ifdef __NR_socketcall -#define SYS_socketcall __NR_socketcall -#endif - -#ifdef __NR_socketpair -#define SYS_socketpair __NR_socketpair -#endif - -#ifdef __NR_splice -#define SYS_splice __NR_splice -#endif - -#ifdef __NR_spu_create -#define SYS_spu_create __NR_spu_create -#endif - -#ifdef __NR_spu_run -#define SYS_spu_run __NR_spu_run -#endif - -#ifdef __NR_ssetmask -#define SYS_ssetmask __NR_ssetmask -#endif - -#ifdef __NR_stat -#define SYS_stat __NR_stat -#endif - -#ifdef __NR_stat64 -#define SYS_stat64 __NR_stat64 -#endif - -#ifdef __NR_statfs -#define SYS_statfs __NR_statfs -#endif - -#ifdef __NR_statfs64 -#define SYS_statfs64 __NR_statfs64 -#endif - -#ifdef __NR_statx -#define SYS_statx __NR_statx -#endif - -#ifdef __NR_stime -#define SYS_stime __NR_stime -#endif - -#ifdef __NR_stty -#define SYS_stty __NR_stty -#endif - -#ifdef __NR_subpage_prot -#define SYS_subpage_prot __NR_subpage_prot -#endif - -#ifdef __NR_swapcontext -#define SYS_swapcontext __NR_swapcontext -#endif - -#ifdef __NR_swapoff -#define SYS_swapoff __NR_swapoff -#endif - -#ifdef __NR_swapon -#define SYS_swapon __NR_swapon -#endif - -#ifdef __NR_switch_endian -#define SYS_switch_endian __NR_switch_endian -#endif - -#ifdef __NR_symlink -#define SYS_symlink __NR_symlink -#endif - -#ifdef __NR_symlinkat -#define SYS_symlinkat __NR_symlinkat -#endif - -#ifdef __NR_sync -#define SYS_sync __NR_sync -#endif - -#ifdef __NR_sync_file_range -#define SYS_sync_file_range __NR_sync_file_range -#endif - -#ifdef __NR_sync_file_range2 -#define SYS_sync_file_range2 __NR_sync_file_range2 -#endif - -#ifdef __NR_syncfs -#define SYS_syncfs __NR_syncfs -#endif - -#ifdef __NR_sys_debug_setcontext -#define SYS_sys_debug_setcontext __NR_sys_debug_setcontext -#endif - -#ifdef __NR_sys_epoll_create -#define SYS_sys_epoll_create __NR_sys_epoll_create -#endif - -#ifdef __NR_sys_epoll_ctl -#define SYS_sys_epoll_ctl __NR_sys_epoll_ctl -#endif - -#ifdef __NR_sys_epoll_wait -#define SYS_sys_epoll_wait __NR_sys_epoll_wait -#endif - -#ifdef __NR_syscall -#define SYS_syscall __NR_syscall -#endif - -#ifdef __NR_sysfs -#define SYS_sysfs __NR_sysfs -#endif - -#ifdef __NR_sysinfo -#define SYS_sysinfo __NR_sysinfo -#endif - -#ifdef __NR_syslog -#define SYS_syslog __NR_syslog -#endif - -#ifdef __NR_sysmips -#define SYS_sysmips __NR_sysmips -#endif - -#ifdef __NR_tee -#define SYS_tee __NR_tee -#endif - -#ifdef __NR_tgkill -#define SYS_tgkill __NR_tgkill -#endif - -#ifdef __NR_time -#define SYS_time __NR_time -#endif - -#ifdef __NR_timer_create -#define SYS_timer_create __NR_timer_create -#endif - -#ifdef __NR_timer_delete -#define SYS_timer_delete __NR_timer_delete -#endif - -#ifdef __NR_timer_getoverrun -#define SYS_timer_getoverrun __NR_timer_getoverrun -#endif - -#ifdef __NR_timer_gettime -#define SYS_timer_gettime __NR_timer_gettime -#endif - -#ifdef __NR_timer_settime -#define SYS_timer_settime __NR_timer_settime -#endif - -#ifdef __NR_timerfd -#define SYS_timerfd __NR_timerfd -#endif - -#ifdef __NR_timerfd_create -#define SYS_timerfd_create __NR_timerfd_create -#endif - -#ifdef __NR_timerfd_gettime -#define SYS_timerfd_gettime __NR_timerfd_gettime -#endif - -#ifdef __NR_timerfd_settime -#define SYS_timerfd_settime __NR_timerfd_settime -#endif - -#ifdef __NR_times -#define SYS_times __NR_times -#endif - -#ifdef __NR_tkill -#define SYS_tkill __NR_tkill -#endif - -#ifdef __NR_truncate -#define SYS_truncate __NR_truncate -#endif - -#ifdef __NR_truncate64 -#define SYS_truncate64 __NR_truncate64 -#endif - -#ifdef __NR_tuxcall -#define SYS_tuxcall __NR_tuxcall -#endif - -#ifdef __NR_ugetrlimit -#define SYS_ugetrlimit __NR_ugetrlimit -#endif - -#ifdef __NR_ulimit -#define SYS_ulimit __NR_ulimit -#endif - -#ifdef __NR_umask -#define SYS_umask __NR_umask -#endif - -#ifdef __NR_umount -#define SYS_umount __NR_umount -#endif - -#ifdef __NR_umount2 -#define SYS_umount2 __NR_umount2 -#endif - -#ifdef __NR_uname -#define SYS_uname __NR_uname -#endif - -#ifdef __NR_unlink -#define SYS_unlink __NR_unlink -#endif - -#ifdef __NR_unlinkat -#define SYS_unlinkat __NR_unlinkat -#endif - -#ifdef __NR_unshare -#define SYS_unshare __NR_unshare -#endif - -#ifdef __NR_uselib -#define SYS_uselib __NR_uselib -#endif - -#ifdef __NR_userfaultfd -#define SYS_userfaultfd __NR_userfaultfd -#endif - -#ifdef __NR_ustat -#define SYS_ustat __NR_ustat -#endif - -#ifdef __NR_utime -#define SYS_utime __NR_utime -#endif - -#ifdef __NR_utimensat -#define SYS_utimensat __NR_utimensat -#endif - -#ifdef __NR_utimes -#define SYS_utimes __NR_utimes -#endif - -#ifdef __NR_utrap_install -#define SYS_utrap_install __NR_utrap_install -#endif - -#ifdef __NR_vfork -#define SYS_vfork __NR_vfork -#endif - -#ifdef __NR_vhangup -#define SYS_vhangup __NR_vhangup -#endif - -#ifdef __NR_vm86 -#define SYS_vm86 __NR_vm86 -#endif - -#ifdef __NR_vm86old -#define SYS_vm86old __NR_vm86old -#endif - -#ifdef __NR_vmsplice -#define SYS_vmsplice __NR_vmsplice -#endif - -#ifdef __NR_vserver -#define SYS_vserver __NR_vserver -#endif - -#ifdef __NR_wait4 -#define SYS_wait4 __NR_wait4 -#endif - -#ifdef __NR_waitid -#define SYS_waitid __NR_waitid -#endif - -#ifdef __NR_waitpid -#define SYS_waitpid __NR_waitpid -#endif - -#ifdef __NR_write -#define SYS_write __NR_write -#endif - -#ifdef __NR_writev -#define SYS_writev __NR_writev -#endif diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index ac170bf7b3da33..9f67dea006699f 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -94,81 +94,81 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.inttypes.strtoumax # stdbit.h entrypoints - libc.src.stdbit.stdc_leading_zeros_uc - libc.src.stdbit.stdc_leading_zeros_us - libc.src.stdbit.stdc_leading_zeros_ui - libc.src.stdbit.stdc_leading_zeros_ul - libc.src.stdbit.stdc_leading_zeros_ull - libc.src.stdbit.stdc_leading_ones_uc - libc.src.stdbit.stdc_leading_ones_us - libc.src.stdbit.stdc_leading_ones_ui - libc.src.stdbit.stdc_leading_ones_ul - libc.src.stdbit.stdc_leading_ones_ull - libc.src.stdbit.stdc_trailing_zeros_uc - libc.src.stdbit.stdc_trailing_zeros_us - libc.src.stdbit.stdc_trailing_zeros_ui - libc.src.stdbit.stdc_trailing_zeros_ul - libc.src.stdbit.stdc_trailing_zeros_ull - libc.src.stdbit.stdc_trailing_ones_uc - libc.src.stdbit.stdc_trailing_ones_us - libc.src.stdbit.stdc_trailing_ones_ui - libc.src.stdbit.stdc_trailing_ones_ul - libc.src.stdbit.stdc_trailing_ones_ull - libc.src.stdbit.stdc_first_leading_zero_uc - libc.src.stdbit.stdc_first_leading_zero_us - libc.src.stdbit.stdc_first_leading_zero_ui - libc.src.stdbit.stdc_first_leading_zero_ul - libc.src.stdbit.stdc_first_leading_zero_ull + libc.src.stdbit.stdc_bit_ceil_uc + libc.src.stdbit.stdc_bit_ceil_ui + libc.src.stdbit.stdc_bit_ceil_ul + libc.src.stdbit.stdc_bit_ceil_ull + libc.src.stdbit.stdc_bit_ceil_us + libc.src.stdbit.stdc_bit_floor_uc + libc.src.stdbit.stdc_bit_floor_ui + libc.src.stdbit.stdc_bit_floor_ul + libc.src.stdbit.stdc_bit_floor_ull + libc.src.stdbit.stdc_bit_floor_us + libc.src.stdbit.stdc_bit_width_uc + libc.src.stdbit.stdc_bit_width_ui + libc.src.stdbit.stdc_bit_width_ul + libc.src.stdbit.stdc_bit_width_ull + libc.src.stdbit.stdc_bit_width_us + libc.src.stdbit.stdc_count_ones_uc + libc.src.stdbit.stdc_count_ones_ui + libc.src.stdbit.stdc_count_ones_ul + libc.src.stdbit.stdc_count_ones_ull + libc.src.stdbit.stdc_count_ones_us + libc.src.stdbit.stdc_count_zeros_uc + libc.src.stdbit.stdc_count_zeros_ui + libc.src.stdbit.stdc_count_zeros_ul + libc.src.stdbit.stdc_count_zeros_ull + libc.src.stdbit.stdc_count_zeros_us libc.src.stdbit.stdc_first_leading_one_uc - libc.src.stdbit.stdc_first_leading_one_us libc.src.stdbit.stdc_first_leading_one_ui libc.src.stdbit.stdc_first_leading_one_ul libc.src.stdbit.stdc_first_leading_one_ull - libc.src.stdbit.stdc_first_trailing_zero_uc - libc.src.stdbit.stdc_first_trailing_zero_us - libc.src.stdbit.stdc_first_trailing_zero_ui - libc.src.stdbit.stdc_first_trailing_zero_ul - libc.src.stdbit.stdc_first_trailing_zero_ull + libc.src.stdbit.stdc_first_leading_one_us + libc.src.stdbit.stdc_first_leading_zero_uc + libc.src.stdbit.stdc_first_leading_zero_ui + libc.src.stdbit.stdc_first_leading_zero_ul + libc.src.stdbit.stdc_first_leading_zero_ull + libc.src.stdbit.stdc_first_leading_zero_us libc.src.stdbit.stdc_first_trailing_one_uc - libc.src.stdbit.stdc_first_trailing_one_us libc.src.stdbit.stdc_first_trailing_one_ui libc.src.stdbit.stdc_first_trailing_one_ul libc.src.stdbit.stdc_first_trailing_one_ull - libc.src.stdbit.stdc_count_zeros_uc - libc.src.stdbit.stdc_count_zeros_us - libc.src.stdbit.stdc_count_zeros_ui - libc.src.stdbit.stdc_count_zeros_ul - libc.src.stdbit.stdc_count_zeros_ull - libc.src.stdbit.stdc_count_ones_uc - libc.src.stdbit.stdc_count_ones_us - libc.src.stdbit.stdc_count_ones_ui - libc.src.stdbit.stdc_count_ones_ul - libc.src.stdbit.stdc_count_ones_ull + libc.src.stdbit.stdc_first_trailing_one_us + libc.src.stdbit.stdc_first_trailing_zero_uc + libc.src.stdbit.stdc_first_trailing_zero_ui + libc.src.stdbit.stdc_first_trailing_zero_ul + libc.src.stdbit.stdc_first_trailing_zero_ull + libc.src.stdbit.stdc_first_trailing_zero_us libc.src.stdbit.stdc_has_single_bit_uc - libc.src.stdbit.stdc_has_single_bit_us libc.src.stdbit.stdc_has_single_bit_ui libc.src.stdbit.stdc_has_single_bit_ul libc.src.stdbit.stdc_has_single_bit_ull - libc.src.stdbit.stdc_bit_width_uc - libc.src.stdbit.stdc_bit_width_us - libc.src.stdbit.stdc_bit_width_ui - libc.src.stdbit.stdc_bit_width_ul - libc.src.stdbit.stdc_bit_width_ull - libc.src.stdbit.stdc_bit_floor_uc - libc.src.stdbit.stdc_bit_floor_us - libc.src.stdbit.stdc_bit_floor_ui - libc.src.stdbit.stdc_bit_floor_ul - libc.src.stdbit.stdc_bit_floor_ull - libc.src.stdbit.stdc_bit_ceil_uc - libc.src.stdbit.stdc_bit_ceil_us - libc.src.stdbit.stdc_bit_ceil_ui - libc.src.stdbit.stdc_bit_ceil_ul - libc.src.stdbit.stdc_bit_ceil_ull + libc.src.stdbit.stdc_has_single_bit_us + libc.src.stdbit.stdc_leading_ones_uc + libc.src.stdbit.stdc_leading_ones_ui + libc.src.stdbit.stdc_leading_ones_ul + libc.src.stdbit.stdc_leading_ones_ull + libc.src.stdbit.stdc_leading_ones_us + libc.src.stdbit.stdc_leading_zeros_uc + libc.src.stdbit.stdc_leading_zeros_ui + libc.src.stdbit.stdc_leading_zeros_ul + libc.src.stdbit.stdc_leading_zeros_ull + libc.src.stdbit.stdc_leading_zeros_us + libc.src.stdbit.stdc_trailing_ones_uc + libc.src.stdbit.stdc_trailing_ones_ui + libc.src.stdbit.stdc_trailing_ones_ul + libc.src.stdbit.stdc_trailing_ones_ull + libc.src.stdbit.stdc_trailing_ones_us + libc.src.stdbit.stdc_trailing_zeros_uc + libc.src.stdbit.stdc_trailing_zeros_ui + libc.src.stdbit.stdc_trailing_zeros_ul + libc.src.stdbit.stdc_trailing_zeros_ull + libc.src.stdbit.stdc_trailing_zeros_us # stdlib.h entrypoints libc.src.stdlib.abs - libc.src.stdlib.atoi libc.src.stdlib.atof + libc.src.stdlib.atoi libc.src.stdlib.atol libc.src.stdlib.atoll libc.src.stdlib.bsearch @@ -193,52 +193,52 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.stdlib.strtoull # stdlib.h external entrypoints - libc.src.stdlib.malloc - libc.src.stdlib.calloc - libc.src.stdlib.realloc libc.src.stdlib.aligned_alloc + libc.src.stdlib.calloc libc.src.stdlib.free + libc.src.stdlib.malloc + libc.src.stdlib.realloc # stdio.h entrypoints + libc.src.stdio.fdopen + libc.src.stdio.fileno + libc.src.stdio.fprintf + libc.src.stdio.fscanf + libc.src.stdio.printf libc.src.stdio.remove libc.src.stdio.rename - libc.src.stdio.sprintf + libc.src.stdio.scanf libc.src.stdio.snprintf - libc.src.stdio.fprintf - libc.src.stdio.printf - libc.src.stdio.vsprintf - libc.src.stdio.vsnprintf + libc.src.stdio.sprintf + libc.src.stdio.sscanf libc.src.stdio.vfprintf libc.src.stdio.vprintf - libc.src.stdio.sscanf - libc.src.stdio.scanf - libc.src.stdio.fscanf - libc.src.stdio.fileno - libc.src.stdio.fdopen + libc.src.stdio.vsnprintf + libc.src.stdio.vsprintf # sys/epoll.h entrypoints libc.src.sys.epoll.epoll_create libc.src.sys.epoll.epoll_create1 libc.src.sys.epoll.epoll_ctl - libc.src.sys.epoll.epoll_wait libc.src.sys.epoll.epoll_pwait + libc.src.sys.epoll.epoll_wait # TODO: Need to check if pwait2 is available before providing. # https://github.com/llvm/llvm-project/issues/80060 # libc.src.sys.epoll.epoll_pwait2 # sys/mman.h entrypoints libc.src.sys.mman.madvise - libc.src.sys.mman.mmap - libc.src.sys.mman.mprotect - libc.src.sys.mman.munmap - libc.src.sys.mman.posix_madvise libc.src.sys.mman.mincore libc.src.sys.mman.mlock libc.src.sys.mman.mlock2 - libc.src.sys.mman.munlock libc.src.sys.mman.mlockall - libc.src.sys.mman.munlockall + libc.src.sys.mman.mmap + libc.src.sys.mman.mprotect libc.src.sys.mman.msync + libc.src.sys.mman.munlock + libc.src.sys.mman.munlockall + libc.src.sys.mman.munmap + libc.src.sys.mman.posix_madvise libc.src.sys.mman.shm_open libc.src.sys.mman.shm_unlink @@ -263,8 +263,8 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.sys.stat.stat # sys/statvfs.h - libc.src.sys.statvfs.statvfs libc.src.sys.statvfs.fstatvfs + libc.src.sys.statvfs.statvfs # sys/utsname.h entrypoints libc.src.sys.utsname.uname @@ -285,11 +285,11 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.termios.cfgetospeed libc.src.termios.cfsetispeed libc.src.termios.cfsetospeed - libc.src.termios.tcgetattr - libc.src.termios.tcgetsid libc.src.termios.tcdrain libc.src.termios.tcflow libc.src.termios.tcflush + libc.src.termios.tcgetattr + libc.src.termios.tcgetsid libc.src.termios.tcsendbreak libc.src.termios.tcsetattr @@ -342,11 +342,11 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.fenv.fegetexceptflag libc.src.fenv.fegetround libc.src.fenv.feholdexcept + libc.src.fenv.feraiseexcept libc.src.fenv.fesetenv libc.src.fenv.fesetexcept libc.src.fenv.fesetexceptflag libc.src.fenv.fesetround - libc.src.fenv.feraiseexcept libc.src.fenv.fetestexcept libc.src.fenv.fetestexceptflag libc.src.fenv.feupdateenv @@ -362,23 +362,23 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.canonicalize libc.src.math.canonicalizef libc.src.math.canonicalizel - libc.src.math.copysign - libc.src.math.copysignf - libc.src.math.copysignl libc.src.math.ceil libc.src.math.ceilf libc.src.math.ceill + libc.src.math.copysign + libc.src.math.copysignf + libc.src.math.copysignl libc.src.math.cos - libc.src.math.coshf libc.src.math.cosf + libc.src.math.coshf libc.src.math.erff libc.src.math.exp - libc.src.math.expf libc.src.math.exp10 libc.src.math.exp10f libc.src.math.exp2 libc.src.math.exp2f libc.src.math.exp2m1f + libc.src.math.expf libc.src.math.expm1 libc.src.math.expm1f libc.src.math.fabs @@ -392,40 +392,40 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.floorl libc.src.math.fma libc.src.math.fmaf - libc.src.math.fmin - libc.src.math.fminf - libc.src.math.fminl libc.src.math.fmax libc.src.math.fmaxf - libc.src.math.fmaxl libc.src.math.fmaximum - libc.src.math.fmaximumf - libc.src.math.fmaximuml - libc.src.math.fmaximum_num - libc.src.math.fmaximum_numf - libc.src.math.fmaximum_numl libc.src.math.fmaximum_mag - libc.src.math.fmaximum_magf - libc.src.math.fmaximum_magl libc.src.math.fmaximum_mag_num libc.src.math.fmaximum_mag_numf libc.src.math.fmaximum_mag_numl + libc.src.math.fmaximum_magf + libc.src.math.fmaximum_magl + libc.src.math.fmaximum_num + libc.src.math.fmaximum_numf + libc.src.math.fmaximum_numl + libc.src.math.fmaximumf + libc.src.math.fmaximuml + libc.src.math.fmaxl + libc.src.math.fmin + libc.src.math.fminf libc.src.math.fminimum - libc.src.math.fminimumf - libc.src.math.fminimuml - libc.src.math.fminimum_num - libc.src.math.fminimum_numf - libc.src.math.fminimum_numl libc.src.math.fminimum_mag - libc.src.math.fminimum_magf - libc.src.math.fminimum_magl libc.src.math.fminimum_mag_num libc.src.math.fminimum_mag_numf libc.src.math.fminimum_mag_numl - libc.src.math.fmul + libc.src.math.fminimum_magf + libc.src.math.fminimum_magl + libc.src.math.fminimum_num + libc.src.math.fminimum_numf + libc.src.math.fminimum_numl + libc.src.math.fminimumf + libc.src.math.fminimuml + libc.src.math.fminl libc.src.math.fmod libc.src.math.fmodf libc.src.math.fmodl + libc.src.math.fmul libc.src.math.frexp libc.src.math.frexpf libc.src.math.frexpl @@ -452,17 +452,17 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.llround libc.src.math.llroundf libc.src.math.llroundl + libc.src.math.log libc.src.math.log10 libc.src.math.log10f libc.src.math.log1p libc.src.math.log1pf libc.src.math.log2 libc.src.math.log2f - libc.src.math.log - libc.src.math.logf libc.src.math.logb libc.src.math.logbf libc.src.math.logbl + libc.src.math.logf libc.src.math.lrint libc.src.math.lrintf libc.src.math.lrintl @@ -491,28 +491,29 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.nextupf libc.src.math.nextupl libc.src.math.powf - libc.src.math.remainderf libc.src.math.remainder + libc.src.math.remainderf libc.src.math.remainderl - libc.src.math.remquof libc.src.math.remquo + libc.src.math.remquof libc.src.math.remquol libc.src.math.rint libc.src.math.rintf libc.src.math.rintl libc.src.math.round - libc.src.math.roundf - libc.src.math.roundl libc.src.math.roundeven libc.src.math.roundevenf libc.src.math.roundevenl + libc.src.math.roundf + libc.src.math.roundl libc.src.math.scalbn libc.src.math.scalbnf libc.src.math.scalbnl libc.src.math.sin + libc.src.math.sincos libc.src.math.sincosf - libc.src.math.sinhf libc.src.math.sinf + libc.src.math.sinhf libc.src.math.sqrt libc.src.math.sqrtf libc.src.math.sqrtl @@ -536,21 +537,28 @@ if(LIBC_TYPES_HAS_FLOAT16) libc.src.math.canonicalizef16 libc.src.math.ceilf16 libc.src.math.copysignf16 + libc.src.math.f16div + libc.src.math.f16divf + libc.src.math.f16divl + libc.src.math.f16fma libc.src.math.f16fmaf + libc.src.math.f16fmal + libc.src.math.f16sqrt libc.src.math.f16sqrtf + libc.src.math.f16sqrtl libc.src.math.fabsf16 libc.src.math.fdimf16 libc.src.math.floorf16 libc.src.math.fmaxf16 - libc.src.math.fmaximumf16 - libc.src.math.fmaximum_magf16 libc.src.math.fmaximum_mag_numf16 + libc.src.math.fmaximum_magf16 libc.src.math.fmaximum_numf16 + libc.src.math.fmaximumf16 libc.src.math.fminf16 - libc.src.math.fminimumf16 - libc.src.math.fminimum_magf16 libc.src.math.fminimum_mag_numf16 + libc.src.math.fminimum_magf16 libc.src.math.fminimum_numf16 + libc.src.math.fminimumf16 libc.src.math.fmodf16 libc.src.math.frexpf16 libc.src.math.fromfpf16 @@ -574,8 +582,8 @@ if(LIBC_TYPES_HAS_FLOAT16) libc.src.math.remainderf16 libc.src.math.remquof16 libc.src.math.rintf16 - libc.src.math.roundf16 libc.src.math.roundevenf16 + libc.src.math.roundf16 libc.src.math.scalblnf16 libc.src.math.scalbnf16 libc.src.math.setpayloadf16 @@ -586,6 +594,15 @@ if(LIBC_TYPES_HAS_FLOAT16) libc.src.math.ufromfpf16 libc.src.math.ufromfpxf16 ) + + if(LIBC_TYPES_HAS_FLOAT128) + list(APPEND TARGET_LIBM_ENTRYPOINTS + # math.h C23 mixed _Float16 and _Float128 entrypoints + libc.src.math.f16divf128 + libc.src.math.f16fmaf128 + libc.src.math.f16sqrtf128 + ) + endif() endif() if(LIBC_TYPES_HAS_FLOAT128) @@ -598,15 +615,15 @@ if(LIBC_TYPES_HAS_FLOAT128) libc.src.math.fdimf128 libc.src.math.floorf128 libc.src.math.fmaxf128 - libc.src.math.fminf128 - libc.src.math.fmaximumf128 - libc.src.math.fmaximum_numf128 - libc.src.math.fmaximum_magf128 libc.src.math.fmaximum_mag_numf128 - libc.src.math.fminimumf128 - libc.src.math.fminimum_numf128 - libc.src.math.fminimum_magf128 + libc.src.math.fmaximum_magf128 + libc.src.math.fmaximum_numf128 + libc.src.math.fmaximumf128 + libc.src.math.fminf128 libc.src.math.fminimum_mag_numf128 + libc.src.math.fminimum_magf128 + libc.src.math.fminimum_numf128 + libc.src.math.fminimumf128 libc.src.math.fmodf128 libc.src.math.frexpf128 libc.src.math.fromfpf128 @@ -614,9 +631,9 @@ if(LIBC_TYPES_HAS_FLOAT128) libc.src.math.ilogbf128 libc.src.math.ldexpf128 libc.src.math.llogbf128 - libc.src.math.logbf128 libc.src.math.llrintf128 libc.src.math.llroundf128 + libc.src.math.logbf128 libc.src.math.lrintf128 libc.src.math.lroundf128 libc.src.math.modff128 @@ -643,23 +660,23 @@ if(LIBC_COMPILER_HAS_FIXED_POINT) libc.src.stdfix.abshk libc.src.stdfix.abshr libc.src.stdfix.absk - libc.src.stdfix.absr libc.src.stdfix.abslk libc.src.stdfix.abslr + libc.src.stdfix.absr libc.src.stdfix.exphk libc.src.stdfix.expk libc.src.stdfix.roundhk libc.src.stdfix.roundhr libc.src.stdfix.roundk - libc.src.stdfix.roundr libc.src.stdfix.roundlk libc.src.stdfix.roundlr + libc.src.stdfix.roundr libc.src.stdfix.rounduhk libc.src.stdfix.rounduhr libc.src.stdfix.rounduk - libc.src.stdfix.roundur libc.src.stdfix.roundulk libc.src.stdfix.roundulr + libc.src.stdfix.roundur libc.src.stdfix.sqrtuhk libc.src.stdfix.sqrtuhr libc.src.stdfix.sqrtuk @@ -694,11 +711,11 @@ if(LLVM_LIBC_FULL_BUILD) # pthread.h entrypoints libc.src.pthread.pthread_atfork libc.src.pthread.pthread_attr_destroy - libc.src.pthread.pthread_attr_init libc.src.pthread.pthread_attr_getdetachstate libc.src.pthread.pthread_attr_getguardsize libc.src.pthread.pthread_attr_getstack libc.src.pthread.pthread_attr_getstacksize + libc.src.pthread.pthread_attr_init libc.src.pthread.pthread_attr_setdetachstate libc.src.pthread.pthread_attr_setguardsize libc.src.pthread.pthread_attr_setstack @@ -718,36 +735,36 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.pthread.pthread_join libc.src.pthread.pthread_key_create libc.src.pthread.pthread_key_delete - libc.src.pthread.pthread_self - libc.src.pthread.pthread_setname_np libc.src.pthread.pthread_mutex_destroy libc.src.pthread.pthread_mutex_init libc.src.pthread.pthread_mutex_lock libc.src.pthread.pthread_mutex_unlock libc.src.pthread.pthread_mutexattr_destroy - libc.src.pthread.pthread_mutexattr_init libc.src.pthread.pthread_mutexattr_getpshared libc.src.pthread.pthread_mutexattr_getrobust libc.src.pthread.pthread_mutexattr_gettype + libc.src.pthread.pthread_mutexattr_init libc.src.pthread.pthread_mutexattr_setpshared libc.src.pthread.pthread_mutexattr_setrobust libc.src.pthread.pthread_mutexattr_settype libc.src.pthread.pthread_once + libc.src.pthread.pthread_rwlock_destroy libc.src.pthread.pthread_rwlock_init - libc.src.pthread.pthread_rwlock_tryrdlock libc.src.pthread.pthread_rwlock_rdlock libc.src.pthread.pthread_rwlock_timedrdlock - libc.src.pthread.pthread_rwlock_trywrlock - libc.src.pthread.pthread_rwlock_wrlock libc.src.pthread.pthread_rwlock_timedwrlock + libc.src.pthread.pthread_rwlock_tryrdlock + libc.src.pthread.pthread_rwlock_trywrlock libc.src.pthread.pthread_rwlock_unlock - libc.src.pthread.pthread_rwlock_destroy + libc.src.pthread.pthread_rwlock_wrlock libc.src.pthread.pthread_rwlockattr_destroy libc.src.pthread.pthread_rwlockattr_getkind_np libc.src.pthread.pthread_rwlockattr_getpshared libc.src.pthread.pthread_rwlockattr_init libc.src.pthread.pthread_rwlockattr_setkind_np libc.src.pthread.pthread_rwlockattr_setpshared + libc.src.pthread.pthread_self + libc.src.pthread.pthread_setname_np libc.src.pthread.pthread_setspecific # sched.h entrypoints @@ -761,24 +778,24 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.stdio.clearerr libc.src.stdio.clearerr_unlocked libc.src.stdio.fclose - libc.src.stdio.flockfile libc.src.stdio.feof libc.src.stdio.feof_unlocked libc.src.stdio.ferror libc.src.stdio.ferror_unlocked + libc.src.stdio.fflush libc.src.stdio.fgetc libc.src.stdio.fgetc_unlocked libc.src.stdio.fgets - libc.src.stdio.fflush + libc.src.stdio.flockfile libc.src.stdio.fopen + libc.src.stdio.fopencookie libc.src.stdio.fputc libc.src.stdio.fputs - libc.src.stdio.fopencookie libc.src.stdio.fread libc.src.stdio.fread_unlocked libc.src.stdio.fseek - libc.src.stdio.ftell libc.src.stdio.fseeko + libc.src.stdio.ftell libc.src.stdio.ftello libc.src.stdio.funlockfile libc.src.stdio.fwrite @@ -807,16 +824,16 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.stdlib.quick_exit # signal.h entrypoints - libc.src.signal.raise libc.src.signal.kill + libc.src.signal.raise libc.src.signal.sigaction + libc.src.signal.sigaddset libc.src.signal.sigaltstack libc.src.signal.sigdelset - libc.src.signal.sigaddset libc.src.signal.sigemptyset - libc.src.signal.sigprocmask libc.src.signal.sigfillset libc.src.signal.signal + libc.src.signal.sigprocmask # spawn.h entrypoints libc.src.spawn.posix_spawn @@ -829,10 +846,10 @@ if(LLVM_LIBC_FULL_BUILD) # search.h entrypoints libc.src.search.hcreate libc.src.search.hcreate_r - libc.src.search.hsearch - libc.src.search.hsearch_r libc.src.search.hdestroy libc.src.search.hdestroy_r + libc.src.search.hsearch + libc.src.search.hsearch_r libc.src.search.insque libc.src.search.remque @@ -861,8 +878,8 @@ if(LLVM_LIBC_FULL_BUILD) # time.h entrypoints libc.src.time.asctime libc.src.time.asctime_r - libc.src.time.clock_gettime libc.src.time.clock + libc.src.time.clock_gettime libc.src.time.difftime libc.src.time.gettimeofday libc.src.time.gmtime @@ -872,24 +889,24 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.time.time # unistd.h entrypoints + libc.src.unistd.__llvm_libc_syscall libc.src.unistd._exit libc.src.unistd.environ libc.src.unistd.execv libc.src.unistd.fork - libc.src.unistd.__llvm_libc_syscall libc.src.unistd.getopt libc.src.unistd.optarg + libc.src.unistd.opterr libc.src.unistd.optind libc.src.unistd.optopt - libc.src.unistd.opterr libc.src.unistd.swab # sys/select.h entrypoints libc.src.sys.select.select # sys/socket.h entrypoints - libc.src.sys.socket.socket libc.src.sys.socket.bind + libc.src.sys.socket.socket ) endif() diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt index a4898724daf86d..b33d572cf999ac 100644 --- a/libc/config/windows/entrypoints.txt +++ b/libc/config/windows/entrypoints.txt @@ -251,6 +251,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.scalbnl libc.src.math.sin libc.src.math.sincosf + libc.src.math.sincosf libc.src.math.sinf libc.src.math.sinhf libc.src.math.sqrt diff --git a/libc/docs/gpu/support.rst b/libc/docs/gpu/support.rst index 31bbdc41090be6..1044b005de0eef 100644 --- a/libc/docs/gpu/support.rst +++ b/libc/docs/gpu/support.rst @@ -190,6 +190,8 @@ strtold |check| strtoll |check| strtoul |check| strtoull |check| +srand |check| +rand |check| ============= ========= ============ inttypes.h diff --git a/libc/docs/math/index.rst b/libc/docs/math/index.rst index d6e642c4907f04..3ca7bf9fdb2835 100644 --- a/libc/docs/math/index.rst +++ b/libc/docs/math/index.rst @@ -124,7 +124,9 @@ Basic Operations +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | dsub | N/A | N/A | | N/A | | 7.12.14.2 | F.10.11 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ -| f16fma | |check| | | | N/A | | 7.12.14.5 | F.10.11 | +| f16div | |check|\* | |check|\* | |check|\* | N/A | |check| | 7.12.14.4 | F.10.11 | ++------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ +| f16fma | |check| | |check| | |check| | N/A | |check| | 7.12.14.5 | F.10.11 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | fabs | |check| | |check| | |check| | |check| | |check| | 7.12.7.3 | F.10.4.3 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ @@ -264,7 +266,7 @@ Higher Math Functions +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | compoundn | | | | | | 7.12.7.2 | F.10.4.2 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ -| cos | |check| | large | | | | 7.12.4.5 | F.10.1.5 | +| cos | |check| | |check| | | | | 7.12.4.5 | F.10.1.5 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | cosh | |check| | | | | | 7.12.5.4 | F.10.2.4 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ @@ -290,7 +292,7 @@ Higher Math Functions +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | fma | |check| | |check| | | | | 7.12.13.1 | F.10.10.1 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ -| f16sqrt | |check| | | | N/A | | 7.12.14.6 | F.10.11 | +| f16sqrt | |check|\* | |check|\* | |check|\* | N/A | |check| | 7.12.14.6 | F.10.11 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | fsqrt | N/A | | | N/A | | 7.12.14.6 | F.10.11 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ @@ -322,9 +324,9 @@ Higher Math Functions +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | rsqrt | | | | | | 7.12.7.9 | F.10.4.9 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ -| sin | |check| | large | | | | 7.12.4.6 | F.10.1.6 | +| sin | |check| | |check| | | | | 7.12.4.6 | F.10.1.6 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ -| sincos | |check| | large | | | | | | +| sincos | |check| | |check| | | | | | | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | sinh | |check| | | | | | 7.12.5.5 | F.10.2.5 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ @@ -348,6 +350,7 @@ Legends: tie-to-even). * x ULPs: largest errors recorded. * N/A: Not defined in the standard or will not be added. +* \*: LLVM libc extension. .. TODO(lntue): Add a new page to discuss about the algorithms used in the diff --git a/libc/hdr/types/CMakeLists.txt b/libc/hdr/types/CMakeLists.txt index 9b3373a0ca3905..1cab1d3b812cf0 100644 --- a/libc/hdr/types/CMakeLists.txt +++ b/libc/hdr/types/CMakeLists.txt @@ -126,3 +126,12 @@ add_proxy_header_library( libc.include.llvm-libc-types.atexithandler_t libc.include.stdlib ) + +add_proxy_header_library( + struct_sigaction + HDRS + struct_sigaction.h + FULL_BUILD_DEPENDS + libc.include.llvm-libc-types.struct_sigaction + libc.include.signal +) diff --git a/libc/hdr/types/struct_sigaction.h b/libc/hdr/types/struct_sigaction.h new file mode 100644 index 00000000000000..60f6caeb4af106 --- /dev/null +++ b/libc/hdr/types/struct_sigaction.h @@ -0,0 +1,21 @@ +//===-- Proxy for struct sigaction ---------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_LIBC_HDR_TYPES_STRUCT_SIGACTION_H +#define LLVM_LIBC_HDR_TYPES_STRUCT_SIGACTION_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-types/struct_sigaction.h" + +#else + +#include + +#endif // LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_TYPES_STRUCT_SIGACTION_H diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt index bb10fd4c947034..3ab7817d8568b7 100644 --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -223,30 +223,23 @@ add_gen_header( GEN_HDR errno.h DEPENDS .llvm-libc-macros.generic_error_number_macros + .llvm-libc-macros.error_number_macros ) -if(EXISTS "${LIBC_SOURCE_DIR}/config/${LIBC_TARGET_OS}/signal.h.in") - add_gen_header( - signal - DEF_FILE signal.h.def - PARAMS - platform_signal=../config/${LIBC_TARGET_OS}/signal.h.in - GEN_HDR signal.h - DATA_FILES - ../config/${LIBC_TARGET_OS}/signal.h.in - DEPENDS - .llvm-libc-macros.signal_macros - .llvm-libc-types.sig_atomic_t - .llvm-libc-types.sigset_t - .llvm-libc-types.struct_sigaction - .llvm-libc-types.union_sigval - .llvm-libc-types.siginfo_t - .llvm-libc-types.stack_t - .llvm-libc-types.pid_t - ) -else() - message(STATUS "Skipping header signal.h as the target config is missing") -endif() +add_gen_header( + signal + DEF_FILE signal.h.def + GEN_HDR signal.h + DEPENDS + .llvm-libc-macros.signal_macros + .llvm-libc-types.sig_atomic_t + .llvm-libc-types.sigset_t + .llvm-libc-types.struct_sigaction + .llvm-libc-types.union_sigval + .llvm-libc-types.siginfo_t + .llvm-libc-types.stack_t + .llvm-libc-types.pid_t +) add_gen_header( stdbit @@ -523,10 +516,6 @@ add_gen_header( sys_syscall DEF_FILE sys/syscall.h.def GEN_HDR sys/syscall.h - PARAMS - syscall_numbers=../config/${LIBC_TARGET_OS}/syscall_numbers.h.inc - DATA_FILES - ../config/${LIBC_TARGET_OS}/syscall_numbers.h.inc ) add_gen_header( diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt index a4c2ca0df74d35..f6af11abd4dd76 100644 --- a/libc/include/llvm-libc-macros/CMakeLists.txt +++ b/libc/include/llvm-libc-macros/CMakeLists.txt @@ -103,6 +103,12 @@ add_macro_header( limits-macros.h ) +add_macro_header( + link_macros + HDR + link-macros.h +) + add_macro_header( math_macros HDR diff --git a/libc/include/llvm-libc-macros/float16-macros.h b/libc/include/llvm-libc-macros/float16-macros.h index e7d8d93bca1b60..9a11ecc49307e2 100644 --- a/libc/include/llvm-libc-macros/float16-macros.h +++ b/libc/include/llvm-libc-macros/float16-macros.h @@ -9,10 +9,18 @@ #ifndef LLVM_LIBC_MACROS_FLOAT16_MACROS_H #define LLVM_LIBC_MACROS_FLOAT16_MACROS_H +#include "../llvm-libc-types/float128.h" + #if defined(__FLT16_MANT_DIG__) && \ (!defined(__GNUC__) || __GNUC__ >= 13 || defined(__clang__)) && \ !defined(__arm__) && !defined(_M_ARM) && !defined(__riscv) #define LIBC_TYPES_HAS_FLOAT16 + +// TODO: This would no longer be required if HdrGen let us guard function +// declarations with multiple macros. +#ifdef LIBC_TYPES_HAS_FLOAT128 +#define LIBC_TYPES_HAS_FLOAT16_AND_FLOAT128 +#endif // LIBC_TYPES_HAS_FLOAT128 #endif #endif // LLVM_LIBC_MACROS_FLOAT16_MACROS_H diff --git a/libc/include/llvm-libc-macros/link-macros.h b/libc/include/llvm-libc-macros/link-macros.h new file mode 100644 index 00000000000000..5c8cadab8e71cb --- /dev/null +++ b/libc/include/llvm-libc-macros/link-macros.h @@ -0,0 +1,13 @@ +//===-- Definition of macros to for extra dynamic linker functionality ----===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifdef __LP64__ +#define ElfW(type) Elf64_ ## type +#else +#define ElfW(type) Elf32_ ## type +#endif diff --git a/libc/include/sys/syscall.h.def b/libc/include/sys/syscall.h.def index 5cb6a20da77bee..03c19eb0885ed6 100644 --- a/libc/include/sys/syscall.h.def +++ b/libc/include/sys/syscall.h.def @@ -9,9 +9,2345 @@ #ifndef LLVM_LIBC_SYS_SYSCALL_H #define LLVM_LIBC_SYS_SYSCALL_H - If syscall.h were a linux only file, then we do not need this indirection. - However, to keep the option of a non-linux OS requiring a syscall.h file, - with its own special syscall numbers, we use this indirection. -%%include_file(${syscall_numbers}) +//TODO: Handle non-linux syscalls + +#include + +#ifdef __NR_FAST_atomic_update +#define SYS_FAST_atomic_update __NR_FAST_atomic_update +#endif + +#ifdef __NR_FAST_cmpxchg +#define SYS_FAST_cmpxchg __NR_FAST_cmpxchg +#endif + +#ifdef __NR_FAST_cmpxchg64 +#define SYS_FAST_cmpxchg64 __NR_FAST_cmpxchg64 +#endif + +#ifdef __NR__llseek +#define SYS__llseek __NR__llseek +#endif + +#ifdef __NR__newselect +#define SYS__newselect __NR__newselect +#endif + +#ifdef __NR__sysctl +#define SYS__sysctl __NR__sysctl +#endif + +#ifdef __NR_accept +#define SYS_accept __NR_accept +#endif + +#ifdef __NR_accept4 +#define SYS_accept4 __NR_accept4 +#endif + +#ifdef __NR_access +#define SYS_access __NR_access +#endif + +#ifdef __NR_acct +#define SYS_acct __NR_acct +#endif + +#ifdef __NR_acl_get +#define SYS_acl_get __NR_acl_get +#endif + +#ifdef __NR_acl_set +#define SYS_acl_set __NR_acl_set +#endif + +#ifdef __NR_add_key +#define SYS_add_key __NR_add_key +#endif + +#ifdef __NR_adjtimex +#define SYS_adjtimex __NR_adjtimex +#endif + +#ifdef __NR_afs_syscall +#define SYS_afs_syscall __NR_afs_syscall +#endif + +#ifdef __NR_alarm +#define SYS_alarm __NR_alarm +#endif + +#ifdef __NR_alloc_hugepages +#define SYS_alloc_hugepages __NR_alloc_hugepages +#endif + +#ifdef __NR_arch_prctl +#define SYS_arch_prctl __NR_arch_prctl +#endif + +#ifdef __NR_arm_fadvise64_64 +#define SYS_arm_fadvise64_64 __NR_arm_fadvise64_64 +#endif + +#ifdef __NR_arm_sync_file_range +#define SYS_arm_sync_file_range __NR_arm_sync_file_range +#endif + +#ifdef __NR_atomic_barrier +#define SYS_atomic_barrier __NR_atomic_barrier +#endif + +#ifdef __NR_atomic_cmpxchg_32 +#define SYS_atomic_cmpxchg_32 __NR_atomic_cmpxchg_32 +#endif + +#ifdef __NR_attrctl +#define SYS_attrctl __NR_attrctl +#endif + +#ifdef __NR_bdflush +#define SYS_bdflush __NR_bdflush +#endif + +#ifdef __NR_bind +#define SYS_bind __NR_bind +#endif + +#ifdef __NR_bpf +#define SYS_bpf __NR_bpf +#endif + +#ifdef __NR_break +#define SYS_break __NR_break +#endif + +#ifdef __NR_brk +#define SYS_brk __NR_brk +#endif + +#ifdef __NR_cachectl +#define SYS_cachectl __NR_cachectl +#endif + +#ifdef __NR_cacheflush +#define SYS_cacheflush __NR_cacheflush +#endif + +#ifdef __NR_capget +#define SYS_capget __NR_capget +#endif + +#ifdef __NR_capset +#define SYS_capset __NR_capset +#endif + +#ifdef __NR_chdir +#define SYS_chdir __NR_chdir +#endif + +#ifdef __NR_chmod +#define SYS_chmod __NR_chmod +#endif + +#ifdef __NR_chown +#define SYS_chown __NR_chown +#endif + +#ifdef __NR_chown32 +#define SYS_chown32 __NR_chown32 +#endif + +#ifdef __NR_chroot +#define SYS_chroot __NR_chroot +#endif + +#ifdef __NR_clock_adjtime +#define SYS_clock_adjtime __NR_clock_adjtime +#endif + +#ifdef __NR_clock_getres +#define SYS_clock_getres __NR_clock_getres +#endif + +#ifdef __NR_clock_gettime +#define SYS_clock_gettime __NR_clock_gettime +#endif + +#ifdef __NR_clock_gettime64 +#define SYS_clock_gettime64 __NR_clock_gettime64 +#endif + +#ifdef __NR_clock_nanosleep +#define SYS_clock_nanosleep __NR_clock_nanosleep +#endif + +#ifdef __NR_clock_nanosleep_time64 +#define SYS_clock_nanosleep_time64 __NR_clock_nanosleep_time64 +#endif + +#ifdef __NR_clock_settime +#define SYS_clock_settime __NR_clock_settime +#endif + +#ifdef __NR_clone +#define SYS_clone __NR_clone +#endif + +#ifdef __NR_clone2 +#define SYS_clone2 __NR_clone2 +#endif + +#ifdef __NR_close +#define SYS_close __NR_close +#endif + +#ifdef __NR_cmpxchg_badaddr +#define SYS_cmpxchg_badaddr __NR_cmpxchg_badaddr +#endif + +#ifdef __NR_connect +#define SYS_connect __NR_connect +#endif + +#ifdef __NR_copy_file_range +#define SYS_copy_file_range __NR_copy_file_range +#endif + +#ifdef __NR_creat +#define SYS_creat __NR_creat +#endif + +#ifdef __NR_create_module +#define SYS_create_module __NR_create_module +#endif + +#ifdef __NR_delete_module +#define SYS_delete_module __NR_delete_module +#endif + +#ifdef __NR_dipc +#define SYS_dipc __NR_dipc +#endif + +#ifdef __NR_dup +#define SYS_dup __NR_dup +#endif + +#ifdef __NR_dup2 +#define SYS_dup2 __NR_dup2 +#endif + +#ifdef __NR_dup3 +#define SYS_dup3 __NR_dup3 +#endif + +#ifdef __NR_epoll_create +#define SYS_epoll_create __NR_epoll_create +#endif + +#ifdef __NR_epoll_create1 +#define SYS_epoll_create1 __NR_epoll_create1 +#endif + +#ifdef __NR_epoll_ctl +#define SYS_epoll_ctl __NR_epoll_ctl +#endif + +#ifdef __NR_epoll_ctl_old +#define SYS_epoll_ctl_old __NR_epoll_ctl_old +#endif + +#ifdef __NR_epoll_pwait +#define SYS_epoll_pwait __NR_epoll_pwait +#endif + +#ifdef __NR_epoll_pwait2 +#define SYS_epoll_pwait2 __NR_epoll_pwait2 +#endif + +#ifdef __NR_epoll_wait +#define SYS_epoll_wait __NR_epoll_wait +#endif + +#ifdef __NR_epoll_wait_old +#define SYS_epoll_wait_old __NR_epoll_wait_old +#endif + +#ifdef __NR_eventfd +#define SYS_eventfd __NR_eventfd +#endif + +#ifdef __NR_eventfd2 +#define SYS_eventfd2 __NR_eventfd2 +#endif + +#ifdef __NR_exec_with_loader +#define SYS_exec_with_loader __NR_exec_with_loader +#endif + +#ifdef __NR_execv +#define SYS_execv __NR_execv +#endif + +#ifdef __NR_execve +#define SYS_execve __NR_execve +#endif + +#ifdef __NR_execveat +#define SYS_execveat __NR_execveat +#endif + +#ifdef __NR_exit +#define SYS_exit __NR_exit +#endif + +#ifdef __NR_exit_group +#define SYS_exit_group __NR_exit_group +#endif + +#ifdef __NR_faccessat +#define SYS_faccessat __NR_faccessat +#endif + +#ifdef __NR_fadvise64 +#define SYS_fadvise64 __NR_fadvise64 +#endif + +#ifdef __NR_fadvise64_64 +#define SYS_fadvise64_64 __NR_fadvise64_64 +#endif + +#ifdef __NR_fallocate +#define SYS_fallocate __NR_fallocate +#endif + +#ifdef __NR_fanotify_init +#define SYS_fanotify_init __NR_fanotify_init +#endif + +#ifdef __NR_fanotify_mark +#define SYS_fanotify_mark __NR_fanotify_mark +#endif + +#ifdef __NR_fchdir +#define SYS_fchdir __NR_fchdir +#endif + +#ifdef __NR_fchmod +#define SYS_fchmod __NR_fchmod +#endif + +#ifdef __NR_fchmodat +#define SYS_fchmodat __NR_fchmodat +#endif + +#ifdef __NR_fchmodat2 +#define SYS_fchmodat2 __NR_fchmodat2 +#endif + +#ifdef __NR_fchown +#define SYS_fchown __NR_fchown +#endif + +#ifdef __NR_fchown32 +#define SYS_fchown32 __NR_fchown32 +#endif + +#ifdef __NR_fchownat +#define SYS_fchownat __NR_fchownat +#endif + +#ifdef __NR_fcntl +#define SYS_fcntl __NR_fcntl +#endif + +#ifdef __NR_fcntl64 +#define SYS_fcntl64 __NR_fcntl64 +#endif + +#ifdef __NR_fdatasync +#define SYS_fdatasync __NR_fdatasync +#endif + +#ifdef __NR_fgetxattr +#define SYS_fgetxattr __NR_fgetxattr +#endif + +#ifdef __NR_finit_module +#define SYS_finit_module __NR_finit_module +#endif + +#ifdef __NR_flistxattr +#define SYS_flistxattr __NR_flistxattr +#endif + +#ifdef __NR_flock +#define SYS_flock __NR_flock +#endif + +#ifdef __NR_fork +#define SYS_fork __NR_fork +#endif + +#ifdef __NR_free_hugepages +#define SYS_free_hugepages __NR_free_hugepages +#endif + +#ifdef __NR_fremovexattr +#define SYS_fremovexattr __NR_fremovexattr +#endif + +#ifdef __NR_fsetxattr +#define SYS_fsetxattr __NR_fsetxattr +#endif + +#ifdef __NR_fstat +#define SYS_fstat __NR_fstat +#endif + +#ifdef __NR_fstat64 +#define SYS_fstat64 __NR_fstat64 +#endif + +#ifdef __NR_fstatat64 +#define SYS_fstatat64 __NR_fstatat64 +#endif + +#ifdef __NR_fstatfs +#define SYS_fstatfs __NR_fstatfs +#endif + +#ifdef __NR_fstatfs64 +#define SYS_fstatfs64 __NR_fstatfs64 +#endif + +#ifdef __NR_fsync +#define SYS_fsync __NR_fsync +#endif + +#ifdef __NR_ftime +#define SYS_ftime __NR_ftime +#endif + +#ifdef __NR_ftruncate +#define SYS_ftruncate __NR_ftruncate +#endif + +#ifdef __NR_ftruncate64 +#define SYS_ftruncate64 __NR_ftruncate64 +#endif + +#ifdef __NR_futex +#define SYS_futex __NR_futex +#endif + +#ifdef __NR_futex_time64 +#define SYS_futex_time64 __NR_futex_time64 +#endif + +#ifdef __NR_futimesat +#define SYS_futimesat __NR_futimesat +#endif + +#ifdef __NR_get_kernel_syms +#define SYS_get_kernel_syms __NR_get_kernel_syms +#endif + +#ifdef __NR_get_mempolicy +#define SYS_get_mempolicy __NR_get_mempolicy +#endif + +#ifdef __NR_get_robust_list +#define SYS_get_robust_list __NR_get_robust_list +#endif + +#ifdef __NR_get_thread_area +#define SYS_get_thread_area __NR_get_thread_area +#endif + +#ifdef __NR_getcpu +#define SYS_getcpu __NR_getcpu +#endif + +#ifdef __NR_getcwd +#define SYS_getcwd __NR_getcwd +#endif + +#ifdef __NR_getdents +#define SYS_getdents __NR_getdents +#endif + +#ifdef __NR_getdents64 +#define SYS_getdents64 __NR_getdents64 +#endif + +#ifdef __NR_getdomainname +#define SYS_getdomainname __NR_getdomainname +#endif + +#ifdef __NR_getdtablesize +#define SYS_getdtablesize __NR_getdtablesize +#endif + +#ifdef __NR_getegid +#define SYS_getegid __NR_getegid +#endif + +#ifdef __NR_getegid32 +#define SYS_getegid32 __NR_getegid32 +#endif + +#ifdef __NR_geteuid +#define SYS_geteuid __NR_geteuid +#endif + +#ifdef __NR_geteuid32 +#define SYS_geteuid32 __NR_geteuid32 +#endif + +#ifdef __NR_getgid +#define SYS_getgid __NR_getgid +#endif + +#ifdef __NR_getgid32 +#define SYS_getgid32 __NR_getgid32 +#endif + +#ifdef __NR_getgroups +#define SYS_getgroups __NR_getgroups +#endif + +#ifdef __NR_getgroups32 +#define SYS_getgroups32 __NR_getgroups32 +#endif + +#ifdef __NR_gethostname +#define SYS_gethostname __NR_gethostname +#endif + +#ifdef __NR_getitimer +#define SYS_getitimer __NR_getitimer +#endif + +#ifdef __NR_getpagesize +#define SYS_getpagesize __NR_getpagesize +#endif + +#ifdef __NR_getpeername +#define SYS_getpeername __NR_getpeername +#endif + +#ifdef __NR_getpgid +#define SYS_getpgid __NR_getpgid +#endif + +#ifdef __NR_getpgrp +#define SYS_getpgrp __NR_getpgrp +#endif + +#ifdef __NR_getpid +#define SYS_getpid __NR_getpid +#endif + +#ifdef __NR_getpmsg +#define SYS_getpmsg __NR_getpmsg +#endif + +#ifdef __NR_getppid +#define SYS_getppid __NR_getppid +#endif + +#ifdef __NR_getpriority +#define SYS_getpriority __NR_getpriority +#endif + +#ifdef __NR_getrandom +#define SYS_getrandom __NR_getrandom +#endif + +#ifdef __NR_getresgid +#define SYS_getresgid __NR_getresgid +#endif + +#ifdef __NR_getresgid32 +#define SYS_getresgid32 __NR_getresgid32 +#endif + +#ifdef __NR_getresuid +#define SYS_getresuid __NR_getresuid +#endif + +#ifdef __NR_getresuid32 +#define SYS_getresuid32 __NR_getresuid32 +#endif + +#ifdef __NR_getrlimit +#define SYS_getrlimit __NR_getrlimit +#endif + +#ifdef __NR_getrusage +#define SYS_getrusage __NR_getrusage +#endif + +#ifdef __NR_getsid +#define SYS_getsid __NR_getsid +#endif + +#ifdef __NR_getsockname +#define SYS_getsockname __NR_getsockname +#endif + +#ifdef __NR_getsockopt +#define SYS_getsockopt __NR_getsockopt +#endif + +#ifdef __NR_gettid +#define SYS_gettid __NR_gettid +#endif + +#ifdef __NR_gettimeofday +#define SYS_gettimeofday __NR_gettimeofday +#endif + +#ifdef __NR_getuid +#define SYS_getuid __NR_getuid +#endif + +#ifdef __NR_getuid32 +#define SYS_getuid32 __NR_getuid32 +#endif + +#ifdef __NR_getunwind +#define SYS_getunwind __NR_getunwind +#endif + +#ifdef __NR_getxattr +#define SYS_getxattr __NR_getxattr +#endif + +#ifdef __NR_getxgid +#define SYS_getxgid __NR_getxgid +#endif + +#ifdef __NR_getxpid +#define SYS_getxpid __NR_getxpid +#endif + +#ifdef __NR_getxuid +#define SYS_getxuid __NR_getxuid +#endif + +#ifdef __NR_gtty +#define SYS_gtty __NR_gtty +#endif + +#ifdef __NR_idle +#define SYS_idle __NR_idle +#endif + +#ifdef __NR_init_module +#define SYS_init_module __NR_init_module +#endif + +#ifdef __NR_inotify_add_watch +#define SYS_inotify_add_watch __NR_inotify_add_watch +#endif + +#ifdef __NR_inotify_init +#define SYS_inotify_init __NR_inotify_init +#endif + +#ifdef __NR_inotify_init1 +#define SYS_inotify_init1 __NR_inotify_init1 +#endif + +#ifdef __NR_inotify_rm_watch +#define SYS_inotify_rm_watch __NR_inotify_rm_watch +#endif + +#ifdef __NR_io_cancel +#define SYS_io_cancel __NR_io_cancel +#endif + +#ifdef __NR_io_destroy +#define SYS_io_destroy __NR_io_destroy +#endif + +#ifdef __NR_io_getevents +#define SYS_io_getevents __NR_io_getevents +#endif + +#ifdef __NR_io_pgetevents +#define SYS_io_pgetevents __NR_io_pgetevents +#endif + +#ifdef __NR_io_setup +#define SYS_io_setup __NR_io_setup +#endif + +#ifdef __NR_io_submit +#define SYS_io_submit __NR_io_submit +#endif + +#ifdef __NR_ioctl +#define SYS_ioctl __NR_ioctl +#endif + +#ifdef __NR_ioperm +#define SYS_ioperm __NR_ioperm +#endif + +#ifdef __NR_iopl +#define SYS_iopl __NR_iopl +#endif + +#ifdef __NR_ioprio_get +#define SYS_ioprio_get __NR_ioprio_get +#endif + +#ifdef __NR_ioprio_set +#define SYS_ioprio_set __NR_ioprio_set +#endif + +#ifdef __NR_ipc +#define SYS_ipc __NR_ipc +#endif + +#ifdef __NR_kcmp +#define SYS_kcmp __NR_kcmp +#endif + +#ifdef __NR_kern_features +#define SYS_kern_features __NR_kern_features +#endif + +#ifdef __NR_kexec_file_load +#define SYS_kexec_file_load __NR_kexec_file_load +#endif + +#ifdef __NR_kexec_load +#define SYS_kexec_load __NR_kexec_load +#endif + +#ifdef __NR_keyctl +#define SYS_keyctl __NR_keyctl +#endif + +#ifdef __NR_kill +#define SYS_kill __NR_kill +#endif + +#ifdef __NR_lchown +#define SYS_lchown __NR_lchown +#endif + +#ifdef __NR_lchown32 +#define SYS_lchown32 __NR_lchown32 +#endif + +#ifdef __NR_lgetxattr +#define SYS_lgetxattr __NR_lgetxattr +#endif + +#ifdef __NR_link +#define SYS_link __NR_link +#endif + +#ifdef __NR_linkat +#define SYS_linkat __NR_linkat +#endif + +#ifdef __NR_listen +#define SYS_listen __NR_listen +#endif + +#ifdef __NR_listxattr +#define SYS_listxattr __NR_listxattr +#endif + +#ifdef __NR_llistxattr +#define SYS_llistxattr __NR_llistxattr +#endif + +#ifdef __NR_llseek +#define SYS_llseek __NR_llseek +#endif + +#ifdef __NR_lock +#define SYS_lock __NR_lock +#endif + +#ifdef __NR_lookup_dcookie +#define SYS_lookup_dcookie __NR_lookup_dcookie +#endif + +#ifdef __NR_lremovexattr +#define SYS_lremovexattr __NR_lremovexattr +#endif + +#ifdef __NR_lseek +#define SYS_lseek __NR_lseek +#endif + +#ifdef __NR_lsetxattr +#define SYS_lsetxattr __NR_lsetxattr +#endif + +#ifdef __NR_lstat +#define SYS_lstat __NR_lstat +#endif + +#ifdef __NR_lstat64 +#define SYS_lstat64 __NR_lstat64 +#endif + +#ifdef __NR_madvise +#define SYS_madvise __NR_madvise +#endif + +#ifdef __NR_mbind +#define SYS_mbind __NR_mbind +#endif + +#ifdef __NR_membarrier +#define SYS_membarrier __NR_membarrier +#endif + +#ifdef __NR_memfd_create +#define SYS_memfd_create __NR_memfd_create +#endif + +#ifdef __NR_memory_ordering +#define SYS_memory_ordering __NR_memory_ordering +#endif + +#ifdef __NR_migrate_pages +#define SYS_migrate_pages __NR_migrate_pages +#endif + +#ifdef __NR_mincore +#define SYS_mincore __NR_mincore +#endif + +#ifdef __NR_mkdir +#define SYS_mkdir __NR_mkdir +#endif + +#ifdef __NR_mkdirat +#define SYS_mkdirat __NR_mkdirat +#endif + +#ifdef __NR_mknod +#define SYS_mknod __NR_mknod +#endif + +#ifdef __NR_mknodat +#define SYS_mknodat __NR_mknodat +#endif + +#ifdef __NR_mlock +#define SYS_mlock __NR_mlock +#endif + +#ifdef __NR_mlock2 +#define SYS_mlock2 __NR_mlock2 +#endif + +#ifdef __NR_mlockall +#define SYS_mlockall __NR_mlockall +#endif + +#ifdef __NR_mmap +#define SYS_mmap __NR_mmap +#endif + +#ifdef __NR_mmap2 +#define SYS_mmap2 __NR_mmap2 +#endif + +#ifdef __NR_modify_ldt +#define SYS_modify_ldt __NR_modify_ldt +#endif + +#ifdef __NR_mount +#define SYS_mount __NR_mount +#endif + +#ifdef __NR_move_pages +#define SYS_move_pages __NR_move_pages +#endif + +#ifdef __NR_mprotect +#define SYS_mprotect __NR_mprotect +#endif + +#ifdef __NR_mpx +#define SYS_mpx __NR_mpx +#endif + +#ifdef __NR_mq_getsetattr +#define SYS_mq_getsetattr __NR_mq_getsetattr +#endif + +#ifdef __NR_mq_notify +#define SYS_mq_notify __NR_mq_notify +#endif + +#ifdef __NR_mq_open +#define SYS_mq_open __NR_mq_open +#endif + +#ifdef __NR_mq_timedreceive +#define SYS_mq_timedreceive __NR_mq_timedreceive +#endif + +#ifdef __NR_mq_timedsend +#define SYS_mq_timedsend __NR_mq_timedsend +#endif + +#ifdef __NR_mq_unlink +#define SYS_mq_unlink __NR_mq_unlink +#endif + +#ifdef __NR_mremap +#define SYS_mremap __NR_mremap +#endif + +#ifdef __NR_msgctl +#define SYS_msgctl __NR_msgctl +#endif + +#ifdef __NR_msgget +#define SYS_msgget __NR_msgget +#endif + +#ifdef __NR_msgrcv +#define SYS_msgrcv __NR_msgrcv +#endif + +#ifdef __NR_msgsnd +#define SYS_msgsnd __NR_msgsnd +#endif + +#ifdef __NR_msync +#define SYS_msync __NR_msync +#endif + +#ifdef __NR_multiplexer +#define SYS_multiplexer __NR_multiplexer +#endif + +#ifdef __NR_munlock +#define SYS_munlock __NR_munlock +#endif + +#ifdef __NR_munlockall +#define SYS_munlockall __NR_munlockall +#endif + +#ifdef __NR_munmap +#define SYS_munmap __NR_munmap +#endif + +#ifdef __NR_name_to_handle_at +#define SYS_name_to_handle_at __NR_name_to_handle_at +#endif + +#ifdef __NR_nanosleep +#define SYS_nanosleep __NR_nanosleep +#endif + +#ifdef __NR_newfstatat +#define SYS_newfstatat __NR_newfstatat +#endif + +#ifdef __NR_nfsservctl +#define SYS_nfsservctl __NR_nfsservctl +#endif + +#ifdef __NR_ni_syscall +#define SYS_ni_syscall __NR_ni_syscall +#endif + +#ifdef __NR_nice +#define SYS_nice __NR_nice +#endif + +#ifdef __NR_old_adjtimex +#define SYS_old_adjtimex __NR_old_adjtimex +#endif + +#ifdef __NR_oldfstat +#define SYS_oldfstat __NR_oldfstat +#endif + +#ifdef __NR_oldlstat +#define SYS_oldlstat __NR_oldlstat +#endif + +#ifdef __NR_oldolduname +#define SYS_oldolduname __NR_oldolduname +#endif + +#ifdef __NR_oldstat +#define SYS_oldstat __NR_oldstat +#endif + +#ifdef __NR_oldumount +#define SYS_oldumount __NR_oldumount +#endif + +#ifdef __NR_olduname +#define SYS_olduname __NR_olduname +#endif + +#ifdef __NR_open +#define SYS_open __NR_open +#endif + +#ifdef __NR_open_by_handle_at +#define SYS_open_by_handle_at __NR_open_by_handle_at +#endif + +#ifdef __NR_openat +#define SYS_openat __NR_openat +#endif + +#ifdef __NR_osf_adjtime +#define SYS_osf_adjtime __NR_osf_adjtime +#endif + +#ifdef __NR_osf_afs_syscall +#define SYS_osf_afs_syscall __NR_osf_afs_syscall +#endif + +#ifdef __NR_osf_alt_plock +#define SYS_osf_alt_plock __NR_osf_alt_plock +#endif + +#ifdef __NR_osf_alt_setsid +#define SYS_osf_alt_setsid __NR_osf_alt_setsid +#endif + +#ifdef __NR_osf_alt_sigpending +#define SYS_osf_alt_sigpending __NR_osf_alt_sigpending +#endif + +#ifdef __NR_osf_asynch_daemon +#define SYS_osf_asynch_daemon __NR_osf_asynch_daemon +#endif + +#ifdef __NR_osf_audcntl +#define SYS_osf_audcntl __NR_osf_audcntl +#endif + +#ifdef __NR_osf_audgen +#define SYS_osf_audgen __NR_osf_audgen +#endif + +#ifdef __NR_osf_chflags +#define SYS_osf_chflags __NR_osf_chflags +#endif + +#ifdef __NR_osf_execve +#define SYS_osf_execve __NR_osf_execve +#endif + +#ifdef __NR_osf_exportfs +#define SYS_osf_exportfs __NR_osf_exportfs +#endif + +#ifdef __NR_osf_fchflags +#define SYS_osf_fchflags __NR_osf_fchflags +#endif + +#ifdef __NR_osf_fdatasync +#define SYS_osf_fdatasync __NR_osf_fdatasync +#endif + +#ifdef __NR_osf_fpathconf +#define SYS_osf_fpathconf __NR_osf_fpathconf +#endif + +#ifdef __NR_osf_fstat +#define SYS_osf_fstat __NR_osf_fstat +#endif + +#ifdef __NR_osf_fstatfs +#define SYS_osf_fstatfs __NR_osf_fstatfs +#endif + +#ifdef __NR_osf_fstatfs64 +#define SYS_osf_fstatfs64 __NR_osf_fstatfs64 +#endif + +#ifdef __NR_osf_fuser +#define SYS_osf_fuser __NR_osf_fuser +#endif + +#ifdef __NR_osf_getaddressconf +#define SYS_osf_getaddressconf __NR_osf_getaddressconf +#endif + +#ifdef __NR_osf_getdirentries +#define SYS_osf_getdirentries __NR_osf_getdirentries +#endif + +#ifdef __NR_osf_getdomainname +#define SYS_osf_getdomainname __NR_osf_getdomainname +#endif + +#ifdef __NR_osf_getfh +#define SYS_osf_getfh __NR_osf_getfh +#endif + +#ifdef __NR_osf_getfsstat +#define SYS_osf_getfsstat __NR_osf_getfsstat +#endif + +#ifdef __NR_osf_gethostid +#define SYS_osf_gethostid __NR_osf_gethostid +#endif + +#ifdef __NR_osf_getitimer +#define SYS_osf_getitimer __NR_osf_getitimer +#endif + +#ifdef __NR_osf_getlogin +#define SYS_osf_getlogin __NR_osf_getlogin +#endif + +#ifdef __NR_osf_getmnt +#define SYS_osf_getmnt __NR_osf_getmnt +#endif + +#ifdef __NR_osf_getrusage +#define SYS_osf_getrusage __NR_osf_getrusage +#endif + +#ifdef __NR_osf_getsysinfo +#define SYS_osf_getsysinfo __NR_osf_getsysinfo +#endif + +#ifdef __NR_osf_gettimeofday +#define SYS_osf_gettimeofday __NR_osf_gettimeofday +#endif + +#ifdef __NR_osf_kloadcall +#define SYS_osf_kloadcall __NR_osf_kloadcall +#endif + +#ifdef __NR_osf_kmodcall +#define SYS_osf_kmodcall __NR_osf_kmodcall +#endif + +#ifdef __NR_osf_lstat +#define SYS_osf_lstat __NR_osf_lstat +#endif + +#ifdef __NR_osf_memcntl +#define SYS_osf_memcntl __NR_osf_memcntl +#endif + +#ifdef __NR_osf_mincore +#define SYS_osf_mincore __NR_osf_mincore +#endif + +#ifdef __NR_osf_mount +#define SYS_osf_mount __NR_osf_mount +#endif + +#ifdef __NR_osf_mremap +#define SYS_osf_mremap __NR_osf_mremap +#endif + +#ifdef __NR_osf_msfs_syscall +#define SYS_osf_msfs_syscall __NR_osf_msfs_syscall +#endif + +#ifdef __NR_osf_msleep +#define SYS_osf_msleep __NR_osf_msleep +#endif + +#ifdef __NR_osf_mvalid +#define SYS_osf_mvalid __NR_osf_mvalid +#endif + +#ifdef __NR_osf_mwakeup +#define SYS_osf_mwakeup __NR_osf_mwakeup +#endif + +#ifdef __NR_osf_naccept +#define SYS_osf_naccept __NR_osf_naccept +#endif + +#ifdef __NR_osf_nfssvc +#define SYS_osf_nfssvc __NR_osf_nfssvc +#endif + +#ifdef __NR_osf_ngetpeername +#define SYS_osf_ngetpeername __NR_osf_ngetpeername +#endif + +#ifdef __NR_osf_ngetsockname +#define SYS_osf_ngetsockname __NR_osf_ngetsockname +#endif + +#ifdef __NR_osf_nrecvfrom +#define SYS_osf_nrecvfrom __NR_osf_nrecvfrom +#endif + +#ifdef __NR_osf_nrecvmsg +#define SYS_osf_nrecvmsg __NR_osf_nrecvmsg +#endif + +#ifdef __NR_osf_nsendmsg +#define SYS_osf_nsendmsg __NR_osf_nsendmsg +#endif + +#ifdef __NR_osf_ntp_adjtime +#define SYS_osf_ntp_adjtime __NR_osf_ntp_adjtime +#endif + +#ifdef __NR_osf_ntp_gettime +#define SYS_osf_ntp_gettime __NR_osf_ntp_gettime +#endif + +#ifdef __NR_osf_old_creat +#define SYS_osf_old_creat __NR_osf_old_creat +#endif + +#ifdef __NR_osf_old_fstat +#define SYS_osf_old_fstat __NR_osf_old_fstat +#endif + +#ifdef __NR_osf_old_getpgrp +#define SYS_osf_old_getpgrp __NR_osf_old_getpgrp +#endif + +#ifdef __NR_osf_old_killpg +#define SYS_osf_old_killpg __NR_osf_old_killpg +#endif + +#ifdef __NR_osf_old_lstat +#define SYS_osf_old_lstat __NR_osf_old_lstat +#endif + +#ifdef __NR_osf_old_open +#define SYS_osf_old_open __NR_osf_old_open +#endif + +#ifdef __NR_osf_old_sigaction +#define SYS_osf_old_sigaction __NR_osf_old_sigaction +#endif + +#ifdef __NR_osf_old_sigblock +#define SYS_osf_old_sigblock __NR_osf_old_sigblock +#endif + +#ifdef __NR_osf_old_sigreturn +#define SYS_osf_old_sigreturn __NR_osf_old_sigreturn +#endif + +#ifdef __NR_osf_old_sigsetmask +#define SYS_osf_old_sigsetmask __NR_osf_old_sigsetmask +#endif + +#ifdef __NR_osf_old_sigvec +#define SYS_osf_old_sigvec __NR_osf_old_sigvec +#endif + +#ifdef __NR_osf_old_stat +#define SYS_osf_old_stat __NR_osf_old_stat +#endif + +#ifdef __NR_osf_old_vadvise +#define SYS_osf_old_vadvise __NR_osf_old_vadvise +#endif + +#ifdef __NR_osf_old_vtrace +#define SYS_osf_old_vtrace __NR_osf_old_vtrace +#endif + +#ifdef __NR_osf_old_wait +#define SYS_osf_old_wait __NR_osf_old_wait +#endif + +#ifdef __NR_osf_oldquota +#define SYS_osf_oldquota __NR_osf_oldquota +#endif + +#ifdef __NR_osf_pathconf +#define SYS_osf_pathconf __NR_osf_pathconf +#endif + +#ifdef __NR_osf_pid_block +#define SYS_osf_pid_block __NR_osf_pid_block +#endif + +#ifdef __NR_osf_pid_unblock +#define SYS_osf_pid_unblock __NR_osf_pid_unblock +#endif + +#ifdef __NR_osf_plock +#define SYS_osf_plock __NR_osf_plock +#endif + +#ifdef __NR_osf_priocntlset +#define SYS_osf_priocntlset __NR_osf_priocntlset +#endif + +#ifdef __NR_osf_profil +#define SYS_osf_profil __NR_osf_profil +#endif + +#ifdef __NR_osf_proplist_syscall +#define SYS_osf_proplist_syscall __NR_osf_proplist_syscall +#endif + +#ifdef __NR_osf_reboot +#define SYS_osf_reboot __NR_osf_reboot +#endif + +#ifdef __NR_osf_revoke +#define SYS_osf_revoke __NR_osf_revoke +#endif + +#ifdef __NR_osf_sbrk +#define SYS_osf_sbrk __NR_osf_sbrk +#endif + +#ifdef __NR_osf_security +#define SYS_osf_security __NR_osf_security +#endif + +#ifdef __NR_osf_select +#define SYS_osf_select __NR_osf_select +#endif + +#ifdef __NR_osf_set_program_attributes +#define SYS_osf_set_program_attributes __NR_osf_set_program_attributes +#endif + +#ifdef __NR_osf_set_speculative +#define SYS_osf_set_speculative __NR_osf_set_speculative +#endif + +#ifdef __NR_osf_sethostid +#define SYS_osf_sethostid __NR_osf_sethostid +#endif + +#ifdef __NR_osf_setitimer +#define SYS_osf_setitimer __NR_osf_setitimer +#endif + +#ifdef __NR_osf_setlogin +#define SYS_osf_setlogin __NR_osf_setlogin +#endif + +#ifdef __NR_osf_setsysinfo +#define SYS_osf_setsysinfo __NR_osf_setsysinfo +#endif + +#ifdef __NR_osf_settimeofday +#define SYS_osf_settimeofday __NR_osf_settimeofday +#endif + +#ifdef __NR_osf_shmat +#define SYS_osf_shmat __NR_osf_shmat +#endif + +#ifdef __NR_osf_signal +#define SYS_osf_signal __NR_osf_signal +#endif + +#ifdef __NR_osf_sigprocmask +#define SYS_osf_sigprocmask __NR_osf_sigprocmask +#endif + +#ifdef __NR_osf_sigsendset +#define SYS_osf_sigsendset __NR_osf_sigsendset +#endif + +#ifdef __NR_osf_sigstack +#define SYS_osf_sigstack __NR_osf_sigstack +#endif + +#ifdef __NR_osf_sigwaitprim +#define SYS_osf_sigwaitprim __NR_osf_sigwaitprim +#endif + +#ifdef __NR_osf_sstk +#define SYS_osf_sstk __NR_osf_sstk +#endif + +#ifdef __NR_osf_stat +#define SYS_osf_stat __NR_osf_stat +#endif + +#ifdef __NR_osf_statfs +#define SYS_osf_statfs __NR_osf_statfs +#endif + +#ifdef __NR_osf_statfs64 +#define SYS_osf_statfs64 __NR_osf_statfs64 +#endif + +#ifdef __NR_osf_subsys_info +#define SYS_osf_subsys_info __NR_osf_subsys_info +#endif + +#ifdef __NR_osf_swapctl +#define SYS_osf_swapctl __NR_osf_swapctl +#endif + +#ifdef __NR_osf_swapon +#define SYS_osf_swapon __NR_osf_swapon +#endif + +#ifdef __NR_osf_syscall +#define SYS_osf_syscall __NR_osf_syscall +#endif + +#ifdef __NR_osf_sysinfo +#define SYS_osf_sysinfo __NR_osf_sysinfo +#endif + +#ifdef __NR_osf_table +#define SYS_osf_table __NR_osf_table +#endif + +#ifdef __NR_osf_uadmin +#define SYS_osf_uadmin __NR_osf_uadmin +#endif + +#ifdef __NR_osf_usleep_thread +#define SYS_osf_usleep_thread __NR_osf_usleep_thread +#endif + +#ifdef __NR_osf_uswitch +#define SYS_osf_uswitch __NR_osf_uswitch +#endif + +#ifdef __NR_osf_utc_adjtime +#define SYS_osf_utc_adjtime __NR_osf_utc_adjtime +#endif + +#ifdef __NR_osf_utc_gettime +#define SYS_osf_utc_gettime __NR_osf_utc_gettime +#endif + +#ifdef __NR_osf_utimes +#define SYS_osf_utimes __NR_osf_utimes +#endif + +#ifdef __NR_osf_utsname +#define SYS_osf_utsname __NR_osf_utsname +#endif + +#ifdef __NR_osf_wait4 +#define SYS_osf_wait4 __NR_osf_wait4 +#endif + +#ifdef __NR_osf_waitid +#define SYS_osf_waitid __NR_osf_waitid +#endif + +#ifdef __NR_pause +#define SYS_pause __NR_pause +#endif + +#ifdef __NR_pciconfig_iobase +#define SYS_pciconfig_iobase __NR_pciconfig_iobase +#endif + +#ifdef __NR_pciconfig_read +#define SYS_pciconfig_read __NR_pciconfig_read +#endif + +#ifdef __NR_pciconfig_write +#define SYS_pciconfig_write __NR_pciconfig_write +#endif + +#ifdef __NR_perf_event_open +#define SYS_perf_event_open __NR_perf_event_open +#endif + +#ifdef __NR_perfctr +#define SYS_perfctr __NR_perfctr +#endif + +#ifdef __NR_perfmonctl +#define SYS_perfmonctl __NR_perfmonctl +#endif + +#ifdef __NR_personality +#define SYS_personality __NR_personality +#endif + +#ifdef __NR_pipe +#define SYS_pipe __NR_pipe +#endif + +#ifdef __NR_pipe2 +#define SYS_pipe2 __NR_pipe2 +#endif + +#ifdef __NR_pivot_root +#define SYS_pivot_root __NR_pivot_root +#endif + +#ifdef __NR_pkey_alloc +#define SYS_pkey_alloc __NR_pkey_alloc +#endif + +#ifdef __NR_pkey_free +#define SYS_pkey_free __NR_pkey_free +#endif + +#ifdef __NR_pkey_mprotect +#define SYS_pkey_mprotect __NR_pkey_mprotect +#endif + +#ifdef __NR_poll +#define SYS_poll __NR_poll +#endif + +#ifdef __NR_ppoll +#define SYS_ppoll __NR_ppoll +#endif + +#ifdef __NR_prctl +#define SYS_prctl __NR_prctl +#endif + +#ifdef __NR_pread64 +#define SYS_pread64 __NR_pread64 +#endif + +#ifdef __NR_preadv +#define SYS_preadv __NR_preadv +#endif + +#ifdef __NR_preadv2 +#define SYS_preadv2 __NR_preadv2 +#endif + +#ifdef __NR_prlimit64 +#define SYS_prlimit64 __NR_prlimit64 +#endif + +#ifdef __NR_process_vm_readv +#define SYS_process_vm_readv __NR_process_vm_readv +#endif + +#ifdef __NR_process_vm_writev +#define SYS_process_vm_writev __NR_process_vm_writev +#endif + +#ifdef __NR_prof +#define SYS_prof __NR_prof +#endif + +#ifdef __NR_profil +#define SYS_profil __NR_profil +#endif + +#ifdef __NR_pselect6 +#define SYS_pselect6 __NR_pselect6 +#endif + +#ifdef __NR_pselect6_time64 +#define SYS_pselect6_time64 __NR_pselect6_time64 +#endif + +#ifdef __NR_ptrace +#define SYS_ptrace __NR_ptrace +#endif + +#ifdef __NR_putpmsg +#define SYS_putpmsg __NR_putpmsg +#endif + +#ifdef __NR_pwrite64 +#define SYS_pwrite64 __NR_pwrite64 +#endif + +#ifdef __NR_pwritev +#define SYS_pwritev __NR_pwritev +#endif + +#ifdef __NR_pwritev2 +#define SYS_pwritev2 __NR_pwritev2 +#endif + +#ifdef __NR_query_module +#define SYS_query_module __NR_query_module +#endif + +#ifdef __NR_quotactl +#define SYS_quotactl __NR_quotactl +#endif + +#ifdef __NR_read +#define SYS_read __NR_read +#endif + +#ifdef __NR_readahead +#define SYS_readahead __NR_readahead +#endif + +#ifdef __NR_readdir +#define SYS_readdir __NR_readdir +#endif + +#ifdef __NR_readlink +#define SYS_readlink __NR_readlink +#endif + +#ifdef __NR_readlinkat +#define SYS_readlinkat __NR_readlinkat +#endif + +#ifdef __NR_readv +#define SYS_readv __NR_readv +#endif + +#ifdef __NR_reboot +#define SYS_reboot __NR_reboot +#endif + +#ifdef __NR_recv +#define SYS_recv __NR_recv +#endif + +#ifdef __NR_recvfrom +#define SYS_recvfrom __NR_recvfrom +#endif + +#ifdef __NR_recvmmsg +#define SYS_recvmmsg __NR_recvmmsg +#endif + +#ifdef __NR_recvmsg +#define SYS_recvmsg __NR_recvmsg +#endif + +#ifdef __NR_remap_file_pages +#define SYS_remap_file_pages __NR_remap_file_pages +#endif + +#ifdef __NR_removexattr +#define SYS_removexattr __NR_removexattr +#endif + +#ifdef __NR_rename +#define SYS_rename __NR_rename +#endif + +#ifdef __NR_renameat +#define SYS_renameat __NR_renameat +#endif + +#ifdef __NR_renameat2 +#define SYS_renameat2 __NR_renameat2 +#endif + +#ifdef __NR_request_key +#define SYS_request_key __NR_request_key +#endif + +#ifdef __NR_restart_syscall +#define SYS_restart_syscall __NR_restart_syscall +#endif + +#ifdef __NR_rmdir +#define SYS_rmdir __NR_rmdir +#endif + +#ifdef __NR_rseq +#define SYS_rseq __NR_rseq +#endif + +#ifdef __NR_rt_sigaction +#define SYS_rt_sigaction __NR_rt_sigaction +#endif + +#ifdef __NR_rt_sigpending +#define SYS_rt_sigpending __NR_rt_sigpending +#endif + +#ifdef __NR_rt_sigprocmask +#define SYS_rt_sigprocmask __NR_rt_sigprocmask +#endif + +#ifdef __NR_rt_sigqueueinfo +#define SYS_rt_sigqueueinfo __NR_rt_sigqueueinfo +#endif + +#ifdef __NR_rt_sigreturn +#define SYS_rt_sigreturn __NR_rt_sigreturn +#endif + +#ifdef __NR_rt_sigsuspend +#define SYS_rt_sigsuspend __NR_rt_sigsuspend +#endif + +#ifdef __NR_rt_sigtimedwait +#define SYS_rt_sigtimedwait __NR_rt_sigtimedwait +#endif + +#ifdef __NR_rt_tgsigqueueinfo +#define SYS_rt_tgsigqueueinfo __NR_rt_tgsigqueueinfo +#endif + +#ifdef __NR_rtas +#define SYS_rtas __NR_rtas +#endif + +#ifdef __NR_s390_guarded_storage +#define SYS_s390_guarded_storage __NR_s390_guarded_storage +#endif + +#ifdef __NR_s390_pci_mmio_read +#define SYS_s390_pci_mmio_read __NR_s390_pci_mmio_read +#endif + +#ifdef __NR_s390_pci_mmio_write +#define SYS_s390_pci_mmio_write __NR_s390_pci_mmio_write +#endif + +#ifdef __NR_s390_runtime_instr +#define SYS_s390_runtime_instr __NR_s390_runtime_instr +#endif + +#ifdef __NR_s390_sthyi +#define SYS_s390_sthyi __NR_s390_sthyi +#endif + +#ifdef __NR_sched_get_affinity +#define SYS_sched_get_affinity __NR_sched_get_affinity +#endif + +#ifdef __NR_sched_get_priority_max +#define SYS_sched_get_priority_max __NR_sched_get_priority_max +#endif + +#ifdef __NR_sched_get_priority_min +#define SYS_sched_get_priority_min __NR_sched_get_priority_min +#endif + +#ifdef __NR_sched_getaffinity +#define SYS_sched_getaffinity __NR_sched_getaffinity +#endif + +#ifdef __NR_sched_getattr +#define SYS_sched_getattr __NR_sched_getattr +#endif + +#ifdef __NR_sched_getparam +#define SYS_sched_getparam __NR_sched_getparam +#endif + +#ifdef __NR_sched_getscheduler +#define SYS_sched_getscheduler __NR_sched_getscheduler +#endif + +#ifdef __NR_sched_rr_get_interval +#define SYS_sched_rr_get_interval __NR_sched_rr_get_interval +#endif + +#ifdef __NR_sched_rr_get_interval_time64 +#define SYS_sched_rr_get_interval_time64 __NR_sched_rr_get_interval_time64 +#endif + +#ifdef __NR_sched_set_affinity +#define SYS_sched_set_affinity __NR_sched_set_affinity +#endif + +#ifdef __NR_sched_setaffinity +#define SYS_sched_setaffinity __NR_sched_setaffinity +#endif + +#ifdef __NR_sched_setattr +#define SYS_sched_setattr __NR_sched_setattr +#endif + +#ifdef __NR_sched_setparam +#define SYS_sched_setparam __NR_sched_setparam +#endif + +#ifdef __NR_sched_setscheduler +#define SYS_sched_setscheduler __NR_sched_setscheduler +#endif + +#ifdef __NR_sched_yield +#define SYS_sched_yield __NR_sched_yield +#endif + +#ifdef __NR_seccomp +#define SYS_seccomp __NR_seccomp +#endif + +#ifdef __NR_security +#define SYS_security __NR_security +#endif + +#ifdef __NR_select +#define SYS_select __NR_select +#endif + +#ifdef __NR_semctl +#define SYS_semctl __NR_semctl +#endif + +#ifdef __NR_semget +#define SYS_semget __NR_semget +#endif + +#ifdef __NR_semop +#define SYS_semop __NR_semop +#endif + +#ifdef __NR_semtimedop +#define SYS_semtimedop __NR_semtimedop +#endif + +#ifdef __NR_send +#define SYS_send __NR_send +#endif + +#ifdef __NR_sendfile +#define SYS_sendfile __NR_sendfile +#endif + +#ifdef __NR_sendfile64 +#define SYS_sendfile64 __NR_sendfile64 +#endif + +#ifdef __NR_sendmmsg +#define SYS_sendmmsg __NR_sendmmsg +#endif + +#ifdef __NR_sendmsg +#define SYS_sendmsg __NR_sendmsg +#endif + +#ifdef __NR_sendto +#define SYS_sendto __NR_sendto +#endif + +#ifdef __NR_set_mempolicy +#define SYS_set_mempolicy __NR_set_mempolicy +#endif + +#ifdef __NR_set_robust_list +#define SYS_set_robust_list __NR_set_robust_list +#endif + +#ifdef __NR_set_thread_area +#define SYS_set_thread_area __NR_set_thread_area +#endif + +#ifdef __NR_set_tid_address +#define SYS_set_tid_address __NR_set_tid_address +#endif + +#ifdef __NR_setdomainname +#define SYS_setdomainname __NR_setdomainname +#endif + +#ifdef __NR_setfsgid +#define SYS_setfsgid __NR_setfsgid +#endif + +#ifdef __NR_setfsgid32 +#define SYS_setfsgid32 __NR_setfsgid32 +#endif + +#ifdef __NR_setfsuid +#define SYS_setfsuid __NR_setfsuid +#endif + +#ifdef __NR_setfsuid32 +#define SYS_setfsuid32 __NR_setfsuid32 +#endif + +#ifdef __NR_setgid +#define SYS_setgid __NR_setgid +#endif + +#ifdef __NR_setgid32 +#define SYS_setgid32 __NR_setgid32 +#endif + +#ifdef __NR_setgroups +#define SYS_setgroups __NR_setgroups +#endif + +#ifdef __NR_setgroups32 +#define SYS_setgroups32 __NR_setgroups32 +#endif + +#ifdef __NR_sethae +#define SYS_sethae __NR_sethae +#endif + +#ifdef __NR_sethostname +#define SYS_sethostname __NR_sethostname +#endif + +#ifdef __NR_setitimer +#define SYS_setitimer __NR_setitimer +#endif + +#ifdef __NR_setns +#define SYS_setns __NR_setns +#endif + +#ifdef __NR_setpgid +#define SYS_setpgid __NR_setpgid +#endif + +#ifdef __NR_setpgrp +#define SYS_setpgrp __NR_setpgrp +#endif + +#ifdef __NR_setpriority +#define SYS_setpriority __NR_setpriority +#endif + +#ifdef __NR_setregid +#define SYS_setregid __NR_setregid +#endif + +#ifdef __NR_setregid32 +#define SYS_setregid32 __NR_setregid32 +#endif + +#ifdef __NR_setresgid +#define SYS_setresgid __NR_setresgid +#endif + +#ifdef __NR_setresgid32 +#define SYS_setresgid32 __NR_setresgid32 +#endif + +#ifdef __NR_setresuid +#define SYS_setresuid __NR_setresuid +#endif + +#ifdef __NR_setresuid32 +#define SYS_setresuid32 __NR_setresuid32 +#endif + +#ifdef __NR_setreuid +#define SYS_setreuid __NR_setreuid +#endif + +#ifdef __NR_setreuid32 +#define SYS_setreuid32 __NR_setreuid32 +#endif + +#ifdef __NR_setrlimit +#define SYS_setrlimit __NR_setrlimit +#endif + +#ifdef __NR_setsid +#define SYS_setsid __NR_setsid +#endif + +#ifdef __NR_setsockopt +#define SYS_setsockopt __NR_setsockopt +#endif + +#ifdef __NR_settimeofday +#define SYS_settimeofday __NR_settimeofday +#endif + +#ifdef __NR_setuid +#define SYS_setuid __NR_setuid +#endif + +#ifdef __NR_setuid32 +#define SYS_setuid32 __NR_setuid32 +#endif + +#ifdef __NR_setxattr +#define SYS_setxattr __NR_setxattr +#endif + +#ifdef __NR_sgetmask +#define SYS_sgetmask __NR_sgetmask +#endif + +#ifdef __NR_shmat +#define SYS_shmat __NR_shmat +#endif + +#ifdef __NR_shmctl +#define SYS_shmctl __NR_shmctl +#endif + +#ifdef __NR_shmdt +#define SYS_shmdt __NR_shmdt +#endif + +#ifdef __NR_shmget +#define SYS_shmget __NR_shmget +#endif + +#ifdef __NR_shutdown +#define SYS_shutdown __NR_shutdown +#endif + +#ifdef __NR_sigaction +#define SYS_sigaction __NR_sigaction +#endif + +#ifdef __NR_sigaltstack +#define SYS_sigaltstack __NR_sigaltstack +#endif + +#ifdef __NR_signal +#define SYS_signal __NR_signal +#endif + +#ifdef __NR_signalfd +#define SYS_signalfd __NR_signalfd +#endif + +#ifdef __NR_signalfd4 +#define SYS_signalfd4 __NR_signalfd4 +#endif + +#ifdef __NR_sigpending +#define SYS_sigpending __NR_sigpending +#endif + +#ifdef __NR_sigprocmask +#define SYS_sigprocmask __NR_sigprocmask +#endif + +#ifdef __NR_sigreturn +#define SYS_sigreturn __NR_sigreturn +#endif + +#ifdef __NR_sigsuspend +#define SYS_sigsuspend __NR_sigsuspend +#endif + +#ifdef __NR_socket +#define SYS_socket __NR_socket +#endif + +#ifdef __NR_socketcall +#define SYS_socketcall __NR_socketcall +#endif + +#ifdef __NR_socketpair +#define SYS_socketpair __NR_socketpair +#endif + +#ifdef __NR_splice +#define SYS_splice __NR_splice +#endif + +#ifdef __NR_spu_create +#define SYS_spu_create __NR_spu_create +#endif + +#ifdef __NR_spu_run +#define SYS_spu_run __NR_spu_run +#endif + +#ifdef __NR_ssetmask +#define SYS_ssetmask __NR_ssetmask +#endif + +#ifdef __NR_stat +#define SYS_stat __NR_stat +#endif + +#ifdef __NR_stat64 +#define SYS_stat64 __NR_stat64 +#endif + +#ifdef __NR_statfs +#define SYS_statfs __NR_statfs +#endif + +#ifdef __NR_statfs64 +#define SYS_statfs64 __NR_statfs64 +#endif + +#ifdef __NR_statx +#define SYS_statx __NR_statx +#endif + +#ifdef __NR_stime +#define SYS_stime __NR_stime +#endif + +#ifdef __NR_stty +#define SYS_stty __NR_stty +#endif + +#ifdef __NR_subpage_prot +#define SYS_subpage_prot __NR_subpage_prot +#endif + +#ifdef __NR_swapcontext +#define SYS_swapcontext __NR_swapcontext +#endif + +#ifdef __NR_swapoff +#define SYS_swapoff __NR_swapoff +#endif + +#ifdef __NR_swapon +#define SYS_swapon __NR_swapon +#endif + +#ifdef __NR_switch_endian +#define SYS_switch_endian __NR_switch_endian +#endif + +#ifdef __NR_symlink +#define SYS_symlink __NR_symlink +#endif + +#ifdef __NR_symlinkat +#define SYS_symlinkat __NR_symlinkat +#endif + +#ifdef __NR_sync +#define SYS_sync __NR_sync +#endif + +#ifdef __NR_sync_file_range +#define SYS_sync_file_range __NR_sync_file_range +#endif + +#ifdef __NR_sync_file_range2 +#define SYS_sync_file_range2 __NR_sync_file_range2 +#endif + +#ifdef __NR_syncfs +#define SYS_syncfs __NR_syncfs +#endif + +#ifdef __NR_sys_debug_setcontext +#define SYS_sys_debug_setcontext __NR_sys_debug_setcontext +#endif + +#ifdef __NR_sys_epoll_create +#define SYS_sys_epoll_create __NR_sys_epoll_create +#endif + +#ifdef __NR_sys_epoll_ctl +#define SYS_sys_epoll_ctl __NR_sys_epoll_ctl +#endif + +#ifdef __NR_sys_epoll_wait +#define SYS_sys_epoll_wait __NR_sys_epoll_wait +#endif + +#ifdef __NR_syscall +#define SYS_syscall __NR_syscall +#endif + +#ifdef __NR_sysfs +#define SYS_sysfs __NR_sysfs +#endif + +#ifdef __NR_sysinfo +#define SYS_sysinfo __NR_sysinfo +#endif + +#ifdef __NR_syslog +#define SYS_syslog __NR_syslog +#endif + +#ifdef __NR_sysmips +#define SYS_sysmips __NR_sysmips +#endif + +#ifdef __NR_tee +#define SYS_tee __NR_tee +#endif + +#ifdef __NR_tgkill +#define SYS_tgkill __NR_tgkill +#endif + +#ifdef __NR_time +#define SYS_time __NR_time +#endif + +#ifdef __NR_timer_create +#define SYS_timer_create __NR_timer_create +#endif + +#ifdef __NR_timer_delete +#define SYS_timer_delete __NR_timer_delete +#endif + +#ifdef __NR_timer_getoverrun +#define SYS_timer_getoverrun __NR_timer_getoverrun +#endif + +#ifdef __NR_timer_gettime +#define SYS_timer_gettime __NR_timer_gettime +#endif + +#ifdef __NR_timer_settime +#define SYS_timer_settime __NR_timer_settime +#endif + +#ifdef __NR_timerfd +#define SYS_timerfd __NR_timerfd +#endif + +#ifdef __NR_timerfd_create +#define SYS_timerfd_create __NR_timerfd_create +#endif + +#ifdef __NR_timerfd_gettime +#define SYS_timerfd_gettime __NR_timerfd_gettime +#endif + +#ifdef __NR_timerfd_settime +#define SYS_timerfd_settime __NR_timerfd_settime +#endif + +#ifdef __NR_times +#define SYS_times __NR_times +#endif + +#ifdef __NR_tkill +#define SYS_tkill __NR_tkill +#endif + +#ifdef __NR_truncate +#define SYS_truncate __NR_truncate +#endif + +#ifdef __NR_truncate64 +#define SYS_truncate64 __NR_truncate64 +#endif + +#ifdef __NR_tuxcall +#define SYS_tuxcall __NR_tuxcall +#endif + +#ifdef __NR_ugetrlimit +#define SYS_ugetrlimit __NR_ugetrlimit +#endif + +#ifdef __NR_ulimit +#define SYS_ulimit __NR_ulimit +#endif + +#ifdef __NR_umask +#define SYS_umask __NR_umask +#endif + +#ifdef __NR_umount +#define SYS_umount __NR_umount +#endif + +#ifdef __NR_umount2 +#define SYS_umount2 __NR_umount2 +#endif + +#ifdef __NR_uname +#define SYS_uname __NR_uname +#endif + +#ifdef __NR_unlink +#define SYS_unlink __NR_unlink +#endif + +#ifdef __NR_unlinkat +#define SYS_unlinkat __NR_unlinkat +#endif + +#ifdef __NR_unshare +#define SYS_unshare __NR_unshare +#endif + +#ifdef __NR_uselib +#define SYS_uselib __NR_uselib +#endif + +#ifdef __NR_userfaultfd +#define SYS_userfaultfd __NR_userfaultfd +#endif + +#ifdef __NR_ustat +#define SYS_ustat __NR_ustat +#endif + +#ifdef __NR_utime +#define SYS_utime __NR_utime +#endif + +#ifdef __NR_utimensat +#define SYS_utimensat __NR_utimensat +#endif + +#ifdef __NR_utimes +#define SYS_utimes __NR_utimes +#endif + +#ifdef __NR_utrap_install +#define SYS_utrap_install __NR_utrap_install +#endif + +#ifdef __NR_vfork +#define SYS_vfork __NR_vfork +#endif + +#ifdef __NR_vhangup +#define SYS_vhangup __NR_vhangup +#endif + +#ifdef __NR_vm86 +#define SYS_vm86 __NR_vm86 +#endif + +#ifdef __NR_vm86old +#define SYS_vm86old __NR_vm86old +#endif + +#ifdef __NR_vmsplice +#define SYS_vmsplice __NR_vmsplice +#endif + +#ifdef __NR_vserver +#define SYS_vserver __NR_vserver +#endif + +#ifdef __NR_wait4 +#define SYS_wait4 __NR_wait4 +#endif + +#ifdef __NR_waitid +#define SYS_waitid __NR_waitid +#endif + +#ifdef __NR_waitpid +#define SYS_waitpid __NR_waitpid +#endif + +#ifdef __NR_write +#define SYS_write __NR_write +#endif + +#ifdef __NR_writev +#define SYS_writev __NR_writev +#endif + #endif // LLVM_LIBC_SYS_SYSCALL_H diff --git a/libc/newhdrgen/class_implementation/classes/enumeration.py b/libc/newhdrgen/class_implementation/classes/enumeration.py new file mode 100644 index 00000000000000..be03dbf603c2ba --- /dev/null +++ b/libc/newhdrgen/class_implementation/classes/enumeration.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +# +# ====-- Enumeration class for libc function headers ----------*- python -*--==# +# +# 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 +# +# ==-------------------------------------------------------------------------==# + + +class Enumeration: + def __init__(self, name, value=None): + self.name = name + self.value = value + + def __str__(self): + if self.value != None: + return f"{self.name} = {self.value}" + else: + return f"{self.name}" diff --git a/libc/newhdrgen/class_implementation/classes/function.py b/libc/newhdrgen/class_implementation/classes/function.py new file mode 100644 index 00000000000000..3c464e48b6e3bb --- /dev/null +++ b/libc/newhdrgen/class_implementation/classes/function.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +# +# ====-- Function class for libc function headers -------------*- python -*--==# +# +# 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 +# +# ==-------------------------------------------------------------------------==# + + +class Function: + def __init__( + self, standards, return_type, name, arguments, guard=None, attributes=[] + ): + self.standards = standards + self.return_type = return_type + self.name = name + self.arguments = [ + arg if isinstance(arg, str) else arg["type"] for arg in arguments + ] + self.guard = guard + self.attributes = attributes or [] + + def __str__(self): + attributes_str = " ".join(self.attributes) + arguments_str = ", ".join(self.arguments) + result = f"{self.return_type} {self.name}({arguments_str}){attributes_str};" + if self.guard: + result = f"#ifdef {self.guard}\n{result}\n#endif // {self.guard}" + return result diff --git a/libc/newhdrgen/class_implementation/classes/include.py b/libc/newhdrgen/class_implementation/classes/include.py new file mode 100644 index 00000000000000..2657f2e7c931cb --- /dev/null +++ b/libc/newhdrgen/class_implementation/classes/include.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +# +# ====-- Include class for libc function headers --------------*- python -*--==# +# +# 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 +# +# ==-------------------------------------------------------------------------==# + + +class Include: + def __init__(self, name): + self.name = name + + def __str__(self): + return f'#include "{self.name}"' diff --git a/libc/newhdrgen/class_implementation/classes/macro.py b/libc/newhdrgen/class_implementation/classes/macro.py new file mode 100644 index 00000000000000..bf17ae6b6c5ab8 --- /dev/null +++ b/libc/newhdrgen/class_implementation/classes/macro.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +# +# ====-- Macro class for libc function headers ----------------*- python -*--==# +# +# 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 +# +# ==-------------------------------------------------------------------------==# + + +class Macro: + def __init__(self, name, value=None): + self.name = name + self.value = value + + def __str__(self): + if self.value != None: + return f"#define {self.name} {self.value}" + else: + return f"#define {self.name}" diff --git a/libc/newhdrgen/class_implementation/classes/object.py b/libc/newhdrgen/class_implementation/classes/object.py new file mode 100644 index 00000000000000..c65a82e1a660d1 --- /dev/null +++ b/libc/newhdrgen/class_implementation/classes/object.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python +# +# ====-- Object class for libc function headers ---------------*- python -*--==# +# +# 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 +# +# ==-------------------------------------------------------------------------==# + + +class Object: + def __init__(self, name, type): + self.name = name + self.type = type + + def __str__(self): + return f"extern {self.type} {self.name}" diff --git a/libc/newhdrgen/class_implementation/classes/type.py b/libc/newhdrgen/class_implementation/classes/type.py new file mode 100644 index 00000000000000..8e4a8f3cc9c58f --- /dev/null +++ b/libc/newhdrgen/class_implementation/classes/type.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +# +# ====-- Type class for libc function headers -----------------*- python -*--==# +# +# 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 +# +# ==-------------------------------------------------------------------------==# + + +class Type: + def __init__(self, type_name): + self.type_name = type_name + + def __str__(self): + return f"#include " diff --git a/libc/newhdrgen/header.py b/libc/newhdrgen/header.py new file mode 100644 index 00000000000000..7ce356831677eb --- /dev/null +++ b/libc/newhdrgen/header.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python +# +# ====- HeaderFile Class for libc function headers -----------*- python -*--==# +# +# 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 +# +# ==-------------------------------------------------------------------------==# + + +class HeaderFile: + def __init__(self, name): + self.name = name + self.macros = [] + self.types = [] + self.enumerations = [] + self.objects = [] + self.functions = [] + self.includes = [] + + def add_macro(self, macro): + self.macros.append(macro) + + def add_type(self, type_): + self.types.append(type_) + + def add_enumeration(self, enumeration): + self.enumerations.append(enumeration) + + def add_object(self, object): + self.objects.append(object) + + def add_function(self, function): + self.functions.append(function) + + def add_include(self, include): + self.includes.append(include) + + def __str__(self): + content = [""] + + for include in self.includes: + content.append(str(include)) + + for macro in self.macros: + content.append(str(macro)) + + for object in self.objects: + content.append(str(object)) + + for type_ in self.types: + content.append(str(type_)) + + if self.enumerations: + content.append("enum {") + for enum in self.enumerations: + content.append(f"\t{str(enum)},") + content.append("};") + + # TODO: replace line below with common.h functionality + content.append("__BEGIN_C_DECLS\n") + for function in self.functions: + content.append(str(function)) + content.append("") + content.append("__END_C_DECLS\n") + return "\n".join(content) diff --git a/libc/newhdrgen/yaml/arpa_inet.yaml b/libc/newhdrgen/yaml/arpa_inet.yaml new file mode 100644 index 00000000000000..945a602705dba4 --- /dev/null +++ b/libc/newhdrgen/yaml/arpa_inet.yaml @@ -0,0 +1,33 @@ +header: arpa-inet.h +macros: [] +types: + - type_name: uint32_t + - type_name: uint16_t + - type_name: inttypes.h +enums: [] +objects: [] +functions: + - name: htonl + standards: + - POSIX + return_type: uint32_t + arguments: + - type: uint32_t + - name: htons + standards: + - POSIX + return_type: uint16_t + arguments: + - type: uint16_t + - name: ntohl + standards: + - POSIX + return_type: uint32_t + arguments: + - type: uint32_t + - name: ntohs + standards: + - POSIX + return_type: uint16_t + arguments: + - type: uint16_t diff --git a/libc/newhdrgen/yaml/dirent.yaml b/libc/newhdrgen/yaml/dirent.yaml new file mode 100644 index 00000000000000..84a539a966345c --- /dev/null +++ b/libc/newhdrgen/yaml/dirent.yaml @@ -0,0 +1,46 @@ +header: dirent.h +macros: [] +types: + - type_name: struct_dirent + - type_name: DIR + - type_name: ino_t +enums: [] +objects: [] +functions: + - name: alphasort + standards: + - POSIX + return_type: int + arguments: + - type: const struct dirent ** + - type: const struct dirent ** + - name: closedir + standards: + - POSIX + return_type: int + arguments: + - type: DIR * + - name: dirfd + standards: + - POSIX + return_type: int + arguments: + - type: DIR * + - name: fdopendir + standards: + - POSIX + return_type: DIR * + arguments: + - type: int + - name: opendir + standards: + - POSIX + return_type: DIR * + arguments: + - type: const char * + - name: readdir + standards: + - POSIX + return_type: struct dirent * + arguments: + - type: DIR * diff --git a/libc/newhdrgen/yaml/errno.yaml b/libc/newhdrgen/yaml/errno.yaml new file mode 100644 index 00000000000000..5d8de90f035bd3 --- /dev/null +++ b/libc/newhdrgen/yaml/errno.yaml @@ -0,0 +1,10 @@ +header: errno.h +standards: + - stdc + - Linux + - POSIX +macros: [] +types: [] +enums: [] +objects: [] +functions: [] diff --git a/libc/newhdrgen/yaml/fcntl.yaml b/libc/newhdrgen/yaml/fcntl.yaml new file mode 100644 index 00000000000000..3cb9741256a3d2 --- /dev/null +++ b/libc/newhdrgen/yaml/fcntl.yaml @@ -0,0 +1,40 @@ +header: fcntl.h +macros: [] +types: + - type_name: off_t + - type_name: mode_t +enums: [] +objects: [] +functions: + - name: creat + standards: + - POSIX + return_type: int + arguments: + - type: const char * + - type: mode_t + - name: fcntl + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: int + - type: ... + - name: open + standards: + - POSIX + return_type: int + arguments: + - type: const char * + - type: int + - type: ... + - name: openat + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: const char * + - type: int + - type: ... diff --git a/libc/newhdrgen/yaml/float.yaml b/libc/newhdrgen/yaml/float.yaml new file mode 100644 index 00000000000000..fcbede018113cd --- /dev/null +++ b/libc/newhdrgen/yaml/float.yaml @@ -0,0 +1,8 @@ +header: float.h +standards: + - stdc +macros: [] +types: [] +enums: [] +objects: [] +functions: [] diff --git a/libc/newhdrgen/yaml/inttypes.yaml b/libc/newhdrgen/yaml/inttypes.yaml new file mode 100644 index 00000000000000..772a1a0e06b214 --- /dev/null +++ b/libc/newhdrgen/yaml/inttypes.yaml @@ -0,0 +1,36 @@ +header: inttypes.h +macros: +types: + - type_name: imaxdiv_t +enums: [] +objects: [] +functions: + - name: imaxabs + standards: + - stdc + return_type: intmax_t + arguments: + - type: intmax_t + - name: imaxdiv + standards: + - stdc + return_type: imaxdiv_t + arguments: + - type: intmax_t + - type: intmax_t + - name: strtoimax + standards: + - stdc + return_type: intmax_t + arguments: + - type: const char *__restrict + - type: char * *__restrict + - type: int + - name: strtoumax + standards: + - stdc + return_type: uintmax_t + arguments: + - type: const char *__restrict + - type: char * *__restrict + - type: int diff --git a/libc/newhdrgen/yaml/limits.yaml b/libc/newhdrgen/yaml/limits.yaml new file mode 100644 index 00000000000000..9d0f14fa3095d1 --- /dev/null +++ b/libc/newhdrgen/yaml/limits.yaml @@ -0,0 +1,8 @@ +header: limits.h +standards: + - stdc +macros: [] +types: [] +enums: [] +objects: [] +functions: [] diff --git a/libc/newhdrgen/yaml/rpc.yaml b/libc/newhdrgen/yaml/rpc.yaml new file mode 100644 index 00000000000000..8a096db8784ec1 --- /dev/null +++ b/libc/newhdrgen/yaml/rpc.yaml @@ -0,0 +1,23 @@ +header: gpu-rpc.h +macros: [] +types: [] +enums: [] +objects: [] +functions: + - name: rpc_host_call + standards: + - GPUExtensions + return_type: void + arguments: + - type: void * + - type: void * + - type: size_t + - name: rpc_fprintf + standards: + - GPUExtensions + return_type: int + arguments: + - type: ::FILE *__restrict + - type: const char *__restrict + - type: void * + - type: size_t diff --git a/libc/newhdrgen/yaml/search.yaml b/libc/newhdrgen/yaml/search.yaml new file mode 100644 index 00000000000000..a7983a70bda730 --- /dev/null +++ b/libc/newhdrgen/yaml/search.yaml @@ -0,0 +1,60 @@ +header: search.h +macros: [] +types: + - type_name: size_t + - type_name: struct_hsearch_data + - type_name: ENTRY + - type_name: ACTION +enums: [] +objects: [] +functions: + - name: hcreate + standards: + - POSIX + return_type: int + arguments: + - type: size_t + - name: hcreate_r + standards: GNUExtensions + return_type: int + arguments: + - type: size_t + - type: struct hsearch_data * + - name: hsearch + standards: + - POSIX + return_type: ENTRY * + arguments: + - type: ENTRY + - type: ACTION + - name: hsearch_r + standards: GNUExtensions + return_type: int + arguments: + - type: ENTRY + - type: ACTION + - type: ENTRY * * + - type: struct hsearch_data * + - name: hdestroy + standards: GNUExtensions + return_type: void + arguments: [] + - name: hdestroy_r + standards: + - POSIX + return_type: void + arguments: + - type: struct hsearch_data * + - name: insque + standards: + - POSIX + return_type: void + arguments: + - type: void * + - type: void * + - name: remque + standards: + - POSIX + return_type: void + arguments: + - type: void * diff --git a/libc/newhdrgen/yaml/setjmp.yaml b/libc/newhdrgen/yaml/setjmp.yaml new file mode 100644 index 00000000000000..c750b46fc20881 --- /dev/null +++ b/libc/newhdrgen/yaml/setjmp.yaml @@ -0,0 +1,20 @@ +header: setjmp.h +macros: [] +types: + - type_name: jmp_buf +enums: [] +objects: [] +functions: + - name: longjmp + standards: + - stdc + return_type: _Noreturn void + arguments: + - type: jmp_buf + - type: int + - name: setjmp + standards: + - stdc + return_type: int + arguments: + - type: jmp_buf diff --git a/libc/newhdrgen/yaml/spawn.yaml b/libc/newhdrgen/yaml/spawn.yaml new file mode 100644 index 00000000000000..86a2e624d4ef48 --- /dev/null +++ b/libc/newhdrgen/yaml/spawn.yaml @@ -0,0 +1,58 @@ +header: spawn.h +macros: [] +types: + - type_name: posix_spawn_file_actions_t + - type_name: posix_spawnattr_t + - type_name: pid_t + - type_name: mode_t +enums: [] +objects: [] +functions: + - name: posix_spawn + standards: + - POSIX + return_type: int + arguments: + - type: pid_t *__restrict + - type: const char *__restrict + - type: posix_spawn_file_actions_t * + - type: posix_spawnattr_t *__restrict + - type: const char *__restrict * + - type: const char *__restrict * + - name: posix_spawn_file_actions_addclose + standards: + - POSIX + return_type: int + arguments: + - type: posix_spawn_file_actions_t * + - type: int + - name: posix_spawn_file_actions_adddup2 + standards: + - POSIX + return_type: int + arguments: + - type: posix_spawn_file_actions_t * + - type: int + - type: int + - name: posix_spawn_file_actions_addopen + standards: + - POSIX + return_type: int + arguments: + - type: posix_spawn_file_actions_t *__restrict + - type: int + - type: const char *__restrict + - type: int + - type: mode_t + - name: posix_spawn_file_actions_destroy + standards: + - POSIX + return_type: int + arguments: + - type: posix_spawn_file_actions_t * + - name: posix_spawn_file_actions_init + standards: + - POSIX + return_type: int + arguments: + - type: posix_spawn_file_actions_t * diff --git a/libc/newhdrgen/yaml/stdbit.yaml b/libc/newhdrgen/yaml/stdbit.yaml new file mode 100644 index 00000000000000..7e1368df9de511 --- /dev/null +++ b/libc/newhdrgen/yaml/stdbit.yaml @@ -0,0 +1,396 @@ +header: stdbit.h +macros: [] +types: [] +enums: [] +objects: [] +functions: + - name: stdc_leading_zeros_uc + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned char + - name: stdc_leading_zeros_us + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned short + - name: stdc_leading_zeros_ui + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned int + - name: stdc_leading_zeros_ul + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned long + - name: stdc_leading_zeros_ull + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned long long + - name: stdc_leading_ones_uc + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned char + - name: stdc_leading_ones_us + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned short + - name: stdc_leading_ones_ui + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned int + - name: stdc_leading_ones_ul + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned long + - name: stdc_leading_ones_ull + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned long long + - name: stdc_trailing_zeros_uc + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned char + - name: stdc_trailing_zeros_us + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned short + - name: stdc_trailing_zeros_ui + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned int + - name: stdc_trailing_zeros_ul + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned long + - name: stdc_trailing_zeros_ull + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned long long + - name: stdc_trailing_ones_uc + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned char + - name: stdc_trailing_ones_us + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned short + - name: stdc_trailing_ones_ui + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned int + - name: stdc_trailing_ones_ul + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned long + - name: stdc_trailing_ones_ull + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned long long + - name: stdc_first_leading_zero_uc + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned char + - name: stdc_first_leading_zero_us + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned short + - name: stdc_first_leading_zero_ui + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned int + - name: stdc_first_leading_zero_ul + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned long + - name: stdc_first_leading_zero_ull + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned long long + - name: stdc_first_leading_one_uc + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned char + - name: stdc_first_leading_one_us + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned short + - name: stdc_first_leading_one_ui + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned int + - name: stdc_first_leading_one_ul + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned long + - name: stdc_first_leading_one_ull + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned long long + - name: stdc_first_trailing_one_uc + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned char + - name: stdc_first_trailing_one_us + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned short + - name: stdc_first_trailing_one_ui + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned int + - name: stdc_first_trailing_one_ul + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned long + - name: stdc_first_trailing_one_ull + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned long long + - name: stdc_count_zeros_uc + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned char + - name: stdc_count_zeros_us + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned short + - name: stdc_count_zeros_ui + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned int + - name: stdc_count_zeros_ul + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned long + - name: stdc_count_zeros_ull + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned long long + - name: stdc_count_ones_uc + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned char + - name: stdc_count_ones_us + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned short + - name: stdc_count_ones_ui + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned int + - name: stdc_count_ones_ul + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned long + - name: stdc_count_ones_ull + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned long long + - name: stdc_has_single_bit_uc + standards: + - stdc + return_type: bool + arguments: + - type: unsigned char + - name: stdc_has_single_bit_us + standards: + - stdc + return_type: bool + arguments: + - type: unsigned short + - name: stdc_has_single_bit_ui + standards: + - stdc + return_type: bool + arguments: + - type: unsigned int + - name: stdc_has_single_bit_ul + standards: + - stdc + return_type: bool + arguments: + - type: unsigned long + - name: stdc_has_single_bit_ull + standards: + - stdc + return_type: bool + arguments: + - type: unsigned long long + - name: stdc_bit_width_uc + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned char + - name: stdc_bit_width_us + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned short + - name: stdc_bit_width_ui + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned int + - name: stdc_bit_width_ul + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned long + - name: stdc_bit_width_ull + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned long long + - name: stdc_bit_floor_uc + standards: + - stdc + return_type: unsigned char + arguments: + - type: unsigned char + - name: stdc_bit_floor_us + standards: + - stdc + return_type: unsigned short + arguments: + - type: unsigned short + - name: stdc_bit_floor_ui + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned int + - name: stdc_bit_floor_ul + standards: + - stdc + return_type: unsigned long + arguments: + - type: unsigned long + - name: stdc_bit_floor_ull + standards: + - stdc + return_type: unsigned long long + arguments: + - type: unsigned long long + - name: stdc_bit_ceil_uc + standards: + - stdc + return_type: unsigned char + arguments: + - type: unsigned char + - name: stdc_bit_ceil_us + standards: + - stdc + return_type: unsigned short + arguments: + - type: unsigned short + - name: stdc_bit_ceil_ui + standards: + - stdc + return_type: unsigned int + arguments: + - type: unsigned int + - name: stdc_bit_ceil_ul + standards: + - stdc + return_type: unsigned long + arguments: + - type: unsigned long + - name: stdc_bit_ceil_ull + standards: + - stdc + return_type: unsigned long long + arguments: + - type: unsigned long long diff --git a/libc/newhdrgen/yaml/stdckdint.yaml b/libc/newhdrgen/yaml/stdckdint.yaml new file mode 100644 index 00000000000000..5cc2e109e90e75 --- /dev/null +++ b/libc/newhdrgen/yaml/stdckdint.yaml @@ -0,0 +1,8 @@ +header: stdckdint.h +standards: + - stdc +macros: [] +types: [] +enums: [] +objects: [] +functions: [] diff --git a/libc/newhdrgen/yaml/stdint.yaml b/libc/newhdrgen/yaml/stdint.yaml new file mode 100644 index 00000000000000..5f613e1daa67fd --- /dev/null +++ b/libc/newhdrgen/yaml/stdint.yaml @@ -0,0 +1,8 @@ +header: stdint.h +standards: + - stdc +macros: [] +types: [] +enums: [] +objects: [] +functions: [] diff --git a/libc/newhdrgen/yaml/sys_auxv.yaml b/libc/newhdrgen/yaml/sys_auxv.yaml new file mode 100644 index 00000000000000..beea1d8b5f09f2 --- /dev/null +++ b/libc/newhdrgen/yaml/sys_auxv.yaml @@ -0,0 +1,8 @@ +header: sys-auxv.h +standards: + - GNUExtensions +macros: [] +types: [] +enums: [] +objects: [] +functions: [] diff --git a/libc/newhdrgen/yaml/sys_epoll.yaml b/libc/newhdrgen/yaml/sys_epoll.yaml new file mode 100644 index 00000000000000..18d8f59de15f11 --- /dev/null +++ b/libc/newhdrgen/yaml/sys_epoll.yaml @@ -0,0 +1,60 @@ +header: sys-epoll.h +macros: [] +types: + - type_name: struct_epoll_event + - type_name: struct_epoll_data + - type_name: sigset_t + - type_name: struct_timespec +enums: [] +objects: [] +functions: + - name: epoll_create + standards: + - Linux + return_type: int + arguments: + - type: int + - name: epoll_create1 + standards: + - Linux + return_type: int + arguments: + - type: int + - name: epoll_ctl + standards: + - Linux + return_type: int + arguments: + - type: int + - type: int + - type: int + - type: struct epoll_event * + - name: epoll_wait + standards: + - Linux + return_type: int + arguments: + - type: int + - type: struct epoll_event * + - type: int + - type: int + - name: epoll_pwait + standards: + - Linux + return_type: int + arguments: + - type: int + - type: struct epoll_event * + - type: int + - type: int + - type: const sigset_t * + - name: epoll_pwait2 + standards: + - Linux + return_type: int + arguments: + - type: int + - type: struct epoll_event * + - type: int + - type: const struct timespec * + - type: const sigset_t * diff --git a/libc/newhdrgen/yaml/sys_ioctl.yaml b/libc/newhdrgen/yaml/sys_ioctl.yaml new file mode 100644 index 00000000000000..ffe73a84d51b96 --- /dev/null +++ b/libc/newhdrgen/yaml/sys_ioctl.yaml @@ -0,0 +1,7 @@ +header: sys-ioctl.h +standards: POSIX +macros: [] +types: [] +enums: [] +objects: [] +functions: [] diff --git a/libc/newhdrgen/yaml/sys_prctl.yaml b/libc/newhdrgen/yaml/sys_prctl.yaml new file mode 100644 index 00000000000000..35289f6274e7a0 --- /dev/null +++ b/libc/newhdrgen/yaml/sys_prctl.yaml @@ -0,0 +1,7 @@ +header: sys-prctl.h +standards: Linux +macros: [] +types: [] +enums: [] +objects: [] +functions: [] diff --git a/libc/newhdrgen/yaml/sys_random.yaml b/libc/newhdrgen/yaml/sys_random.yaml new file mode 100644 index 00000000000000..233fb2c7988cb9 --- /dev/null +++ b/libc/newhdrgen/yaml/sys_random.yaml @@ -0,0 +1,16 @@ +header: sys-random.h +macros: [] +types: + - type_name: ssize_t + - type_name: size_t +enums: [] +objects: +functions: + - name: getrandom + standards: + - Linux + return_type: ssize_t + arguments: + - type: void * + - type: size_t + - type: unsigned int diff --git a/libc/newhdrgen/yaml/sys_resource.yaml b/libc/newhdrgen/yaml/sys_resource.yaml new file mode 100644 index 00000000000000..2cc801c823ed1f --- /dev/null +++ b/libc/newhdrgen/yaml/sys_resource.yaml @@ -0,0 +1,20 @@ +header: sys-resource.h +macros: [] +types: + - type_name: struct_rlimit + - type_name: rlim_t +enums: [] +objects: [] +functions: + - name: getrlimit + standards: + - POSIX + return_type: int + arguments: + - type: struct rlimit * + - name: setrlimit + standards: + - POSIX + return_type: int + arguments: + - type: const struct rlimit diff --git a/libc/newhdrgen/yaml/sys_select.yaml b/libc/newhdrgen/yaml/sys_select.yaml new file mode 100644 index 00000000000000..eb621f7d14750b --- /dev/null +++ b/libc/newhdrgen/yaml/sys_select.yaml @@ -0,0 +1,22 @@ +header: sys-select.h +macros: [] +types: + - type_name: struct_timeval + - type_name: struct_timespec + - type_name: suseconds_t + - type_name: sigset_t + - type_name: time_t + - type_name: fd_set +enums: [] +objects: [] +functions: + - name: select + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: fd_set *__restrict + - type: fd_set *__restrict + - type: fd_set *__restrict + - type: struct timeval *__restrict diff --git a/libc/newhdrgen/yaml/sys_sendfile.yaml b/libc/newhdrgen/yaml/sys_sendfile.yaml new file mode 100644 index 00000000000000..8743bf01b99ba4 --- /dev/null +++ b/libc/newhdrgen/yaml/sys_sendfile.yaml @@ -0,0 +1,18 @@ +header: sys-sendfile.h +macros: [] +types: + - type_name: ssize_t + - type_name: size_t + - type_name: off_t +enums: [] +objects: [] +functions: + - name: sendfile + standards: + - GNUExtensions + return_type: ssize_t + arguments: + - type: int + - type: int + - type: off_t * + - type: size_t diff --git a/libc/newhdrgen/yaml/sys_socket.yaml b/libc/newhdrgen/yaml/sys_socket.yaml new file mode 100644 index 00000000000000..f9984c638ceae6 --- /dev/null +++ b/libc/newhdrgen/yaml/sys_socket.yaml @@ -0,0 +1,26 @@ +header: sys-socket.h +macros: [] +types: + - type_name: struct_sockaddr_un + - type_name: struct_sockaddr + - type_name: socklen_t + - type_name: sa_family_t +enums: [] +objects: [] +functions: + - name: socket + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: int + - type: int + - name: bind + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: const struct sockaddr * + - type: socklen_t diff --git a/libc/newhdrgen/yaml/sys_stat.yaml b/libc/newhdrgen/yaml/sys_stat.yaml new file mode 100644 index 00000000000000..6ae69b4f870a2e --- /dev/null +++ b/libc/newhdrgen/yaml/sys_stat.yaml @@ -0,0 +1,77 @@ +header: sys-stat.h +macros: [] +types: + - type_name: blkcnt_t + - type_name: blksize_t + - type_name: off_t + - type_name: struct_timeval + - type_name: gid_t + - type_name: struct_stat + - type_name: uid_t + - type_name: nlink_t + - type_name: dev_t + - type_name: struct_timespec + - type_name: ino_t + - type_name: mode_t +enums: [] +objects: [] +functions: + - name: chmod + standards: + - POSIX + return_type: int + arguments: + - type: const char * + - type: mode_t + - name: fchmod + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: mode_t + - name: fchmodat + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: const char * + - type: mode_t + - type: int + - name: fstat + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: struct stat * + - name: lstat + standards: + - POSIX + return_type: int + arguments: + - type: const char *__restrict + - type: struct stat *__restrict + - name: mkdir + standards: + - POSIX + return_type: int + arguments: + - type: const char * + - type: mode_t + - name: mkdirat + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: const char * + - type: mode_t + - name: stat + standards: + - POSIX + return_type: int + arguments: + - type: const char *__restrict + - type: struct stat *__restrict diff --git a/libc/newhdrgen/yaml/sys_statvfs.yaml b/libc/newhdrgen/yaml/sys_statvfs.yaml new file mode 100644 index 00000000000000..3651901e9f2c75 --- /dev/null +++ b/libc/newhdrgen/yaml/sys_statvfs.yaml @@ -0,0 +1,21 @@ +header: sys-statvfs.h +macros: [] +types: + - type_name: struct_statvfs +enums: [] +objects: [] +functions: + - name: statvfs + standards: + - POSIX + return_type: int + arguments: + - type: const char *__restrict + - type: struct statvfs *__restrict + - name: fstatvfs + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: struct statvfs * diff --git a/libc/newhdrgen/yaml/sys_time.yaml b/libc/newhdrgen/yaml/sys_time.yaml new file mode 100644 index 00000000000000..a901cdafd26a16 --- /dev/null +++ b/libc/newhdrgen/yaml/sys_time.yaml @@ -0,0 +1,8 @@ +header: sys-time.h +standards: Linux +macros: [] +types: + - type_name: struct_timeval +enums: [] +functions: [] +objects: [] diff --git a/libc/newhdrgen/yaml/sys_types.yaml b/libc/newhdrgen/yaml/sys_types.yaml new file mode 100644 index 00000000000000..6b08254a7fab13 --- /dev/null +++ b/libc/newhdrgen/yaml/sys_types.yaml @@ -0,0 +1,30 @@ +header: sys-types.h +standards: POSIX +macros: [] +types: + - type_name: uid_t + - type_name: time_t + - type_name: pthread_t + - type_name: pthread_rwlockattr_t + - type_name: pthread_mutex_t + - type_name: blkcnt_t + - type_name: blksize_t + - type_name: clockid_t + - type_name: ssize_t + - type_name: pthread_mutexattr_t + - type_name: ino_t + - type_name: pthread_once_t + - type_name: mode_t + - type_name: dev_t + - type_name: pthread_attr_t + - type_name: gid_t + - type_name: pid_t + - type_name: nlink_t + - type_name: suseconds_t + - type_name: off_t + - type_name: size_t + - type_name: pthread_key_t + - type_name: pthread_condattr_t +enums: [] +functions: [] +objects: [] diff --git a/libc/newhdrgen/yaml/sys_utsname.yaml b/libc/newhdrgen/yaml/sys_utsname.yaml new file mode 100644 index 00000000000000..c48f7e32707486 --- /dev/null +++ b/libc/newhdrgen/yaml/sys_utsname.yaml @@ -0,0 +1,13 @@ +header: sys-utsname.h +macros: [] +types: + - type_name: struct_utsname +enums: [] +objects: [] +functions: + - name: uname + standards: + - POSIX + return_type: int + arguments: + - type: struct utsname * diff --git a/libc/newhdrgen/yaml/termios.yaml b/libc/newhdrgen/yaml/termios.yaml new file mode 100644 index 00000000000000..17986f8c0fc63e --- /dev/null +++ b/libc/newhdrgen/yaml/termios.yaml @@ -0,0 +1,85 @@ +header: termios.h +macros: [] +types: + - type_name: tcflag_t + - type_name: struct_termios + - type_name: speed_t + - type_name: pid_t + - type_name: cc_t +enums: [] +objects: [] +functions: + - name: cfgetispeed + standards: + - POSIX + return_type: speed_t + arguments: + - type: const struct termios * + - name: cfgetospeed + standards: + - POSIX + return_type: speed_t + arguments: + - type: const struct termios * + - name: cfsetispeed + standards: + - POSIX + return_type: int + arguments: + - type: struct termios * + - type: speed_t + - name: cfsetospeed + standards: + - POSIX + return_type: int + arguments: + - type: struct termios * + - type: speed_t + - name: tcgetattr + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: struct termios * + - name: tcgetsid + standards: + - POSIX + return_type: pid_t + arguments: + - type: int + - name: tcdrain + standards: + - POSIX + return_type: int + arguments: + - type: int + - name: tcflow + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: int + - name: tcflush + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: int + - name: tcsendbreak + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: int + - name: tcsetattr + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: int + - type: struct termios * diff --git a/libc/newhdrgen/yaml/threads.yaml b/libc/newhdrgen/yaml/threads.yaml new file mode 100644 index 00000000000000..ef472af8bfd328 --- /dev/null +++ b/libc/newhdrgen/yaml/threads.yaml @@ -0,0 +1,148 @@ +header: threads.h +macros: + - macro_name: ONCE_FLAG_INIT + macro_value: "{0}" +types: + - type_name: once_flag + - type_name: __call_once_func_t + - type_name: cnd_t + - type_name: mtx_t + - type_name: thrd_start_t + - type_name: thrd_t + - type_name: tss_t + - type_name: tss_dtor_t +enums: + - name: mtx_plain + value: null + - name: mtx_recursive + value: null + - name: mtx_timed + value: null + - name: thrd_timedout + value: null + - name: thrd_success + value: null + - name: thrd_busy + value: null + - name: thrd_error + value: null + - name: thrd_nomem + value: null +objects: [] +functions: + - name: call_once + standards: + - stdc + return_type: void + arguments: + - type: once_flag * + - type: __call_once_func_t + - name: cnd_broadcast + standards: + - stdc + return_type: int + arguments: + - type: cnd_t * + - name: cnd_destroy + standards: + - stdc + return_type: void + arguments: + - type: cnd_t * + - name: cnd_init + standards: + - stdc + return_type: int + arguments: + - type: cnd_t * + - name: cnd_signal + standards: + - stdc + return_type: int + arguments: + - type: cnd_t * + - name: cnd_wait + standards: + - stdc + return_type: int + arguments: + - type: cnd_t * + - type: mtx_t * + - name: mtx_init + standards: + - stdc + return_type: int + arguments: + - type: mtx_t * + - type: int + - name: mtx_destroy + standards: + - stdc + return_type: int + arguments: + - type: void + - name: mtx_lock + standards: + - stdc + return_type: int + arguments: + - type: mtx_t * + - name: mtx_unlock + standards: + - stdc + return_type: int + arguments: + - type: mtx_t * + - name: thrd_create + standards: + - stdc + return_type: int + arguments: + - type: thrd_t * + - type: thrd_start_t + - type: void * + - name: thrd_join + standards: + - stdc + return_type: int + arguments: + - type: thrd_t + - type: int * + - name: thrd_detach + standards: + - stdc + return_type: int + arguments: + - type: thrd_t + - name: thrd_current + standards: + - stdc + return_type: thrd_t + arguments: + - type: void + - name: thrd_equal + standards: + - stdc + return_type: int + arguments: + - type: thrd_t + - type: thrd_t + - name: thrd_exit + standards: + - stdc + return_type: void + arguments: + - type: int + - name: tss_create + standards: + - stdc + return_type: int + arguments: + - type: tss_t * + - type: tss_dtor_t + - name: tss_delete + standards: + - stdc + return_type: int + arguments: + - type: tss_t diff --git a/libc/newhdrgen/yaml/uchar.yaml b/libc/newhdrgen/yaml/uchar.yaml new file mode 100644 index 00000000000000..a73da17acdeac3 --- /dev/null +++ b/libc/newhdrgen/yaml/uchar.yaml @@ -0,0 +1,12 @@ +header: uchar.h +standards: + - stdc +macros: [] +types: + - type_name: char32_t + - type_name: char16_t + - type_name: char8_t + - type_name: mbstate_t +enums: [] +objects: [] +functions: [] diff --git a/libc/newhdrgen/yaml/unistd.yaml b/libc/newhdrgen/yaml/unistd.yaml new file mode 100644 index 00000000000000..511746aa19e856 --- /dev/null +++ b/libc/newhdrgen/yaml/unistd.yaml @@ -0,0 +1,329 @@ +header: unistd.h +macros: [] +types: + - type_name: uid_t + - type_name: ssize_t + - type_name: size_t + - type_name: pid_t + - type_name: off_t + - type_name: __getoptargv_t + - type_name: __exec_envp_t + - type_name: __exec_argv_t +enums: [] +objects: + - object_name: environ + object_type: char ** + - object_name: optarg + object_type: char * + - object_name: optind + object_type: int + - object_name: opterr + object_type: int + - object_name: optopt + object_type: int +functions: + - name: access + standards: + - POSIX + return_type: int + arguments: + - type: const char * + - type: int + - name: chdir + standards: + - POSIX + return_type: int + arguments: + - type: const char * + - name: close + standards: + - POSIX + return_type: int + arguments: + - type: int + - name: dup + standards: + - POSIX + return_type: int + arguments: + - type: int + - name: dup2 + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: int + - name: dup3 + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: int + - type: int + - name: execve + standards: + - POSIX + return_type: int + arguments: + - type: const char * + - type: __exec_argv_t + - type: __exec_envp_t + - name: fchdir + standards: + - POSIX + return_type: int + arguments: + - type: int + - name: fsync + standards: + - POSIX + return_type: int + arguments: + - type: int + - name: ftruncate + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: off_t + - name: getcwd + standards: + - POSIX + return_type: char * + arguments: + - type: char * + - type: size_t + - name: geteuid + standards: + - POSIX + return_type: uid_t + arguments: [] + - name: getpid + standards: + - POSIX + return_type: int + arguments: [] + - name: getppid + standards: + - POSIX + return_type: int + arguments: [] + - name: getuid + standards: + - POSIX + return_type: uid_t + arguments: [] + - name: isatty + standards: + - POSIX + return_type: int + arguments: + - type: int + guard: null + attributes: [] + - name: link + standards: + - POSIX + return_type: int + arguments: + - type: const char * + - type: const char * + - name: linkat + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: const char * + - type: int + - type: const char * + - type: int + - name: lseek + standards: + - POSIX + return_type: off_t + arguments: + - type: int + - type: off_t + - type: int + - name: pipe + standards: + - POSIX + return_type: int + arguments: + - type: int * + - name: pread + standards: + - POSIX + return_type: ssize_t + arguments: + - type: int + - type: void * + - type: size_t + - type: off_t + - name: pwrite + standards: + - POSIX + return_type: ssize_t + arguments: + - type: int + - type: const void * + - type: size_t + - type: off_t + - name: read + standards: + - POSIX + return_type: ssize_t + arguments: + - type: int + - type: void * + - type: size_t + - name: readlink + standards: + - POSIX + return_type: ssize_t + arguments: + - type: const char * __restrict + - type: char * __restrict + - type: size_t + - name: readlinkat + standards: + - POSIX + return_type: ssize_t + arguments: + - type: const char * __restrict + - type: char * __restrict + - type: size_t + - name: rmdir + standards: + - POSIX + return_type: int + arguments: + - type: const char * + - name: symlink + standards: + - POSIX + return_type: int + arguments: + - type: const char * + - type: const char * + - name: symlinkat + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: const char * + - type: int + - type: const char * + - name: sysconf + standards: + - POSIX + return_type: int + arguments: + - type: int + - name: truncate + standards: + - POSIX + return_type: int + arguments: + - type: const char * + - type: off_t + - name: unlink + standards: + - POSIX + return_type: int + arguments: + - type: const char * + - name: unlinkat + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: const char * + - type: int + - name: write + standards: + - POSIX + return_type: ssize_t + arguments: + - type: int + - type: const void * + - type: size_t + guard: null + attributes: [] + - name: _exit + standards: + - POSIX + return_type: _Noreturn void + arguments: + - type: int + - name: execv + standards: + - POSIX + return_type: int + arguments: + - type: const char * + - type: __exec_argv_t + - name: fork + standards: + - POSIX + return_type: pid_t + arguments: [] + - name: __llvm_libc_syscall + standards: + - POSIX + return_type: long + arguments: + - type: long + - type: long + - type: long + - type: long + - type: long + - type: long + - type: long + - name: getopt + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: __getoptargv_t + - type: const char * + - name: swab + standards: + - POSIX + return_type: void + arguments: + - type: const void * __restrict + - type: void * + - type: ssize_t + - name: enivron + standards: + - POSIX + return_type: extern char ** + arguments: [] + - name: optarg + standards: + - POSIX + return_type: extern char * + arguments: [] + - name: optind + standards: + - POSIX + return_type: extern int + arguments: [] + - name: optopt + standards: + - POSIX + return_type: extern int + arguments: [] + - name: opterr + standards: + - POSIX + return_type: extern int + arguments: [] diff --git a/libc/newhdrgen/yaml/wchar.yaml b/libc/newhdrgen/yaml/wchar.yaml new file mode 100644 index 00000000000000..663267fb69d73e --- /dev/null +++ b/libc/newhdrgen/yaml/wchar.yaml @@ -0,0 +1,15 @@ +header: wchar.h +macros: [] +types: + - type_name: size_t + - type_name: wint_t + - type_name: wchar_t +enums: [] +objects: [] +functions: + - name: wctob + standards: + - stdc + return_type: int + arguments: + - type: wint_t diff --git a/libc/newhdrgen/yaml_combined/ctype.yaml b/libc/newhdrgen/yaml_combined/ctype.yaml new file mode 100644 index 00000000000000..a4a3048ede872c --- /dev/null +++ b/libc/newhdrgen/yaml_combined/ctype.yaml @@ -0,0 +1,103 @@ +header: ctype.h +macros: [] +types: [] +enums: [] +objects: [] +functions: + - name: isalnum + standards: + - stdc + return_type: int + arguments: + - type: int + - name: isalpha + standards: + - stdc + return_type: int + arguments: + - type: int + - name: isblank + standards: + - stdc + return_type: int + arguments: + - type: int + - name: iscntrl + standards: + - stdc + return_type: int + arguments: + - type: int + - name: isdigit + standards: + - stdc + return_type: int + arguments: + - type: int + - name: isgraph + standards: + - stdc + return_type: int + arguments: + - type: int + - name: islower + standards: + - stdc + return_type: int + arguments: + - type: int + - name: isprint + standards: + - stdc + return_type: int + arguments: + - type: int + - name: ispunct + standards: + - stdc + return_type: int + arguments: + - type: int + - name: isspace + standards: + - stdc + return_type: int + arguments: + - type: int + - name: isupper + standards: + - stdc + return_type: int + arguments: + - type: int + - name: isxdigit + standards: + - stdc + return_type: int + arguments: + - type: int + - name: tolower + standards: + - stdc + return_type: int + arguments: + - type: int + - name: toupper + standards: + - stdc + return_type: int + arguments: + - type: int + functions: + - name: isascii + standards: + - POSIX + return_type: int + arguments: + - type: int + - name: toascii + standards: + - GNUExtensions + return_type: int + arguments: + - type: int diff --git a/libc/newhdrgen/yaml_combined/fenv.yaml b/libc/newhdrgen/yaml_combined/fenv.yaml new file mode 100644 index 00000000000000..e7ff8cdf4e3b0b --- /dev/null +++ b/libc/newhdrgen/yaml_combined/fenv.yaml @@ -0,0 +1,107 @@ +header: fenv.h +macros: [] +types: + - type_name: fenv_t + - type_name: fexcept_t +enums: [] +objects: [] +functions: + - name: feclearexcept + standards: + - stdc + return_type: int + arguments: + - type: int + - name: fetestexcept + standards: + - stdc + return_type: int + arguments: + - type: int + - name: fetestexceptflag + standards: + - stdc + return_type: int + arguments: + - type: const fexcept_t * + - type: int + - name: feraiseexcept + standards: + - stdc + return_type: int + arguments: + - type: int + - name: fesetround + standards: + - stdc + return_type: int + arguments: + - type: int + - name: fegetround + standards: + - stdc + return_type: int + arguments: [] + - name: fegetenv + standards: + - stdc + return_type: int + arguments: + - type: fenv_t * + - name: fesetenv + standards: + - stdc + return_type: int + arguments: + - type: const fenv_t * + - name: fegetexceptflag + standards: + - stdc + return_type: int + arguments: + - type: fexcept_t * + - type: int + - name: fesetexcept + standards: + - stdc + return_type: int + arguments: + - type: int + - name: fesetexceptflag + standards: + - stdc + return_type: int + arguments: + - type: const fexcept_t * + - type: int + - name: feholdexcept + standards: + - stdc + return_type: int + arguments: + - type: fenv_t * + - name: feupdateenv + standards: + - stdc + return_type: int + arguments: + - type: const fenv_t * + - name: fedisableexcept + standards: + - GNUExtensions + return_type: int + arguments: + - type: int + guard: null + - name: feenableexcept + standards: + - GNUExtensions + return_type: int + arguments: + - type: int + attributes: [] + - name: fegetexcept + standards: + - GNUExtensions + return_type: int + arguments: [] diff --git a/libc/newhdrgen/yaml_combined/math.yaml b/libc/newhdrgen/yaml_combined/math.yaml new file mode 100644 index 00000000000000..dbb1e6ec63030b --- /dev/null +++ b/libc/newhdrgen/yaml_combined/math.yaml @@ -0,0 +1,1884 @@ +header: math.h +macros: [] +types: + - type_name: float_t + - type_name: double_t + - type_name: float128 +enums: [] +objects: [] +functions: + - name: copysign + standards: + - stdc + return_type: double + arguments: + - type: double + - type: double + - name: copysignf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: float + - name: copysignl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: long double + - name: copysignf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: copysignf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: ceil + standards: + - stdc + return_type: double + arguments: + - type: double + - name: ceilf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: ceill + standards: + - stdc + return_type: long double + arguments: + - type: long double + - name: ceilf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: ceilf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: fabs + standards: + - stdc + return_type: double + arguments: + - type: double + attributes: + - __LIBC_CONST_ATTR + - name: fabsf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: fabsl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - name: fabsf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: fabsf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: fdim + standards: + - stdc + return_type: double + arguments: + - type: double + - type: double + - name: fdimf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: float + - name: fdiml + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: long double + - name: fdimf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: fdimf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: floor + standards: + - stdc + return_type: double + arguments: + - type: double + - name: floorf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: floorl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - name: floorf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: floorf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: fmin + standards: + - stdc + return_type: double + arguments: + - type: double + - type: double + - name: fminf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: float + - name: fminl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: long double + - name: fminf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: fminf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + - type: float128 + - name: fmax + standards: + - stdc + return_type: double + arguments: + - type: double + - type: double + - name: fmaxf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: float + - name: fmaxl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: long double + - name: fmaxf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: fmaxf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + - type: float128 + - name: fmaximum + standards: + - stdc + return_type: double + arguments: + - type: double + - type: double + - name: fmaximumf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: float + - name: fmaximuml + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: long double + - name: fmaximumf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: fmaximumf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: fmaximum_num + standards: + - stdc + return_type: double + arguments: + - type: double + - type: double + - name: fmaximum_numf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: float + - name: fmaximum_numl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: long double + - name: fmaximum_numf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: fmaximum_numf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: fmaximum_mag + standards: + - stdc + return_type: double + arguments: + - type: double + - type: double + - name: fmaximum_magf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: float + - name: fmaximum_magl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: long double + - name: fmaximum_magf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: fmaximum_magf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: fmaximum_mag_num + standards: + - stdc + return_type: double + arguments: + - type: double + - type: double + - name: fmaximum_mag_numf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: float + - name: fmaximum_mag_numl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: long double + - name: fmaximum_mag_numf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: fmaximum_mag_numf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: fminimum + standards: + - stdc + return_type: double + arguments: + - type: double + - type: double + - name: fminimumf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: float + - name: fminimuml + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: long double + - name: fminimumf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: fminimumf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: fminimum_num + standards: + - stdc + return_type: double + arguments: + - type: double + - type: double + - name: fminimum_numf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: float + - name: fminimum_numl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: long double + - name: fminimum_numf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: fminimum_numf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: fminimum_mag + standards: + - stdc + return_type: double + arguments: + - type: double + - type: double + - name: fminimum_magf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: float + - name: fminimum_magl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: long double + - name: fminimum_magf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: fminimum_magf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: fminimum_mag_num + standards: + - stdc + return_type: double + arguments: + - type: double + - type: double + - name: fminimum_mag_numf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: float + - name: fminimum_mag_numl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: long double + - name: fminimum_mag_numf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: fminimum_mag_numf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: fma + standards: + - stdc + return_type: double + arguments: + - type: double + - type: double + - type: double + - name: fmaf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: float + - type: float + - name: f16fmaf + standards: + - stdc + return_type: _Float16 + arguments: + - type: float + - type: float + - type: float + guard: LIBC_TYPES_HAS_FLOAT16 + - name: fmod + standards: + - stdc + return_type: double + arguments: + - type: double + - type: double + - name: fmodf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: float + - name: fmodl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: long double + - name: fmodf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: fmodf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: frexp + standards: + - stdc + return_type: double + arguments: + - type: double + - type: int * + - name: frexpf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: int * + - name: frexpl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: int * + - name: frexpf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + - type: int * + guard: LIBC_TYPES_HAS_FLOAT16 + - name: frexpf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + - type: int * + guard: LIBC_TYPES_HAS_FLOAT128 + - name: fromfp + standards: + - stdc + return_type: double + arguments: + - type: double + - type: int + - type: unsigned int + - name: fromfpf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: int + - type: unsigned int + - name: fromfpl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: int + - type: unsigned int + - name: fromfpf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + - type: int + - type: unsigned int + guard: LIBC_TYPES_HAS_FLOAT16 + - name: fromfpf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + - type: int + - type: unsigned int + guard: LIBC_TYPES_HAS_FLOAT128 + - name: fromfpx + standards: + - stdc + return_type: double + arguments: + - type: double + - type: int + - type: unsigned int + - name: fromfpxf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: int + - type: unsigned int + - name: fromfpxl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: int + - type: unsigned int + - name: fromfpxf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + - type: int + - type: unsigned int + guard: LIBC_TYPES_HAS_FLOAT16 + - name: fromfpxf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + - type: int + - type: unsigned int + guard: LIBC_TYPES_HAS_FLOAT128 + - name: ufromfp + standards: + - stdc + return_type: double + arguments: + - type: double + - type: int + - type: unsigned int + - name: ufromfpf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: int + - type: unsigned int + - name: ufromfpl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: int + - type: unsigned int + - name: ufromfpf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + - type: int + - type: unsigned int + guard: LIBC_TYPES_HAS_FLOAT16 + - name: ufromfpf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + - type: int + - type: unsigned int + guard: LIBC_TYPES_HAS_FLOAT128 + - name: ufromfpx + standards: + - stdc + return_type: double + arguments: + - type: double + - type: int + - type: unsigned int + - name: ufromfpxf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: int + - type: unsigned int + - name: ufromfpxl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: int + - type: unsigned int + - name: ufromfpxf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + - type: int + - type: unsigned int + guard: LIBC_TYPES_HAS_FLOAT16 + - name: ufromfpxf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + - type: int + - type: unsigned int + guard: LIBC_TYPES_HAS_FLOAT128 + - name: hypot + standards: + - stdc + return_type: double + arguments: + - type: double + - type: double + - name: hypotf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: float + - name: ilogb + standards: + - stdc + return_type: int + arguments: + - type: double + - name: ilogbf + standards: + - stdc + return_type: int + arguments: + - type: float + - name: ilogbl + standards: + - stdc + return_type: int + arguments: + - type: long double + - name: ilogbf16 + standards: + - stdc + return_type: int + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: ilogbf128 + standards: + - stdc + return_type: int + arguments: + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: llogb + standards: + - stdc + return_type: long + arguments: + - type: double + - name: llogbf + standards: + - stdc + return_type: long + arguments: + - type: float + - name: llogbl + standards: + - stdc + return_type: long + arguments: + - type: long double + - name: llogbf16 + standards: + - stdc + return_type: long + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: llogbf128 + standards: + - stdc + return_type: long + arguments: + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: ldexp + standards: + - stdc + return_type: double + arguments: + - type: double + - type: int + - name: ldexpf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: int + - name: ldexpl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: int + - name: ldexpf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + - type: int + guard: LIBC_TYPES_HAS_FLOAT128 + - name: log10 + standards: + - stdc + return_type: double + arguments: + - type: double + - name: log10f + standards: + - stdc + return_type: float + arguments: + - type: float + - name: log1p + standards: + - stdc + return_type: double + arguments: + - type: double + - name: log1pf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: log2 + standards: + - stdc + return_type: double + arguments: + - type: double + - name: log2f + standards: + - stdc + return_type: float + arguments: + - type: float + - name: log + standards: + - stdc + return_type: double + arguments: + - type: double + - name: logf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: log1p + standards: + - stdc + return_type: double + arguments: + - type: double + - name: log1pf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: log2 + standards: + - stdc + return_type: double + arguments: + - type: double + - name: log2f + standards: + - stdc + return_type: float + arguments: + - type: float + - name: logb + standards: + - stdc + return_type: double + arguments: + - type: double + - name: logbf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: logbl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - name: logbf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: logbf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: modf + standards: + - stdc + return_type: double + arguments: + - type: double + - type: double * + - name: modff + standards: + - stdc + return_type: float + arguments: + - type: float + - type: float * + - name: modfl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: long double * + - name: modff16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + - type: _Float16 * + guard: LIBC_TYPES_HAS_FLOAT16 + - name: modff128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + - type: float128 * + guard: LIBC_TYPES_HAS_FLOAT128 + - name: cos + standards: + - stdc + return_type: double + arguments: + - type: double + - name: cosf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: sin + standards: + - stdc + return_type: double + arguments: + - type: double + - name: sincosf + standards: + - gnu + return_type: void + arguments: + - type: float + - type: float * + - type: float * + - name: sinf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: tan + standards: + - stdc + return_type: double + arguments: + - type: double + - name: tanf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: erff + standards: + - stdc + return_type: float + arguments: + - type: float + - name: exp + standards: + - stdc + return_type: double + arguments: + - type: double + - name: expf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: exp2 + standards: + - stdc + return_type: double + arguments: + - type: double + - name: exp2f + standards: + - stdc + return_type: float + arguments: + - type: float + - name: exp2m1f + standards: + - stdc + return_type: float + arguments: + - type: float + - name: expm1 + standards: + - stdc + return_type: double + arguments: + - type: double + - name: expm1f + standards: + - stdc + return_type: float + arguments: + - type: float + - name: exp10 + standards: + - stdc + return_type: double + arguments: + - type: double + - name: exp10f + standards: + - stdc + return_type: float + arguments: + - type: float + - name: remainder + standards: + - stdc + return_type: double + arguments: + - type: double + - type: double + - name: remainderf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: float + - name: remainderl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: long double + - name: remainderf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: remquo + standards: + - stdc + return_type: double + arguments: + - type: double + - type: double + - type: int * + - name: remquof + standards: + - stdc + return_type: float + arguments: + - type: float + - type: float + - type: int * + - name: remquol + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: long double + - type: int * + - name: remquof16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + - type: _Float16 + - type: int * + guard: LIBC_TYPES_HAS_FLOAT16 + - name: remquof128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + - type: float128 + - type: int * + guard: LIBC_TYPES_HAS_FLOAT128 + - name: round + standards: + - stdc + return_type: double + arguments: + - type: double + - name: roundf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: roundl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - name: roundf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: roundf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: roundeven + standards: + - stdc + return_type: double + arguments: + - type: double + - name: roundevenf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: roundevenl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - name: roundevenf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: roundevenf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: lround + standards: + - stdc + return_type: long + arguments: + - type: double + - name: lroundf + standards: + - stdc + return_type: long + arguments: + - type: float + - name: lroundl + standards: + - stdc + return_type: long + arguments: + - type: long double + - name: lroundf16 + standards: + - stdc + return_type: long + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: lroundf128 + standards: + - stdc + return_type: long + arguments: + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: llround + standards: + - stdc + return_type: Longlong + arguments: + - type: double + - name: llroundf + standards: + - stdc + return_type: Longlong + arguments: + - type: float + - name: llroundl + standards: + - stdc + return_type: Longlong + arguments: + - type: long double + - name: llroundf16 + standards: + - stdc + return_type: Longlong + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: llroundf128 + standards: + - stdc + return_type: Longlong + arguments: + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: rint + standards: + - stdc + return_type: double + arguments: + - type: double + - name: rintf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: rintl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - name: rintf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: rintf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: lrint + standards: + - stdc + return_type: long + arguments: + - type: double + - name: lrintf + standards: + - stdc + return_type: long + arguments: + - type: float + - name: lrintl + standards: + - stdc + return_type: long + arguments: + - type: long double + - name: lrintf16 + standards: + - stdc + return_type: long + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: lrintf128 + standards: + - stdc + return_type: long + arguments: + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: llrint + standards: + - stdc + return_type: Longlong + arguments: + - type: double + - name: llrintf + standards: + - stdc + return_type: Longlong + arguments: + - type: float + - name: llrintl + standards: + - stdc + return_type: Longlong + arguments: + - type: long double + - name: llrintf16 + standards: + - stdc + return_type: Longlong + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: llrintf128 + standards: + - stdc + return_type: Longlong + arguments: + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: sqrt + standards: + - stdc + return_type: double + arguments: + - type: double + - name: sqrtf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: sqrtl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - name: sqrtf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: trunc + standards: + - stdc + return_type: double + arguments: + - type: double + - name: truncf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: truncl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - name: truncf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: truncf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: nearbyint + standards: + - stdc + return_type: double + arguments: + - type: double + - name: nearbyintf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: nearbyintl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - name: nearbyintf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: nearbyintf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: nextafterf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: float + - name: nextafter + standards: + - stdc + return_type: double + arguments: + - type: double + - type: double + - name: nextafterl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: long double + - name: nextafterf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: nextafterf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: nexttowardf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: long double + - name: nexttoward + standards: + - stdc + return_type: double + arguments: + - type: double + - type: long double + - name: nexttowardl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: long double + - name: nexttowardf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: nextdown + standards: + - stdc + return_type: double + arguments: + - type: double + - name: nextdownf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: nextdownl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - name: nextdownf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: nextdownf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: nextup + standards: + - stdc + return_type: double + arguments: + - type: double + - name: nextupf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: nextupl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - name: nextupf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: nextupf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: powf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: float + - name: pow + standards: + - stdc + return_type: double + arguments: + - type: double + - type: double + - name: coshf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: sinhf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: tanhf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: acosf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: asinf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: asin + standards: + - stdc + return_type: double + arguments: + - type: double + - name: atanf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: atan2f + standards: + - stdc + return_type: float + arguments: + - type: float + - type: float + - name: acoshf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: asinhf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: atanhf + standards: + - stdc + return_type: float + arguments: + - type: float + - name: scalbn + standards: + - stdc + return_type: double + arguments: + - type: double + - type: int + - name: scalbnf + standards: + - stdc + return_type: float + arguments: + - type: float + - type: int + - name: scalbnl + standards: + - stdc + return_type: long double + arguments: + - type: long double + - type: int + - name: scalbnf128 + standards: + - stdc + return_type: float128 + arguments: + - type: float128 + - type: int + guard: LIBC_TYPES_HAS_FLOAT128 + - name: nanf + standards: + - stdc + return_type: float + arguments: + - type: const char * + - name: nan + standards: + - stdc + return_type: double + arguments: + - type: const char * + - name: nanl + standards: + - stdc + return_type: long double + arguments: + - type: const char * + - name: nanf16 + standards: + - stdc + return_type: _Float16 + arguments: + - type: const char * + guard: LIBC_TYPES_HAS_FLOAT16 + - name: nanf128 + standards: + - stdc + return_type: float128 + arguments: + - type: const char * + guard: LIBC_TYPES_HAS_FLOAT128 + - name: canonicalize + standards: + - stdc + return_type: int + arguments: + - type: double + - type: double + - name: canonicalizef + standards: + - stdc + return_type: int + arguments: + - type: float + - type: float + - name: canonicalizel + standards: + - stdc + return_type: int + arguments: + - type: long double + - type: long double + - name: canonicalizef16 + standards: + - stdc + return_type: int + arguments: + - type: _Float16 + - type: _Float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - name: canonicalizef128 + standards: + - stdc + return_type: int + arguments: + - type: float128 + - type: float128 + guard: LIBC_TYPES_HAS_FLOAT128 + - name: totalorderf16 + standards: + - stdc + return_type: int + arguments: + - type: _Float16 * + - type: _Float16 * + guard: LIBC_TYPES_HAS_FLOAT16 + - name: totalordermagf16 + standards: + - stdc + return_type: int + arguments: + - type: _Float16 * + - type: _Float16 * + guard: LIBC_TYPES_HAS_FLOAT16 + - name: f16sqrtf + standards: + - stdc + return_type: _Float16 + arguments: + - type: float + guard: LIBC_TYPES_HAS_FLOAT16 diff --git a/libc/newhdrgen/yaml_combined/pthread.yaml b/libc/newhdrgen/yaml_combined/pthread.yaml new file mode 100644 index 00000000000000..5a1ede32e53e3e --- /dev/null +++ b/libc/newhdrgen/yaml_combined/pthread.yaml @@ -0,0 +1,368 @@ +header: pthread.h +macros: [] +types: + - type_name: pthread_t + - type_name: pthread_once_t + - type_name: pthread_mutex_t + - type_name: pthread_mutexattr_t + - type_name: pthread_key_t + - type_name: pthread_condattr_t + - type_name: __pthread_tss_dtor_t + - type_name: pthread_rwlockattr_t + - type_name: pthread_attr_t + - type_name: __pthread_start_t + - type_name: __pthread_once_func_t + - type_name: __atfork_callback_t +enums: + - name: PTHREAD_CREATE_JOINABLE + value: 0x0 + - name: PTHREAD_CREATE_DETACHED + value: 0x1 + - name: PTHREAD_MUTEX_NORMAL + value: 0x0 + - name: PTHREAD_MUTEX_ERRORCHECK + value: 0x1 + - name: PTHREAD_MUTEX_RECURSIVE + value: 0x2 + - name: PTHREAD_MUTEX_DEFAULT + value: 0x0 + - name: PTHREAD_PROCESS_PRIVATE + value: 0x0 + - name: PTHREAD_PROCESS_SHARED + value: 0x1 + - name: PTHREAD_MUTEX_STALLED + value: 0x0 + - name: PTHREAD_MUTEX_ROBUST + value: 0x1 + - name: PTHREAD_RWLOCK_PREFER_READER_NP + value: 0 + - name: PTHREAD_RWLOCK_PREFER_WRITER_NP + value: 1 + - name: PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP + value: 2 +functions: + - name: pthread_atfork + standards: + - POSIX + return_type: int + arguments: + - type: __atfork_callback_t + - type: __atfork_callback_t + - type: __atfork_callback_t + - name: pthread_attr_destroy + standards: + - POSIX + return_type: int + arguments: + - type: pthread_attr_t * + - name: pthread_attr_init + standards: + - POSIX + return_type: int + arguments: + - type: pthread_attr_t * + - name: pthread_attr_getdetachstate + standards: + - POSIX + return_type: int + arguments: + - type: const pthread_attr_t * + - type: int * + - name: pthread_attr_getguardsize + standards: + - POSIX + return_type: int + arguments: + - type: const pthread_attr_t * __restrict + - type: size_t * __restrict + - name: pthread_attr_getstack + standards: + - POSIX + return_type: int + arguments: + - type: const pthread_attr_t * __restrict + - type: void * * __restrict + - type: size_t * __restrict + - name: pthread_attr_getstacksize + standards: + - POSIX + return_type: int + arguments: + - type: const pthread_attr_t * __restrict + - type: size_t * __restrict + - name: pthread_attr_setdetachstate + standards: + - POSIX + return_type: int + arguments: + - type: pthread_attr_t * + - type: int + - name: pthread_attr_setguardsize + standards: + - POSIX + return_type: int + arguments: + - type: pthread_attr_t * + - type: size_t + - name: pthread_attr_setstack + standards: + - POSIX + return_type: int + arguments: + - type: pthread_attr_t * + - type: void * + - type: size_t + - name: pthread_attr_setstacksize + standards: + - POSIX + return_type: int + arguments: + - type: pthread_attr_t * + - type: size_t + - name: pthread_condattr_destroy + standards: + - POSIX + return_type: int + arguments: + - type: pthread_condattr_t * + - name: pthread_condattr_getclock + standards: + - POSIX + return_type: int + arguments: + - type: const pthread_condattr_t * __restrict + - type: clockid_t * __restrict + - name: pthread_condattr_getpshared + standards: + - POSIX + return_type: int + arguments: + - type: const pthread_condattr_t * __restrict + - type: int * __restrict + - name: pthread_condattr_init + standards: + - POSIX + return_type: int + arguments: + - type: pthread_condattr_t * + - name: pthread_condattr_setclock + standards: + - POSIX + return_type: int + arguments: + - type: pthread_condattr_t * + - type: clockid_t + - name: pthread_condattr_setpshared + standards: + - POSIX + return_type: int + arguments: + - type: pthread_condattr_t * + - type: int + - name: pthread_create + standards: + - POSIX + return_type: int + arguments: + - type: pthread_t * __restrict + - type: const pthread_attr_t * __restrict + - type: __pthread_start_t + - type: void * + - name: pthread_detach + standards: + - POSIX + return_type: int + arguments: + - type: pthread_t + - name: pthread_equal + standards: + - POSIX + return_type: int + arguments: + - type: pthread_t + - type: pthread_t + - name: pthread_exit + standards: + - POSIX + return_type: __Noreturn void + arguments: + - type: void * + - name: pthread_getname_np + standards: + - GNUExtensions + return_type: int + arguments: + - type: pthread_t + - type: char * + - type: size_t + - name: pthread_getspecific + standards: + - POSIX + return_type: void * + arguments: + - type: pthread_key_t + - name: pthread_join + standards: + - POSIX + return_type: int + arguments: + - type: pthread_t + - type: void * * + - name: pthread_key_create + standards: + - POSIX + return_type: int + arguments: + - type: pthread_key_t * + - type: __pthread_tss_dtor_t + - name: pthread_key_delete + standards: + - POSIX + return_type: int + arguments: + - type: pthread_key_t + - name: pthread_self + standards: + - POSIX + return_type: pthread_t + arguments: [] + - name: pthread_setname_np + standards: + - GNUExtensions + return_type: int + arguments: + - type: pthread_t + - type: const char * + - name: pthread_mutex_destroy + standards: + - POSIX + return_type: int + arguments: + - type: pthread_mutex_t * + - name: pthread_mutex_init + standards: + - POSIX + return_type: int + arguments: + - type: pthread_mutex_t * __restrict + - type: const pthread_mutexattr_t * __restrict + - name: pthread_mutex_lock + standards: + - POSIX + return_type: int + arguments: + - type: pthread_mutex_t * + - name: pthread_mutex_unlock + standards: + - POSIX + return_type: int + arguments: + - type: pthread_mutex_t * + - name: pthread_mutexattr_destroy + standards: + - POSIX + return_type: int + arguments: + - type: pthread_mutexattr_t * + - name: pthread_mutexattr_init + standards: + - POSIX + return_type: int + arguments: + - type: pthread_mutexattr_t * + - name: pthread_mutexattr_getpshared + standards: + - POSIX + return_type: int + arguments: + - type: const pthread_mutexattr_t * __restrict + - type: int * __restrict + - name: pthread_mutexattr_getrobust + standards: + - POSIX + return_type: int + arguments: + - type: const pthread_mutexattr_t * __restrict + - type: int * __restrict + - name: pthread_mutexattr_gettype + standards: + - POSIX + return_type: int + arguments: + - type: const pthread_mutexattr_t * __restrict + - type: int * __restrict + - name: pthread_mutexattr_setpshared + standards: + - POSIX + return_type: int + arguments: + - type: pthread_mutexattr_t * __restrict + - type: int + - name: pthread_mutexattr_setrobust + standards: + - POSIX + return_type: int + arguments: + - type: pthread_mutexattr_t * __restrict + - type: int + - name: pthread_mutexattr_settype + standards: + - POSIX + return_type: int + arguments: + - type: pthread_mutexattr_t * __restrict + - type: int + - name: pthread_once + standards: + - POSIX + return_type: int + arguments: + - type: pthread_once_t * + - type: __pthread_once_func_t + - name: pthread_rwlockattr_destroy + standards: + - POSIX + return_type: int + arguments: + - type: pthread_rwlockattr_t * + - name: pthread_rwlockattr_getkind_np + standards: + - POSIX + return_type: int + arguments: + - type: pthread_rwlockattr_t * + - type: int * + - name: pthread_rwlockattr_getpshared + standards: + - POSIX + return_type: int + arguments: + - type: const pthread_rwlockattr_t * + - type: int * + - name: pthread_rwlockattr_init + standards: + - POSIX + return_type: int + arguments: + - type: pthread_rwlockattr_t * + - name: pthread_rwlockattr_setkind_np + standards: + - POSIX + return_type: int + arguments: + - type: pthread_rwlockattr_t * + - type: int + - name: pthread_rwlockattr_setpshared + standards: + - POSIX + return_type: int + arguments: + - type: pthread_rwlockattr_t * + - type: int + - name: pthread_setspecific + standards: + - POSIX + return_type: void * + arguments: + - type: pthread_key_t + - type: const void * diff --git a/libc/newhdrgen/yaml_combined/sched.yaml b/libc/newhdrgen/yaml_combined/sched.yaml new file mode 100644 index 00000000000000..11a55b7d993b90 --- /dev/null +++ b/libc/newhdrgen/yaml_combined/sched.yaml @@ -0,0 +1,87 @@ +header: sched.h +macros: [] +types: + - type_name: struct_timespec + - type_name: time_t + - type_name: struct_sched_param + - type_name: size_t + - type_name: cpu_set_t + - type_name: pid_t +enums: [] +objects: [] +functions: + - name: sched_get_priority_max + standards: + - POSIX + return_type: int + arguments: + - type: int + - name: sched_get_priority_min + standards: + - POSIX + return_type: int + arguments: + - type: int + - name: sched_getaffinity + standards: + - GNUExtensions + return_type: int + arguments: + - type: pid_t + - type: size_t + - type: cpu_set_t * + - name: sched_getparam + standards: + - POSIX + return_type: int + arguments: + - type: pid_t + - type: struct sched_param * + - name: sched_getscheduler + standards: + - POSIX + return_type: int + arguments: + - type: pid_t + - type: int + - type: const struct sched_param * + - name: sched_rr_get_interval + standards: + - POSIX + return_type: int + arguments: + - type: pid_t + - type: struct timespec * + - name: sched_setaffinity + standards: + - GNUExtensions + return_type: int + arguments: + - type: pid_t + - type: size_t + - type: const cpu_set_t * + - name: sched_setparam + standards: + - POSIX + return_type: int + arguments: + - type: pid_t + - type: const struct sched_param * + - name: sched_setscheduler + standards: + - POSIX + return_type: int + arguments: + - type: pid_t + - name: sched_yield + standards: + - POSIX + return_type: int + arguments: [] + - name: __sched_getcpucount + standards: + - llvm_libc_ext + return_type: int + arguments: + - type: size_t + - type: const cpu_set_t * diff --git a/libc/newhdrgen/yaml_combined/signal.yaml b/libc/newhdrgen/yaml_combined/signal.yaml new file mode 100644 index 00000000000000..a95273419dbde4 --- /dev/null +++ b/libc/newhdrgen/yaml_combined/signal.yaml @@ -0,0 +1,84 @@ +header: signal.h +macros: + - macro_name: __need_size_t + macro_value: null +types: + - type_name: pid_t + - type_name: stack_t + - type_name: siginfo_t + - type_name: struct_sigaction + - type_name: sigset_t + - type_name: union_sigval + - type_name: sig_atomic_t +enums: [] +objects: [] +functions: + - name: raise + standards: + - stdc + return_type: int + arguments: + - type: int + - name: kill + standards: + - POSIX + return_type: int + arguments: + - type: pid_t + - type: int + - name: sigaction + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: const struct sigaction * __restrict + - type: struct sigaction * __restrict + - name: sigaltstack + standards: + - POSIX + return_type: int + arguments: + - type: const stack_t * __restrict + - type: stack_t * __restrict + - name: sigdelset + standards: + - POSIX + return_type: int + arguments: + - type: sigset_t * + - type: int + - name: sigaddset + standards: + - POSIX + return_type: int + arguments: + - type: sigset_t * + - type: int + - name: sigemptyset + standards: + - POSIX + return_type: int + arguments: + - type: sigset_t * + - name: sigprocmask + standards: + - POSIX + return_type: int + arguments: + - type: int + - type: const sigset_t * __restrict + - type: sigset_t * __restrict + - name: sigfillset + standards: + - POSIX + return_type: int + arguments: + - type: sigset_t * + - name: signal + standards: + - stdc + return_type: __sighandler_t + arguments: + - type: int + - type: __sighandler_t diff --git a/libc/newhdrgen/yaml_combined/stdfix.yaml b/libc/newhdrgen/yaml_combined/stdfix.yaml new file mode 100644 index 00000000000000..564826a3335805 --- /dev/null +++ b/libc/newhdrgen/yaml_combined/stdfix.yaml @@ -0,0 +1,222 @@ +header: stdfix.h +macros: [] +types: [] +enums: [] +objects: [] +functions: + - name: abshk + standards: + - stdc_ext + return_type: short accum + arguments: + - type: short accum + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: abshr + standards: + - stdc_ext + return_type: short fract + arguments: + - type: short fract + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: absk + standards: + - stdc_ext + return_type: accum + arguments: + - type: accum + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: absr + standards: + - stdc_ext + return_type: fract + arguments: + - type: fract + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: abslk + standards: + - stdc_ext + return_type: long accum + arguments: + - type: long accum + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: abslr + standards: + - stdc_ext + return_type: long fract + arguments: + - type: long fract + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: exphk + standards: + - stdc_ext + - llvm_libc_stdfix_ext + return_type: short accum + arguments: + - type: short accum + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: expk + standards: + - stdc_ext + - llvm_libc_stdfix_ext + return_type: accum + arguments: + - type: accum + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: roundhk + standards: + - stdc_ext + return_type: short accum + arguments: + - type: short accum + - type: int + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: roundhr + standards: + - stdc_ext + return_type: short fract + arguments: + - type: short fract + - type: int + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: roundk + standards: + - stdc_ext + return_type: accum + arguments: + - type: accum + - type: int + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: roundr + standards: + - stdc_ext + return_type: fract + arguments: + - type: fract + - type: int + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: roundlk + standards: + - stdc_ext + return_type: long accum + arguments: + - type: long accum + - type: int + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: roundlr + standards: + - stdc_ext + return_type: long fract + arguments: + - type: long fract + - type: int + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: rounduhk + standards: + - stdc_ext + return_type: unsigned short accum + arguments: + - type: unsigned short accum + - type: int + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: rounduhr + standards: + - stdc_ext + return_type: unsigned short fract + arguments: + - type: unsigned short fract + - type: int + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: rounduk + standards: + - stdc_ext + return_type: unsigned accum + arguments: + - type: unsigned accum + - type: int + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: roundur + standards: + - stdc_ext + return_type: unsigned fract + arguments: + - type: unsigned fract + - type: int + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: roundulk + standards: + - stdc_ext + return_type: unsigned long accum + arguments: + - type: unsigned long accum + - type: int + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: roundulr + standards: + - stdc_ext + return_type: unsigned long fract + arguments: + - type: unsigned long fract + - type: int + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: sqrtuhk + standards: + - stdc_ext + - llvm_libc_stdfix_ext + return_type: unsigned short accum + arguments: + - type: unsigned short accum + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: sqrtuhr + standards: + - stdc_ext + - llvm_libc_stdfix_ext + return_type: unsigned short fract + arguments: + - type: unsigned short fract + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: sqrtuk + standards: + - stdc_ext + - llvm_libc_stdfix_ext + return_type: unsigned accum + arguments: + - type: unsigned accum + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: sqrtur + standards: + - stdc_ext + - llvm_libc_stdfix_ext + return_type: unsigned fract + arguments: + - type: unsigned fract + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: sqrtulr + standards: + - stdc_ext + - llvm_libc_stdfix_ext + return_type: unsigned long fract + arguments: + - type: unsigned long fract + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: sqrtulk + standards: llvm_libc_stdfix_ext + return_type: unsigned long accum + arguments: + - type: unsigned long accum + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: uhksqrtus + standards: + - stdc_ext + - llvm_libc_stdfix_ext + return_type: unsigned short accum + arguments: + - type: unsigned short + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: uksqrtui + standards: + - stdc_ext + - llvm_libc_stdfix_ext + return_type: unsigned accum + arguments: + - type: unsigned int + guard: LIBC_COMPILER_HAS_FIXED_POINT diff --git a/libc/newhdrgen/yaml_combined/stdio.yaml b/libc/newhdrgen/yaml_combined/stdio.yaml new file mode 100644 index 00000000000000..928a8d5228c211 --- /dev/null +++ b/libc/newhdrgen/yaml_combined/stdio.yaml @@ -0,0 +1,370 @@ +header: stdio.h +macros: + - macro_name: _IONBF + macro_value: 2 + - macro_name: _IOLBF + macro_value: 1 + - macro_name: _IOFBF + macro_value: 0 + - macro_name: stdout + macro_value: stdout + - macro_name: stdin + macro_value: stdin +types: + - type_name: size_t + - type_name: off_t + - type_name: cookie_io_functions_t + - type_name: FILE +enums: [] +objects: + - object_name: stdin + object_type: FILE * + - object_name: stdout + object_type: FILE * + - object_name: stderr + object_type: FILE * +functions: + - name: remove + standards: + - stdc + return_type: int + arguments: + - type: const char * + - name: rename + standards: + - stdc + return_type: int + arguments: + - type: const char * + - type: const char * + - name: sprintf + standards: + - stdc + return_type: int + arguments: + - type: char * __restrict + - type: const char * __restrict + - type: ... + - name: snprintf + standards: + - stdc + return_type: int + arguments: + - type: char * __restrict + - type: size_t + - type: const char * __restrict + - type: ... + - name: fprintf + standards: + - stdc + return_type: int + arguments: + - type: FILE * __restrict + - type: const char * __restrict + - type: ... + - name: printf + standards: + - stdc + return_type: int + arguments: + - type: const char * __restrict + - type: ... + - name: vsprintf + standards: + - stdc + return_type: int + arguments: + - type: char * __restrict + - type: const char * __restrict + - type: va_list + - name: vsnprintf + standards: + - stdc + return_type: int + arguments: + - type: char * __restrict + - type: size_t + - type: const char * __restrict + - type: va_list + - name: vfprintf + standards: + - stdc + return_type: int + arguments: + - type: FILE * __restrict + - type: const char * __restrict + - type: va_list + - name: vprintf + standards: + - stdc + return_type: int + arguments: + - type: const char * __restrict + - type: va_list + - name: sscanf + standards: + - stdc + return_type: int + arguments: + - type: const char * __restrict + - type: const char * __restrict + - type: ... + - name: scanf + standards: + - stdc + return_type: int + arguments: + - type: const char * __restrict + - type: ... + - name: fscanf + standards: + - stdc + return_type: int + arguments: + - type: FILE * __restrict + - type: const char * __restrict + - type: ... + - name: fileno + standards: + - POSIX + return_type: int + arguments: + - type: FILE * + - name: clearerr + standards: + - stdc + return_type: void + arguments: + - type: FILE * + - name: clearerr_unlocked + standards: + - GNUExtensions + return_type: void + arguments: + - type: FILE * + - name: fclose + standards: + - stdc + return_type: int + arguments: + - type: FILE * + - name: flockfile + standards: + - POSIX + return_type: void + arguments: + - type: FILE * + - name: feof + standards: + - stdc + return_type: int + arguments: + - type: FILE * + - name: feof_unlocked + standards: + - GNUExtensions + return_type: int + arguments: + - type: FILE * + - name: ferror + standards: + - stdc + return_type: int + arguments: + - type: FILE * + - name: ferror_unlocked + standards: + - GNUExtensions + return_type: int + arguments: + - type: FILE * + - name: fgetc + standards: + - stdc + return_type: int + arguments: + - type: FILE * + - name: fgetc_unlocked + standards: + - GNUExtensions + return_type: int + arguments: + - type: FILE * + - name: fgets + standards: + - stdc + return_type: char * + arguments: + - type: char * __restrict + - type: int + - type: FILE * __restrict + - name: fflush + standards: + - stdc + return_type: int + arguments: + - type: FILE * + - name: fopen + standards: + - stdc + return_type: FILE * + arguments: + - type: const char * + - type: const char * + - name: fputc + standards: + - stdc + return_type: int + arguments: + - type: int + - type: FILE * + - name: fputs + standards: + - stdc + return_type: int + arguments: + - type: const char * __restrict + - type: FILE * __restrict + - name: fopencookie + standards: + - GNUExtensions + return_type: FILE * + arguments: + - type: void * + - type: const char * + - type: cookie_io_functions_t + - name: fread + standards: + - stdc + return_type: size_t + arguments: + - type: void * __restrict + - type: size_t + - type: size_t + - type: FILE * __restrict + - name: fread_unlocked + standards: + - GNUExtensions + return_type: size_t + arguments: + - type: void * __restrict + - type: size_t + - type: size_t + - type: FILE * __restrict + - name: fseek + standards: + - stdc + return_type: int + arguments: + - type: FILE * + - type: long + - type: int + - name: ftell + standards: + - stdc + return_type: long + arguments: + - type: FILE * + - name: funlockfile + standards: + - POSIX + return_type: void + arguments: + - type: FILE * + - name: fwrite + standards: + - stdc + return_type: size_t + arguments: + - type: const void * __restrict + - type: size_t + - type: size_t + - type: FILE * __restrict + - name: fwrite_unlocked + standards: + - GNUExtensions + return_type: size_t + arguments: + - type: const void * __restrict + - type: size_t + - type: size_t + - type: FILE * __restrict + - name: getc + standards: + - stdc + return_type: int + arguments: + - type: FILE * + - name: getc_unlocked + standards: + - POSIX + return_type: int + arguments: + - type: FILE * + - name: getchar + standards: + - stdc + return_type: int + arguments: [] + - name: getchar_unlocked + standards: + - POSIX + return_type: int + arguments: [] + - name: putc + standards: + - stdc + return_type: int + arguments: + - type: int + - type: FILE * + - name: putchar + standards: + - stdc + return_type: int + arguments: + - type: int + - name: puts + standards: + - stdc + return_type: int + arguments: + - type: const char * + - name: setbuf + standards: + - stdc + return_type: void + arguments: + - type: FILE * __restrict + - type: char * __restrict + - name: setvbuf + standards: + - stdc + return_type: int + arguments: + - type: FILE * __restrict + - type: char * __restrict + - type: int + - type: size_t + - name: ungetc + standards: + - stdc + return_type: int + arguments: + - type: int + - type: FILE * + - name: stderr + standards: + - stdc + return_type: extern FILE * + arguments: [] + - name: stdin + standards: + - stdc + return_type: extern FILE * + arguments: [] + - name: stdout + standards: + - stdc + return_type: extern FILE * + arguments: [] diff --git a/libc/newhdrgen/yaml_combined/stdlib.yaml b/libc/newhdrgen/yaml_combined/stdlib.yaml new file mode 100644 index 00000000000000..032b47f8291e61 --- /dev/null +++ b/libc/newhdrgen/yaml_combined/stdlib.yaml @@ -0,0 +1,273 @@ +header: stdlib.h +standards: + - stdc +macros: [] +types: + - type_name: __atexithandler_t + - type_name: __qsortrcompare_t + - type_name: __qsortcompare_t + - type_name: __bsearchcompare_t + - type_name: size_t + - type_name: lldiv_t + - type_name: ldiv_t + - type_name: div_t +enums: [] +objects: [] +functions: + - name: abs + standards: + - stdc + return_type: int + arguments: + - type: int + - name: atoi + standards: + - stdc + return_type: int + arguments: + - type: const char * + - name: atof + standards: + - stdc + return_type: double + arguments: + - type: const char * __restrict + - name: atol + standards: + - stdc + return_type: long + arguments: + - type: const char * + - name: atoll + standards: + - stdc + return_type: long long + arguments: + - type: const char * + - name: bsearch + standards: + - stdc + return_type: void * + arguments: + - type: const void * + - type: const void * + - type: size_t + - type: size_t + - type: __bsearchcompare_t + - name: div + standards: + - stdc + return_type: div_t + arguments: + - type: int + - type: int + - name: labs + standards: + - stdc + return_type: long + arguments: + - type: long + - name: ldiv + standards: + - stdc + return_type: ldiv_t + arguments: + - type: long + - type: long + - name: llabs + standards: + - stdc + return_type: long long + arguments: + - type: long long + - name: lldiv + standards: + - stdc + return_type: lldiv_t + arguments: + - type: long long + - type: long long + - name: qsort + standards: + - stdc + return_type: void + arguments: + - type: void * + - type: size_t + - type: size_t + - type: __qsortcompare_t + - name: qsort_r + standards: + - GNUExtensions + return_type: void + arguments: + - type: void * + - type: size_t + - type: size_t + - type: __qsortrcompare_t + - type: void * + - name: rand + standards: + - stdc + return_type: int + arguments: [] + - name: srand + standards: + - stdc + return_type: void + arguments: + - type: unsigned int + - name: strfromd + standards: + - stdc + return_type: int + arguments: + - type: char * __restrict + - type: size_t + - type: const char * __restrict + - type: double + - name: strfromf + standards: + - stdc + return_type: int + arguments: + - type: char * __restrict + - type: size_t + - type: const char * __restrict + - type: float + - name: strfroml + standards: + - stdc + return_type: int + arguments: + - type: char * __restrict + - type: size_t + - type: const char * __restrict + - type: long double + - name: strtod + standards: + - stdc + return_type: double + arguments: + - type: const char * __restrict + - type: char * * __restrict + - name: strtof + standards: + - stdc + return_type: float + arguments: + - type: const char * __restrict + - type: char * * __restrict + - name: strtol + standards: + - stdc + return_type: long + arguments: + - type: const char * __restrict + - type: char * * __restrict + - type: int + - name: strtold + standards: + - stdc + return_type: long double + arguments: + - type: const char * __restrict + - type: char * * __restrict + - name: strtoll + standards: + - stdc + return_type: long long + arguments: + - type: const char * __restrict + - type: char * * __restrict + - type: int + - name: strtoul + standards: + - stdc + return_type: unsigned long + arguments: + - type: const char * __restrict + - type: char * * __restrict + - type: int + - name: strtoull + standards: + - stdc + return_type: unsigned long long + arguments: + - type: const char * __restrict + - type: char * * __restrict + - type: int + - name: malloc + standards: + - stdc + return_type: void * + arguments: + - type: size_t + - name: calloc + standards: + - stdc + return_type: void * + arguments: + - type: size_t + - type: size_t + - name: realloc + standards: + - stdc + return_type: void * + arguments: + - type: void * + - type: size_t + - name: aligned_alloc + standards: + - stdc + return_type: void * + arguments: + - type: size_t + - type: size_t + - name: free + standards: + - stdc + return_type: void + arguments: + - type: void * + - name: _Exit + standards: + - stdc + return_type: _Noreturn void + arguments: + - type: int + - name: abort + standards: + - stdc + return_type: _Noreturn void + arguments: [] + - name: at_quick_exit + standards: + - stdc + return_type: int + arguments: + - type: __atexithandler_t + - name: atexit + standards: + - stdc + return_type: int + arguments: + - type: __atexithandler_t + - name: exit + standards: + - stdc + return_type: _Noreturn void + arguments: + - type: int + - name: getenv + standards: + - stdc + return_type: char * + arguments: + - type: const char * + - name: quick_exit + standards: + - stdc + return_type: _Noreturn void + arguments: + - type: int diff --git a/libc/newhdrgen/yaml_combined/string.yaml b/libc/newhdrgen/yaml_combined/string.yaml new file mode 100644 index 00000000000000..7080a9b7cb3a75 --- /dev/null +++ b/libc/newhdrgen/yaml_combined/string.yaml @@ -0,0 +1,302 @@ +header: string.h +macros: [] +types: + - type_name: size_t +enums: [] +objects: [] +functions: + - name: memcpy + standards: + - stdc + return_type: void * + arguments: + - type: void *__restrict + - type: const void *__restrict + - type: size_t + - name: memmove + standards: + - stdc + return_type: void * + arguments: + - type: void * + - type: const void * + - type: size_t + - name: memcmp + standards: + - stdc + return_type: int + arguments: + - type: const void * + - type: const void * + - type: size_t + - name: memchr + standards: + - stdc + return_type: void * + arguments: + - type: const void * + - type: int + - type: size_t + - name: memset + standards: + - stdc + return_type: void * + arguments: + - type: void * + - type: int + - type: size_t + - name: memset_explicit + standards: + - stdc + return_type: void * + arguments: + - type: void * + - type: int + - type: size_t + - name: strcpy + standards: + - stdc + return_type: char + arguments: + - type: char *__restrict + - type: const char *__restrict + - name: strncpy + standards: + - stdc + return_type: char * + arguments: + - type: char *__restrict + - type: const char *__restrict + - type: size_t + - name: strcat + standards: + - stdc + return_type: char * + arguments: + - type: char *__restrict + - type: const char *__restrict + - name: strncat + standards: + - stdc + return_type: char * + arguments: + - type: char * + - type: const char * + - type: size_t + - name: strcmp + standards: + - stdc + return_type: int + arguments: + - type: const char * + - type: const char * + - name: strcoll + standards: + - stdc + return_type: int + arguments: + - type: const char * + - type: const char * + - name: strncmp + standards: + - stdc + return_type: int + arguments: + - type: const char * + - type: const char * + - type: size_t + - name: strxfrm + standards: + - stdc + return_type: size_t + arguments: + - type: char *__restrict + - type: const char *__restrict + - type: size_t + - name: strchr + standards: + - stdc + return_type: char * + arguments: + - type: const char * + - type: int + - name: strcspn + standards: + - stdc + return_type: size_t + arguments: + - type: const char * + - type: const char * + - name: strdup + return_type: char * + arguments: + - type: const char * + - name: strndup + standards: + - stdc + return_type: char * + arguments: + - type: const char * + - type: size_t + - name: strpbrk + standards: + - stdc + return_type: char * + arguments: + - type: const char * + - type: const char * + - name: strrchr + standards: + - stdc + return_type: char * + arguments: + - type: const char * + - type: int + - name: strspn + standards: + - stdc + return_type: size_t + arguments: + - type: const char * + - type: const char * + - name: strstr + standards: + - stdc + return_type: char * + arguments: + - type: const char * + - type: const char * + - name: strtok + standards: + - stdc + return_type: char * + arguments: + - type: char *__restrict + - type: const char *__restrict + - name: strerror + standards: + - stdc + return_type: char * + arguments: + - type: int + - name: strlen + standards: + - stdc + return_type: size_t + arguments: + - type: const char * + - name: memccpy + standards: + - POSIX + return_type: void * + arguments: + - type: void *__restrict + - type: const void *__restrict + - type: int + - type: size_t + - name: mempcpy + standards: + - POSIX + return_type: void * + arguments: + - type: void *__restrict + - type: const void *__restrict + - type: size_t + - name: stpcpy + standards: + - POSIX + return_type: char * + arguments: + - type: char *__restrict + - type: const char *__restrict + - name: stpncpy + standards: + - POSIX + return_type: char * + arguments: + - type: char *__restrict + - type: const char *__restrict + - type: size_t + - name: strnlen + standards: + - POSIX + return_type: size_t + arguments: + - type: const char * + - type: size_t + - name: strtok_r + standards: + - POSIX + return_type: char * + arguments: + - type: char *__restrict + - type: const char *__restrict + - type: char ** __restrict + - name: strsignal + standards: + - POSIX + return_type: char * + arguments: + - type: int + - name: memmem + standards: + - GNUExtensions + return_type: void * + arguments: + - type: const void * + - type: size_t + - type: const void * + - type: size_t + - name: memrchr + standards: + - GNUExtensions + return_type: void * + arguments: + - type: const void * + - type: int + - type: size_t + - name: strerror_r + standards: + - GNUExtensions + return_type: char * + arguments: + - type: int + - type: char * + - type: size_t + - name: strcasestr + standards: + - GNUExtensions + return_type: char * + arguments: + - type: const char * + - type: const char * + - name: strchrnul + standards: + - GNUExtensions + return_type: char * + arguments: + - type: const char * + - type: int + - name: strlcat + standards: + - BSDExtensions + return_type: size_t + arguments: + - type: char *__restrict + - type: char *__restrict + - type: size_t + - name: strlcpy + standards: + - BSDExtensions + return_type: size_t + arguments: + - type: char *__restrict + - type: char *__restrict + - type: size_t + - name: strsep + standards: + - BSDExtensions + return_type: char * + arguments: + - type: char **__restrict + - type: char *__restrict diff --git a/libc/newhdrgen/yaml_combined/strings.yaml b/libc/newhdrgen/yaml_combined/strings.yaml new file mode 100644 index 00000000000000..3bc0c4a76dd1bf --- /dev/null +++ b/libc/newhdrgen/yaml_combined/strings.yaml @@ -0,0 +1,58 @@ +header: strings.h +macros: [] +types: [] +enums: [] +objects: [] +functions: + - name: bcopy + standards: + - llvm_libc_ext + return_type: void + arguments: + - type: const void * + - type: void * + - type: size_t + - name: bzero + standards: + - llvm_libc_ext + return_type: void + arguments: + - type: void * + - type: size_t + - name: bcmp + standards: + - llvm_libc_ext + return_type: int + arguments: + - type: const void * + - type: const void * + - type: size_t + - name: strcasecmp + standards: + - BSDExtensions + return_type: int + arguments: + - type: const char * + - type: const char * + - name: strncasecmp + standards: + - BSDExtensions + return_type: int + arguments: + - type: const char * + - type: const char * + - type: size_t + - name: index + standards: + - BSDExtensions + return_type: char * + arguments: + - type: const char * + - type: int + - name: rindex + standards: + - BSDExtensions + return_type: char * + arguments: + - type: const char * + - type: int diff --git a/libc/newhdrgen/yaml_combined/sys_mman.yaml b/libc/newhdrgen/yaml_combined/sys_mman.yaml new file mode 100644 index 00000000000000..7b858db2de11a7 --- /dev/null +++ b/libc/newhdrgen/yaml_combined/sys_mman.yaml @@ -0,0 +1,118 @@ +#known as sys/mman in POSIX +header: sys-mman.h +standards: POSIX +macros: [] +macros: [] +types: + - type_name: mode_t + - type_name: size_t + - type_name: off_t +enums: [] +objects: [] +functions: + - name: madvise + standards: + - POSIX + return_type: int + arguments: + - type: void * + - type: size_t + - type: int + - name: mmap + standards: + - POSIX + return_type: void * + arguments: + - type: void * + - type: size_t + - type: int + - type: int + - type: int + - type: off_t + - name: mprotect + standards: + - POSIX + return_type: int + arguments: + - type: void * + - type: size_t + - type: int + - name: munmap + standards: + - POSIX + return_type: int + arguments: + - type: void * + - type: size_t + - name: POSIX_madvise + standards: + - POSIX + return_type: int + arguments: + - type: void * + - type: size_t + - type: int + # this is a linux function + - name: mincore + standards: + - Linux + return_type: int + arguments: + - type: void * + - type: size_t + - type: unsigned char * + - name: mlock + standards: + - POSIX + return_type: int + arguments: + - type: void * + - type: size_t + - name: mlock2 + standards: + - Linux + return_type: int + arguments: + - type: void * + - type: size_t + - type: unsigned int + - name: munlock + standards: POSIX + return_type: int + arguments: + - type: void * + - type: size_t + - name: mlockall + standards: + -POSIX + return_type: int + arguments: + - type: int + - name: munlockall + standards: + - POSIX + return_type: int + arguments: [] + - name: msync + standards: + - POSIX + return_type: int + arguments: + - type: void * + - type: size_t + - type: int + - name: shm_open + standards: + - POSIX + return_type: int + arguments: + - type: const char * + - type: int + - type: mode_t + - name: shm_unlink + standards: + - POSIX + return_type: int + arguments: + - type: const char * + \ No newline at end of file diff --git a/libc/newhdrgen/yaml_combined/sys_wait.yaml b/libc/newhdrgen/yaml_combined/sys_wait.yaml new file mode 100644 index 00000000000000..56a6066e925d68 --- /dev/null +++ b/libc/newhdrgen/yaml_combined/sys_wait.yaml @@ -0,0 +1,33 @@ +header: sys-wait.h #sys/wait.h +macros: [] +types: + - type_name: siginfo_t + - type_name: struct_rusage + - type_name: pid_t +enums: [] +objects: [] +functions: + - name: wait + standards: + - POSIX + return_type: pid_t + arguments: + - type: int * + - name: wait4 + standards: + - BSDExtensions + - POSIX + return_type: pid_t + arguments: + - type: pid_t + - type: int * + - type: int + - type: struct rusage * + - name: waitpid + standards: + - POSIX + return_type: pid_t + arguments: + - type: pid_t + - type: int * + - type: int diff --git a/libc/newhdrgen/yaml_combined/time.yaml b/libc/newhdrgen/yaml_combined/time.yaml new file mode 100644 index 00000000000000..fbdf1877924846 --- /dev/null +++ b/libc/newhdrgen/yaml_combined/time.yaml @@ -0,0 +1,83 @@ +header: time.h +macros: [] +types: + - type_name: struct_timeval + - type_name: clockid_t + - type_name: struct_timespec + - type_name: struct_tm + - type_name: time_t + - type_name: clock_t +enums: [] +objects: [] +functions: + - name: asctime + standard: + - stdc + return_type: char * + arguments: + - type: struct tm * + - name: asctime_r + standard: + - stdc + return_type: char * + arguments: + - type: struct tm * + - type: char * + - name: clock_gettime + standard: + - POSIX + return_type: int + arguments: + - type: clockid_t + - type: struct timespec * + - name: clock + standard: + - stdc + return_type: clock_t + arguments: [] + - name: difftime + standard: + - stdc + return_type: double + arguments: + - type: time_t + - type: time_t + - name: gettimeofday + standard: + - POSIX + return_type: int + arguments: + - type: struct timeval * + - type: void * + - name: gmtime + standard: + - stdc + return_type: struct tm * + arguments: + - type: time_t * + - name: gmtime_r + standard: + - stdc + return_type: struct tm * + arguments: + - type: time_t * + - type: struct tm * + - name: mktime + standard: + - stdc + return_type: time_t + arguments: + - type: struct tm * + - name: nanosleep + standard: + - POSIX + return_type: int + arguments: + - type: const struct timespec * + - type: struct timespec * + - name: time + standard: + - stdc + return_type: time_t + arguments: + - type: time_t * diff --git a/libc/newhdrgen/yaml_to_classes.py b/libc/newhdrgen/yaml_to_classes.py new file mode 100644 index 00000000000000..7159dd9cc88817 --- /dev/null +++ b/libc/newhdrgen/yaml_to_classes.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python +# +# ===- Generate headers for libc functions -------------------*- python -*--==# +# +# 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 +# +# ==-------------------------------------------------------------------------==# + + +import yaml +import re +import argparse + +from pathlib import Path +from header import HeaderFile +from class_implementation.classes.macro import Macro +from class_implementation.classes.type import Type +from class_implementation.classes.function import Function +from class_implementation.classes.include import Include +from class_implementation.classes.enumeration import Enumeration +from class_implementation.classes.object import Object + + +def yaml_to_classes(yaml_data): + """ + Convert YAML data to header classes. + + Args: + yaml_data: The YAML data containing header specifications. + + Returns: + HeaderFile: An instance of HeaderFile populated with the data. + """ + header_name = yaml_data.get("header") + header = HeaderFile(header_name) + + for macro_data in yaml_data.get("macros", []): + header.add_macro(Macro(macro_data["macro_name"], macro_data["macro_value"])) + + for type_data in yaml_data.get("types", []): + header.add_type(Type(type_data["type_name"])) + + for enum_data in yaml_data.get("enums", []): + header.add_enumeration( + Enumeration(enum_data["name"], enum_data.get("value", None)) + ) + + for function_data in yaml_data.get("functions", []): + arguments = [arg["type"] for arg in function_data["arguments"]] + guard = function_data.get("guard", None) + attributes = function_data.get("attributes", None) + standards = (function_data.get("standards", None),) + header.add_function( + Function( + standards, + function_data["return_type"], + function_data["name"], + arguments, + guard, + attributes, + ) + ) + + for object_data in yaml_data.get("objects", []): + header.add_object( + Object(object_data["object_name"], object_data["object_type"]) + ) + + for include_data in yaml_data.get("includes", []): + header.add_include(Include(include_data)) + + return header + + +def load_yaml_file(yaml_file): + """ + Load YAML file and convert it to header classes. + + Args: + yaml_file: The path to the YAML file. + + Returns: + HeaderFile: An instance of HeaderFile populated with the data from the YAML file. + """ + with open(yaml_file, "r") as f: + yaml_data = yaml.safe_load(f) + return yaml_to_classes(yaml_data) + + +def fill_public_api(header_str, h_def_content): + """ + Replace the %%public_api() placeholder in the .h.def content with the generated header content. + + Args: + header_str: The generated header string. + h_def_content: The content of the .h.def file. + + Returns: + The final header content with the public API filled in. + """ + return h_def_content.replace("%%public_api()", header_str, 1) + + +def main(yaml_file, h_def_file, output_dir): + """ + Main function to generate header files from YAML and .h.def templates. + + Args: + yaml_file: Path to the YAML file containing header specification. + h_def_file: Path to the .h.def template file. + output_dir: Directory to output the generated header file. + """ + + header = load_yaml_file(yaml_file) + + with open(h_def_file, "r") as f: + h_def_content = f.read() + + header_str = str(header) + final_header_content = fill_public_api(header_str, h_def_content) + + output_file_name = Path(h_def_file).stem + output_file_path = Path(output_dir) / output_file_name + + with open(output_file_path, "w") as f: + f.write(final_header_content) + + print(f"Generated header file: {output_file_path}") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Generate header files from YAML and .h.def templates" + ) + parser.add_argument( + "yaml_file", help="Path to the YAML file containing header specification" + ) + parser.add_argument("h_def_file", help="Path to the .h.def template file") + parser.add_argument( + "--output_dir", + default=".", + help="Directory to output the generated header file", + ) + args = parser.parse_args() + + main(args.yaml_file, args.h_def_file, args.output_dir) diff --git a/libc/spec/llvm_libc_ext.td b/libc/spec/llvm_libc_ext.td index ca61d4ef371a2e..74a90a4d041321 100644 --- a/libc/spec/llvm_libc_ext.td +++ b/libc/spec/llvm_libc_ext.td @@ -51,8 +51,25 @@ def LLVMLibcExt : StandardSpec<"llvm_libc_ext"> { ] >; + HeaderSpec Math = HeaderSpec< + "math.h", + [], // Macros + [], // Types + [], // Enumerations + [ + GuardedFunctionSpec<"f16div", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, + GuardedFunctionSpec<"f16divf", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, + GuardedFunctionSpec<"f16divl", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, + + GuardedFunctionSpec<"f16sqrt", RetValSpec, [ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, + GuardedFunctionSpec<"f16sqrtf", RetValSpec, [ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, + GuardedFunctionSpec<"f16sqrtl", RetValSpec, [ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, + ] + >; + let Headers = [ Assert, + Math, Sched, Strings, ]; diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td index 73d00c3e33aa9c..6e59062dde7273 100644 --- a/libc/spec/stdc.td +++ b/libc/spec/stdc.td @@ -477,7 +477,10 @@ def StdC : StandardSpec<"stdc"> { FunctionSpec<"fma", RetValSpec, [ArgSpec, ArgSpec, ArgSpec]>, FunctionSpec<"fmaf", RetValSpec, [ArgSpec, ArgSpec, ArgSpec]>, + GuardedFunctionSpec<"f16fma", RetValSpec, [ArgSpec, ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, GuardedFunctionSpec<"f16fmaf", RetValSpec, [ArgSpec, ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, + GuardedFunctionSpec<"f16fmal", RetValSpec, [ArgSpec, ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, + GuardedFunctionSpec<"f16fmaf128", RetValSpec, [ArgSpec, ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16_AND_FLOAT128">, FunctionSpec<"fmod", RetValSpec, [ArgSpec, ArgSpec]>, FunctionSpec<"fmodf", RetValSpec, [ArgSpec, ArgSpec]>, @@ -726,7 +729,9 @@ def StdC : StandardSpec<"stdc"> { GuardedFunctionSpec<"setpayloadsigf16", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, - GuardedFunctionSpec<"f16sqrtf", RetValSpec, [ArgSpec], "LIBC_TYPES_HAS_FLOAT16">, + GuardedFunctionSpec<"f16divf128", RetValSpec, [ArgSpec, ArgSpec], "LIBC_TYPES_HAS_FLOAT16_AND_FLOAT128">, + + GuardedFunctionSpec<"f16sqrtf128", RetValSpec, [ArgSpec], "LIBC_TYPES_HAS_FLOAT16_AND_FLOAT128">, ] >; diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt index 4ede74206e9737..84c5f802710c4a 100644 --- a/libc/src/__support/FPUtil/CMakeLists.txt +++ b/libc/src/__support/FPUtil/CMakeLists.txt @@ -154,7 +154,6 @@ add_header_library( HDRS multiply_add.h DEPENDS - .fma libc.src.__support.common ) @@ -199,6 +198,7 @@ add_header_library( HDRS dyadic_float.h DEPENDS + .fenv_impl .fp_bits .multiply_add libc.src.__support.CPP.type_traits diff --git a/libc/src/__support/FPUtil/NearestIntegerOperations.h b/libc/src/__support/FPUtil/NearestIntegerOperations.h index 741e24aa519a79..cff32938229d02 100644 --- a/libc/src/__support/FPUtil/NearestIntegerOperations.h +++ b/libc/src/__support/FPUtil/NearestIntegerOperations.h @@ -199,7 +199,8 @@ round_using_specific_rounding_mode(T x, int rnd) { return x; StorageType trim_value = - bits.get_mantissa() & ((StorageType(1) << trim_size) - 1); + bits.get_mantissa() & + static_cast(((StorageType(1) << trim_size) - 1)); StorageType half_value = static_cast((StorageType(1) << (trim_size - 1))); // If exponent is 0, trimSize will be equal to the mantissa width, and diff --git a/libc/src/__support/FPUtil/double_double.h b/libc/src/__support/FPUtil/double_double.h index b9490b52f6b41e..3d16a3cce3a99c 100644 --- a/libc/src/__support/FPUtil/double_double.h +++ b/libc/src/__support/FPUtil/double_double.h @@ -21,12 +21,22 @@ using DoubleDouble = LIBC_NAMESPACE::NumberPair; // The output of Dekker's FastTwoSum algorithm is correct, i.e.: // r.hi + r.lo = a + b exactly // and |r.lo| < eps(r.lo) -// if ssumption: |a| >= |b|, or a = 0. +// Assumption: |a| >= |b|, or a = 0. +template LIBC_INLINE constexpr DoubleDouble exact_add(double a, double b) { DoubleDouble r{0.0, 0.0}; - r.hi = a + b; - double t = r.hi - a; - r.lo = b - t; + if constexpr (FAST2SUM) { + r.hi = a + b; + double t = r.hi - a; + r.lo = b - t; + } else { + r.hi = a + b; + double t1 = r.hi - a; + double t2 = r.hi - t1; + double t3 = b - t1; + double t4 = a - t2; + r.lo = t3 + t4; + } return r; } @@ -40,15 +50,20 @@ LIBC_INLINE constexpr DoubleDouble add(const DoubleDouble &a, // Assumption: |a.hi| >= |b| LIBC_INLINE constexpr DoubleDouble add(const DoubleDouble &a, double b) { - DoubleDouble r = exact_add(a.hi, b); + DoubleDouble r = exact_add(a.hi, b); return exact_add(r.hi, r.lo + a.lo); } -// Velkamp's Splitting for double precision. -LIBC_INLINE constexpr DoubleDouble split(double a) { +// Veltkamp's Splitting for double precision. +// Note: This is proved to be correct for all rounding modes: +// Zimmermann, P., "Note on the Veltkamp/Dekker Algorithms with Directed +// Roundings," https://inria.hal.science/hal-04480440. +// Default splitting constant = 2^ceil(prec(double)/2) + 1 = 2^27 + 1. +template LIBC_INLINE constexpr DoubleDouble split(double a) { DoubleDouble r{0.0, 0.0}; - // Splitting constant = 2^ceil(prec(double)/2) + 1 = 2^27 + 1. - constexpr double C = 0x1.0p27 + 1.0; + // CN = 2^N. + constexpr double CN = static_cast(1 << N); + constexpr double C = CN + 1.0; double t1 = C * a; double t2 = a - t1; r.hi = t1 + t2; @@ -56,6 +71,14 @@ LIBC_INLINE constexpr DoubleDouble split(double a) { return r; } +// Note: When FMA instruction is not available, the `exact_mult` function is +// only correct for round-to-nearest mode. See: +// Zimmermann, P., "Note on the Veltkamp/Dekker Algorithms with Directed +// Roundings," https://inria.hal.science/hal-04480440. +// Using Theorem 1 in the paper above, without FMA instruction, if we restrict +// the generated constants to precision <= 51, and splitting it by 2^28 + 1, +// then a * b = r.hi + r.lo is exact for all rounding modes. +template LIBC_INLINE DoubleDouble exact_mult(double a, double b) { DoubleDouble r{0.0, 0.0}; @@ -65,7 +88,13 @@ LIBC_INLINE DoubleDouble exact_mult(double a, double b) { #else // Dekker's Product. DoubleDouble as = split(a); - DoubleDouble bs = split(b); + DoubleDouble bs; + + if constexpr (NO_FMA_ALL_ROUNDINGS) + bs = split<28>(b); + else + bs = split(b); + r.hi = a * b; double t1 = as.hi * bs.hi - r.hi; double t2 = as.hi * bs.lo + t1; @@ -82,9 +111,10 @@ LIBC_INLINE DoubleDouble quick_mult(double a, const DoubleDouble &b) { return r; } +template LIBC_INLINE DoubleDouble quick_mult(const DoubleDouble &a, const DoubleDouble &b) { - DoubleDouble r = exact_mult(a.hi, b.hi); + DoubleDouble r = exact_mult(a.hi, b.hi); double t1 = multiply_add(a.hi, b.lo, r.lo); double t2 = multiply_add(a.lo, b.hi, t1); r.lo = t2; diff --git a/libc/src/__support/FPUtil/dyadic_float.h b/libc/src/__support/FPUtil/dyadic_float.h index 63cb98351201f6..8d44a98a693f87 100644 --- a/libc/src/__support/FPUtil/dyadic_float.h +++ b/libc/src/__support/FPUtil/dyadic_float.h @@ -9,6 +9,7 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_DYADIC_FLOAT_H #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_DYADIC_FLOAT_H +#include "FEnvImpl.h" #include "FPBits.h" #include "multiply_add.h" #include "src/__support/CPP/type_traits.h" @@ -86,11 +87,11 @@ template struct DyadicFloat { // Assume that it is already normalized. // Output is rounded correctly with respect to the current rounding mode. - template && (FPBits::FRACTION_LEN < Bits), void>> - LIBC_INLINE explicit constexpr operator T() const { + LIBC_INLINE constexpr T as() const { if (LIBC_UNLIKELY(mantissa.is_zero())) return FPBits::zero(sign).get_val(); @@ -107,7 +108,17 @@ template struct DyadicFloat { T d_hi = FPBits::create_value(sign, 2 * FPBits::EXP_BIAS, IMPLICIT_MASK) .get_val(); - return T(2) * d_hi; + // volatile prevents constant propagation that would result in infinity + // always being returned no matter the current rounding mode. + volatile T two = static_cast(2.0); + T r = two * d_hi; + + // TODO: Whether rounding down the absolute value to max_normal should + // also raise FE_OVERFLOW and set ERANGE is debatable. + if (ShouldSignalExceptions && FPBits(r).is_inf()) + set_errno_if_required(ERANGE); + + return r; } bool denorm = false; @@ -145,13 +156,13 @@ template struct DyadicFloat { // d_lo is denormal, but the output is normal. int scale_up_exponent = 1 - exp_lo; T scale_up_factor = - FPBits::create_value(sign, + FPBits::create_value(Sign::POS, static_cast( FPBits::EXP_BIAS + scale_up_exponent), IMPLICIT_MASK) .get_val(); T scale_down_factor = - FPBits::create_value(sign, + FPBits::create_value(Sign::POS, static_cast( FPBits::EXP_BIAS - scale_up_exponent), IMPLICIT_MASK) @@ -179,10 +190,20 @@ template struct DyadicFloat { output_bits_t clear_exp = static_cast( output_bits_t(exp_hi) << FPBits::SIG_LEN); output_bits_t r_bits = FPBits(r).uintval() - clear_exp; + if (!(r_bits & FPBits::EXP_MASK)) { // Output is denormal after rounding, clear the implicit bit for 80-bit // long double. r_bits -= IMPLICIT_MASK; + + // TODO: IEEE Std 754-2019 lets implementers choose whether to check for + // "tininess" before or after rounding for base-2 formats, as long as + // the same choice is made for all operations. Our choice to check after + // rounding might not be the same as the hardware's. + if (ShouldSignalExceptions && round_and_sticky) { + set_errno_if_required(ERANGE); + raise_except_if_required(FE_UNDERFLOW); + } } return FPBits(r_bits).get_val(); @@ -191,6 +212,14 @@ template struct DyadicFloat { return r; } + template && + (FPBits::FRACTION_LEN < Bits), + void>> + LIBC_INLINE explicit constexpr operator T() const { + return as(); + } + LIBC_INLINE explicit constexpr operator MantissaType() const { if (mantissa.is_zero()) return 0; @@ -278,11 +307,11 @@ LIBC_INLINE constexpr DyadicFloat quick_add(DyadicFloat a, // don't need to normalize the inputs again in this function. If the inputs are // not normalized, the results might lose precision significantly. template -LIBC_INLINE constexpr DyadicFloat quick_mul(DyadicFloat a, - DyadicFloat b) { +LIBC_INLINE constexpr DyadicFloat quick_mul(const DyadicFloat &a, + const DyadicFloat &b) { DyadicFloat result; result.sign = (a.sign != b.sign) ? Sign::NEG : Sign::POS; - result.exponent = a.exponent + b.exponent + int(Bits); + result.exponent = a.exponent + b.exponent + static_cast(Bits); if (!(a.mantissa.is_zero() || b.mantissa.is_zero())) { result.mantissa = a.mantissa.quick_mul_hi(b.mantissa); @@ -309,7 +338,7 @@ multiply_add(const DyadicFloat &a, const DyadicFloat &b, // Simple exponentiation implementation for printf. Only handles positive // exponents, since division isn't implemented. template -LIBC_INLINE constexpr DyadicFloat pow_n(DyadicFloat a, +LIBC_INLINE constexpr DyadicFloat pow_n(const DyadicFloat &a, uint32_t power) { DyadicFloat result = 1.0; DyadicFloat cur_power = a; @@ -325,7 +354,7 @@ LIBC_INLINE constexpr DyadicFloat pow_n(DyadicFloat a, } template -LIBC_INLINE constexpr DyadicFloat mul_pow_2(DyadicFloat a, +LIBC_INLINE constexpr DyadicFloat mul_pow_2(const DyadicFloat &a, int32_t pow_2) { DyadicFloat result = a; result.exponent += pow_2; diff --git a/libc/src/__support/FPUtil/generic/CMakeLists.txt b/libc/src/__support/FPUtil/generic/CMakeLists.txt index a8a95ba3f15ffa..fb49fd00395371 100644 --- a/libc/src/__support/FPUtil/generic/CMakeLists.txt +++ b/libc/src/__support/FPUtil/generic/CMakeLists.txt @@ -8,6 +8,7 @@ add_header_library( libc.src.__support.common libc.src.__support.CPP.bit libc.src.__support.CPP.type_traits + libc.src.__support.FPUtil.dyadic_float libc.src.__support.FPUtil.fenv_impl libc.src.__support.FPUtil.fp_bits libc.src.__support.FPUtil.rounding_mode @@ -24,6 +25,8 @@ add_header_library( libc.src.__support.CPP.bit libc.src.__support.CPP.limits libc.src.__support.CPP.type_traits + libc.src.__support.FPUtil.basic_operations + libc.src.__support.FPUtil.dyadic_float libc.src.__support.FPUtil.fenv_impl libc.src.__support.FPUtil.fp_bits libc.src.__support.FPUtil.rounding_mode @@ -45,3 +48,20 @@ add_header_library( libc.src.__support.FPUtil.rounding_mode libc.src.__support.macros.optimization ) + +add_header_library( + div + HDRS + div.h + DEPENDS + libc.hdr.errno_macros + libc.hdr.fenv_macros + libc.src.__support.CPP.bit + libc.src.__support.CPP.type_traits + libc.src.__support.FPUtil.basic_operations + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.dyadic_float + libc.src.__support.macros.attributes + libc.src.__support.macros.optimization +) diff --git a/libc/src/__support/FPUtil/generic/FMA.h b/libc/src/__support/FPUtil/generic/FMA.h index 71b150758d4191..72341a129dcb58 100644 --- a/libc/src/__support/FPUtil/generic/FMA.h +++ b/libc/src/__support/FPUtil/generic/FMA.h @@ -12,7 +12,9 @@ #include "src/__support/CPP/bit.h" #include "src/__support/CPP/limits.h" #include "src/__support/CPP/type_traits.h" +#include "src/__support/FPUtil/BasicOperations.h" #include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/dyadic_float.h" #include "src/__support/FPUtil/rounding_mode.h" #include "src/__support/big_int.h" #include "src/__support/macros/attributes.h" // LIBC_INLINE @@ -106,20 +108,52 @@ LIBC_INLINE cpp::enable_if_t && sizeof(OutType) <= sizeof(InType), OutType> fma(InType x, InType y, InType z) { - using OutFPBits = fputil::FPBits; + using OutFPBits = FPBits; using OutStorageType = typename OutFPBits::StorageType; - using InFPBits = fputil::FPBits; + using InFPBits = FPBits; using InStorageType = typename InFPBits::StorageType; constexpr int IN_EXPLICIT_MANT_LEN = InFPBits::FRACTION_LEN + 1; constexpr size_t PROD_LEN = 2 * IN_EXPLICIT_MANT_LEN; constexpr size_t TMP_RESULT_LEN = cpp::bit_ceil(PROD_LEN + 1); using TmpResultType = UInt; + using DyadicFloat = DyadicFloat; - constexpr size_t EXTRA_FRACTION_LEN = - TMP_RESULT_LEN - 1 - OutFPBits::FRACTION_LEN; - constexpr TmpResultType EXTRA_FRACTION_STICKY_MASK = - (TmpResultType(1) << (EXTRA_FRACTION_LEN - 1)) - 1; + InFPBits x_bits(x), y_bits(y), z_bits(z); + + if (LIBC_UNLIKELY(x_bits.is_nan() || y_bits.is_nan() || z_bits.is_nan())) { + if (x_bits.is_nan() || y_bits.is_nan()) { + if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan() || + z_bits.is_signaling_nan()) + raise_except_if_required(FE_INVALID); + + if (x_bits.is_quiet_nan()) { + InStorageType x_payload = static_cast(getpayload(x)); + if ((x_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0) + return OutFPBits::quiet_nan(x_bits.sign(), + static_cast(x_payload)) + .get_val(); + } + + if (y_bits.is_quiet_nan()) { + InStorageType y_payload = static_cast(getpayload(y)); + if ((y_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0) + return OutFPBits::quiet_nan(y_bits.sign(), + static_cast(y_payload)) + .get_val(); + } + + if (z_bits.is_quiet_nan()) { + InStorageType z_payload = static_cast(getpayload(z)); + if ((z_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0) + return OutFPBits::quiet_nan(z_bits.sign(), + static_cast(z_payload)) + .get_val(); + } + + return OutFPBits::quiet_nan().get_val(); + } + } if (LIBC_UNLIKELY(x == 0 || y == 0 || z == 0)) return static_cast(x * y + z); @@ -142,7 +176,9 @@ fma(InType x, InType y, InType z) { z *= InType(InStorageType(1) << InFPBits::FRACTION_LEN); } - InFPBits x_bits(x), y_bits(y), z_bits(z); + x_bits = InFPBits(x); + y_bits = InFPBits(y); + z_bits = InFPBits(z); const Sign z_sign = z_bits.sign(); Sign prod_sign = (x_bits.sign() == y_bits.sign()) ? Sign::POS : Sign::NEG; x_exp += x_bits.get_biased_exponent(); @@ -182,7 +218,6 @@ fma(InType x, InType y, InType z) { constexpr int RESULT_MIN_LEN = PROD_LEN - InFPBits::FRACTION_LEN; z_mant <<= RESULT_MIN_LEN; int z_lsb_exp = z_exp - (InFPBits::FRACTION_LEN + RESULT_MIN_LEN); - bool round_bit = false; bool sticky_bits = false; bool z_shifted = false; @@ -221,85 +256,18 @@ fma(InType x, InType y, InType z) { } } - OutStorageType result = 0; - int r_exp = 0; // Unbiased exponent of the result - - int round_mode = fputil::quick_get_round(); - - // Normalize the result. - if (prod_mant != 0) { - int lead_zeros = cpp::countl_zero(prod_mant); - // Move the leading 1 to the most significant bit. - prod_mant <<= lead_zeros; - prod_lsb_exp -= lead_zeros; - r_exp = prod_lsb_exp + (cpp::numeric_limits::digits - 1) - - InFPBits::EXP_BIAS + OutFPBits::EXP_BIAS; - - if (r_exp > 0) { - // The result is normal. We will shift the mantissa to the right by the - // amount of extra bits compared to the length of the explicit mantissa in - // the output type. The rounding bit then becomes the highest bit that is - // shifted out, and the following lower bits are merged into sticky bits. - round_bit = - (prod_mant & (TmpResultType(1) << (EXTRA_FRACTION_LEN - 1))) != 0; - sticky_bits |= (prod_mant & EXTRA_FRACTION_STICKY_MASK) != 0; - result = static_cast(prod_mant >> EXTRA_FRACTION_LEN); - } else { - if (r_exp < -OutFPBits::FRACTION_LEN) { - // The result is smaller than 1/2 of the smallest denormal number. - sticky_bits = true; // since the result is non-zero. - result = 0; - } else { - // The result is denormal. - TmpResultType mask = TmpResultType(1) << (EXTRA_FRACTION_LEN - r_exp); - round_bit = (prod_mant & mask) != 0; - sticky_bits |= (prod_mant & (mask - 1)) != 0; - if (r_exp > -OutFPBits::FRACTION_LEN) - result = static_cast( - prod_mant >> (EXTRA_FRACTION_LEN + 1 - r_exp)); - else - result = 0; - } - - r_exp = 0; - } - } else { + if (prod_mant == 0) { // When there is exact cancellation, i.e., x*y == -z exactly, return -0.0 if // rounding downward and +0.0 for other rounding modes. - if (round_mode == FE_DOWNWARD) + if (quick_get_round() == FE_DOWNWARD) prod_sign = Sign::NEG; else prod_sign = Sign::POS; } - // Finalize the result. - if (LIBC_UNLIKELY(r_exp >= OutFPBits::MAX_BIASED_EXPONENT)) { - if ((round_mode == FE_TOWARDZERO) || - (round_mode == FE_UPWARD && prod_sign.is_neg()) || - (round_mode == FE_DOWNWARD && prod_sign.is_pos())) { - return OutFPBits::max_normal(prod_sign).get_val(); - } - return OutFPBits::inf(prod_sign).get_val(); - } - - // Remove hidden bit and append the exponent field and sign bit. - result = static_cast( - (result & OutFPBits::FRACTION_MASK) | - (static_cast(r_exp) << OutFPBits::FRACTION_LEN)); - if (prod_sign.is_neg()) - result |= OutFPBits::SIGN_MASK; - - // Rounding. - if (round_mode == FE_TONEAREST) { - if (round_bit && (sticky_bits || ((result & 1) != 0))) - ++result; - } else if ((round_mode == FE_UPWARD && prod_sign.is_pos()) || - (round_mode == FE_DOWNWARD && prod_sign.is_neg())) { - if (round_bit || sticky_bits) - ++result; - } - - return cpp::bit_cast(result); + DyadicFloat result(prod_sign, prod_lsb_exp - InFPBits::EXP_BIAS, prod_mant); + result.mantissa |= static_cast(sticky_bits); + return result.template as(); } } // namespace generic diff --git a/libc/src/__support/FPUtil/generic/div.h b/libc/src/__support/FPUtil/generic/div.h new file mode 100644 index 00000000000000..0d84aa8d8bccc1 --- /dev/null +++ b/libc/src/__support/FPUtil/generic/div.h @@ -0,0 +1,123 @@ +//===-- Division of IEEE 754 floating-point numbers -------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_GENERIC_DIV_H +#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_GENERIC_DIV_H + +#include "hdr/errno_macros.h" +#include "hdr/fenv_macros.h" +#include "src/__support/CPP/bit.h" +#include "src/__support/CPP/type_traits.h" +#include "src/__support/FPUtil/BasicOperations.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/dyadic_float.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/optimization.h" + +namespace LIBC_NAMESPACE::fputil::generic { + +template +LIBC_INLINE cpp::enable_if_t && + cpp::is_floating_point_v && + sizeof(OutType) <= sizeof(InType), + OutType> +div(InType x, InType y) { + using OutFPBits = FPBits; + using OutStorageType = typename OutFPBits::StorageType; + using InFPBits = FPBits; + using InStorageType = typename InFPBits::StorageType; + using DyadicFloat = + DyadicFloat(InFPBits::FRACTION_LEN))>; + + InFPBits x_bits(x); + InFPBits y_bits(y); + + Sign result_sign = x_bits.sign() == y_bits.sign() ? Sign::POS : Sign::NEG; + + if (LIBC_UNLIKELY(x_bits.is_inf_or_nan() || y_bits.is_inf_or_nan() || + x_bits.is_zero() || y_bits.is_zero())) { + if (x_bits.is_nan() || y_bits.is_nan()) { + if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan()) + raise_except_if_required(FE_INVALID); + + if (x_bits.is_quiet_nan()) { + InStorageType x_payload = static_cast(getpayload(x)); + if ((x_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0) + return OutFPBits::quiet_nan(x_bits.sign(), + static_cast(x_payload)) + .get_val(); + } + + if (y_bits.is_quiet_nan()) { + InStorageType y_payload = static_cast(getpayload(y)); + if ((y_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0) + return OutFPBits::quiet_nan(y_bits.sign(), + static_cast(y_payload)) + .get_val(); + } + + return OutFPBits::quiet_nan().get_val(); + } + + if (x_bits.is_inf()) { + if (y_bits.is_inf()) { + set_errno_if_required(EDOM); + raise_except_if_required(FE_INVALID); + return OutFPBits::quiet_nan().get_val(); + } + + return OutFPBits::inf(result_sign).get_val(); + } + + if (y_bits.is_inf()) + return OutFPBits::inf(result_sign).get_val(); + + if (y_bits.is_zero()) { + if (x_bits.is_zero()) { + raise_except_if_required(FE_INVALID); + return OutFPBits::quiet_nan().get_val(); + } + + raise_except_if_required(FE_DIVBYZERO); + return OutFPBits::inf(result_sign).get_val(); + } + + if (x_bits.is_zero()) + return OutFPBits::zero(result_sign).get_val(); + } + + DyadicFloat xd(x); + DyadicFloat yd(y); + + // Number of iterations = full output precision + 1 rounding bit + 1 potential + // leading 0. + constexpr int NUM_ITERS = OutFPBits::FRACTION_LEN + 3; + int result_exp = xd.exponent - yd.exponent - (NUM_ITERS - 1); + + InStorageType q = 0; + InStorageType r = static_cast(xd.mantissa >> 2); + InStorageType yd_mant_in = static_cast(yd.mantissa >> 1); + + for (int i = 0; i < NUM_ITERS; ++i) { + q <<= 1; + r <<= 1; + if (r >= yd_mant_in) { + q += 1; + r -= yd_mant_in; + } + } + + DyadicFloat result(result_sign, result_exp, q); + result.mantissa |= static_cast(r != 0); + return result.template as(); +} + +} // namespace LIBC_NAMESPACE::fputil::generic + +#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_GENERIC_DIV_H diff --git a/libc/src/__support/FPUtil/generic/sqrt.h b/libc/src/__support/FPUtil/generic/sqrt.h index d6e894fdfe021b..1b713796f74991 100644 --- a/libc/src/__support/FPUtil/generic/sqrt.h +++ b/libc/src/__support/FPUtil/generic/sqrt.h @@ -14,7 +14,7 @@ #include "src/__support/CPP/type_traits.h" #include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/rounding_mode.h" +#include "src/__support/FPUtil/dyadic_float.h" #include "src/__support/common.h" #include "src/__support/uint128.h" @@ -78,16 +78,14 @@ sqrt(InType x) { return x86::sqrt(x); } else { // IEEE floating points formats. - using OutFPBits = typename fputil::FPBits; - using OutStorageType = typename OutFPBits::StorageType; - using InFPBits = typename fputil::FPBits; + using OutFPBits = FPBits; + using InFPBits = FPBits; using InStorageType = typename InFPBits::StorageType; + using DyadicFloat = + DyadicFloat(InFPBits::STORAGE_LEN))>; + constexpr InStorageType ONE = InStorageType(1) << InFPBits::FRACTION_LEN; constexpr auto FLT_NAN = OutFPBits::quiet_nan().get_val(); - constexpr int EXTRA_FRACTION_LEN = - InFPBits::FRACTION_LEN - OutFPBits::FRACTION_LEN; - constexpr InStorageType EXTRA_FRACTION_MASK = - (InStorageType(1) << EXTRA_FRACTION_LEN) - 1; InFPBits bits(x); @@ -135,6 +133,7 @@ sqrt(InType x) { InStorageType y = ONE; InStorageType r = x_mant - ONE; + // TODO: Reduce iteration count to OutFPBits::FRACTION_LEN + 2 or + 3. for (InStorageType current_bit = ONE >> 1; current_bit; current_bit >>= 1) { r <<= 1; @@ -146,91 +145,19 @@ sqrt(InType x) { } // We compute one more iteration in order to round correctly. - bool lsb = (y & (InStorageType(1) << EXTRA_FRACTION_LEN)) != - 0; // Least significant bit - bool rb = false; // Round bit r <<= 2; - InStorageType tmp = (y << 2) + 1; + y <<= 2; + InStorageType tmp = y + 1; if (r >= tmp) { r -= tmp; - rb = true; - } - - bool sticky = false; - - if constexpr (EXTRA_FRACTION_LEN > 0) { - sticky = rb || (y & EXTRA_FRACTION_MASK) != 0; - rb = (y & (InStorageType(1) << (EXTRA_FRACTION_LEN - 1))) != 0; - } - - // Remove hidden bit and append the exponent field. - x_exp = ((x_exp >> 1) + OutFPBits::EXP_BIAS); - - OutStorageType y_out = static_cast( - ((y - ONE) >> EXTRA_FRACTION_LEN) | - (static_cast(x_exp) << OutFPBits::FRACTION_LEN)); - - if constexpr (EXTRA_FRACTION_LEN > 0) { - if (x_exp >= OutFPBits::MAX_BIASED_EXPONENT) { - switch (quick_get_round()) { - case FE_TONEAREST: - case FE_UPWARD: - return OutFPBits::inf().get_val(); - default: - return OutFPBits::max_normal().get_val(); - } - } - - if (x_exp < - -OutFPBits::EXP_BIAS - OutFPBits::SIG_LEN + EXTRA_FRACTION_LEN) { - switch (quick_get_round()) { - case FE_UPWARD: - return OutFPBits::min_subnormal().get_val(); - default: - return OutType(0.0); - } - } - - if (x_exp <= 0) { - int underflow_extra_fraction_len = EXTRA_FRACTION_LEN - x_exp + 1; - InStorageType underflow_extra_fraction_mask = - (InStorageType(1) << underflow_extra_fraction_len) - 1; - - rb = (y & (InStorageType(1) << (underflow_extra_fraction_len - 1))) != - 0; - OutStorageType subnormal_mant = - static_cast(y >> underflow_extra_fraction_len); - lsb = (subnormal_mant & 1) != 0; - sticky = sticky || (y & underflow_extra_fraction_mask) != 0; - - switch (quick_get_round()) { - case FE_TONEAREST: - if (rb && (lsb || sticky)) - ++subnormal_mant; - break; - case FE_UPWARD: - if (rb || sticky) - ++subnormal_mant; - break; - } - - return cpp::bit_cast(subnormal_mant); - } - } - - switch (quick_get_round()) { - case FE_TONEAREST: - // Round to nearest, ties to even - if (rb && (lsb || (r != 0))) - ++y_out; - break; - case FE_UPWARD: - if (rb || (r != 0) || sticky) - ++y_out; - break; + // Rounding bit. + y |= 2; } + // Sticky bit. + y |= static_cast(r != 0); - return cpp::bit_cast(y_out); + DyadicFloat yd(Sign::POS, (x_exp >> 1) - 2 - InFPBits::FRACTION_LEN, y); + return yd.template as(); } } } diff --git a/libc/src/__support/FPUtil/multiply_add.h b/libc/src/__support/FPUtil/multiply_add.h index 622914e4265c91..1b9eee4ace62d0 100644 --- a/libc/src/__support/FPUtil/multiply_add.h +++ b/libc/src/__support/FPUtil/multiply_add.h @@ -39,17 +39,18 @@ multiply_add(T x, T y, T z) { #if defined(LIBC_TARGET_CPU_HAS_FMA) // FMA instructions are available. -#include "FMA.h" +// We use builtins directly instead of including FMA.h to avoid a circular +// dependency: multiply_add.h -> FMA.h -> generic/FMA.h -> dyadic_float.h. namespace LIBC_NAMESPACE { namespace fputil { LIBC_INLINE float multiply_add(float x, float y, float z) { - return fma(x, y, z); + return __builtin_fmaf(x, y, z); } LIBC_INLINE double multiply_add(double x, double y, double z) { - return fma(x, y, z); + return __builtin_fma(x, y, z); } } // namespace fputil diff --git a/libc/src/__support/OSUtil/linux/arm/syscall.h b/libc/src/__support/OSUtil/linux/arm/syscall.h index af100747832750..9674ee45a49e91 100644 --- a/libc/src/__support/OSUtil/linux/arm/syscall.h +++ b/libc/src/__support/OSUtil/linux/arm/syscall.h @@ -12,14 +12,29 @@ #include "src/__support/common.h" #ifdef __thumb__ -#error "The arm syscall implementation does not yet support thumb flavor." -#endif // __thumb__ +#define R7 long r7 = number +#define SYSCALL_INSTR(input_constraint) \ + int temp; \ + LIBC_INLINE_ASM(R"( + mov %[temp], r7 + mov r7, %2 + svc #0 + mov r7, %[temp] + )" \ + : "=r"(r0), [temp] "=&r"(temp) \ + : input_constraint \ + : "memory", "cc") +#else +#define R7 register long r7 asm("r7") = number +#define SYSCALL_INSTR(input_constraint) \ + LIBC_INLINE_ASM("svc 0" : "=r"(r0) : input_constraint : "memory", "cc") +#endif #define REGISTER_DECL_0 \ - register long r7 __asm__("r7") = number; \ + R7; \ register long r0 __asm__("r0"); #define REGISTER_DECL_1 \ - register long r7 __asm__("r7") = number; \ + R7; \ register long r0 __asm__("r0") = arg1; #define REGISTER_DECL_2 \ REGISTER_DECL_1 \ @@ -45,9 +60,6 @@ #define REGISTER_CONSTRAINT_5 REGISTER_CONSTRAINT_4, "r"(r4) #define REGISTER_CONSTRAINT_6 REGISTER_CONSTRAINT_5, "r"(r5) -#define SYSCALL_INSTR(input_constraint) \ - LIBC_INLINE_ASM("svc 0" : "=r"(r0) : input_constraint : "memory", "cc") - namespace LIBC_NAMESPACE { LIBC_INLINE long syscall_impl(long number) { diff --git a/libc/src/__support/OSUtil/linux/fcntl.cpp b/libc/src/__support/OSUtil/linux/fcntl.cpp index b087f898c395d6..083deb8c336813 100644 --- a/libc/src/__support/OSUtil/linux/fcntl.cpp +++ b/libc/src/__support/OSUtil/linux/fcntl.cpp @@ -67,15 +67,11 @@ int fcntl(int fd, int cmd, void *arg) { } case F_GETOWN: { struct f_owner_ex fex; - int retVal = + int ret = LIBC_NAMESPACE::syscall_impl(SYS_fcntl, fd, F_GETOWN_EX, &fex); - if (retVal == -EINVAL) - return LIBC_NAMESPACE::syscall_impl(SYS_fcntl, fd, cmd, - reinterpret_cast(arg)); - if (static_cast(retVal) <= -4096UL) + if (ret >= 0) return fex.type == F_OWNER_PGRP ? -fex.pid : fex.pid; - - libc_errno = -retVal; + libc_errno = -ret; return -1; } // The general case diff --git a/libc/src/__support/big_int.h b/libc/src/__support/big_int.h index 5ce9541d73f68e..59a3912ef0f098 100644 --- a/libc/src/__support/big_int.h +++ b/libc/src/__support/big_int.h @@ -387,7 +387,8 @@ struct BigInt { } // Initialize the first word to |v| and the rest to 0. - template >> + template && + !cpp::is_same_v>> LIBC_INLINE constexpr BigInt(T v) { constexpr size_t T_SIZE = sizeof(T) * CHAR_BIT; const bool is_neg = Signed && (v < 0); @@ -440,7 +441,7 @@ struct BigInt { constexpr size_t MAX_COUNT = T_SIZE > Bits ? WORD_COUNT : T_SIZE / WORD_SIZE; for (size_t i = 1; i < MAX_COUNT; ++i) - lo += static_cast(val[i]) << (WORD_SIZE * i); + lo += static_cast(static_cast(val[i]) << (WORD_SIZE * i)); if constexpr (Signed && (T_SIZE > Bits)) { // Extend sign for negative numbers. constexpr T MASK = (~T(0) << Bits); diff --git a/libc/src/__support/fixedvector.h b/libc/src/__support/fixedvector.h index 403b1620d20df2..5161c0d7a533cf 100644 --- a/libc/src/__support/fixedvector.h +++ b/libc/src/__support/fixedvector.h @@ -90,6 +90,11 @@ template class FixedVector { LIBC_INLINE constexpr iterator begin() { return store.begin(); } LIBC_INLINE constexpr iterator end() { return iterator{&store[item_count]}; } + + LIBC_INLINE constexpr const_iterator begin() const { return store.begin(); } + LIBC_INLINE constexpr const_iterator end() const { + return const_iterator{&store[item_count]}; + } }; } // namespace LIBC_NAMESPACE diff --git a/libc/src/__support/high_precision_decimal.h b/libc/src/__support/high_precision_decimal.h index 2c5a349e4495eb..6a22554165014f 100644 --- a/libc/src/__support/high_precision_decimal.h +++ b/libc/src/__support/high_precision_decimal.h @@ -409,7 +409,8 @@ class HighPrecisionDecimal { result *= 10; ++cur_digit; } - return result + this->should_round_up(this->decimal_point, round); + return result + static_cast( + this->should_round_up(this->decimal_point, round)); } // Extra functions for testing. diff --git a/libc/src/__support/macros/optimization.h b/libc/src/__support/macros/optimization.h index 59886ca44be12a..05a47791deed8a 100644 --- a/libc/src/__support/macros/optimization.h +++ b/libc/src/__support/macros/optimization.h @@ -33,4 +33,18 @@ LIBC_INLINE constexpr bool expects_bool_condition(T value, T expected) { #error "Unhandled compiler" #endif +// Defining optimization options for math functions. +// TODO: Exporting this to public generated headers? +#define LIBC_MATH_SKIP_ACCURATE_PASS 0x01 +#define LIBC_MATH_SMALL_TABLES 0x02 +#define LIBC_MATH_NO_ERRNO 0x04 +#define LIBC_MATH_NO_EXCEPT 0x08 +#define LIBC_MATH_FAST \ + (LIBC_MATH_SKIP_ACCURATE_PASS | LIBC_MATH_SMALL_TABLES | \ + LIBC_MATH_NO_ERRNO | LIBC_MATH_NO_EXCEPT) + +#ifndef LIBC_MATH +#define LIBC_MATH 0 +#endif // LIBC_MATH + #endif // LLVM_LIBC_SRC___SUPPORT_MACROS_OPTIMIZATION_H diff --git a/libc/src/__support/threads/callonce.h b/libc/src/__support/threads/callonce.h index b3d6813f7dda9e..67f4c996571072 100644 --- a/libc/src/__support/threads/callonce.h +++ b/libc/src/__support/threads/callonce.h @@ -9,13 +9,32 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_CALLONCE_H #define LLVM_LIBC_SRC___SUPPORT_THREADS_CALLONCE_H +#include "src/__support/macros/optimization.h" // LIBC_LIKELY + +// Plaform specific routines, provides: +// - OnceFlag definition +// - callonce_impl::callonce_fastpath for fast path check +// - callonce_impl::callonce_slowpath for slow path execution +#ifdef __linux__ +#include "src/__support/threads/linux/callonce.h" +#else +#error "callonce is not supported on this platform" +#endif + namespace LIBC_NAMESPACE { -struct CallOnceFlag; +// Common definitions using CallOnceCallback = void(void); +namespace callonce_impl { +int callonce_slowpath(CallOnceFlag *flag, CallOnceCallback *callback); +} // namespace callonce_impl -int callonce(CallOnceFlag *flag, CallOnceCallback *callback); +LIBC_INLINE int callonce(CallOnceFlag *flag, CallOnceCallback *callback) { + if (LIBC_LIKELY(callonce_impl::callonce_fastpath(flag))) + return 0; + return callonce_impl::callonce_slowpath(flag, callback); +} } // namespace LIBC_NAMESPACE #endif // LLVM_LIBC_SRC___SUPPORT_THREADS_CALLONCE_H diff --git a/libc/src/__support/threads/linux/CMakeLists.txt b/libc/src/__support/threads/linux/CMakeLists.txt index 95e509b7a825dd..8b7971584e77ec 100644 --- a/libc/src/__support/threads/linux/CMakeLists.txt +++ b/libc/src/__support/threads/linux/CMakeLists.txt @@ -100,8 +100,10 @@ add_object_library( callonce.cpp HDRS ../callonce.h + callonce.h DEPENDS .futex_utils + libc.src.__support.macros.optimization ) add_object_library( diff --git a/libc/src/__support/threads/linux/callonce.cpp b/libc/src/__support/threads/linux/callonce.cpp index b48a514a448753..24d376f447fba1 100644 --- a/libc/src/__support/threads/linux/callonce.cpp +++ b/libc/src/__support/threads/linux/callonce.cpp @@ -7,27 +7,16 @@ //===----------------------------------------------------------------------===// #include "src/__support/threads/callonce.h" -#include "src/__support/macros/optimization.h" +#include "src/__support/threads/linux/callonce.h" #include "src/__support/threads/linux/futex_utils.h" namespace LIBC_NAMESPACE { - -static constexpr FutexWordType NOT_CALLED = 0x0; -static constexpr FutexWordType START = 0x11; -static constexpr FutexWordType WAITING = 0x22; -static constexpr FutexWordType FINISH = 0x33; - -int callonce(CallOnceFlag *flag, CallOnceCallback *func) { +namespace callonce_impl { +int callonce_slowpath(CallOnceFlag *flag, CallOnceCallback *func) { auto *futex_word = reinterpret_cast(flag); FutexWordType not_called = NOT_CALLED; - // Avoid cmpxchg operation if the function has already been called. - // The destination operand of cmpxchg may receive a write cycle without - // regard to the result of the comparison - if (LIBC_LIKELY(futex_word->load(cpp::MemoryOrder::RELAXED) == FINISH)) - return 0; - // The call_once call can return only after the called function |func| // returns. So, we use futexes to synchronize calls with the same flag value. if (futex_word->compare_exchange_strong(not_called, START)) { @@ -46,5 +35,5 @@ int callonce(CallOnceFlag *flag, CallOnceCallback *func) { return 0; } - +} // namespace callonce_impl } // namespace LIBC_NAMESPACE diff --git a/libc/src/__support/threads/linux/callonce.h b/libc/src/__support/threads/linux/callonce.h new file mode 100644 index 00000000000000..315cc6149e9ecf --- /dev/null +++ b/libc/src/__support/threads/linux/callonce.h @@ -0,0 +1,31 @@ +//===-- Linux callonce fastpath -------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_CALLONCE_H +#define LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_CALLONCE_H + +#include "src/__support/threads/linux/futex_utils.h" + +namespace LIBC_NAMESPACE { +using CallOnceFlag = Futex; + +namespace callonce_impl { +static constexpr FutexWordType NOT_CALLED = 0x0; +static constexpr FutexWordType START = 0x11; +static constexpr FutexWordType WAITING = 0x22; +static constexpr FutexWordType FINISH = 0x33; + +// Avoid cmpxchg operation if the function has already been called. +// The destination operand of cmpxchg may receive a write cycle without +// regard to the result of the comparison. +LIBC_INLINE bool callonce_fastpath(CallOnceFlag *flag) { + return flag->load(cpp::MemoryOrder::RELAXED) == FINISH; +} +} // namespace callonce_impl + +} // namespace LIBC_NAMESPACE +#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_CALLONCE_H diff --git a/libc/src/__support/threads/thread.h b/libc/src/__support/threads/thread.h index acfe33879f8783..f89c687eeaa19b 100644 --- a/libc/src/__support/threads/thread.h +++ b/libc/src/__support/threads/thread.h @@ -43,6 +43,9 @@ union ThreadReturnValue { defined(LIBC_TARGET_ARCH_IS_X86_64) || \ defined(LIBC_TARGET_ARCH_IS_ANY_RISCV)) constexpr unsigned int STACK_ALIGNMENT = 16; +#elif defined(LIBC_TARGET_ARCH_IS_ARM) +// See Section 6.2.1.2 Stack constraints at a public interface of AAPCS32. +constexpr unsigned int STACK_ALIGNMENT = 8; #endif // TODO: Provide stack alignment requirements for other architectures. diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt index a921939ea806c2..4777f669f0cb5b 100644 --- a/libc/src/math/CMakeLists.txt +++ b/libc/src/math/CMakeLists.txt @@ -99,9 +99,20 @@ add_math_entrypoint_object(exp10f) add_math_entrypoint_object(expm1) add_math_entrypoint_object(expm1f) +add_math_entrypoint_object(f16div) +add_math_entrypoint_object(f16divf) +add_math_entrypoint_object(f16divl) +add_math_entrypoint_object(f16divf128) + +add_math_entrypoint_object(f16fma) add_math_entrypoint_object(f16fmaf) +add_math_entrypoint_object(f16fmal) +add_math_entrypoint_object(f16fmaf128) +add_math_entrypoint_object(f16sqrt) add_math_entrypoint_object(f16sqrtf) +add_math_entrypoint_object(f16sqrtl) +add_math_entrypoint_object(f16sqrtf128) add_math_entrypoint_object(fabs) add_math_entrypoint_object(fabsf) diff --git a/libc/src/math/f16div.h b/libc/src/math/f16div.h new file mode 100644 index 00000000000000..3807bc02276c9b --- /dev/null +++ b/libc/src/math/f16div.h @@ -0,0 +1,20 @@ +//===-- Implementation header for f16div ------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_F16DIV_H +#define LLVM_LIBC_SRC_MATH_F16DIV_H + +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE { + +float16 f16div(double x, double y); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_F16DIV_H diff --git a/libc/src/math/f16divf.h b/libc/src/math/f16divf.h new file mode 100644 index 00000000000000..a3359d9e479445 --- /dev/null +++ b/libc/src/math/f16divf.h @@ -0,0 +1,20 @@ +//===-- Implementation header for f16divf -----------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_F16DIVF_H +#define LLVM_LIBC_SRC_MATH_F16DIVF_H + +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE { + +float16 f16divf(float x, float y); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_F16DIVF_H diff --git a/libc/src/math/f16divf128.h b/libc/src/math/f16divf128.h new file mode 100644 index 00000000000000..2f63535ca27ce2 --- /dev/null +++ b/libc/src/math/f16divf128.h @@ -0,0 +1,20 @@ +//===-- Implementation header for f16divf128 --------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_F16DIVF128_H +#define LLVM_LIBC_SRC_MATH_F16DIVF128_H + +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE { + +float16 f16divf128(float128 x, float128 y); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_F16DIVF128_H diff --git a/libc/src/math/f16divl.h b/libc/src/math/f16divl.h new file mode 100644 index 00000000000000..ad9999135b5880 --- /dev/null +++ b/libc/src/math/f16divl.h @@ -0,0 +1,20 @@ +//===-- Implementation header for f16divl -----------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_F16DIVL_H +#define LLVM_LIBC_SRC_MATH_F16DIVL_H + +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE { + +float16 f16divl(long double x, long double y); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_F16DIVL_H diff --git a/libc/src/math/f16fma.h b/libc/src/math/f16fma.h new file mode 100644 index 00000000000000..d9505f88f37af2 --- /dev/null +++ b/libc/src/math/f16fma.h @@ -0,0 +1,20 @@ +//===-- Implementation header for f16fma ------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_F16FMA_H +#define LLVM_LIBC_SRC_MATH_F16FMA_H + +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE { + +float16 f16fma(double x, double y, double z); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_F16FMA_H diff --git a/libc/src/math/f16fmaf128.h b/libc/src/math/f16fmaf128.h new file mode 100644 index 00000000000000..9203b4d30d2124 --- /dev/null +++ b/libc/src/math/f16fmaf128.h @@ -0,0 +1,20 @@ +//===-- Implementation header for f16fmaf128 --------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_F16FMAF128_H +#define LLVM_LIBC_SRC_MATH_F16FMAF128_H + +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE { + +float16 f16fmaf128(float128 x, float128 y, float128 z); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_F16FMAF128_H diff --git a/libc/src/math/f16fmal.h b/libc/src/math/f16fmal.h new file mode 100644 index 00000000000000..6f5dd33aa18f63 --- /dev/null +++ b/libc/src/math/f16fmal.h @@ -0,0 +1,20 @@ +//===-- Implementation header for f16fmal -----------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_F16FMAL_H +#define LLVM_LIBC_SRC_MATH_F16FMAL_H + +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE { + +float16 f16fmal(long double x, long double y, long double z); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_F16FMAL_H diff --git a/libc/src/math/f16sqrt.h b/libc/src/math/f16sqrt.h new file mode 100644 index 00000000000000..f1134ac5ee2b9c --- /dev/null +++ b/libc/src/math/f16sqrt.h @@ -0,0 +1,20 @@ +//===-- Implementation header for f16sqrt -----------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_F16SQRT_H +#define LLVM_LIBC_SRC_MATH_F16SQRT_H + +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE { + +float16 f16sqrt(double x); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_F16SQRT_H diff --git a/libc/src/math/f16sqrtf128.h b/libc/src/math/f16sqrtf128.h new file mode 100644 index 00000000000000..61a6ce9ea5a5d7 --- /dev/null +++ b/libc/src/math/f16sqrtf128.h @@ -0,0 +1,20 @@ +//===-- Implementation header for f16sqrtf128 -------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_F16SQRTF128_H +#define LLVM_LIBC_SRC_MATH_F16SQRTF128_H + +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE { + +float16 f16sqrtf128(float128 x); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_F16SQRTF128_H diff --git a/libc/src/math/f16sqrtl.h b/libc/src/math/f16sqrtl.h new file mode 100644 index 00000000000000..fd3c55fc95f328 --- /dev/null +++ b/libc/src/math/f16sqrtl.h @@ -0,0 +1,20 @@ +//===-- Implementation header for f16sqrtl ----------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_F16SQRTL_H +#define LLVM_LIBC_SRC_MATH_F16SQRTL_H + +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE { + +float16 f16sqrtl(long double x); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_F16SQRTL_H diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index a0114aafcad39e..7dd6c4812fa153 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -135,6 +135,23 @@ add_header_library( libc.src.__support.common ) +add_header_library( + range_reduction_double + HDRS + range_reduction_double_common.h + range_reduction_double_fma.h + range_reduction_double_nofma.h + DEPENDS + libc.src.__support.FPUtil.double_double + libc.src.__support.FPUtil.dyadic_float + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.fma + libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.nearest_integer + libc.src.__support.common + libc.src.__support.integer_literals +) + add_header_library( sincosf_utils HDRS @@ -146,6 +163,39 @@ add_header_library( libc.src.__support.common ) +add_header_library( + sincos_eval + HDRS + sincos_eval.h + DEPENDS + libc.src.__support.FPUtil.double_double + libc.src.__support.FPUtil.dyadic_float + libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.polyeval + libc.src.__support.integer_literals +) + +add_entrypoint_object( + cos + SRCS + cos.cpp + HDRS + ../cos.h + DEPENDS + .range_reduction_double + .sincos_eval + libc.hdr.errno_macros + libc.src.errno.errno + libc.src.__support.FPUtil.double_double + libc.src.__support.FPUtil.dyadic_float + libc.src.__support.FPUtil.except_value_utils + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.macros.optimization + COMPILE_OPTIONS + -O3 +) + add_entrypoint_object( cosf SRCS @@ -167,6 +217,28 @@ add_entrypoint_object( -O3 ) +add_entrypoint_object( + sin + SRCS + sin.cpp + HDRS + ../sin.h + DEPENDS + .range_reduction_double + .sincos_eval + libc.hdr.errno_macros + libc.src.errno.errno + libc.src.__support.FPUtil.double_double + libc.src.__support.FPUtil.dyadic_float + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.rounding_mode + libc.src.__support.macros.optimization + COMPILE_OPTIONS + -O3 +) + add_entrypoint_object( sinf SRCS @@ -189,6 +261,28 @@ add_entrypoint_object( -O3 ) +add_entrypoint_object( + sincos + SRCS + sincos.cpp + HDRS + ../sincos.h + DEPENDS + .range_reduction_double + .sincos_eval + libc.hdr.errno_macros + libc.src.errno.errno + libc.src.__support.FPUtil.double_double + libc.src.__support.FPUtil.dyadic_float + libc.src.__support.FPUtil.except_value_utils + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.multiply_add + libc.src.__support.macros.optimization + COMPILE_OPTIONS + -O3 +) + add_entrypoint_object( sincosf SRCS @@ -3682,6 +3776,71 @@ add_entrypoint_object( -O3 ) +add_entrypoint_object( + f16div + SRCS + f16div.cpp + HDRS + ../f16div.h + DEPENDS + libc.src.__support.macros.properties.types + libc.src.__support.FPUtil.generic.div + COMPILE_OPTIONS + -O3 +) + +add_entrypoint_object( + f16divf + SRCS + f16divf.cpp + HDRS + ../f16divf.h + DEPENDS + libc.src.__support.macros.properties.types + libc.src.__support.FPUtil.generic.div + COMPILE_OPTIONS + -O3 +) + +add_entrypoint_object( + f16divl + SRCS + f16divl.cpp + HDRS + ../f16divl.h + DEPENDS + libc.src.__support.macros.properties.types + libc.src.__support.FPUtil.generic.div + COMPILE_OPTIONS + -O3 +) + +add_entrypoint_object( + f16divf128 + SRCS + f16divf128.cpp + HDRS + ../f16divf128.h + DEPENDS + libc.src.__support.macros.properties.types + libc.src.__support.FPUtil.generic.div + COMPILE_OPTIONS + -O3 +) + +add_entrypoint_object( + f16fma + SRCS + f16fma.cpp + HDRS + ../f16fma.h + DEPENDS + libc.src.__support.macros.properties.types + libc.src.__support.FPUtil.fma + COMPILE_OPTIONS + -O0 -ggdb3 +) + add_entrypoint_object( f16fmaf SRCS @@ -3695,6 +3854,45 @@ add_entrypoint_object( -O3 ) +add_entrypoint_object( + f16fmal + SRCS + f16fmal.cpp + HDRS + ../f16fmal.h + DEPENDS + libc.src.__support.macros.properties.types + libc.src.__support.FPUtil.fma + COMPILE_OPTIONS + -O3 +) + +add_entrypoint_object( + f16fmaf128 + SRCS + f16fmaf128.cpp + HDRS + ../f16fmaf128.h + DEPENDS + libc.src.__support.macros.properties.types + libc.src.__support.FPUtil.fma + COMPILE_OPTIONS + -O3 +) + +add_entrypoint_object( + f16sqrt + SRCS + f16sqrt.cpp + HDRS + ../f16sqrt.h + DEPENDS + libc.src.__support.macros.properties.types + libc.src.__support.FPUtil.sqrt + COMPILE_OPTIONS + -O3 +) + add_entrypoint_object( f16sqrtf SRCS @@ -3707,3 +3905,29 @@ add_entrypoint_object( COMPILE_OPTIONS -O3 ) + +add_entrypoint_object( + f16sqrtl + SRCS + f16sqrtl.cpp + HDRS + ../f16sqrtl.h + DEPENDS + libc.src.__support.macros.properties.types + libc.src.__support.FPUtil.sqrt + COMPILE_OPTIONS + -O3 +) + +add_entrypoint_object( + f16sqrtf128 + SRCS + f16sqrtf128.cpp + HDRS + ../f16sqrtf128.h + DEPENDS + libc.src.__support.macros.properties.types + libc.src.__support.FPUtil.sqrt + COMPILE_OPTIONS + -O3 +) diff --git a/libc/src/math/generic/cos.cpp b/libc/src/math/generic/cos.cpp new file mode 100644 index 00000000000000..a2cfe758fe4cc0 --- /dev/null +++ b/libc/src/math/generic/cos.cpp @@ -0,0 +1,197 @@ +//===-- Double-precision cos function -------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/math/cos.h" +#include "hdr/errno_macros.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/double_double.h" +#include "src/__support/FPUtil/dyadic_float.h" +#include "src/__support/FPUtil/except_value_utils.h" +#include "src/__support/common.h" +#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY +#include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA +#include "src/math/generic/sincos_eval.h" + +#ifdef LIBC_TARGET_CPU_HAS_FMA +#include "range_reduction_double_fma.h" + +using LIBC_NAMESPACE::fma::FAST_PASS_EXPONENT; +using LIBC_NAMESPACE::fma::ONE_TWENTY_EIGHT_OVER_PI; +using LIBC_NAMESPACE::fma::range_reduction_small; +using LIBC_NAMESPACE::fma::SIN_K_PI_OVER_128; + +LIBC_INLINE constexpr bool NO_FMA = false; +#else +#include "range_reduction_double_nofma.h" + +using LIBC_NAMESPACE::nofma::FAST_PASS_EXPONENT; +using LIBC_NAMESPACE::nofma::ONE_TWENTY_EIGHT_OVER_PI; +using LIBC_NAMESPACE::nofma::range_reduction_small; +using LIBC_NAMESPACE::nofma::SIN_K_PI_OVER_128; + +LIBC_INLINE constexpr bool NO_FMA = true; +#endif // LIBC_TARGET_CPU_HAS_FMA + +// TODO: We might be able to improve the performance of large range reduction of +// non-FMA targets further by operating directly on 25-bit chunks of 128/pi and +// pre-split SIN_K_PI_OVER_128, but that might double the memory footprint of +// those lookup table. +#include "range_reduction_double_common.h" + +#if ((LIBC_MATH & LIBC_MATH_SKIP_ACCURATE_PASS) != 0) +#define LIBC_MATH_COS_SKIP_ACCURATE_PASS +#endif + +namespace LIBC_NAMESPACE { + +using DoubleDouble = fputil::DoubleDouble; +using Float128 = typename fputil::DyadicFloat<128>; + +LLVM_LIBC_FUNCTION(double, cos, (double x)) { + using FPBits = typename fputil::FPBits; + FPBits xbits(x); + + uint16_t x_e = xbits.get_biased_exponent(); + + DoubleDouble y; + unsigned k; + generic::LargeRangeReduction range_reduction_large; + + // |x| < 2^32 (with FMA) or |x| < 2^23 (w/o FMA) + if (LIBC_LIKELY(x_e < FPBits::EXP_BIAS + FAST_PASS_EXPONENT)) { + // |x| < 2^-27 + if (LIBC_UNLIKELY(x_e < FPBits::EXP_BIAS - 27)) { + // Signed zeros. + if (LIBC_UNLIKELY(x == 0.0)) + return 1.0; + + // For |x| < 2^-27, |cos(x) - 1| < |x|^2/2 < 2^-54 = ulp(1 - 2^-53)/2. + return fputil::round_result_slightly_down(1.0); + } + + // // Small range reduction. + k = range_reduction_small(x, y); + } else { + // Inf or NaN + if (LIBC_UNLIKELY(x_e > 2 * FPBits::EXP_BIAS)) { + // sin(+-Inf) = NaN + if (xbits.get_mantissa() == 0) { + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_INVALID); + } + return x + FPBits::quiet_nan().get_val(); + } + + // Large range reduction. + k = range_reduction_large.compute_high_part(x); + y = range_reduction_large.fast(); + } + + DoubleDouble sin_y, cos_y; + + generic::sincos_eval(y, sin_y, cos_y); + + // Look up sin(k * pi/128) and cos(k * pi/128) + // Memory saving versions: + + // Use 128-entry table instead: + // DoubleDouble sin_k = SIN_K_PI_OVER_128[k & 127]; + // uint64_t sin_s = static_cast((k + 128) & 128) << (63 - 7); + // sin_k.hi = FPBits(FPBits(sin_k.hi).uintval() ^ sin_s).get_val(); + // sin_k.lo = FPBits(FPBits(sin_k.hi).uintval() ^ sin_s).get_val(); + // DoubleDouble cos_k = SIN_K_PI_OVER_128[(k + 64) & 127]; + // uint64_t cos_s = static_cast((k + 64) & 128) << (63 - 7); + // cos_k.hi = FPBits(FPBits(cos_k.hi).uintval() ^ cos_s).get_val(); + // cos_k.lo = FPBits(FPBits(cos_k.hi).uintval() ^ cos_s).get_val(); + + // Use 64-entry table instead: + // auto get_idx_dd = [](unsigned kk) -> DoubleDouble { + // unsigned idx = (kk & 64) ? 64 - (kk & 63) : (kk & 63); + // DoubleDouble ans = SIN_K_PI_OVER_128[idx]; + // if (kk & 128) { + // ans.hi = -ans.hi; + // ans.lo = -ans.lo; + // } + // return ans; + // }; + // DoubleDouble sin_k = get_idx_dd(k + 128); + // DoubleDouble cos_k = get_idx_dd(k + 64); + + // Fast look up version, but needs 256-entry table. + // -sin(k * pi/128) = sin((k + 128) * pi/128) + // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). + DoubleDouble msin_k = SIN_K_PI_OVER_128[(k + 128) & 255]; + DoubleDouble cos_k = SIN_K_PI_OVER_128[(k + 64) & 255]; + + // After range reduction, k = round(x * 128 / pi) and y = x - k * (pi / 128). + // So k is an integer and -pi / 256 <= y <= pi / 256. + // Then cos(x) = cos((k * pi/128 + y) + // = cos(y) * cos(k*pi/128) - sin(y) * sin(k*pi/128) + DoubleDouble cos_k_cos_y = fputil::quick_mult(cos_y, cos_k); + DoubleDouble msin_k_sin_y = fputil::quick_mult(sin_y, msin_k); + + DoubleDouble rr = fputil::exact_add(cos_k_cos_y.hi, msin_k_sin_y.hi); + rr.lo += msin_k_sin_y.lo + cos_k_cos_y.lo; + +#ifdef LIBC_MATH_COS_SKIP_ACCURATE_PASS + return rr.hi + rr.lo; +#else + + // Accurate test and pass for correctly rounded implementation. +#ifdef LIBC_TARGET_CPU_HAS_FMA + constexpr double ERR = 0x1.0p-70; +#else + // TODO: Improve non-FMA fast pass accuracy. + constexpr double ERR = 0x1.0p-66; +#endif // LIBC_TARGET_CPU_HAS_FMA + + double rlp = rr.lo + ERR; + double rlm = rr.lo - ERR; + + double r_upper = rr.hi + rlp; // (rr.lo + ERR); + double r_lower = rr.hi + rlm; // (rr.lo - ERR); + + // Ziv's rounding test. + if (LIBC_LIKELY(r_upper == r_lower)) + return r_upper; + + Float128 u_f128, sin_u, cos_u; + if (LIBC_LIKELY(x_e < FPBits::EXP_BIAS + FAST_PASS_EXPONENT)) + u_f128 = generic::range_reduction_small_f128(x); + else + u_f128 = range_reduction_large.accurate(); + + generic::sincos_eval(u_f128, sin_u, cos_u); + + auto get_sin_k = [](unsigned kk) -> Float128 { + unsigned idx = (kk & 64) ? 64 - (kk & 63) : (kk & 63); + Float128 ans = generic::SIN_K_PI_OVER_128_F128[idx]; + if (kk & 128) + ans.sign = Sign::NEG; + return ans; + }; + + // -sin(k * pi/128) = sin((k + 128) * pi/128) + // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). + Float128 msin_k_f128 = get_sin_k(k + 128); + Float128 cos_k_f128 = get_sin_k(k + 64); + + // cos(x) = cos((k * pi/128 + u) + // = cos(u) * cos(k*pi/128) - sin(u) * sin(k*pi/128) + Float128 r = fputil::quick_add(fputil::quick_mul(cos_k_f128, cos_u), + fputil::quick_mul(msin_k_f128, sin_u)); + + // TODO: Add assertion if Ziv's accuracy tests fail in debug mode. + // https://github.com/llvm/llvm-project/issues/96452. + + return static_cast(r); +#endif // !LIBC_MATH_COS_SKIP_ACCURATE_PASS +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/src/math/generic/f16div.cpp b/libc/src/math/generic/f16div.cpp new file mode 100644 index 00000000000000..2ff0ff78655391 --- /dev/null +++ b/libc/src/math/generic/f16div.cpp @@ -0,0 +1,19 @@ +//===-- Implementation of f16div function ---------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/math/f16div.h" +#include "src/__support/FPUtil/generic/div.h" +#include "src/__support/common.h" + +namespace LIBC_NAMESPACE { + +LLVM_LIBC_FUNCTION(float16, f16div, (double x, double y)) { + return fputil::generic::div(x, y); +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/src/math/generic/f16divf.cpp b/libc/src/math/generic/f16divf.cpp new file mode 100644 index 00000000000000..45874fbac2055a --- /dev/null +++ b/libc/src/math/generic/f16divf.cpp @@ -0,0 +1,19 @@ +//===-- Implementation of f16divf function --------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/math/f16divf.h" +#include "src/__support/FPUtil/generic/div.h" +#include "src/__support/common.h" + +namespace LIBC_NAMESPACE { + +LLVM_LIBC_FUNCTION(float16, f16divf, (float x, float y)) { + return fputil::generic::div(x, y); +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/src/math/generic/f16divf128.cpp b/libc/src/math/generic/f16divf128.cpp new file mode 100644 index 00000000000000..1d37ad8aa2366c --- /dev/null +++ b/libc/src/math/generic/f16divf128.cpp @@ -0,0 +1,19 @@ +//===-- Implementation of f16divf128 function -----------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/math/f16divf128.h" +#include "src/__support/FPUtil/generic/div.h" +#include "src/__support/common.h" + +namespace LIBC_NAMESPACE { + +LLVM_LIBC_FUNCTION(float16, f16divf128, (float128 x, float128 y)) { + return fputil::generic::div(x, y); +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/src/math/generic/f16divl.cpp b/libc/src/math/generic/f16divl.cpp new file mode 100644 index 00000000000000..3fb9c7891f5d1b --- /dev/null +++ b/libc/src/math/generic/f16divl.cpp @@ -0,0 +1,19 @@ +//===-- Implementation of f16divl function --------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/math/f16divl.h" +#include "src/__support/FPUtil/generic/div.h" +#include "src/__support/common.h" + +namespace LIBC_NAMESPACE { + +LLVM_LIBC_FUNCTION(float16, f16divl, (long double x, long double y)) { + return fputil::generic::div(x, y); +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/src/math/generic/f16fma.cpp b/libc/src/math/generic/f16fma.cpp new file mode 100644 index 00000000000000..10ee028c069301 --- /dev/null +++ b/libc/src/math/generic/f16fma.cpp @@ -0,0 +1,19 @@ +//===-- Implementation of f16fma function ---------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/math/f16fma.h" +#include "src/__support/FPUtil/FMA.h" +#include "src/__support/common.h" + +namespace LIBC_NAMESPACE { + +LLVM_LIBC_FUNCTION(float16, f16fma, (double x, double y, double z)) { + return fputil::fma(x, y, z); +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/src/math/generic/f16fmaf128.cpp b/libc/src/math/generic/f16fmaf128.cpp new file mode 100644 index 00000000000000..5b2f801cf21fa5 --- /dev/null +++ b/libc/src/math/generic/f16fmaf128.cpp @@ -0,0 +1,19 @@ +//===-- Implementation of f16fmaf128 function -----------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/math/f16fmaf128.h" +#include "src/__support/FPUtil/FMA.h" +#include "src/__support/common.h" + +namespace LIBC_NAMESPACE { + +LLVM_LIBC_FUNCTION(float16, f16fmaf128, (float128 x, float128 y, float128 z)) { + return fputil::fma(x, y, z); +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/src/math/generic/f16fmal.cpp b/libc/src/math/generic/f16fmal.cpp new file mode 100644 index 00000000000000..067483629a3362 --- /dev/null +++ b/libc/src/math/generic/f16fmal.cpp @@ -0,0 +1,20 @@ +//===-- Implementation of f16fmal function --------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/math/f16fmal.h" +#include "src/__support/FPUtil/FMA.h" +#include "src/__support/common.h" + +namespace LIBC_NAMESPACE { + +LLVM_LIBC_FUNCTION(float16, f16fmal, + (long double x, long double y, long double z)) { + return fputil::fma(x, y, z); +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/src/math/x86_64/cos.cpp b/libc/src/math/generic/f16sqrt.cpp similarity index 64% rename from libc/src/math/x86_64/cos.cpp rename to libc/src/math/generic/f16sqrt.cpp index 2cb8db4b7a859d..9d5f081f633152 100644 --- a/libc/src/math/x86_64/cos.cpp +++ b/libc/src/math/generic/f16sqrt.cpp @@ -1,4 +1,4 @@ -//===-- Implementation of the cos function for x86_64 ---------------------===// +//===-- Implementation of f16sqrt function --------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,14 +6,14 @@ // //===----------------------------------------------------------------------===// -#include "src/math/cos.h" +#include "src/math/f16sqrt.h" +#include "src/__support/FPUtil/sqrt.h" #include "src/__support/common.h" namespace LIBC_NAMESPACE { -LLVM_LIBC_FUNCTION(double, cos, (double x)) { - __asm__ __volatile__("fcos" : "+t"(x)); - return x; +LLVM_LIBC_FUNCTION(float16, f16sqrt, (double x)) { + return fputil::sqrt(x); } } // namespace LIBC_NAMESPACE diff --git a/libc/src/math/generic/f16sqrtf128.cpp b/libc/src/math/generic/f16sqrtf128.cpp new file mode 100644 index 00000000000000..11a1e8252788ee --- /dev/null +++ b/libc/src/math/generic/f16sqrtf128.cpp @@ -0,0 +1,19 @@ +//===-- Implementation of f16sqrtf128 function ----------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/math/f16sqrtf128.h" +#include "src/__support/FPUtil/sqrt.h" +#include "src/__support/common.h" + +namespace LIBC_NAMESPACE { + +LLVM_LIBC_FUNCTION(float16, f16sqrtf128, (float128 x)) { + return fputil::sqrt(x); +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/src/math/x86_64/sin.cpp b/libc/src/math/generic/f16sqrtl.cpp similarity index 64% rename from libc/src/math/x86_64/sin.cpp rename to libc/src/math/generic/f16sqrtl.cpp index 2c7b8aa6e8c836..2aaac9a780f66c 100644 --- a/libc/src/math/x86_64/sin.cpp +++ b/libc/src/math/generic/f16sqrtl.cpp @@ -1,4 +1,4 @@ -//===-- Implementation of the sin function for x86_64 ---------------------===// +//===-- Implementation of f16sqrtl function -------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,14 +6,14 @@ // //===----------------------------------------------------------------------===// -#include "src/math/sin.h" +#include "src/math/f16sqrtl.h" +#include "src/__support/FPUtil/sqrt.h" #include "src/__support/common.h" namespace LIBC_NAMESPACE { -LLVM_LIBC_FUNCTION(double, sin, (double x)) { - __asm__ __volatile__("fsin" : "+t"(x)); - return x; +LLVM_LIBC_FUNCTION(float16, f16sqrtl, (long double x)) { + return fputil::sqrt(x); } } // namespace LIBC_NAMESPACE diff --git a/libc/src/math/generic/range_reduction_double_common.h b/libc/src/math/generic/range_reduction_double_common.h new file mode 100644 index 00000000000000..150118fba0ba06 --- /dev/null +++ b/libc/src/math/generic/range_reduction_double_common.h @@ -0,0 +1,230 @@ +//===-- Range reduction for double precision sin/cos/tan -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_GENERIC_RANGE_REDUCTION_DOUBLE_COMMON_H +#define LLVM_LIBC_SRC_MATH_GENERIC_RANGE_REDUCTION_DOUBLE_COMMON_H + +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/double_double.h" +#include "src/__support/FPUtil/dyadic_float.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/nearest_integer.h" +#include "src/__support/common.h" +#include "src/__support/integer_literals.h" + +namespace LIBC_NAMESPACE { + +namespace generic { + +using LIBC_NAMESPACE::fputil::DoubleDouble; +using Float128 = LIBC_NAMESPACE::fputil::DyadicFloat<128>; + +LIBC_INLINE constexpr Float128 PI_OVER_128_F128 = { + Sign::POS, -133, 0xc90f'daa2'2168'c234'c4c6'628b'80dc'1cd1_u128}; + +// Note: The look-up tables ONE_TWENTY_EIGHT_OVER_PI is selected to be either +// from fma:: or nofma:: namespace. + +// For large range |x| >= 2^32, we use the exponent of x to find 3 double-chunks +// of 128/pi c_hi, c_mid, c_lo such that: +// 1) ulp(round(x * c_hi, D, RN)) >= 256, +// 2) If x * c_hi = ph_hi + ph_lo and x * c_mid = pm_hi + pm_lo, then +// min(ulp(ph_lo), ulp(pm_hi)) >= 2^-53. +// 3) ulp(round(x * c_lo, D, RN)) <= 2^-7x. +// This will allow us to do quick computations as: +// (x * 256/pi) ~ x * (c_hi + c_mid + c_lo) (mod 256) +// ~ ph_lo + pm_hi + pm_lo + (x * c_lo) +// Then, +// round(x * 128/pi) = round(ph_lo + pm_hi) (mod 256) +// And the high part of fractional part of (x * 128/pi) can simply be: +// {x * 128/pi}_hi = {ph_lo + pm_hi}. +// To prevent overflow when x is very large, we simply scale up +// (c_hi, c_mid, c_lo) by a fixed power of 2 (based on the index) and scale down +// x by the same amount. + +template struct LargeRangeReduction { + // Calculate the high part of the range reduction exactly. + LIBC_INLINE unsigned compute_high_part(double x) { + using FPBits = typename fputil::FPBits; + FPBits xbits(x); + + // TODO: The extra exponent gap of 62 below can be reduced a bit for non-FMA + // with a more careful analysis, which in turn will reduce the error bound + // for non-FMA + int x_e_m62 = xbits.get_biased_exponent() - (FPBits::EXP_BIAS + 62); + idx = static_cast((x_e_m62 >> 4) + 3); + // Scale x down by 2^(-(16 * (idx - 3)) + xbits.set_biased_exponent((x_e_m62 & 15) + FPBits::EXP_BIAS + 62); + // 2^62 <= |x_reduced| < 2^(62 + 16) = 2^78 + x_reduced = xbits.get_val(); + // x * c_hi = ph.hi + ph.lo exactly. + DoubleDouble ph = + fputil::exact_mult(x_reduced, ONE_TWENTY_EIGHT_OVER_PI[idx][0]); + // x * c_mid = pm.hi + pm.lo exactly. + DoubleDouble pm = + fputil::exact_mult(x_reduced, ONE_TWENTY_EIGHT_OVER_PI[idx][1]); + // Extract integral parts and fractional parts of (ph.lo + pm.hi). + double kh = fputil::nearest_integer(ph.lo); + double ph_lo_frac = ph.lo - kh; // Exact + double km = fputil::nearest_integer(pm.hi + ph_lo_frac); + double pm_hi_frac = pm.hi - km; // Exact + // x * 128/pi mod 1 ~ y_hi + y_lo + y_hi = ph_lo_frac + pm_hi_frac; // Exact + pm_lo = pm.lo; + return static_cast(static_cast(kh) + + static_cast(km)); + } + + LIBC_INLINE DoubleDouble fast() const { + // y_lo = x * c_lo + pm.lo + double y_lo = fputil::multiply_add(x_reduced, + ONE_TWENTY_EIGHT_OVER_PI[idx][2], pm_lo); + DoubleDouble y = fputil::exact_add(y_hi, y_lo); + + // Digits of pi/128, generated by Sollya with: + // > a = round(pi/128, D, RN); + // > b = round(pi/128 - a, D, RN); + constexpr DoubleDouble PI_OVER_128_DD = {0x1.1a62633145c07p-60, + 0x1.921fb54442d18p-6}; + + // Error bound: with {a} denote the fractional part of a, i.e.: + // {a} = a - round(a) + // Then, + // | {x * 128/pi} - (y_hi + y_lo) | < 2 * ulp(x_reduced * + // * ONE_TWENTY_EIGHT_OVER_PI[idx][2]) + // For FMA: + // | {x * 128/pi} - (y_hi + y_lo) | <= 2 * 2^77 * 2^-103 * 2^-52 + // = 2^-77. + // | {x mod pi/128} - (u.hi + u.lo) | < 2 * 2^-6 * 2^-77. + // = 2^-82. + // For non-FMA: + // | {x * 128/pi} - (y_hi + y_lo) | <= 2 * 2^77 * 2^-99 * 2^-52 + // = 2^-73. + // | {x mod pi/128} - (u.hi + u.lo) | < 2 * 2^-6 * 2^-73. + // = 2^-78. + return fputil::quick_mult(y, PI_OVER_128_DD); + } + + LIBC_INLINE Float128 accurate() const { + // y_lo = x * c_lo + pm.lo + Float128 y_lo_0(x_reduced * ONE_TWENTY_EIGHT_OVER_PI[idx][3]); + Float128 y_lo_1 = fputil::quick_mul( + Float128(x_reduced), Float128(ONE_TWENTY_EIGHT_OVER_PI[idx][2])); + Float128 y_lo_2(pm_lo); + Float128 y_hi_f128(y_hi); + + Float128 y = fputil::quick_add( + y_hi_f128, + fputil::quick_add(y_lo_2, fputil::quick_add(y_lo_1, y_lo_0))); + + return fputil::quick_mul(y, PI_OVER_128_F128); + } + +private: + // Index of x in the look-up table ONE_TWENTY_EIGHT_OVER_PI. + unsigned idx; + // x scaled down by 2^(-16 *(idx - 3))). + double x_reduced; + // High part of (x * 128/pi) mod 1. + double y_hi; + // Low part of x * ONE_TWENTY_EIGHT_OVER_PI[idx][1]. + double pm_lo; +}; + +LIBC_INLINE Float128 range_reduction_small_f128(double x) { + double prod_hi = x * ONE_TWENTY_EIGHT_OVER_PI[3][0]; + double kd = fputil::nearest_integer(prod_hi); + + Float128 mk_f128(-kd); + Float128 x_f128(x); + Float128 p_hi = + fputil::quick_mul(x_f128, Float128(ONE_TWENTY_EIGHT_OVER_PI[3][0])); + Float128 p_mid = + fputil::quick_mul(x_f128, Float128(ONE_TWENTY_EIGHT_OVER_PI[3][1])); + Float128 p_lo = + fputil::quick_mul(x_f128, Float128(ONE_TWENTY_EIGHT_OVER_PI[3][2])); + Float128 s_hi = fputil::quick_add(p_hi, mk_f128); + Float128 s_lo = fputil::quick_add(p_mid, p_lo); + Float128 y = fputil::quick_add(s_hi, s_lo); + + return fputil::quick_mul(y, PI_OVER_128_F128); +} + +LIBC_INLINE constexpr Float128 SIN_K_PI_OVER_128_F128[65] = { + {Sign::POS, 0, 0}, + {Sign::POS, -133, 0xc90a'afbd'1b33'efc9'c539'edcb'fda0'cf2c_u128}, + {Sign::POS, -132, 0xc8fb'2f88'6ec0'9f37'6a17'954b'2b7c'5171_u128}, + {Sign::POS, -131, 0x96a9'0496'70cf'ae65'f775'7409'4d3c'35c4_u128}, + {Sign::POS, -131, 0xc8bd'35e1'4da1'5f0e'c739'6c89'4bbf'7389_u128}, + {Sign::POS, -131, 0xfab2'72b5'4b98'71a2'7047'29ae'56d7'8a37_u128}, + {Sign::POS, -130, 0x9640'8374'7309'd113'000a'89a1'1e07'c1fe_u128}, + {Sign::POS, -130, 0xaf10'a224'59fe'32a6'3fee'f3bb'58b1'f10d_u128}, + {Sign::POS, -130, 0xc7c5'c1e3'4d30'55b2'5cc8'c00e'4fcc'd850_u128}, + {Sign::POS, -130, 0xe05c'1353'f27b'17e5'0ebc'61ad'e6ca'83cd_u128}, + {Sign::POS, -130, 0xf8cf'cbd9'0af8'd57a'4221'dc4b'a772'598d_u128}, + {Sign::POS, -129, 0x888e'9315'8fb3'bb04'9841'56f5'5334'4306_u128}, + {Sign::POS, -129, 0x94a0'3176'acf8'2d45'ae4b'a773'da6b'f754_u128}, + {Sign::POS, -129, 0xa09a'e4a0'bb30'0a19'2f89'5f44'a303'cc0b_u128}, + {Sign::POS, -129, 0xac7c'd3ad'58fe'e7f0'811f'9539'84ef'f83e_u128}, + {Sign::POS, -129, 0xb844'2987'd22c'f576'9cc3'ef36'746d'e3b8_u128}, + {Sign::POS, -129, 0xc3ef'1535'754b'168d'3122'c2a5'9efd'dc37_u128}, + {Sign::POS, -129, 0xcf7b'ca1d'476c'516d'a812'90bd'baad'62e4_u128}, + {Sign::POS, -129, 0xdae8'804f'0ae6'015b'362c'b974'182e'3030_u128}, + {Sign::POS, -129, 0xe633'74c9'8e22'f0b4'2872'ce1b'fc7a'd1cd_u128}, + {Sign::POS, -129, 0xf15a'e9c0'37b1'd8f0'6c48'e9e3'420b'0f1e_u128}, + {Sign::POS, -129, 0xfc5d'26df'c4d5'cfda'27c0'7c91'1290'b8d1_u128}, + {Sign::POS, -128, 0x839c'3cc9'17ff'6cb4'bfd7'9717'f288'0abf_u128}, + {Sign::POS, -128, 0x88f5'9aa0'da59'1421'b892'ca83'61d8'c84c_u128}, + {Sign::POS, -128, 0x8e39'd9cd'7346'4364'bba4'cfec'bff5'4867_u128}, + {Sign::POS, -128, 0x9368'2a66'e896'f544'b178'2191'1e71'c16e_u128}, + {Sign::POS, -128, 0x987f'bfe7'0b81'a708'19ce'c845'ac87'a5c6_u128}, + {Sign::POS, -128, 0x9d7f'd149'0285'c9e3'e25e'3954'9638'ae68_u128}, + {Sign::POS, -128, 0xa267'9928'48ee'b0c0'3b51'67ee'359a'234e_u128}, + {Sign::POS, -128, 0xa736'55df'1f2f'489e'149f'6e75'9934'68a3_u128}, + {Sign::POS, -128, 0xabeb'49a4'6764'fd15'1bec'da80'89c1'a94c_u128}, + {Sign::POS, -128, 0xb085'baa8'e966'f6da'e4ca'd00d'5c94'bcd2_u128}, + {Sign::POS, -128, 0xb504'f333'f9de'6484'597d'89b3'754a'be9f_u128}, + {Sign::POS, -128, 0xb968'41bf'7ffc'b21a'9de1'e3b2'2b8b'f4db_u128}, + {Sign::POS, -128, 0xbdae'f913'557d'76f0'ac85'320f'528d'6d5d_u128}, + {Sign::POS, -128, 0xc1d8'705f'fcbb'6e90'bdf0'715c'b8b2'0bd7_u128}, + {Sign::POS, -128, 0xc5e4'0358'a8ba'05a7'43da'25d9'9267'326b_u128}, + {Sign::POS, -128, 0xc9d1'124c'931f'da7a'8335'241b'e169'3225_u128}, + {Sign::POS, -128, 0xcd9f'023f'9c3a'059e'23af'31db'7179'a4aa_u128}, + {Sign::POS, -128, 0xd14d'3d02'313c'0eed'744f'ea20'e8ab'ef92_u128}, + {Sign::POS, -128, 0xd4db'3148'750d'1819'f630'e8b6'dac8'3e69_u128}, + {Sign::POS, -128, 0xd848'52c0'a80f'fcdb'24b9'fe00'6635'74a4_u128}, + {Sign::POS, -128, 0xdb94'1a28'cb71'ec87'2c19'b632'53da'43fc_u128}, + {Sign::POS, -128, 0xdebe'0563'7ca9'4cfb'4b19'aa71'fec3'ae6d_u128}, + {Sign::POS, -128, 0xe1c5'978c'05ed'8691'f4e8'a837'2f8c'5810_u128}, + {Sign::POS, -128, 0xe4aa'5909'a08f'a7b4'1227'85ae'67f5'515d_u128}, + {Sign::POS, -128, 0xe76b'd7a1'e63b'9786'1251'2952'9d48'a92f_u128}, + {Sign::POS, -128, 0xea09'a68a'6e49'cd62'15ad'45b4'a1b5'e823_u128}, + {Sign::POS, -128, 0xec83'5e79'946a'3145'7e61'0231'ac1d'6181_u128}, + {Sign::POS, -128, 0xeed8'9db6'6611'e307'86f8'c20f'b664'b01b_u128}, + {Sign::POS, -128, 0xf109'0827'b437'25fd'6712'7db3'5b28'7316_u128}, + {Sign::POS, -128, 0xf314'4762'4708'8f74'a548'6bdc'455d'56a2_u128}, + {Sign::POS, -128, 0xf4fa'0ab6'316e'd2ec'163c'5c7f'03b7'18c5_u128}, + {Sign::POS, -128, 0xf6ba'073b'424b'19e8'2c79'1f59'cc1f'fc23_u128}, + {Sign::POS, -128, 0xf853'f7dc'9186'b952'c7ad'c6b4'9888'91bb_u128}, + {Sign::POS, -128, 0xf9c7'9d63'272c'4628'4504'ae08'd19b'2980_u128}, + {Sign::POS, -128, 0xfb14'be7f'bae5'8156'2172'a361'fd2a'722f_u128}, + {Sign::POS, -128, 0xfc3b'27d3'8a5d'49ab'2567'78ff'cb5c'1769_u128}, + {Sign::POS, -128, 0xfd3a'abf8'4528'b50b'eae6'bd95'1c1d'abbe_u128}, + {Sign::POS, -128, 0xfe13'2387'0cfe'9a3d'90cd'1d95'9db6'74ef_u128}, + {Sign::POS, -128, 0xfec4'6d1e'8929'2cf0'4139'0efd'c726'e9ef_u128}, + {Sign::POS, -128, 0xff4e'6d68'0c41'd0a9'0f66'8633'f1ab'858a_u128}, + {Sign::POS, -128, 0xffb1'0f1b'cb6b'ef1d'421e'8eda'af59'453e_u128}, + {Sign::POS, -128, 0xffec'4304'2668'65d9'5657'5523'6696'1732_u128}, + {Sign::POS, 0, 1}, +}; + +} // namespace generic + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_GENERIC_RANGE_REDUCTION_DOUBLE_COMMON_H diff --git a/libc/src/math/generic/range_reduction_double_fma.h b/libc/src/math/generic/range_reduction_double_fma.h new file mode 100644 index 00000000000000..c136de957d2f05 --- /dev/null +++ b/libc/src/math/generic/range_reduction_double_fma.h @@ -0,0 +1,495 @@ +//===-- Range reduction for double precision sin/cos/tan w/ FMA -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_GENERIC_RANGE_REDUCTION_DOUBLE_FMA_H +#define LLVM_LIBC_SRC_MATH_GENERIC_RANGE_REDUCTION_DOUBLE_FMA_H + +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/double_double.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/nearest_integer.h" +#include "src/__support/common.h" + +namespace LIBC_NAMESPACE { + +namespace fma { + +using LIBC_NAMESPACE::fputil::DoubleDouble; + +LIBC_INLINE constexpr int FAST_PASS_EXPONENT = 32; + +// Digits of 2^(16*i) / pi, generated by Sollya with: +// For [2..62]: +// > for i from 3 to 63 do { +// pi_inv = 2^(16*(i - 3)) / pi; +// pn = nearestint(pi_inv); +// pi_frac = pi_inv - pn; +// a = round(pi_frac, D, RN); +// b = round(pi_frac - a, D, RN); +// c = round(pi_frac - a - b, D, RN); +// d = round(pi_frac - a - b - c, D, RN); +// print("{", 2^7 * a, ",", 2^7 * b, ",", 2^7 * c, ",", 2^7 * d, "},"); +// }; +// For [0..1]: +// The leading bit of 2^(16*(i - 3)) / pi is very small, so we add 0.25 so that +// the conditions for the algorithms are still satisfied, and one of those +// conditions guarantees that ulp(0.25 * x_reduced) >= 2, and will safely be +// discarded. +// for i from 0 to 2 do { +// pi_frac = 0.25 + 2^(16*(i - 3)) / pi; +// a = round(pi_frac, D, RN); +// b = round(pi_frac - a, D, RN); +// c = round(pi_frac - a - b, D, RN); +// d = round(pi_frac - a - b - c, D, RN); +// print("{", 2^7 * a, ",", 2^7 * b, ",", 2^7 * c, ",", 2^7 * d, "},"); +// }; +// For The fast pass using double-double, we only need 3 parts (a, b, c), but +// for the accurate pass using Float128, instead of using another table of +// Float128s, we simply add the fourth path (a, b, c, d), which simplify the +// implementation a bit and saving some memory. +LIBC_INLINE constexpr double ONE_TWENTY_EIGHT_OVER_PI[64][4] = { + {0x1.0000000000014p5, 0x1.7cc1b727220a9p-49, 0x1.3f84eafa3ea6ap-103, + -0x1.11f924eb53362p-157}, + {0x1.0000000145f3p5, 0x1.b727220a94fe1p-49, 0x1.d5f47d4d37703p-104, + 0x1.b6295993c439p-158}, + {0x1.000145f306dcap5, -0x1.bbead603d8a83p-50, 0x1.f534ddc0db629p-106, + 0x1.664f10e4107f9p-160}, + {0x1.45f306dc9c883p5, -0x1.6b01ec5417056p-49, -0x1.6447e493ad4cep-103, + 0x1.e21c820ff28b2p-157}, + {-0x1.f246c6efab581p4, 0x1.3abe8fa9a6eep-53, 0x1.b6c52b3278872p-107, + 0x1.07f9458eaf7afp-164}, + {0x1.391054a7f09d6p4, -0x1.70565911f924fp-53, 0x1.2b3278872084p-107, + -0x1.ae9c5421443aap-162}, + {0x1.529fc2757d1f5p2, 0x1.a6ee06db14acdp-53, -0x1.8778df7c035d4p-107, + 0x1.d5ef5de2b0db9p-161}, + {-0x1.ec54170565912p-1, 0x1.b6c52b3278872p-59, 0x1.07f9458eaf7afp-116, + -0x1.d4f246dc8e2dfp-173}, + {-0x1.505c1596447e5p5, 0x1.b14acc9e21c82p-49, 0x1.fe5163abdebbcp-106, + 0x1.586dc91b8e909p-160}, + {-0x1.596447e493ad5p1, 0x1.93c439041fe51p-54, 0x1.8eaf7aef1586ep-108, + -0x1.b7238b7b645a4p-163}, + {0x1.bb81b6c52b328p5, -0x1.de37df00d74e3p-49, 0x1.7bd778ac36e49p-103, + -0x1.1c5bdb22d1ffap-158}, + {0x1.b6c52b3278872p5, 0x1.07f9458eaf7afp-52, -0x1.d4f246dc8e2dfp-109, + 0x1.374b801924bbbp-164}, + {0x1.2b3278872084p5, -0x1.ae9c5421443aap-50, 0x1.b7246e3a424ddp-106, + 0x1.700324977504fp-161}, + {-0x1.8778df7c035d4p5, 0x1.d5ef5de2b0db9p-49, 0x1.1b8e909374b8p-104, + 0x1.924bba8274648p-160}, + {-0x1.bef806ba71508p4, -0x1.443a9e48db91cp-50, -0x1.6f6c8b47fe6dbp-104, + -0x1.115f62e6de302p-158}, + {-0x1.ae9c5421443aap-2, 0x1.b7246e3a424ddp-58, 0x1.700324977504fp-113, + -0x1.cdbc603c429c7p-167}, + {-0x1.38a84288753c9p5, -0x1.b7238b7b645a4p-51, 0x1.924bba8274648p-112, + 0x1.cfe1deb1cb12ap-166}, + {-0x1.0a21d4f246dc9p3, 0x1.d2126e9700325p-53, -0x1.a22bec5cdbc6p-107, + -0x1.e214e34ed658cp-162}, + {-0x1.d4f246dc8e2dfp3, 0x1.374b801924bbbp-52, -0x1.f62e6de301e21p-106, + -0x1.38d3b5963045ep-160}, + {-0x1.236e4716f6c8bp4, -0x1.1ff9b6d115f63p-50, 0x1.921cfe1deb1cbp-106, + 0x1.29a73ee88235fp-162}, + {0x1.b8e909374b802p4, -0x1.b6d115f62e6dep-50, -0x1.80f10a71a76b3p-105, + 0x1.cfba208d7d4bbp-160}, + {0x1.09374b801924cp4, -0x1.15f62e6de301ep-50, -0x1.0a71a76b2c609p-105, + 0x1.1046bea5d7689p-159}, + {-0x1.68ffcdb688afbp3, -0x1.736f180f10a72p-53, 0x1.62534e7dd1047p-107, + -0x1.0568a25dbd8b3p-161}, + {0x1.924bba8274648p0, 0x1.cfe1deb1cb12ap-54, -0x1.63045df7282b4p-108, + -0x1.44bb7b16638fep-162}, + {-0x1.a22bec5cdbc6p5, -0x1.e214e34ed658cp-50, -0x1.177dca0ad144cp-106, + 0x1.213a671c09ad1p-160}, + {0x1.3a32439fc3bd6p1, 0x1.cb129a73ee882p-54, 0x1.afa975da24275p-109, + -0x1.8e3f652e8207p-164}, + {-0x1.b78c0788538d4p4, 0x1.29a73ee88235fp-50, 0x1.4baed1213a672p-104, + -0x1.fb29741037d8dp-159}, + {0x1.fc3bd63962535p5, -0x1.822efb9415a29p-51, 0x1.a24274ce38136p-105, + -0x1.741037d8cdc54p-159}, + {-0x1.4e34ed658c117p2, -0x1.f7282b4512edfp-52, 0x1.d338e04d68bfp-107, + -0x1.bec66e29c67cbp-162}, + {0x1.62534e7dd1047p5, -0x1.0568a25dbd8b3p-49, -0x1.c7eca5d040df6p-105, + -0x1.9b8a719f2b318p-160}, + {-0x1.63045df7282b4p4, -0x1.44bb7b16638fep-50, 0x1.ad17df904e647p-104, + 0x1.639835339f49dp-158}, + {0x1.d1046bea5d769p5, -0x1.bd8b31c7eca5dp-49, -0x1.037d8cdc538dp-107, + 0x1.a99cfa4e422fcp-161}, + {0x1.afa975da24275p3, -0x1.8e3f652e8207p-52, 0x1.3991d63983534p-106, + -0x1.82d8dee81d108p-160}, + {-0x1.a28976f62cc72p5, 0x1.35a2fbf209cc9p-53, -0x1.4e33e566305b2p-109, + 0x1.08bf177bf2507p-163}, + {-0x1.76f62cc71fb29p5, -0x1.d040df633714ep-49, -0x1.9f2b3182d8defp-104, + 0x1.f8bbdf9283b2p-158}, + {0x1.d338e04d68bfp5, -0x1.bec66e29c67cbp-50, 0x1.9cfa4e422fc5ep-105, + -0x1.036be27003b4p-161}, + {0x1.c09ad17df904ep4, 0x1.91d639835339fp-50, 0x1.272117e2ef7e5p-104, + -0x1.7c4e007680022p-158}, + {0x1.68befc827323bp5, -0x1.c67cacc60b638p-50, 0x1.17e2ef7e4a0ecp-104, + 0x1.ff897ffde0598p-158}, + {-0x1.037d8cdc538dp5, 0x1.a99cfa4e422fcp-49, 0x1.77bf250763ff1p-103, + 0x1.7ffde05980fefp-158}, + {-0x1.8cdc538cf9599p5, 0x1.f49c845f8bbep-50, -0x1.b5f13801da001p-104, + 0x1.e05980fef2f12p-158}, + {-0x1.4e33e566305b2p3, 0x1.08bf177bf2507p-51, 0x1.8ffc4bffef02dp-105, + -0x1.fc04343b9d298p-160}, + {-0x1.f2b3182d8dee8p4, -0x1.d1081b5f13802p-52, 0x1.2fffbc0b301fep-107, + -0x1.a1dce94beb25cp-163}, + {-0x1.8c16c6f740e88p5, -0x1.036be27003b4p-49, -0x1.0fd33f8086877p-109, + -0x1.d297d64b824b2p-164}, + {0x1.3908bf177bf25p5, 0x1.d8ffc4bffef03p-53, -0x1.9fc04343b9d29p-108, + -0x1.f592e092c9813p-162}, + {0x1.7e2ef7e4a0ec8p4, -0x1.da00087e99fcp-56, -0x1.0d0ee74a5f593p-110, + 0x1.f6d367ecf27cbp-166}, + {-0x1.081b5f13801dap4, -0x1.0fd33f8086877p-61, -0x1.d297d64b824b2p-116, + -0x1.8130d834f648bp-170}, + {-0x1.af89c00ed0004p5, -0x1.fa67f010d0ee7p-50, -0x1.297d64b824b26p-104, + -0x1.30d834f648b0cp-162}, + {-0x1.c00ed00043f4dp5, 0x1.fde5e2316b415p-55, -0x1.2e092c98130d8p-110, + -0x1.a7b24585ce04dp-165}, + {0x1.2fffbc0b301fep5, -0x1.a1dce94beb25cp-51, -0x1.25930261b069fp-107, + 0x1.b74f463f669e6p-162}, + {-0x1.0fd33f8086877p3, -0x1.d297d64b824b2p-52, -0x1.8130d834f648bp-106, + -0x1.738132c3402bap-163}, + {-0x1.9fc04343b9d29p4, -0x1.f592e092c9813p-50, -0x1.b069ec9161738p-107, + -0x1.32c3402ba515bp-163}, + {-0x1.0d0ee74a5f593p2, 0x1.f6d367ecf27cbp-54, 0x1.36e9e8c7ecd3dp-111, + -0x1.00ae9456c229cp-165}, + {-0x1.dce94beb25c12p5, -0x1.64c0986c1a7b2p-49, -0x1.161738132c34p-103, + -0x1.5d28ad8453814p-158}, + {-0x1.4beb25c12593p5, -0x1.30d834f648b0cp-50, 0x1.8fd9a797fa8b6p-104, + -0x1.5b08a7028341dp-159}, + {0x1.b47db4d9fb3cap4, -0x1.a7b24585ce04dp-53, 0x1.3cbfd45aea4f7p-107, + 0x1.63f5f2f8bd9e8p-161}, + {-0x1.25930261b069fp5, 0x1.b74f463f669e6p-50, -0x1.5d28ad8453814p-110, + -0x1.a0e84c2f8c608p-166}, + {0x1.fb3c9f2c26dd4p4, -0x1.738132c3402bap-51, -0x1.456c229c0a0dp-105, + -0x1.d0985f18c10ebp-159}, + {-0x1.b069ec9161738p5, -0x1.32c3402ba515bp-51, -0x1.14e050683a131p-108, + 0x1.0739f78a5292fp-162}, + {-0x1.ec9161738132cp5, -0x1.a015d28ad8454p-50, 0x1.faf97c5ecf41dp-104, + -0x1.821d6b5b4565p-160}, + {-0x1.61738132c3403p5, 0x1.16ba93dd63f5fp-49, 0x1.7c5ecf41ce7dep-104, + 0x1.4a525d4d7f6bfp-159}, + {0x1.fb34f2ff516bbp3, -0x1.b08a7028341d1p-51, 0x1.9e839cfbc5295p-105, + -0x1.a2b2809409dc1p-159}, + {0x1.3cbfd45aea4f7p5, 0x1.63f5f2f8bd9e8p-49, 0x1.ce7de294a4baap-104, + -0x1.404a04ee072a3p-158}, + {-0x1.5d28ad8453814p2, -0x1.a0e84c2f8c608p-54, -0x1.d6b5b45650128p-108, + -0x1.3b81ca8bdea7fp-164}, + {-0x1.15b08a7028342p5, 0x1.7b3d0739f78a5p-50, 0x1.497535fdafd89p-105, + -0x1.ca8bdea7f33eep-164}, +}; + +// Lookup table for sin(k * pi / 128) with k = 0, ..., 255. +// Table is generated with Sollya as follow: +// > display = hexadecimal; +// > for k from 0 to 255 do { +// a = D(sin(k * pi/128)); }; +// b = D(sin(k * pi/128) - a); +// print("{", b, ",", a, "},"); +// }; +LIBC_INLINE constexpr DoubleDouble SIN_K_PI_OVER_128[256] = { + {0, 0}, + {-0x1.b1d63091a013p-64, 0x1.92155f7a3667ep-6}, + {-0x1.912bd0d569a9p-61, 0x1.91f65f10dd814p-5}, + {-0x1.9a088a8bf6b2cp-59, 0x1.2d52092ce19f6p-4}, + {-0x1.e2718d26ed688p-60, 0x1.917a6bc29b42cp-4}, + {0x1.a2704729ae56dp-59, 0x1.f564e56a9730ep-4}, + {0x1.13000a89a11ep-58, 0x1.2c8106e8e613ap-3}, + {0x1.531ff779ddac6p-57, 0x1.5e214448b3fc6p-3}, + {-0x1.26d19b9ff8d82p-57, 0x1.8f8b83c69a60bp-3}, + {-0x1.af1439e521935p-62, 0x1.c0b826a7e4f63p-3}, + {-0x1.42deef11da2c4p-57, 0x1.f19f97b215f1bp-3}, + {0x1.824c20ab7aa9ap-56, 0x1.111d262b1f677p-2}, + {-0x1.5d28da2c4612dp-56, 0x1.294062ed59f06p-2}, + {0x1.0c97c4afa2518p-56, 0x1.4135c94176601p-2}, + {-0x1.efdc0d58cf62p-62, 0x1.58f9a75ab1fddp-2}, + {-0x1.44b19e0864c5dp-56, 0x1.7088530fa459fp-2}, + {-0x1.72cedd3d5a61p-57, 0x1.87de2a6aea963p-2}, + {0x1.6da81290bdbabp-57, 0x1.9ef7943a8ed8ap-2}, + {0x1.5b362cb974183p-57, 0x1.b5d1009e15ccp-2}, + {0x1.6850e59c37f8fp-58, 0x1.cc66e9931c45ep-2}, + {0x1.e0d891d3c6841p-58, 0x1.e2b5d3806f63bp-2}, + {-0x1.2ec1fc1b776b8p-60, 0x1.f8ba4dbf89abap-2}, + {-0x1.a5a014347406cp-55, 0x1.073879922ffeep-1}, + {-0x1.ef23b69abe4f1p-55, 0x1.11eb3541b4b23p-1}, + {0x1.b25dd267f66p-55, 0x1.1c73b39ae68c8p-1}, + {-0x1.5da743ef3770cp-55, 0x1.26d054cdd12dfp-1}, + {-0x1.efcc626f74a6fp-57, 0x1.30ff7fce17035p-1}, + {0x1.e3e25e3954964p-56, 0x1.3affa292050b9p-1}, + {0x1.8076a2cfdc6b3p-57, 0x1.44cf325091dd6p-1}, + {0x1.3c293edceb327p-57, 0x1.4e6cabbe3e5e9p-1}, + {-0x1.75720992bfbb2p-55, 0x1.57d69348cecap-1}, + {-0x1.251b352ff2a37p-56, 0x1.610b7551d2cdfp-1}, + {-0x1.bdd3413b26456p-55, 0x1.6a09e667f3bcdp-1}, + {0x1.0d4ef0f1d915cp-55, 0x1.72d0837efff96p-1}, + {-0x1.0f537acdf0ad7p-56, 0x1.7b5df226aafafp-1}, + {-0x1.6f420f8ea3475p-56, 0x1.83b0e0bff976ep-1}, + {-0x1.2c5e12ed1336dp-55, 0x1.8bc806b151741p-1}, + {0x1.3d419a920df0bp-55, 0x1.93a22499263fbp-1}, + {-0x1.30ee286712474p-55, 0x1.9b3e047f38741p-1}, + {-0x1.128bb015df175p-56, 0x1.a29a7a0462782p-1}, + {0x1.9f630e8b6dac8p-60, 0x1.a9b66290ea1a3p-1}, + {-0x1.926da300ffccep-55, 0x1.b090a581502p-1}, + {-0x1.bc69f324e6d61p-55, 0x1.b728345196e3ep-1}, + {-0x1.825a732ac700ap-55, 0x1.bd7c0ac6f952ap-1}, + {-0x1.6e0b1757c8d07p-56, 0x1.c38b2f180bdb1p-1}, + {-0x1.2fb761e946603p-58, 0x1.c954b213411f5p-1}, + {-0x1.e7b6bb5ab58aep-58, 0x1.ced7af43cc773p-1}, + {-0x1.4ef5295d25af2p-55, 0x1.d4134d14dc93ap-1}, + {0x1.457e610231ac2p-56, 0x1.d906bcf328d46p-1}, + {0x1.83c37c6107db3p-55, 0x1.ddb13b6ccc23cp-1}, + {-0x1.014c76c126527p-55, 0x1.e212104f686e5p-1}, + {-0x1.16b56f2847754p-57, 0x1.e6288ec48e112p-1}, + {0x1.760b1e2e3f81ep-55, 0x1.e9f4156c62ddap-1}, + {0x1.e82c791f59cc2p-56, 0x1.ed740e7684963p-1}, + {0x1.52c7adc6b4989p-56, 0x1.f0a7efb9230d7p-1}, + {-0x1.d7bafb51f72e6p-56, 0x1.f38f3ac64e589p-1}, + {0x1.562172a361fd3p-56, 0x1.f6297cff75cbp-1}, + {0x1.ab256778ffcb6p-56, 0x1.f8764fa714ba9p-1}, + {-0x1.7a0a8ca13571fp-55, 0x1.fa7557f08a517p-1}, + {0x1.1ec8668ecaceep-55, 0x1.fc26470e19fd3p-1}, + {-0x1.87df6378811c7p-55, 0x1.fd88da3d12526p-1}, + {0x1.521ecd0c67e35p-57, 0x1.fe9cdad01883ap-1}, + {-0x1.c57bc2e24aa15p-57, 0x1.ff621e3796d7ep-1}, + {-0x1.1354d4556e4cbp-55, 0x1.ffd886084cd0dp-1}, + {0, 1}, + {-0x1.1354d4556e4cbp-55, 0x1.ffd886084cd0dp-1}, + {-0x1.c57bc2e24aa15p-57, 0x1.ff621e3796d7ep-1}, + {0x1.521ecd0c67e35p-57, 0x1.fe9cdad01883ap-1}, + {-0x1.87df6378811c7p-55, 0x1.fd88da3d12526p-1}, + {0x1.1ec8668ecaceep-55, 0x1.fc26470e19fd3p-1}, + {-0x1.7a0a8ca13571fp-55, 0x1.fa7557f08a517p-1}, + {0x1.ab256778ffcb6p-56, 0x1.f8764fa714ba9p-1}, + {0x1.562172a361fd3p-56, 0x1.f6297cff75cbp-1}, + {-0x1.d7bafb51f72e6p-56, 0x1.f38f3ac64e589p-1}, + {0x1.52c7adc6b4989p-56, 0x1.f0a7efb9230d7p-1}, + {0x1.e82c791f59cc2p-56, 0x1.ed740e7684963p-1}, + {0x1.760b1e2e3f81ep-55, 0x1.e9f4156c62ddap-1}, + {-0x1.16b56f2847754p-57, 0x1.e6288ec48e112p-1}, + {-0x1.014c76c126527p-55, 0x1.e212104f686e5p-1}, + {0x1.83c37c6107db3p-55, 0x1.ddb13b6ccc23cp-1}, + {0x1.457e610231ac2p-56, 0x1.d906bcf328d46p-1}, + {-0x1.4ef5295d25af2p-55, 0x1.d4134d14dc93ap-1}, + {-0x1.e7b6bb5ab58aep-58, 0x1.ced7af43cc773p-1}, + {-0x1.2fb761e946603p-58, 0x1.c954b213411f5p-1}, + {-0x1.6e0b1757c8d07p-56, 0x1.c38b2f180bdb1p-1}, + {-0x1.825a732ac700ap-55, 0x1.bd7c0ac6f952ap-1}, + {-0x1.bc69f324e6d61p-55, 0x1.b728345196e3ep-1}, + {-0x1.926da300ffccep-55, 0x1.b090a581502p-1}, + {0x1.9f630e8b6dac8p-60, 0x1.a9b66290ea1a3p-1}, + {-0x1.128bb015df175p-56, 0x1.a29a7a0462782p-1}, + {-0x1.30ee286712474p-55, 0x1.9b3e047f38741p-1}, + {0x1.3d419a920df0bp-55, 0x1.93a22499263fbp-1}, + {-0x1.2c5e12ed1336dp-55, 0x1.8bc806b151741p-1}, + {-0x1.6f420f8ea3475p-56, 0x1.83b0e0bff976ep-1}, + {-0x1.0f537acdf0ad7p-56, 0x1.7b5df226aafafp-1}, + {0x1.0d4ef0f1d915cp-55, 0x1.72d0837efff96p-1}, + {-0x1.bdd3413b26456p-55, 0x1.6a09e667f3bcdp-1}, + {-0x1.251b352ff2a37p-56, 0x1.610b7551d2cdfp-1}, + {-0x1.75720992bfbb2p-55, 0x1.57d69348cecap-1}, + {0x1.3c293edceb327p-57, 0x1.4e6cabbe3e5e9p-1}, + {0x1.8076a2cfdc6b3p-57, 0x1.44cf325091dd6p-1}, + {0x1.e3e25e3954964p-56, 0x1.3affa292050b9p-1}, + {-0x1.efcc626f74a6fp-57, 0x1.30ff7fce17035p-1}, + {-0x1.5da743ef3770cp-55, 0x1.26d054cdd12dfp-1}, + {0x1.b25dd267f66p-55, 0x1.1c73b39ae68c8p-1}, + {-0x1.ef23b69abe4f1p-55, 0x1.11eb3541b4b23p-1}, + {-0x1.a5a014347406cp-55, 0x1.073879922ffeep-1}, + {-0x1.2ec1fc1b776b8p-60, 0x1.f8ba4dbf89abap-2}, + {0x1.e0d891d3c6841p-58, 0x1.e2b5d3806f63bp-2}, + {0x1.6850e59c37f8fp-58, 0x1.cc66e9931c45ep-2}, + {0x1.5b362cb974183p-57, 0x1.b5d1009e15ccp-2}, + {0x1.6da81290bdbabp-57, 0x1.9ef7943a8ed8ap-2}, + {-0x1.72cedd3d5a61p-57, 0x1.87de2a6aea963p-2}, + {-0x1.44b19e0864c5dp-56, 0x1.7088530fa459fp-2}, + {-0x1.efdc0d58cf62p-62, 0x1.58f9a75ab1fddp-2}, + {0x1.0c97c4afa2518p-56, 0x1.4135c94176601p-2}, + {-0x1.5d28da2c4612dp-56, 0x1.294062ed59f06p-2}, + {0x1.824c20ab7aa9ap-56, 0x1.111d262b1f677p-2}, + {-0x1.42deef11da2c4p-57, 0x1.f19f97b215f1bp-3}, + {-0x1.af1439e521935p-62, 0x1.c0b826a7e4f63p-3}, + {-0x1.26d19b9ff8d82p-57, 0x1.8f8b83c69a60bp-3}, + {0x1.531ff779ddac6p-57, 0x1.5e214448b3fc6p-3}, + {0x1.13000a89a11ep-58, 0x1.2c8106e8e613ap-3}, + {0x1.a2704729ae56dp-59, 0x1.f564e56a9730ep-4}, + {-0x1.e2718d26ed688p-60, 0x1.917a6bc29b42cp-4}, + {-0x1.9a088a8bf6b2cp-59, 0x1.2d52092ce19f6p-4}, + {-0x1.912bd0d569a9p-61, 0x1.91f65f10dd814p-5}, + {-0x1.b1d63091a013p-64, 0x1.92155f7a3667ep-6}, + {0, 0}, + {0x1.b1d63091a013p-64, -0x1.92155f7a3667ep-6}, + {0x1.912bd0d569a9p-61, -0x1.91f65f10dd814p-5}, + {0x1.9a088a8bf6b2cp-59, -0x1.2d52092ce19f6p-4}, + {0x1.e2718d26ed688p-60, -0x1.917a6bc29b42cp-4}, + {-0x1.a2704729ae56dp-59, -0x1.f564e56a9730ep-4}, + {-0x1.13000a89a11ep-58, -0x1.2c8106e8e613ap-3}, + {-0x1.531ff779ddac6p-57, -0x1.5e214448b3fc6p-3}, + {0x1.26d19b9ff8d82p-57, -0x1.8f8b83c69a60bp-3}, + {0x1.af1439e521935p-62, -0x1.c0b826a7e4f63p-3}, + {0x1.42deef11da2c4p-57, -0x1.f19f97b215f1bp-3}, + {-0x1.824c20ab7aa9ap-56, -0x1.111d262b1f677p-2}, + {0x1.5d28da2c4612dp-56, -0x1.294062ed59f06p-2}, + {-0x1.0c97c4afa2518p-56, -0x1.4135c94176601p-2}, + {0x1.efdc0d58cf62p-62, -0x1.58f9a75ab1fddp-2}, + {0x1.44b19e0864c5dp-56, -0x1.7088530fa459fp-2}, + {0x1.72cedd3d5a61p-57, -0x1.87de2a6aea963p-2}, + {-0x1.6da81290bdbabp-57, -0x1.9ef7943a8ed8ap-2}, + {-0x1.5b362cb974183p-57, -0x1.b5d1009e15ccp-2}, + {-0x1.6850e59c37f8fp-58, -0x1.cc66e9931c45ep-2}, + {-0x1.e0d891d3c6841p-58, -0x1.e2b5d3806f63bp-2}, + {0x1.2ec1fc1b776b8p-60, -0x1.f8ba4dbf89abap-2}, + {0x1.a5a014347406cp-55, -0x1.073879922ffeep-1}, + {0x1.ef23b69abe4f1p-55, -0x1.11eb3541b4b23p-1}, + {-0x1.b25dd267f66p-55, -0x1.1c73b39ae68c8p-1}, + {0x1.5da743ef3770cp-55, -0x1.26d054cdd12dfp-1}, + {0x1.efcc626f74a6fp-57, -0x1.30ff7fce17035p-1}, + {-0x1.e3e25e3954964p-56, -0x1.3affa292050b9p-1}, + {-0x1.8076a2cfdc6b3p-57, -0x1.44cf325091dd6p-1}, + {-0x1.3c293edceb327p-57, -0x1.4e6cabbe3e5e9p-1}, + {0x1.75720992bfbb2p-55, -0x1.57d69348cecap-1}, + {0x1.251b352ff2a37p-56, -0x1.610b7551d2cdfp-1}, + {0x1.bdd3413b26456p-55, -0x1.6a09e667f3bcdp-1}, + {-0x1.0d4ef0f1d915cp-55, -0x1.72d0837efff96p-1}, + {0x1.0f537acdf0ad7p-56, -0x1.7b5df226aafafp-1}, + {0x1.6f420f8ea3475p-56, -0x1.83b0e0bff976ep-1}, + {0x1.2c5e12ed1336dp-55, -0x1.8bc806b151741p-1}, + {-0x1.3d419a920df0bp-55, -0x1.93a22499263fbp-1}, + {0x1.30ee286712474p-55, -0x1.9b3e047f38741p-1}, + {0x1.128bb015df175p-56, -0x1.a29a7a0462782p-1}, + {-0x1.9f630e8b6dac8p-60, -0x1.a9b66290ea1a3p-1}, + {0x1.926da300ffccep-55, -0x1.b090a581502p-1}, + {0x1.bc69f324e6d61p-55, -0x1.b728345196e3ep-1}, + {0x1.825a732ac700ap-55, -0x1.bd7c0ac6f952ap-1}, + {0x1.6e0b1757c8d07p-56, -0x1.c38b2f180bdb1p-1}, + {0x1.2fb761e946603p-58, -0x1.c954b213411f5p-1}, + {0x1.e7b6bb5ab58aep-58, -0x1.ced7af43cc773p-1}, + {0x1.4ef5295d25af2p-55, -0x1.d4134d14dc93ap-1}, + {-0x1.457e610231ac2p-56, -0x1.d906bcf328d46p-1}, + {-0x1.83c37c6107db3p-55, -0x1.ddb13b6ccc23cp-1}, + {0x1.014c76c126527p-55, -0x1.e212104f686e5p-1}, + {0x1.16b56f2847754p-57, -0x1.e6288ec48e112p-1}, + {-0x1.760b1e2e3f81ep-55, -0x1.e9f4156c62ddap-1}, + {-0x1.e82c791f59cc2p-56, -0x1.ed740e7684963p-1}, + {-0x1.52c7adc6b4989p-56, -0x1.f0a7efb9230d7p-1}, + {0x1.d7bafb51f72e6p-56, -0x1.f38f3ac64e589p-1}, + {-0x1.562172a361fd3p-56, -0x1.f6297cff75cbp-1}, + {-0x1.ab256778ffcb6p-56, -0x1.f8764fa714ba9p-1}, + {0x1.7a0a8ca13571fp-55, -0x1.fa7557f08a517p-1}, + {-0x1.1ec8668ecaceep-55, -0x1.fc26470e19fd3p-1}, + {0x1.87df6378811c7p-55, -0x1.fd88da3d12526p-1}, + {-0x1.521ecd0c67e35p-57, -0x1.fe9cdad01883ap-1}, + {0x1.c57bc2e24aa15p-57, -0x1.ff621e3796d7ep-1}, + {0x1.1354d4556e4cbp-55, -0x1.ffd886084cd0dp-1}, + {0, -1}, + {0x1.1354d4556e4cbp-55, -0x1.ffd886084cd0dp-1}, + {0x1.c57bc2e24aa15p-57, -0x1.ff621e3796d7ep-1}, + {-0x1.521ecd0c67e35p-57, -0x1.fe9cdad01883ap-1}, + {0x1.87df6378811c7p-55, -0x1.fd88da3d12526p-1}, + {-0x1.1ec8668ecaceep-55, -0x1.fc26470e19fd3p-1}, + {0x1.7a0a8ca13571fp-55, -0x1.fa7557f08a517p-1}, + {-0x1.ab256778ffcb6p-56, -0x1.f8764fa714ba9p-1}, + {-0x1.562172a361fd3p-56, -0x1.f6297cff75cbp-1}, + {0x1.d7bafb51f72e6p-56, -0x1.f38f3ac64e589p-1}, + {-0x1.52c7adc6b4989p-56, -0x1.f0a7efb9230d7p-1}, + {-0x1.e82c791f59cc2p-56, -0x1.ed740e7684963p-1}, + {-0x1.760b1e2e3f81ep-55, -0x1.e9f4156c62ddap-1}, + {0x1.16b56f2847754p-57, -0x1.e6288ec48e112p-1}, + {0x1.014c76c126527p-55, -0x1.e212104f686e5p-1}, + {-0x1.83c37c6107db3p-55, -0x1.ddb13b6ccc23cp-1}, + {-0x1.457e610231ac2p-56, -0x1.d906bcf328d46p-1}, + {0x1.4ef5295d25af2p-55, -0x1.d4134d14dc93ap-1}, + {0x1.e7b6bb5ab58aep-58, -0x1.ced7af43cc773p-1}, + {0x1.2fb761e946603p-58, -0x1.c954b213411f5p-1}, + {0x1.6e0b1757c8d07p-56, -0x1.c38b2f180bdb1p-1}, + {0x1.825a732ac700ap-55, -0x1.bd7c0ac6f952ap-1}, + {0x1.bc69f324e6d61p-55, -0x1.b728345196e3ep-1}, + {0x1.926da300ffccep-55, -0x1.b090a581502p-1}, + {-0x1.9f630e8b6dac8p-60, -0x1.a9b66290ea1a3p-1}, + {0x1.128bb015df175p-56, -0x1.a29a7a0462782p-1}, + {0x1.30ee286712474p-55, -0x1.9b3e047f38741p-1}, + {-0x1.3d419a920df0bp-55, -0x1.93a22499263fbp-1}, + {0x1.2c5e12ed1336dp-55, -0x1.8bc806b151741p-1}, + {0x1.6f420f8ea3475p-56, -0x1.83b0e0bff976ep-1}, + {0x1.0f537acdf0ad7p-56, -0x1.7b5df226aafafp-1}, + {-0x1.0d4ef0f1d915cp-55, -0x1.72d0837efff96p-1}, + {0x1.bdd3413b26456p-55, -0x1.6a09e667f3bcdp-1}, + {0x1.251b352ff2a37p-56, -0x1.610b7551d2cdfp-1}, + {0x1.75720992bfbb2p-55, -0x1.57d69348cecap-1}, + {-0x1.3c293edceb327p-57, -0x1.4e6cabbe3e5e9p-1}, + {-0x1.8076a2cfdc6b3p-57, -0x1.44cf325091dd6p-1}, + {-0x1.e3e25e3954964p-56, -0x1.3affa292050b9p-1}, + {0x1.efcc626f74a6fp-57, -0x1.30ff7fce17035p-1}, + {0x1.5da743ef3770cp-55, -0x1.26d054cdd12dfp-1}, + {-0x1.b25dd267f66p-55, -0x1.1c73b39ae68c8p-1}, + {0x1.ef23b69abe4f1p-55, -0x1.11eb3541b4b23p-1}, + {0x1.a5a014347406cp-55, -0x1.073879922ffeep-1}, + {0x1.2ec1fc1b776b8p-60, -0x1.f8ba4dbf89abap-2}, + {-0x1.e0d891d3c6841p-58, -0x1.e2b5d3806f63bp-2}, + {-0x1.6850e59c37f8fp-58, -0x1.cc66e9931c45ep-2}, + {-0x1.5b362cb974183p-57, -0x1.b5d1009e15ccp-2}, + {-0x1.6da81290bdbabp-57, -0x1.9ef7943a8ed8ap-2}, + {0x1.72cedd3d5a61p-57, -0x1.87de2a6aea963p-2}, + {0x1.44b19e0864c5dp-56, -0x1.7088530fa459fp-2}, + {0x1.efdc0d58cf62p-62, -0x1.58f9a75ab1fddp-2}, + {-0x1.0c97c4afa2518p-56, -0x1.4135c94176601p-2}, + {0x1.5d28da2c4612dp-56, -0x1.294062ed59f06p-2}, + {-0x1.824c20ab7aa9ap-56, -0x1.111d262b1f677p-2}, + {0x1.42deef11da2c4p-57, -0x1.f19f97b215f1bp-3}, + {0x1.af1439e521935p-62, -0x1.c0b826a7e4f63p-3}, + {0x1.26d19b9ff8d82p-57, -0x1.8f8b83c69a60bp-3}, + {-0x1.531ff779ddac6p-57, -0x1.5e214448b3fc6p-3}, + {-0x1.13000a89a11ep-58, -0x1.2c8106e8e613ap-3}, + {-0x1.a2704729ae56dp-59, -0x1.f564e56a9730ep-4}, + {0x1.e2718d26ed688p-60, -0x1.917a6bc29b42cp-4}, + {0x1.9a088a8bf6b2cp-59, -0x1.2d52092ce19f6p-4}, + {0x1.912bd0d569a9p-61, -0x1.91f65f10dd814p-5}, + {0x1.b1d63091a013p-64, -0x1.92155f7a3667ep-6}, +}; + +// For |x| < 2^-32, return k and u such that: +// k = round(x * 128/pi) +// x mod pi/128 = x - k * pi/128 ~ u.hi + u.lo +LIBC_INLINE unsigned range_reduction_small(double x, DoubleDouble &u) { + // Digits of pi/128, generated by Sollya with: + // > a = round(pi/128, D, RN); + // > b = round(pi/128 - a, D, RN); + constexpr DoubleDouble PI_OVER_128_DD = {0x1.1a62633145c07p-60, + 0x1.921fb54442d18p-6}; + + double prod_hi = x * ONE_TWENTY_EIGHT_OVER_PI[3][0]; + double kd = fputil::nearest_integer(prod_hi); + + // Let y = x - k * (pi/128) + // Then |y| < pi / 256 + // With extra rounding errors, we can bound |y| < 2^-6. + double y_hi = fputil::multiply_add(kd, -PI_OVER_128_DD.hi, x); // Exact + // u_hi + u_lo ~ (y_hi + kd*(-PI_OVER_128_DD[1])) + // and |u_lo| < 2* ulp(u_hi) + // The upper bound 2^-6 is over-estimated, we should still have: + // |u_hi + u_lo| < 2^-6. + u.hi = fputil::multiply_add(kd, -PI_OVER_128_DD.lo, y_hi); + u.lo = y_hi - u.hi; // Exact; + u.lo = fputil::multiply_add(kd, -PI_OVER_128_DD.lo, u.lo); + // Error bound: + // For |x| < 2^32: + // |x * high part of 128/pi| < 2^32 * 2^6 = 2^38 + // So |k| = |round(x * high part of 128/pi)| < 2^38 + // And hence, + // |(x mod pi/128) - (u.hi + u.lo)| <= ulp(2 * kd * PI_OVER_128_DD.lo) + // < 2 * 2^38 * 2^-59 * 2^-52 + // = 2^-72 + // Note: if we limit the input exponent to the same as in non-FMA version, + // i.e., |x| < 2^-23, then the output errors can be bounded by 2^-81, similar + // to the large range reduction bound. + return static_cast(static_cast(kd)); +} + +} // namespace fma + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_GENERIC_RANGE_REDUCTION_DOUBLE_FMA_H diff --git a/libc/src/math/generic/range_reduction_double_nofma.h b/libc/src/math/generic/range_reduction_double_nofma.h new file mode 100644 index 00000000000000..b9d34d6d9f1a8f --- /dev/null +++ b/libc/src/math/generic/range_reduction_double_nofma.h @@ -0,0 +1,493 @@ +//===-- Range reduction for double precision sin/cos/tan --------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_GENERIC_RANGE_REDUCTION_DOUBLE_NOFMA_H +#define LLVM_LIBC_SRC_MATH_GENERIC_RANGE_REDUCTION_DOUBLE_NOFMA_H + +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/double_double.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/nearest_integer.h" +#include "src/__support/common.h" + +namespace LIBC_NAMESPACE { + +namespace nofma { + +using fputil::DoubleDouble; + +LIBC_INLINE constexpr int FAST_PASS_EXPONENT = 23; + +// Digits of 2^(16*i) / pi, generated by Sollya with: +// For [2..62]: +// > for i from 3 to 63 do { +// pi_inv = 2^(16*(i - 3)) / pi; +// pn = nearestint(pi_inv); +// pi_frac = pi_inv - pn; +// a = round(pi_frac, 51, RN); +// b = round(pi_frac - a, 51, RN); +// c = round(pi_frac - a - b, D, RN); +// d = round(pi_frac - a - b - c, D, RN); +// print("{", 2^7 * a, ",", 2^7 * b, ",", 2^7 * c, ",", 2^7 * d, "},"); +// }; +// For [0..1]: +// The leading bit of 2^(16*(i - 3)) / pi is very small, so we add 0.25 so that +// the conditions for the algorithms are still satisfied, and one of those +// conditions guarantees that ulp(0.25 * x_reduced) >= 2, and will safely be +// discarded. +// for i from 0 to 2 do { +// pi_frac = 0.25 + 2^(16*(i - 3)) / pi; +// a = round(pi_frac, 51, RN); +// b = round(pi_frac - a, 51, RN); +// c = round(pi_frac - a - b, D, RN); +// d = round(pi_frac - a - b - c, D, RN); +// print("{", 2^7 * a, ",", 2^7 * b, ",", 2^7 * c, ",", 2^7 * d, "},"); +// }; +// For The fast pass using double-double, we only need 3 parts (a, b, c), but +// for the accurate pass using Float128, instead of using another table of +// Float128s, we simply add the fourth path (a, b, c, d), which simplify the +// implementation a bit and saving some memory. +LIBC_INLINE constexpr double ONE_TWENTY_EIGHT_OVER_PI[64][4] = { + {0x1.0000000000014p5, 0x1.7cc1b727220a8p-49, 0x1.4fe13abe8fa9ap-101, + 0x1.bb81b6c52b328p-155}, + {0x1.0000000145f3p5, 0x1.b727220a94fep-49, 0x1.3abe8fa9a6eep-101, + 0x1.b6c52b3278872p-155}, + {0x1.000145f306dc8p5, 0x1.c882a53f84ebp-47, -0x1.70565911f924fp-101, + 0x1.2b3278872084p-155}, + {0x1.45f306dc9c884p5, -0x1.5ac07b1505c14p-47, -0x1.96447e493ad4dp-99, + 0x1.3c439041fe516p-154}, + {-0x1.f246c6efab58p4, -0x1.ec5417056591p-49, -0x1.f924eb53361dep-101, + -0x1.bef806ba71508p-156}, + {0x1.391054a7f09d4p4, 0x1.f47d4d377036cp-48, 0x1.8a5664f10e41p-100, + 0x1.fe5163abdebbcp-154}, + {0x1.529fc2757d1f4p2, 0x1.34ddc0db62958p-50, 0x1.93c439041fe51p-102, + 0x1.8eaf7aef1586ep-156}, + {-0x1.ec5417056591p-1, -0x1.f924eb53361ep-53, 0x1.c820ff28b1d5fp-105, + -0x1.443a9e48db91cp-162}, + {-0x1.505c1596447e4p5, -0x1.275a99b0ef1cp-48, 0x1.07f9458eaf7afp-100, + -0x1.d4f246dc8e2dfp-157}, + {-0x1.596447e493ad4p1, -0x1.9b0ef1bef806cp-52, 0x1.63abdebbc561bp-106, + 0x1.c91b8e909374cp-160}, + {0x1.bb81b6c52b328p5, -0x1.de37df00d74e4p-49, 0x1.5ef5de2b0db92p-101, + 0x1.b8e909374b802p-156}, + {0x1.b6c52b3278874p5, -0x1.f7c035d38a844p-47, 0x1.778ac36e48dc7p-99, + 0x1.2126e97003249p-153}, + {0x1.2b3278872084p5, -0x1.ae9c5421443a8p-50, -0x1.e48db91c5bdb2p-102, + -0x1.68ffcdb688afbp-157}, + {-0x1.8778df7c035d4p5, 0x1.d5ef5de2b0db8p-49, 0x1.2371d2126e97p-101, + 0x1.924bba8274648p-160}, + {-0x1.bef806ba71508p4, -0x1.443a9e48db91cp-50, -0x1.6f6c8b47fe6dbp-104, + -0x1.115f62e6de302p-158}, + {-0x1.ae9c5421443a8p-2, -0x1.e48db91c5bdb4p-54, 0x1.d2e006492eea1p-106, + -0x1.8b9b78c078854p-160}, + {-0x1.38a84288753c8p5, -0x1.1b7238b7b645cp-47, 0x1.c00c925dd413ap-99, + 0x1.921cfe1deb1cbp-154}, + {-0x1.0a21d4f246dc8p3, -0x1.c5bdb22d1ff9cp-50, 0x1.25dd413a3243ap-103, + -0x1.e214e34ed658cp-162}, + {-0x1.d4f246dc8e2ep3, 0x1.26e9700324978p-49, -0x1.5f62e6de301e2p-102, + -0x1.4e34ed658c117p-158}, + {-0x1.236e4716f6c8cp4, 0x1.700324977505p-49, -0x1.736f180f10a72p-101, + 0x1.62534e7dd1047p-155}, + {0x1.b8e909374b8p4, 0x1.924bba8274648p-48, 0x1.cfe1deb1cb12ap-102, + -0x1.63045df7282b4p-156}, + {0x1.09374b801924cp4, -0x1.15f62e6de302p-50, 0x1.deb1cb129a73fp-102, + -0x1.77dca0ad144bbp-158}, + {-0x1.68ffcdb688afcp3, 0x1.d1921cfe1debp-50, 0x1.cb129a73ee882p-102, + 0x1.afa975da24275p-157}, + {0x1.924bba8274648p0, 0x1.cfe1deb1cb128p-54, 0x1.a73ee88235f53p-106, + -0x1.44bb7b16638fep-162}, + {-0x1.a22bec5cdbc6p5, -0x1.e214e34ed658cp-50, -0x1.177dca0ad144cp-106, + 0x1.213a671c09ad1p-160}, + {0x1.3a32439fc3bd8p1, -0x1.c69dacb1822fp-51, 0x1.1afa975da2427p-105, + 0x1.338e04d68befdp-159}, + {-0x1.b78c0788538d4p4, 0x1.29a73ee88236p-50, -0x1.5a28976f62cc7p-103, + -0x1.fb29741037d8dp-159}, + {0x1.fc3bd63962534p5, 0x1.cfba208d7d4bcp-48, -0x1.12edec598e3f6p-100, + -0x1.4ba081bec66e3p-154}, + {-0x1.4e34ed658c118p2, 0x1.046bea5d7689p-51, 0x1.3a671c09ad17ep-104, + -0x1.bec66e29c67cbp-162}, + {0x1.62534e7dd1048p5, -0x1.415a28976f62cp-47, -0x1.8e3f652e8207p-100, + 0x1.3991d63983534p-154}, + {-0x1.63045df7282b4p4, -0x1.44bb7b16638fcp-50, -0x1.94ba081bec66ep-102, + -0x1.4e33e566305b2p-157}, + {0x1.d1046bea5d768p5, 0x1.213a671c09adp-48, 0x1.7df904e64758ep-100, + 0x1.835339f49c846p-154}, + {0x1.afa975da24274p3, 0x1.9c7026b45f7e4p-50, 0x1.3991d63983534p-106, + -0x1.82d8dee81d108p-160}, + {-0x1.a28976f62cc7p5, -0x1.fb29741037d8cp-47, -0x1.b8a719f2b3183p-100, + 0x1.3908bf177bf25p-155}, + {-0x1.76f62cc71fb28p5, -0x1.741037d8cdc54p-47, 0x1.cc1a99cfa4e42p-101, + 0x1.7e2ef7e4a0ec8p-156}, + {0x1.d338e04d68bfp5, -0x1.bec66e29c67ccp-50, 0x1.339f49c845f8cp-102, + -0x1.081b5f13801dap-156}, + {0x1.c09ad17df905p4, -0x1.9b8a719f2b318p-48, -0x1.6c6f740e8840ep-103, + 0x1.41d8ffc4bffefp-157}, + {0x1.68befc827323cp5, -0x1.38cf9598c16c8p-47, 0x1.08bf177bf2507p-99, + 0x1.8ffc4bffef02dp-153}, + {-0x1.037d8cdc538dp5, 0x1.a99cfa4e422fcp-49, 0x1.77bf250763ff1p-103, + 0x1.7ffde05980fefp-158}, + {-0x1.8cdc538cf9598p5, -0x1.82d8dee81d108p-48, -0x1.b5f13801da001p-104, + 0x1.e05980fef2f12p-158}, + {-0x1.4e33e566305bp3, -0x1.bdd03a21036cp-49, 0x1.d8ffc4bffef03p-101, + -0x1.9fc04343b9d29p-156}, + {-0x1.f2b3182d8dee8p4, -0x1.d1081b5f138p-52, -0x1.da00087e99fcp-104, + -0x1.0d0ee74a5f593p-158}, + {-0x1.8c16c6f740e88p5, -0x1.036be27003b4p-49, -0x1.0fd33f8086877p-109, + -0x1.d297d64b824b2p-164}, + {0x1.3908bf177bf24p5, 0x1.0763ff12fffbcp-47, 0x1.6603fbcbc462dp-104, + 0x1.a0a6d1f6d367fp-158}, + {0x1.7e2ef7e4a0ec8p4, -0x1.da00087e99fcp-56, -0x1.0d0ee74a5f593p-110, + 0x1.f6d367ecf27cbp-166}, + {-0x1.081b5f13801dcp4, 0x1.fff7816603fbcp-48, 0x1.788c5ad05369p-101, + -0x1.25930261b069fp-155}, + {-0x1.af89c00ed0004p5, -0x1.fa67f010d0ee8p-50, 0x1.6b414da3eda6dp-103, + -0x1.30d834f648b0cp-162}, + {-0x1.c00ed00043f4cp5, -0x1.fc04343b9d298p-48, 0x1.4da3eda6cfd9ep-103, + 0x1.3e584dba7a32p-157}, + {0x1.2fffbc0b301fcp5, 0x1.e5e2316b414dcp-47, -0x1.c125930261b07p-99, + 0x1.84dba7a31fb35p-153}, + {-0x1.0fd33f8086878p3, 0x1.8b5a0a6d1f6d4p-50, -0x1.30261b069ec91p-103, + -0x1.85ce04cb0d00bp-157}, + {-0x1.9fc04343b9d28p4, -0x1.7d64b824b2604p-48, -0x1.86c1a7b24585dp-101, + 0x1.fb34f2ff516bbp-157}, + {-0x1.0d0ee74a5f594p2, 0x1.1f6d367ecf27cp-50, 0x1.6136e9e8c7ecdp-103, + 0x1.e5fea2d7527bbp-158}, + {-0x1.dce94beb25c14p5, 0x1.a6cfd9e4f9614p-47, -0x1.22c2e70265868p-100, + -0x1.5d28ad8453814p-158}, + {-0x1.4beb25c12593p5, -0x1.30d834f648b0cp-50, 0x1.8fd9a797fa8b6p-104, + -0x1.5b08a7028341dp-159}, + {0x1.b47db4d9fb3c8p4, 0x1.f2c26dd3d18fcp-48, 0x1.9a797fa8b5d4ap-100, + -0x1.14e050683a131p-156}, + {-0x1.25930261b06ap5, 0x1.36e9e8c7ecd3cp-47, 0x1.7fa8b5d49eeb2p-100, + -0x1.41a0e84c2f8c6p-158}, + {0x1.fb3c9f2c26dd4p4, -0x1.738132c3402bcp-51, 0x1.aea4f758fd7ccp-103, + -0x1.d0985f18c10ebp-159}, + {-0x1.b069ec9161738p5, -0x1.32c3402ba515cp-51, 0x1.eeb1faf97c5edp-104, + -0x1.7c63043ad6b69p-161}, + {-0x1.ec9161738132cp5, -0x1.a015d28ad8454p-50, 0x1.faf97c5ecf41dp-104, + -0x1.821d6b5b4565p-160}, + {-0x1.61738132c3404p5, 0x1.45aea4f758fd8p-47, -0x1.a0e84c2f8c608p-102, + -0x1.d6b5b45650128p-156}, + {0x1.fb34f2ff516bcp3, -0x1.6c229c0a0d074p-49, -0x1.30be31821d6b6p-104, + 0x1.2ea6bfb5fb12p-158}, + {0x1.3cbfd45aea4f8p5, -0x1.4e050683a130cp-48, 0x1.ce7de294a4baap-104, + -0x1.404a04ee072a3p-158}, + {-0x1.5d28ad8453814p2, -0x1.a0e84c2f8c608p-54, -0x1.d6b5b45650128p-108, + -0x1.3b81ca8bdea7fp-164}, + {-0x1.15b08a702834p5, -0x1.d0985f18c10ecp-47, 0x1.4a4ba9afed7ecp-100, + 0x1.1f8d5d0856033p-154}, +}; + +// Lookup table for sin(k * pi / 128) with k = 0, ..., 255. +// Table is generated with Sollya as follow: +// > display = hexadecimal; +// > for k from 0 to 255 do { +// a = round(sin(k * pi/128), 51, RN); +// b = round(sin(k * pi/128) - a, D, RN); +// print("{", b, ",", a, "},"); +// }; +LIBC_INLINE constexpr DoubleDouble SIN_K_PI_OVER_128[256] = { + {0, 0}, + {0x1.f938a73db97fbp-58, 0x1.92155f7a3667cp-6}, + {-0x1.912bd0d569a9p-61, 0x1.91f65f10dd814p-5}, + {0x1.ccbeeeae8129ap-56, 0x1.2d52092ce19f4p-4}, + {-0x1.e2718d26ed688p-60, 0x1.917a6bc29b42cp-4}, + {-0x1.cbb1f71aca352p-56, 0x1.f564e56a9731p-4}, + {-0x1.dd9ffeaecbdc4p-55, 0x1.2c8106e8e613cp-3}, + {-0x1.ab3802218894fp-55, 0x1.5e214448b3fc8p-3}, + {-0x1.49b466e7fe36p-55, 0x1.8f8b83c69a60cp-3}, + {-0x1.035e2873ca432p-55, 0x1.c0b826a7e4f64p-3}, + {-0x1.50b7bbc4768b1p-55, 0x1.f19f97b215f1cp-3}, + {-0x1.3ed9efaa42ab3p-55, 0x1.111d262b1f678p-2}, + {0x1.a8b5c974ee7b5p-54, 0x1.294062ed59f04p-2}, + {0x1.4325f12be8946p-54, 0x1.4135c941766p-2}, + {0x1.fc2047e54e614p-55, 0x1.58f9a75ab1fdcp-2}, + {-0x1.512c678219317p-54, 0x1.7088530fa45ap-2}, + {-0x1.2e59dba7ab4c2p-54, 0x1.87de2a6aea964p-2}, + {-0x1.d24afdade848bp-54, 0x1.9ef7943a8ed8cp-2}, + {0x1.5b362cb974183p-57, 0x1.b5d1009e15ccp-2}, + {-0x1.e97af1a63c807p-54, 0x1.cc66e9931c46p-2}, + {-0x1.c3e4edc5872f8p-55, 0x1.e2b5d3806f63cp-2}, + {0x1.fb44f80f92225p-54, 0x1.f8ba4dbf89ab8p-2}, + {0x1.9697faf2e2fe5p-53, 0x1.073879922ffecp-1}, + {-0x1.7bc8eda6af93cp-53, 0x1.11eb3541b4b24p-1}, + {0x1.b25dd267f66p-55, 0x1.1c73b39ae68c8p-1}, + {-0x1.5769d0fbcddc3p-53, 0x1.26d054cdd12ep-1}, + {0x1.c20673b2116b2p-54, 0x1.30ff7fce17034p-1}, + {0x1.3c7c4bc72a92cp-53, 0x1.3affa292050b8p-1}, + {-0x1.e7f895d302395p-53, 0x1.44cf325091dd8p-1}, + {0x1.13c293edceb32p-53, 0x1.4e6cabbe3e5e8p-1}, + {-0x1.75720992bfbb2p-55, 0x1.57d69348cecap-1}, + {-0x1.24a366a5fe547p-53, 0x1.610b7551d2cep-1}, + {0x1.21165f626cdd5p-54, 0x1.6a09e667f3bccp-1}, + {-0x1.bcac43c389ba9p-53, 0x1.72d0837efff98p-1}, + {-0x1.21ea6f59be15bp-53, 0x1.7b5df226aafbp-1}, + {0x1.d217be0e2b971p-53, 0x1.83b0e0bff976cp-1}, + {0x1.69d0f6897664ap-54, 0x1.8bc806b15174p-1}, + {-0x1.615f32b6f907ap-54, 0x1.93a22499263fcp-1}, + {0x1.6788ebcc76dc6p-54, 0x1.9b3e047f3874p-1}, + {0x1.ddae89fd441d1p-53, 0x1.a29a7a046278p-1}, + {-0x1.f98273c5d2495p-54, 0x1.a9b66290ea1a4p-1}, + {-0x1.926da300ffccep-55, 0x1.b090a581502p-1}, + {0x1.90e58336c64a8p-53, 0x1.b728345196e3cp-1}, + {0x1.9f6963354e3fep-53, 0x1.bd7c0ac6f9528p-1}, + {0x1.a47d3a2a0dcbep-54, 0x1.c38b2f180bdbp-1}, + {0x1.ed0489e16b9ap-54, 0x1.c954b213411f4p-1}, + {-0x1.0f3db5dad5ac5p-53, 0x1.ced7af43cc774p-1}, + {0x1.ac42b5a8b6943p-53, 0x1.d4134d14dc938p-1}, + {-0x1.d75033dfb9ca8p-53, 0x1.d906bcf328d48p-1}, + {0x1.83c37c6107db3p-55, 0x1.ddb13b6ccc23cp-1}, + {0x1.7f59c49f6cd6dp-54, 0x1.e212104f686e4p-1}, + {0x1.ee94a90d7b88bp-53, 0x1.e6288ec48e11p-1}, + {-0x1.a27d3874701f9p-53, 0x1.e9f4156c62ddcp-1}, + {-0x1.85f4e1b8298dp-54, 0x1.ed740e7684964p-1}, + {-0x1.ab4e148e52d9ep-54, 0x1.f0a7efb9230d8p-1}, + {0x1.8a11412b82346p-54, 0x1.f38f3ac64e588p-1}, + {0x1.562172a361fd3p-56, 0x1.f6297cff75cbp-1}, + {0x1.3564acef1ff97p-53, 0x1.f8764fa714ba8p-1}, + {-0x1.5e82a3284d5c8p-53, 0x1.fa7557f08a518p-1}, + {-0x1.709bccb89a989p-54, 0x1.fc26470e19fd4p-1}, + {0x1.9e082721dfb8ep-53, 0x1.fd88da3d12524p-1}, + {-0x1.eade132f3981dp-53, 0x1.fe9cdad01883cp-1}, + {0x1.e3a843d1db55fp-53, 0x1.ff621e3796d7cp-1}, + {0x1.765595d548d9ap-54, 0x1.ffd886084cd0cp-1}, + {0, 1}, + {0x1.765595d548d9ap-54, 0x1.ffd886084cd0cp-1}, + {0x1.e3a843d1db55fp-53, 0x1.ff621e3796d7cp-1}, + {-0x1.eade132f3981dp-53, 0x1.fe9cdad01883cp-1}, + {0x1.9e082721dfb8ep-53, 0x1.fd88da3d12524p-1}, + {-0x1.709bccb89a989p-54, 0x1.fc26470e19fd4p-1}, + {-0x1.5e82a3284d5c8p-53, 0x1.fa7557f08a518p-1}, + {0x1.3564acef1ff97p-53, 0x1.f8764fa714ba8p-1}, + {0x1.562172a361fd3p-56, 0x1.f6297cff75cbp-1}, + {0x1.8a11412b82346p-54, 0x1.f38f3ac64e588p-1}, + {-0x1.ab4e148e52d9ep-54, 0x1.f0a7efb9230d8p-1}, + {-0x1.85f4e1b8298dp-54, 0x1.ed740e7684964p-1}, + {-0x1.a27d3874701f9p-53, 0x1.e9f4156c62ddcp-1}, + {0x1.ee94a90d7b88bp-53, 0x1.e6288ec48e11p-1}, + {0x1.7f59c49f6cd6dp-54, 0x1.e212104f686e4p-1}, + {0x1.83c37c6107db3p-55, 0x1.ddb13b6ccc23cp-1}, + {-0x1.d75033dfb9ca8p-53, 0x1.d906bcf328d48p-1}, + {0x1.ac42b5a8b6943p-53, 0x1.d4134d14dc938p-1}, + {-0x1.0f3db5dad5ac5p-53, 0x1.ced7af43cc774p-1}, + {0x1.ed0489e16b9ap-54, 0x1.c954b213411f4p-1}, + {0x1.a47d3a2a0dcbep-54, 0x1.c38b2f180bdbp-1}, + {0x1.9f6963354e3fep-53, 0x1.bd7c0ac6f9528p-1}, + {0x1.90e58336c64a8p-53, 0x1.b728345196e3cp-1}, + {-0x1.926da300ffccep-55, 0x1.b090a581502p-1}, + {-0x1.f98273c5d2495p-54, 0x1.a9b66290ea1a4p-1}, + {0x1.ddae89fd441d1p-53, 0x1.a29a7a046278p-1}, + {0x1.6788ebcc76dc6p-54, 0x1.9b3e047f3874p-1}, + {-0x1.615f32b6f907ap-54, 0x1.93a22499263fcp-1}, + {0x1.69d0f6897664ap-54, 0x1.8bc806b15174p-1}, + {0x1.d217be0e2b971p-53, 0x1.83b0e0bff976cp-1}, + {-0x1.21ea6f59be15bp-53, 0x1.7b5df226aafbp-1}, + {-0x1.bcac43c389ba9p-53, 0x1.72d0837efff98p-1}, + {0x1.21165f626cdd5p-54, 0x1.6a09e667f3bccp-1}, + {-0x1.24a366a5fe547p-53, 0x1.610b7551d2cep-1}, + {-0x1.75720992bfbb2p-55, 0x1.57d69348cecap-1}, + {0x1.13c293edceb32p-53, 0x1.4e6cabbe3e5e8p-1}, + {-0x1.e7f895d302395p-53, 0x1.44cf325091dd8p-1}, + {0x1.3c7c4bc72a92cp-53, 0x1.3affa292050b8p-1}, + {0x1.c20673b2116b2p-54, 0x1.30ff7fce17034p-1}, + {-0x1.5769d0fbcddc3p-53, 0x1.26d054cdd12ep-1}, + {0x1.b25dd267f66p-55, 0x1.1c73b39ae68c8p-1}, + {-0x1.7bc8eda6af93cp-53, 0x1.11eb3541b4b24p-1}, + {0x1.9697faf2e2fe5p-53, 0x1.073879922ffecp-1}, + {0x1.fb44f80f92225p-54, 0x1.f8ba4dbf89ab8p-2}, + {-0x1.c3e4edc5872f8p-55, 0x1.e2b5d3806f63cp-2}, + {-0x1.e97af1a63c807p-54, 0x1.cc66e9931c46p-2}, + {0x1.5b362cb974183p-57, 0x1.b5d1009e15ccp-2}, + {-0x1.d24afdade848bp-54, 0x1.9ef7943a8ed8cp-2}, + {-0x1.2e59dba7ab4c2p-54, 0x1.87de2a6aea964p-2}, + {-0x1.512c678219317p-54, 0x1.7088530fa45ap-2}, + {0x1.fc2047e54e614p-55, 0x1.58f9a75ab1fdcp-2}, + {0x1.4325f12be8946p-54, 0x1.4135c941766p-2}, + {0x1.a8b5c974ee7b5p-54, 0x1.294062ed59f04p-2}, + {-0x1.3ed9efaa42ab3p-55, 0x1.111d262b1f678p-2}, + {-0x1.50b7bbc4768b1p-55, 0x1.f19f97b215f1cp-3}, + {-0x1.035e2873ca432p-55, 0x1.c0b826a7e4f64p-3}, + {-0x1.49b466e7fe36p-55, 0x1.8f8b83c69a60cp-3}, + {-0x1.ab3802218894fp-55, 0x1.5e214448b3fc8p-3}, + {-0x1.dd9ffeaecbdc4p-55, 0x1.2c8106e8e613cp-3}, + {-0x1.cbb1f71aca352p-56, 0x1.f564e56a9731p-4}, + {-0x1.e2718d26ed688p-60, 0x1.917a6bc29b42cp-4}, + {0x1.ccbeeeae8129ap-56, 0x1.2d52092ce19f4p-4}, + {-0x1.912bd0d569a9p-61, 0x1.91f65f10dd814p-5}, + {0x1.f938a73db97fbp-58, 0x1.92155f7a3667cp-6}, + {0, 0}, + {-0x1.f938a73db97fbp-58, -0x1.92155f7a3667cp-6}, + {0x1.912bd0d569a9p-61, -0x1.91f65f10dd814p-5}, + {-0x1.ccbeeeae8129ap-56, -0x1.2d52092ce19f4p-4}, + {0x1.e2718d26ed688p-60, -0x1.917a6bc29b42cp-4}, + {0x1.cbb1f71aca352p-56, -0x1.f564e56a9731p-4}, + {0x1.dd9ffeaecbdc4p-55, -0x1.2c8106e8e613cp-3}, + {0x1.ab3802218894fp-55, -0x1.5e214448b3fc8p-3}, + {0x1.49b466e7fe36p-55, -0x1.8f8b83c69a60cp-3}, + {0x1.035e2873ca432p-55, -0x1.c0b826a7e4f64p-3}, + {0x1.50b7bbc4768b1p-55, -0x1.f19f97b215f1cp-3}, + {0x1.3ed9efaa42ab3p-55, -0x1.111d262b1f678p-2}, + {-0x1.a8b5c974ee7b5p-54, -0x1.294062ed59f04p-2}, + {-0x1.4325f12be8946p-54, -0x1.4135c941766p-2}, + {-0x1.fc2047e54e614p-55, -0x1.58f9a75ab1fdcp-2}, + {0x1.512c678219317p-54, -0x1.7088530fa45ap-2}, + {0x1.2e59dba7ab4c2p-54, -0x1.87de2a6aea964p-2}, + {0x1.d24afdade848bp-54, -0x1.9ef7943a8ed8cp-2}, + {-0x1.5b362cb974183p-57, -0x1.b5d1009e15ccp-2}, + {0x1.e97af1a63c807p-54, -0x1.cc66e9931c46p-2}, + {0x1.c3e4edc5872f8p-55, -0x1.e2b5d3806f63cp-2}, + {-0x1.fb44f80f92225p-54, -0x1.f8ba4dbf89ab8p-2}, + {-0x1.9697faf2e2fe5p-53, -0x1.073879922ffecp-1}, + {0x1.7bc8eda6af93cp-53, -0x1.11eb3541b4b24p-1}, + {-0x1.b25dd267f66p-55, -0x1.1c73b39ae68c8p-1}, + {0x1.5769d0fbcddc3p-53, -0x1.26d054cdd12ep-1}, + {-0x1.c20673b2116b2p-54, -0x1.30ff7fce17034p-1}, + {-0x1.3c7c4bc72a92cp-53, -0x1.3affa292050b8p-1}, + {0x1.e7f895d302395p-53, -0x1.44cf325091dd8p-1}, + {-0x1.13c293edceb32p-53, -0x1.4e6cabbe3e5e8p-1}, + {0x1.75720992bfbb2p-55, -0x1.57d69348cecap-1}, + {0x1.24a366a5fe547p-53, -0x1.610b7551d2cep-1}, + {-0x1.21165f626cdd5p-54, -0x1.6a09e667f3bccp-1}, + {0x1.bcac43c389ba9p-53, -0x1.72d0837efff98p-1}, + {0x1.21ea6f59be15bp-53, -0x1.7b5df226aafbp-1}, + {-0x1.d217be0e2b971p-53, -0x1.83b0e0bff976cp-1}, + {-0x1.69d0f6897664ap-54, -0x1.8bc806b15174p-1}, + {0x1.615f32b6f907ap-54, -0x1.93a22499263fcp-1}, + {-0x1.6788ebcc76dc6p-54, -0x1.9b3e047f3874p-1}, + {-0x1.ddae89fd441d1p-53, -0x1.a29a7a046278p-1}, + {0x1.f98273c5d2495p-54, -0x1.a9b66290ea1a4p-1}, + {0x1.926da300ffccep-55, -0x1.b090a581502p-1}, + {-0x1.90e58336c64a8p-53, -0x1.b728345196e3cp-1}, + {-0x1.9f6963354e3fep-53, -0x1.bd7c0ac6f9528p-1}, + {-0x1.a47d3a2a0dcbep-54, -0x1.c38b2f180bdbp-1}, + {-0x1.ed0489e16b9ap-54, -0x1.c954b213411f4p-1}, + {0x1.0f3db5dad5ac5p-53, -0x1.ced7af43cc774p-1}, + {-0x1.ac42b5a8b6943p-53, -0x1.d4134d14dc938p-1}, + {0x1.d75033dfb9ca8p-53, -0x1.d906bcf328d48p-1}, + {-0x1.83c37c6107db3p-55, -0x1.ddb13b6ccc23cp-1}, + {-0x1.7f59c49f6cd6dp-54, -0x1.e212104f686e4p-1}, + {-0x1.ee94a90d7b88bp-53, -0x1.e6288ec48e11p-1}, + {0x1.a27d3874701f9p-53, -0x1.e9f4156c62ddcp-1}, + {0x1.85f4e1b8298dp-54, -0x1.ed740e7684964p-1}, + {0x1.ab4e148e52d9ep-54, -0x1.f0a7efb9230d8p-1}, + {-0x1.8a11412b82346p-54, -0x1.f38f3ac64e588p-1}, + {-0x1.562172a361fd3p-56, -0x1.f6297cff75cbp-1}, + {-0x1.3564acef1ff97p-53, -0x1.f8764fa714ba8p-1}, + {0x1.5e82a3284d5c8p-53, -0x1.fa7557f08a518p-1}, + {0x1.709bccb89a989p-54, -0x1.fc26470e19fd4p-1}, + {-0x1.9e082721dfb8ep-53, -0x1.fd88da3d12524p-1}, + {0x1.eade132f3981dp-53, -0x1.fe9cdad01883cp-1}, + {-0x1.e3a843d1db55fp-53, -0x1.ff621e3796d7cp-1}, + {-0x1.765595d548d9ap-54, -0x1.ffd886084cd0cp-1}, + {0, -1}, + {-0x1.765595d548d9ap-54, -0x1.ffd886084cd0cp-1}, + {-0x1.e3a843d1db55fp-53, -0x1.ff621e3796d7cp-1}, + {0x1.eade132f3981dp-53, -0x1.fe9cdad01883cp-1}, + {-0x1.9e082721dfb8ep-53, -0x1.fd88da3d12524p-1}, + {0x1.709bccb89a989p-54, -0x1.fc26470e19fd4p-1}, + {0x1.5e82a3284d5c8p-53, -0x1.fa7557f08a518p-1}, + {-0x1.3564acef1ff97p-53, -0x1.f8764fa714ba8p-1}, + {-0x1.562172a361fd3p-56, -0x1.f6297cff75cbp-1}, + {-0x1.8a11412b82346p-54, -0x1.f38f3ac64e588p-1}, + {0x1.ab4e148e52d9ep-54, -0x1.f0a7efb9230d8p-1}, + {0x1.85f4e1b8298dp-54, -0x1.ed740e7684964p-1}, + {0x1.a27d3874701f9p-53, -0x1.e9f4156c62ddcp-1}, + {-0x1.ee94a90d7b88bp-53, -0x1.e6288ec48e11p-1}, + {-0x1.7f59c49f6cd6dp-54, -0x1.e212104f686e4p-1}, + {-0x1.83c37c6107db3p-55, -0x1.ddb13b6ccc23cp-1}, + {0x1.d75033dfb9ca8p-53, -0x1.d906bcf328d48p-1}, + {-0x1.ac42b5a8b6943p-53, -0x1.d4134d14dc938p-1}, + {0x1.0f3db5dad5ac5p-53, -0x1.ced7af43cc774p-1}, + {-0x1.ed0489e16b9ap-54, -0x1.c954b213411f4p-1}, + {-0x1.a47d3a2a0dcbep-54, -0x1.c38b2f180bdbp-1}, + {-0x1.9f6963354e3fep-53, -0x1.bd7c0ac6f9528p-1}, + {-0x1.90e58336c64a8p-53, -0x1.b728345196e3cp-1}, + {0x1.926da300ffccep-55, -0x1.b090a581502p-1}, + {0x1.f98273c5d2495p-54, -0x1.a9b66290ea1a4p-1}, + {-0x1.ddae89fd441d1p-53, -0x1.a29a7a046278p-1}, + {-0x1.6788ebcc76dc6p-54, -0x1.9b3e047f3874p-1}, + {0x1.615f32b6f907ap-54, -0x1.93a22499263fcp-1}, + {-0x1.69d0f6897664ap-54, -0x1.8bc806b15174p-1}, + {-0x1.d217be0e2b971p-53, -0x1.83b0e0bff976cp-1}, + {0x1.21ea6f59be15bp-53, -0x1.7b5df226aafbp-1}, + {0x1.bcac43c389ba9p-53, -0x1.72d0837efff98p-1}, + {-0x1.21165f626cdd5p-54, -0x1.6a09e667f3bccp-1}, + {0x1.24a366a5fe547p-53, -0x1.610b7551d2cep-1}, + {0x1.75720992bfbb2p-55, -0x1.57d69348cecap-1}, + {-0x1.13c293edceb32p-53, -0x1.4e6cabbe3e5e8p-1}, + {0x1.e7f895d302395p-53, -0x1.44cf325091dd8p-1}, + {-0x1.3c7c4bc72a92cp-53, -0x1.3affa292050b8p-1}, + {-0x1.c20673b2116b2p-54, -0x1.30ff7fce17034p-1}, + {0x1.5769d0fbcddc3p-53, -0x1.26d054cdd12ep-1}, + {-0x1.b25dd267f66p-55, -0x1.1c73b39ae68c8p-1}, + {0x1.7bc8eda6af93cp-53, -0x1.11eb3541b4b24p-1}, + {-0x1.9697faf2e2fe5p-53, -0x1.073879922ffecp-1}, + {-0x1.fb44f80f92225p-54, -0x1.f8ba4dbf89ab8p-2}, + {0x1.c3e4edc5872f8p-55, -0x1.e2b5d3806f63cp-2}, + {0x1.e97af1a63c807p-54, -0x1.cc66e9931c46p-2}, + {-0x1.5b362cb974183p-57, -0x1.b5d1009e15ccp-2}, + {0x1.d24afdade848bp-54, -0x1.9ef7943a8ed8cp-2}, + {0x1.2e59dba7ab4c2p-54, -0x1.87de2a6aea964p-2}, + {0x1.512c678219317p-54, -0x1.7088530fa45ap-2}, + {-0x1.fc2047e54e614p-55, -0x1.58f9a75ab1fdcp-2}, + {-0x1.4325f12be8946p-54, -0x1.4135c941766p-2}, + {-0x1.a8b5c974ee7b5p-54, -0x1.294062ed59f04p-2}, + {0x1.3ed9efaa42ab3p-55, -0x1.111d262b1f678p-2}, + {0x1.50b7bbc4768b1p-55, -0x1.f19f97b215f1cp-3}, + {0x1.035e2873ca432p-55, -0x1.c0b826a7e4f64p-3}, + {0x1.49b466e7fe36p-55, -0x1.8f8b83c69a60cp-3}, + {0x1.ab3802218894fp-55, -0x1.5e214448b3fc8p-3}, + {0x1.dd9ffeaecbdc4p-55, -0x1.2c8106e8e613cp-3}, + {0x1.cbb1f71aca352p-56, -0x1.f564e56a9731p-4}, + {0x1.e2718d26ed688p-60, -0x1.917a6bc29b42cp-4}, + {-0x1.ccbeeeae8129ap-56, -0x1.2d52092ce19f4p-4}, + {0x1.912bd0d569a9p-61, -0x1.91f65f10dd814p-5}, + {-0x1.f938a73db97fbp-58, -0x1.92155f7a3667cp-6}, +}; + +LIBC_INLINE unsigned range_reduction_small(double x, DoubleDouble &u) { + constexpr double ONE_TWENTY_EIGHT_OVER_PI = 0x1.45f306dc9c883p5; + + // Digits of -pi/128, generated by Sollya with: + // > a = round(-pi/128, 25, RN); + // > b = round(-pi/128 - a, 23, RN); + // > c = round(-pi/128 - a - b, 25, RN); + // > d = round(-pi/128 - a - b - c, D, RN); + // -pi/128 ~ a + b + c + d + // The precisions of the parts are chosen so that: + // 1) k * a, k * b, k * c are exact in double precision + // 2) k * b + (x - (k * a)) is exact in double precsion + constexpr double MPI_OVER_128[4] = {-0x1.921fb5p-6, -0x1.110b48p-32, + +0x1.ee59dap-56, -0x1.98a2e03707345p-83}; + + double prod_hi = x * ONE_TWENTY_EIGHT_OVER_PI; + double kd = fputil::nearest_integer(prod_hi); + + // With -pi/128 ~ a + b + c + d as in MPI_OVER_128 description: + // t = x + k * a + double t = fputil::multiply_add(kd, MPI_OVER_128[0], x); // Exact + // y_hi = t + k * b = (x + k * a) + k * b + double y_hi = fputil::multiply_add(kd, MPI_OVER_128[1], t); // Exact + // y_lo ~ k * c + k * d + double y_lo = fputil::multiply_add(kd, MPI_OVER_128[2], kd * MPI_OVER_128[3]); + // u.hi + u.lo ~ x + k * (a + b + c + d) + u = fputil::exact_add(y_hi, y_lo); + // Error bound: For |x| < 2^-23, + // |(x mod pi/128) - (u_hi + u_lo)| < ulp(y_lo) + // <= ulp(2 * x * c) + // <= ulp(2^24 * 2^-56) + // = 2^(24 - 56 - 52) + // = 2^-84 + return static_cast(static_cast(kd)); +} + +} // namespace nofma + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_GENERIC_RANGE_REDUCTION_DOUBLE_NOFMA_H diff --git a/libc/src/math/generic/sin.cpp b/libc/src/math/generic/sin.cpp new file mode 100644 index 00000000000000..207435d4385ae1 --- /dev/null +++ b/libc/src/math/generic/sin.cpp @@ -0,0 +1,207 @@ +//===-- Double-precision sin function -------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/math/sin.h" +#include "hdr/errno_macros.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/double_double.h" +#include "src/__support/FPUtil/dyadic_float.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/rounding_mode.h" +#include "src/__support/common.h" +#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY +#include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA +#include "src/math/generic/sincos_eval.h" + +#ifdef LIBC_TARGET_CPU_HAS_FMA +#include "range_reduction_double_fma.h" + +using LIBC_NAMESPACE::fma::FAST_PASS_EXPONENT; +using LIBC_NAMESPACE::fma::ONE_TWENTY_EIGHT_OVER_PI; +using LIBC_NAMESPACE::fma::range_reduction_small; +using LIBC_NAMESPACE::fma::SIN_K_PI_OVER_128; + +LIBC_INLINE constexpr bool NO_FMA = false; +#else +#include "range_reduction_double_nofma.h" + +using LIBC_NAMESPACE::nofma::FAST_PASS_EXPONENT; +using LIBC_NAMESPACE::nofma::ONE_TWENTY_EIGHT_OVER_PI; +using LIBC_NAMESPACE::nofma::range_reduction_small; +using LIBC_NAMESPACE::nofma::SIN_K_PI_OVER_128; + +LIBC_INLINE constexpr bool NO_FMA = true; +#endif // LIBC_TARGET_CPU_HAS_FMA + +// TODO: We might be able to improve the performance of large range reduction of +// non-FMA targets further by operating directly on 25-bit chunks of 128/pi and +// pre-split SIN_K_PI_OVER_128, but that might double the memory footprint of +// those lookup table. +#include "range_reduction_double_common.h" + +#if ((LIBC_MATH & LIBC_MATH_SKIP_ACCURATE_PASS) != 0) +#define LIBC_MATH_SIN_SKIP_ACCURATE_PASS +#endif + +namespace LIBC_NAMESPACE { + +using DoubleDouble = fputil::DoubleDouble; +using Float128 = typename fputil::DyadicFloat<128>; + +LLVM_LIBC_FUNCTION(double, sin, (double x)) { + using FPBits = typename fputil::FPBits; + FPBits xbits(x); + + uint16_t x_e = xbits.get_biased_exponent(); + + DoubleDouble y; + unsigned k; + generic::LargeRangeReduction range_reduction_large; + + // |x| < 2^32 (with FMA) or |x| < 2^23 (w/o FMA) + if (LIBC_LIKELY(x_e < FPBits::EXP_BIAS + FAST_PASS_EXPONENT)) { + // |x| < 2^-26 + if (LIBC_UNLIKELY(x_e < FPBits::EXP_BIAS - 26)) { + // Signed zeros. + if (LIBC_UNLIKELY(x == 0.0)) + return x; + + // For |x| < 2^-26, |sin(x) - x| < ulp(x)/2. +#ifdef LIBC_TARGET_CPU_HAS_FMA + return fputil::multiply_add(x, -0x1.0p-54, x); +#else + if (LIBC_UNLIKELY(x_e < 4)) { + int rounding_mode = fputil::quick_get_round(); + if (rounding_mode == FE_TOWARDZERO || + (xbits.sign() == Sign::POS && rounding_mode == FE_DOWNWARD) || + (xbits.sign() == Sign::NEG && rounding_mode == FE_UPWARD)) + return FPBits(xbits.uintval() - 1).get_val(); + } + return fputil::multiply_add(x, -0x1.0p-54, x); +#endif // LIBC_TARGET_CPU_HAS_FMA + } + + // // Small range reduction. + k = range_reduction_small(x, y); + } else { + // Inf or NaN + if (LIBC_UNLIKELY(x_e > 2 * FPBits::EXP_BIAS)) { + // sin(+-Inf) = NaN + if (xbits.get_mantissa() == 0) { + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_INVALID); + } + return x + FPBits::quiet_nan().get_val(); + } + + // Large range reduction. + k = range_reduction_large.compute_high_part(x); + y = range_reduction_large.fast(); + } + + DoubleDouble sin_y, cos_y; + + generic::sincos_eval(y, sin_y, cos_y); + + // Look up sin(k * pi/128) and cos(k * pi/128) + // Memory saving versions: + + // Use 128-entry table instead: + // DoubleDouble sin_k = SIN_K_PI_OVER_128[k & 127]; + // uint64_t sin_s = static_cast(k & 128) << (63 - 7); + // sin_k.hi = FPBits(FPBits(sin_k.hi).uintval() ^ sin_s).get_val(); + // sin_k.lo = FPBits(FPBits(sin_k.hi).uintval() ^ sin_s).get_val(); + // DoubleDouble cos_k = SIN_K_PI_OVER_128[(k + 64) & 127]; + // uint64_t cos_s = static_cast((k + 64) & 128) << (63 - 7); + // cos_k.hi = FPBits(FPBits(cos_k.hi).uintval() ^ cos_s).get_val(); + // cos_k.lo = FPBits(FPBits(cos_k.hi).uintval() ^ cos_s).get_val(); + + // Use 64-entry table instead: + // auto get_idx_dd = [](unsigned kk) -> DoubleDouble { + // unsigned idx = (kk & 64) ? 64 - (kk & 63) : (kk & 63); + // DoubleDouble ans = SIN_K_PI_OVER_128[idx]; + // if (kk & 128) { + // ans.hi = -ans.hi; + // ans.lo = -ans.lo; + // } + // return ans; + // }; + // DoubleDouble sin_k = get_idx_dd(k); + // DoubleDouble cos_k = get_idx_dd(k + 64); + + // Fast look up version, but needs 256-entry table. + // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). + DoubleDouble sin_k = SIN_K_PI_OVER_128[k & 255]; + DoubleDouble cos_k = SIN_K_PI_OVER_128[(k + 64) & 255]; + + // After range reduction, k = round(x * 128 / pi) and y = x - k * (pi / 128). + // So k is an integer and -pi / 256 <= y <= pi / 256. + // Then sin(x) = sin((k * pi/128 + y) + // = sin(y) * cos(k*pi/128) + cos(y) * sin(k*pi/128) + DoubleDouble sin_k_cos_y = fputil::quick_mult(cos_y, sin_k); + DoubleDouble cos_k_sin_y = fputil::quick_mult(sin_y, cos_k); + + DoubleDouble rr = fputil::exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); + rr.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; + +#ifdef LIBC_MATH_SIN_SKIP_ACCURATE_PASS + return rr.hi + rr.lo; +#else + // Accurate test and pass for correctly rounded implementation. + +#ifdef LIBC_TARGET_CPU_HAS_FMA + constexpr double ERR = 0x1.0p-70; +#else + // TODO: Improve non-FMA fast pass accuracy. + constexpr double ERR = 0x1.0p-66; +#endif // LIBC_TARGET_CPU_HAS_FMA + + double rlp = rr.lo + ERR; + double rlm = rr.lo - ERR; + + double r_upper = rr.hi + rlp; // (rr.lo + ERR); + double r_lower = rr.hi + rlm; // (rr.lo - ERR); + + // Ziv's rounding test. + if (LIBC_LIKELY(r_upper == r_lower)) + return r_upper; + + Float128 u_f128, sin_u, cos_u; + if (LIBC_LIKELY(x_e < FPBits::EXP_BIAS + FAST_PASS_EXPONENT)) + u_f128 = generic::range_reduction_small_f128(x); + else + u_f128 = range_reduction_large.accurate(); + + generic::sincos_eval(u_f128, sin_u, cos_u); + + auto get_sin_k = [](unsigned kk) -> Float128 { + unsigned idx = (kk & 64) ? 64 - (kk & 63) : (kk & 63); + Float128 ans = generic::SIN_K_PI_OVER_128_F128[idx]; + if (kk & 128) + ans.sign = Sign::NEG; + return ans; + }; + + // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). + Float128 sin_k_f128 = get_sin_k(k); + Float128 cos_k_f128 = get_sin_k(k + 64); + + // sin(x) = sin((k * pi/128 + u) + // = sin(u) * cos(k*pi/128) + cos(u) * sin(k*pi/128) + Float128 r = fputil::quick_add(fputil::quick_mul(sin_k_f128, cos_u), + fputil::quick_mul(cos_k_f128, sin_u)); + + // TODO: Add assertion if Ziv's accuracy tests fail in debug mode. + // https://github.com/llvm/llvm-project/issues/96452. + + return static_cast(r); +#endif // !LIBC_MATH_SIN_SKIP_ACCURATE_PASS +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/src/math/generic/sincos.cpp b/libc/src/math/generic/sincos.cpp new file mode 100644 index 00000000000000..a0dd3a018af59c --- /dev/null +++ b/libc/src/math/generic/sincos.cpp @@ -0,0 +1,247 @@ +//===-- Double-precision sincos function ----------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/math/sincos.h" +#include "hdr/errno_macros.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/double_double.h" +#include "src/__support/FPUtil/dyadic_float.h" +#include "src/__support/FPUtil/except_value_utils.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/rounding_mode.h" +#include "src/__support/common.h" +#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY +#include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA +#include "src/math/generic/sincos_eval.h" + +#ifdef LIBC_TARGET_CPU_HAS_FMA +#include "range_reduction_double_fma.h" + +using LIBC_NAMESPACE::fma::FAST_PASS_EXPONENT; +using LIBC_NAMESPACE::fma::ONE_TWENTY_EIGHT_OVER_PI; +using LIBC_NAMESPACE::fma::range_reduction_small; +using LIBC_NAMESPACE::fma::SIN_K_PI_OVER_128; + +LIBC_INLINE constexpr bool NO_FMA = false; +#else +#include "range_reduction_double_nofma.h" + +using LIBC_NAMESPACE::nofma::FAST_PASS_EXPONENT; +using LIBC_NAMESPACE::nofma::ONE_TWENTY_EIGHT_OVER_PI; +using LIBC_NAMESPACE::nofma::range_reduction_small; +using LIBC_NAMESPACE::nofma::SIN_K_PI_OVER_128; + +LIBC_INLINE constexpr bool NO_FMA = true; +#endif // LIBC_TARGET_CPU_HAS_FMA + +// TODO: We might be able to improve the performance of large range reduction of +// non-FMA targets further by operating directly on 25-bit chunks of 128/pi and +// pre-split SIN_K_PI_OVER_128, but that might double the memory footprint of +// those lookup table. +#include "range_reduction_double_common.h" + +#if ((LIBC_MATH & LIBC_MATH_SKIP_ACCURATE_PASS) != 0) +#define LIBC_MATH_SINCOS_SKIP_ACCURATE_PASS +#endif + +namespace LIBC_NAMESPACE { + +using DoubleDouble = fputil::DoubleDouble; +using Float128 = typename fputil::DyadicFloat<128>; + +LLVM_LIBC_FUNCTION(void, sincos, (double x, double *sin_x, double *cos_x)) { + using FPBits = typename fputil::FPBits; + FPBits xbits(x); + + uint16_t x_e = xbits.get_biased_exponent(); + + DoubleDouble y; + unsigned k; + generic::LargeRangeReduction range_reduction_large; + + // |x| < 2^32 (with FMA) or |x| < 2^23 (w/o FMA) + if (LIBC_LIKELY(x_e < FPBits::EXP_BIAS + FAST_PASS_EXPONENT)) { + // |x| < 2^-27 + if (LIBC_UNLIKELY(x_e < FPBits::EXP_BIAS - 27)) { + // Signed zeros. + if (LIBC_UNLIKELY(x == 0.0)) { + *sin_x = x; + *cos_x = 1.0; + return; + } + + // For |x| < 2^-27, max(|sin(x) - x|, |cos(x) - 1|) < ulp(x)/2. +#ifdef LIBC_TARGET_CPU_HAS_FMA + *sin_x = fputil::multiply_add(x, -0x1.0p-54, x); + *cos_x = fputil::multiply_add(x, -x, 1.0); +#else + *cos_x = fputil::round_result_slightly_down(1.0); + + if (LIBC_UNLIKELY(x_e < 4)) { + int rounding_mode = fputil::quick_get_round(); + if (rounding_mode == FE_TOWARDZERO || + (xbits.sign() == Sign::POS && rounding_mode == FE_DOWNWARD) || + (xbits.sign() == Sign::NEG && rounding_mode == FE_UPWARD)) + *sin_x = FPBits(xbits.uintval() - 1).get_val(); + } + *sin_x = fputil::multiply_add(x, -0x1.0p-54, x); +#endif // LIBC_TARGET_CPU_HAS_FMA + return; + } + + // // Small range reduction. + k = range_reduction_small(x, y); + } else { + // Inf or NaN + if (LIBC_UNLIKELY(x_e > 2 * FPBits::EXP_BIAS)) { + // sin(+-Inf) = NaN + if (xbits.get_mantissa() == 0) { + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_INVALID); + } + *sin_x = *cos_x = x + FPBits::quiet_nan().get_val(); + return; + } + + // Large range reduction. + k = range_reduction_large.compute_high_part(x); + y = range_reduction_large.fast(); + } + + DoubleDouble sin_y, cos_y; + + generic::sincos_eval(y, sin_y, cos_y); + + // Look up sin(k * pi/128) and cos(k * pi/128) + // Memory saving versions: + + // Use 128-entry table instead: + // DoubleDouble sin_k = SIN_K_PI_OVER_128[k & 127]; + // uint64_t sin_s = static_cast(k & 128) << (63 - 7); + // sin_k.hi = FPBits(FPBits(sin_k.hi).uintval() ^ sin_s).get_val(); + // sin_k.lo = FPBits(FPBits(sin_k.hi).uintval() ^ sin_s).get_val(); + // DoubleDouble cos_k = SIN_K_PI_OVER_128[(k + 64) & 127]; + // uint64_t cos_s = static_cast((k + 64) & 128) << (63 - 7); + // cos_k.hi = FPBits(FPBits(cos_k.hi).uintval() ^ cos_s).get_val(); + // cos_k.lo = FPBits(FPBits(cos_k.hi).uintval() ^ cos_s).get_val(); + + // Use 64-entry table instead: + // auto get_idx_dd = [](unsigned kk) -> DoubleDouble { + // unsigned idx = (kk & 64) ? 64 - (kk & 63) : (kk & 63); + // DoubleDouble ans = SIN_K_PI_OVER_128[idx]; + // if (kk & 128) { + // ans.hi = -ans.hi; + // ans.lo = -ans.lo; + // } + // return ans; + // }; + // DoubleDouble sin_k = get_idx_dd(k); + // DoubleDouble cos_k = get_idx_dd(k + 64); + + // Fast look up version, but needs 256-entry table. + // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). + DoubleDouble sin_k = SIN_K_PI_OVER_128[k & 255]; + DoubleDouble cos_k = SIN_K_PI_OVER_128[(k + 64) & 255]; + DoubleDouble msin_k{-sin_k.lo, -sin_k.hi}; + + // After range reduction, k = round(x * 128 / pi) and y = x - k * (pi / 128). + // So k is an integer and -pi / 256 <= y <= pi / 256. + // Then sin(x) = sin((k * pi/128 + y) + // = sin(y) * cos(k*pi/128) + cos(y) * sin(k*pi/128) + DoubleDouble sin_k_cos_y = fputil::quick_mult(cos_y, sin_k); + DoubleDouble cos_k_sin_y = fputil::quick_mult(sin_y, cos_k); + // cos(x) = cos((k * pi/128 + y) + // = cos(y) * cos(k*pi/128) - sin(y) * sin(k*pi/128) + DoubleDouble cos_k_cos_y = fputil::quick_mult(cos_y, cos_k); + DoubleDouble msin_k_sin_y = fputil::quick_mult(sin_y, msin_k); + + DoubleDouble sin_dd = + fputil::exact_add(sin_k_cos_y.hi, cos_k_sin_y.hi); + DoubleDouble cos_dd = + fputil::exact_add(cos_k_cos_y.hi, msin_k_sin_y.hi); + sin_dd.lo += sin_k_cos_y.lo + cos_k_sin_y.lo; + cos_dd.lo += msin_k_sin_y.lo + cos_k_cos_y.lo; + +#ifdef LIBC_MATH_SINCOS_SKIP_ACCURATE_PASS + *sin_x = sin_dd.hi + sin_dd.lo; + *cos_x = cos_dd.hi + cos_dd.lo; + return; +#else + // Accurate test and pass for correctly rounded implementation. + +#ifdef LIBC_TARGET_CPU_HAS_FMA + constexpr double ERR = 0x1.0p-70; +#else + // TODO: Improve non-FMA fast pass accuracy. + constexpr double ERR = 0x1.0p-66; +#endif // LIBC_TARGET_CPU_HAS_FMA + + double sin_lp = sin_dd.lo + ERR; + double sin_lm = sin_dd.lo - ERR; + double cos_lp = cos_dd.lo + ERR; + double cos_lm = cos_dd.lo - ERR; + + double sin_upper = sin_dd.hi + sin_lp; + double sin_lower = sin_dd.hi + sin_lm; + double cos_upper = cos_dd.hi + cos_lp; + double cos_lower = cos_dd.hi + cos_lm; + + // Ziv's rounding test. + if (LIBC_LIKELY(sin_upper == sin_lower && cos_upper == cos_lower)) { + *sin_x = sin_upper; + *cos_x = cos_upper; + return; + } + + Float128 u_f128, sin_u, cos_u; + if (LIBC_LIKELY(x_e < FPBits::EXP_BIAS + FAST_PASS_EXPONENT)) + u_f128 = generic::range_reduction_small_f128(x); + else + u_f128 = range_reduction_large.accurate(); + + generic::sincos_eval(u_f128, sin_u, cos_u); + + auto get_sin_k = [](unsigned kk) -> Float128 { + unsigned idx = (kk & 64) ? 64 - (kk & 63) : (kk & 63); + Float128 ans = generic::SIN_K_PI_OVER_128_F128[idx]; + if (kk & 128) + ans.sign = Sign::NEG; + return ans; + }; + + // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). + Float128 sin_k_f128 = get_sin_k(k); + Float128 cos_k_f128 = get_sin_k(k + 64); + Float128 msin_k_f128 = get_sin_k(k + 128); + + // TODO: Add assertion if Ziv's accuracy tests fail in debug mode. + // https://github.com/llvm/llvm-project/issues/96452. + + if (sin_upper == sin_lower) + *sin_x = sin_upper; + else + // sin(x) = sin((k * pi/128 + u) + // = sin(u) * cos(k*pi/128) + cos(u) * sin(k*pi/128) + *sin_x = static_cast( + fputil::quick_add(fputil::quick_mul(sin_k_f128, cos_u), + fputil::quick_mul(cos_k_f128, sin_u))); + + if (cos_upper == cos_lower) + *cos_x = cos_upper; + else + // cos(x) = cos((k * pi/128 + u) + // = cos(u) * cos(k*pi/128) - sin(u) * sin(k*pi/128) + *cos_x = static_cast( + fputil::quick_add(fputil::quick_mul(cos_k_f128, cos_u), + fputil::quick_mul(msin_k_f128, sin_u))); + +#endif // !LIBC_MATH_SINCOS_SKIP_ACCURATE_PASS +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/src/math/generic/sincos_eval.h b/libc/src/math/generic/sincos_eval.h new file mode 100644 index 00000000000000..5b4f3b8563cffc --- /dev/null +++ b/libc/src/math/generic/sincos_eval.h @@ -0,0 +1,124 @@ +//===-- Compute sin + cos for small angles ----------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_GENERIC_SINCOS_EVAL_H +#define LLVM_LIBC_SRC_MATH_GENERIC_SINCOS_EVAL_H + +#include "src/__support/FPUtil/PolyEval.h" +#include "src/__support/FPUtil/double_double.h" +#include "src/__support/FPUtil/dyadic_float.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/integer_literals.h" + +namespace LIBC_NAMESPACE { + +namespace generic { + +using fputil::DoubleDouble; +using Float128 = fputil::DyadicFloat<128>; + +LIBC_INLINE void sincos_eval(const DoubleDouble &u, DoubleDouble &sin_u, + DoubleDouble &cos_u) { + // Evaluate sin(y) = sin(x - k * (pi/128)) + // We use the degree-7 Taylor approximation: + // sin(y) ~ y - y^3/3! + y^5/5! - y^7/7! + // Then the error is bounded by: + // |sin(y) - (y - y^3/3! + y^5/5! - y^7/7!)| < |y|^9/9! < 2^-54/9! < 2^-72. + // For y ~ u_hi + u_lo, fully expanding the polynomial and drop any terms + // < ulp(u_hi^3) gives us: + // y - y^3/3! + y^5/5! - y^7/7! = ... + // ~ u_hi + u_hi^3 * (-1/6 + u_hi^2 * (1/120 - u_hi^2 * 1/5040)) + + // + u_lo (1 + u_hi^2 * (-1/2 + u_hi^2 / 24)) + double u_hi_sq = u.hi * u.hi; // Error < ulp(u_hi^2) < 2^(-6 - 52) = 2^-58. + // p1 ~ 1/120 + u_hi^2 / 5040. + double p1 = fputil::multiply_add(u_hi_sq, -0x1.a01a01a01a01ap-13, + 0x1.1111111111111p-7); + // q1 ~ -1/2 + u_hi^2 / 24. + double q1 = fputil::multiply_add(u_hi_sq, 0x1.5555555555555p-5, -0x1.0p-1); + double u_hi_3 = u_hi_sq * u.hi; + // p2 ~ -1/6 + u_hi^2 (1/120 - u_hi^2 * 1/5040) + double p2 = fputil::multiply_add(u_hi_sq, p1, -0x1.5555555555555p-3); + // q2 ~ 1 + u_hi^2 (-1/2 + u_hi^2 / 24) + double q2 = fputil::multiply_add(u_hi_sq, q1, 1.0); + double sin_lo = fputil::multiply_add(u_hi_3, p2, u.lo * q2); + // Overall, |sin(y) - (u_hi + sin_lo)| < 2*ulp(u_hi^3) < 2^-69. + + // Evaluate cos(y) = cos(x - k * (pi/128)) + // We use the degree-8 Taylor approximation: + // cos(y) ~ 1 - y^2/2 + y^4/4! - y^6/6! + y^8/8! + // Then the error is bounded by: + // |cos(y) - (...)| < |y|^10/10! < 2^-81 + // For y ~ u_hi + u_lo, fully expanding the polynomial and drop any terms + // < ulp(u_hi^3) gives us: + // 1 - y^2/2 + y^4/4! - y^6/6! + y^8/8! = ... + // ~ 1 - u_hi^2/2 + u_hi^4(1/24 + u_hi^2 (-1/720 + u_hi^2/40320)) + + // + u_hi u_lo (-1 + u_hi^2/6) + // We compute 1 - u_hi^2 accurately: + // v_hi + v_lo ~ 1 - u_hi^2/2 + double v_hi = fputil::multiply_add(u.hi, u.hi * (-0.5), 1.0); + double v_lo = 1.0 - v_hi; // Exact + v_lo = fputil::multiply_add(u.hi, u.hi * (-0.5), v_lo); + + // r1 ~ -1/720 + u_hi^2 / 40320 + double r1 = fputil::multiply_add(u_hi_sq, 0x1.a01a01a01a01ap-16, + -0x1.6c16c16c16c17p-10); + // s1 ~ -1 + u_hi^2 / 6 + double s1 = fputil::multiply_add(u_hi_sq, 0x1.5555555555555p-3, -1.0); + double u_hi_4 = u_hi_sq * u_hi_sq; + double u_hi_u_lo = u.hi * u.lo; + // r2 ~ 1/24 + u_hi^2 (-1/720 + u_hi^2 / 40320) + double r2 = fputil::multiply_add(u_hi_sq, r1, 0x1.5555555555555p-5); + // s2 ~ v_lo + u_hi * u_lo * (-1 + u_hi^2 / 6) + double s2 = fputil::multiply_add(u_hi_u_lo, s1, v_lo); + double cos_lo = fputil::multiply_add(u_hi_4, r2, s2); + // Overall, |cos(y) - (v_hi + cos_lo)| < 2*ulp(u_hi^4) < 2^-75. + + sin_u = fputil::exact_add(u.hi, sin_lo); + cos_u = fputil::exact_add(v_hi, cos_lo); +} + +LIBC_INLINE void sincos_eval(const Float128 &u, Float128 &sin_u, + Float128 &cos_u) { + Float128 u_sq = fputil::quick_mul(u, u); + + // sin(u) ~ x - x^3/3! + x^5/5! - x^7/7! + x^9/9! - x^11/11! + x^13/13! + constexpr Float128 SIN_COEFFS[] = { + {Sign::POS, -127, 0x80000000'00000000'00000000'00000000_u128}, // 1 + {Sign::NEG, -130, 0xaaaaaaaa'aaaaaaaa'aaaaaaaa'aaaaaaab_u128}, // -1/3! + {Sign::POS, -134, 0x88888888'88888888'88888888'88888889_u128}, // 1/5! + {Sign::NEG, -140, 0xd00d00d0'0d00d00d'00d00d00'd00d00d0_u128}, // -1/7! + {Sign::POS, -146, 0xb8ef1d2a'b6399c7d'560e4472'800b8ef2_u128}, // 1/9! + {Sign::NEG, -153, 0xd7322b3f'aa271c7f'3a3f25c1'bee38f10_u128}, // -1/11! + {Sign::POS, -160, 0xb092309d'43684be5'1c198e91'd7b4269e_u128}, // 1/13! + }; + + // cos(u) ~ 1 - x^2/2 + x^4/4! - x^6/6! + x^8/8! - x^10/10! + x^12/12! + constexpr Float128 COS_COEFFS[] = { + {Sign::POS, -127, 0x80000000'00000000'00000000'00000000_u128}, // 1.0 + {Sign::NEG, -128, 0x80000000'00000000'00000000'00000000_u128}, // 1/2 + {Sign::POS, -132, 0xaaaaaaaa'aaaaaaaa'aaaaaaaa'aaaaaaab_u128}, // 1/4! + {Sign::NEG, -137, 0xb60b60b6'0b60b60b'60b60b60'b60b60b6_u128}, // 1/6! + {Sign::POS, -143, 0xd00d00d0'0d00d00d'00d00d00'd00d00d0_u128}, // 1/8! + {Sign::NEG, -149, 0x93f27dbb'c4fae397'780b69f5'333c725b_u128}, // 1/10! + {Sign::POS, -156, 0x8f76c77f'c6c4bdaa'26d4c3d6'7f425f60_u128}, // 1/12! + }; + + sin_u = fputil::quick_mul(u, fputil::polyeval(u_sq, SIN_COEFFS[0], + SIN_COEFFS[1], SIN_COEFFS[2], + SIN_COEFFS[3], SIN_COEFFS[4], + SIN_COEFFS[5], SIN_COEFFS[6])); + cos_u = fputil::polyeval(u_sq, COS_COEFFS[0], COS_COEFFS[1], COS_COEFFS[2], + COS_COEFFS[3], COS_COEFFS[4], COS_COEFFS[5], + COS_COEFFS[6]); +} + +} // namespace generic + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_GENERIC_SINCOSF_EVAL_H diff --git a/libc/src/math/x86_64/CMakeLists.txt b/libc/src/math/x86_64/CMakeLists.txt index cd129e3eefb75c..3cfc422e56d49a 100644 --- a/libc/src/math/x86_64/CMakeLists.txt +++ b/libc/src/math/x86_64/CMakeLists.txt @@ -1,23 +1,3 @@ -add_entrypoint_object( - cos - SRCS - cos.cpp - HDRS - ../cos.h - COMPILE_OPTIONS - -O2 -) - -add_entrypoint_object( - sin - SRCS - sin.cpp - HDRS - ../sin.h - COMPILE_OPTIONS - -O2 -) - add_entrypoint_object( tan SRCS diff --git a/libc/src/signal/linux/CMakeLists.txt b/libc/src/signal/linux/CMakeLists.txt index 7606b4b21d3ddb..5a6be242ddd94f 100644 --- a/libc/src/signal/linux/CMakeLists.txt +++ b/libc/src/signal/linux/CMakeLists.txt @@ -60,6 +60,7 @@ add_entrypoint_object( DEPENDS .__restore libc.hdr.types.sigset_t + libc.hdr.types.struct_sigaction libc.include.sys_syscall libc.src.__support.OSUtil.osutil libc.src.errno.errno @@ -124,7 +125,7 @@ add_entrypoint_object( ../signal.h DEPENDS .sigaction - libc.include.signal + libc.hdr.signal_macros ) add_entrypoint_object( diff --git a/libc/src/signal/linux/signal.cpp b/libc/src/signal/linux/signal.cpp index a517fa73ba8a2c..0d5463553eb78d 100644 --- a/libc/src/signal/linux/signal.cpp +++ b/libc/src/signal/linux/signal.cpp @@ -7,11 +7,9 @@ //===----------------------------------------------------------------------===// #include "src/signal/signal.h" -#include "src/signal/sigaction.h" - +#include "hdr/signal_macros.h" #include "src/__support/common.h" - -#include +#include "src/signal/sigaction.h" namespace LIBC_NAMESPACE { diff --git a/libc/src/signal/sigaction.h b/libc/src/signal/sigaction.h index c36a3ec9fedfaa..15b689b7dacc75 100644 --- a/libc/src/signal/sigaction.h +++ b/libc/src/signal/sigaction.h @@ -9,7 +9,7 @@ #ifndef LLVM_LIBC_SRC_SIGNAL_SIGACTION_H #define LLVM_LIBC_SRC_SIGNAL_SIGACTION_H -#include +#include "hdr/types/struct_sigaction.h" namespace LIBC_NAMESPACE { diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt index 61c05f07389590..677bf358c82c4a 100644 --- a/libc/src/stdlib/CMakeLists.txt +++ b/libc/src/stdlib/CMakeLists.txt @@ -304,6 +304,7 @@ add_entrypoint_object( DEPENDS .rand_util libc.include.stdlib + libc.src.__support.threads.sleep ) add_entrypoint_object( diff --git a/libc/src/stdlib/rand.cpp b/libc/src/stdlib/rand.cpp index ad543b4048a949..ff3875c2f69592 100644 --- a/libc/src/stdlib/rand.cpp +++ b/libc/src/stdlib/rand.cpp @@ -8,6 +8,7 @@ #include "src/stdlib/rand.h" #include "src/__support/common.h" +#include "src/__support/threads/sleep.h" #include "src/stdlib/rand_util.h" namespace LIBC_NAMESPACE { @@ -15,12 +16,17 @@ namespace LIBC_NAMESPACE { // An implementation of the xorshift64star pseudo random number generator. This // is a good general purpose generator for most non-cryptographics applications. LLVM_LIBC_FUNCTION(int, rand, (void)) { - unsigned long x = rand_next; - x ^= x >> 12; - x ^= x << 25; - x ^= x >> 27; - rand_next = x; - return static_cast((x * 0x2545F4914F6CDD1Dul) >> 32) & RAND_MAX; + unsigned long orig = rand_next.load(cpp::MemoryOrder::RELAXED); + for (;;) { + unsigned long x = orig; + x ^= x >> 12; + x ^= x << 25; + x ^= x >> 27; + if (rand_next.compare_exchange_strong(orig, x, cpp::MemoryOrder::ACQUIRE, + cpp::MemoryOrder::RELAXED)) + return static_cast((x * 0x2545F4914F6CDD1Dul) >> 32) & RAND_MAX; + sleep_briefly(); + } } } // namespace LIBC_NAMESPACE diff --git a/libc/src/stdlib/rand_util.cpp b/libc/src/stdlib/rand_util.cpp index 1f3dbce9c78608..ff3478db700035 100644 --- a/libc/src/stdlib/rand_util.cpp +++ b/libc/src/stdlib/rand_util.cpp @@ -7,18 +7,13 @@ //===----------------------------------------------------------------------===// #include "src/stdlib/rand_util.h" +#include "src/__support/CPP/atomic.h" #include "src/__support/macros/attributes.h" namespace LIBC_NAMESPACE { -#ifdef LIBC_TARGET_ARCH_IS_GPU -// FIXME: Local GPU memory cannot be initialized so we cannot currently provide -// a standard compliant default value. -ThreadLocal rand_next; -#else -// C standard 7.10p2: If 'rand' is called before 'srand' it is to proceed as if -// the 'srand' function was called with a value of '1'. -LIBC_THREAD_LOCAL unsigned long rand_next = 1; -#endif +// C standard 7.10p2: If 'rand' is called before 'srand' it is to +// proceed as if the 'srand' function was called with a value of '1'. +cpp::Atomic rand_next = 1; } // namespace LIBC_NAMESPACE diff --git a/libc/src/stdlib/rand_util.h b/libc/src/stdlib/rand_util.h index cadd6b5cdcbb8c..5d7febf8248d88 100644 --- a/libc/src/stdlib/rand_util.h +++ b/libc/src/stdlib/rand_util.h @@ -9,33 +9,15 @@ #ifndef LLVM_LIBC_SRC_STDLIB_RAND_UTIL_H #define LLVM_LIBC_SRC_STDLIB_RAND_UTIL_H -#include "src/__support/GPU/utils.h" +#include "src/__support/CPP/atomic.h" #include "src/__support/macros/attributes.h" namespace LIBC_NAMESPACE { -#ifdef LIBC_TARGET_ARCH_IS_GPU -// Implement thread local storage on the GPU using local memory. Each thread -// gets its slot in the local memory array and is private to the group. -// TODO: We need to implement the 'thread_local' keyword on the GPU. This is an -// inefficient and incomplete stand-in until that is done. -template class ThreadLocal { -private: - static constexpr long MAX_THREADS = 1024; - [[clang::loader_uninitialized]] static inline gpu::Local - storage[MAX_THREADS]; - -public: - LIBC_INLINE operator T() const { return storage[gpu::get_thread_id()]; } - LIBC_INLINE void operator=(const T &value) { - storage[gpu::get_thread_id()] = value; - } -}; - -extern ThreadLocal rand_next; -#else -extern LIBC_THREAD_LOCAL unsigned long rand_next; -#endif +// The ISO C standard does not explicitly require thread-safe behavior for the +// generic `rand()` function. Some implementations expect it however, so we +// provide it here. +extern cpp::Atomic rand_next; } // namespace LIBC_NAMESPACE diff --git a/libc/src/stdlib/srand.cpp b/libc/src/stdlib/srand.cpp index 008c7a9e565e41..21166c7a6754e9 100644 --- a/libc/src/stdlib/srand.cpp +++ b/libc/src/stdlib/srand.cpp @@ -12,6 +12,8 @@ namespace LIBC_NAMESPACE { -LLVM_LIBC_FUNCTION(void, srand, (unsigned int seed)) { rand_next = seed; } +LLVM_LIBC_FUNCTION(void, srand, (unsigned int seed)) { + rand_next.store(seed, cpp::MemoryOrder::RELAXED); +} } // namespace LIBC_NAMESPACE diff --git a/libc/startup/linux/CMakeLists.txt b/libc/startup/linux/CMakeLists.txt index f041a4826dc947..336c5d0f6bfa27 100644 --- a/libc/startup/linux/CMakeLists.txt +++ b/libc/startup/linux/CMakeLists.txt @@ -98,6 +98,7 @@ add_object_library( libc.config.linux.app_h libc.include.sys_mman libc.include.sys_syscall + libc.include.llvm-libc-macros.link_macros libc.src.__support.threads.thread libc.src.__support.OSUtil.osutil libc.src.stdlib.exit diff --git a/libc/startup/linux/do_start.cpp b/libc/startup/linux/do_start.cpp index 55fd575f7ad0b0..30ab1f0e26ea58 100644 --- a/libc/startup/linux/do_start.cpp +++ b/libc/startup/linux/do_start.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// #include "startup/linux/do_start.h" +#include "include/llvm-libc-macros/link-macros.h" #include "src/__support/OSUtil/syscall.h" #include "src/__support/threads/thread.h" #include "src/stdlib/atexit.h" @@ -68,8 +69,8 @@ static ThreadAttributes main_thread_attrib; // After the argv array, is a 8-byte long NULL value before the array of env // values. The end of the env values is marked by another 8-byte long NULL // value. We step over it (the "+ 1" below) to get to the env values. - ArgVEntryType *env_ptr = app.args->argv + app.args->argc + 1; - ArgVEntryType *env_end_marker = env_ptr; + uintptr_t *env_ptr = app.args->argv + app.args->argc + 1; + uintptr_t *env_end_marker = env_ptr; app.env_ptr = env_ptr; while (*env_end_marker) ++env_end_marker; @@ -79,13 +80,13 @@ static ThreadAttributes main_thread_attrib; // After the env array, is the aux-vector. The end of the aux-vector is // denoted by an AT_NULL entry. - Elf64_Phdr *program_hdr_table = nullptr; + ElfW(Phdr) *program_hdr_table = nullptr; uintptr_t program_hdr_count = 0; app.auxv_ptr = reinterpret_cast(env_end_marker + 1); for (auto *aux_entry = app.auxv_ptr; aux_entry->id != AT_NULL; ++aux_entry) { switch (aux_entry->id) { case AT_PHDR: - program_hdr_table = reinterpret_cast(aux_entry->value); + program_hdr_table = reinterpret_cast(aux_entry->value); break; case AT_PHNUM: program_hdr_count = aux_entry->value; @@ -100,10 +101,10 @@ static ThreadAttributes main_thread_attrib; ptrdiff_t base = 0; app.tls.size = 0; - Elf64_Phdr *tls_phdr = nullptr; + ElfW(Phdr) *tls_phdr = nullptr; for (uintptr_t i = 0; i < program_hdr_count; ++i) { - Elf64_Phdr &phdr = program_hdr_table[i]; + ElfW(Phdr) &phdr = program_hdr_table[i]; if (phdr.p_type == PT_PHDR) base = reinterpret_cast(program_hdr_table) - phdr.p_vaddr; if (phdr.p_type == PT_DYNAMIC && _DYNAMIC) diff --git a/libc/test/src/__support/CMakeLists.txt b/libc/test/src/__support/CMakeLists.txt index e224e82c922f03..ce8413fed71721 100644 --- a/libc/test/src/__support/CMakeLists.txt +++ b/libc/test/src/__support/CMakeLists.txt @@ -13,17 +13,19 @@ add_libc_test( libc.src.string.memcpy ) -add_libc_test( - freelist_test - SUITE - libc-support-tests - SRCS - freelist_test.cpp - DEPENDS - libc.src.__support.CPP.array - libc.src.__support.CPP.span - libc.src.__support.freelist -) +if(NOT LIBC_TARGET_ARCHITECTURE_IS_NVPTX) + add_libc_test( + freelist_test + SUITE + libc-support-tests + SRCS + freelist_test.cpp + DEPENDS + libc.src.__support.CPP.array + libc.src.__support.CPP.span + libc.src.__support.freelist + ) +endif() if(LLVM_LIBC_FULL_BUILD) add_libc_test( diff --git a/libc/test/src/__support/fixedvector_test.cpp b/libc/test/src/__support/fixedvector_test.cpp index 212e1aed20f7cd..b73df04d03746b 100644 --- a/libc/test/src/__support/fixedvector_test.cpp +++ b/libc/test/src/__support/fixedvector_test.cpp @@ -96,3 +96,13 @@ TEST(LlvmLibcFixedVectorTest, ForwardIteration) { ASSERT_EQ(*it, arr[idx]); } } + +TEST(LlvmLibcFixedVectorTest, ConstForwardIteration) { + const LIBC_NAMESPACE::cpp::array arr{1, 2, 3, 4}; + const LIBC_NAMESPACE::FixedVector vec(arr.begin(), arr.end()); + ASSERT_EQ(vec.size(), arr.size()); + for (auto it = vec.begin(); it != vec.end(); ++it) { + auto idx = it - vec.begin(); + ASSERT_EQ(*it, arr[idx]); + } +} diff --git a/libc/test/src/__support/math_extras_test.cpp b/libc/test/src/__support/math_extras_test.cpp index 0047888965177e..9f9036b9d5cdfa 100644 --- a/libc/test/src/__support/math_extras_test.cpp +++ b/libc/test/src/__support/math_extras_test.cpp @@ -102,7 +102,7 @@ TYPED_TEST(LlvmLibcBitTest, CountZeros, UnsignedTypesNoBigInt) { } using UnsignedTypes = testing::TypeList< -#if defined(__SIZEOF_INT128__) +#if defined(LIBC_TYPES_HAS_INT128) __uint128_t, #endif unsigned char, unsigned short, unsigned int, unsigned long, diff --git a/libc/test/src/fcntl/CMakeLists.txt b/libc/test/src/fcntl/CMakeLists.txt index aae296f074bea0..48048b7fe88666 100644 --- a/libc/test/src/fcntl/CMakeLists.txt +++ b/libc/test/src/fcntl/CMakeLists.txt @@ -29,6 +29,7 @@ add_libc_unittest( libc.src.fcntl.fcntl libc.src.fcntl.open libc.src.unistd.close + libc.src.unistd.getpid libc.hdr.types.struct_flock libc.hdr.fcntl_macros libc.test.UnitTest.ErrnoSetterMatcher diff --git a/libc/test/src/fcntl/fcntl_test.cpp b/libc/test/src/fcntl/fcntl_test.cpp index fc909acc1aa0be..ffbb3ec337ed4d 100644 --- a/libc/test/src/fcntl/fcntl_test.cpp +++ b/libc/test/src/fcntl/fcntl_test.cpp @@ -12,6 +12,7 @@ #include "src/fcntl/fcntl.h" #include "src/fcntl/open.h" #include "src/unistd/close.h" +#include "src/unistd/getpid.h" #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" @@ -163,3 +164,22 @@ TEST(LlvmLibcFcntlTest, UseAfterClose) { ASSERT_EQ(-1, LIBC_NAMESPACE::fcntl(fd, F_GETFL)); ASSERT_ERRNO_EQ(EBADF); } + +TEST(LlvmLibcFcntlTest, SetGetOwnerTest) { + LIBC_NAMESPACE::libc_errno = 0; + using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; + pid_t pid = LIBC_NAMESPACE::getpid(); + ASSERT_GT(pid, -1); + constexpr const char *TEST_FILE_NAME = "testdata/fcntl_set_get_owner.test"; + auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME); + int fd = LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU); + ASSERT_ERRNO_SUCCESS(); + ASSERT_GT(fd, 0); + int ret = LIBC_NAMESPACE::fcntl(fd, F_SETOWN, pid); + ASSERT_ERRNO_SUCCESS(); + ASSERT_GT(ret, -1); + int ret2 = LIBC_NAMESPACE::fcntl(fd, F_GETOWN); + ASSERT_ERRNO_SUCCESS(); + ASSERT_EQ(ret2, pid); + ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0)); +} diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt index bb364c3f0a1751..2e04abd7ce062a 100644 --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -72,6 +72,18 @@ add_fp_unittest( libc.src.__support.FPUtil.fp_bits ) +add_fp_unittest( + sincos_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + sincos_test.cpp + DEPENDS + libc.src.math.sincos + libc.src.__support.FPUtil.fp_bits +) + add_fp_unittest( tanf_test NEED_MPFR @@ -1247,9 +1259,10 @@ add_fp_unittest( libc-math-unittests SRCS sqrtf_test.cpp + HDRS + SqrtTest.h DEPENDS libc.src.math.sqrtf - libc.src.__support.FPUtil.fp_bits ) add_fp_unittest( @@ -1259,9 +1272,10 @@ add_fp_unittest( libc-math-unittests SRCS sqrt_test.cpp + HDRS + SqrtTest.h DEPENDS libc.src.math.sqrt - libc.src.__support.FPUtil.fp_bits ) add_fp_unittest( @@ -1271,9 +1285,10 @@ add_fp_unittest( libc-math-unittests SRCS sqrtl_test.cpp + HDRS + SqrtTest.h DEPENDS libc.src.math.sqrtl - libc.src.__support.FPUtil.fp_bits ) add_fp_unittest( @@ -1283,9 +1298,10 @@ add_fp_unittest( libc-math-unittests SRCS generic_sqrtf_test.cpp + HDRS + SqrtTest.h DEPENDS libc.src.math.sqrtf - libc.src.__support.FPUtil.fp_bits libc.src.__support.FPUtil.generic.sqrt COMPILE_OPTIONS -O3 @@ -1298,9 +1314,10 @@ add_fp_unittest( libc-math-unittests SRCS generic_sqrt_test.cpp + HDRS + SqrtTest.h DEPENDS libc.src.math.sqrt - libc.src.__support.FPUtil.fp_bits libc.src.__support.FPUtil.generic.sqrt COMPILE_OPTIONS -O3 @@ -1313,9 +1330,10 @@ add_fp_unittest( libc-math-unittests SRCS generic_sqrtl_test.cpp + HDRS + SqrtTest.h DEPENDS libc.src.math.sqrtl - libc.src.__support.FPUtil.fp_bits libc.src.__support.FPUtil.generic.sqrt COMPILE_OPTIONS -O3 @@ -1729,6 +1747,18 @@ add_fp_unittest( libc.src.__support.FPUtil.fp_bits ) +add_fp_unittest( + fmul_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + fmul_test.cpp + HDRS + FMulTest.h + DEPENDS + libc.src.math.fmul +) add_fp_unittest( asinhf_test NEED_MPFR @@ -1890,6 +1920,60 @@ add_fp_unittest( libc.src.__support.FPUtil.fp_bits ) +add_fp_unittest( + f16div_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + f16div_test.cpp + HDRS + DivTest.h + DEPENDS + libc.src.math.f16div +) + +add_fp_unittest( + f16divf_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + f16divf_test.cpp + HDRS + DivTest.h + DEPENDS + libc.src.math.f16divf +) + +add_fp_unittest( + f16divl_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + f16divl_test.cpp + HDRS + DivTest.h + DEPENDS + libc.src.math.f16divl +) + +add_fp_unittest( + f16fma_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + f16fma_test.cpp + HDRS + FmaTest.h + DEPENDS + libc.src.math.f16fma + libc.src.stdlib.rand + libc.src.stdlib.srand +) + add_fp_unittest( f16fmaf_test NEED_MPFR @@ -1905,6 +1989,47 @@ add_fp_unittest( libc.src.stdlib.srand ) +add_fp_unittest( + f16fmal_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + f16fmal_test.cpp + HDRS + FmaTest.h + DEPENDS + libc.src.math.f16fmal + libc.src.stdlib.rand + libc.src.stdlib.srand +) + +add_fp_unittest( + f16sqrt_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + f16sqrt_test.cpp + HDRS + SqrtTest.h + DEPENDS + libc.src.math.f16sqrt +) + +add_fp_unittest( + f16sqrtl_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + f16sqrtl_test.cpp + HDRS + SqrtTest.h + DEPENDS + libc.src.math.f16sqrtl +) + add_subdirectory(generic) add_subdirectory(smoke) diff --git a/libc/test/src/math/DivTest.h b/libc/test/src/math/DivTest.h new file mode 100644 index 00000000000000..1cdc1398a1a1c1 --- /dev/null +++ b/libc/test/src/math/DivTest.h @@ -0,0 +1,74 @@ +//===-- Utility class to test different flavors of float div ----*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_TEST_SRC_MATH_DIVTEST_H +#define LLVM_LIBC_TEST_SRC_MATH_DIVTEST_H + +#include "test/UnitTest/FEnvSafeTest.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" +#include "utils/MPFRWrapper/MPFRUtils.h" + +namespace mpfr = LIBC_NAMESPACE::testing::mpfr; + +template +class DivTest : public LIBC_NAMESPACE::testing::FEnvSafeTest { + + struct InConstants { + DECLARE_SPECIAL_CONSTANTS(InType) + }; + + using InFPBits = typename InConstants::FPBits; + using InStorageType = typename InConstants::StorageType; + + static constexpr InStorageType IN_MAX_NORMAL_U = + InFPBits::max_normal().uintval(); + static constexpr InStorageType IN_MIN_NORMAL_U = + InFPBits::min_normal().uintval(); + static constexpr InStorageType IN_MAX_SUBNORMAL_U = + InFPBits::max_subnormal().uintval(); + static constexpr InStorageType IN_MIN_SUBNORMAL_U = + InFPBits::min_subnormal().uintval(); + +public: + using DivFunc = OutType (*)(InType, InType); + + void test_subnormal_range(DivFunc func) { + constexpr InStorageType COUNT = 100'001; + constexpr InStorageType STEP = + (IN_MAX_SUBNORMAL_U - IN_MIN_SUBNORMAL_U) / COUNT; + for (InStorageType i = 0, v = 0, w = IN_MAX_SUBNORMAL_U; i <= COUNT; + ++i, v += STEP, w -= STEP) { + InType x = InFPBits(v).get_val(); + InType y = InFPBits(w).get_val(); + mpfr::BinaryInput input{x, y}; + EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Div, input, func(x, y), + 0.5); + } + } + + void test_normal_range(DivFunc func) { + constexpr InStorageType COUNT = 100'001; + constexpr InStorageType STEP = (IN_MAX_NORMAL_U - IN_MIN_NORMAL_U) / COUNT; + for (InStorageType i = 0, v = 0, w = IN_MAX_NORMAL_U; i <= COUNT; + ++i, v += STEP, w -= STEP) { + InType x = InFPBits(v).get_val(); + InType y = InFPBits(w).get_val(); + mpfr::BinaryInput input{x, y}; + EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Div, input, func(x, y), + 0.5); + } + } +}; + +#define LIST_DIV_TESTS(OutType, InType, func) \ + using LlvmLibcDivTest = DivTest; \ + TEST_F(LlvmLibcDivTest, SubnormalRange) { test_subnormal_range(&func); } \ + TEST_F(LlvmLibcDivTest, NormalRange) { test_normal_range(&func); } + +#endif // LLVM_LIBC_TEST_SRC_MATH_DIVTEST_H diff --git a/libc/test/src/math/FMulTest.h b/libc/test/src/math/FMulTest.h new file mode 100644 index 00000000000000..864910c29d83f4 --- /dev/null +++ b/libc/test/src/math/FMulTest.h @@ -0,0 +1,121 @@ +//===-- Utility class to test fmul[f|l] ---------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_TEST_SRC_MATH_FMULTEST_H +#define LLVM_LIBC_TEST_SRC_MATH_FMULTEST_H + +#include "src/__support/FPUtil/FPBits.h" +#include "test/UnitTest/FEnvSafeTest.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" +#include "utils/MPFRWrapper/MPFRUtils.h" + +namespace mpfr = LIBC_NAMESPACE::testing::mpfr; + +template +class FmulMPFRTest : public LIBC_NAMESPACE::testing::FEnvSafeTest { + + DECLARE_SPECIAL_CONSTANTS(InType) + +public: + typedef OutType (*FMulFunc)(InType, InType); + + void testFMulMPFR(FMulFunc func) { + constexpr int N = 10; + mpfr::BinaryInput INPUTS[N] = { + {3.0, 5.0}, + {0x1.0p1, 0x1.0p-131}, + {0x1.0p2, 0x1.0p-129}, + {1.0, 1.0}, + {-0.0, -0.0}, + {-0.0, 0.0}, + {0.0, -0.0}, + {0x1.0p100, 0x1.0p100}, + {1.0, 1.0 + 0x1.0p-128 + 0x1.0p-149 + 0x1.0p-150}, + {1.0, 0x1.0p-128 + 0x1.0p-149 + 0x1.0p-150}}; + + for (int i = 0; i < N; ++i) { + InType x = INPUTS[i].x; + InType y = INPUTS[i].y; + ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Fmul, INPUTS[i], + func(x, y), 0.5); + } + } + + void testSpecialInputsMPFR(FMulFunc func) { + constexpr int N = 27; + mpfr::BinaryInput INPUTS[N] = {{inf, 0x1.0p-129}, + {0x1.0p-129, inf}, + {inf, 2.0}, + {3.0, inf}, + {0.0, 0.0}, + {neg_inf, aNaN}, + {aNaN, neg_inf}, + {neg_inf, neg_inf}, + {0.0, neg_inf}, + {neg_inf, 0.0}, + {neg_inf, 1.0}, + {1.0, neg_inf}, + {neg_inf, 0x1.0p-129}, + {0x1.0p-129, neg_inf}, + {0.0, 0x1.0p-129}, + {inf, 0.0}, + {0.0, inf}, + {0.0, aNaN}, + {2.0, aNaN}, + {0x1.0p-129, aNaN}, + {inf, aNaN}, + {aNaN, aNaN}, + {0.0, sNaN}, + {2.0, sNaN}, + {0x1.0p-129, sNaN}, + {inf, sNaN}, + {sNaN, sNaN}}; + + for (int i = 0; i < N; ++i) { + InType x = INPUTS[i].x; + InType y = INPUTS[i].y; + ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Fmul, INPUTS[i], + func(x, y), 0.5); + } + } + + void testNormalRange(FMulFunc func) { + using FPBits = LIBC_NAMESPACE::fputil::FPBits; + using StorageType = typename FPBits::StorageType; + static constexpr StorageType MAX_NORMAL = FPBits::max_normal().uintval(); + static constexpr StorageType MIN_NORMAL = FPBits::min_normal().uintval(); + + constexpr StorageType COUNT = 10'001; + constexpr StorageType STEP = (MAX_NORMAL - MIN_NORMAL) / COUNT; + for (int signs = 0; signs < 4; ++signs) { + for (StorageType v = MIN_NORMAL, w = MAX_NORMAL; + v <= MAX_NORMAL && w >= MIN_NORMAL; v += STEP, w -= STEP) { + InType x = FPBits(v).get_val(), y = FPBits(w).get_val(); + if (signs % 2 == 1) { + x = -x; + } + if (signs >= 2) { + y = -y; + } + + mpfr::BinaryInput input{x, y}; + ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Fmul, input, func(x, y), + 0.5); + } + } + } +}; + +#define LIST_FMUL_MPFR_TESTS(OutType, InType, func) \ + using LlvmLibcFmulTest = FmulMPFRTest; \ + TEST_F(LlvmLibcFmulTest, MulMpfr) { testFMulMPFR(&func); } \ + TEST_F(LlvmLibcFmulTest, NanInfMpfr) { testSpecialInputsMPFR(&func); } \ + TEST_F(LlvmLibcFmulTest, NormalRange) { testNormalRange(&func); } + +#endif // LLVM_LIBC_TEST_SRC_MATH_FMULTEST_H diff --git a/libc/test/src/math/FmaTest.h b/libc/test/src/math/FmaTest.h index 53895e7d633c29..01143331d4ab57 100644 --- a/libc/test/src/math/FmaTest.h +++ b/libc/test/src/math/FmaTest.h @@ -45,9 +45,6 @@ class FmaTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { static constexpr InStorageType IN_MIN_SUBNORMAL_U = InFPBits::min_subnormal().uintval(); - OutConstants out; - InConstants in; - InStorageType get_random_bit_pattern() { InStorageType bits{0}; for (InStorageType i = 0; i < sizeof(InStorageType) / 2; ++i) { @@ -92,4 +89,14 @@ class FmaTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { } }; +#define LIST_FMA_TESTS(T, func) \ + using LlvmLibcFmaTest = FmaTestTemplate; \ + TEST_F(LlvmLibcFmaTest, SubnormalRange) { test_subnormal_range(&func); } \ + TEST_F(LlvmLibcFmaTest, NormalRange) { test_normal_range(&func); } + +#define LIST_NARROWING_FMA_TESTS(OutType, InType, func) \ + using LlvmLibcFmaTest = FmaTestTemplate; \ + TEST_F(LlvmLibcFmaTest, SubnormalRange) { test_subnormal_range(&func); } \ + TEST_F(LlvmLibcFmaTest, NormalRange) { test_normal_range(&func); } + #endif // LLVM_LIBC_TEST_SRC_MATH_FMATEST_H diff --git a/libc/test/src/math/SqrtTest.h b/libc/test/src/math/SqrtTest.h index 1c422e201bb234..770cc94b3b9406 100644 --- a/libc/test/src/math/SqrtTest.h +++ b/libc/test/src/math/SqrtTest.h @@ -6,51 +6,36 @@ // //===----------------------------------------------------------------------===// -#include "src/__support/CPP/bit.h" #include "test/UnitTest/FEnvSafeTest.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" #include "utils/MPFRWrapper/MPFRUtils.h" -#include "hdr/math_macros.h" - namespace mpfr = LIBC_NAMESPACE::testing::mpfr; -template +template class SqrtTest : public LIBC_NAMESPACE::testing::FEnvSafeTest { - DECLARE_SPECIAL_CONSTANTS(T) + DECLARE_SPECIAL_CONSTANTS(InType) static constexpr StorageType HIDDEN_BIT = - StorageType(1) << LIBC_NAMESPACE::fputil::FPBits::FRACTION_LEN; + StorageType(1) << LIBC_NAMESPACE::fputil::FPBits::FRACTION_LEN; public: - typedef T (*SqrtFunc)(T); - - void test_special_numbers(SqrtFunc func) { - ASSERT_FP_EQ(aNaN, func(aNaN)); - ASSERT_FP_EQ(inf, func(inf)); - ASSERT_FP_EQ(aNaN, func(neg_inf)); - ASSERT_FP_EQ(0.0, func(0.0)); - ASSERT_FP_EQ(-0.0, func(-0.0)); - ASSERT_FP_EQ(aNaN, func(T(-1.0))); - ASSERT_FP_EQ(T(1.0), func(T(1.0))); - ASSERT_FP_EQ(T(2.0), func(T(4.0))); - ASSERT_FP_EQ(T(3.0), func(T(9.0))); - } + using SqrtFunc = OutType (*)(InType); void test_denormal_values(SqrtFunc func) { for (StorageType mant = 1; mant < HIDDEN_BIT; mant <<= 1) { - FPBits denormal(T(0.0)); + FPBits denormal(zero); denormal.set_mantissa(mant); - T x = denormal.get_val(); + InType x = denormal.get_val(); EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Sqrt, x, func(x), 0.5); } constexpr StorageType COUNT = 200'001; constexpr StorageType STEP = HIDDEN_BIT / COUNT; for (StorageType i = 0, v = 0; i <= COUNT; ++i, v += STEP) { - T x = LIBC_NAMESPACE::cpp::bit_cast(v); + InType x = FPBits(i).get_val(); EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Sqrt, x, func(x), 0.5); } } @@ -59,17 +44,21 @@ class SqrtTest : public LIBC_NAMESPACE::testing::FEnvSafeTest { constexpr StorageType COUNT = 200'001; constexpr StorageType STEP = STORAGE_MAX / COUNT; for (StorageType i = 0, v = 0; i <= COUNT; ++i, v += STEP) { - T x = LIBC_NAMESPACE::cpp::bit_cast(v); - if (isnan(x) || (x < 0)) { + FPBits x_bits(v); + InType x = x_bits.get_val(); + if (x_bits.is_nan() || (x < 0)) continue; - } EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Sqrt, x, func(x), 0.5); } } }; #define LIST_SQRT_TESTS(T, func) \ - using LlvmLibcSqrtTest = SqrtTest; \ - TEST_F(LlvmLibcSqrtTest, SpecialNumbers) { test_special_numbers(&func); } \ + using LlvmLibcSqrtTest = SqrtTest; \ + TEST_F(LlvmLibcSqrtTest, DenormalValues) { test_denormal_values(&func); } \ + TEST_F(LlvmLibcSqrtTest, NormalRange) { test_normal_range(&func); } + +#define LIST_NARROWING_SQRT_TESTS(OutType, InType, func) \ + using LlvmLibcSqrtTest = SqrtTest; \ TEST_F(LlvmLibcSqrtTest, DenormalValues) { test_denormal_values(&func); } \ TEST_F(LlvmLibcSqrtTest, NormalRange) { test_normal_range(&func); } diff --git a/libc/test/src/math/cos_test.cpp b/libc/test/src/math/cos_test.cpp index 9a39616ed16f81..e12e9a8274692d 100644 --- a/libc/test/src/math/cos_test.cpp +++ b/libc/test/src/math/cos_test.cpp @@ -6,27 +6,124 @@ // //===----------------------------------------------------------------------===// +#include "src/__support/FPUtil/FPBits.h" #include "src/math/cos.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" #include "utils/MPFRWrapper/MPFRUtils.h" -#include "hdr/math_macros.h" - using LlvmLibcCosTest = LIBC_NAMESPACE::testing::FPTest; namespace mpfr = LIBC_NAMESPACE::testing::mpfr; -TEST_F(LlvmLibcCosTest, Range) { - static constexpr double _2pi = 6.283185307179586; - constexpr StorageType COUNT = 100'000; - constexpr StorageType STEP = STORAGE_MAX / COUNT; - for (StorageType i = 0, v = 0; i <= COUNT; ++i, v += STEP) { - double x = FPBits(v).get_val(); - // TODO: Expand the range of testing after range reduction is implemented. - if (isnan(x) || isinf(x) || x > _2pi || x < -_2pi) - continue; - - ASSERT_MPFR_MATCH(mpfr::Operation::Cos, x, LIBC_NAMESPACE::cos(x), 1.0); +using LIBC_NAMESPACE::testing::tlog; + +TEST_F(LlvmLibcCosTest, TrickyInputs) { + constexpr double INPUTS[] = { + 0x1.8000000000009p-23, 0x1.8000000000024p-22, + 0x1.800000000009p-21, 0x1.20000000000f3p-20, + 0x1.800000000024p-20, 0x1.e0000000001c2p-20, + 0x1.940c877fb7dacp-7, -0x1.f42fb19b5b9b2p-6, + -0x1.0285070f9f1bcp-5, 0x1.23f40dccdef72p+0, + 0x1.43cf16358c9d7p+0, 0x1.addf3b9722265p+0, + 0x1.ae78d360afa15p+0, 0x1.e31b55306f22cp+2, + 0x1.e639103a05997p+2, -0x1.f7898d5a756ddp+2, + 0x1.1685973506319p+3, 0x1.5f09cad750ab1p+3, + -0x1.aaf85537ea4c7p+3, 0x1.4f2b874135d27p+4, + 0x1.13114266f9764p+4, 0x1.a211877de55dbp+4, + -0x1.a5eece87e8606p+4, 0x1.a65d441ea6dcep+4, + 0x1.1ffb509f3db15p+5, 0x1.2345d1e090529p+5, + 0x1.c96e28eb679f8p+5, 0x1.be886d9c2324dp+6, + -0x1.ab514bfc61c76p+7, -0x1.14823229799c2p+7, + 0x1.48ff1782ca91dp+8, 0x1.dcbfda0c7559ep+8, + 0x1.dcbfda0c7559ep+8, 0x1.2e566149bf5fdp+9, + 0x1.cb996c60f437ep+9, 0x1.ae945054939c2p+10, + -0x1.119471e9216cdp+10, 0x1.ae945054939c2p+10, + 0x1.fffffffffdb6p+24, 0x1.fd4da4ef37075p+29, + 0x1.55202aefde314p+31, 0x1.b951f1572eba5p+31, + 0x1.7776c2343ba4ep+101, 0x1.85fc0f04c0128p+101, + 0x1.678309fa50d58p+110, 0x1.fffffffffef4ep+199, + 0x1.3eec5912ea7cdp+331, -0x1.3eec5912ea7cdp+331, + -0x1.6deb37da81129p+205, 0x1.08087e9aad90bp+887, + -0x1.08087e9aad90bp+887, -0x1.8bb5847d49973p+845, + 0x1.6ac5b262ca1ffp+849, 0x1.f08b14e1c4d0fp+890, + 0x1.2b5fe88a9d8d5p+903, 0x1.f6d7518808571p+1023, + -0x1.a880417b7b119p+1023, 0x1.00a33764a0a83p-7, + 0x1.fe81868fc47fep+1, 0x1.0da8cc189b47dp-10, + 0x1.da1838053b866p+5, + + }; + constexpr int N = sizeof(INPUTS) / sizeof(INPUTS[0]); + + for (int i = 0; i < N; ++i) { + double x = INPUTS[i]; + ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Cos, x, + LIBC_NAMESPACE::cos(x), 0.5); } } + +TEST_F(LlvmLibcCosTest, InDoubleRange) { + constexpr uint64_t COUNT = 1'234'51; + uint64_t START = LIBC_NAMESPACE::fputil::FPBits(0x1.0p-50).uintval(); + uint64_t STOP = LIBC_NAMESPACE::fputil::FPBits(0x1.0p200).uintval(); + uint64_t STEP = (STOP - START) / COUNT; + + auto test = [&](mpfr::RoundingMode rounding_mode) { + mpfr::ForceRoundingMode __r(rounding_mode); + if (!__r.success) + return; + + uint64_t fails = 0; + uint64_t tested = 0; + uint64_t total = 0; + double worst_input, worst_output = 0.0; + double ulp = 0.5; + + for (uint64_t i = 0, v = START; i <= COUNT; ++i, v += STEP) { + double x = FPBits(v).get_val(); + if (isnan(x) || isinf(x)) + continue; + + double result = LIBC_NAMESPACE::cos(x); + ++total; + if (isnan(result) || isinf(result)) + continue; + + ++tested; + + if (!TEST_MPFR_MATCH_ROUNDING_SILENTLY(mpfr::Operation::Cos, x, result, + 0.5, rounding_mode)) { + ++fails; + while (!TEST_MPFR_MATCH_ROUNDING_SILENTLY(mpfr::Operation::Cos, x, + result, ulp, rounding_mode)) { + worst_input = x; + worst_output = result; + + if (ulp > 1000.0) + break; + + ulp *= 2.0; + } + } + } + if (fails) { + tlog << " Cos failed: " << fails << "/" << tested << "/" << total + << " tests.\n"; + tlog << " Max ULPs is at most: " << static_cast(ulp) << ".\n"; + EXPECT_MPFR_MATCH(mpfr::Operation::Cos, worst_input, worst_output, 0.5, + rounding_mode); + } + }; + + tlog << " Test Rounding To Nearest...\n"; + test(mpfr::RoundingMode::Nearest); + + tlog << " Test Rounding Downward...\n"; + test(mpfr::RoundingMode::Downward); + + tlog << " Test Rounding Upward...\n"; + test(mpfr::RoundingMode::Upward); + + tlog << " Test Rounding Toward Zero...\n"; + test(mpfr::RoundingMode::TowardZero); +} diff --git a/libc/test/src/math/exhaustive/CMakeLists.txt b/libc/test/src/math/exhaustive/CMakeLists.txt index 34df8720ed4dbe..fb3596c3378ff4 100644 --- a/libc/test/src/math/exhaustive/CMakeLists.txt +++ b/libc/test/src/math/exhaustive/CMakeLists.txt @@ -4,6 +4,10 @@ add_header_library( exhaustive_test HDRS exhaustive_test.h + DEPENDS + libc.src.__support.CPP.type_traits + libc.src.__support.FPUtil.fp_bits + libc.src.__support.macros.properties.types ) add_fp_unittest( @@ -277,6 +281,21 @@ add_fp_unittest( libc.src.__support.FPUtil.generic.fmod ) +add_fp_unittest( + fmodf16_test + NO_RUN_POSTBUILD + NEED_MPFR + SUITE + libc_math_exhaustive_tests + SRCS + fmodf16_test.cpp + DEPENDS + .exhaustive_test + libc.src.math.fmodf16 + LINK_LIBRARIES + -lpthread +) + add_fp_unittest( coshf_test NO_RUN_POSTBUILD diff --git a/libc/test/src/math/exhaustive/exhaustive_test.h b/libc/test/src/math/exhaustive/exhaustive_test.h index 13e272783250b8..6f0c78ebefa470 100644 --- a/libc/test/src/math/exhaustive/exhaustive_test.h +++ b/libc/test/src/math/exhaustive/exhaustive_test.h @@ -8,6 +8,7 @@ #include "src/__support/CPP/type_traits.h" #include "src/__support/FPUtil/FPBits.h" +#include "src/__support/macros/properties/types.h" #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" #include "utils/MPFRWrapper/MPFRUtils.h" @@ -68,9 +69,46 @@ struct UnaryOpChecker : public virtual LIBC_NAMESPACE::testing::Test { } }; +template +using BinaryOp = OutType(InType, InType); + +template Func> +struct BinaryOpChecker : public virtual LIBC_NAMESPACE::testing::Test { + using FloatType = InType; + using FPBits = LIBC_NAMESPACE::fputil::FPBits; + using StorageType = typename FPBits::StorageType; + + // Check in a range, return the number of failures. + uint64_t check(StorageType x_start, StorageType x_stop, StorageType y_start, + StorageType y_stop, mpfr::RoundingMode rounding) { + mpfr::ForceRoundingMode r(rounding); + if (!r.success) + return x_stop > x_start || y_stop > y_start; + StorageType xbits = x_start; + uint64_t failed = 0; + do { + FloatType x = FPBits(xbits).get_val(); + StorageType ybits = y_start; + do { + FloatType y = FPBits(ybits).get_val(); + mpfr::BinaryInput input{x, y}; + bool correct = TEST_MPFR_MATCH_ROUNDING_SILENTLY(Op, input, Func(x, y), + 0.5, rounding); + failed += (!correct); + // Uncomment to print out failed values. + // if (!correct) { + // EXPECT_MPFR_MATCH_ROUNDING(Op, input, Func(x, y), 0.5, rounding); + // } + } while (ybits++ < y_stop); + } while (xbits++ < x_stop); + return failed; + } +}; + // Checker class needs inherit from LIBC_NAMESPACE::testing::Test and provide // StorageType and check method. -template +template struct LlvmLibcExhaustiveMathTest : public virtual LIBC_NAMESPACE::testing::Test, public Checker { @@ -78,12 +116,35 @@ struct LlvmLibcExhaustiveMathTest using FPBits = typename Checker::FPBits; using StorageType = typename Checker::StorageType; - static constexpr StorageType INCREMENT = (1 << 20); + void explain_failed_range(std::stringstream &msg, StorageType x_begin, + StorageType x_end) { +#ifdef LIBC_TYPES_HAS_FLOAT16 + using T = LIBC_NAMESPACE::cpp::conditional_t< + LIBC_NAMESPACE::cpp::is_same_v, float, FloatType>; +#else + using T = FloatType; +#endif + + msg << x_begin << " to " << x_end << " [0x" << std::hex << x_begin << ", 0x" + << x_end << "), [" << std::hexfloat + << static_cast(FPBits(x_begin).get_val()) << ", " + << static_cast(FPBits(x_end).get_val()) << ")"; + } + + void explain_failed_range(std::stringstream &msg, StorageType x_begin, + StorageType x_end, StorageType y_begin, + StorageType y_end) { + msg << "x "; + explain_failed_range(msg, x_begin, x_end); + msg << ", y "; + explain_failed_range(msg, y_begin, y_end); + } // Break [start, stop) into `nthreads` subintervals and apply *check to each // subinterval in parallel. - void test_full_range(StorageType start, StorageType stop, - mpfr::RoundingMode rounding) { + template + void test_full_range(mpfr::RoundingMode rounding, StorageType start, + StorageType stop, T... extra_range_bounds) { int n_threads = std::thread::hardware_concurrency(); std::vector thread_list; std::mutex mx_cur_val; @@ -102,8 +163,8 @@ struct LlvmLibcExhaustiveMathTest return; range_begin = current_value; - if (stop >= INCREMENT && stop - INCREMENT >= current_value) { - range_end = current_value + INCREMENT; + if (stop >= Increment && stop - Increment >= current_value) { + range_end = current_value + Increment; } else { range_end = stop; } @@ -120,15 +181,14 @@ struct LlvmLibcExhaustiveMathTest std::cout << msg.str() << std::flush; } - uint64_t failed_in_range = - Checker::check(range_begin, range_end, rounding); + uint64_t failed_in_range = Checker::check( + range_begin, range_end, extra_range_bounds..., rounding); if (failed_in_range > 0) { std::stringstream msg; msg << "Test failed for " << std::dec << failed_in_range - << " inputs in range: " << range_begin << " to " << range_end - << " [0x" << std::hex << range_begin << ", 0x" << range_end - << "), [" << std::hexfloat << FPBits(range_begin).get_val() - << ", " << FPBits(range_end).get_val() << ")\n"; + << " inputs in range: "; + explain_failed_range(msg, start, stop, extra_range_bounds...); + msg << "\n"; std::cerr << msg.str() << std::flush; failed.fetch_add(failed_in_range); @@ -151,19 +211,46 @@ struct LlvmLibcExhaustiveMathTest void test_full_range_all_roundings(StorageType start, StorageType stop) { std::cout << "-- Testing for FE_TONEAREST in range [0x" << std::hex << start << ", 0x" << stop << ") --" << std::dec << std::endl; - test_full_range(start, stop, mpfr::RoundingMode::Nearest); + test_full_range(mpfr::RoundingMode::Nearest, start, stop); std::cout << "-- Testing for FE_UPWARD in range [0x" << std::hex << start << ", 0x" << stop << ") --" << std::dec << std::endl; - test_full_range(start, stop, mpfr::RoundingMode::Upward); + test_full_range(mpfr::RoundingMode::Upward, start, stop); std::cout << "-- Testing for FE_DOWNWARD in range [0x" << std::hex << start << ", 0x" << stop << ") --" << std::dec << std::endl; - test_full_range(start, stop, mpfr::RoundingMode::Downward); + test_full_range(mpfr::RoundingMode::Downward, start, stop); std::cout << "-- Testing for FE_TOWARDZERO in range [0x" << std::hex << start << ", 0x" << stop << ") --" << std::dec << std::endl; - test_full_range(start, stop, mpfr::RoundingMode::TowardZero); + test_full_range(mpfr::RoundingMode::TowardZero, start, stop); + }; + + void test_full_range_all_roundings(StorageType x_start, StorageType x_stop, + StorageType y_start, StorageType y_stop) { + std::cout << "-- Testing for FE_TONEAREST in x range [0x" << std::hex + << x_start << ", 0x" << x_stop << "), y range [0x" << y_start + << ", 0x" << y_stop << ") --" << std::dec << std::endl; + test_full_range(mpfr::RoundingMode::Nearest, x_start, x_stop, y_start, + y_stop); + + std::cout << "-- Testing for FE_UPWARD in x range [0x" << std::hex + << x_start << ", 0x" << x_stop << "), y range [0x" << y_start + << ", 0x" << y_stop << ") --" << std::dec << std::endl; + test_full_range(mpfr::RoundingMode::Upward, x_start, x_stop, y_start, + y_stop); + + std::cout << "-- Testing for FE_DOWNWARD in x range [0x" << std::hex + << x_start << ", 0x" << x_stop << "), y range [0x" << y_start + << ", 0x" << y_stop << ") --" << std::dec << std::endl; + test_full_range(mpfr::RoundingMode::Downward, x_start, x_stop, y_start, + y_stop); + + std::cout << "-- Testing for FE_TOWARDZERO in x range [0x" << std::hex + << x_start << ", 0x" << x_stop << "), y range [0x" << y_start + << ", 0x" << y_stop << ") --" << std::dec << std::endl; + test_full_range(mpfr::RoundingMode::TowardZero, x_start, x_stop, y_start, + y_stop); }; }; @@ -175,3 +262,8 @@ template Func> using LlvmLibcUnaryNarrowingOpExhaustiveMathTest = LlvmLibcExhaustiveMathTest>; + +template Func> +using LlvmLibcBinaryOpExhaustiveMathTest = + LlvmLibcExhaustiveMathTest, + 1 << 2>; diff --git a/libc/test/src/math/exhaustive/fmodf16_test.cpp b/libc/test/src/math/exhaustive/fmodf16_test.cpp new file mode 100644 index 00000000000000..067cec969a4f70 --- /dev/null +++ b/libc/test/src/math/exhaustive/fmodf16_test.cpp @@ -0,0 +1,41 @@ +//===-- Exhaustive test for fmodf16 ---------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "exhaustive_test.h" +#include "src/math/fmodf16.h" +#include "utils/MPFRWrapper/MPFRUtils.h" + +namespace mpfr = LIBC_NAMESPACE::testing::mpfr; + +using LlvmLibcFmodf16ExhaustiveTest = + LlvmLibcBinaryOpExhaustiveMathTest; + +// Range: [0, Inf]; +static constexpr uint16_t POS_START = 0x0000U; +static constexpr uint16_t POS_STOP = 0x7c00U; + +// Range: [-Inf, 0]; +static constexpr uint16_t NEG_START = 0x8000U; +static constexpr uint16_t NEG_STOP = 0xfc00U; + +TEST_F(LlvmLibcFmodf16ExhaustiveTest, PostivePositiveRange) { + test_full_range_all_roundings(POS_START, POS_STOP, POS_START, POS_STOP); +} + +TEST_F(LlvmLibcFmodf16ExhaustiveTest, PostiveNegativeRange) { + test_full_range_all_roundings(POS_START, POS_STOP, NEG_START, NEG_STOP); +} + +TEST_F(LlvmLibcFmodf16ExhaustiveTest, NegativePositiveRange) { + test_full_range_all_roundings(NEG_START, NEG_STOP, POS_START, POS_STOP); +} + +TEST_F(LlvmLibcFmodf16ExhaustiveTest, NegativeNegativeRange) { + test_full_range_all_roundings(NEG_START, NEG_STOP, POS_START, POS_STOP); +} diff --git a/libc/config/linux/signal.h.in b/libc/test/src/math/f16div_test.cpp similarity index 63% rename from libc/config/linux/signal.h.in rename to libc/test/src/math/f16div_test.cpp index fd0b41d3de5b2b..0bfa69f9b8028a 100644 --- a/libc/config/linux/signal.h.in +++ b/libc/test/src/math/f16div_test.cpp @@ -1,4 +1,4 @@ -//===-- Linux specific signal.h definitions -------------------------------===// +//===-- Unittests for f16div ----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,10 +6,8 @@ // //===----------------------------------------------------------------------===// -%%begin() +#include "DivTest.h" -#include +#include "src/math/f16div.h" -#ifndef __LLVM_LIBC_INTERNAL_SIGACTION -#define sigaction __sigaction -#endif +LIST_DIV_TESTS(float16, double, LIBC_NAMESPACE::f16div) diff --git a/libcxx/test/libcxx/containers/sequences/vector/const_T.compile.pass.cpp b/libc/test/src/math/f16divf_test.cpp similarity index 58% rename from libcxx/test/libcxx/containers/sequences/vector/const_T.compile.pass.cpp rename to libc/test/src/math/f16divf_test.cpp index 62fff96ac5abe3..85be1ebcd55c9e 100644 --- a/libcxx/test/libcxx/containers/sequences/vector/const_T.compile.pass.cpp +++ b/libc/test/src/math/f16divf_test.cpp @@ -1,4 +1,4 @@ -//===----------------------------------------------------------------------===// +//===-- Unittests for f16divf ---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,13 +6,8 @@ // //===----------------------------------------------------------------------===// -// Make sure that `vector` works +#include "DivTest.h" -#include +#include "src/math/f16divf.h" -void test() { - std::vector v; - v.emplace_back(1); - v.push_back(1); - v.resize(3); -} +LIST_DIV_TESTS(float16, float, LIBC_NAMESPACE::f16divf) diff --git a/libc/test/src/math/f16divl_test.cpp b/libc/test/src/math/f16divl_test.cpp new file mode 100644 index 00000000000000..bad3e70a477b4f --- /dev/null +++ b/libc/test/src/math/f16divl_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16divl ---------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "DivTest.h" + +#include "src/math/f16divl.h" + +LIST_DIV_TESTS(float16, long double, LIBC_NAMESPACE::f16divl) diff --git a/libc/test/src/math/f16fma_test.cpp b/libc/test/src/math/f16fma_test.cpp new file mode 100644 index 00000000000000..2e46b5bdd46829 --- /dev/null +++ b/libc/test/src/math/f16fma_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16fma ----------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "FmaTest.h" + +#include "src/math/f16fma.h" + +LIST_NARROWING_FMA_TESTS(float16, double, LIBC_NAMESPACE::f16fma) diff --git a/libc/test/src/math/f16fmaf_test.cpp b/libc/test/src/math/f16fmaf_test.cpp index e4ca88b8810e16..5e3aec768c1910 100644 --- a/libc/test/src/math/f16fmaf_test.cpp +++ b/libc/test/src/math/f16fmaf_test.cpp @@ -10,12 +10,4 @@ #include "src/math/f16fmaf.h" -using LlvmLibcF16fmafTest = FmaTestTemplate; - -TEST_F(LlvmLibcF16fmafTest, SubnormalRange) { - test_subnormal_range(&LIBC_NAMESPACE::f16fmaf); -} - -TEST_F(LlvmLibcF16fmafTest, NormalRange) { - test_normal_range(&LIBC_NAMESPACE::f16fmaf); -} +LIST_NARROWING_FMA_TESTS(float16, float, LIBC_NAMESPACE::f16fmaf) diff --git a/libc/test/src/math/f16fmal_test.cpp b/libc/test/src/math/f16fmal_test.cpp new file mode 100644 index 00000000000000..5394268a9cd8f3 --- /dev/null +++ b/libc/test/src/math/f16fmal_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16fmal ---------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "FmaTest.h" + +#include "src/math/f16fmal.h" + +LIST_NARROWING_FMA_TESTS(float16, long double, LIBC_NAMESPACE::f16fmal) diff --git a/libc/test/src/math/f16sqrt_test.cpp b/libc/test/src/math/f16sqrt_test.cpp new file mode 100644 index 00000000000000..759b388ad3b3d9 --- /dev/null +++ b/libc/test/src/math/f16sqrt_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16sqrt ---------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "SqrtTest.h" + +#include "src/math/f16sqrt.h" + +LIST_NARROWING_SQRT_TESTS(float16, double, LIBC_NAMESPACE::f16sqrt) diff --git a/libc/test/src/math/f16sqrtl_test.cpp b/libc/test/src/math/f16sqrtl_test.cpp new file mode 100644 index 00000000000000..4e069bc8dbffd1 --- /dev/null +++ b/libc/test/src/math/f16sqrtl_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16sqrtl --------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "SqrtTest.h" + +#include "src/math/f16sqrtl.h" + +LIST_NARROWING_SQRT_TESTS(float16, long double, LIBC_NAMESPACE::f16sqrtl) diff --git a/libc/test/src/math/fmaf_test.cpp b/libc/test/src/math/fmaf_test.cpp index 0e498d46ecfb0d..09e9c504b942a0 100644 --- a/libc/test/src/math/fmaf_test.cpp +++ b/libc/test/src/math/fmaf_test.cpp @@ -10,12 +10,4 @@ #include "src/math/fmaf.h" -using LlvmLibcFmafTest = FmaTestTemplate; - -TEST_F(LlvmLibcFmafTest, SubnormalRange) { - test_subnormal_range(&LIBC_NAMESPACE::fmaf); -} - -TEST_F(LlvmLibcFmafTest, NormalRange) { - test_normal_range(&LIBC_NAMESPACE::fmaf); -} +LIST_FMA_TESTS(float, LIBC_NAMESPACE::fmaf) diff --git a/libc/config/linux/platform_defs.h.inc b/libc/test/src/math/fmul_test.cpp similarity index 51% rename from libc/config/linux/platform_defs.h.inc rename to libc/test/src/math/fmul_test.cpp index 495d07c80cf294..16eaa1a818daf7 100644 --- a/libc/config/linux/platform_defs.h.inc +++ b/libc/test/src/math/fmul_test.cpp @@ -1,13 +1,13 @@ -//===----- Definition of platform specific macros for ELF paltforms -------===// +//===-- Unittests for fmul-------------------------------------------------===// // // 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 // -//===----------------------------------------------------------------------===// +//===---------------------------------------------------------------------===// -%%begin() +#include "FMulTest.h" -#define ENTRYPOINT_SECTION_ATTRIBUTE(name) \ - __attribute__((section(".llvm.libc.entrypoint."#name))) -#define LLVM_LIBC_ENTRYPOINT(name) ENTRYPOINT_SECTION_ATTRIBUTE(name) name +#include "src/math/fmul.h" + +LIST_FMUL_MPFR_TESTS(float, double, LIBC_NAMESPACE::fmul) diff --git a/libc/test/src/math/sin_test.cpp b/libc/test/src/math/sin_test.cpp index 0171b79810d4e9..89534ae82b56e3 100644 --- a/libc/test/src/math/sin_test.cpp +++ b/libc/test/src/math/sin_test.cpp @@ -12,22 +12,103 @@ #include "test/UnitTest/Test.h" #include "utils/MPFRWrapper/MPFRUtils.h" -#include "hdr/math_macros.h" - using LlvmLibcSinTest = LIBC_NAMESPACE::testing::FPTest; namespace mpfr = LIBC_NAMESPACE::testing::mpfr; -TEST_F(LlvmLibcSinTest, Range) { - static constexpr double _2pi = 6.283185307179586; - constexpr StorageType COUNT = 100'000; - constexpr StorageType STEP = STORAGE_MAX / COUNT; - for (StorageType i = 0, v = 0; i <= COUNT; ++i, v += STEP) { - double x = FPBits(v).get_val(); - // TODO: Expand the range of testing after range reduction is implemented. - if (isnan(x) || isinf(x) || x > _2pi || x < -_2pi) - continue; - - ASSERT_MPFR_MATCH(mpfr::Operation::Sin, x, LIBC_NAMESPACE::sin(x), 1.0); +using LIBC_NAMESPACE::testing::tlog; + +TEST_F(LlvmLibcSinTest, TrickyInputs) { + constexpr double INPUTS[] = { + 0x1.940c877fb7dacp-7, 0x1.fffffffffdb6p24, 0x1.fd4da4ef37075p29, + 0x1.b951f1572eba5p+31, 0x1.55202aefde314p+31, 0x1.85fc0f04c0128p101, + 0x1.7776c2343ba4ep101, 0x1.678309fa50d58p110, 0x1.fffffffffef4ep199, + -0x1.ab514bfc61c76p+7, -0x1.f7898d5a756ddp+2, -0x1.f42fb19b5b9b2p-6, + 0x1.5f09cad750ab1p+3, -0x1.14823229799c2p+7, -0x1.0285070f9f1bcp-5, + 0x1.23f40dccdef72p+0, 0x1.43cf16358c9d7p+0, 0x1.addf3b9722265p+0, + 0x1.48ff1782ca91dp+8, 0x1.a211877de55dbp+4, 0x1.dcbfda0c7559ep+8, + 0x1.1ffb509f3db15p+5, 0x1.2345d1e090529p+5, 0x1.ae945054939c2p+10, + 0x1.2e566149bf5fdp+9, 0x1.be886d9c2324dp+6, -0x1.119471e9216cdp+10, + -0x1.aaf85537ea4c7p+3, 0x1.cb996c60f437ep+9, 0x1.c96e28eb679f8p+5, + -0x1.a5eece87e8606p+4, 0x1.e31b55306f22cp+2, 0x1.ae78d360afa15p+0, + 0x1.1685973506319p+3, 0x1.4f2b874135d27p+4, 0x1.ae945054939c2p+10, + 0x1.3eec5912ea7cdp+331, 0x1.dcbfda0c7559ep+8, 0x1.a65d441ea6dcep+4, + 0x1.e639103a05997p+2, 0x1.13114266f9764p+4, -0x1.3eec5912ea7cdp+331, + 0x1.08087e9aad90bp+887, 0x1.2b5fe88a9d8d5p+903, -0x1.a880417b7b119p+1023, + -0x1.6deb37da81129p+205, 0x1.08087e9aad90bp+887, 0x1.f6d7518808571p+1023, + -0x1.8bb5847d49973p+845, 0x1.f08b14e1c4d0fp+890, 0x1.6ac5b262ca1ffp+849, + 0x1.e0000000001c2p-20, + }; + constexpr int N = sizeof(INPUTS) / sizeof(INPUTS[0]); + + for (int i = 0; i < N; ++i) { + double x = INPUTS[i]; + ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Sin, x, + LIBC_NAMESPACE::sin(x), 0.5); } } + +TEST_F(LlvmLibcSinTest, InDoubleRange) { + constexpr uint64_t COUNT = 1'234'51; + uint64_t START = LIBC_NAMESPACE::fputil::FPBits(0x1.0p-50).uintval(); + uint64_t STOP = LIBC_NAMESPACE::fputil::FPBits(0x1.0p200).uintval(); + uint64_t STEP = (STOP - START) / COUNT; + + auto test = [&](mpfr::RoundingMode rounding_mode) { + mpfr::ForceRoundingMode __r(rounding_mode); + if (!__r.success) + return; + + uint64_t fails = 0; + uint64_t count = 0; + uint64_t cc = 0; + double mx, mr = 0.0; + double tol = 0.5; + + for (uint64_t i = 0, v = START; i <= COUNT; ++i, v += STEP) { + double x = FPBits(v).get_val(); + if (isnan(x) || isinf(x)) + continue; + LIBC_NAMESPACE::libc_errno = 0; + double result = LIBC_NAMESPACE::sin(x); + ++cc; + if (isnan(result) || isinf(result)) + continue; + + ++count; + + if (!TEST_MPFR_MATCH_ROUNDING_SILENTLY(mpfr::Operation::Sin, x, result, + 0.5, rounding_mode)) { + ++fails; + while (!TEST_MPFR_MATCH_ROUNDING_SILENTLY(mpfr::Operation::Sin, x, + result, tol, rounding_mode)) { + mx = x; + mr = result; + + if (tol > 1000.0) + break; + + tol *= 2.0; + } + } + } + if (fails) { + tlog << " Sin failed: " << fails << "/" << count << "/" << cc + << " tests.\n"; + tlog << " Max ULPs is at most: " << static_cast(tol) << ".\n"; + EXPECT_MPFR_MATCH(mpfr::Operation::Sin, mx, mr, 0.5, rounding_mode); + } + }; + + tlog << " Test Rounding To Nearest...\n"; + test(mpfr::RoundingMode::Nearest); + + tlog << " Test Rounding Downward...\n"; + test(mpfr::RoundingMode::Downward); + + tlog << " Test Rounding Upward...\n"; + test(mpfr::RoundingMode::Upward); + + tlog << " Test Rounding Toward Zero...\n"; + test(mpfr::RoundingMode::TowardZero); +} diff --git a/libc/test/src/math/sincos_test.cpp b/libc/test/src/math/sincos_test.cpp new file mode 100644 index 00000000000000..7e06456f2e05c5 --- /dev/null +++ b/libc/test/src/math/sincos_test.cpp @@ -0,0 +1,118 @@ +//===-- Unittests for sincos ----------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/__support/FPUtil/FPBits.h" +#include "src/math/sincos.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" +#include "utils/MPFRWrapper/MPFRUtils.h" + +using LlvmLibcSincosTest = LIBC_NAMESPACE::testing::FPTest; + +namespace mpfr = LIBC_NAMESPACE::testing::mpfr; + +using LIBC_NAMESPACE::testing::tlog; + +#define ASSERT_SINCOS_MATCH_ALL_ROUNDING(input) \ + do { \ + double sin_x, cos_x; \ + namespace mpfr = LIBC_NAMESPACE::testing::mpfr; \ + \ + mpfr::ForceRoundingMode __r1(mpfr::RoundingMode::Nearest); \ + if (__r1.success) { \ + LIBC_NAMESPACE::sincos(input, &sin_x, &cos_x); \ + ASSERT_MPFR_MATCH(mpfr::Operation::Sin, input, sin_x, 0.5, \ + mpfr::RoundingMode::Nearest); \ + ASSERT_MPFR_MATCH(mpfr::Operation::Cos, input, cos_x, 0.5, \ + mpfr::RoundingMode::Nearest); \ + } \ + \ + mpfr::ForceRoundingMode __r2(mpfr::RoundingMode::Upward); \ + if (__r2.success) { \ + LIBC_NAMESPACE::sincos(input, &sin_x, &cos_x); \ + ASSERT_MPFR_MATCH(mpfr::Operation::Sin, input, sin_x, 0.5, \ + mpfr::RoundingMode::Upward); \ + ASSERT_MPFR_MATCH(mpfr::Operation::Cos, input, cos_x, 0.5, \ + mpfr::RoundingMode::Upward); \ + } \ + \ + mpfr::ForceRoundingMode __r3(mpfr::RoundingMode::Downward); \ + if (__r3.success) { \ + LIBC_NAMESPACE::sincos(input, &sin_x, &cos_x); \ + ASSERT_MPFR_MATCH(mpfr::Operation::Sin, input, sin_x, 0.5, \ + mpfr::RoundingMode::Downward); \ + ASSERT_MPFR_MATCH(mpfr::Operation::Cos, input, cos_x, 0.5, \ + mpfr::RoundingMode::Downward); \ + } \ + \ + mpfr::ForceRoundingMode __r4(mpfr::RoundingMode::TowardZero); \ + if (__r4.success) { \ + LIBC_NAMESPACE::sincos(input, &sin_x, &cos_x); \ + ASSERT_MPFR_MATCH(mpfr::Operation::Sin, input, sin_x, 0.5, \ + mpfr::RoundingMode::TowardZero); \ + ASSERT_MPFR_MATCH(mpfr::Operation::Cos, input, cos_x, 0.5, \ + mpfr::RoundingMode::TowardZero); \ + } \ + } while (0) + +TEST_F(LlvmLibcSincosTest, TrickyInputs) { + constexpr double INPUTS[] = { + 0x1.8000000000009p-23, 0x1.8000000000024p-22, + 0x1.800000000009p-21, 0x1.20000000000f3p-20, + 0x1.800000000024p-20, 0x1.e0000000001c2p-20, + 0x1.940c877fb7dacp-7, -0x1.f42fb19b5b9b2p-6, + -0x1.0285070f9f1bcp-5, 0x1.23f40dccdef72p+0, + 0x1.43cf16358c9d7p+0, 0x1.addf3b9722265p+0, + 0x1.ae78d360afa15p+0, 0x1.e31b55306f22cp+2, + 0x1.e639103a05997p+2, -0x1.f7898d5a756ddp+2, + 0x1.1685973506319p+3, 0x1.5f09cad750ab1p+3, + -0x1.aaf85537ea4c7p+3, 0x1.4f2b874135d27p+4, + 0x1.13114266f9764p+4, 0x1.a211877de55dbp+4, + -0x1.a5eece87e8606p+4, 0x1.a65d441ea6dcep+4, + 0x1.1ffb509f3db15p+5, 0x1.2345d1e090529p+5, + 0x1.c96e28eb679f8p+5, 0x1.be886d9c2324dp+6, + -0x1.ab514bfc61c76p+7, -0x1.14823229799c2p+7, + 0x1.48ff1782ca91dp+8, 0x1.dcbfda0c7559ep+8, + 0x1.dcbfda0c7559ep+8, 0x1.2e566149bf5fdp+9, + 0x1.cb996c60f437ep+9, 0x1.ae945054939c2p+10, + -0x1.119471e9216cdp+10, 0x1.ae945054939c2p+10, + 0x1.fffffffffdb6p+24, 0x1.fd4da4ef37075p+29, + 0x1.55202aefde314p+31, 0x1.b951f1572eba5p+31, + 0x1.7776c2343ba4ep+101, 0x1.85fc0f04c0128p+101, + 0x1.678309fa50d58p+110, 0x1.fffffffffef4ep+199, + 0x1.3eec5912ea7cdp+331, -0x1.3eec5912ea7cdp+331, + -0x1.6deb37da81129p+205, 0x1.08087e9aad90bp+887, + -0x1.08087e9aad90bp+887, -0x1.8bb5847d49973p+845, + 0x1.6ac5b262ca1ffp+849, 0x1.f08b14e1c4d0fp+890, + 0x1.2b5fe88a9d8d5p+903, 0x1.f6d7518808571p+1023, + -0x1.a880417b7b119p+1023, 0x1.00a33764a0a83p-7, + 0x1.fe81868fc47fep+1, 0x1.0da8cc189b47dp-10, + 0x1.da1838053b866p+5, + + }; + constexpr int N = sizeof(INPUTS) / sizeof(INPUTS[0]); + + for (int i = 0; i < N; ++i) { + ASSERT_SINCOS_MATCH_ALL_ROUNDING(INPUTS[i]); + } +} + +TEST_F(LlvmLibcSincosTest, InDoubleRange) { + constexpr uint64_t COUNT = 123'41; + uint64_t START = LIBC_NAMESPACE::fputil::FPBits(0x1.0p-50).uintval(); + uint64_t STOP = LIBC_NAMESPACE::fputil::FPBits(0x1.0p200).uintval(); + uint64_t STEP = (STOP - START) / COUNT; + + for (uint64_t i = 0, v = START; i <= COUNT; ++i, v += STEP) { + double x = FPBits(v).get_val(); + if (isnan(x) || isinf(x)) + continue; + + ASSERT_SINCOS_MATCH_ALL_ROUNDING(x); + } +} diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt index 8cae52fb0cebe5..a1b4a03eb2e854 100644 --- a/libc/test/src/math/smoke/CMakeLists.txt +++ b/libc/test/src/math/smoke/CMakeLists.txt @@ -3630,6 +3630,74 @@ add_fp_unittest( libc.src.math.setpayloadsigf16 ) +add_fp_unittest( + f16div_test + SUITE + libc-math-smoke-tests + SRCS + f16div_test.cpp + HDRS + DivTest.h + DEPENDS + libc.hdr.fenv_macros + libc.src.__support.FPUtil.basic_operations + libc.src.math.f16div +) + +add_fp_unittest( + f16divf_test + SUITE + libc-math-smoke-tests + SRCS + f16divf_test.cpp + HDRS + DivTest.h + DEPENDS + libc.hdr.fenv_macros + libc.src.__support.FPUtil.basic_operations + libc.src.math.f16divf +) + +add_fp_unittest( + f16divl_test + SUITE + libc-math-smoke-tests + SRCS + f16divl_test.cpp + HDRS + DivTest.h + DEPENDS + libc.hdr.fenv_macros + libc.src.__support.FPUtil.basic_operations + libc.src.math.f16divl +) + +add_fp_unittest( + f16divf128_test + SUITE + libc-math-smoke-tests + SRCS + f16divf128_test.cpp + HDRS + DivTest.h + DEPENDS + libc.hdr.fenv_macros + libc.src.__support.FPUtil.basic_operations + libc.src.math.f16divf128 +) + +add_fp_unittest( + f16fma_test + SUITE + libc-math-smoke-tests + SRCS + f16fma_test.cpp + HDRS + FmaTest.h + DEPENDS + libc.src.math.f16fma +) + add_fp_unittest( f16fmaf_test SUITE @@ -3642,6 +3710,42 @@ add_fp_unittest( libc.src.math.f16fmaf ) +add_fp_unittest( + f16fmal_test + SUITE + libc-math-smoke-tests + SRCS + f16fmal_test.cpp + HDRS + FmaTest.h + DEPENDS + libc.src.math.f16fmal +) + +add_fp_unittest( + f16fmaf128_test + SUITE + libc-math-smoke-tests + SRCS + f16fmaf128_test.cpp + HDRS + FmaTest.h + DEPENDS + libc.src.math.f16fmaf128 +) + +add_fp_unittest( + f16sqrt_test + SUITE + libc-math-smoke-tests + SRCS + f16sqrt_test.cpp + HDRS + SqrtTest.h + DEPENDS + libc.src.math.f16sqrt +) + add_fp_unittest( f16sqrtf_test SUITE @@ -3653,3 +3757,57 @@ add_fp_unittest( DEPENDS libc.src.math.f16sqrtf ) + +add_fp_unittest( + f16sqrtl_test + SUITE + libc-math-smoke-tests + SRCS + f16sqrtl_test.cpp + HDRS + SqrtTest.h + DEPENDS + libc.src.math.f16sqrtl +) + +add_fp_unittest( + f16sqrtf128_test + SUITE + libc-math-smoke-tests + SRCS + f16sqrtf128_test.cpp + HDRS + SqrtTest.h + DEPENDS + libc.src.math.f16sqrtf128 +) + +add_fp_unittest( + sin_test + SUITE + libc-math-smoke-tests + SRCS + sin_test.cpp + DEPENDS + libc.src.math.sin +) + +add_fp_unittest( + cos_test + SUITE + libc-math-smoke-tests + SRCS + cos_test.cpp + DEPENDS + libc.src.math.cos +) + +add_fp_unittest( + sincos_test + SUITE + libc-math-smoke-tests + SRCS + sincos_test.cpp + DEPENDS + libc.src.math.sincos +) diff --git a/libc/test/src/math/smoke/DivTest.h b/libc/test/src/math/smoke/DivTest.h new file mode 100644 index 00000000000000..71cfb326b97cc2 --- /dev/null +++ b/libc/test/src/math/smoke/DivTest.h @@ -0,0 +1,171 @@ +//===-- Utility class to test different flavors of float div --------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_TEST_SRC_MATH_SMOKE_DIVTEST_H +#define LLVM_LIBC_TEST_SRC_MATH_SMOKE_DIVTEST_H + +#include "hdr/fenv_macros.h" +#include "src/__support/FPUtil/BasicOperations.h" +#include "test/UnitTest/FEnvSafeTest.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/RoundingModeUtils.h" +#include "test/UnitTest/Test.h" + +template +class DivTest : public LIBC_NAMESPACE::testing::FEnvSafeTest { + + DECLARE_SPECIAL_CONSTANTS(OutType) + + struct InConstants { + DECLARE_SPECIAL_CONSTANTS(InType) + }; + + using InFPBits = typename InConstants::FPBits; + using InStorageType = typename InConstants::StorageType; + +public: + using DivFunc = OutType (*)(InType, InType); + + void test_special_numbers(DivFunc func) { + EXPECT_FP_IS_NAN(func(aNaN, aNaN)); + EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(sNaN, sNaN), FE_INVALID); + + InType qnan_42 = InFPBits::quiet_nan(Sign::POS, 0x42).get_val(); + EXPECT_FP_EQ(InType(0x42.0p+0), + LIBC_NAMESPACE::fputil::getpayload(func(qnan_42, zero))); + EXPECT_FP_EQ(InType(0x42.0p+0), + LIBC_NAMESPACE::fputil::getpayload(func(zero, qnan_42))); + + if constexpr (sizeof(OutType) < sizeof(InType)) { + InStorageType max_payload = InFPBits::FRACTION_MASK >> 1; + InType qnan_max = InFPBits::quiet_nan(Sign::POS, max_payload).get_val(); + EXPECT_FP_EQ(zero, + LIBC_NAMESPACE::fputil::getpayload(func(qnan_max, zero))); + EXPECT_FP_EQ(zero, + LIBC_NAMESPACE::fputil::getpayload(func(zero, qnan_max))); + EXPECT_FP_EQ(InType(0x42.0p+0), + LIBC_NAMESPACE::fputil::getpayload(func(qnan_max, qnan_42))); + EXPECT_FP_EQ(InType(0x42.0p+0), + LIBC_NAMESPACE::fputil::getpayload(func(qnan_42, qnan_max))); + } + + EXPECT_FP_EQ(inf, func(inf, zero)); + EXPECT_FP_EQ(neg_inf, func(neg_inf, zero)); + EXPECT_FP_EQ(neg_inf, func(inf, neg_zero)); + EXPECT_FP_EQ(inf, func(neg_inf, neg_zero)); + } + + void test_division_by_zero(DivFunc func) { + EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(InType(1.0), zero), FE_DIVBYZERO); + EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, func(InType(-1.0), zero), + FE_DIVBYZERO); + EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, func(InType(1.0), neg_zero), + FE_DIVBYZERO); + EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(InType(1.0), zero), FE_DIVBYZERO); + } + + void test_invalid_operations(DivFunc func) { + EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(zero, zero), FE_INVALID); + EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(neg_zero, zero), FE_INVALID); + EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(zero, neg_zero), FE_INVALID); + EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(neg_zero, neg_zero), FE_INVALID); + + EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(inf, inf), FE_INVALID); + EXPECT_MATH_ERRNO(EDOM); + EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(neg_inf, inf), FE_INVALID); + EXPECT_MATH_ERRNO(EDOM); + EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(inf, neg_inf), FE_INVALID); + EXPECT_MATH_ERRNO(EDOM); + EXPECT_FP_IS_NAN_WITH_EXCEPTION(func(neg_inf, neg_inf), FE_INVALID); + EXPECT_MATH_ERRNO(EDOM); + } + + void test_range_errors(DivFunc func) { + using namespace LIBC_NAMESPACE::fputil::testing; + + if (ForceRoundingMode r(RoundingMode::Nearest); r.success) { + EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(max_normal, min_normal), + FE_OVERFLOW | FE_INEXACT); + EXPECT_MATH_ERRNO(ERANGE); + EXPECT_FP_EQ_WITH_EXCEPTION(-inf, func(neg_max_normal, min_denormal), + FE_OVERFLOW | FE_INEXACT); + EXPECT_MATH_ERRNO(ERANGE); + + EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(min_denormal, max_normal), + FE_UNDERFLOW | FE_INEXACT); + EXPECT_MATH_ERRNO(ERANGE); + EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero, func(neg_min_denormal, max_normal), + FE_UNDERFLOW | FE_INEXACT); + EXPECT_MATH_ERRNO(ERANGE); + } + + if (ForceRoundingMode r(RoundingMode::TowardZero); r.success) { + EXPECT_FP_EQ_WITH_EXCEPTION(max_normal, func(max_normal, min_normal), + FE_OVERFLOW | FE_INEXACT); + EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal, + func(neg_max_normal, min_denormal), + FE_OVERFLOW | FE_INEXACT); + + EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(min_denormal, max_normal), + FE_UNDERFLOW | FE_INEXACT); + EXPECT_MATH_ERRNO(ERANGE); + EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero, func(neg_min_denormal, max_normal), + FE_UNDERFLOW | FE_INEXACT); + EXPECT_MATH_ERRNO(ERANGE); + } + + if (ForceRoundingMode r(RoundingMode::Downward); r.success) { + EXPECT_FP_EQ_WITH_EXCEPTION(max_normal, func(max_normal, min_normal), + FE_OVERFLOW | FE_INEXACT); + EXPECT_FP_EQ_WITH_EXCEPTION(-inf, func(neg_max_normal, min_denormal), + FE_OVERFLOW | FE_INEXACT); + EXPECT_MATH_ERRNO(ERANGE); + + EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(min_denormal, max_normal), + FE_UNDERFLOW | FE_INEXACT); + EXPECT_MATH_ERRNO(ERANGE); + EXPECT_FP_EQ_WITH_EXCEPTION(neg_min_denormal, + func(neg_min_denormal, max_normal), + FE_UNDERFLOW | FE_INEXACT); + EXPECT_MATH_ERRNO(ERANGE); + } + + if (ForceRoundingMode r(RoundingMode::Upward); r.success) { + EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(max_normal, min_normal), + FE_OVERFLOW | FE_INEXACT); + EXPECT_MATH_ERRNO(ERANGE); + EXPECT_FP_EQ_WITH_EXCEPTION(neg_max_normal, + func(neg_max_normal, min_denormal), + FE_OVERFLOW | FE_INEXACT); + + EXPECT_FP_EQ_WITH_EXCEPTION(min_denormal, func(min_denormal, max_normal), + FE_UNDERFLOW | FE_INEXACT); + EXPECT_MATH_ERRNO(ERANGE); + EXPECT_FP_EQ_WITH_EXCEPTION(neg_zero, func(neg_min_denormal, max_normal), + FE_UNDERFLOW | FE_INEXACT); + EXPECT_MATH_ERRNO(ERANGE); + } + } + + void test_inexact_results(DivFunc func) { + func(InType(1.0), InType(3.0)); + EXPECT_FP_EXCEPTION(FE_INEXACT); + } +}; + +#define LIST_DIV_TESTS(OutType, InType, func) \ + using LlvmLibcDivTest = DivTest; \ + TEST_F(LlvmLibcDivTest, SpecialNumbers) { test_special_numbers(&func); } \ + TEST_F(LlvmLibcDivTest, DivisionByZero) { test_division_by_zero(&func); } \ + TEST_F(LlvmLibcDivTest, InvalidOperations) { \ + test_invalid_operations(&func); \ + } \ + TEST_F(LlvmLibcDivTest, RangeErrors) { test_range_errors(&func); } \ + TEST_F(LlvmLibcDivTest, InexactResults) { test_inexact_results(&func); } + +#endif // LLVM_LIBC_TEST_SRC_MATH_SMOKE_DIVTEST_H diff --git a/libc/test/src/math/smoke/cos_test.cpp b/libc/test/src/math/smoke/cos_test.cpp new file mode 100644 index 00000000000000..81c8612dba26e5 --- /dev/null +++ b/libc/test/src/math/smoke/cos_test.cpp @@ -0,0 +1,26 @@ +//===-- Unittests for cos -------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/math/cos.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" + +using LlvmLibcCosTest = LIBC_NAMESPACE::testing::FPTest; + +using LIBC_NAMESPACE::testing::tlog; + +TEST_F(LlvmLibcCosTest, SpecialNumbers) { + EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::cos(aNaN)); + EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::cos(inf)); + EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::cos(neg_inf)); + EXPECT_FP_EQ_ALL_ROUNDING(1.0, LIBC_NAMESPACE::cos(zero)); + EXPECT_FP_EQ_ALL_ROUNDING(1.0, LIBC_NAMESPACE::cos(neg_zero)); + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::cos(0x1.0p-50)); + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::cos(min_normal)); + EXPECT_FP_EQ(1.0, LIBC_NAMESPACE::cos(min_denormal)); +} diff --git a/libc/test/src/math/smoke/f16div_test.cpp b/libc/test/src/math/smoke/f16div_test.cpp new file mode 100644 index 00000000000000..0bfa69f9b8028a --- /dev/null +++ b/libc/test/src/math/smoke/f16div_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16div ----------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "DivTest.h" + +#include "src/math/f16div.h" + +LIST_DIV_TESTS(float16, double, LIBC_NAMESPACE::f16div) diff --git a/libc/test/src/math/smoke/f16divf128_test.cpp b/libc/test/src/math/smoke/f16divf128_test.cpp new file mode 100644 index 00000000000000..d2ea9718246216 --- /dev/null +++ b/libc/test/src/math/smoke/f16divf128_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16divf128 ------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "DivTest.h" + +#include "src/math/f16divf128.h" + +LIST_DIV_TESTS(float16, float128, LIBC_NAMESPACE::f16divf128) diff --git a/libc/test/src/math/smoke/f16divf_test.cpp b/libc/test/src/math/smoke/f16divf_test.cpp new file mode 100644 index 00000000000000..85be1ebcd55c9e --- /dev/null +++ b/libc/test/src/math/smoke/f16divf_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16divf ---------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "DivTest.h" + +#include "src/math/f16divf.h" + +LIST_DIV_TESTS(float16, float, LIBC_NAMESPACE::f16divf) diff --git a/libc/test/src/math/smoke/f16divl_test.cpp b/libc/test/src/math/smoke/f16divl_test.cpp new file mode 100644 index 00000000000000..bad3e70a477b4f --- /dev/null +++ b/libc/test/src/math/smoke/f16divl_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16divl ---------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "DivTest.h" + +#include "src/math/f16divl.h" + +LIST_DIV_TESTS(float16, long double, LIBC_NAMESPACE::f16divl) diff --git a/libc/test/src/math/smoke/f16fma_test.cpp b/libc/test/src/math/smoke/f16fma_test.cpp new file mode 100644 index 00000000000000..2e46b5bdd46829 --- /dev/null +++ b/libc/test/src/math/smoke/f16fma_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16fma ----------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "FmaTest.h" + +#include "src/math/f16fma.h" + +LIST_NARROWING_FMA_TESTS(float16, double, LIBC_NAMESPACE::f16fma) diff --git a/libc/test/src/math/smoke/f16fmaf128_test.cpp b/libc/test/src/math/smoke/f16fmaf128_test.cpp new file mode 100644 index 00000000000000..ea4003bc5f77ee --- /dev/null +++ b/libc/test/src/math/smoke/f16fmaf128_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16fmaf128 ------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "FmaTest.h" + +#include "src/math/f16fmaf128.h" + +LIST_NARROWING_FMA_TESTS(float16, float128, LIBC_NAMESPACE::f16fmaf128) diff --git a/libc/test/src/math/smoke/f16fmal_test.cpp b/libc/test/src/math/smoke/f16fmal_test.cpp new file mode 100644 index 00000000000000..5394268a9cd8f3 --- /dev/null +++ b/libc/test/src/math/smoke/f16fmal_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16fmal ---------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "FmaTest.h" + +#include "src/math/f16fmal.h" + +LIST_NARROWING_FMA_TESTS(float16, long double, LIBC_NAMESPACE::f16fmal) diff --git a/libc/test/src/math/smoke/f16sqrt_test.cpp b/libc/test/src/math/smoke/f16sqrt_test.cpp new file mode 100644 index 00000000000000..759b388ad3b3d9 --- /dev/null +++ b/libc/test/src/math/smoke/f16sqrt_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16sqrt ---------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "SqrtTest.h" + +#include "src/math/f16sqrt.h" + +LIST_NARROWING_SQRT_TESTS(float16, double, LIBC_NAMESPACE::f16sqrt) diff --git a/libc/test/src/math/smoke/f16sqrtf128_test.cpp b/libc/test/src/math/smoke/f16sqrtf128_test.cpp new file mode 100644 index 00000000000000..31c994860dcd8e --- /dev/null +++ b/libc/test/src/math/smoke/f16sqrtf128_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16sqrtf128 -----------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "SqrtTest.h" + +#include "src/math/f16sqrtf128.h" + +LIST_NARROWING_SQRT_TESTS(float16, float128, LIBC_NAMESPACE::f16sqrtf128) diff --git a/libc/test/src/math/smoke/f16sqrtl_test.cpp b/libc/test/src/math/smoke/f16sqrtl_test.cpp new file mode 100644 index 00000000000000..4e069bc8dbffd1 --- /dev/null +++ b/libc/test/src/math/smoke/f16sqrtl_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for f16sqrtl --------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "SqrtTest.h" + +#include "src/math/f16sqrtl.h" + +LIST_NARROWING_SQRT_TESTS(float16, long double, LIBC_NAMESPACE::f16sqrtl) diff --git a/libc/test/src/math/smoke/sin_test.cpp b/libc/test/src/math/smoke/sin_test.cpp new file mode 100644 index 00000000000000..16ced68709ca75 --- /dev/null +++ b/libc/test/src/math/smoke/sin_test.cpp @@ -0,0 +1,26 @@ +//===-- Unittests for sin -------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/math/sin.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" + +using LlvmLibcSinTest = LIBC_NAMESPACE::testing::FPTest; + +using LIBC_NAMESPACE::testing::tlog; + +TEST_F(LlvmLibcSinTest, SpecialNumbers) { + EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::sin(aNaN)); + EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::sin(inf)); + EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::sin(neg_inf)); + EXPECT_FP_EQ_ALL_ROUNDING(zero, LIBC_NAMESPACE::sin(zero)); + EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, LIBC_NAMESPACE::sin(neg_zero)); + EXPECT_FP_EQ(0x1.0p-50, LIBC_NAMESPACE::sin(0x1.0p-50)); + EXPECT_FP_EQ(min_normal, LIBC_NAMESPACE::sin(min_normal)); + EXPECT_FP_EQ(min_denormal, LIBC_NAMESPACE::sin(min_denormal)); +} diff --git a/libc/test/src/math/smoke/sincos_test.cpp b/libc/test/src/math/smoke/sincos_test.cpp new file mode 100644 index 00000000000000..371c0ad63cbf55 --- /dev/null +++ b/libc/test/src/math/smoke/sincos_test.cpp @@ -0,0 +1,41 @@ +//===-- Unittests for sincos ----------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/math/sincos.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" + +using LlvmLibcSincosTest = LIBC_NAMESPACE::testing::FPTest; + +TEST_F(LlvmLibcSincosTest, SpecialNumbers) { + double sin_x, cos_x; + + LIBC_NAMESPACE::sincos(aNaN, &sin_x, &cos_x); + EXPECT_FP_EQ_ALL_ROUNDING(aNaN, cos_x); + EXPECT_FP_EQ_ALL_ROUNDING(aNaN, sin_x); + + LIBC_NAMESPACE::sincos(zero, &sin_x, &cos_x); + EXPECT_FP_EQ_ALL_ROUNDING(1.0, cos_x); + EXPECT_FP_EQ_ALL_ROUNDING(0.0, sin_x); + + LIBC_NAMESPACE::sincos(neg_zero, &sin_x, &cos_x); + EXPECT_FP_EQ_ALL_ROUNDING(1.0, cos_x); + EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, sin_x); + + LIBC_NAMESPACE::sincos(inf, &sin_x, &cos_x); + EXPECT_FP_EQ_ALL_ROUNDING(aNaN, cos_x); + EXPECT_FP_EQ_ALL_ROUNDING(aNaN, sin_x); + + LIBC_NAMESPACE::sincos(neg_inf, &sin_x, &cos_x); + EXPECT_FP_EQ_ALL_ROUNDING(aNaN, cos_x); + EXPECT_FP_EQ_ALL_ROUNDING(aNaN, sin_x); + + LIBC_NAMESPACE::sincos(0x1.0p-28, &sin_x, &cos_x); + EXPECT_FP_EQ(1.0, cos_x); + EXPECT_FP_EQ(0x1.0p-28, sin_x); +} diff --git a/libc/test/src/signal/CMakeLists.txt b/libc/test/src/signal/CMakeLists.txt index 56ae6fd2cf6170..edbd5c19edab38 100644 --- a/libc/test/src/signal/CMakeLists.txt +++ b/libc/test/src/signal/CMakeLists.txt @@ -32,8 +32,8 @@ add_libc_unittest( SRCS sigaction_test.cpp DEPENDS - libc.include.errno - libc.include.signal + libc.hdr.errno_macros + libc.hdr.signal_macros libc.src.signal.raise libc.src.signal.sigaction libc.test.UnitTest.ErrnoSetterMatcher @@ -119,7 +119,7 @@ add_libc_unittest( SRCS sigaltstack_test.cpp DEPENDS - libc.include.signal + libc.hdr.signal_macros libc.src.errno.errno libc.src.signal.raise libc.src.signal.sigaltstack diff --git a/libc/test/src/signal/sigaction_test.cpp b/libc/test/src/signal/sigaction_test.cpp index 262469c7600e3f..a12d7989586fe6 100644 --- a/libc/test/src/signal/sigaction_test.cpp +++ b/libc/test/src/signal/sigaction_test.cpp @@ -6,15 +6,13 @@ // //===----------------------------------------------------------------------===// +#include "hdr/errno_macros.h" +#include "hdr/signal_macros.h" #include "src/signal/raise.h" #include "src/signal/sigaction.h" - #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -#include -#include - using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails; using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; diff --git a/libc/test/src/signal/sigaltstack_test.cpp b/libc/test/src/signal/sigaltstack_test.cpp index 12bf2bf5e3723a..cc392da8f4731b 100644 --- a/libc/test/src/signal/sigaltstack_test.cpp +++ b/libc/test/src/signal/sigaltstack_test.cpp @@ -6,17 +6,16 @@ // //===----------------------------------------------------------------------===// +#include "hdr/signal_macros.h" #include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/errno/libc_errno.h" #include "src/signal/linux/signal_utils.h" #include "src/signal/raise.h" #include "src/signal/sigaction.h" #include "src/signal/sigaltstack.h" - #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -#include #include #include diff --git a/libc/test/src/stdlib/rand_test.cpp b/libc/test/src/stdlib/rand_test.cpp index 7934dc16aa461a..6f25708e539053 100644 --- a/libc/test/src/stdlib/rand_test.cpp +++ b/libc/test/src/stdlib/rand_test.cpp @@ -23,15 +23,12 @@ TEST(LlvmLibcRandTest, UnsetSeed) { vals[i] = val; } - // FIXME: The GPU implementation cannot initialize the seed correctly. -#ifndef LIBC_TARGET_ARCH_IS_GPU // The C standard specifies that if 'srand' is never called it should behave // as if 'srand' was called with a value of 1. If we seed the value with 1 we // should get the same sequence as the unseeded version. LIBC_NAMESPACE::srand(1); for (size_t i = 0; i < 1000; ++i) ASSERT_EQ(LIBC_NAMESPACE::rand(), vals[i]); -#endif } TEST(LlvmLibcRandTest, SetSeed) { diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp index 2eac4dd8e199de..1ff241ddf20add 100644 --- a/libc/utils/MPFRWrapper/MPFRUtils.cpp +++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp @@ -296,6 +296,12 @@ class MPFRNumber { return result; } + MPFRNumber div(const MPFRNumber &b) const { + MPFRNumber result(*this); + mpfr_div(result.value, value, b.value, mpfr_rounding); + return result; + } + MPFRNumber floor() const { MPFRNumber result(*this); mpfr_floor(result.value, value); @@ -467,6 +473,12 @@ class MPFRNumber { return result; } + MPFRNumber fmul(const MPFRNumber &b) { + MPFRNumber result(*this); + mpfr_mul(result.value, value, b.value, mpfr_rounding); + return result; + } + cpp::string str() const { // 200 bytes should be more than sufficient to hold a 100-digit number // plus additional bytes for the decimal point, '-' sign etc. @@ -708,12 +720,16 @@ binary_operation_one_output(Operation op, InputType x, InputType y, switch (op) { case Operation::Atan2: return inputX.atan2(inputY); + case Operation::Div: + return inputX.div(inputY); case Operation::Fmod: return inputX.fmod(inputY); case Operation::Hypot: return inputX.hypot(inputY); case Operation::Pow: return inputX.pow(inputY); + case Operation::Fmul: + return inputX.fmul(inputY); default: __builtin_unreachable(); } @@ -802,6 +818,12 @@ template void explain_unary_operation_single_output_error(Operation op, float16, template void explain_unary_operation_single_output_error(Operation op, float, float16, double, RoundingMode); +template void explain_unary_operation_single_output_error(Operation op, double, + float16, double, + RoundingMode); +template void explain_unary_operation_single_output_error(Operation op, + long double, float16, + double, RoundingMode); #endif template @@ -885,38 +907,37 @@ template void explain_binary_operation_two_outputs_error( Operation, const BinaryInput &, const BinaryOutput &, double, RoundingMode); -template -void explain_binary_operation_one_output_error(Operation op, - const BinaryInput &input, - T libc_result, - double ulp_tolerance, - RoundingMode rounding) { - unsigned int precision = get_precision(ulp_tolerance); +template +void explain_binary_operation_one_output_error( + Operation op, const BinaryInput &input, OutputType libc_result, + double ulp_tolerance, RoundingMode rounding) { + unsigned int precision = get_precision(ulp_tolerance); MPFRNumber mpfrX(input.x, precision); MPFRNumber mpfrY(input.y, precision); - FPBits xbits(input.x); - FPBits ybits(input.y); + FPBits xbits(input.x); + FPBits ybits(input.y); MPFRNumber mpfr_result = binary_operation_one_output(op, input.x, input.y, precision, rounding); MPFRNumber mpfrMatchValue(libc_result); tlog << "Input decimal: x: " << mpfrX.str() << " y: " << mpfrY.str() << '\n'; - tlog << "First input bits: " << str(FPBits(input.x)) << '\n'; - tlog << "Second input bits: " << str(FPBits(input.y)) << '\n'; + tlog << "First input bits: " << str(FPBits(input.x)) << '\n'; + tlog << "Second input bits: " << str(FPBits(input.y)) << '\n'; tlog << "Libc result: " << mpfrMatchValue.str() << '\n' << "MPFR result: " << mpfr_result.str() << '\n'; - tlog << "Libc floating point result bits: " << str(FPBits(libc_result)) - << '\n'; + tlog << "Libc floating point result bits: " + << str(FPBits(libc_result)) << '\n'; tlog << " MPFR rounded bits: " - << str(FPBits(mpfr_result.as())) << '\n'; + << str(FPBits(mpfr_result.as())) << '\n'; tlog << "ULP error: " << mpfr_result.ulp_as_mpfr_number(libc_result).str() << '\n'; } -template void explain_binary_operation_one_output_error( - Operation, const BinaryInput &, float, double, RoundingMode); -template void explain_binary_operation_one_output_error( +template void +explain_binary_operation_one_output_error(Operation, const BinaryInput &, + float, double, RoundingMode); +template void explain_binary_operation_one_output_error( Operation, const BinaryInput &, double, double, RoundingMode); template void explain_binary_operation_one_output_error( Operation, const BinaryInput &, long double, double, @@ -964,6 +985,12 @@ explain_ternary_operation_one_output_error(Operation, #ifdef LIBC_TYPES_HAS_FLOAT16 template void explain_ternary_operation_one_output_error( Operation, const TernaryInput &, float16, double, RoundingMode); +template void explain_ternary_operation_one_output_error( + Operation, const TernaryInput &, float16, double, RoundingMode); +template void +explain_ternary_operation_one_output_error(Operation, + const TernaryInput &, + float16, double, RoundingMode); #endif template @@ -990,6 +1017,11 @@ template bool compare_unary_operation_single_output(Operation, float16, float16, double, RoundingMode); template bool compare_unary_operation_single_output(Operation, float, float16, double, RoundingMode); +template bool compare_unary_operation_single_output(Operation, double, float16, + double, RoundingMode); +template bool compare_unary_operation_single_output(Operation, long double, + float16, double, + RoundingMode); #endif template @@ -1051,10 +1083,11 @@ template bool compare_binary_operation_two_outputs( Operation, const BinaryInput &, const BinaryOutput &, double, RoundingMode); -template +template bool compare_binary_operation_one_output(Operation op, - const BinaryInput &input, - T libc_result, double ulp_tolerance, + const BinaryInput &input, + OutputType libc_result, + double ulp_tolerance, RoundingMode rounding) { unsigned int precision = get_precision(ulp_tolerance); MPFRNumber mpfr_result = @@ -1102,6 +1135,14 @@ template bool compare_ternary_operation_one_output(Operation, const TernaryInput &, float16, double, RoundingMode); +template bool compare_ternary_operation_one_output(Operation, + const TernaryInput &, + float16, double, + RoundingMode); +template bool +compare_ternary_operation_one_output(Operation, + const TernaryInput &, float16, + double, RoundingMode); #endif } // namespace internal diff --git a/libc/utils/MPFRWrapper/MPFRUtils.h b/libc/utils/MPFRWrapper/MPFRUtils.h index 0b4f42a72ec813..71087361947063 100644 --- a/libc/utils/MPFRWrapper/MPFRUtils.h +++ b/libc/utils/MPFRWrapper/MPFRUtils.h @@ -41,6 +41,7 @@ enum class Operation : int { Exp10, Expm1, Floor, + Fmul, Log, Log2, Log10, @@ -71,6 +72,7 @@ enum class Operation : int { // output. BeginBinaryOperationsSingleOutput, Atan2, + Div, Fmod, Hypot, Pow, @@ -129,6 +131,14 @@ struct AreMatchingBinaryInputAndBinaryOutput, BinaryOutput> { static constexpr bool VALUE = cpp::is_floating_point_v; }; +template struct IsBinaryInput { + static constexpr bool VALUE = false; +}; + +template struct IsBinaryInput> { + static constexpr bool VALUE = true; +}; + template struct IsTernaryInput { static constexpr bool VALUE = false; }; @@ -137,8 +147,19 @@ template struct IsTernaryInput> { static constexpr bool VALUE = true; }; +template struct IsBinaryInput { + static constexpr bool VALUE = false; +}; + +template struct IsBinaryInput> { + static constexpr bool VALUE = true; +}; + template struct MakeScalarInput : cpp::type_identity {}; +template +struct MakeScalarInput> : cpp::type_identity {}; + template struct MakeScalarInput> : cpp::type_identity {}; @@ -159,10 +180,11 @@ bool compare_binary_operation_two_outputs(Operation op, double ulp_tolerance, RoundingMode rounding); -template +template bool compare_binary_operation_one_output(Operation op, - const BinaryInput &input, - T libc_output, double ulp_tolerance, + const BinaryInput &input, + OutputType libc_output, + double ulp_tolerance, RoundingMode rounding); template @@ -187,12 +209,10 @@ void explain_binary_operation_two_outputs_error( const BinaryOutput &match_value, double ulp_tolerance, RoundingMode rounding); -template -void explain_binary_operation_one_output_error(Operation op, - const BinaryInput &input, - T match_value, - double ulp_tolerance, - RoundingMode rounding); +template +void explain_binary_operation_one_output_error( + Operation op, const BinaryInput &input, OutputType match_value, + double ulp_tolerance, RoundingMode rounding); template void explain_ternary_operation_one_output_error( @@ -225,56 +245,63 @@ class MPFRMatcher : public testing::Matcher { bool is_silent() const override { return silent; } private: - template bool match(T in, U out) { + template + bool match(InType in, OutType out) { return compare_unary_operation_single_output(op, in, out, ulp_tolerance, rounding); } - template bool match(T in, const BinaryOutput &out) { + template + bool match(InType in, const BinaryOutput &out) { return compare_unary_operation_two_outputs(op, in, out, ulp_tolerance, rounding); } - template bool match(const BinaryInput &in, T out) { + template + bool match(const BinaryInput &in, U out) { return compare_binary_operation_one_output(op, in, out, ulp_tolerance, rounding); } - template - bool match(BinaryInput in, const BinaryOutput &out) { + template + bool match(BinaryInput in, const BinaryOutput &out) { return compare_binary_operation_two_outputs(op, in, out, ulp_tolerance, rounding); } - template - bool match(const TernaryInput &in, U out) { + template + bool match(const TernaryInput &in, OutType out) { return compare_ternary_operation_one_output(op, in, out, ulp_tolerance, rounding); } - template void explain_error(T in, U out) { + template + void explain_error(InType in, OutType out) { explain_unary_operation_single_output_error(op, in, out, ulp_tolerance, rounding); } - template void explain_error(T in, const BinaryOutput &out) { + template + void explain_error(InType in, const BinaryOutput &out) { explain_unary_operation_two_outputs_error(op, in, out, ulp_tolerance, rounding); } - template - void explain_error(const BinaryInput &in, const BinaryOutput &out) { + template + void explain_error(const BinaryInput &in, + const BinaryOutput &out) { explain_binary_operation_two_outputs_error(op, in, out, ulp_tolerance, rounding); } - template void explain_error(const BinaryInput &in, T out) { + template + void explain_error(const BinaryInput &in, U out) { explain_binary_operation_one_output_error(op, in, out, ulp_tolerance, rounding); } - template - void explain_error(const TernaryInput &in, U out) { + template + void explain_error(const TernaryInput &in, OutType out) { explain_ternary_operation_one_output_error(op, in, out, ulp_tolerance, rounding); } @@ -290,9 +317,15 @@ constexpr bool is_valid_operation() { (op == Operation::Sqrt && cpp::is_floating_point_v && cpp::is_floating_point_v && sizeof(OutputType) <= sizeof(InputType)) || + (op == Operation::Div && internal::IsBinaryInput::VALUE && + cpp::is_floating_point_v< + typename internal::MakeScalarInput::type> && + cpp::is_floating_point_v) || (op == Operation::Fma && internal::IsTernaryInput::VALUE && cpp::is_floating_point_v< typename internal::MakeScalarInput::type> && + cpp::is_floating_point_v) || + (op == Operation::Fmul && internal::IsBinaryInput::VALUE && cpp::is_floating_point_v); if (IS_NARROWING_OP) return true; diff --git a/libclc/CMakeLists.txt b/libclc/CMakeLists.txt index 9858ae905983f3..ef8d21b167623a 100644 --- a/libclc/CMakeLists.txt +++ b/libclc/CMakeLists.txt @@ -374,15 +374,21 @@ foreach( t ${LIBCLC_TARGETS_TO_BUILD} ) OUTPUT ${output_file} EXTRA_OPTS "${mcpu}" -fno-builtin -nostdlib "${build_flags}" -I${PROJECT_SOURCE_DIR}/${file_dir} + DEPENDENCIES generate_convert.cl clspv-generate_convert.cl ) list( APPEND bytecode_files ${output_file} ) endforeach() - set( builtins_link_lib_tgt builtins.link.${arch_suffix} ) + set( builtins_comp_lib_tgt builtins.comp.${arch_suffix} ) + add_custom_target( ${builtins_comp_lib_tgt} + DEPENDS ${bytecode_files} + ) + set( builtins_link_lib_tgt builtins.link.${arch_suffix} ) link_bc( TARGET ${builtins_link_lib_tgt} INPUTS ${bytecode_files} + DEPENDENCIES ${builtins_comp_lib_tgt} ) set( builtins_link_lib $ ) @@ -391,7 +397,7 @@ foreach( t ${LIBCLC_TARGETS_TO_BUILD} ) set( spv_suffix ${arch_suffix}.spv ) add_custom_command( OUTPUT ${spv_suffix} COMMAND libclc::llvm-spirv ${spvflags} -o ${spv_suffix} ${builtins_link_lib} - DEPENDS ${builtins_link_lib} + DEPENDS ${builtins_link_lib} ${builtins_link_lib_tgt} ) add_custom_target( "prepare-${spv_suffix}" ALL DEPENDS "${spv_suffix}" ) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${spv_suffix} @@ -403,7 +409,7 @@ foreach( t ${LIBCLC_TARGETS_TO_BUILD} ) add_custom_command( OUTPUT ${builtins_opt_lib_tgt}.bc COMMAND libclc::opt ${opt_flags} -o ${builtins_opt_lib_tgt}.bc ${builtins_link_lib} - DEPENDS libclc::opt ${builtins_link_lib} + DEPENDS libclc::opt ${builtins_link_lib} ${builtins_link_lib_tgt} ) add_custom_target( ${builtins_opt_lib_tgt} ALL DEPENDS ${builtins_opt_lib_tgt}.bc @@ -418,7 +424,7 @@ foreach( t ${LIBCLC_TARGETS_TO_BUILD} ) set( obj_suffix ${arch_suffix}.bc ) add_custom_command( OUTPUT ${obj_suffix} COMMAND prepare_builtins -o ${obj_suffix} ${builtins_opt_lib} - DEPENDS ${builtins_opt_lib} prepare_builtins ) + DEPENDS ${builtins_opt_lib} ${builtins_opt_lib_tgt} prepare_builtins ) add_custom_target( prepare-${obj_suffix} ALL DEPENDS ${obj_suffix} ) # nvptx-- targets don't include workitem builtins diff --git a/libclc/cmake/modules/AddLibclc.cmake b/libclc/cmake/modules/AddLibclc.cmake index 7f4620fa6a21df..ea97e504364ba5 100644 --- a/libclc/cmake/modules/AddLibclc.cmake +++ b/libclc/cmake/modules/AddLibclc.cmake @@ -80,11 +80,13 @@ endfunction() # Custom target to create # * INPUT ... # List of bytecode files to link together +# * DEPENDENCIES ... +# List of extra dependencies to inject function(link_bc) cmake_parse_arguments(ARG "" "TARGET" - "INPUTS" + "INPUTS;DEPENDENCIES" ${ARGN} ) @@ -106,7 +108,7 @@ function(link_bc) add_custom_command( OUTPUT ${ARG_TARGET}.bc COMMAND libclc::llvm-link -o ${ARG_TARGET}.bc ${LINK_INPUT_ARG} - DEPENDS libclc::llvm-link ${ARG_INPUTS} ${RSP_FILE} + DEPENDS libclc::llvm-link ${ARG_DEPENDENCIES} ${ARG_INPUTS} ${RSP_FILE} ) add_custom_target( ${ARG_TARGET} ALL DEPENDS ${ARG_TARGET}.bc ) diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt index 4b927017f8c2ac..e098bd574eec73 100644 --- a/libcxx/CMakeLists.txt +++ b/libcxx/CMakeLists.txt @@ -553,6 +553,10 @@ function(cxx_add_basic_build_flags target) target_add_compile_flags_if_supported(${target} PRIVATE -fvisibility=hidden) endif() + # Build with -fsized-deallocation, which is default in recent versions of Clang. + # TODO(LLVM 21): This can be dropped once we only support Clang >= 19. + target_add_compile_flags_if_supported(${target} PRIVATE -fsized-deallocation) + # Let the library headers know they are currently being used to build the # library. target_compile_definitions(${target} PRIVATE -D_LIBCPP_BUILDING_LIBRARY) diff --git a/libcxx/docs/ReleaseNotes/19.rst b/libcxx/docs/ReleaseNotes/19.rst index 71de10abb6eaa8..d30021b7eb2347 100644 --- a/libcxx/docs/ReleaseNotes/19.rst +++ b/libcxx/docs/ReleaseNotes/19.rst @@ -121,6 +121,15 @@ Deprecations and Removals - The ``_LIBCPP_DISABLE_ADDITIONAL_DIAGNOSTICS`` macro has been removed and is not honored anymore. Additional warnings provided by libc++ as a matter of QoI will now be provided unconditionally. +- libc++ no longer supports ``std::allocator`` and containers of ``const``-qualified element type, such + as ``std::vector`` and ``std::list``. This used to be supported as an undocumented extension. + If you were using ``std::vector``, replace it with ``std::vector`` instead. The + ``_LIBCPP_ENABLE_REMOVED_ALLOCATOR_CONST`` macro can be defined to temporarily re-enable this extension as + folks transition their code. This macro will be honored for one released and ignored starting in LLVM 20. + To assist with the clean-up process, consider running your code through Clang Tidy, with + `std-allocator-const ` + enabled. + Upcoming Deprecations and Removals ---------------------------------- diff --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv index 6453f227cfcc24..e748ff6ad749b7 100644 --- a/libcxx/docs/Status/Cxx20Issues.csv +++ b/libcxx/docs/Status/Cxx20Issues.csv @@ -200,7 +200,7 @@ "`3200 `__","``midpoint``\ should not constrain ``T``\ is complete","Prague","|Nothing To Do|","" "`3201 `__","``lerp``\ should be marked as ``noexcept``\ ","Prague","|Complete|","" "`3226 `__","``zoned_time``\ constructor from ``string_view``\ should accept ``zoned_time``\ ","Prague","","","|chrono|" -"`3233 `__","Broken requirements for ``shared_ptr``\ converting constructors","Prague","","" +"`3233 `__","Broken requirements for ``shared_ptr``\ converting constructors","Prague","|Complete|","19.0" "`3237 `__","LWG 3038 and 3190 have inconsistent PRs","Prague","|Complete|","16.0" "`3238 `__","Insufficiently-defined behavior of ``std::function``\ deduction guides","Prague","|Nothing To Do|","" "`3242 `__","``std::format``\ : missing rules for ``arg-id``\ in ``width``\ and ``precision``\ ","Prague","|Complete|","14.0","|format|" diff --git a/libcxx/docs/Status/ParallelismProjects.csv b/libcxx/docs/Status/ParallelismProjects.csv index 2ddac1e52f0264..06087e3d870f93 100644 --- a/libcxx/docs/Status/ParallelismProjects.csv +++ b/libcxx/docs/Status/ParallelismProjects.csv @@ -16,6 +16,7 @@ Section,Description,Dependencies,Assignee,Complete | `[parallel.simd.whereexpr] `_, "Where expression class templates", None, Yin Zhang, |In Progress| | `[parallel.simd.reference] `_, "`Element references operator value_type() `_", None, Yin Zhang, |Complete| | `[parallel.simd.reference] `_, "`Element references operator= `_", None, Yin Zhang, |Complete| +| `[parallel.simd.reference] `_, "`Element references swap functions `_", None, Yin Zhang, |Complete| | `[parallel.simd.class] `_, "`Class template simd declaration and alias `_", [parallel.simd.abi], Yin Zhang, |Complete| | `[parallel.simd.class] `_, "`simd<>::size() `_", [parallel.simd.traits] simd_size[_v], Yin Zhang, |Complete| | `[parallel.simd.class] `_, "`simd default constructor `_", None, Yin Zhang, |Complete| diff --git a/libcxx/include/__atomic/atomic_base.h b/libcxx/include/__atomic/atomic_base.h index d7a5b99b546910..7e26434c9c3a0a 100644 --- a/libcxx/include/__atomic/atomic_base.h +++ b/libcxx/include/__atomic/atomic_base.h @@ -33,7 +33,7 @@ struct __atomic_base // false mutable __cxx_atomic_impl<_Tp> __a_; #if _LIBCPP_STD_VER >= 17 - static _LIBCPP_CONSTEXPR bool is_always_lock_free = __libcpp_is_always_lock_free<__cxx_atomic_impl<_Tp> >::__value; + static constexpr bool is_always_lock_free = __libcpp_is_always_lock_free<__cxx_atomic_impl<_Tp> >::__value; #endif _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const volatile _NOEXCEPT { @@ -129,11 +129,6 @@ struct __atomic_base // false __atomic_base(const __atomic_base&) = delete; }; -#if _LIBCPP_STD_VER >= 17 -template -_LIBCPP_CONSTEXPR bool __atomic_base<_Tp, __b>::is_always_lock_free; -#endif - // atomic template diff --git a/libcxx/include/__atomic/atomic_init.h b/libcxx/include/__atomic/atomic_init.h index 2ed37a9a77c86d..8e86ba31b4ac3b 100644 --- a/libcxx/include/__atomic/atomic_init.h +++ b/libcxx/include/__atomic/atomic_init.h @@ -18,7 +18,7 @@ #define ATOMIC_FLAG_INIT {false} #define ATOMIC_VAR_INIT(__v) {__v} -#if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_DISABLE_DEPRECATION_WARNINGS) +#if _LIBCPP_STD_VER >= 20 && defined(_LIBCPP_COMPILER_CLANG_BASED) && !defined(_LIBCPP_DISABLE_DEPRECATION_WARNINGS) # pragma clang deprecated(ATOMIC_VAR_INIT) #endif diff --git a/libcxx/include/__charconv/chars_format.h b/libcxx/include/__charconv/chars_format.h index 95faa29010dd81..c76cebd5d1847d 100644 --- a/libcxx/include/__charconv/chars_format.h +++ b/libcxx/include/__charconv/chars_format.h @@ -39,20 +39,17 @@ inline _LIBCPP_HIDE_FROM_ABI constexpr chars_format operator^(chars_format __x, return chars_format(std::__to_underlying(__x) ^ std::__to_underlying(__y)); } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 chars_format& -operator&=(chars_format& __x, chars_format __y) { +inline _LIBCPP_HIDE_FROM_ABI constexpr chars_format& operator&=(chars_format& __x, chars_format __y) { __x = __x & __y; return __x; } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 chars_format& -operator|=(chars_format& __x, chars_format __y) { +inline _LIBCPP_HIDE_FROM_ABI constexpr chars_format& operator|=(chars_format& __x, chars_format __y) { __x = __x | __y; return __x; } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 chars_format& -operator^=(chars_format& __x, chars_format __y) { +inline _LIBCPP_HIDE_FROM_ABI constexpr chars_format& operator^=(chars_format& __x, chars_format __y) { __x = __x ^ __y; return __x; } diff --git a/libcxx/include/__chrono/time_point.h b/libcxx/include/__chrono/time_point.h index cb5bf4d13f705b..aaf0b098f280e0 100644 --- a/libcxx/include/__chrono/time_point.h +++ b/libcxx/include/__chrono/time_point.h @@ -92,25 +92,22 @@ time_point_cast(const time_point<_Clock, _Duration>& __t) { #if _LIBCPP_STD_VER >= 17 template ::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR time_point<_Clock, _ToDuration> -floor(const time_point<_Clock, _Duration>& __t) { +inline _LIBCPP_HIDE_FROM_ABI constexpr time_point<_Clock, _ToDuration> floor(const time_point<_Clock, _Duration>& __t) { return time_point<_Clock, _ToDuration>{chrono::floor<_ToDuration>(__t.time_since_epoch())}; } template ::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR time_point<_Clock, _ToDuration> -ceil(const time_point<_Clock, _Duration>& __t) { +inline _LIBCPP_HIDE_FROM_ABI constexpr time_point<_Clock, _ToDuration> ceil(const time_point<_Clock, _Duration>& __t) { return time_point<_Clock, _ToDuration>{chrono::ceil<_ToDuration>(__t.time_since_epoch())}; } template ::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR time_point<_Clock, _ToDuration> -round(const time_point<_Clock, _Duration>& __t) { +inline _LIBCPP_HIDE_FROM_ABI constexpr time_point<_Clock, _ToDuration> round(const time_point<_Clock, _Duration>& __t) { return time_point<_Clock, _ToDuration>{chrono::round<_ToDuration>(__t.time_since_epoch())}; } template ::is_signed, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR duration<_Rep, _Period> abs(duration<_Rep, _Period> __d) { +inline _LIBCPP_HIDE_FROM_ABI constexpr duration<_Rep, _Period> abs(duration<_Rep, _Period> __d) { return __d >= __d.zero() ? +__d : -__d; } #endif // _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/__configuration/availability.h b/libcxx/include/__configuration/availability.h index 7e6e18b22d93aa..ab483a07c9c137 100644 --- a/libcxx/include/__configuration/availability.h +++ b/libcxx/include/__configuration/availability.h @@ -87,171 +87,193 @@ // in all versions of the library are available. #if defined(_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS) -# define _LIBCPP_INTRODUCED_IN_LLVM_4 1 -# define _LIBCPP_INTRODUCED_IN_LLVM_4_ATTRIBUTE /* nothing */ +# define _LIBCPP_INTRODUCED_IN_LLVM_19 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_19_ATTRIBUTE /* nothing */ -# define _LIBCPP_INTRODUCED_IN_LLVM_9 1 -# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE /* nothing */ -# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE_PUSH /* nothing */ -# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE_POP /* nothing */ +# define _LIBCPP_INTRODUCED_IN_LLVM_18 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_18_ATTRIBUTE /* nothing */ -# define _LIBCPP_INTRODUCED_IN_LLVM_11 1 -# define _LIBCPP_INTRODUCED_IN_LLVM_11_ATTRIBUTE /* nothing */ +# define _LIBCPP_INTRODUCED_IN_LLVM_17 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_17_ATTRIBUTE /* nothing */ -# define _LIBCPP_INTRODUCED_IN_LLVM_12 1 -# define _LIBCPP_INTRODUCED_IN_LLVM_12_ATTRIBUTE /* nothing */ +# define _LIBCPP_INTRODUCED_IN_LLVM_16 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_16_ATTRIBUTE /* nothing */ + +# define _LIBCPP_INTRODUCED_IN_LLVM_15 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_15_ATTRIBUTE /* nothing */ # define _LIBCPP_INTRODUCED_IN_LLVM_14 1 # define _LIBCPP_INTRODUCED_IN_LLVM_14_ATTRIBUTE /* nothing */ -# define _LIBCPP_INTRODUCED_IN_LLVM_15 1 -# define _LIBCPP_INTRODUCED_IN_LLVM_15_ATTRIBUTE /* nothing */ +# define _LIBCPP_INTRODUCED_IN_LLVM_13 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_13_ATTRIBUTE /* nothing */ -# define _LIBCPP_INTRODUCED_IN_LLVM_16 1 -# define _LIBCPP_INTRODUCED_IN_LLVM_16_ATTRIBUTE /* nothing */ +# define _LIBCPP_INTRODUCED_IN_LLVM_12 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_12_ATTRIBUTE /* nothing */ -# define _LIBCPP_INTRODUCED_IN_LLVM_18 1 -# define _LIBCPP_INTRODUCED_IN_LLVM_18_ATTRIBUTE /* nothing */ +# define _LIBCPP_INTRODUCED_IN_LLVM_11 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_11_ATTRIBUTE /* nothing */ -# define _LIBCPP_INTRODUCED_IN_LLVM_19 1 -# define _LIBCPP_INTRODUCED_IN_LLVM_19_ATTRIBUTE /* nothing */ +# define _LIBCPP_INTRODUCED_IN_LLVM_10 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_10_ATTRIBUTE /* nothing */ + +# define _LIBCPP_INTRODUCED_IN_LLVM_9 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE /* nothing */ +# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE_PUSH /* nothing */ +# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE_POP /* nothing */ + +# define _LIBCPP_INTRODUCED_IN_LLVM_8 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_8_ATTRIBUTE /* nothing */ + +# define _LIBCPP_INTRODUCED_IN_LLVM_4 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_4_ATTRIBUTE /* nothing */ #elif defined(__APPLE__) -// LLVM 4 -# if defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 50000 -# define _LIBCPP_INTRODUCED_IN_LLVM_4 0 -# define _LIBCPP_INTRODUCED_IN_LLVM_4_ATTRIBUTE __attribute__((availability(watchos, strict, introduced = 5.0))) +// clang-format off + +// LLVM 19 +// TODO: Fill this in +# define _LIBCPP_INTRODUCED_IN_LLVM_19 0 +# define _LIBCPP_INTRODUCED_IN_LLVM_19_ATTRIBUTE __attribute__((unavailable)) + +// LLVM 18 +// TODO: Fill this in +# define _LIBCPP_INTRODUCED_IN_LLVM_18 0 +# define _LIBCPP_INTRODUCED_IN_LLVM_18_ATTRIBUTE __attribute__((unavailable)) + +// LLVM 17 +# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 140400) || \ + (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 170400) || \ + (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 170400) || \ + (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 100400) +# define _LIBCPP_INTRODUCED_IN_LLVM_17 0 # else -# define _LIBCPP_INTRODUCED_IN_LLVM_4 1 -# define _LIBCPP_INTRODUCED_IN_LLVM_4_ATTRIBUTE /* nothing */ +# define _LIBCPP_INTRODUCED_IN_LLVM_17 1 # endif +# define _LIBCPP_INTRODUCED_IN_LLVM_17_ATTRIBUTE \ + __attribute__((availability(macos, strict, introduced = 14.4))) \ + __attribute__((availability(ios, strict, introduced = 17.4))) \ + __attribute__((availability(tvos, strict, introduced = 17.4))) \ + __attribute__((availability(watchos, strict, introduced = 10.4))) + +// LLVM 16 +# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 140000) || \ + (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 170000) || \ + (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 170000) || \ + (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 100000) +# define _LIBCPP_INTRODUCED_IN_LLVM_16 0 +# else +# define _LIBCPP_INTRODUCED_IN_LLVM_16 1 +# endif +# define _LIBCPP_INTRODUCED_IN_LLVM_16_ATTRIBUTE \ + __attribute__((availability(macos, strict, introduced = 14.0))) \ + __attribute__((availability(ios, strict, introduced = 17.0))) \ + __attribute__((availability(tvos, strict, introduced = 17.0))) \ + __attribute__((availability(watchos, strict, introduced = 10.0))) -// LLVM 9 -// clang-format off -# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101500) || \ - (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 130000) || \ - (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 130000) || \ - (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 60000) -// clang-format on -# define _LIBCPP_INTRODUCED_IN_LLVM_9 0 -# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE \ - __attribute__((availability(macos, strict, introduced = 10.15))) \ - __attribute__((availability(ios, strict, introduced = 13.0))) \ - __attribute__((availability(tvos, strict, introduced = 13.0))) \ - __attribute__((availability(watchos, strict, introduced = 6.0))) -// clang-format off -# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE_PUSH \ - _Pragma("clang attribute push(__attribute__((availability(macos,strict,introduced=10.15))), apply_to=any(function,record))") \ - _Pragma("clang attribute push(__attribute__((availability(ios,strict,introduced=13.0))), apply_to=any(function,record))") \ - _Pragma("clang attribute push(__attribute__((availability(tvos,strict,introduced=13.0))), apply_to=any(function,record))") \ - _Pragma("clang attribute push(__attribute__((availability(watchos,strict,introduced=6.0))), apply_to=any(function,record))") -# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE_POP \ - _Pragma("clang attribute pop") \ - _Pragma("clang attribute pop") \ - _Pragma("clang attribute pop") \ - _Pragma("clang attribute pop") -// clang-format on +// LLVM 15 +# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 130400) || \ + (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 160500) || \ + (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 160500) || \ + (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 90500) +# define _LIBCPP_INTRODUCED_IN_LLVM_15 0 # else -# define _LIBCPP_INTRODUCED_IN_LLVM_9 1 -# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE /* nothing */ -# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE_PUSH /* nothing */ -# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE_POP /* nothing */ +# define _LIBCPP_INTRODUCED_IN_LLVM_15 1 # endif +# define _LIBCPP_INTRODUCED_IN_LLVM_15_ATTRIBUTE \ + __attribute__((availability(macos, strict, introduced = 13.4))) \ + __attribute__((availability(ios, strict, introduced = 16.5))) \ + __attribute__((availability(tvos, strict, introduced = 16.5))) \ + __attribute__((availability(watchos, strict, introduced = 9.5))) -// LLVM 11 -// clang-format off -# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 110000) || \ - (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 140000) || \ - (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 140000) || \ - (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 70000) -// clang-format on -# define _LIBCPP_INTRODUCED_IN_LLVM_11 0 -# define _LIBCPP_INTRODUCED_IN_LLVM_11_ATTRIBUTE \ - __attribute__((availability(macos, strict, introduced = 11.0))) \ - __attribute__((availability(ios, strict, introduced = 14.0))) \ - __attribute__((availability(tvos, strict, introduced = 14.0))) \ - __attribute__((availability(watchos, strict, introduced = 7.0))) +// LLVM 14 +# define _LIBCPP_INTRODUCED_IN_LLVM_14 _LIBCPP_INTRODUCED_IN_LLVM_15 +# define _LIBCPP_INTRODUCED_IN_LLVM_14_ATTRIBUTE _LIBCPP_INTRODUCED_IN_LLVM_15_ATTRIBUTE + +// LLVM 13 +# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 130000) || \ + (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 160000) || \ + (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 160000) || \ + (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 90000) +# define _LIBCPP_INTRODUCED_IN_LLVM_13 0 # else -# define _LIBCPP_INTRODUCED_IN_LLVM_11 1 -# define _LIBCPP_INTRODUCED_IN_LLVM_11_ATTRIBUTE /* nothing */ +# define _LIBCPP_INTRODUCED_IN_LLVM_13 1 # endif +# define _LIBCPP_INTRODUCED_IN_LLVM_13_ATTRIBUTE \ + __attribute__((availability(macos, strict, introduced = 13.0))) \ + __attribute__((availability(ios, strict, introduced = 16.0))) \ + __attribute__((availability(tvos, strict, introduced = 16.0))) \ + __attribute__((availability(watchos, strict, introduced = 9.0))) // LLVM 12 -// clang-format off -# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 120000) || \ - (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 150000) || \ - (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 150000) || \ - (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 80000) -// clang-format on +# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 120300) || \ + (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 150300) || \ + (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 150300) || \ + (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 80300) # define _LIBCPP_INTRODUCED_IN_LLVM_12 0 -# define _LIBCPP_INTRODUCED_IN_LLVM_12_ATTRIBUTE \ - __attribute__((availability(macos, strict, introduced = 12.0))) \ - __attribute__((availability(ios, strict, introduced = 15.0))) \ - __attribute__((availability(tvos, strict, introduced = 15.0))) \ - __attribute__((availability(watchos, strict, introduced = 8.0))) # else # define _LIBCPP_INTRODUCED_IN_LLVM_12 1 -# define _LIBCPP_INTRODUCED_IN_LLVM_12_ATTRIBUTE /* nothing */ # endif +# define _LIBCPP_INTRODUCED_IN_LLVM_12_ATTRIBUTE \ + __attribute__((availability(macos, strict, introduced = 12.3))) \ + __attribute__((availability(ios, strict, introduced = 15.3))) \ + __attribute__((availability(tvos, strict, introduced = 15.3))) \ + __attribute__((availability(watchos, strict, introduced = 8.3))) -// LLVM 14 -// clang-format off -# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 130400) || \ - (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 160500) || \ - (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 160500) || \ - (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 90500) -// clang-format on -# define _LIBCPP_INTRODUCED_IN_LLVM_14 0 -# define _LIBCPP_INTRODUCED_IN_LLVM_14_ATTRIBUTE \ - __attribute__((availability(macos, strict, introduced = 13.4))) \ - __attribute__((availability(ios, strict, introduced = 16.5))) \ - __attribute__((availability(tvos, strict, introduced = 16.5))) \ - __attribute__((availability(watchos, strict, introduced = 9.5))) +// LLVM 11 +# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 110000) || \ + (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 140000) || \ + (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 140000) || \ + (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 70000) +# define _LIBCPP_INTRODUCED_IN_LLVM_11 0 # else -# define _LIBCPP_INTRODUCED_IN_LLVM_14 1 -# define _LIBCPP_INTRODUCED_IN_LLVM_14_ATTRIBUTE /* nothing */ +# define _LIBCPP_INTRODUCED_IN_LLVM_11 1 # endif +# define _LIBCPP_INTRODUCED_IN_LLVM_11_ATTRIBUTE \ + __attribute__((availability(macos, strict, introduced = 11.0))) \ + __attribute__((availability(ios, strict, introduced = 14.0))) \ + __attribute__((availability(tvos, strict, introduced = 14.0))) \ + __attribute__((availability(watchos, strict, introduced = 7.0))) -// LLVM 15-16 -# define _LIBCPP_INTRODUCED_IN_LLVM_15 _LIBCPP_INTRODUCED_IN_LLVM_16 -# define _LIBCPP_INTRODUCED_IN_LLVM_15_ATTRIBUTE _LIBCPP_INTRODUCED_IN_LLVM_16_ATTRIBUTE -// clang-format off -# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 140000) || \ - (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 170000) || \ - (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 170000) || \ - (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 100000) -// clang-format on -# define _LIBCPP_INTRODUCED_IN_LLVM_16 0 -# define _LIBCPP_INTRODUCED_IN_LLVM_16_ATTRIBUTE \ - __attribute__((availability(macos, strict, introduced = 14.0))) \ - __attribute__((availability(ios, strict, introduced = 17.0))) \ - __attribute__((availability(tvos, strict, introduced = 17.0))) \ - __attribute__((availability(watchos, strict, introduced = 10.0))) -# else -# define _LIBCPP_INTRODUCED_IN_LLVM_16 1 -# define _LIBCPP_INTRODUCED_IN_LLVM_16_ATTRIBUTE /* nothing */ -# endif +// LLVM 10 +# define _LIBCPP_INTRODUCED_IN_LLVM_10 _LIBCPP_INTRODUCED_IN_LLVM_11 +# define _LIBCPP_INTRODUCED_IN_LLVM_10_ATTRIBUTE _LIBCPP_INTRODUCED_IN_LLVM_11_ATTRIBUTE -// LLVM 18 -// TODO: Fill this in -# if 1 -# define _LIBCPP_INTRODUCED_IN_LLVM_18 0 -# define _LIBCPP_INTRODUCED_IN_LLVM_18_ATTRIBUTE __attribute__((unavailable)) +// LLVM 9 +# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101500) || \ + (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 130000) || \ + (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 130000) || \ + (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 60000) +# define _LIBCPP_INTRODUCED_IN_LLVM_9 0 # else -# define _LIBCPP_INTRODUCED_IN_LLVM_18 1 -# define _LIBCPP_INTRODUCED_IN_LLVM_18_ATTRIBUTE /* nothing */ +# define _LIBCPP_INTRODUCED_IN_LLVM_9 1 # endif +# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE \ + __attribute__((availability(macos, strict, introduced = 10.15))) \ + __attribute__((availability(ios, strict, introduced = 13.0))) \ + __attribute__((availability(tvos, strict, introduced = 13.0))) \ + __attribute__((availability(watchos, strict, introduced = 6.0))) +# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE_PUSH \ + _Pragma("clang attribute push(__attribute__((availability(macos,strict,introduced=10.15))), apply_to=any(function,record))") \ + _Pragma("clang attribute push(__attribute__((availability(ios,strict,introduced=13.0))), apply_to=any(function,record))") \ + _Pragma("clang attribute push(__attribute__((availability(tvos,strict,introduced=13.0))), apply_to=any(function,record))") \ + _Pragma("clang attribute push(__attribute__((availability(watchos,strict,introduced=6.0))), apply_to=any(function,record))") +# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE_POP \ + _Pragma("clang attribute pop") \ + _Pragma("clang attribute pop") \ + _Pragma("clang attribute pop") \ + _Pragma("clang attribute pop") -// LLVM 19 -// TODO: Fill this in -# if 1 -# define _LIBCPP_INTRODUCED_IN_LLVM_19 0 -# define _LIBCPP_INTRODUCED_IN_LLVM_19_ATTRIBUTE __attribute__((unavailable)) +// LLVM 4 +# if defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 50000 +# define _LIBCPP_INTRODUCED_IN_LLVM_4 0 # else -# define _LIBCPP_INTRODUCED_IN_LLVM_19 1 -# define _LIBCPP_INTRODUCED_IN_LLVM_19_ATTRIBUTE /* nothing */ +# define _LIBCPP_INTRODUCED_IN_LLVM_4 1 # endif +# define _LIBCPP_INTRODUCED_IN_LLVM_4_ATTRIBUTE __attribute__((availability(watchos, strict, introduced = 5.0))) + +// clang-format on #else diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h index 0f994e297a877a..f618b20603e609 100644 --- a/libcxx/include/__expected/expected.h +++ b/libcxx/include/__expected/expected.h @@ -507,7 +507,9 @@ class expected : private __expected_base<_Tp, _Err> { _And< is_constructible<_Tp, _UfQual>, is_constructible<_Err, _OtherErrQual>, _If<_Not, bool>>::value, - _And< _Not&>>, + _And< + _Not<_And, is_same<_Err, _OtherErr>>>, // use the copy constructor instead, see #92676 + _Not&>>, _Not>>, _Not&>>, _Not>>, diff --git a/libcxx/include/__functional/function.h b/libcxx/include/__functional/function.h index fb82cfceadaff7..c7b98035e34bfa 100644 --- a/libcxx/include/__functional/function.h +++ b/libcxx/include/__functional/function.h @@ -516,7 +516,7 @@ struct __policy { } _LIBCPP_HIDE_FROM_ABI static const __policy* __create_empty() { - static const _LIBCPP_CONSTEXPR __policy __policy = { + static constexpr __policy __policy = { nullptr, nullptr, true, @@ -543,7 +543,7 @@ struct __policy { template _LIBCPP_HIDE_FROM_ABI static const __policy* __choose_policy(/* is_small = */ false_type) { - static const _LIBCPP_CONSTEXPR __policy __policy = { + static constexpr __policy __policy = { &__large_clone<_Fun>, &__large_destroy<_Fun>, false, @@ -558,7 +558,7 @@ struct __policy { template _LIBCPP_HIDE_FROM_ABI static const __policy* __choose_policy(/* is_small = */ true_type) { - static const _LIBCPP_CONSTEXPR __policy __policy = { + static constexpr __policy __policy = { nullptr, nullptr, false, diff --git a/libcxx/include/__iterator/data.h b/libcxx/include/__iterator/data.h index 39867390610172..b7c1603652b0e6 100644 --- a/libcxx/include/__iterator/data.h +++ b/libcxx/include/__iterator/data.h @@ -23,12 +23,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 17 template -constexpr _LIBCPP_HIDE_FROM_ABI auto data(_Cont& __c) _NOEXCEPT_(noexcept(__c.data())) -> decltype(__c.data()) { +constexpr _LIBCPP_HIDE_FROM_ABI auto data(_Cont& __c) noexcept(noexcept(__c.data())) -> decltype(__c.data()) { return __c.data(); } template -constexpr _LIBCPP_HIDE_FROM_ABI auto data(const _Cont& __c) _NOEXCEPT_(noexcept(__c.data())) -> decltype(__c.data()) { +constexpr _LIBCPP_HIDE_FROM_ABI auto data(const _Cont& __c) noexcept(noexcept(__c.data())) -> decltype(__c.data()) { return __c.data(); } diff --git a/libcxx/include/__iterator/move_iterator.h b/libcxx/include/__iterator/move_iterator.h index c266022159a156..a1c53e9bd2b596 100644 --- a/libcxx/include/__iterator/move_iterator.h +++ b/libcxx/include/__iterator/move_iterator.h @@ -105,9 +105,8 @@ class _LIBCPP_TEMPLATE_VIS move_iterator typedef iterator_type pointer; typedef typename iterator_traits::reference __reference; - typedef typename conditional< is_reference<__reference>::value, - __libcpp_remove_reference_t<__reference>&&, - __reference >::type reference; + typedef __conditional_t::value, __libcpp_remove_reference_t<__reference>&&, __reference> + reference; #endif // _LIBCPP_STD_VER >= 20 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 explicit move_iterator(_Iter __i) : __current_(std::move(__i)) {} diff --git a/libcxx/include/__iterator/size.h b/libcxx/include/__iterator/size.h index eac3ccf522c315..876e6963f77d91 100644 --- a/libcxx/include/__iterator/size.h +++ b/libcxx/include/__iterator/size.h @@ -24,7 +24,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 17 template -_LIBCPP_HIDE_FROM_ABI constexpr auto size(const _Cont& __c) _NOEXCEPT_(noexcept(__c.size())) -> decltype(__c.size()) { +_LIBCPP_HIDE_FROM_ABI constexpr auto size(const _Cont& __c) noexcept(noexcept(__c.size())) -> decltype(__c.size()) { return __c.size(); } @@ -35,9 +35,9 @@ _LIBCPP_HIDE_FROM_ABI constexpr size_t size(const _Tp (&)[_Sz]) noexcept { # if _LIBCPP_STD_VER >= 20 template -_LIBCPP_HIDE_FROM_ABI constexpr auto ssize(const _Cont& __c) - _NOEXCEPT_(noexcept(static_cast>>(__c.size()))) - -> common_type_t> { +_LIBCPP_HIDE_FROM_ABI constexpr auto +ssize(const _Cont& __c) noexcept(noexcept(static_cast>>( + __c.size()))) -> common_type_t> { return static_cast>>(__c.size()); } diff --git a/libcxx/include/__mdspan/extents.h b/libcxx/include/__mdspan/extents.h index ddf9fabd8cea79..fea0decd8c6af7 100644 --- a/libcxx/include/__mdspan/extents.h +++ b/libcxx/include/__mdspan/extents.h @@ -455,8 +455,15 @@ template using dextents = typename __mdspan_detail::__make_dextents<_IndexType, _Rank>::type; // Deduction guide for extents +# if _LIBCPP_STD_VER >= 26 template -extents(_IndexTypes...) -> extents; + requires(is_convertible_v<_IndexTypes, size_t> && ...) +explicit extents(_IndexTypes...) -> extents...>; +# else +template + requires(is_convertible_v<_IndexTypes, size_t> && ...) +explicit extents(_IndexTypes...) -> extents; +# endif namespace __mdspan_detail { diff --git a/libcxx/include/__memory/allocator.h b/libcxx/include/__memory/allocator.h index 215d3832f9ef34..2d8624e771bce0 100644 --- a/libcxx/include/__memory/allocator.h +++ b/libcxx/include/__memory/allocator.h @@ -14,6 +14,7 @@ #include <__memory/addressof.h> #include <__memory/allocate_at_least.h> #include <__memory/allocator_traits.h> +#include <__type_traits/is_const.h> #include <__type_traits/is_constant_evaluated.h> #include <__type_traits/is_same.h> #include <__type_traits/is_void.h> @@ -36,8 +37,6 @@ class allocator; // Specializing allocator is deprecated, but not using it. template <> class _LIBCPP_TEMPLATE_VIS allocator { -# if _LIBCPP_STD_VER <= 17 - public: _LIBCPP_DEPRECATED_IN_CXX17 typedef void* pointer; _LIBCPP_DEPRECATED_IN_CXX17 typedef const void* const_pointer; @@ -47,13 +46,12 @@ class _LIBCPP_TEMPLATE_VIS allocator { struct _LIBCPP_DEPRECATED_IN_CXX17 rebind { typedef allocator<_Up> other; }; -# endif }; +// TODO(LLVM 20): Remove the escape hatch +# ifdef _LIBCPP_ENABLE_REMOVED_ALLOCATOR_CONST template <> class _LIBCPP_TEMPLATE_VIS allocator { -# if _LIBCPP_STD_VER <= 17 - public: _LIBCPP_DEPRECATED_IN_CXX17 typedef const void* pointer; _LIBCPP_DEPRECATED_IN_CXX17 typedef const void* const_pointer; @@ -63,9 +61,9 @@ class _LIBCPP_TEMPLATE_VIS allocator { struct _LIBCPP_DEPRECATED_IN_CXX17 rebind { typedef allocator<_Up> other; }; -# endif }; -#endif +# endif // _LIBCPP_ENABLE_REMOVED_ALLOCATOR_CONST +#endif // _LIBCPP_STD_VER <= 17 // This class provides a non-trivial default constructor to the class that derives from it // if the condition is satisfied. @@ -94,6 +92,7 @@ struct __non_trivial_if { template class _LIBCPP_TEMPLATE_VIS allocator : private __non_trivial_if::value, allocator<_Tp> > { + static_assert(!is_const<_Tp>::value, "std::allocator does not support const types"); static_assert(!is_volatile<_Tp>::value, "std::allocator does not support volatile types"); public: @@ -170,6 +169,8 @@ class _LIBCPP_TEMPLATE_VIS allocator : private __non_trivial_if::v #endif }; +// TODO(LLVM 20): Remove the escape hatch +#ifdef _LIBCPP_ENABLE_REMOVED_ALLOCATOR_CONST template class _LIBCPP_TEMPLATE_VIS allocator : private __non_trivial_if::value, allocator > { @@ -180,9 +181,9 @@ class _LIBCPP_TEMPLATE_VIS allocator typedef ptrdiff_t difference_type; typedef const _Tp value_type; typedef true_type propagate_on_container_move_assignment; -#if _LIBCPP_STD_VER <= 23 || defined(_LIBCPP_ENABLE_CXX26_REMOVED_ALLOCATOR_MEMBERS) +# if _LIBCPP_STD_VER <= 23 || defined(_LIBCPP_ENABLE_CXX26_REMOVED_ALLOCATOR_MEMBERS) _LIBCPP_DEPRECATED_IN_CXX23 typedef true_type is_always_equal; -#endif +# endif _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 allocator() _NOEXCEPT = default; @@ -199,11 +200,11 @@ class _LIBCPP_TEMPLATE_VIS allocator } } -#if _LIBCPP_STD_VER >= 23 +# if _LIBCPP_STD_VER >= 23 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr allocation_result allocate_at_least(size_t __n) { return {allocate(__n), __n}; } -#endif +# endif _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void deallocate(const _Tp* __p, size_t __n) { if (__libcpp_is_constant_evaluated()) { @@ -214,7 +215,7 @@ class _LIBCPP_TEMPLATE_VIS allocator } // C++20 Removed members -#if _LIBCPP_STD_VER <= 17 +# if _LIBCPP_STD_VER <= 17 _LIBCPP_DEPRECATED_IN_CXX17 typedef const _Tp* pointer; _LIBCPP_DEPRECATED_IN_CXX17 typedef const _Tp* const_pointer; _LIBCPP_DEPRECATED_IN_CXX17 typedef const _Tp& reference; @@ -243,8 +244,9 @@ class _LIBCPP_TEMPLATE_VIS allocator } _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI void destroy(pointer __p) { __p->~_Tp(); } -#endif +# endif }; +#endif // _LIBCPP_ENABLE_REMOVED_ALLOCATOR_CONST template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool diff --git a/libcxx/include/__memory/allocator_traits.h b/libcxx/include/__memory/allocator_traits.h index 47fe132d15cb1f..ac564f0e6fa0cc 100644 --- a/libcxx/include/__memory/allocator_traits.h +++ b/libcxx/include/__memory/allocator_traits.h @@ -16,6 +16,7 @@ #include <__type_traits/enable_if.h> #include <__type_traits/is_constructible.h> #include <__type_traits/is_empty.h> +#include <__type_traits/is_same.h> #include <__type_traits/make_unsigned.h> #include <__type_traits/remove_reference.h> #include <__type_traits/void_t.h> @@ -372,6 +373,14 @@ template using __rebind_alloc = typename _Traits::template rebind_alloc<_Tp>::other; #endif +template +struct __check_valid_allocator : true_type { + using _Traits = std::allocator_traits<_Alloc>; + static_assert(is_same<_Alloc, __rebind_alloc<_Traits, typename _Traits::value_type> >::value, + "[allocator.requirements] states that rebinding an allocator to the same type should result in the " + "original allocator"); +}; + // __is_default_allocator template struct __is_default_allocator : false_type {}; diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h index 358a851958db1b..d487e4fbe3a953 100644 --- a/libcxx/include/__memory/shared_ptr.h +++ b/libcxx/include/__memory/shared_ptr.h @@ -259,7 +259,7 @@ struct __shared_ptr_emplace : __shared_weak_count { class _Allocator = _Alloc, __enable_if_t::value, int> = 0> _LIBCPP_HIDE_FROM_ABI explicit __shared_ptr_emplace(_Alloc __a, _Args&&... __args) : __storage_(std::move(__a)) { - using _TpAlloc = typename __allocator_traits_rebind<_Alloc, _Tp>::type; + using _TpAlloc = typename __allocator_traits_rebind<_Alloc, __remove_cv_t<_Tp> >::type; _TpAlloc __tmp(*__get_alloc()); allocator_traits<_TpAlloc>::construct(__tmp, __get_elem(), std::forward<_Args>(__args)...); } @@ -278,7 +278,7 @@ struct __shared_ptr_emplace : __shared_weak_count { template ::value, int> = 0> _LIBCPP_HIDE_FROM_ABI void __on_zero_shared_impl() _NOEXCEPT { - using _TpAlloc = typename __allocator_traits_rebind<_Allocator, _Tp>::type; + using _TpAlloc = typename __allocator_traits_rebind<_Allocator, __remove_cv_t<_Tp> >::type; _TpAlloc __tmp(*__get_alloc()); allocator_traits<_TpAlloc>::destroy(__tmp, __get_elem()); } @@ -403,6 +403,9 @@ struct __shared_ptr_deleter_ctor_reqs { __well_formed_deleter<_Dp, _Yp*>::value; }; +template +using __shared_ptr_nullptr_deleter_ctor_reqs = _And, __well_formed_deleter<_Dp, nullptr_t> >; + #if defined(_LIBCPP_ABI_ENABLE_SHARED_PTR_TRIVIAL_ABI) # define _LIBCPP_SHARED_PTR_TRIVIAL_ABI __attribute__((__trivial_abi__)) #else @@ -411,6 +414,8 @@ struct __shared_ptr_deleter_ctor_reqs { template class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS shared_ptr { + struct __nullptr_sfinae_tag {}; + public: #if _LIBCPP_STD_VER >= 17 typedef weak_ptr<_Tp> weak_type; @@ -503,7 +508,11 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS shared_ptr { } template - _LIBCPP_HIDE_FROM_ABI shared_ptr(nullptr_t __p, _Dp __d) : __ptr_(nullptr) { + _LIBCPP_HIDE_FROM_ABI shared_ptr( + nullptr_t __p, + _Dp __d, + __enable_if_t<__shared_ptr_nullptr_deleter_ctor_reqs<_Dp>::value, __nullptr_sfinae_tag> = __nullptr_sfinae_tag()) + : __ptr_(nullptr) { #ifndef _LIBCPP_HAS_NO_EXCEPTIONS try { #endif // _LIBCPP_HAS_NO_EXCEPTIONS @@ -523,7 +532,12 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS shared_ptr { } template - _LIBCPP_HIDE_FROM_ABI shared_ptr(nullptr_t __p, _Dp __d, _Alloc __a) : __ptr_(nullptr) { + _LIBCPP_HIDE_FROM_ABI shared_ptr( + nullptr_t __p, + _Dp __d, + _Alloc __a, + __enable_if_t<__shared_ptr_nullptr_deleter_ctor_reqs<_Dp>::value, __nullptr_sfinae_tag> = __nullptr_sfinae_tag()) + : __ptr_(nullptr) { #ifndef _LIBCPP_HAS_NO_EXCEPTIONS try { #endif // _LIBCPP_HAS_NO_EXCEPTIONS @@ -598,8 +612,8 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS shared_ptr { #if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR) template ::value, int> = 0> _LIBCPP_HIDE_FROM_ABI shared_ptr(auto_ptr<_Yp>&& __r) : __ptr_(__r.get()) { - typedef __shared_ptr_pointer<_Yp*, default_delete<_Yp>, allocator<_Yp> > _CntrlBlk; - __cntrl_ = new _CntrlBlk(__r.get(), default_delete<_Yp>(), allocator<_Yp>()); + typedef __shared_ptr_pointer<_Yp*, default_delete<_Yp>, allocator<__remove_cv_t<_Yp> > > _CntrlBlk; + __cntrl_ = new _CntrlBlk(__r.get(), default_delete<_Yp>(), allocator<__remove_cv_t<_Yp> >()); __enable_weak_this(__r.get(), __r.get()); __r.release(); } @@ -776,7 +790,7 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS shared_ptr { private: template ::value> struct __shared_ptr_default_allocator { - typedef allocator<_Yp> type; + typedef allocator<__remove_cv_t<_Yp> > type; }; template @@ -834,7 +848,7 @@ _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> allocate_shared(const _Alloc& __a, _Args&& template ::value, int> = 0> _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> make_shared(_Args&&... __args) { - return std::allocate_shared<_Tp>(allocator<_Tp>(), std::forward<_Args>(__args)...); + return std::allocate_shared<_Tp>(allocator<__remove_cv_t<_Tp> >(), std::forward<_Args>(__args)...); } #if _LIBCPP_STD_VER >= 20 @@ -848,7 +862,7 @@ _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> allocate_shared_for_overwrite(const _Alloc template ::value, int> = 0> _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> make_shared_for_overwrite() { - return std::allocate_shared_for_overwrite<_Tp>(allocator<_Tp>()); + return std::allocate_shared_for_overwrite<_Tp>(allocator<__remove_cv_t<_Tp>>()); } #endif // _LIBCPP_STD_VER >= 20 diff --git a/libcxx/include/__numeric/gcd_lcm.h b/libcxx/include/__numeric/gcd_lcm.h index 87ebbae0157f55..9be6cf8516b131 100644 --- a/libcxx/include/__numeric/gcd_lcm.h +++ b/libcxx/include/__numeric/gcd_lcm.h @@ -37,7 +37,7 @@ struct __ct_abs; template struct __ct_abs<_Result, _Source, true> { - _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI _Result operator()(_Source __t) const noexcept { + constexpr _LIBCPP_HIDE_FROM_ABI _Result operator()(_Source __t) const noexcept { if (__t >= 0) return __t; if (__t == numeric_limits<_Source>::min()) @@ -48,11 +48,11 @@ struct __ct_abs<_Result, _Source, true> { template struct __ct_abs<_Result, _Source, false> { - _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI _Result operator()(_Source __t) const noexcept { return __t; } + constexpr _LIBCPP_HIDE_FROM_ABI _Result operator()(_Source __t) const noexcept { return __t; } }; template -_LIBCPP_CONSTEXPR _LIBCPP_HIDDEN _Tp __gcd(_Tp __a, _Tp __b) { +constexpr _LIBCPP_HIDDEN _Tp __gcd(_Tp __a, _Tp __b) { static_assert(!is_signed<_Tp>::value, ""); // From: https://lemire.me/blog/2013/12/26/fastest-way-to-compute-the-greatest-common-divisor @@ -96,7 +96,7 @@ _LIBCPP_CONSTEXPR _LIBCPP_HIDDEN _Tp __gcd(_Tp __a, _Tp __b) { } template -_LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI common_type_t<_Tp, _Up> gcd(_Tp __m, _Up __n) { +constexpr _LIBCPP_HIDE_FROM_ABI common_type_t<_Tp, _Up> gcd(_Tp __m, _Up __n) { static_assert(is_integral<_Tp>::value && is_integral<_Up>::value, "Arguments to gcd must be integer types"); static_assert(!is_same<__remove_cv_t<_Tp>, bool>::value, "First argument to gcd cannot be bool"); static_assert(!is_same<__remove_cv_t<_Up>, bool>::value, "Second argument to gcd cannot be bool"); @@ -107,7 +107,7 @@ _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI common_type_t<_Tp, _Up> gcd(_Tp __m, _Up } template -_LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI common_type_t<_Tp, _Up> lcm(_Tp __m, _Up __n) { +constexpr _LIBCPP_HIDE_FROM_ABI common_type_t<_Tp, _Up> lcm(_Tp __m, _Up __n) { static_assert(is_integral<_Tp>::value && is_integral<_Up>::value, "Arguments to lcm must be integer types"); static_assert(!is_same<__remove_cv_t<_Tp>, bool>::value, "First argument to lcm cannot be bool"); static_assert(!is_same<__remove_cv_t<_Up>, bool>::value, "Second argument to lcm cannot be bool"); @@ -117,11 +117,13 @@ _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI common_type_t<_Tp, _Up> lcm(_Tp __m, _Up using _Rp = common_type_t<_Tp, _Up>; _Rp __val1 = __ct_abs<_Rp, _Tp>()(__m) / std::gcd(__m, __n); _Rp __val2 = __ct_abs<_Rp, _Up>()(__n); - _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN((numeric_limits<_Rp>::max() / __val1 > __val2), "Overflow in lcm"); - return __val1 * __val2; + _Rp __res; + [[maybe_unused]] bool __overflow = __builtin_mul_overflow(__val1, __val2, &__res); + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(!__overflow, "Overflow in lcm"); + return __res; } -#endif // _LIBCPP_STD_VER +#endif // _LIBCPP_STD_VER >= 17 _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__random/discard_block_engine.h b/libcxx/include/__random/discard_block_engine.h index 9279fb66f6942c..07f599067279e6 100644 --- a/libcxx/include/__random/discard_block_engine.h +++ b/libcxx/include/__random/discard_block_engine.h @@ -50,8 +50,8 @@ class _LIBCPP_TEMPLATE_VIS discard_block_engine { static const result_type _Min = _Engine::_Min; static const result_type _Max = _Engine::_Max; #else - static _LIBCPP_CONSTEXPR const result_type _Min = _Engine::min(); - static _LIBCPP_CONSTEXPR const result_type _Max = _Engine::max(); + static constexpr result_type _Min = _Engine::min(); + static constexpr result_type _Max = _Engine::max(); #endif _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR result_type min() { return _Engine::min(); } diff --git a/libcxx/include/__ranges/iota_view.h b/libcxx/include/__ranges/iota_view.h index 9e6f724241ccf1..c0f5ed936a66d9 100644 --- a/libcxx/include/__ranges/iota_view.h +++ b/libcxx/include/__ranges/iota_view.h @@ -22,7 +22,6 @@ #include <__concepts/semiregular.h> #include <__concepts/totally_ordered.h> #include <__config> -#include <__functional/ranges_operations.h> #include <__iterator/concepts.h> #include <__iterator/incrementable_traits.h> #include <__iterator/iterator_traits.h> @@ -313,8 +312,8 @@ class iota_view : public view_interface> { : __value_(std::move(__value)), __bound_sentinel_(std::move(__bound_sentinel)) { // Validate the precondition if possible. if constexpr (totally_ordered_with<_Start, _BoundSentinel>) { - _LIBCPP_ASSERT_UNCATEGORIZED( - ranges::less_equal()(__value_, __bound_sentinel_), "Precondition violated: value is greater than bound."); + _LIBCPP_ASSERT_VALID_INPUT_RANGE( + bool(__value_ <= __bound_sentinel_), "iota_view: bound must be reachable from value"); } } diff --git a/libcxx/include/__string/char_traits.h b/libcxx/include/__string/char_traits.h index 9d347b188ee148..40821f86465b89 100644 --- a/libcxx/include/__string/char_traits.h +++ b/libcxx/include/__string/char_traits.h @@ -270,26 +270,26 @@ struct _LIBCPP_TEMPLATE_VIS char_traits { static inline _LIBCPP_HIDE_FROM_ABI constexpr bool lt(char_type __c1, char_type __c2) noexcept { return __c1 < __c2; } static _LIBCPP_HIDE_FROM_ABI constexpr int - compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT { + compare(const char_type* __s1, const char_type* __s2, size_t __n) noexcept { return std::__constexpr_memcmp(__s1, __s2, __element_count(__n)); } - static _LIBCPP_HIDE_FROM_ABI constexpr size_t length(const char_type* __str) _NOEXCEPT { + static _LIBCPP_HIDE_FROM_ABI constexpr size_t length(const char_type* __str) noexcept { return std::__constexpr_strlen(__str); } _LIBCPP_HIDE_FROM_ABI static constexpr const char_type* - find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT { + find(const char_type* __s, size_t __n, const char_type& __a) noexcept { return std::__constexpr_memchr(__s, __a, __n); } static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type* - move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT { + move(char_type* __s1, const char_type* __s2, size_t __n) noexcept { return std::__constexpr_memmove(__s1, __s2, __element_count(__n)); } static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type* - copy(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT { + copy(char_type* __s1, const char_type* __s2, size_t __n) noexcept { _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(!std::__is_pointer_in_range(__s1, __s1 + __n, __s2), "char_traits::copy: source and destination ranges overlap"); std::__constexpr_memmove(__s1, __s2, __element_count(__n)); @@ -297,7 +297,7 @@ struct _LIBCPP_TEMPLATE_VIS char_traits { } static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type* - assign(char_type* __s, size_t __n, char_type __a) _NOEXCEPT { + assign(char_type* __s, size_t __n, char_type __a) noexcept { std::fill_n(__s, __n, __a); return __s; } diff --git a/libcxx/include/__type_traits/common_type.h b/libcxx/include/__type_traits/common_type.h index 7f86fcaaace444..f6bd9ed71b7a47 100644 --- a/libcxx/include/__type_traits/common_type.h +++ b/libcxx/include/__type_traits/common_type.h @@ -82,9 +82,9 @@ struct _LIBCPP_TEMPLATE_VIS common_type<_Tp> : public common_type<_Tp, _Tp> {}; // sub-bullet 1 - "If is_same_v is false or ..." template struct _LIBCPP_TEMPLATE_VIS common_type<_Tp, _Up> - : conditional<_IsSame<_Tp, __decay_t<_Tp> >::value && _IsSame<_Up, __decay_t<_Up> >::value, - __common_type2_imp<_Tp, _Up>, - common_type<__decay_t<_Tp>, __decay_t<_Up> > >::type {}; + : __conditional_t<_IsSame<_Tp, __decay_t<_Tp> >::value && _IsSame<_Up, __decay_t<_Up> >::value, + __common_type2_imp<_Tp, _Up>, + common_type<__decay_t<_Tp>, __decay_t<_Up> > > {}; // bullet 4 - sizeof...(Tp) > 2 diff --git a/libcxx/include/__type_traits/decay.h b/libcxx/include/__type_traits/decay.h index 95dccaa29cbe19..7412044f931796 100644 --- a/libcxx/include/__type_traits/decay.h +++ b/libcxx/include/__type_traits/decay.h @@ -43,11 +43,11 @@ struct __decay { template struct __decay<_Up, true> { public: - typedef _LIBCPP_NODEBUG typename conditional< - is_array<_Up>::value, - __add_pointer_t<__remove_extent_t<_Up> >, - typename conditional::value, typename add_pointer<_Up>::type, __remove_cv_t<_Up> >::type >::type - type; + typedef _LIBCPP_NODEBUG + __conditional_t::value, + __add_pointer_t<__remove_extent_t<_Up> >, + __conditional_t::value, typename add_pointer<_Up>::type, __remove_cv_t<_Up> > > + type; }; template diff --git a/libcxx/include/__type_traits/is_nothrow_destructible.h b/libcxx/include/__type_traits/is_nothrow_destructible.h index 370ba27ecd1f1c..c2d5ca87232aa1 100644 --- a/libcxx/include/__type_traits/is_nothrow_destructible.h +++ b/libcxx/include/__type_traits/is_nothrow_destructible.h @@ -12,9 +12,6 @@ #include <__config> #include <__type_traits/integral_constant.h> #include <__type_traits/is_destructible.h> -#include <__type_traits/is_reference.h> -#include <__type_traits/is_scalar.h> -#include <__type_traits/remove_all_extents.h> #include <__utility/declval.h> #include @@ -24,7 +21,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD -#if !defined(_LIBCPP_CXX03_LANG) +#if __has_builtin(__is_nothrow_destructible) + +template +struct _LIBCPP_TEMPLATE_VIS is_nothrow_destructible : integral_constant {}; + +#else template struct __libcpp_is_nothrow_destructible; @@ -49,20 +51,7 @@ struct _LIBCPP_TEMPLATE_VIS is_nothrow_destructible<_Tp&> : public true_type {}; template struct _LIBCPP_TEMPLATE_VIS is_nothrow_destructible<_Tp&&> : public true_type {}; -#else - -template -struct __libcpp_nothrow_destructor : public integral_constant::value || is_reference<_Tp>::value> { -}; - -template -struct _LIBCPP_TEMPLATE_VIS is_nothrow_destructible : public __libcpp_nothrow_destructor<__remove_all_extents_t<_Tp> > { -}; - -template -struct _LIBCPP_TEMPLATE_VIS is_nothrow_destructible<_Tp[]> : public false_type {}; - -#endif +#endif // __has_builtin(__is_nothrow_destructible) #if _LIBCPP_STD_VER >= 17 template diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h index 2da434e0fea41b..0afbebcdc9f2ae 100644 --- a/libcxx/include/__utility/pair.h +++ b/libcxx/include/__utility/pair.h @@ -135,16 +135,16 @@ struct _LIBCPP_TEMPLATE_VIS pair typename conditional< _MaybeEnable, _CheckArgs, __check_tuple_constructor_fail>::type; template ::__enable_default(), int> = 0> - explicit(!_CheckArgsDep<_Dummy>::__enable_implicit_default()) _LIBCPP_HIDE_FROM_ABI - _LIBCPP_CONSTEXPR pair() _NOEXCEPT_( - is_nothrow_default_constructible::value&& is_nothrow_default_constructible::value) + explicit(!_CheckArgsDep<_Dummy>::__enable_implicit_default()) _LIBCPP_HIDE_FROM_ABI constexpr pair() noexcept( + is_nothrow_default_constructible::value && is_nothrow_default_constructible::value) : first(), second() {} template ::template __is_pair_constructible<_T1 const&, _T2 const&>(), int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit( - !_CheckArgsDep<_Dummy>::template __is_implicit<_T1 const&, _T2 const&>()) pair(_T1 const& __t1, _T2 const& __t2) - _NOEXCEPT_(is_nothrow_copy_constructible::value&& is_nothrow_copy_constructible::value) + _LIBCPP_HIDE_FROM_ABI + _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_CheckArgsDep<_Dummy>::template __is_implicit<_T1 const&, _T2 const&>()) + pair(_T1 const& __t1, _T2 const& __t2) noexcept(is_nothrow_copy_constructible::value && + is_nothrow_copy_constructible::value) : first(__t1), second(__t2) {} template < @@ -156,10 +156,9 @@ struct _LIBCPP_TEMPLATE_VIS pair class _U2, # endif __enable_if_t<_CheckArgs::template __is_pair_constructible<_U1, _U2>(), int> = 0 > - _LIBCPP_HIDE_FROM_ABI - _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_CheckArgs::template __is_implicit<_U1, _U2>()) pair(_U1&& __u1, _U2&& __u2) - _NOEXCEPT_((is_nothrow_constructible::value && - is_nothrow_constructible::value)) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_CheckArgs::template __is_implicit<_U1, _U2>()) + pair(_U1&& __u1, _U2&& __u2) noexcept(is_nothrow_constructible::value && + is_nothrow_constructible::value) : first(std::forward<_U1>(__u1)), second(std::forward<_U2>(__u2)) { } @@ -176,16 +175,14 @@ struct _LIBCPP_TEMPLATE_VIS pair __enable_if_t<_CheckArgs::template __is_pair_constructible<_U1 const&, _U2 const&>(), int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_CheckArgs::template __is_implicit<_U1 const&, _U2 const&>()) - pair(pair<_U1, _U2> const& __p) - _NOEXCEPT_((is_nothrow_constructible::value && - is_nothrow_constructible::value)) + pair(pair<_U1, _U2> const& __p) noexcept(is_nothrow_constructible::value && + is_nothrow_constructible::value) : first(__p.first), second(__p.second) {} template (), int> = 0> - _LIBCPP_HIDE_FROM_ABI - _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_CheckArgs::template __is_implicit<_U1, _U2>()) pair(pair<_U1, _U2>&& __p) - _NOEXCEPT_((is_nothrow_constructible::value && - is_nothrow_constructible::value)) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_CheckArgs::template __is_implicit<_U1, _U2>()) + pair(pair<_U1, _U2>&& __p) noexcept(is_nothrow_constructible::value && + is_nothrow_constructible::value) : first(std::forward<_U1>(__p.first)), second(std::forward<_U2>(__p.second)) {} # if _LIBCPP_STD_VER >= 23 @@ -219,8 +216,8 @@ struct _LIBCPP_TEMPLATE_VIS pair template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 - pair(piecewise_construct_t __pc, tuple<_Args1...> __first_args, tuple<_Args2...> __second_args) _NOEXCEPT_( - is_nothrow_constructible::value&& is_nothrow_constructible::value) + pair(piecewise_construct_t __pc, tuple<_Args1...> __first_args, tuple<_Args2...> __second_args) noexcept( + is_nothrow_constructible::value && is_nothrow_constructible::value) : pair(__pc, __first_args, __second_args, @@ -228,19 +225,19 @@ struct _LIBCPP_TEMPLATE_VIS pair typename __make_tuple_indices::type()) {} _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair& - operator=(__conditional_t< is_copy_assignable::value && is_copy_assignable::value, - pair, - __nat> const& __p) - _NOEXCEPT_(is_nothrow_copy_assignable::value&& is_nothrow_copy_assignable::value) { + operator=(__conditional_t::value && is_copy_assignable::value, + pair, + __nat> const& __p) noexcept(is_nothrow_copy_assignable::value && + is_nothrow_copy_assignable::value) { first = __p.first; second = __p.second; return *this; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair& operator=( - __conditional_t< is_move_assignable::value && is_move_assignable::value, pair, __nat>&& - __p) - _NOEXCEPT_(is_nothrow_move_assignable::value&& is_nothrow_move_assignable::value) { + __conditional_t::value && is_move_assignable::value, pair, __nat>&& + __p) noexcept(is_nothrow_move_assignable::value && + is_nothrow_move_assignable::value) { first = std::forward(__p.first); second = std::forward(__p.second); return *this; diff --git a/libcxx/include/deque b/libcxx/include/deque index 09888cc7ba78cc..aee4764859dd20 100644 --- a/libcxx/include/deque +++ b/libcxx/include/deque @@ -449,11 +449,11 @@ public: using value_type = _Tp; - static_assert(is_same::value, - "Allocator::value_type must be same type as value_type"); - using allocator_type = _Allocator; using __alloc_traits = allocator_traits; + static_assert(__check_valid_allocator::value, ""); + static_assert(is_same::value, + "Allocator::value_type must be same type as value_type"); using size_type = typename __alloc_traits::size_type; using difference_type = typename __alloc_traits::difference_type; @@ -488,9 +488,6 @@ public: deque, void>; - static_assert(is_same >::value, - "[allocator.requirements] states that rebinding an allocator to the same type should result in the " - "original allocator"); static_assert(is_nothrow_default_constructible::value == is_nothrow_default_constructible<__pointer_allocator>::value, "rebinding an allocator should not change exception guarantees"); @@ -632,11 +629,11 @@ public: return *this; } - _LIBCPP_HIDE_FROM_ABI deque(deque&& __c) _NOEXCEPT_(is_nothrow_move_constructible::value); + _LIBCPP_HIDE_FROM_ABI deque(deque&& __c) noexcept(is_nothrow_move_constructible::value); _LIBCPP_HIDE_FROM_ABI deque(deque&& __c, const __type_identity_t& __a); - _LIBCPP_HIDE_FROM_ABI deque& operator=(deque&& __c) - _NOEXCEPT_(__alloc_traits::propagate_on_container_move_assignment::value&& - is_nothrow_move_assignable::value); + _LIBCPP_HIDE_FROM_ABI deque& + operator=(deque&& __c) noexcept(__alloc_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable::value); _LIBCPP_HIDE_FROM_ABI void assign(initializer_list __il) { assign(__il.begin(), __il.end()); } #endif // _LIBCPP_CXX03_LANG @@ -1309,7 +1306,7 @@ deque<_Tp, _Allocator>::deque(initializer_list __il, const allocator } template -inline deque<_Tp, _Allocator>::deque(deque&& __c) _NOEXCEPT_(is_nothrow_move_constructible::value) +inline deque<_Tp, _Allocator>::deque(deque&& __c) noexcept(is_nothrow_move_constructible::value) : __map_(std::move(__c.__map_)), __start_(std::move(__c.__start_)), __size_(std::move(__c.__size_)) { __c.__start_ = 0; __c.__size() = 0; @@ -1333,8 +1330,9 @@ inline deque<_Tp, _Allocator>::deque(deque&& __c, const __type_identity_t -inline deque<_Tp, _Allocator>& deque<_Tp, _Allocator>::operator=(deque&& __c) _NOEXCEPT_( - __alloc_traits::propagate_on_container_move_assignment::value&& is_nothrow_move_assignable::value) { +inline deque<_Tp, _Allocator>& deque<_Tp, _Allocator>::operator=(deque&& __c) noexcept( + __alloc_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable::value) { __move_assign(__c, integral_constant()); return *this; } @@ -1349,8 +1347,8 @@ void deque<_Tp, _Allocator>::__move_assign(deque& __c, false_type) { } template -void deque<_Tp, _Allocator>::__move_assign(deque& __c, true_type) - _NOEXCEPT_(is_nothrow_move_assignable::value) { +void deque<_Tp, _Allocator>::__move_assign(deque& __c, + true_type) noexcept(is_nothrow_move_assignable::value) { clear(); shrink_to_fit(); __move_assign(__c); diff --git a/libcxx/include/experimental/__simd/reference.h b/libcxx/include/experimental/__simd/reference.h index 7efbba96ec71b1..af61dbcc2fe92d 100644 --- a/libcxx/include/experimental/__simd/reference.h +++ b/libcxx/include/experimental/__simd/reference.h @@ -13,10 +13,14 @@ #include <__type_traits/is_assignable.h> #include <__type_traits/is_same.h> #include <__utility/forward.h> +#include <__utility/move.h> #include #include #include +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + #if _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL) _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL @@ -55,10 +59,47 @@ class __simd_reference { __set(static_cast(std::forward<_Up>(__v))); return {__s_, __idx_}; } + + // Note: This approach might not fully align with the specification, + // which might be a wording defect. (https://wg21.link/N4808 section 9.6.3) + template + friend void + swap(__simd_reference<_Tp1, _Storage1, _Vp1>&& __a, __simd_reference<_Tp1, _Storage1, _Vp1>&& __b) noexcept; + + template + friend void swap(_Vp1& __a, __simd_reference<_Tp1, _Storage1, _Vp1>&& __b) noexcept; + + template + friend void swap(__simd_reference<_Tp1, _Storage1, _Vp1>&& __a, _Vp1& __b) noexcept; }; +template +_LIBCPP_HIDE_FROM_ABI void +swap(__simd_reference<_Tp, _Storage, _Vp>&& __a, __simd_reference<_Tp, _Storage, _Vp>&& __b) noexcept { + _Vp __tmp(std::move(__a)); + std::move(__a) = std::move(__b); + std::move(__b) = std::move(__tmp); +} + +template +_LIBCPP_HIDE_FROM_ABI void swap(_Vp& __a, __simd_reference<_Tp, _Storage, _Vp>&& __b) noexcept { + _Vp __tmp(std::move(__a)); + __a = std::move(__b); + std::move(__b) = std::move(__tmp); +} + +template +_LIBCPP_HIDE_FROM_ABI void swap(__simd_reference<_Tp, _Storage, _Vp>&& __a, _Vp& __b) noexcept { + _Vp __tmp(std::move(__a)); + std::move(__a) = std::move(__b); + __b = std::move(__tmp); +} + } // namespace parallelism_v2 _LIBCPP_END_NAMESPACE_EXPERIMENTAL #endif // _LIBCPP_STD_VER >= 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL) + +_LIBCPP_POP_MACROS + #endif // _LIBCPP_EXPERIMENTAL___SIMD_REFERENCE_H diff --git a/libcxx/include/experimental/propagate_const b/libcxx/include/experimental/propagate_const index a30bba9effb142..d7a695d8388923 100644 --- a/libcxx/include/experimental/propagate_const +++ b/libcxx/include/experimental/propagate_const @@ -145,10 +145,10 @@ template class propagate_const; template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const _Up& get_underlying(const propagate_const<_Up>& __pu) _NOEXCEPT; +inline _LIBCPP_HIDE_FROM_ABI constexpr const _Up& get_underlying(const propagate_const<_Up>& __pu) _NOEXCEPT; template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Up& get_underlying(propagate_const<_Up>& __pu) _NOEXCEPT; +inline _LIBCPP_HIDE_FROM_ABI constexpr _Up& get_underlying(propagate_const<_Up>& __pu) _NOEXCEPT; template class propagate_const { @@ -164,22 +164,22 @@ public: private: template - static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR element_type* __get_pointer(_Up* __u) { + static _LIBCPP_HIDE_FROM_ABI constexpr element_type* __get_pointer(_Up* __u) { return __u; } template - static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR element_type* __get_pointer(_Up& __u) { + static _LIBCPP_HIDE_FROM_ABI constexpr element_type* __get_pointer(_Up& __u) { return __get_pointer(__u.get()); } template - static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const element_type* __get_pointer(const _Up* __u) { + static _LIBCPP_HIDE_FROM_ABI constexpr const element_type* __get_pointer(const _Up* __u) { return __u; } template - static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const element_type* __get_pointer(const _Up& __u) { + static _LIBCPP_HIDE_FROM_ABI constexpr const element_type* __get_pointer(const _Up& __u) { return __get_pointer(__u.get()); } @@ -193,214 +193,207 @@ private: public: template - friend _LIBCPP_CONSTEXPR const _Up& - experimental::fundamentals_v2::get_underlying(const propagate_const<_Up>& __pu) _NOEXCEPT; + friend constexpr const _Up& experimental::fundamentals_v2::get_underlying(const propagate_const<_Up>& __pu) _NOEXCEPT; template - friend _LIBCPP_CONSTEXPR _Up& experimental::fundamentals_v2::get_underlying(propagate_const<_Up>& __pu) _NOEXCEPT; + friend constexpr _Up& experimental::fundamentals_v2::get_underlying(propagate_const<_Up>& __pu) _NOEXCEPT; - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR propagate_const() = default; + _LIBCPP_HIDE_FROM_ABI constexpr propagate_const() = default; propagate_const(const propagate_const&) = delete; - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR propagate_const(propagate_const&&) = default; + _LIBCPP_HIDE_FROM_ABI constexpr propagate_const(propagate_const&&) = default; template ::value && is_constructible<_Tp, _Up&&>::value, bool> = true> - explicit _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR propagate_const(propagate_const<_Up>&& __pu) + explicit _LIBCPP_HIDE_FROM_ABI constexpr propagate_const(propagate_const<_Up>&& __pu) : __t_(std::move(experimental::get_underlying(__pu))) {} template ::value && is_constructible<_Tp, _Up&&>::value, bool> = false> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR propagate_const(propagate_const<_Up>&& __pu) + _LIBCPP_HIDE_FROM_ABI constexpr propagate_const(propagate_const<_Up>&& __pu) : __t_(std::move(experimental::get_underlying(__pu))) {} template ::value && is_constructible<_Tp, _Up&&>::value && !__is_propagate_const>::value, bool> = true> - explicit _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR propagate_const(_Up&& __u) : __t_(std::forward<_Up>(__u)) {} + explicit _LIBCPP_HIDE_FROM_ABI constexpr propagate_const(_Up&& __u) : __t_(std::forward<_Up>(__u)) {} template ::value && is_constructible<_Tp, _Up&&>::value && !__is_propagate_const>::value, bool> = false> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR propagate_const(_Up&& __u) : __t_(std::forward<_Up>(__u)) {} + _LIBCPP_HIDE_FROM_ABI constexpr propagate_const(_Up&& __u) : __t_(std::forward<_Up>(__u)) {} propagate_const& operator=(const propagate_const&) = delete; - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR propagate_const& operator=(propagate_const&&) = default; + _LIBCPP_HIDE_FROM_ABI constexpr propagate_const& operator=(propagate_const&&) = default; template - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR propagate_const& operator=(propagate_const<_Up>&& __pu) { + _LIBCPP_HIDE_FROM_ABI constexpr propagate_const& operator=(propagate_const<_Up>&& __pu) { __t_ = std::move(experimental::get_underlying(__pu)); return *this; } template >::value>> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR propagate_const& operator=(_Up&& __u) { + _LIBCPP_HIDE_FROM_ABI constexpr propagate_const& operator=(_Up&& __u) { __t_ = std::forward<_Up>(__u); return *this; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const element_type* get() const { return __get_pointer(__t_); } + _LIBCPP_HIDE_FROM_ABI constexpr const element_type* get() const { return __get_pointer(__t_); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR element_type* get() { return __get_pointer(__t_); } + _LIBCPP_HIDE_FROM_ABI constexpr element_type* get() { return __get_pointer(__t_); } - _LIBCPP_HIDE_FROM_ABI explicit _LIBCPP_CONSTEXPR operator bool() const { return get() != nullptr; } + _LIBCPP_HIDE_FROM_ABI explicit constexpr operator bool() const { return get() != nullptr; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const element_type* operator->() const { return get(); } + _LIBCPP_HIDE_FROM_ABI constexpr const element_type* operator->() const { return get(); } template ::value>> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR operator const element_type*() const { + _LIBCPP_HIDE_FROM_ABI constexpr operator const element_type*() const { return get(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const element_type& operator*() const { return *get(); } + _LIBCPP_HIDE_FROM_ABI constexpr const element_type& operator*() const { return *get(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR element_type* operator->() { return get(); } + _LIBCPP_HIDE_FROM_ABI constexpr element_type* operator->() { return get(); } template ::value>> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR operator element_type*() { + _LIBCPP_HIDE_FROM_ABI constexpr operator element_type*() { return get(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR element_type& operator*() { return *get(); } + _LIBCPP_HIDE_FROM_ABI constexpr element_type& operator*() { return *get(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR void swap(propagate_const& __pt) _NOEXCEPT_(__is_nothrow_swappable_v<_Tp>) { + _LIBCPP_HIDE_FROM_ABI constexpr void swap(propagate_const& __pt) noexcept(__is_nothrow_swappable_v<_Tp>) { using std::swap; swap(__t_, __pt.__t_); } }; template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator==(const propagate_const<_Tp>& __pt, nullptr_t) { +_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const propagate_const<_Tp>& __pt, nullptr_t) { return experimental::get_underlying(__pt) == nullptr; } template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator==(nullptr_t, const propagate_const<_Tp>& __pt) { +_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(nullptr_t, const propagate_const<_Tp>& __pt) { return nullptr == experimental::get_underlying(__pt); } template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator!=(const propagate_const<_Tp>& __pt, nullptr_t) { +_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const propagate_const<_Tp>& __pt, nullptr_t) { return experimental::get_underlying(__pt) != nullptr; } template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator!=(nullptr_t, const propagate_const<_Tp>& __pt) { +_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(nullptr_t, const propagate_const<_Tp>& __pt) { return nullptr != experimental::get_underlying(__pt); } template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool -operator==(const propagate_const<_Tp>& __pt, const propagate_const<_Up>& __pu) { +_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const propagate_const<_Tp>& __pt, const propagate_const<_Up>& __pu) { return experimental::get_underlying(__pt) == experimental::get_underlying(__pu); } template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool -operator!=(const propagate_const<_Tp>& __pt, const propagate_const<_Up>& __pu) { +_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const propagate_const<_Tp>& __pt, const propagate_const<_Up>& __pu) { return experimental::get_underlying(__pt) != experimental::get_underlying(__pu); } template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool -operator<(const propagate_const<_Tp>& __pt, const propagate_const<_Up>& __pu) { +_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const propagate_const<_Tp>& __pt, const propagate_const<_Up>& __pu) { return experimental::get_underlying(__pt) < experimental::get_underlying(__pu); } template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool -operator>(const propagate_const<_Tp>& __pt, const propagate_const<_Up>& __pu) { +_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const propagate_const<_Tp>& __pt, const propagate_const<_Up>& __pu) { return experimental::get_underlying(__pt) > experimental::get_underlying(__pu); } template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool -operator<=(const propagate_const<_Tp>& __pt, const propagate_const<_Up>& __pu) { +_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const propagate_const<_Tp>& __pt, const propagate_const<_Up>& __pu) { return experimental::get_underlying(__pt) <= experimental::get_underlying(__pu); } template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool -operator>=(const propagate_const<_Tp>& __pt, const propagate_const<_Up>& __pu) { +_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const propagate_const<_Tp>& __pt, const propagate_const<_Up>& __pu) { return experimental::get_underlying(__pt) >= experimental::get_underlying(__pu); } template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator==(const propagate_const<_Tp>& __pt, const _Up& __u) { +_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const propagate_const<_Tp>& __pt, const _Up& __u) { return experimental::get_underlying(__pt) == __u; } template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator!=(const propagate_const<_Tp>& __pt, const _Up& __u) { +_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const propagate_const<_Tp>& __pt, const _Up& __u) { return experimental::get_underlying(__pt) != __u; } template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator<(const propagate_const<_Tp>& __pt, const _Up& __u) { +_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const propagate_const<_Tp>& __pt, const _Up& __u) { return experimental::get_underlying(__pt) < __u; } template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator>(const propagate_const<_Tp>& __pt, const _Up& __u) { +_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const propagate_const<_Tp>& __pt, const _Up& __u) { return experimental::get_underlying(__pt) > __u; } template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator<=(const propagate_const<_Tp>& __pt, const _Up& __u) { +_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const propagate_const<_Tp>& __pt, const _Up& __u) { return experimental::get_underlying(__pt) <= __u; } template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator>=(const propagate_const<_Tp>& __pt, const _Up& __u) { +_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const propagate_const<_Tp>& __pt, const _Up& __u) { return experimental::get_underlying(__pt) >= __u; } template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator==(const _Tp& __t, const propagate_const<_Up>& __pu) { +_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const _Tp& __t, const propagate_const<_Up>& __pu) { return __t == experimental::get_underlying(__pu); } template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator!=(const _Tp& __t, const propagate_const<_Up>& __pu) { +_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const _Tp& __t, const propagate_const<_Up>& __pu) { return __t != experimental::get_underlying(__pu); } template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator<(const _Tp& __t, const propagate_const<_Up>& __pu) { +_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const _Tp& __t, const propagate_const<_Up>& __pu) { return __t < experimental::get_underlying(__pu); } template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator>(const _Tp& __t, const propagate_const<_Up>& __pu) { +_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const _Tp& __t, const propagate_const<_Up>& __pu) { return __t > experimental::get_underlying(__pu); } template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator<=(const _Tp& __t, const propagate_const<_Up>& __pu) { +_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const _Tp& __t, const propagate_const<_Up>& __pu) { return __t <= experimental::get_underlying(__pu); } template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator>=(const _Tp& __t, const propagate_const<_Up>& __pu) { +_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const _Tp& __t, const propagate_const<_Up>& __pu) { return __t >= experimental::get_underlying(__pu); } template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR void swap(propagate_const<_Tp>& __pc1, propagate_const<_Tp>& __pc2) - _NOEXCEPT_(__is_nothrow_swappable_v<_Tp>) { +_LIBCPP_HIDE_FROM_ABI constexpr void +swap(propagate_const<_Tp>& __pc1, propagate_const<_Tp>& __pc2) noexcept(__is_nothrow_swappable_v<_Tp>) { __pc1.swap(__pc2); } template -_LIBCPP_CONSTEXPR const _Tp& get_underlying(const propagate_const<_Tp>& __pt) _NOEXCEPT { +constexpr const _Tp& get_underlying(const propagate_const<_Tp>& __pt) _NOEXCEPT { return __pt.__t_; } template -_LIBCPP_CONSTEXPR _Tp& get_underlying(propagate_const<_Tp>& __pt) _NOEXCEPT { +constexpr _Tp& get_underlying(propagate_const<_Tp>& __pt) _NOEXCEPT { return __pt.__t_; } diff --git a/libcxx/include/experimental/simd b/libcxx/include/experimental/simd index fad6431d13a193..484543b81daf1f 100644 --- a/libcxx/include/experimental/simd +++ b/libcxx/include/experimental/simd @@ -78,6 +78,7 @@ inline namespace parallelism_v2 { #include #include #include +#include #include #include #include diff --git a/libcxx/include/experimental/type_traits b/libcxx/include/experimental/type_traits index 37be434f8edd56..31b041bc94c43a 100644 --- a/libcxx/include/experimental/type_traits +++ b/libcxx/include/experimental/type_traits @@ -129,7 +129,7 @@ using is_detected = typename _DETECTOR::value_t; template