Merge branch 'main' into users/c8ef/generator
This commit is contained in:
commit
1ff848a50f
1042 changed files with 80624 additions and 58304 deletions
23
.github/workflows/libcxx-build-and-test.yaml
vendored
23
.github/workflows/libcxx-build-and-test.yaml
vendored
|
|
@ -198,13 +198,13 @@ jobs:
|
|||
matrix:
|
||||
include:
|
||||
- config: generic-cxx03
|
||||
os: macos-26
|
||||
xcode-version: 26.5
|
||||
- config: generic-cxx23
|
||||
os: macos-26
|
||||
xcode-version: 26.5
|
||||
- config: generic-modules
|
||||
os: macos-26
|
||||
xcode-version: 26.5
|
||||
- config: apple-configuration
|
||||
os: macos-26
|
||||
xcode-version: 26.5
|
||||
# TODO: These jobs are intended to test back-deployment (building against ToT libc++ but running against an
|
||||
# older system-provided libc++.dylib). Doing this properly would require building the test suite on a
|
||||
# recent macOS using a recent Clang (hence recent Xcode), and then running the actual test suite on an
|
||||
|
|
@ -216,18 +216,19 @@ jobs:
|
|||
# macOS versions as a way to avoid rotting that configuration, but it doesn't provide a lot of additional
|
||||
# coverage.
|
||||
- config: apple-system
|
||||
os: macos-26
|
||||
xcode-version: 26.5
|
||||
- config: apple-system-hardened
|
||||
os: macos-26
|
||||
runs-on: ${{ matrix.os }}
|
||||
xcode-version: 26.5
|
||||
runs-on: ["self-hosted", "macOS", "apple-runners"]
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1.7.0
|
||||
with:
|
||||
# https://github.com/actions/runner-images/blob/main/images/macos/macos-26-Readme.md
|
||||
xcode-version: '26.4'
|
||||
- name: Select Xcode
|
||||
run: echo "DEVELOPER_DIR=/Applications/Xcode_${{ matrix.xcode-version }}.app/Contents/Developer" >> $GITHUB_ENV
|
||||
- name: Install Ninja and CMake
|
||||
run: |
|
||||
brew install ninja cmake
|
||||
- name: Build and test
|
||||
run: |
|
||||
python3 -m venv .venv
|
||||
|
|
|
|||
7
.github/workflows/release-binaries-all.yml
vendored
7
.github/workflows/release-binaries-all.yml
vendored
|
|
@ -68,6 +68,13 @@ jobs:
|
|||
release-version: ${{ steps.vars.outputs.release-version }}
|
||||
upload: ${{ steps.vars.outputs.upload }}
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: |
|
||||
.github/workflows/validate-release-version
|
||||
sparse-checkout-cone-mode: false
|
||||
|
||||
- name: Validate Input
|
||||
if: inputs.release-version != ''
|
||||
uses: ./.github/workflows/validate-release-version
|
||||
|
|
|
|||
10
.github/workflows/release-binaries.yml
vendored
10
.github/workflows/release-binaries.yml
vendored
|
|
@ -72,17 +72,17 @@ jobs:
|
|||
attestation-name: ${{ steps.vars.outputs.attestation-name }}
|
||||
|
||||
steps:
|
||||
- name: Checkout LLVM
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Validate Release Version
|
||||
if: inputs.release-version != ''
|
||||
uses: ./.github/workflows/validate-release-version
|
||||
with:
|
||||
release-version: ${{ inputs.release-version }}
|
||||
|
||||
- name: Checkout LLVM
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Check Permissions
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: ./.github/workflows/require-team-membership
|
||||
|
|
|
|||
6
.github/workflows/release-documentation.yml
vendored
6
.github/workflows/release-documentation.yml
vendored
|
|
@ -32,6 +32,12 @@ on:
|
|||
WWW_RELEASES_TOKEN:
|
||||
description: "Secret used to create a PR with the documentation changes."
|
||||
required: false
|
||||
LLVM_TOKEN_GENERATOR_CLIENT_ID:
|
||||
description: "Client ID for our GitHub App we use for generating access tokens."
|
||||
required: true
|
||||
LLVM_TOKEN_GENERATOR_PRIVATE_KEY:
|
||||
description: "Private key for our GitHub App we use for generating access tokens."
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
# This job checks permissions and validates inputs to prevent potential
|
||||
|
|
|
|||
|
|
@ -4500,9 +4500,9 @@ void BinaryFunction::calculateLoopInfo() {
|
|||
L->EntryCount = L->getHeader()->getExecutionCount() - L->TotalBackEdgeCount;
|
||||
|
||||
// Compute exit count.
|
||||
SmallVector<BinaryLoop::Edge, 1> ExitEdges;
|
||||
L->getExitEdges(ExitEdges);
|
||||
for (BinaryLoop::Edge &Exit : ExitEdges) {
|
||||
SmallVector<BinaryLoopInfo::Edge, 1> ExitEdges;
|
||||
BLI->getExitEdges(*L, ExitEdges);
|
||||
for (BinaryLoopInfo::Edge &Exit : ExitEdges) {
|
||||
const BinaryBasicBlock *Exiting = Exit.first;
|
||||
const BinaryBasicBlock *ExitTarget = Exit.second;
|
||||
auto BI = Exiting->branch_info_begin();
|
||||
|
|
|
|||
|
|
@ -15,10 +15,8 @@
|
|||
#include "bolt/RuntimeLibs/InstrumentationRuntimeLibrary.h"
|
||||
#include "bolt/Utils/CommandLineOpts.h"
|
||||
#include "bolt/Utils/Utils.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/RWMutex.h"
|
||||
#include <fstream>
|
||||
#include <queue>
|
||||
#include <stack>
|
||||
|
||||
|
|
@ -78,13 +76,6 @@ cl::opt<bool> InstrumentationWaitForks(
|
|||
"(use with instrumentation-sleep-time option)"),
|
||||
cl::init(false), cl::Optional, cl::cat(BoltInstrCategory));
|
||||
|
||||
cl::opt<std::string> InstrumentFuncsFile(
|
||||
"instrument-funcs-file",
|
||||
cl::desc("file with list of function names (one per line) to instrument; "
|
||||
"only functions whose name exactly matches a line in this file "
|
||||
"will be instrumented"),
|
||||
cl::Optional, cl::cat(BoltInstrCategory));
|
||||
|
||||
cl::opt<bool>
|
||||
InstrumentHotOnly("instrument-hot-only",
|
||||
cl::desc("only insert instrumentation on hot functions "
|
||||
|
|
@ -652,37 +643,9 @@ Error Instrumentation::runOnFunctions(BinaryContext &BC) {
|
|||
|
||||
createAuxiliaryFunctions(BC);
|
||||
|
||||
const bool HasInstrumentFuncsFilter = !opts::InstrumentFuncsFile.empty();
|
||||
StringSet<> InstrumentFuncsSet;
|
||||
if (HasInstrumentFuncsFilter) {
|
||||
std::ifstream FuncsFile(opts::InstrumentFuncsFile, std::ios::in);
|
||||
if (!FuncsFile)
|
||||
return createFatalBOLTError(Twine("instrument-funcs-file \"") +
|
||||
Twine(opts::InstrumentFuncsFile) +
|
||||
Twine("\" can't be opened."));
|
||||
std::string FuncName;
|
||||
while (std::getline(FuncsFile, FuncName))
|
||||
if (!FuncName.empty())
|
||||
InstrumentFuncsSet.insert(FuncName);
|
||||
}
|
||||
|
||||
ParallelUtilities::PredicateTy SkipPredicate = [&](const BinaryFunction &BF) {
|
||||
if (!BF.isSimple() || BF.isIgnored())
|
||||
return true;
|
||||
if (opts::InstrumentHotOnly && !BF.getKnownExecutionCount())
|
||||
return true;
|
||||
if (HasInstrumentFuncsFilter) {
|
||||
bool Found = false;
|
||||
for (const StringRef Name : BF.getNames()) {
|
||||
if (InstrumentFuncsSet.contains(Name)) {
|
||||
Found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!Found)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return (!BF.isSimple() || BF.isIgnored() ||
|
||||
(opts::InstrumentHotOnly && !BF.getKnownExecutionCount()));
|
||||
};
|
||||
|
||||
ParallelUtilities::WorkFuncWithAllocTy WorkFun =
|
||||
|
|
|
|||
|
|
@ -1,82 +0,0 @@
|
|||
# Test --instrument-funcs-file, alone and combined with --instrument-hot-only.
|
||||
#
|
||||
# The binary defines three functions (foo, bar, baz). We attach a profile that
|
||||
# only marks foo as hot. With --instrument-funcs-file listing foo and bar, only
|
||||
# those two are instrumented. Adding --instrument-hot-only further restricts
|
||||
# instrumentation to foo (the only function that is both listed and hot).
|
||||
|
||||
# REQUIRES: system-linux,bolt-runtime,target=x86_64-{{.*}}
|
||||
|
||||
# RUN: %clang %cflags %s -o %t.exe -Wl,-q
|
||||
# RUN: link_fdata %s %t.exe %t.fdata
|
||||
|
||||
# Funcs file lists foo and bar (baz is intentionally omitted).
|
||||
# RUN: echo "foo" > %t.funcs
|
||||
# RUN: echo "bar" >> %t.funcs
|
||||
|
||||
# Test A: only --instrument-funcs-file. Both foo and bar get instrumented.
|
||||
# RUN: llvm-bolt --instrument --instrument-funcs-file=%t.funcs \
|
||||
# RUN: -o %t.a.out %t.exe 2>&1 | FileCheck %s --check-prefix=CHECK-A
|
||||
|
||||
# Test B: --instrument-funcs-file combined with --instrument-hot-only. Profile
|
||||
# marks only foo as hot, so bar is filtered out by --instrument-hot-only.
|
||||
# RUN: llvm-bolt --instrument --instrument-funcs-file=%t.funcs \
|
||||
# RUN: --instrument-hot-only --data %t.fdata \
|
||||
# RUN: -o %t.b.out %t.exe 2>&1 | FileCheck %s --check-prefix=CHECK-B
|
||||
|
||||
# Test C: empty file means "no functions match", so nothing is instrumented.
|
||||
# RUN: rm -f %t.empty && touch %t.empty
|
||||
# RUN: llvm-bolt --instrument --instrument-funcs-file=%t.empty \
|
||||
# RUN: -o %t.c.out %t.exe 2>&1 | FileCheck %s --check-prefix=CHECK-C
|
||||
|
||||
# Test D: missing file produces a fatal error.
|
||||
# RUN: not llvm-bolt --instrument --instrument-funcs-file=%t.missing \
|
||||
# RUN: -o %t.d.out %t.exe 2>&1 | FileCheck %s --check-prefix=CHECK-D
|
||||
|
||||
# CHECK-A: BOLT-INSTRUMENTER: Number of function descriptors: 2
|
||||
# CHECK-B: BOLT-INSTRUMENTER: Number of function descriptors: 1
|
||||
# CHECK-C: BOLT-INSTRUMENTER: Number of function descriptors: 0
|
||||
# CHECK-D: instrument-funcs-file {{.*}}.missing{{.*}} can't be opened
|
||||
|
||||
.text
|
||||
.globl _start
|
||||
.type _start, %function
|
||||
_start:
|
||||
call foo
|
||||
call bar
|
||||
call baz
|
||||
retq
|
||||
.size _start, .-_start
|
||||
|
||||
.globl foo
|
||||
.type foo, %function
|
||||
foo:
|
||||
# FDATA: 0 [unknown] 0 1 foo 0 0 100
|
||||
retq
|
||||
.size foo, .-foo
|
||||
|
||||
.globl bar
|
||||
.type bar, %function
|
||||
bar:
|
||||
retq
|
||||
.size bar, .-bar
|
||||
|
||||
.globl baz
|
||||
.type baz, %function
|
||||
baz:
|
||||
retq
|
||||
.size baz, .-baz
|
||||
|
||||
.globl _init
|
||||
.type _init, %function
|
||||
# Force DT_INIT to be created (needed for instrumentation).
|
||||
_init:
|
||||
retq
|
||||
.size _init, .-_init
|
||||
|
||||
.globl _fini
|
||||
.type _fini, %function
|
||||
# Force DT_FINI to be created (needed for instrumentation).
|
||||
_fini:
|
||||
retq
|
||||
.size _fini, .-_fini
|
||||
|
|
@ -465,25 +465,7 @@ Building the target ``docs-clang-tools-html`` will run the Sphinx documentation
|
|||
generator and create HTML documentation files in the
|
||||
``tools/clang/tools/extra/docs/html`` directory in your build tree.
|
||||
Make sure that your check is correctly shown in the release notes and the list
|
||||
of checks. Make sure that the formatting and structure of your check's
|
||||
documentation look correct: there is no trailing whitespaces and lines are no
|
||||
longer than 80 characters.
|
||||
|
||||
To validate your files, please use ``doc8`` as described below.
|
||||
|
||||
Clang-Tidy uses `doc8 <https://pypi.org/project/doc8/>`_ to check ``.rst``
|
||||
files for formatting consistency. You can install ``doc8`` with ``pip``:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ pip install doc8
|
||||
|
||||
To run ``doc8`` on the modified documentations:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ git diff --name-only HEAD -- clang-tools-extra/docs/clang-tidy/ | grep "\.rst$" | xargs -r doc8
|
||||
|
||||
of checks, and that its documentation is formatted and structured correctly.
|
||||
|
||||
Registering your Check
|
||||
----------------------
|
||||
|
|
|
|||
|
|
@ -127,8 +127,12 @@ set(RUNTIMES_hexagon-unknown-linux-musl_LLVM_ENABLE_PER_TARGET_RUNTIME_DIR OFF C
|
|||
# The Hexagon driver's getCompilerRTPath() returns ${SysRoot}/usr/lib/,
|
||||
# so compiler-rt libraries must be installed there with arch-suffix names.
|
||||
# Headers stay in the resource dir (COMPILER_RT_INSTALL_INCLUDE_DIR default).
|
||||
# NOTE: must be CACHE STRING, not CACHE PATH. A relative PATH-typed cache
|
||||
# entry is resolved against the (runtimes sub-) build directory, which sent the
|
||||
# sanitizer libs to obj_llvm/.../runtimes-bins instead of the sysroot. STRING
|
||||
# is joined to CMAKE_INSTALL_PREFIX at install time, matching LIBCXX_* below.
|
||||
set(RUNTIMES_hexagon-unknown-linux-musl_COMPILER_RT_INSTALL_LIBRARY_DIR
|
||||
"target/hexagon-unknown-linux-musl/usr/lib" CACHE PATH "")
|
||||
"target/hexagon-unknown-linux-musl/usr/lib" CACHE STRING "")
|
||||
|
||||
# libc++/libcxxabi/libunwind headers and libraries -> sysroot.
|
||||
# Paths are relative to CMAKE_INSTALL_PREFIX (the host toolchain root).
|
||||
|
|
@ -170,11 +174,11 @@ set(RUNTIMES_hexagon-unknown-linux-musl_COMPILER_RT_CXX_LIBRARY "libcxx" CACHE S
|
|||
set(RUNTIMES_hexagon-unknown-linux-musl_COMPILER_RT_USE_BUILTINS_LIBRARY ON CACHE BOOL "")
|
||||
set(RUNTIMES_hexagon-unknown-linux-musl_SANITIZER_CXX_ABI "libc++" CACHE STRING "")
|
||||
set(RUNTIMES_hexagon-unknown-linux-musl_SANITIZER_CXX_ABI_INTREE ON CACHE BOOL "")
|
||||
# COMPILER_RT_BUILD_{SANITIZERS,XRAY,PROFILE,GWP_ASAN,LIBFUZZER,MEMPROF,
|
||||
# CTX_PROFILE} all default ON upstream, so they're left unset here.
|
||||
# COMPILER_RT_SANITIZERS_TO_BUILD defaults to "all"; set explicitly for
|
||||
# documentation clarity. Sanitizers Hexagon can't support (e.g. tsan) simply
|
||||
# aren't built, since Hexagon is absent from their own
|
||||
# ALL_<X>_SUPPORTED_ARCH list in cmake/Modules/AllSupportedArchDefs.cmake.
|
||||
set(RUNTIMES_hexagon-unknown-linux-musl_COMPILER_RT_BUILD_BUILTINS OFF CACHE BOOL "")
|
||||
set(RUNTIMES_hexagon-unknown-linux-musl_COMPILER_RT_BUILD_SANITIZERS ON CACHE BOOL "")
|
||||
set(RUNTIMES_hexagon-unknown-linux-musl_COMPILER_RT_BUILD_XRAY ON CACHE BOOL "")
|
||||
set(RUNTIMES_hexagon-unknown-linux-musl_COMPILER_RT_BUILD_PROFILE ON CACHE BOOL "")
|
||||
set(RUNTIMES_hexagon-unknown-linux-musl_COMPILER_RT_BUILD_GWP_ASAN ON CACHE BOOL "")
|
||||
set(RUNTIMES_hexagon-unknown-linux-musl_COMPILER_RT_BUILD_LIBFUZZER ON CACHE BOOL "")
|
||||
set(RUNTIMES_hexagon-unknown-linux-musl_COMPILER_RT_BUILD_MEMPROF ON CACHE BOOL "")
|
||||
set(RUNTIMES_hexagon-unknown-linux-musl_COMPILER_RT_BUILD_CTX_PROFILE ON CACHE BOOL "")
|
||||
set(RUNTIMES_hexagon-unknown-linux-musl_COMPILER_RT_SANITIZERS_TO_BUILD "all" CACHE STRING "")
|
||||
|
|
|
|||
|
|
@ -5,6 +5,6 @@
|
|||
# conflicts with libLLVM.so), so ELD must be excluded when this cache
|
||||
# is used.
|
||||
|
||||
set(LLVM_BUILD_LLVM_DYLIB ON CACHE BOOL "")
|
||||
set(LLVM_LINK_LLVM_DYLIB ON CACHE BOOL "")
|
||||
set(CLANG_LINK_LLVM_DYLIB ON CACHE BOOL "")
|
||||
set(LLVM_BUILD_LLVM_DYLIB ON CACHE BOOL "" FORCE)
|
||||
set(LLVM_LINK_LLVM_DYLIB ON CACHE BOOL "" FORCE)
|
||||
set(CLANG_LINK_LLVM_DYLIB ON CACHE BOOL "" FORCE)
|
||||
|
|
|
|||
|
|
@ -12,8 +12,11 @@ set(CLANG_INCLUDE_DIRS "@CLANG_CONFIG_INCLUDE_DIRS@")
|
|||
set(CLANG_LINK_CLANG_DYLIB "@CLANG_LINK_CLANG_DYLIB@")
|
||||
set(CLANG_DEFAULT_LINKER "@CLANG_DEFAULT_LINKER@")
|
||||
|
||||
# Provide all our library targets to users.
|
||||
@CLANG_CONFIG_INCLUDE_EXPORTS@
|
||||
# Provide all our library targets to users. Skip when
|
||||
# LLVM_OMIT_EXPORTS_FROM_CONFIG flag is set.
|
||||
if(NOT LLVM_OMIT_EXPORTS_FROM_CONFIG)
|
||||
@CLANG_CONFIG_INCLUDE_EXPORTS@
|
||||
endif()
|
||||
|
||||
# By creating clang-tablegen-targets here, subprojects that depend on Clang's
|
||||
# tablegen-generated headers can always depend on this target whether building
|
||||
|
|
|
|||
|
|
@ -3332,8 +3332,8 @@ are similar.
|
|||
shouldn't impact your testing.
|
||||
|
||||
#. Introduce an AST node for your new expression. This starts with declaring
|
||||
the node in ``include/Basic/StmtNodes.td`` and creating a new class for your
|
||||
expression in the appropriate ``include/AST/Expr*.h`` header. It's best to
|
||||
the node in ``include/clang/Basic/StmtNodes.td`` and creating a new class for your
|
||||
expression in the appropriate ``include/clang/AST/Expr*.h`` header. It's best to
|
||||
look at the class for a similar expression to get ideas, and there are some
|
||||
specific things to watch for:
|
||||
|
||||
|
|
|
|||
|
|
@ -115,6 +115,9 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
|
|||
|
||||
### New Compiler Flags
|
||||
|
||||
- New option `-fdefined-pointer-subtraction` added to preserve stable semantics
|
||||
when subtracting pointers to unrelated objects.
|
||||
|
||||
### Deprecated Compiler Flags
|
||||
|
||||
### Modified Compiler Flags
|
||||
|
|
@ -123,6 +126,8 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
|
|||
|
||||
### Attribute Changes in Clang
|
||||
|
||||
- Clang now properly propagates attributes on class and variable templates to their redeclarations, which will result in redeclarations not interfering with diagnostics. (#GH209812)
|
||||
|
||||
### Improvements to Clang's diagnostics
|
||||
|
||||
- Fixed bug in `-Wdocumentation` so that it correctly handles explicit
|
||||
|
|
@ -290,6 +295,9 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
|
|||
against or converted to a null pointer, the same as a bare function name.
|
||||
(#GH46362)
|
||||
|
||||
- Clang now attempts to print enumerator names rather than C-style cast expressions
|
||||
in more diagnostics.
|
||||
|
||||
|
||||
### Improvements to Clang's time-trace
|
||||
|
||||
|
|
@ -302,6 +310,9 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
|
|||
|
||||
#### Bug Fixes to Compiler Builtins
|
||||
|
||||
- Fixed a crash when classifying a call to a builtin with dependent arguments,
|
||||
such as when the call is used as an `auto` non-type template argument.
|
||||
|
||||
#### Bug Fixes to Attribute Support
|
||||
|
||||
- The `counted_by`/`counted_by_or_null` diagnostic that rejects a pointer whose
|
||||
|
|
@ -318,6 +329,11 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
|
|||
- Fixed a crash when a using-declaration naming an unresolvable member of a
|
||||
dependent base was shadowed by an invalid using-declaration. (#GH209427)
|
||||
|
||||
- Fixed a crash when a lambda parameter pack was given a default argument that
|
||||
is a pack expansion referencing an enclosing function's parameter pack (e.g.
|
||||
`[](Types... = args...) {}`). Clang now diagnoses the illegal default
|
||||
argument instead of asserting. (#GH210714)
|
||||
|
||||
#### Bug Fixes to AST Handling
|
||||
|
||||
- Fixed a non-deterministic ordering of unused local typedefs that made
|
||||
|
|
|
|||
|
|
@ -3002,6 +3002,22 @@ are listed below.
|
|||
``aligned`` attribute, this option is ignored.
|
||||
```
|
||||
|
||||
```{eval-rst}
|
||||
.. option:: -fdefined-pointer-subtraction
|
||||
|
||||
The C and C++ standards require both operands of a pointer subtraction to
|
||||
refer to elements of the same array object. Clang normally exploits this
|
||||
rule when lowering pointer subtraction operations, for example by emitting
|
||||
IR constructs such as ``sdiv exact`` that rely on the computed byte offset
|
||||
being an exact multiple of the pointee size.
|
||||
|
||||
``-fdefined-pointer-subtraction`` disables these assumptions and emits IR
|
||||
that preserves the behavior of pointer subtraction even when the standard
|
||||
requirements are violated. This is primarily intended for low-level code,
|
||||
such as kernels and boot loaders, that performs pointer arithmetic over
|
||||
externally defined memory layouts rather than ordinary C or C++ objects.
|
||||
```
|
||||
|
||||
(strict_aliasing)=
|
||||
(strict-aliasing)=
|
||||
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ struct PrintingPolicy {
|
|||
PrintAsCanonical(false), PrintInjectedClassNameWithArguments(true),
|
||||
UsePreferredNames(true), AlwaysIncludeTypeForTemplateArgument(false),
|
||||
CleanUglifiedParameters(false), EntireContentsOfLargeArray(true),
|
||||
UseEnumerators(true), UseHLSLTypes(LO.HLSL),
|
||||
PrettyEnums(true), UseEnumerators(true), UseHLSLTypes(LO.HLSL),
|
||||
SuppressDeclAttributes(false), SuppressLambdaBody(false) {}
|
||||
|
||||
/// Adjust this printing policy for cases where it's known that we're
|
||||
|
|
@ -357,6 +357,11 @@ struct PrintingPolicy {
|
|||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned EntireContentsOfLargeArray : 1;
|
||||
|
||||
/// Whether to print enumerators with a matching enumerator name or via cast
|
||||
// of an integer.
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned PrettyEnums : 1;
|
||||
|
||||
/// Whether to print enumerator non-type template parameters with a matching
|
||||
/// enumerator name or via cast of an integer.
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
|
|
|
|||
|
|
@ -295,6 +295,8 @@ public:
|
|||
/// Return the kind of stored template argument.
|
||||
ArgKind getKind() const { return (ArgKind)TypeOrValue.Kind; }
|
||||
|
||||
StringRef getKindName() const;
|
||||
|
||||
/// Determine whether this template argument has no value.
|
||||
bool isNull() const { return getKind() == Null; }
|
||||
|
||||
|
|
|
|||
|
|
@ -6465,7 +6465,7 @@ class UnaryTransformType : public Type, public llvm::FoldingSetNode {
|
|||
public:
|
||||
enum UTTKind {
|
||||
#define TRANSFORM_TYPE_TRAIT_DEF(Enum, _) Enum,
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -47,13 +47,7 @@ using MapTy = llvm::ImmutableMap<KeyT, ValT, llvm::ImutKeyValueInfo<KeyT, ValT>,
|
|||
/// Computes the union of two ImmutableSets.
|
||||
template <typename T>
|
||||
SetTy<T> join(SetTy<T> A, SetTy<T> B, typename SetTy<T>::Factory &F) {
|
||||
if (A.getRootWithoutRetain() == B.getRootWithoutRetain())
|
||||
return A;
|
||||
if (A.getHeight() < B.getHeight())
|
||||
std::swap(A, B);
|
||||
for (const auto &E : B)
|
||||
A = F.add(A, E);
|
||||
return A;
|
||||
return F.unionSets(A, B);
|
||||
}
|
||||
|
||||
/// Describes the strategy for joining two `ImmutableMap` instances, primarily
|
||||
|
|
@ -72,30 +66,36 @@ enum class JoinKind {
|
|||
Asymmetric,
|
||||
};
|
||||
|
||||
/// Computes the key-wise union of two ImmutableMaps.
|
||||
// TODO(opt): This key-wise join is a performance bottleneck. A more
|
||||
// efficient merge could be implemented using a Patricia Trie or HAMT
|
||||
// instead of the current AVL-tree-based ImmutableMap.
|
||||
/// Computes the key-wise union of two ImmutableMaps in a single traversal
|
||||
/// (see ImmutableMap::Factory::mergeWith), sharing subtrees the two maps do
|
||||
/// not overlap. This assumes -- as the swap below already does -- that
|
||||
/// JoinValues is commutative with a left identity, which holds for the
|
||||
/// lifetime lattices.
|
||||
template <typename KeyT, typename ValT, typename Joiner>
|
||||
MapTy<KeyT, ValT> join(const MapTy<KeyT, ValT> &A, const MapTy<KeyT, ValT> &B,
|
||||
MapTy<KeyT, ValT> join(MapTy<KeyT, ValT> A, MapTy<KeyT, ValT> B,
|
||||
typename MapTy<KeyT, ValT>::Factory &F,
|
||||
Joiner JoinValues, JoinKind Kind) {
|
||||
if (A.getRootWithoutRetain() == B.getRootWithoutRetain())
|
||||
return A;
|
||||
// Drive the merge with the taller map so the shorter one is the one split.
|
||||
if (A.getHeight() < B.getHeight())
|
||||
return join(B, A, F, JoinValues, Kind);
|
||||
std::swap(A, B);
|
||||
|
||||
// For each element in B, join it with the corresponding element in A
|
||||
// (or with an empty value if it doesn't exist in A).
|
||||
MapTy<KeyT, ValT> Res = A;
|
||||
for (const auto &[Key, ValB] : B)
|
||||
Res = F.add(Res, Key, JoinValues(A.lookup(Key), &ValB));
|
||||
if (Kind == JoinKind::Symmetric) {
|
||||
for (const auto &[Key, ValA] : A)
|
||||
if (!B.contains(Key))
|
||||
Res = F.add(Res, Key, JoinValues(&ValA, nullptr));
|
||||
}
|
||||
return Res;
|
||||
using ValueTy = typename MapTy<KeyT, ValT>::value_type;
|
||||
auto Combine = [&JoinValues](const ValueTy *AElem,
|
||||
const ValueTy *BElem) -> std::pair<KeyT, ValT> {
|
||||
const KeyT &Key = AElem ? AElem->first : BElem->first;
|
||||
return std::pair<KeyT, ValT>(Key,
|
||||
JoinValues(AElem ? &AElem->second : nullptr,
|
||||
BElem ? &BElem->second : nullptr));
|
||||
};
|
||||
// Asymmetric keeps keys unique to either map as-is (valid because JoinValues
|
||||
// has a left identity); symmetric passes unmatched keys through JoinValues.
|
||||
// The lifetime joins are idempotent lattice joins, so pointer-identical
|
||||
// subtrees (common once one state is derived from the other) can be shared.
|
||||
return F.mergeWith(A, B, Combine,
|
||||
/*KeepUnmatched=*/Kind == JoinKind::Asymmetric,
|
||||
/*SkipShared=*/true);
|
||||
}
|
||||
} // namespace clang::lifetimes::internal::utils
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
|
||||
namespace clang {
|
||||
|
|
@ -247,6 +248,53 @@ public:
|
|||
/// It might return null.
|
||||
const StackFrame *getParent() const { return Parent; }
|
||||
|
||||
/// Forward iterator over a chain of \c StackFrame parents. Advancing follows
|
||||
/// \c getParent(); the past-the-end iterator holds a null frame.
|
||||
class parent_iterator {
|
||||
const StackFrame *Current = nullptr;
|
||||
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = const StackFrame;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = const StackFrame *;
|
||||
using reference = const StackFrame &;
|
||||
|
||||
parent_iterator() = default;
|
||||
explicit parent_iterator(const StackFrame *SF) : Current(SF) {}
|
||||
|
||||
reference operator*() const { return *Current; }
|
||||
pointer operator->() const { return Current; }
|
||||
parent_iterator &operator++() {
|
||||
assert(Current && "Cannot call ++ on the end iterator");
|
||||
Current = Current->getParent();
|
||||
return *this;
|
||||
}
|
||||
parent_iterator operator++(int) {
|
||||
parent_iterator Tmp = *this;
|
||||
++*this;
|
||||
return Tmp;
|
||||
}
|
||||
bool operator==(const parent_iterator &Other) const {
|
||||
return Current == Other.Current;
|
||||
}
|
||||
bool operator!=(const parent_iterator &Other) const {
|
||||
return !(*this == Other);
|
||||
}
|
||||
};
|
||||
|
||||
/// Iterates over the strict ancestors of this frame, i.e. \c getParent(),
|
||||
/// \c getParent()->getParent(), ... up to (but excluding) the null frame.
|
||||
/// Does not include \c *this.
|
||||
llvm::iterator_range<parent_iterator> parents() const {
|
||||
return {parent_iterator(getParent()), parent_iterator()};
|
||||
}
|
||||
|
||||
/// Iterates over this frame followed by all of its ancestors.
|
||||
llvm::iterator_range<parent_iterator> parentsIncludingSelf() const {
|
||||
return {parent_iterator(this), parent_iterator()};
|
||||
}
|
||||
|
||||
int64_t getID() const { return ID; }
|
||||
|
||||
bool isParentOf(const StackFrame *SF) const;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,10 @@
|
|||
#ifndef LLVM_CLANG_BASIC_ADDRESSSPACES_H
|
||||
#define LLVM_CLANG_BASIC_ADDRESSSPACES_H
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <initializer_list>
|
||||
#include <utility>
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
|
@ -76,7 +79,20 @@ enum class LangAS : unsigned {
|
|||
|
||||
/// The type of a lookup table which maps from language-specific address spaces
|
||||
/// to target-specific ones.
|
||||
using LangASMap = unsigned[(unsigned)LangAS::FirstTargetAddressSpace];
|
||||
class LangASMap {
|
||||
std::array<unsigned, (unsigned)LangAS::FirstTargetAddressSpace> Map{};
|
||||
|
||||
public:
|
||||
constexpr LangASMap() = default;
|
||||
|
||||
constexpr LangASMap(
|
||||
std::initializer_list<std::pair<LangAS, unsigned>> Mappings) {
|
||||
for (auto [LanguageAS, TargetAS] : Mappings)
|
||||
Map[(unsigned)LanguageAS] = TargetAS;
|
||||
}
|
||||
|
||||
constexpr unsigned operator[](LangAS AS) const { return Map[(unsigned)AS]; }
|
||||
};
|
||||
|
||||
/// \return whether \p AS is a target-specific address space rather than a
|
||||
/// clang AST address space
|
||||
|
|
|
|||
|
|
@ -154,6 +154,10 @@ clang_tablegen(BuiltinTemplates.inc -gen-clang-builtin-templates
|
|||
SOURCE BuiltinTemplates.td
|
||||
TARGET ClangBuiltinTemplates)
|
||||
|
||||
clang_tablegen(Traits.inc -gen-clang-traits
|
||||
SOURCE Traits.td
|
||||
TARGET ClangTraits)
|
||||
|
||||
# ARM NEON and MVE
|
||||
clang_tablegen(arm_neon.inc -gen-arm-neon-sema
|
||||
SOURCE arm_neon.td
|
||||
|
|
|
|||
|
|
@ -350,6 +350,7 @@ def ExtraTokens : DiagGroup<"extra-tokens">;
|
|||
def CXX98CompatExtraSemi : DiagGroup<"c++98-compat-extra-semi">;
|
||||
def CXX11ExtraSemi : DiagGroup<"c++11-extra-semi">;
|
||||
def EmptyInitStatement : DiagGroup<"empty-init-stmt">;
|
||||
def ExpansionStmtBody : DiagGroup<"expansion-stmt-missing-braces">;
|
||||
def ExportUnnamed : DiagGroup<"export-unnamed">;
|
||||
def ExtraSemiStmt : DiagGroup<"extra-semi-stmt", [EmptyInitStatement]>;
|
||||
def ExtraSemi : DiagGroup<"extra-semi", [CXX98CompatExtraSemi,
|
||||
|
|
|
|||
|
|
@ -463,6 +463,12 @@ def err_expansion_stmt_requires_cxx2c : Error<
|
|||
"expansion statements are only supported in C++2c">;
|
||||
def err_for_template : Error<
|
||||
"'for template' is invalid; use 'template for' instead">;
|
||||
def ext_expansion_stmt_body_not_compound_stmt : Extension<
|
||||
"ISO C++ requires the body of an expansion statement to be a compound statement">,
|
||||
InGroup<ExpansionStmtBody>;
|
||||
def ext_expansion_stmt_body_attr : Extension<
|
||||
"ISO C++ forbids attributes before the compound statement of an expansion statement">,
|
||||
InGroup<ExpansionStmtBody>;
|
||||
|
||||
def err_expected_case_before_expression: Error<
|
||||
"expected 'case' keyword before expression">;
|
||||
|
|
|
|||
|
|
@ -20,10 +20,10 @@ namespace clang {
|
|||
|
||||
enum ExpressionTrait {
|
||||
#define EXPRESSION_TRAIT(Spelling, Name, Key) ET_##Name,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
ET_Last = -1 // ET_Last == last ET_XX in the enum.
|
||||
#define EXPRESSION_TRAIT(Spelling, Name, Key) +1
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
};
|
||||
|
||||
/// Return the internal name of type trait \p T. Never null.
|
||||
|
|
|
|||
|
|
@ -534,6 +534,8 @@ LANGOPT(EnableLifetimeSafetyTUAnalysis, 1, 0, Benign, "Lifetime safety at transl
|
|||
LANGOPT(PreserveVec3Type, 1, 0, NotCompatible, "Preserve 3-component vector type")
|
||||
LANGOPT(Reflection , 1, 0, NotCompatible, "C++26 Reflection")
|
||||
|
||||
LANGOPT(StablePointerSubtraction, 1, 0, NotCompatible, "Make unaligned pointer subtraction stable")
|
||||
|
||||
#undef LANGOPT
|
||||
#undef ENUM_LANGOPT
|
||||
#undef VALUE_LANGOPT
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ namespace clang {
|
|||
TST_typeof_unqualExpr, // C23 typeof_unqual(expression)
|
||||
TST_decltype, // C++11 decltype
|
||||
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) TST_##Trait,
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
TST_auto, // C++11 auto
|
||||
TST_decltype_auto, // C++1y decltype(auto)
|
||||
TST_auto_type, // __auto_type extension
|
||||
|
|
|
|||
|
|
@ -1701,7 +1701,7 @@ public:
|
|||
unsigned getTargetAddressSpace(LangAS AS) const {
|
||||
if (isTargetAddressSpace(AS))
|
||||
return toTargetAddressSpace(AS);
|
||||
return getAddressSpaceMap()[(unsigned)AS];
|
||||
return getAddressSpaceMap()[AS];
|
||||
}
|
||||
|
||||
/// Determine whether the given pointer-authentication key is valid.
|
||||
|
|
|
|||
|
|
@ -327,8 +327,6 @@ KEYWORD(register , KEYALL)
|
|||
KEYWORD(return , KEYALL)
|
||||
KEYWORD(short , KEYALL)
|
||||
KEYWORD(signed , KEYALL)
|
||||
UNARY_EXPR_OR_TYPE_TRAIT(sizeof, SizeOf, KEYALL)
|
||||
UNARY_EXPR_OR_TYPE_TRAIT(__datasizeof, DataSizeOf, KEYCXX)
|
||||
KEYWORD(static , KEYALL)
|
||||
KEYWORD(struct , KEYALL)
|
||||
KEYWORD(switch , KEYALL)
|
||||
|
|
@ -362,9 +360,6 @@ KEYWORD(__ptrauth , KEYALL)
|
|||
KEYWORD(__ob_wrap , KEYALL)
|
||||
KEYWORD(__ob_trap , KEYALL)
|
||||
|
||||
// C2y
|
||||
UNARY_EXPR_OR_TYPE_TRAIT(_Countof, CountOf, KEYNOCXX)
|
||||
|
||||
// C++ 2.11p1: Keywords.
|
||||
KEYWORD(asm , KEYCXX|KEYGNU)
|
||||
KEYWORD(bool , BOOLSUPPORT|KEYC23)
|
||||
|
|
@ -417,8 +412,6 @@ C99_KEYWORD(inline , KEYCXX|KEYGNU)
|
|||
|
||||
// C++11 keywords
|
||||
CXX11_KEYWORD(alignas , KEYC23)
|
||||
// alignof and _Alignof return the required ABI alignment
|
||||
CXX11_UNARY_EXPR_OR_TYPE_TRAIT(alignof, AlignOf, KEYC23)
|
||||
CXX11_KEYWORD(char16_t , KEYNOMS18)
|
||||
CXX11_KEYWORD(char32_t , KEYNOMS18)
|
||||
CXX11_KEYWORD(constexpr , KEYC23)
|
||||
|
|
@ -466,9 +459,6 @@ KEYWORD(_Decimal32 , KEYALL)
|
|||
KEYWORD(_Decimal64 , KEYALL)
|
||||
KEYWORD(_Decimal128 , KEYALL)
|
||||
KEYWORD(__null , KEYCXX)
|
||||
// __alignof returns the preferred alignment of a type, the alignment
|
||||
// clang will attempt to give an object of the type if allowed by ABI.
|
||||
UNARY_EXPR_OR_TYPE_TRAIT(__alignof, PreferredAlignOf, KEYALL)
|
||||
KEYWORD(__attribute , KEYALL)
|
||||
KEYWORD(__builtin_choose_expr , KEYALL)
|
||||
KEYWORD(__builtin_offsetof , KEYALL)
|
||||
|
|
@ -480,9 +470,6 @@ KEYWORD(__builtin_LINE , KEYALL)
|
|||
KEYWORD(__builtin_COLUMN , KEYALL)
|
||||
KEYWORD(__builtin_source_location , KEYCXX)
|
||||
|
||||
// __builtin_types_compatible_p is a GNU C extension that we handle like a C++
|
||||
// type trait.
|
||||
TYPE_TRAIT_2(__builtin_types_compatible_p, TypeCompatible, KEYNOCXX)
|
||||
KEYWORD(__builtin_va_arg , KEYALL)
|
||||
KEYWORD(__extension__ , KEYALL)
|
||||
KEYWORD(__float128 , KEYALL)
|
||||
|
|
@ -501,131 +488,11 @@ KEYWORD(__FUNCDNAME__ , KEYMS)
|
|||
KEYWORD(__FUNCSIG__ , KEYMS)
|
||||
KEYWORD(L__FUNCTION__ , KEYMS)
|
||||
KEYWORD(L__FUNCSIG__ , KEYMS)
|
||||
TYPE_TRAIT_1(__is_interface_class, IsInterfaceClass, KEYMS)
|
||||
TYPE_TRAIT_1(__is_sealed, IsSealed, KEYMS)
|
||||
|
||||
// MSVC12.0 / VS2013 Type Traits
|
||||
TYPE_TRAIT_1(__is_destructible, IsDestructible, KEYALL)
|
||||
TYPE_TRAIT_1(__is_trivially_destructible, IsTriviallyDestructible, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_nothrow_destructible, IsNothrowDestructible, KEYALL)
|
||||
TYPE_TRAIT_2(__is_nothrow_assignable, IsNothrowAssignable, KEYCXX)
|
||||
TYPE_TRAIT_N(__is_constructible, IsConstructible, KEYCXX)
|
||||
TYPE_TRAIT_N(__is_nothrow_constructible, IsNothrowConstructible, KEYCXX)
|
||||
|
||||
// MSVC14.0 / VS2015 Type Traits
|
||||
TYPE_TRAIT_2(__is_assignable, IsAssignable, KEYCXX)
|
||||
|
||||
// MSVC Type Traits of unknown vintage
|
||||
TYPE_TRAIT_1(__has_nothrow_move_assign, HasNothrowMoveAssign, KEYCXX)
|
||||
TYPE_TRAIT_1(__has_trivial_move_assign, HasTrivialMoveAssign, KEYCXX)
|
||||
TYPE_TRAIT_1(__has_trivial_move_constructor, HasTrivialMoveConstructor, KEYCXX)
|
||||
|
||||
// GNU and MS Type Traits
|
||||
TYPE_TRAIT_1(__builtin_is_implicit_lifetime, IsImplicitLifetime, KEYCXX)
|
||||
TYPE_TRAIT_2(__builtin_is_virtual_base_of, IsVirtualBaseOf, KEYCXX)
|
||||
TYPE_TRAIT_1(__has_nothrow_assign, HasNothrowAssign, KEYCXX)
|
||||
TYPE_TRAIT_1(__has_nothrow_copy, HasNothrowCopy, KEYCXX)
|
||||
TYPE_TRAIT_1(__has_nothrow_constructor, HasNothrowConstructor, KEYCXX)
|
||||
TYPE_TRAIT_1(__has_trivial_assign, HasTrivialAssign, KEYCXX)
|
||||
TYPE_TRAIT_1(__has_trivial_copy, HasTrivialCopy, KEYCXX)
|
||||
TYPE_TRAIT_1(__has_trivial_constructor, HasTrivialDefaultConstructor, KEYCXX)
|
||||
TYPE_TRAIT_1(__has_trivial_destructor, HasTrivialDestructor, KEYCXX)
|
||||
TYPE_TRAIT_1(__has_virtual_destructor, HasVirtualDestructor, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_abstract, IsAbstract, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_aggregate, IsAggregate, KEYCXX)
|
||||
TYPE_TRAIT_2(__is_base_of, IsBaseOf, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_class, IsClass, KEYCXX)
|
||||
TYPE_TRAIT_2(__is_convertible_to, IsConvertibleTo, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_empty, IsEmpty, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_enum, IsEnum, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_final, IsFinal, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_literal, IsLiteral, KEYCXX)
|
||||
// Name for GCC 4.6 compatibility - people have already written libraries using
|
||||
// this name unfortunately.
|
||||
ALIAS("__is_literal_type", __is_literal, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_pod, IsPOD, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_polymorphic, IsPolymorphic, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_standard_layout, IsStandardLayout, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_trivial, IsTrivial, KEYCXX)
|
||||
TYPE_TRAIT_2(__is_trivially_assignable, IsTriviallyAssignable, KEYCXX)
|
||||
TYPE_TRAIT_N(__is_trivially_constructible, IsTriviallyConstructible, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_trivially_copyable, IsTriviallyCopyable, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_union, IsUnion, KEYCXX)
|
||||
TYPE_TRAIT_1(__has_unique_object_representations,
|
||||
HasUniqueObjectRepresentations, KEYCXX)
|
||||
TYPE_TRAIT_2(__is_layout_compatible, IsLayoutCompatible, KEYCXX)
|
||||
TYPE_TRAIT_2(__is_pointer_interconvertible_base_of, IsPointerInterconvertibleBaseOf, KEYCXX)
|
||||
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
|
||||
// Clang-only C++ Type Traits
|
||||
TYPE_TRAIT_1(__is_trivially_equality_comparable, IsTriviallyEqualityComparable, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_bounded_array, IsBoundedArray, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_unbounded_array, IsUnboundedArray, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_scoped_enum, IsScopedEnum, KEYCXX)
|
||||
TYPE_TRAIT_1(__can_pass_in_regs, CanPassInRegs, KEYCXX)
|
||||
TYPE_TRAIT_2(__reference_binds_to_temporary, ReferenceBindsToTemporary, KEYCXX)
|
||||
TYPE_TRAIT_2(__reference_constructs_from_temporary, ReferenceConstructsFromTemporary, KEYCXX)
|
||||
TYPE_TRAIT_2(__reference_converts_from_temporary, ReferenceConvertsFromTemporary, KEYCXX)
|
||||
TYPE_TRAIT_2(__builtin_lt_synthesizes_from_spaceship, LtSynthesizesFromSpaceship, KEYCXX)
|
||||
TYPE_TRAIT_2(__builtin_le_synthesizes_from_spaceship, LeSynthesizesFromSpaceship, KEYCXX)
|
||||
TYPE_TRAIT_2(__builtin_gt_synthesizes_from_spaceship, GtSynthesizesFromSpaceship, KEYCXX)
|
||||
TYPE_TRAIT_2(__builtin_ge_synthesizes_from_spaceship, GeSynthesizesFromSpaceship, KEYCXX)
|
||||
// IsDeducible is only used internally by clang for CTAD implementation and
|
||||
// is not exposed to users.
|
||||
TYPE_TRAIT_2(/*EmptySpellingName*/, IsDeducible, KEYCXX)
|
||||
|
||||
// __is_trivially_relocatable is deprecated
|
||||
TYPE_TRAIT_1(__builtin_is_cpp_trivially_relocatable, IsCppTriviallyRelocatable, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_trivially_relocatable, IsTriviallyRelocatable, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_bitwise_cloneable, IsBitwiseCloneable, KEYALL)
|
||||
TYPE_TRAIT_1(__builtin_structured_binding_size, StructuredBindingSize, KEYCXX)
|
||||
|
||||
|
||||
|
||||
// Embarcadero Expression Traits
|
||||
EXPRESSION_TRAIT(__is_lvalue_expr, IsLValueExpr, KEYCXX)
|
||||
EXPRESSION_TRAIT(__is_rvalue_expr, IsRValueExpr, KEYCXX)
|
||||
|
||||
// Embarcadero Unary Type Traits
|
||||
TYPE_TRAIT_1(__is_arithmetic, IsArithmetic, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_floating_point, IsFloatingPoint, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_integral, IsIntegral, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_complete_type, IsCompleteType, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_void, IsVoid, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_array, IsArray, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_function, IsFunction, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_reference, IsReference, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_lvalue_reference, IsLvalueReference, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_rvalue_reference, IsRvalueReference, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_fundamental, IsFundamental, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_object, IsObject, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_scalar, IsScalar, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_compound, IsCompound, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_pointer, IsPointer, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_member_object_pointer, IsMemberObjectPointer, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_member_function_pointer, IsMemberFunctionPointer, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_member_pointer, IsMemberPointer, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_const, IsConst, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_volatile, IsVolatile, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_signed, IsSigned, KEYCXX)
|
||||
TYPE_TRAIT_1(__is_unsigned, IsUnsigned, KEYCXX)
|
||||
|
||||
// Embarcadero Binary Type Traits
|
||||
TYPE_TRAIT_2(__is_same, IsSame, KEYCXX)
|
||||
TYPE_TRAIT_2(__is_convertible, IsConvertible, KEYCXX)
|
||||
TYPE_TRAIT_2(__is_nothrow_convertible, IsNothrowConvertible, KEYCXX)
|
||||
ARRAY_TYPE_TRAIT(__array_rank, ArrayRank, KEYCXX)
|
||||
ARRAY_TYPE_TRAIT(__array_extent, ArrayExtent, KEYCXX)
|
||||
// Name for GCC 6 compatibility.
|
||||
ALIAS("__is_same_as", __is_same, KEYCXX)
|
||||
|
||||
// Apple Extension.
|
||||
KEYWORD(__private_extern__ , KEYALL)
|
||||
KEYWORD(__module_private__ , KEYALL)
|
||||
|
||||
UNARY_EXPR_OR_TYPE_TRAIT(__builtin_ptrauth_type_discriminator, PtrAuthTypeDiscriminator, KEYALL)
|
||||
|
||||
// Extension that will be enabled for Microsoft, Borland and PS4, but can be
|
||||
// disabled via '-fno-declspec'.
|
||||
KEYWORD(__declspec , 0)
|
||||
|
|
@ -664,7 +531,6 @@ ALIAS("write_only", __write_only , KEYOPENCLC | KEYOPENCLCXX)
|
|||
ALIAS("read_write", __read_write , KEYOPENCLC | KEYOPENCLCXX)
|
||||
// OpenCL builtins
|
||||
KEYWORD(__builtin_astype , KEYOPENCLC | KEYOPENCLCXX)
|
||||
UNARY_EXPR_OR_TYPE_TRAIT(vec_step, VecStep, KEYOPENCLC | KEYOPENCLCXX | KEYALTIVEC | KEYZVECTOR)
|
||||
#define GENERIC_IMAGE_TYPE(ImgType, Id) KEYWORD(ImgType##_t, KEYOPENCLC | KEYOPENCLCXX)
|
||||
#include "clang/Basic/OpenCLImageTypes.def"
|
||||
KEYWORD(pipe , KEYOPENCLC | KEYOPENCLCXX)
|
||||
|
|
@ -687,15 +553,6 @@ KEYWORD(column_major , KEYHLSL)
|
|||
#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) KEYWORD(Name, KEYHLSL)
|
||||
#include "clang/Basic/HLSLIntangibleTypes.def"
|
||||
|
||||
// HLSL Type traits
|
||||
TYPE_TRAIT_2(__builtin_hlsl_is_scalarized_layout_compatible, IsScalarizedLayoutCompatible, KEYHLSL)
|
||||
TYPE_TRAIT_1(__builtin_hlsl_is_intangible, IsIntangibleType, KEYHLSL)
|
||||
TYPE_TRAIT_1(__builtin_hlsl_is_typed_resource_element_compatible, IsTypedResourceElementCompatible, KEYHLSL)
|
||||
TYPE_TRAIT_1(__builtin_hlsl_is_constant_buffer_element_compatible, IsConstantBufferElementCompatible, KEYHLSL)
|
||||
|
||||
// OpenMP Type Traits
|
||||
UNARY_EXPR_OR_TYPE_TRAIT(__builtin_omp_required_simd_align, OpenMPRequiredSimdAlign, KEYALL)
|
||||
|
||||
// Borland Extensions.
|
||||
KEYWORD(__pascal , KEYALL)
|
||||
|
||||
|
|
@ -724,7 +581,6 @@ KEYWORD(__kindof , KEYOBJC)
|
|||
|
||||
// Alternate spelling for various tokens. There are GCC extensions in all
|
||||
// languages, but should not be disabled in strict conformance mode.
|
||||
ALIAS("__alignof__" , __alignof , KEYALL)
|
||||
ALIAS("__asm" , asm , KEYALL)
|
||||
ALIAS("__asm__" , asm , KEYALL)
|
||||
ALIAS("__attribute__" , __attribute , KEYALL)
|
||||
|
|
@ -779,12 +635,10 @@ ALIAS("__int8" , char , KEYMS)
|
|||
ALIAS("__int16" , short , KEYMS)
|
||||
ALIAS("__int32" , int , KEYMS)
|
||||
ALIAS("__wchar_t" , wchar_t , KEYMS)
|
||||
ALIAS("__builtin_alignof", __alignof , KEYMS)
|
||||
|
||||
// Microsoft single-underscore prefixed aliases for double-underscore prefixed
|
||||
// keywords.
|
||||
ALIAS("_asm" , asm , KEYMS)
|
||||
ALIAS("_alignof" , __alignof , KEYMS)
|
||||
ALIAS("_cdecl" , __cdecl , KEYMS | KEYBORLAND)
|
||||
ALIAS("_declspec" , __declspec , KEYMS)
|
||||
ALIAS("_fastcall" , __fastcall , KEYMS | KEYBORLAND)
|
||||
|
|
@ -815,7 +669,6 @@ ALIAS("_pascal" , __pascal , KEYBORLAND)
|
|||
|
||||
// Clang Extensions.
|
||||
KEYWORD(__builtin_convertvector , KEYALL)
|
||||
UNARY_EXPR_OR_TYPE_TRAIT(__builtin_vectorelements, VectorElements, KEYALL)
|
||||
ALIAS("__char16_t" , char16_t , KEYCXX)
|
||||
ALIAS("__char32_t" , char32_t , KEYCXX)
|
||||
KEYWORD(__builtin_bit_cast , KEYALL)
|
||||
|
|
@ -1060,6 +913,8 @@ ANNOTATION(repl_input_end)
|
|||
// Annotation for #embed
|
||||
ANNOTATION(embed)
|
||||
|
||||
#include "clang/Basic/Traits.inc"
|
||||
|
||||
#undef PRAGMA_ANNOTATION
|
||||
#undef ANNOTATION
|
||||
#undef TESTING_KEYWORD
|
||||
|
|
|
|||
639
clang/include/clang/Basic/Traits.td
Normal file
639
clang/include/clang/Basic/Traits.td
Normal file
|
|
@ -0,0 +1,639 @@
|
|||
//==--- Traits.td - expression and type traits ----------------------------===//
|
||||
//
|
||||
// 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 TokenKey<int V> {
|
||||
int Value = V;
|
||||
}
|
||||
|
||||
def KEYC99 : TokenKey<0x1>;
|
||||
def KEYCXX : TokenKey<0x2>;
|
||||
def KEYCXX11 : TokenKey<0x4>;
|
||||
def KEYGNU : TokenKey<0x8>;
|
||||
def KEYMS : TokenKey<0x10>;
|
||||
def BOOLSUPPORT : TokenKey<0x20>;
|
||||
def KEYALTIVEC : TokenKey<0x40>;
|
||||
def KEYNOCXX : TokenKey<0x80>;
|
||||
def KEYBORLAND : TokenKey<0x100>;
|
||||
def KEYOPENCLC : TokenKey<0x200>;
|
||||
def KEYC23 : TokenKey<0x400>;
|
||||
def KEYNOMS18 : TokenKey<0x800>;
|
||||
def KEYNOOPENCL : TokenKey<0x1000>;
|
||||
def WCHARSUPPORT : TokenKey<0x2000>;
|
||||
def HALFSUPPORT : TokenKey<0x4000>;
|
||||
def CHAR8SUPPORT : TokenKey<0x8000>;
|
||||
def KEYOBJC : TokenKey<0x10000>;
|
||||
def KEYZVECTOR : TokenKey<0x20000>;
|
||||
def KEYCOROUTINES : TokenKey<0x40000>;
|
||||
def KEYMODULES : TokenKey<0x80000>;
|
||||
def KEYCXX20 : TokenKey<0x100000>;
|
||||
def KEYOPENCLCXX : TokenKey<0x200000>;
|
||||
def KEYMSCOMPAT : TokenKey<0x400000>;
|
||||
def KEYSYCL : TokenKey<0x800000>;
|
||||
def KEYCUDA : TokenKey<0x1000000>;
|
||||
def KEYZOS : TokenKey<0x2000000>;
|
||||
def KEYNOZOS : TokenKey<0x4000000>;
|
||||
def KEYHLSL : TokenKey<0x8000000>;
|
||||
def KEYFIXEDPOINT : TokenKey<0x10000000>;
|
||||
def KEYDEFERTS : TokenKey<0x20000000>;
|
||||
def KEYNOHLSL : TokenKey<0x40000000>;
|
||||
|
||||
def KEYMAX : TokenKey<KEYNOHLSL.Value>;
|
||||
def KEYALLCXX : TokenKey<!or(KEYCXX.Value, KEYCXX11.Value, KEYCXX20.Value)>;
|
||||
def KEYALL : TokenKey<!and(!or(KEYMAX.Value, !sub(KEYMAX.Value, 1)),
|
||||
!xor(KEYNOMS18.Value, -1),
|
||||
!xor(KEYNOOPENCL.Value, -1),
|
||||
!xor(KEYNOZOS.Value, -1),
|
||||
!xor(KEYNOHLSL.Value, -1))>;
|
||||
class Trait<string P> {
|
||||
string Prefix = P;
|
||||
string Spelling = "";
|
||||
string StdName = "";
|
||||
list<TokenKey> KeyFlags = [KEYCXX];
|
||||
}
|
||||
class TypeTrait<string P> : Trait<P>;
|
||||
|
||||
class UnaryTrait : TypeTrait<"UTT">;
|
||||
class BinaryTrait : TypeTrait<"BTT">;
|
||||
class VariadicTrait : TypeTrait<"TT">;
|
||||
class ArrayTrait : Trait<"ATT">;
|
||||
class ExpressionTrait : Trait<"ET">;
|
||||
class UnaryExprOrTypeTrait : Trait<"UETT">;
|
||||
class CXX11UnaryExprOrTypeTrait : Trait<"UETT">;
|
||||
class TransformTypeTrait : Trait<"TST">;
|
||||
|
||||
class Alias<Trait P> {
|
||||
Trait Primary = P;
|
||||
string Spelling = "";
|
||||
list<TokenKey> KeyFlags = [KEYCXX];
|
||||
}
|
||||
|
||||
// C99 6.4.1: Keywords. These turn into kw_* tokens.
|
||||
def SizeOf : UnaryExprOrTypeTrait {
|
||||
let Spelling = "sizeof";
|
||||
let KeyFlags = [KEYALL];
|
||||
}
|
||||
|
||||
def DataSizeOf : UnaryExprOrTypeTrait {
|
||||
let Spelling = "__datasizeof";
|
||||
}
|
||||
|
||||
// C2y
|
||||
def CountOf : UnaryExprOrTypeTrait {
|
||||
let Spelling = "_Countof";
|
||||
let KeyFlags = [KEYNOCXX];
|
||||
}
|
||||
|
||||
// C++11 keywords
|
||||
// alignof and _Alignof return the required ABI alignment
|
||||
def AlignOf : CXX11UnaryExprOrTypeTrait {
|
||||
let Spelling = "alignof";
|
||||
let KeyFlags = [KEYC23];
|
||||
}
|
||||
|
||||
// GNU Extensions (in impl-reserved namespace)
|
||||
|
||||
// __alignof returns the preferred alignment of a type, the alignment
|
||||
// clang will attempt to give an object of the type if allowed by ABI.
|
||||
def PreferredAlignOf : UnaryExprOrTypeTrait {
|
||||
let Spelling = "__alignof";
|
||||
let KeyFlags = [KEYALL];
|
||||
}
|
||||
|
||||
def PreferredAlignOfAlt : Alias<PreferredAlignOf> {
|
||||
let Spelling = "__alignof__";
|
||||
let KeyFlags = [KEYALL];
|
||||
}
|
||||
|
||||
def BuiltinAlignOf : Alias<PreferredAlignOf> {
|
||||
let Spelling = "__builtin_alignof";
|
||||
let KeyFlags = [KEYMS];
|
||||
}
|
||||
|
||||
def MSAlignOf : Alias<PreferredAlignOf> {
|
||||
let Spelling = "_alignof";
|
||||
let KeyFlags = [KEYMS];
|
||||
}
|
||||
|
||||
// __builtin_types_compatible_p is a GNU C extension that we handle like a C++
|
||||
// type trait.
|
||||
def TypeCompatible : BinaryTrait {
|
||||
let Spelling = "__builtin_types_compatible_p";
|
||||
let KeyFlags = [KEYNOCXX];
|
||||
}
|
||||
|
||||
// MS Extensions
|
||||
def IsInterfaceClass : UnaryTrait {
|
||||
let Spelling = "__is_interface_class";
|
||||
let KeyFlags = [KEYMS];
|
||||
}
|
||||
|
||||
def IsSealed : UnaryTrait {
|
||||
let Spelling = "__is_sealed";
|
||||
let KeyFlags = [KEYMS];
|
||||
}
|
||||
|
||||
// MSVC12.0 / VS2013 Type Traits
|
||||
def IsDestructible : UnaryTrait {
|
||||
let Spelling = "__is_destructible";
|
||||
let KeyFlags = [KEYALL];
|
||||
}
|
||||
|
||||
def IsTriviallyDestructible : UnaryTrait {
|
||||
let Spelling = "__is_trivially_destructible";
|
||||
}
|
||||
|
||||
def IsNothrowDestructible : UnaryTrait {
|
||||
let Spelling = "__is_nothrow_destructible";
|
||||
let KeyFlags = [KEYALL];
|
||||
}
|
||||
|
||||
def IsNothrowAssignable : BinaryTrait {
|
||||
let Spelling = "__is_nothrow_assignable";
|
||||
}
|
||||
|
||||
def IsConstructible : VariadicTrait {
|
||||
let Spelling = "__is_constructible";
|
||||
let StdName = "is_constructible";
|
||||
}
|
||||
|
||||
def IsNothrowConstructible : VariadicTrait {
|
||||
let Spelling = "__is_nothrow_constructible";
|
||||
}
|
||||
|
||||
// MSVC14.0 / VS2015 Type Traits
|
||||
def IsAssignable : BinaryTrait {
|
||||
let Spelling = "__is_assignable";
|
||||
let StdName = "is_assignable";
|
||||
}
|
||||
|
||||
// MSVC Type Traits of unknown vintage
|
||||
def HasNothrowMoveAssign : UnaryTrait {
|
||||
let Spelling = "__has_nothrow_move_assign";
|
||||
}
|
||||
|
||||
def HasTrivialMoveAssign : UnaryTrait {
|
||||
let Spelling = "__has_trivial_move_assign";
|
||||
}
|
||||
|
||||
def HasTrivialMoveConstructor : UnaryTrait {
|
||||
let Spelling = "__has_trivial_move_constructor";
|
||||
}
|
||||
|
||||
// GNU and MS Type Traits
|
||||
def IsImplicitLifetime : UnaryTrait {
|
||||
let Spelling = "__builtin_is_implicit_lifetime";
|
||||
}
|
||||
|
||||
def IsVirtualBaseOf : BinaryTrait {
|
||||
let Spelling = "__builtin_is_virtual_base_of";
|
||||
}
|
||||
|
||||
def HasNothrowAssign : UnaryTrait {
|
||||
let Spelling = "__has_nothrow_assign";
|
||||
}
|
||||
|
||||
def HasNothrowCopy : UnaryTrait {
|
||||
let Spelling = "__has_nothrow_copy";
|
||||
}
|
||||
|
||||
def HasNothrowConstructor : UnaryTrait {
|
||||
let Spelling = "__has_nothrow_constructor";
|
||||
}
|
||||
|
||||
def HasTrivialAssign : UnaryTrait {
|
||||
let Spelling = "__has_trivial_assign";
|
||||
}
|
||||
|
||||
def HasTrivialCopy : UnaryTrait {
|
||||
let Spelling = "__has_trivial_copy";
|
||||
}
|
||||
|
||||
def HasTrivialDefaultConstructor : UnaryTrait {
|
||||
let Spelling = "__has_trivial_constructor";
|
||||
}
|
||||
|
||||
def HasTrivialDestructor : UnaryTrait {
|
||||
let Spelling = "__has_trivial_destructor";
|
||||
}
|
||||
|
||||
def HasVirtualDestructor : UnaryTrait {
|
||||
let Spelling = "__has_virtual_destructor";
|
||||
}
|
||||
|
||||
def IsAbstract : UnaryTrait {
|
||||
let Spelling = "__is_abstract";
|
||||
let StdName = "is_abstract";
|
||||
}
|
||||
|
||||
def IsAggregate : UnaryTrait {
|
||||
let Spelling = "__is_aggregate";
|
||||
let StdName = "is_aggregate";
|
||||
}
|
||||
|
||||
def IsBaseOf : BinaryTrait {
|
||||
let Spelling = "__is_base_of";
|
||||
}
|
||||
|
||||
def IsClass : UnaryTrait {
|
||||
let Spelling = "__is_class";
|
||||
}
|
||||
|
||||
def IsConvertibleTo : BinaryTrait {
|
||||
let Spelling = "__is_convertible_to";
|
||||
}
|
||||
|
||||
def IsEmpty : UnaryTrait {
|
||||
let Spelling = "__is_empty";
|
||||
let StdName = "is_empty";
|
||||
}
|
||||
|
||||
def IsEnum : UnaryTrait {
|
||||
let Spelling = "__is_enum";
|
||||
}
|
||||
|
||||
def IsFinal : UnaryTrait {
|
||||
let Spelling = "__is_final";
|
||||
let StdName = "is_final";
|
||||
}
|
||||
|
||||
def IsLiteral : UnaryTrait {
|
||||
let Spelling = "__is_literal";
|
||||
}
|
||||
|
||||
// Name for GCC 4.6 compatibility - people have already written libraries using
|
||||
// this name unfortunately.
|
||||
def IsLiteralType : Alias<IsLiteral> {
|
||||
let Spelling = "__is_literal_type";
|
||||
}
|
||||
|
||||
def IsPOD : UnaryTrait {
|
||||
let Spelling = "__is_pod";
|
||||
}
|
||||
|
||||
def IsPolymorphic : UnaryTrait {
|
||||
let Spelling = "__is_polymorphic";
|
||||
}
|
||||
|
||||
def IsStandardLayout : UnaryTrait {
|
||||
let Spelling = "__is_standard_layout";
|
||||
let StdName = "is_standard_layout";
|
||||
}
|
||||
|
||||
def IsTrivial : UnaryTrait {
|
||||
let Spelling = "__is_trivial";
|
||||
}
|
||||
|
||||
def IsTriviallyAssignable : BinaryTrait {
|
||||
let Spelling = "__is_trivially_assignable";
|
||||
}
|
||||
|
||||
def IsTriviallyConstructible : VariadicTrait {
|
||||
let Spelling = "__is_trivially_constructible";
|
||||
}
|
||||
|
||||
def IsTriviallyCopyable : UnaryTrait {
|
||||
let Spelling = "__is_trivially_copyable";
|
||||
let StdName = "is_trivially_copyable";
|
||||
}
|
||||
|
||||
def IsUnion : UnaryTrait {
|
||||
let Spelling = "__is_union";
|
||||
}
|
||||
|
||||
def HasUniqueObjectRepresentations : UnaryTrait {
|
||||
let Spelling = "__has_unique_object_representations";
|
||||
}
|
||||
|
||||
def IsLayoutCompatible : BinaryTrait {
|
||||
let Spelling = "__is_layout_compatible";
|
||||
}
|
||||
|
||||
def IsPointerInterconvertibleBaseOf : BinaryTrait {
|
||||
let Spelling = "__is_pointer_interconvertible_base_of";
|
||||
}
|
||||
|
||||
def AddLvalueReference : TransformTypeTrait {
|
||||
let Spelling = "__add_lvalue_reference";
|
||||
let StdName = "add_lvalue_reference";
|
||||
}
|
||||
|
||||
def AddPointer : TransformTypeTrait {
|
||||
let Spelling = "__add_pointer";
|
||||
let StdName = "add_pointer";
|
||||
}
|
||||
|
||||
def AddRvalueReference : TransformTypeTrait {
|
||||
let Spelling = "__add_rvalue_reference";
|
||||
let StdName = "add_rvalue_reference";
|
||||
}
|
||||
|
||||
def Decay : TransformTypeTrait {
|
||||
let Spelling = "__decay";
|
||||
let StdName = "decay";
|
||||
}
|
||||
|
||||
def MakeSigned : TransformTypeTrait {
|
||||
let Spelling = "__make_signed";
|
||||
let StdName = "make_signed";
|
||||
}
|
||||
|
||||
def MakeUnsigned : TransformTypeTrait {
|
||||
let Spelling = "__make_unsigned";
|
||||
let StdName = "make_unsigned";
|
||||
}
|
||||
|
||||
def RemoveAllExtents : TransformTypeTrait {
|
||||
let Spelling = "__remove_all_extents";
|
||||
let StdName = "remove_all_extents";
|
||||
}
|
||||
|
||||
def RemoveConst : TransformTypeTrait {
|
||||
let Spelling = "__remove_const";
|
||||
let StdName = "remove_const";
|
||||
}
|
||||
|
||||
def RemoveCV : TransformTypeTrait {
|
||||
let Spelling = "__remove_cv";
|
||||
let StdName = "remove_cv";
|
||||
}
|
||||
|
||||
def RemoveCVRef : TransformTypeTrait {
|
||||
let Spelling = "__remove_cvref";
|
||||
let StdName = "remove_cvref";
|
||||
}
|
||||
|
||||
def RemoveExtent : TransformTypeTrait {
|
||||
let Spelling = "__remove_extent";
|
||||
let StdName = "remove_extent";
|
||||
}
|
||||
|
||||
def RemovePointer : TransformTypeTrait {
|
||||
let Spelling = "__remove_pointer";
|
||||
let StdName = "remove_pointer";
|
||||
}
|
||||
|
||||
def RemoveReference : TransformTypeTrait {
|
||||
let Spelling = "__remove_reference_t";
|
||||
let StdName = "remove_reference_t";
|
||||
}
|
||||
|
||||
def RemoveRestrict : TransformTypeTrait {
|
||||
let Spelling = "__remove_restrict";
|
||||
let StdName = "remove_restrict";
|
||||
}
|
||||
|
||||
def RemoveVolatile : TransformTypeTrait {
|
||||
let Spelling = "__remove_volatile";
|
||||
let StdName = "remove_volatile";
|
||||
}
|
||||
|
||||
def EnumUnderlyingType : TransformTypeTrait {
|
||||
let Spelling = "__underlying_type";
|
||||
let StdName = "underlying_type";
|
||||
}
|
||||
|
||||
// Clang-only C++ Type Traits
|
||||
def IsTriviallyEqualityComparable : UnaryTrait {
|
||||
let Spelling = "__is_trivially_equality_comparable";
|
||||
}
|
||||
|
||||
def IsBoundedArray : UnaryTrait {
|
||||
let Spelling = "__is_bounded_array";
|
||||
}
|
||||
|
||||
def IsUnboundedArray : UnaryTrait {
|
||||
let Spelling = "__is_unbounded_array";
|
||||
}
|
||||
|
||||
def IsScopedEnum : UnaryTrait {
|
||||
let Spelling = "__is_scoped_enum";
|
||||
}
|
||||
|
||||
def CanPassInRegs : UnaryTrait {
|
||||
let Spelling = "__can_pass_in_regs";
|
||||
}
|
||||
|
||||
def ReferenceBindsToTemporary : BinaryTrait {
|
||||
let Spelling = "__reference_binds_to_temporary";
|
||||
}
|
||||
|
||||
def ReferenceConstructsFromTemporary : BinaryTrait {
|
||||
let Spelling = "__reference_constructs_from_temporary";
|
||||
}
|
||||
|
||||
def ReferenceConvertsFromTemporary : BinaryTrait {
|
||||
let Spelling = "__reference_converts_from_temporary";
|
||||
}
|
||||
|
||||
def LtSynthesizesFromSpaceship : BinaryTrait {
|
||||
let Spelling = "__builtin_lt_synthesizes_from_spaceship";
|
||||
}
|
||||
|
||||
def LeSynthesizesFromSpaceship : BinaryTrait {
|
||||
let Spelling = "__builtin_le_synthesizes_from_spaceship";
|
||||
}
|
||||
|
||||
def GtSynthesizesFromSpaceship : BinaryTrait {
|
||||
let Spelling = "__builtin_gt_synthesizes_from_spaceship";
|
||||
}
|
||||
|
||||
def GeSynthesizesFromSpaceship : BinaryTrait {
|
||||
let Spelling = "__builtin_ge_synthesizes_from_spaceship";
|
||||
}
|
||||
|
||||
// IsDeducible is only used internally by clang for CTAD implementation and
|
||||
// is not exposed to users.
|
||||
def IsDeducible : BinaryTrait {}
|
||||
|
||||
// __is_trivially_relocatable is deprecated
|
||||
def IsCppTriviallyRelocatable : UnaryTrait {
|
||||
let Spelling = "__builtin_is_cpp_trivially_relocatable";
|
||||
let StdName = "is_trivially_relocatable";
|
||||
}
|
||||
|
||||
def IsTriviallyRelocatable : UnaryTrait {
|
||||
let Spelling = "__is_trivially_relocatable";
|
||||
}
|
||||
|
||||
def IsBitwiseCloneable : UnaryTrait {
|
||||
let Spelling = "__is_bitwise_cloneable";
|
||||
let KeyFlags = [KEYALL];
|
||||
}
|
||||
|
||||
def StructuredBindingSize : UnaryTrait {
|
||||
let Spelling = "__builtin_structured_binding_size";
|
||||
}
|
||||
|
||||
// Embarcadero Expression Traits
|
||||
def IsLValueExpr : ExpressionTrait {
|
||||
let Spelling = "__is_lvalue_expr";
|
||||
}
|
||||
|
||||
def IsRValueExpr : ExpressionTrait {
|
||||
let Spelling = "__is_rvalue_expr";
|
||||
}
|
||||
|
||||
// Embarcadero Unary Type Traits
|
||||
def IsArithmetic : UnaryTrait {
|
||||
let Spelling = "__is_arithmetic";
|
||||
}
|
||||
|
||||
def IsFloatingPoint : UnaryTrait {
|
||||
let Spelling = "__is_floating_point";
|
||||
}
|
||||
|
||||
def IsIntegral : UnaryTrait {
|
||||
let Spelling = "__is_integral";
|
||||
}
|
||||
|
||||
def IsCompleteType : UnaryTrait {
|
||||
let Spelling = "__is_complete_type";
|
||||
}
|
||||
|
||||
def IsVoid : UnaryTrait {
|
||||
let Spelling = "__is_void";
|
||||
}
|
||||
|
||||
def IsArray : UnaryTrait {
|
||||
let Spelling = "__is_array";
|
||||
}
|
||||
|
||||
def IsFunction : UnaryTrait {
|
||||
let Spelling = "__is_function";
|
||||
}
|
||||
|
||||
def IsReference : UnaryTrait {
|
||||
let Spelling = "__is_reference";
|
||||
}
|
||||
|
||||
def IsLvalueReference : UnaryTrait {
|
||||
let Spelling = "__is_lvalue_reference";
|
||||
}
|
||||
|
||||
def IsRvalueReference : UnaryTrait {
|
||||
let Spelling = "__is_rvalue_reference";
|
||||
}
|
||||
|
||||
def IsFundamental : UnaryTrait {
|
||||
let Spelling = "__is_fundamental";
|
||||
}
|
||||
|
||||
def IsObject : UnaryTrait {
|
||||
let Spelling = "__is_object";
|
||||
}
|
||||
|
||||
def IsScalar : UnaryTrait {
|
||||
let Spelling = "__is_scalar";
|
||||
}
|
||||
|
||||
def IsCompound : UnaryTrait {
|
||||
let Spelling = "__is_compound";
|
||||
}
|
||||
|
||||
def IsPointer : UnaryTrait {
|
||||
let Spelling = "__is_pointer";
|
||||
}
|
||||
|
||||
def IsMemberObjectPointer : UnaryTrait {
|
||||
let Spelling = "__is_member_object_pointer";
|
||||
}
|
||||
|
||||
def IsMemberFunctionPointer : UnaryTrait {
|
||||
let Spelling = "__is_member_function_pointer";
|
||||
}
|
||||
|
||||
def IsMemberPointer : UnaryTrait {
|
||||
let Spelling = "__is_member_pointer";
|
||||
}
|
||||
|
||||
def IsConst : UnaryTrait {
|
||||
let Spelling = "__is_const";
|
||||
}
|
||||
|
||||
def IsVolatile : UnaryTrait {
|
||||
let Spelling = "__is_volatile";
|
||||
}
|
||||
|
||||
def IsSigned : UnaryTrait {
|
||||
let Spelling = "__is_signed";
|
||||
}
|
||||
|
||||
def IsUnsigned : UnaryTrait {
|
||||
let Spelling = "__is_unsigned";
|
||||
}
|
||||
|
||||
// Embarcadero Binary Type Traits
|
||||
def IsSame : BinaryTrait {
|
||||
let Spelling = "__is_same";
|
||||
}
|
||||
|
||||
// Name for GCC 6 compatibility
|
||||
def IsSameAs : Alias<IsSame> {
|
||||
let Spelling = "__is_same_as";
|
||||
}
|
||||
|
||||
def IsConvertible : BinaryTrait {
|
||||
let Spelling = "__is_convertible";
|
||||
}
|
||||
|
||||
def IsNothrowConvertible : BinaryTrait {
|
||||
let Spelling = "__is_nothrow_convertible";
|
||||
}
|
||||
|
||||
def ArrayRank : ArrayTrait {
|
||||
let Spelling = "__array_rank";
|
||||
}
|
||||
|
||||
def ArrayExtent : ArrayTrait {
|
||||
let Spelling = "__array_extent";
|
||||
}
|
||||
|
||||
// Apple Extension.
|
||||
def PtrAuthTypeDiscriminator : UnaryExprOrTypeTrait {
|
||||
let Spelling = "__builtin_ptrauth_type_discriminator";
|
||||
let KeyFlags = [KEYALL];
|
||||
}
|
||||
|
||||
// OpenCL builtins
|
||||
def VecStep : UnaryExprOrTypeTrait {
|
||||
let Spelling = "vec_step";
|
||||
let KeyFlags = [KEYOPENCLC, KEYOPENCLCXX, KEYALTIVEC, KEYZVECTOR];
|
||||
}
|
||||
|
||||
// HLSL Type traits
|
||||
def IsScalarizedLayoutCompatible : BinaryTrait {
|
||||
let Spelling = "__builtin_hlsl_is_scalarized_layout_compatible";
|
||||
let KeyFlags = [KEYHLSL];
|
||||
}
|
||||
|
||||
def IsIntangibleType : UnaryTrait {
|
||||
let Spelling = "__builtin_hlsl_is_intangible";
|
||||
let KeyFlags = [KEYHLSL];
|
||||
}
|
||||
|
||||
def IsTypedResourceElementCompatible : UnaryTrait {
|
||||
let Spelling = "__builtin_hlsl_is_typed_resource_element_compatible";
|
||||
let KeyFlags = [KEYHLSL];
|
||||
}
|
||||
|
||||
def IsConstantBufferElementCompatible : UnaryTrait {
|
||||
let Spelling = "__builtin_hlsl_is_constant_buffer_element_compatible";
|
||||
let KeyFlags = [KEYHLSL];
|
||||
}
|
||||
|
||||
// OpenMP Type Traits
|
||||
def OpenMPRequiredSimdAlign : UnaryExprOrTypeTrait {
|
||||
let Spelling = "__builtin_omp_required_simd_align";
|
||||
let KeyFlags = [KEYALL];
|
||||
}
|
||||
|
||||
// Clang Extensions.
|
||||
def VectorElements : UnaryExprOrTypeTrait {
|
||||
let Spelling = "__builtin_vectorelements";
|
||||
let KeyFlags = [KEYALL];
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
//==--- TransformTypeTraits.def - type trait transformations --------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines transform type traits' names.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
TRANSFORM_TYPE_TRAIT_DEF(AddLvalueReference, add_lvalue_reference)
|
||||
TRANSFORM_TYPE_TRAIT_DEF(AddPointer, add_pointer)
|
||||
TRANSFORM_TYPE_TRAIT_DEF(AddRvalueReference, add_rvalue_reference)
|
||||
TRANSFORM_TYPE_TRAIT_DEF(Decay, decay)
|
||||
TRANSFORM_TYPE_TRAIT_DEF(MakeSigned, make_signed)
|
||||
TRANSFORM_TYPE_TRAIT_DEF(MakeUnsigned, make_unsigned)
|
||||
TRANSFORM_TYPE_TRAIT_DEF(RemoveAllExtents, remove_all_extents)
|
||||
TRANSFORM_TYPE_TRAIT_DEF(RemoveConst, remove_const)
|
||||
TRANSFORM_TYPE_TRAIT_DEF(RemoveCV, remove_cv)
|
||||
TRANSFORM_TYPE_TRAIT_DEF(RemoveCVRef, remove_cvref)
|
||||
TRANSFORM_TYPE_TRAIT_DEF(RemoveExtent, remove_extent)
|
||||
TRANSFORM_TYPE_TRAIT_DEF(RemovePointer, remove_pointer)
|
||||
TRANSFORM_TYPE_TRAIT_DEF(RemoveReference, remove_reference_t)
|
||||
TRANSFORM_TYPE_TRAIT_DEF(RemoveRestrict, remove_restrict)
|
||||
TRANSFORM_TYPE_TRAIT_DEF(RemoveVolatile, remove_volatile)
|
||||
TRANSFORM_TYPE_TRAIT_DEF(EnumUnderlyingType, underlying_type)
|
||||
#undef TRANSFORM_TYPE_TRAIT_DEF
|
||||
|
|
@ -18,45 +18,28 @@
|
|||
|
||||
namespace clang {
|
||||
/// Names for traits that operate specifically on types.
|
||||
enum TypeTrait {
|
||||
#define TYPE_TRAIT_1(Spelling, Name, Key) UTT_##Name,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
UTT_Last = -1 // UTT_Last == last UTT_XX in the enum.
|
||||
#define TYPE_TRAIT_1(Spelling, Name, Key) +1
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
,
|
||||
#define TYPE_TRAIT_2(Spelling, Name, Key) BTT_##Name,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
BTT_Last = UTT_Last // BTT_Last == last BTT_XX in the enum.
|
||||
#define TYPE_TRAIT_2(Spelling, Name, Key) +1
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
,
|
||||
#define TYPE_TRAIT_N(Spelling, Name, Key) TT_##Name,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
TT_Last = BTT_Last // TT_Last == last TT_XX in the enum.
|
||||
#define TYPE_TRAIT_N(Spelling, Name, Key) +1
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
};
|
||||
// enum TypeTrait {
|
||||
// UTT_ ...
|
||||
// UTT_Last == last UTT_XX in the enum.
|
||||
// BTT_ ...
|
||||
// BTT_Last == last BTT_XX in the enum.
|
||||
// TT_ ...
|
||||
// TT_Last == last TT_XX in the enum.
|
||||
// };
|
||||
|
||||
/// Names for the array type traits.
|
||||
enum ArrayTypeTrait {
|
||||
#define ARRAY_TYPE_TRAIT(Spelling, Name, Key) ATT_##Name,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
ATT_Last = -1 // ATT_Last == last ATT_XX in the enum.
|
||||
#define ARRAY_TYPE_TRAIT(Spelling, Name, Key) +1
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
};
|
||||
// enum ArrayTypeTrait {
|
||||
// ATT_ ...
|
||||
// ATT_Last == last ATT_XX in the enum.
|
||||
// };
|
||||
|
||||
/// Names for the "expression or type" traits.
|
||||
enum UnaryExprOrTypeTrait {
|
||||
#define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) UETT_##Name,
|
||||
#define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) UETT_##Name,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
UETT_Last = -1 // UETT_Last == last UETT_XX in the enum.
|
||||
#define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) +1
|
||||
#define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) +1
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
};
|
||||
// enum UnaryExprOrTypeTrait {
|
||||
// UETT_ ...
|
||||
// UETT_Last == last UETT_XX in the enum.
|
||||
// };
|
||||
#define EMIT_ENUMS
|
||||
#include "clang/Basic/Traits.inc"
|
||||
|
||||
/// Return the internal name of type trait \p T. Never null.
|
||||
const char *getTraitName(TypeTrait T) LLVM_READONLY;
|
||||
|
|
|
|||
|
|
@ -880,6 +880,8 @@ def CIR_UnionType : CIR_Type<"Union", "union", [
|
|||
/// the storage type when lowering to LLVM IR). Returns a null type for
|
||||
/// empty unions.
|
||||
mlir::Type getUnionStorageType(const mlir::DataLayout &dataLayout) const;
|
||||
static mlir::Type getUnionStorageType(const mlir::DataLayout &dataLayout,
|
||||
llvm::ArrayRef<mlir::Type> members);
|
||||
|
||||
void complete(llvm::ArrayRef<mlir::Type> members, bool packed,
|
||||
mlir::Type padding = {});
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#define LLVM_CLANG_CIR_LOWERINGHELPERS_H
|
||||
|
||||
#include "mlir/IR/BuiltinAttributes.h"
|
||||
#include "mlir/Interfaces/DataLayoutInterfaces.h"
|
||||
#include "mlir/Transforms/DialectConversion.h"
|
||||
#include "clang/CIR/Dialect/IR/CIRDialect.h"
|
||||
|
||||
|
|
@ -43,6 +44,18 @@ lowerConstRecordAttr(cir::ConstRecordAttr constRecord,
|
|||
const mlir::TypeConverter *converter,
|
||||
mlir::ModuleOp moduleOp = {});
|
||||
|
||||
/// Adjust \p llvmType (the converted type of \p init) to the concrete LLVM type
|
||||
/// a global constant initialized with \p init actually lowers to. This differs
|
||||
/// from a plain type conversion for flexible-array-member and union
|
||||
/// initializers, and the adjustment recurses through nested aggregates. Returns
|
||||
/// \p llvmType unchanged when no adjustment is needed. This is the single
|
||||
/// source of truth for the shape of a lowered record constant; the
|
||||
/// value-producing paths (the insertvalue visitor and lowerConstRecordAttr)
|
||||
/// conform to it.
|
||||
mlir::Type adjustGlobalTypeForInit(mlir::Type llvmType, mlir::Attribute init,
|
||||
const mlir::TypeConverter &converter,
|
||||
const mlir::DataLayout &dataLayout);
|
||||
|
||||
mlir::Value getConstAPInt(mlir::OpBuilder &bld, mlir::Location loc,
|
||||
mlir::Type typ, const llvm::APInt &val);
|
||||
|
||||
|
|
|
|||
|
|
@ -4933,6 +4933,19 @@ def fno_wrapv : Flag<["-"], "fno-wrapv">, Group<f_Group>,
|
|||
def fwrapv_pointer : Flag<["-"], "fwrapv-pointer">, Group<f_Group>,
|
||||
Visibility<[ClangOption, CLOption, CC1Option, FlangOption, FC1Option]>,
|
||||
HelpText<"Treat pointer overflow as two's complement">;
|
||||
def fdefined_pointer_subtraction :
|
||||
Flag<["-"], "fdefined-pointer-subtraction">, Group<f_Group>,
|
||||
Visibility<[ClangOption, CC1Option]>,
|
||||
HelpText<
|
||||
"Define subtraction of pointers not aligned to object boundaries"
|
||||
>,
|
||||
DocBrief<
|
||||
"When subtracting two pointers, do not assume that the byte difference is an "
|
||||
"exact multiple of the pointee type size, thereby preventing such subtraction "
|
||||
"from resulting in undefined behavior. Users should prefer casting pointers "
|
||||
"to ``char *`` before subtracting them rather than relying on this flag."
|
||||
>,
|
||||
MarshallingInfoFlag<LangOpts<"StablePointerSubtraction">>;
|
||||
def fno_wrapv_pointer : Flag<["-"], "fno-wrapv-pointer">, Group<f_Group>,
|
||||
Visibility<[ClangOption, CLOption, FlangOption]>;
|
||||
def fwritable_strings : Flag<["-"], "fwritable-strings">, Group<f_Group>,
|
||||
|
|
|
|||
|
|
@ -287,7 +287,7 @@ public:
|
|||
clang::TST_typename_pack_indexing;
|
||||
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \
|
||||
static const TST TST_##Trait = clang::TST_##Trait;
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
static const TST TST_auto = clang::TST_auto;
|
||||
static const TST TST_auto_type = clang::TST_auto_type;
|
||||
static const TST TST_unknown_anytype = clang::TST_unknown_anytype;
|
||||
|
|
@ -502,7 +502,7 @@ public:
|
|||
static bool isTransformTypeTrait(TST T) {
|
||||
constexpr std::array<TST, 16> Traits = {
|
||||
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) TST_##Trait,
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
};
|
||||
|
||||
return T >= Traits.front() && T <= Traits.back();
|
||||
|
|
|
|||
|
|
@ -10924,6 +10924,12 @@ public:
|
|||
const UnresolvedSetImpl &Fns,
|
||||
bool PerformADL = true);
|
||||
|
||||
/// Perform lookup for an overloaded unary operator.
|
||||
void LookupOverloadedUnaryOp(OverloadCandidateSet &CandidateSet,
|
||||
OverloadedOperatorKind Op,
|
||||
const UnresolvedSetImpl &Fns,
|
||||
ArrayRef<Expr *> Args, bool RequiresADL = true);
|
||||
|
||||
/// Create a unary operation that may resolve to an overloaded
|
||||
/// operator.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -276,6 +276,9 @@ public:
|
|||
|
||||
SourceRange getSourceRange() const { return {getBeginLoc(), getEndLoc()}; }
|
||||
|
||||
void dump(ASTContext &Context) const;
|
||||
void dump(llvm::raw_ostream &OS, ASTContext &Context) const;
|
||||
|
||||
private:
|
||||
friend class Sema;
|
||||
static NormalizedConstraint *
|
||||
|
|
|
|||
|
|
@ -103,6 +103,11 @@ public:
|
|||
|
||||
const StackFrame *getStackFrame() const { return Pred->getStackFrame(); }
|
||||
|
||||
/// Iterates over the current stack frame and all of its ancestors.
|
||||
llvm::iterator_range<StackFrame::parent_iterator> stackframes() const {
|
||||
return getStackFrame()->parentsIncludingSelf();
|
||||
}
|
||||
|
||||
/// Return true if the current StackFrame has no caller context.
|
||||
bool inTopFrame() const { return getStackFrame()->inTopFrame(); }
|
||||
|
||||
|
|
|
|||
|
|
@ -144,6 +144,11 @@ public:
|
|||
return getLocation().getStackFrame();
|
||||
}
|
||||
|
||||
/// Iterates over the current stack frame and all of its ancestors.
|
||||
llvm::iterator_range<StackFrame::parent_iterator> stackframes() const {
|
||||
return getStackFrame()->parentsIncludingSelf();
|
||||
}
|
||||
|
||||
const Decl &getCodeDecl() const { return *getStackFrame()->getDecl(); }
|
||||
|
||||
CFG &getCFG() const { return *getStackFrame()->getCFG(); }
|
||||
|
|
|
|||
|
|
@ -843,8 +843,10 @@ private:
|
|||
bool isLoad);
|
||||
|
||||
/// Count the stack depth and determine if the call is recursive.
|
||||
void examineStackFrames(const Decl *D, const StackFrame *SF,
|
||||
bool &IsRecursive, unsigned &StackDepth);
|
||||
void
|
||||
examineStackFrames(const Decl *D,
|
||||
llvm::iterator_range<StackFrame::parent_iterator> Frames,
|
||||
bool &IsRecursive, unsigned &StackDepth);
|
||||
|
||||
enum CallInlinePolicy {
|
||||
CIP_Allowed,
|
||||
|
|
|
|||
|
|
@ -74,7 +74,6 @@ module Clang_Basic {
|
|||
textual header "clang/Basic/TargetCXXABI.def"
|
||||
textual header "clang/Basic/TargetOSMacros.def"
|
||||
textual header "clang/Basic/TokenKinds.def"
|
||||
textual header "clang/Basic/TransformTypeTraits.def"
|
||||
textual header "clang/Basic/WebAssemblyReferenceTypes.def"
|
||||
|
||||
module * { export * }
|
||||
|
|
|
|||
|
|
@ -1628,7 +1628,9 @@ QualType CallExpr::getCallReturnType(const ASTContext &Ctx) const {
|
|||
// dependent call to the call operator of that type.
|
||||
return Ctx.DependentTy;
|
||||
} else if (CalleeType->isDependentType() ||
|
||||
CalleeType->isSpecificPlaceholderType(BuiltinType::Overload)) {
|
||||
CalleeType->isSpecificPlaceholderType(BuiltinType::Overload) ||
|
||||
CalleeType->isSpecificPlaceholderType(BuiltinType::BuiltinFn)) {
|
||||
// Dependent builtin calls keep their placeholder until instantiation.
|
||||
return Ctx.DependentTy;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4580,7 +4580,7 @@ void CXXNameMangler::mangleType(const UnaryTransformType *T) {
|
|||
case UnaryTransformType::Enum: \
|
||||
BuiltinName = "__" #Trait; \
|
||||
break;
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
}
|
||||
mangleVendorType(BuiltinName);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -771,7 +771,7 @@ void JSONNodeDumper::VisitUnaryTransformType(const UnaryTransformType *UTT) {
|
|||
case UnaryTransformType::Enum: \
|
||||
JOS.attribute("transformKind", #Trait); \
|
||||
break;
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -161,6 +161,8 @@ namespace {
|
|||
|
||||
void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node);
|
||||
|
||||
void VisitBinComma(BinaryOperator *Node);
|
||||
|
||||
#define ABSTRACT_STMT(CLASS)
|
||||
#define STMT(CLASS, PARENT) \
|
||||
void Visit##CLASS(CLASS *Node);
|
||||
|
|
@ -1882,6 +1884,24 @@ void StmtPrinter::VisitMatrixElementExpr(MatrixElementExpr *Node) {
|
|||
}
|
||||
|
||||
void StmtPrinter::VisitCStyleCastExpr(CStyleCastExpr *Node) {
|
||||
if (QualType T = Node->getType(); Policy.PrettyEnums && T->isEnumeralType()) {
|
||||
// special case enums to avoid producing cast expressions when naming
|
||||
// an enumerator would suffice
|
||||
|
||||
const auto *IL = dyn_cast<IntegerLiteral>(Node->getSubExpr());
|
||||
const auto *ED = T->getAsEnumDecl();
|
||||
if (IL && ED) {
|
||||
llvm::APInt Val = IL->getValue();
|
||||
const auto ECD =
|
||||
llvm::find_if(ED->enumerators(), [&](const EnumConstantDecl *ECD) {
|
||||
return llvm::APInt::isSameValue(ECD->getInitVal(), Val);
|
||||
});
|
||||
if (ECD != ED->enumerator_end()) {
|
||||
ECD->printQualifiedName(OS, Policy);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
OS << '(';
|
||||
Node->getTypeAsWritten().print(OS, Policy);
|
||||
OS << ')';
|
||||
|
|
@ -1900,6 +1920,12 @@ void StmtPrinter::VisitImplicitCastExpr(ImplicitCastExpr *Node) {
|
|||
PrintExpr(Node->getSubExpr());
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitBinComma(BinaryOperator *Node) {
|
||||
PrintExpr(Node->getLHS());
|
||||
OS << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " ";
|
||||
PrintExpr(Node->getRHS());
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitBinaryOperator(BinaryOperator *Node) {
|
||||
PrintExpr(Node->getLHS());
|
||||
OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " ";
|
||||
|
|
|
|||
|
|
@ -258,6 +258,32 @@ TemplateArgument::CreatePackCopy(ASTContext &Context,
|
|||
return TemplateArgument(Args.copy(Context));
|
||||
}
|
||||
|
||||
StringRef TemplateArgument::getKindName() const {
|
||||
switch (getKind()) {
|
||||
case TemplateArgument::Null:
|
||||
return "null";
|
||||
case TemplateArgument::Type:
|
||||
return "type";
|
||||
case TemplateArgument::Declaration:
|
||||
return "decl";
|
||||
case TemplateArgument::NullPtr:
|
||||
return "nullptr";
|
||||
case TemplateArgument::Integral:
|
||||
return "integral";
|
||||
case TemplateArgument::Template:
|
||||
return "template";
|
||||
case TemplateArgument::TemplateExpansion:
|
||||
return "template expansion";
|
||||
case TemplateArgument::Expression:
|
||||
return "expression";
|
||||
case TemplateArgument::Pack:
|
||||
return "pack";
|
||||
case TemplateArgument::StructuralValue:
|
||||
return "structural value";
|
||||
}
|
||||
llvm_unreachable("unhandled ArgKind");
|
||||
}
|
||||
|
||||
TemplateArgumentDependence TemplateArgument::getDependence() const {
|
||||
auto Deps = TemplateArgumentDependence::None;
|
||||
switch (getKind()) {
|
||||
|
|
|
|||
|
|
@ -2244,7 +2244,7 @@ void TextNodeDumper::VisitUnaryTransformType(const UnaryTransformType *T) {
|
|||
case UnaryTransformType::Enum: \
|
||||
OS << " " #Trait; \
|
||||
break;
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1395,7 +1395,7 @@ void TypePrinter::printUnaryTransformBefore(const UnaryTransformType *T,
|
|||
static const llvm::DenseMap<int, const char *> Transformation = {{
|
||||
#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait) \
|
||||
{UnaryTransformType::Enum, "__" #Trait},
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
}};
|
||||
OS << Transformation.lookup(T->getUTTKind()) << '(';
|
||||
print(T->getBaseType(), OS, StringRef());
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ clang::ast_matchers::dynamic::internal::ArgTypeTraits<
|
|||
static constexpr llvm::StringRef Allowed[] = {
|
||||
#define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) "UETT_" #Name,
|
||||
#define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) "UETT_" #Name,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
};
|
||||
if (Value.isString())
|
||||
return ::getBestGuess(Value.getString(), llvm::ArrayRef(Allowed), "UETT_");
|
||||
|
|
|
|||
|
|
@ -276,7 +276,7 @@ private:
|
|||
#define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) .Case(#Name, UETT_##Name)
|
||||
#define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) \
|
||||
.Case(#Name, UETT_##Name)
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
.Default(std::nullopt);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include "clang/Basic/SourceManager.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
|
|
@ -424,15 +425,8 @@ const StackFrame *StackFrameManager::getStackFrame(
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
bool StackFrame::isParentOf(const StackFrame *SF) const {
|
||||
do {
|
||||
const StackFrame *Parent = SF->getParent();
|
||||
if (Parent == this)
|
||||
return true;
|
||||
else
|
||||
SF = Parent;
|
||||
} while (SF);
|
||||
|
||||
return false;
|
||||
return llvm::any_of(SF->parents(),
|
||||
[this](const StackFrame &A) { return &A == this; });
|
||||
}
|
||||
|
||||
static void printLocation(raw_ostream &Out, const SourceManager &SM,
|
||||
|
|
@ -451,15 +445,13 @@ void StackFrame::dumpStack(raw_ostream &Out) const {
|
|||
const SourceManager &SM =
|
||||
getAnalysisDeclContext()->getASTContext().getSourceManager();
|
||||
|
||||
unsigned Frame = 0;
|
||||
for (const StackFrame *SF = this; SF; SF = SF->getParent()) {
|
||||
Out << "\t#" << Frame << ' ';
|
||||
++Frame;
|
||||
if (const auto *D = dyn_cast<NamedDecl>(SF->getDecl()))
|
||||
for (auto [Idx, SF] : llvm::enumerate(parentsIncludingSelf())) {
|
||||
Out << "\t#" << Idx << ' ';
|
||||
if (const auto *D = dyn_cast<NamedDecl>(SF.getDecl()))
|
||||
Out << "Calling " << AnalysisDeclContext::getFunctionName(D);
|
||||
else
|
||||
Out << "Calling anonymous code";
|
||||
if (const Expr *E = SF->getCallSite()) {
|
||||
if (const Expr *E = SF.getCallSite()) {
|
||||
Out << " at line ";
|
||||
printLocation(Out, SM, E->getBeginLoc());
|
||||
}
|
||||
|
|
@ -477,19 +469,17 @@ void StackFrame::printJson(
|
|||
const SourceManager &SM =
|
||||
getAnalysisDeclContext()->getASTContext().getSourceManager();
|
||||
|
||||
unsigned Frame = 0;
|
||||
for (const StackFrame *SF = this; SF; SF = SF->getParent()) {
|
||||
for (auto [Idx, SF] : llvm::enumerate(parentsIncludingSelf())) {
|
||||
Indent(Out, Space, IsDot)
|
||||
<< "{ \"lctx_id\": " << SF->getID() << ", \"location_context\": \"";
|
||||
Out << '#' << Frame << " Call\", \"calling\": \"";
|
||||
++Frame;
|
||||
if (const auto *D = dyn_cast<NamedDecl>(SF->getDecl()))
|
||||
<< "{ \"lctx_id\": " << SF.getID() << ", \"location_context\": \"";
|
||||
Out << '#' << Idx << " Call\", \"calling\": \"";
|
||||
if (const auto *D = dyn_cast<NamedDecl>(SF.getDecl()))
|
||||
Out << D->getQualifiedNameAsString();
|
||||
else
|
||||
Out << "anonymous code";
|
||||
|
||||
Out << "\", \"location\": ";
|
||||
if (const Expr *E = SF->getCallSite()) {
|
||||
if (const Expr *E = SF.getCallSite()) {
|
||||
printSourceLocationAsJson(Out, E->getBeginLoc(), SM);
|
||||
} else {
|
||||
Out << "null";
|
||||
|
|
@ -497,10 +487,10 @@ void StackFrame::printJson(
|
|||
|
||||
Out << ", \"items\": ";
|
||||
|
||||
printMoreInfoPerStackFrame(SF);
|
||||
printMoreInfoPerStackFrame(&SF);
|
||||
|
||||
Out << '}';
|
||||
if (SF->getParent())
|
||||
if (SF.getParent())
|
||||
Out << ',';
|
||||
Out << NL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,9 +30,6 @@ namespace {
|
|||
class LiveVariablesImpl {
|
||||
public:
|
||||
template <typename T> using SetTy = LiveVariables::SetTy<T>;
|
||||
template <typename T>
|
||||
using SetRefTy = llvm::ImmutableSetRef<T, llvm::ImutContainerInfo<T>,
|
||||
/*Canonicalize=*/false>;
|
||||
|
||||
AnalysisDeclContext &analysisContext;
|
||||
SetTy<const Expr *>::Factory ESetFact;
|
||||
|
|
@ -89,51 +86,18 @@ bool LiveVariables::LivenessValues::isLive(const VarDecl *D) const {
|
|||
return liveDecls.contains(D);
|
||||
}
|
||||
|
||||
namespace {
|
||||
template <typename SET> SET mergeSets(SET A, SET B) {
|
||||
if (A.getRootWithoutRetain() == B.getRootWithoutRetain())
|
||||
return A;
|
||||
|
||||
if (A.getHeight() < B.getHeight())
|
||||
std::swap(A, B);
|
||||
|
||||
for (const auto *Elem : B) {
|
||||
A = A.add(Elem);
|
||||
}
|
||||
return A;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void LiveVariables::Observer::anchor() { }
|
||||
|
||||
LiveVariables::LivenessValues
|
||||
LiveVariablesImpl::merge(LiveVariables::LivenessValues valsA,
|
||||
LiveVariables::LivenessValues valsB) {
|
||||
|
||||
SetRefTy<const Expr *> SSetRefA(valsA.liveExprs.getRootWithoutRetain(),
|
||||
ESetFact.getTreeFactory()),
|
||||
SSetRefB(valsB.liveExprs.getRootWithoutRetain(),
|
||||
ESetFact.getTreeFactory());
|
||||
|
||||
SetRefTy<const VarDecl *> DSetRefA(valsA.liveDecls.getRootWithoutRetain(),
|
||||
DSetFact.getTreeFactory()),
|
||||
DSetRefB(valsB.liveDecls.getRootWithoutRetain(),
|
||||
DSetFact.getTreeFactory());
|
||||
|
||||
SetRefTy<const BindingDecl *> BSetRefA(
|
||||
valsA.liveBindings.getRootWithoutRetain(), BSetFact.getTreeFactory()),
|
||||
BSetRefB(valsB.liveBindings.getRootWithoutRetain(),
|
||||
BSetFact.getTreeFactory());
|
||||
|
||||
SSetRefA = mergeSets(SSetRefA, SSetRefB);
|
||||
DSetRefA = mergeSets(DSetRefA, DSetRefB);
|
||||
BSetRefA = mergeSets(BSetRefA, BSetRefB);
|
||||
|
||||
// Finalize the merged builder refs into immutable sets. These are not
|
||||
// canonicalized; LivenessValues::operator== compares them structurally.
|
||||
return LiveVariables::LivenessValues(SSetRefA.asImmutableSet(),
|
||||
DSetRefA.asImmutableSet(),
|
||||
BSetRefA.asImmutableSet());
|
||||
// Liveness at a merge point is the union of the successors' live sets. These
|
||||
// sets are not canonicalized; LivenessValues::operator== compares them
|
||||
// structurally.
|
||||
return LiveVariables::LivenessValues(
|
||||
ESetFact.unionSets(valsA.liveExprs, valsB.liveExprs),
|
||||
DSetFact.unionSets(valsA.liveDecls, valsB.liveDecls),
|
||||
BSetFact.unionSets(valsA.liveBindings, valsB.liveBindings));
|
||||
}
|
||||
|
||||
bool LiveVariables::LivenessValues::operator==(const LivenessValues &V) const {
|
||||
|
|
|
|||
|
|
@ -16,12 +16,12 @@ using namespace clang;
|
|||
|
||||
static constexpr const char *ExpressionTraitNames[] = {
|
||||
#define EXPRESSION_TRAIT(Spelling, Name, Key) #Name,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
};
|
||||
|
||||
static constexpr const char *ExpressionTraitSpellings[] = {
|
||||
#define EXPRESSION_TRAIT(Spelling, Name, Key) #Spelling,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
};
|
||||
|
||||
const char *clang::getTraitName(ExpressionTrait T) {
|
||||
|
|
|
|||
|
|
@ -24,37 +24,37 @@
|
|||
#include <cstdlib>
|
||||
using namespace clang;
|
||||
|
||||
static const LangASMap DefaultAddrSpaceMap = {0};
|
||||
static constexpr LangASMap DefaultAddrSpaceMap;
|
||||
// The fake address space map must have a distinct entry for each
|
||||
// language-specific address space.
|
||||
static const LangASMap FakeAddrSpaceMap = {
|
||||
0, // Default
|
||||
1, // opencl_global
|
||||
3, // opencl_local
|
||||
2, // opencl_constant
|
||||
0, // opencl_private
|
||||
4, // opencl_generic
|
||||
5, // opencl_global_device
|
||||
6, // opencl_global_host
|
||||
7, // cuda_device
|
||||
8, // cuda_constant
|
||||
9, // cuda_shared
|
||||
1, // sycl_global
|
||||
5, // sycl_global_device
|
||||
6, // sycl_global_host
|
||||
3, // sycl_local
|
||||
0, // sycl_private
|
||||
10, // ptr32_sptr
|
||||
11, // ptr32_uptr
|
||||
12, // ptr64
|
||||
13, // hlsl_groupshared
|
||||
14, // hlsl_constant
|
||||
15, // hlsl_private
|
||||
16, // hlsl_device
|
||||
17, // hlsl_input
|
||||
18, // hlsl_output
|
||||
19, // hlsl_push_constant
|
||||
20, // wasm_funcref
|
||||
static constexpr LangASMap FakeAddrSpaceMap = {
|
||||
{LangAS::Default, 0},
|
||||
{LangAS::opencl_global, 1},
|
||||
{LangAS::opencl_local, 3},
|
||||
{LangAS::opencl_constant, 2},
|
||||
{LangAS::opencl_private, 0},
|
||||
{LangAS::opencl_generic, 4},
|
||||
{LangAS::opencl_global_device, 5},
|
||||
{LangAS::opencl_global_host, 6},
|
||||
{LangAS::cuda_device, 7},
|
||||
{LangAS::cuda_constant, 8},
|
||||
{LangAS::cuda_shared, 9},
|
||||
{LangAS::sycl_global, 1},
|
||||
{LangAS::sycl_global_device, 5},
|
||||
{LangAS::sycl_global_host, 6},
|
||||
{LangAS::sycl_local, 3},
|
||||
{LangAS::sycl_private, 0},
|
||||
{LangAS::ptr32_sptr, 10},
|
||||
{LangAS::ptr32_uptr, 11},
|
||||
{LangAS::ptr64, 12},
|
||||
{LangAS::hlsl_groupshared, 13},
|
||||
{LangAS::hlsl_constant, 14},
|
||||
{LangAS::hlsl_private, 15},
|
||||
{LangAS::hlsl_device, 16},
|
||||
{LangAS::hlsl_input, 17},
|
||||
{LangAS::hlsl_output, 18},
|
||||
{LangAS::hlsl_push_constant, 19},
|
||||
{LangAS::wasm_funcref, 20},
|
||||
};
|
||||
|
||||
// TargetInfo Constructor.
|
||||
|
|
|
|||
|
|
@ -24,36 +24,10 @@ namespace targets {
|
|||
|
||||
enum AArch64AddrSpace { ptr32_sptr = 270, ptr32_uptr = 271, ptr64 = 272 };
|
||||
|
||||
static const unsigned ARM64AddrSpaceMap[] = {
|
||||
0, // Default
|
||||
0, // opencl_global
|
||||
0, // opencl_local
|
||||
0, // opencl_constant
|
||||
0, // opencl_private
|
||||
0, // opencl_generic
|
||||
0, // opencl_global_device
|
||||
0, // opencl_global_host
|
||||
0, // cuda_device
|
||||
0, // cuda_constant
|
||||
0, // cuda_shared
|
||||
0, // sycl_global
|
||||
0, // sycl_global_device
|
||||
0, // sycl_global_host
|
||||
0, // sycl_local
|
||||
0, // sycl_private
|
||||
static_cast<unsigned>(AArch64AddrSpace::ptr32_sptr),
|
||||
static_cast<unsigned>(AArch64AddrSpace::ptr32_uptr),
|
||||
static_cast<unsigned>(AArch64AddrSpace::ptr64),
|
||||
0, // hlsl_groupshared
|
||||
0, // hlsl_constant
|
||||
0, // hlsl_private
|
||||
0, // hlsl_device
|
||||
0, // hlsl_input
|
||||
0, // hlsl_output
|
||||
0, // hlsl_push_constant
|
||||
// Wasm address space values for this target are dummy values,
|
||||
// as it is only enabled for Wasm targets.
|
||||
20, // wasm_funcref
|
||||
static constexpr LangASMap ARM64AddrSpaceMap = {
|
||||
{LangAS::ptr32_sptr, static_cast<unsigned>(AArch64AddrSpace::ptr32_sptr)},
|
||||
{LangAS::ptr32_uptr, static_cast<unsigned>(AArch64AddrSpace::ptr32_uptr)},
|
||||
{LangAS::ptr64, static_cast<unsigned>(AArch64AddrSpace::ptr64)},
|
||||
};
|
||||
|
||||
using AArch64FeatureSet = llvm::SmallDenseSet<StringRef, 32>;
|
||||
|
|
|
|||
|
|
@ -28,34 +28,34 @@ namespace targets {
|
|||
// getPointerWidthV().
|
||||
|
||||
const LangASMap AMDGPUTargetInfo::AMDGPUAddrSpaceMap = {
|
||||
llvm::AMDGPUAS::FLAT_ADDRESS, // Default
|
||||
llvm::AMDGPUAS::GLOBAL_ADDRESS, // opencl_global
|
||||
llvm::AMDGPUAS::LOCAL_ADDRESS, // opencl_local
|
||||
llvm::AMDGPUAS::CONSTANT_ADDRESS, // opencl_constant
|
||||
llvm::AMDGPUAS::PRIVATE_ADDRESS, // opencl_private
|
||||
llvm::AMDGPUAS::FLAT_ADDRESS, // opencl_generic
|
||||
llvm::AMDGPUAS::GLOBAL_ADDRESS, // opencl_global_device
|
||||
llvm::AMDGPUAS::GLOBAL_ADDRESS, // opencl_global_host
|
||||
llvm::AMDGPUAS::GLOBAL_ADDRESS, // cuda_device
|
||||
llvm::AMDGPUAS::CONSTANT_ADDRESS, // cuda_constant
|
||||
llvm::AMDGPUAS::LOCAL_ADDRESS, // cuda_shared
|
||||
llvm::AMDGPUAS::GLOBAL_ADDRESS, // sycl_global
|
||||
llvm::AMDGPUAS::GLOBAL_ADDRESS, // sycl_global_device
|
||||
llvm::AMDGPUAS::GLOBAL_ADDRESS, // sycl_global_host
|
||||
llvm::AMDGPUAS::LOCAL_ADDRESS, // sycl_local
|
||||
llvm::AMDGPUAS::PRIVATE_ADDRESS, // sycl_private
|
||||
llvm::AMDGPUAS::FLAT_ADDRESS, // ptr32_sptr
|
||||
llvm::AMDGPUAS::FLAT_ADDRESS, // ptr32_uptr
|
||||
llvm::AMDGPUAS::FLAT_ADDRESS, // ptr64
|
||||
llvm::AMDGPUAS::FLAT_ADDRESS, // hlsl_groupshared
|
||||
llvm::AMDGPUAS::CONSTANT_ADDRESS, // hlsl_constant
|
||||
{LangAS::Default, llvm::AMDGPUAS::FLAT_ADDRESS},
|
||||
{LangAS::opencl_global, llvm::AMDGPUAS::GLOBAL_ADDRESS},
|
||||
{LangAS::opencl_local, llvm::AMDGPUAS::LOCAL_ADDRESS},
|
||||
{LangAS::opencl_constant, llvm::AMDGPUAS::CONSTANT_ADDRESS},
|
||||
{LangAS::opencl_private, llvm::AMDGPUAS::PRIVATE_ADDRESS},
|
||||
{LangAS::opencl_generic, llvm::AMDGPUAS::FLAT_ADDRESS},
|
||||
{LangAS::opencl_global_device, llvm::AMDGPUAS::GLOBAL_ADDRESS},
|
||||
{LangAS::opencl_global_host, llvm::AMDGPUAS::GLOBAL_ADDRESS},
|
||||
{LangAS::cuda_device, llvm::AMDGPUAS::GLOBAL_ADDRESS},
|
||||
{LangAS::cuda_constant, llvm::AMDGPUAS::CONSTANT_ADDRESS},
|
||||
{LangAS::cuda_shared, llvm::AMDGPUAS::LOCAL_ADDRESS},
|
||||
{LangAS::sycl_global, llvm::AMDGPUAS::GLOBAL_ADDRESS},
|
||||
{LangAS::sycl_global_device, llvm::AMDGPUAS::GLOBAL_ADDRESS},
|
||||
{LangAS::sycl_global_host, llvm::AMDGPUAS::GLOBAL_ADDRESS},
|
||||
{LangAS::sycl_local, llvm::AMDGPUAS::LOCAL_ADDRESS},
|
||||
{LangAS::sycl_private, llvm::AMDGPUAS::PRIVATE_ADDRESS},
|
||||
{LangAS::ptr32_sptr, llvm::AMDGPUAS::FLAT_ADDRESS},
|
||||
{LangAS::ptr32_uptr, llvm::AMDGPUAS::FLAT_ADDRESS},
|
||||
{LangAS::ptr64, llvm::AMDGPUAS::FLAT_ADDRESS},
|
||||
{LangAS::hlsl_groupshared, llvm::AMDGPUAS::FLAT_ADDRESS},
|
||||
{LangAS::hlsl_constant, llvm::AMDGPUAS::CONSTANT_ADDRESS},
|
||||
// FIXME(pr/122103): hlsl_private -> PRIVATE is wrong, but at least this
|
||||
// will break loudly.
|
||||
llvm::AMDGPUAS::PRIVATE_ADDRESS, // hlsl_private
|
||||
llvm::AMDGPUAS::GLOBAL_ADDRESS, // hlsl_device
|
||||
llvm::AMDGPUAS::PRIVATE_ADDRESS, // hlsl_input
|
||||
llvm::AMDGPUAS::PRIVATE_ADDRESS, // hlsl_output
|
||||
llvm::AMDGPUAS::GLOBAL_ADDRESS, // hlsl_push_constant
|
||||
{LangAS::hlsl_private, llvm::AMDGPUAS::PRIVATE_ADDRESS},
|
||||
{LangAS::hlsl_device, llvm::AMDGPUAS::GLOBAL_ADDRESS},
|
||||
{LangAS::hlsl_input, llvm::AMDGPUAS::PRIVATE_ADDRESS},
|
||||
{LangAS::hlsl_output, llvm::AMDGPUAS::PRIVATE_ADDRESS},
|
||||
{LangAS::hlsl_push_constant, llvm::AMDGPUAS::GLOBAL_ADDRESS},
|
||||
};
|
||||
|
||||
} // namespace targets
|
||||
|
|
|
|||
|
|
@ -20,37 +20,11 @@
|
|||
namespace clang {
|
||||
namespace targets {
|
||||
|
||||
static const unsigned DirectXAddrSpaceMap[] = {
|
||||
0, // Default
|
||||
1, // opencl_global
|
||||
3, // opencl_local
|
||||
2, // opencl_constant
|
||||
0, // opencl_private
|
||||
4, // opencl_generic
|
||||
5, // opencl_global_device
|
||||
6, // opencl_global_host
|
||||
0, // cuda_device
|
||||
0, // cuda_constant
|
||||
0, // cuda_shared
|
||||
// SYCL address space values for this map are dummy
|
||||
0, // sycl_global
|
||||
0, // sycl_global_device
|
||||
0, // sycl_global_host
|
||||
0, // sycl_local
|
||||
0, // sycl_private
|
||||
0, // ptr32_sptr
|
||||
0, // ptr32_uptr
|
||||
0, // ptr64
|
||||
3, // hlsl_groupshared
|
||||
2, // hlsl_constant
|
||||
0, // hlsl_private
|
||||
0, // hlsl_device
|
||||
0, // hlsl_input
|
||||
0, // hlsl_output
|
||||
0, // hlsl_push_constant
|
||||
// Wasm address space values for this target are dummy values,
|
||||
// as it is only enabled for Wasm targets.
|
||||
20, // wasm_funcref
|
||||
static constexpr LangASMap DirectXAddrSpaceMap = {
|
||||
{LangAS::opencl_global, 1}, {LangAS::opencl_local, 3},
|
||||
{LangAS::opencl_constant, 2}, {LangAS::opencl_generic, 4},
|
||||
{LangAS::opencl_global_device, 5}, {LangAS::opencl_global_host, 6},
|
||||
{LangAS::hlsl_groupshared, 3}, {LangAS::hlsl_constant, 2},
|
||||
};
|
||||
|
||||
class LLVM_LIBRARY_VISIBILITY DirectXTargetInfo : public TargetInfo {
|
||||
|
|
|
|||
|
|
@ -24,37 +24,21 @@
|
|||
namespace clang {
|
||||
namespace targets {
|
||||
|
||||
static const unsigned NVPTXAddrSpaceMap[] = {
|
||||
0, // Default
|
||||
1, // opencl_global
|
||||
3, // opencl_local
|
||||
4, // opencl_constant
|
||||
0, // opencl_private
|
||||
static constexpr LangASMap NVPTXAddrSpaceMap = {
|
||||
{LangAS::opencl_global, 1},
|
||||
{LangAS::opencl_local, 3},
|
||||
{LangAS::opencl_constant, 4},
|
||||
// FIXME: generic has to be added to the target
|
||||
0, // opencl_generic
|
||||
1, // opencl_global_device
|
||||
1, // opencl_global_host
|
||||
1, // cuda_device
|
||||
4, // cuda_constant
|
||||
3, // cuda_shared
|
||||
1, // sycl_global
|
||||
1, // sycl_global_device
|
||||
1, // sycl_global_host
|
||||
3, // sycl_local
|
||||
0, // sycl_private
|
||||
0, // ptr32_sptr
|
||||
0, // ptr32_uptr
|
||||
0, // ptr64
|
||||
0, // hlsl_groupshared
|
||||
0, // hlsl_constant
|
||||
0, // hlsl_private
|
||||
0, // hlsl_device
|
||||
0, // hlsl_input
|
||||
0, // hlsl_output
|
||||
0, // hlsl_push_constant
|
||||
// Wasm address space values for this target are dummy values,
|
||||
// as it is only enabled for Wasm targets.
|
||||
20, // wasm_funcref
|
||||
{LangAS::opencl_generic, 0},
|
||||
{LangAS::opencl_global_device, 1},
|
||||
{LangAS::opencl_global_host, 1},
|
||||
{LangAS::cuda_device, 1},
|
||||
{LangAS::cuda_constant, 4},
|
||||
{LangAS::cuda_shared, 3},
|
||||
{LangAS::sycl_global, 1},
|
||||
{LangAS::sycl_global_device, 1},
|
||||
{LangAS::sycl_global_host, 1},
|
||||
{LangAS::sycl_local, 3},
|
||||
};
|
||||
|
||||
/// The DWARF address class. Taken from
|
||||
|
|
|
|||
|
|
@ -28,75 +28,43 @@ namespace clang {
|
|||
namespace targets {
|
||||
|
||||
// Used by both the SPIR and SPIR-V targets.
|
||||
static const unsigned SPIRDefIsPrivMap[] = {
|
||||
0, // Default
|
||||
1, // opencl_global
|
||||
3, // opencl_local
|
||||
2, // opencl_constant
|
||||
0, // opencl_private
|
||||
4, // opencl_generic
|
||||
5, // opencl_global_device
|
||||
6, // opencl_global_host
|
||||
0, // cuda_device
|
||||
0, // cuda_constant
|
||||
0, // cuda_shared
|
||||
// SYCL address space values for this map are dummy
|
||||
0, // sycl_global
|
||||
0, // sycl_global_device
|
||||
0, // sycl_global_host
|
||||
0, // sycl_local
|
||||
0, // sycl_private
|
||||
0, // ptr32_sptr
|
||||
0, // ptr32_uptr
|
||||
0, // ptr64
|
||||
3, // hlsl_groupshared
|
||||
12, // hlsl_constant
|
||||
10, // hlsl_private
|
||||
11, // hlsl_device
|
||||
7, // hlsl_input
|
||||
8, // hlsl_output
|
||||
13, // hlsl_push_constant
|
||||
// Wasm address space values for this target are dummy values,
|
||||
// as it is only enabled for Wasm targets.
|
||||
20, // wasm_funcref
|
||||
static constexpr LangASMap SPIRDefIsPrivMap = {
|
||||
{LangAS::opencl_global, 1}, {LangAS::opencl_local, 3},
|
||||
{LangAS::opencl_constant, 2}, {LangAS::opencl_generic, 4},
|
||||
{LangAS::opencl_global_device, 5}, {LangAS::opencl_global_host, 6},
|
||||
{LangAS::hlsl_groupshared, 3}, {LangAS::hlsl_constant, 12},
|
||||
{LangAS::hlsl_private, 10}, {LangAS::hlsl_device, 11},
|
||||
{LangAS::hlsl_input, 7}, {LangAS::hlsl_output, 8},
|
||||
{LangAS::hlsl_push_constant, 13},
|
||||
};
|
||||
|
||||
// Used by both the SPIR and SPIR-V targets.
|
||||
static const unsigned SPIRDefIsGenMap[] = {
|
||||
4, // Default
|
||||
1, // opencl_global
|
||||
3, // opencl_local
|
||||
2, // opencl_constant
|
||||
0, // opencl_private
|
||||
4, // opencl_generic
|
||||
5, // opencl_global_device
|
||||
6, // opencl_global_host
|
||||
static constexpr LangASMap SPIRDefIsGenMap = {
|
||||
{LangAS::Default, 4},
|
||||
{LangAS::opencl_global, 1},
|
||||
{LangAS::opencl_local, 3},
|
||||
{LangAS::opencl_constant, 2},
|
||||
{LangAS::opencl_generic, 4},
|
||||
{LangAS::opencl_global_device, 5},
|
||||
{LangAS::opencl_global_host, 6},
|
||||
// cuda_* address space mapping is intended for HIPSPV (HIP to SPIR-V
|
||||
// translation). This mapping is enabled when the language mode is HIP.
|
||||
1, // cuda_device
|
||||
{LangAS::cuda_device, 1},
|
||||
// cuda_constant pointer can be casted to default/"flat" pointer, but in
|
||||
// SPIR-V casts between constant and generic pointers are not allowed. For
|
||||
// this reason cuda_constant is mapped to SPIR-V CrossWorkgroup.
|
||||
1, // cuda_constant
|
||||
3, // cuda_shared
|
||||
1, // sycl_global
|
||||
5, // sycl_global_device
|
||||
6, // sycl_global_host
|
||||
3, // sycl_local
|
||||
0, // sycl_private
|
||||
0, // ptr32_sptr
|
||||
0, // ptr32_uptr
|
||||
0, // ptr64
|
||||
3, // hlsl_groupshared
|
||||
0, // hlsl_constant
|
||||
10, // hlsl_private
|
||||
11, // hlsl_device
|
||||
7, // hlsl_input
|
||||
8, // hlsl_output
|
||||
13, // hlsl_push_constant
|
||||
// Wasm address space values for this target are dummy values,
|
||||
// as it is only enabled for Wasm targets.
|
||||
20, // wasm_funcref
|
||||
{LangAS::cuda_constant, 1},
|
||||
{LangAS::cuda_shared, 3},
|
||||
{LangAS::sycl_global, 1},
|
||||
{LangAS::sycl_global_device, 5},
|
||||
{LangAS::sycl_global_host, 6},
|
||||
{LangAS::sycl_local, 3},
|
||||
{LangAS::hlsl_groupshared, 3},
|
||||
{LangAS::hlsl_private, 10},
|
||||
{LangAS::hlsl_device, 11},
|
||||
{LangAS::hlsl_input, 7},
|
||||
{LangAS::hlsl_output, 8},
|
||||
{LangAS::hlsl_push_constant, 13},
|
||||
};
|
||||
|
||||
// Base class for SPIR and SPIR-V target info.
|
||||
|
|
|
|||
|
|
@ -21,34 +21,8 @@
|
|||
namespace clang {
|
||||
namespace targets {
|
||||
|
||||
static const unsigned ZOSAddressMap[] = {
|
||||
0, // Default
|
||||
0, // opencl_global
|
||||
0, // opencl_local
|
||||
0, // opencl_constant
|
||||
0, // opencl_private
|
||||
0, // opencl_generic
|
||||
0, // opencl_global_device
|
||||
0, // opencl_global_host
|
||||
0, // cuda_device
|
||||
0, // cuda_constant
|
||||
0, // cuda_shared
|
||||
0, // sycl_global
|
||||
0, // sycl_global_device
|
||||
0, // sycl_global_host
|
||||
0, // sycl_local
|
||||
0, // sycl_private
|
||||
0, // ptr32_sptr
|
||||
1, // ptr32_uptr
|
||||
0, // ptr64
|
||||
0, // hlsl_groupshared
|
||||
0, // hlsl_constant
|
||||
0, // hlsl_private
|
||||
0, // hlsl_device
|
||||
0, // hlsl_input
|
||||
0, // hlsl_output
|
||||
0, // hlsl_push_constant
|
||||
0 // wasm_funcref
|
||||
static constexpr LangASMap ZOSAddressMap = {
|
||||
{LangAS::ptr32_uptr, 1},
|
||||
};
|
||||
|
||||
class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
|
||||
|
|
|
|||
|
|
@ -29,37 +29,14 @@ namespace targets {
|
|||
// target processor and program binary. TCE co-design environment is
|
||||
// publicly available in http://tce.cs.tut.fi
|
||||
|
||||
static const unsigned TCEOpenCLAddrSpaceMap[] = {
|
||||
0, // Default
|
||||
1, // opencl_global
|
||||
3, // opencl_local
|
||||
2, // opencl_constant
|
||||
0, // opencl_private
|
||||
1, // opencl_global_device
|
||||
1, // opencl_global_host
|
||||
static constexpr LangASMap TCEOpenCLAddrSpaceMap = {
|
||||
{LangAS::opencl_global, 1},
|
||||
{LangAS::opencl_local, 3},
|
||||
{LangAS::opencl_constant, 2},
|
||||
// FIXME: generic has to be added to the target
|
||||
0, // opencl_generic
|
||||
0, // cuda_device
|
||||
0, // cuda_constant
|
||||
0, // cuda_shared
|
||||
0, // sycl_global
|
||||
0, // sycl_global_device
|
||||
0, // sycl_global_host
|
||||
0, // sycl_local
|
||||
0, // sycl_private
|
||||
0, // ptr32_sptr
|
||||
0, // ptr32_uptr
|
||||
0, // ptr64
|
||||
0, // hlsl_groupshared
|
||||
0, // hlsl_constant
|
||||
0, // hlsl_private
|
||||
0, // hlsl_device
|
||||
0, // hlsl_input
|
||||
0, // hlsl_output
|
||||
0, // hlsl_push_constant
|
||||
// Wasm address space values for this target are dummy values,
|
||||
// as it is only enabled for Wasm targets.
|
||||
20, // wasm_funcref
|
||||
{LangAS::opencl_generic, 0},
|
||||
{LangAS::opencl_global_device, 1},
|
||||
{LangAS::opencl_global_host, 1},
|
||||
};
|
||||
|
||||
class LLVM_LIBRARY_VISIBILITY TCETargetInfo : public TargetInfo {
|
||||
|
|
|
|||
|
|
@ -21,34 +21,8 @@
|
|||
namespace clang {
|
||||
namespace targets {
|
||||
|
||||
static const unsigned WebAssemblyAddrSpaceMap[] = {
|
||||
0, // Default
|
||||
0, // opencl_global
|
||||
0, // opencl_local
|
||||
0, // opencl_constant
|
||||
0, // opencl_private
|
||||
0, // opencl_generic
|
||||
0, // opencl_global_device
|
||||
0, // opencl_global_host
|
||||
0, // cuda_device
|
||||
0, // cuda_constant
|
||||
0, // cuda_shared
|
||||
0, // sycl_global
|
||||
0, // sycl_global_device
|
||||
0, // sycl_global_host
|
||||
0, // sycl_local
|
||||
0, // sycl_private
|
||||
0, // ptr32_sptr
|
||||
0, // ptr32_uptr
|
||||
0, // ptr64
|
||||
0, // hlsl_groupshared
|
||||
0, // hlsl_constant
|
||||
0, // hlsl_private
|
||||
0, // hlsl_device
|
||||
0, // hlsl_input
|
||||
0, // hlsl_output
|
||||
0, // hlsl_push_constant
|
||||
20, // wasm_funcref
|
||||
static constexpr LangASMap WebAssemblyAddrSpaceMap = {
|
||||
{LangAS::wasm_funcref, 20},
|
||||
};
|
||||
|
||||
class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo {
|
||||
|
|
|
|||
|
|
@ -25,36 +25,10 @@
|
|||
namespace clang {
|
||||
namespace targets {
|
||||
|
||||
static const unsigned X86AddrSpaceMap[] = {
|
||||
0, // Default
|
||||
0, // opencl_global
|
||||
0, // opencl_local
|
||||
0, // opencl_constant
|
||||
0, // opencl_private
|
||||
0, // opencl_generic
|
||||
0, // opencl_global_device
|
||||
0, // opencl_global_host
|
||||
0, // cuda_device
|
||||
0, // cuda_constant
|
||||
0, // cuda_shared
|
||||
0, // sycl_global
|
||||
0, // sycl_global_device
|
||||
0, // sycl_global_host
|
||||
0, // sycl_local
|
||||
0, // sycl_private
|
||||
270, // ptr32_sptr
|
||||
271, // ptr32_uptr
|
||||
272, // ptr64
|
||||
0, // hlsl_groupshared
|
||||
0, // hlsl_constant
|
||||
0, // hlsl_private
|
||||
0, // hlsl_device
|
||||
0, // hlsl_input
|
||||
0, // hlsl_output
|
||||
0, // hlsl_push_constant
|
||||
// Wasm address space values for this target are dummy values,
|
||||
// as it is only enabled for Wasm targets.
|
||||
20, // wasm_funcref
|
||||
static constexpr LangASMap X86AddrSpaceMap = {
|
||||
{LangAS::ptr32_sptr, 270},
|
||||
{LangAS::ptr32_uptr, 271},
|
||||
{LangAS::ptr64, 272},
|
||||
};
|
||||
|
||||
// X86 target abstract base class; x86-32 and x86-64 are very close, so
|
||||
|
|
|
|||
|
|
@ -15,54 +15,15 @@
|
|||
#include <cstring>
|
||||
using namespace clang;
|
||||
|
||||
static constexpr const char *TypeTraitNames[] = {
|
||||
#define TYPE_TRAIT_1(Spelling, Name, Key) #Name,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
#define TYPE_TRAIT_2(Spelling, Name, Key) #Name,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
#define TYPE_TRAIT_N(Spelling, Name, Key) #Name,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
};
|
||||
|
||||
static constexpr const char *TypeTraitSpellings[] = {
|
||||
#define TYPE_TRAIT_1(Spelling, Name, Key) #Spelling,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
#define TYPE_TRAIT_2(Spelling, Name, Key) #Spelling,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
#define TYPE_TRAIT_N(Spelling, Name, Key) #Spelling,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
};
|
||||
|
||||
static constexpr const char *ArrayTypeTraitNames[] = {
|
||||
#define ARRAY_TYPE_TRAIT(Spelling, Name, Key) #Name,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
};
|
||||
|
||||
static constexpr const char *ArrayTypeTraitSpellings[] = {
|
||||
#define ARRAY_TYPE_TRAIT(Spelling, Name, Key) #Spelling,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
};
|
||||
|
||||
static constexpr const char *UnaryExprOrTypeTraitNames[] = {
|
||||
#define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) #Name,
|
||||
#define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) #Name,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
};
|
||||
|
||||
static constexpr const char *UnaryExprOrTypeTraitSpellings[] = {
|
||||
#define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) #Spelling,
|
||||
#define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) #Spelling,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
};
|
||||
|
||||
static constexpr const unsigned TypeTraitArities[] = {
|
||||
#define TYPE_TRAIT_1(Spelling, Name, Key) 1,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
#define TYPE_TRAIT_2(Spelling, Name, Key) 2,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
#define TYPE_TRAIT_N(Spelling, Name, Key) 0,
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
};
|
||||
// static constexpr const char *TypeTraitNames[] = {...};
|
||||
// static constexpr const char *TypeTraitSpellings[] = {...};
|
||||
// static constexpr const char *ArrayTypeTraitNames[] = {...};
|
||||
// static constexpr const char *ArrayTypeTraitSpellings[] = {...};
|
||||
// static constexpr const char *UnaryExprOrTypeTraitNames[] = {...};
|
||||
// static constexpr const char *UnaryExprOrTypeTraitSpellings[] = {...};
|
||||
// static constexpr const unsigned TypeTraitArities[] = {...};
|
||||
#define EMIT_ARRAYS
|
||||
#include "clang/Basic/Traits.inc"
|
||||
|
||||
const char *clang::getTraitName(TypeTrait T) {
|
||||
assert(T <= TT_Last && "invalid enum value!");
|
||||
|
|
|
|||
|
|
@ -163,11 +163,12 @@ static Address checkAtomicAlignment(CIRGenFunction &cgf, const CallExpr *e) {
|
|||
|
||||
/// Utility to insert an atomic instruction based on Intrinsic::ID
|
||||
/// and the expression node.
|
||||
static mlir::Value makeBinaryAtomicValue(
|
||||
CIRGenFunction &cgf, cir::AtomicFetchKind kind, const CallExpr *expr,
|
||||
mlir::Type *originalArgType = nullptr,
|
||||
mlir::Value *emittedArgValue = nullptr,
|
||||
cir::MemOrder ordering = cir::MemOrder::SequentiallyConsistent) {
|
||||
mlir::Value CIRGenFunction::makeBinaryAtomicValue(cir::AtomicFetchKind kind,
|
||||
const CallExpr *expr,
|
||||
mlir::Type *originalArgType,
|
||||
mlir::Value *emittedArgValue,
|
||||
cir::MemOrder ordering) {
|
||||
CIRGenFunction &cgf = *this;
|
||||
|
||||
QualType type = expr->getType();
|
||||
QualType ptrType = expr->getArg(0)->getType();
|
||||
|
|
@ -224,7 +225,7 @@ static mlir::Value makeBinaryAtomicValue(
|
|||
static RValue emitBinaryAtomic(CIRGenFunction &cgf,
|
||||
cir::AtomicFetchKind atomicOpkind,
|
||||
const CallExpr *e) {
|
||||
return RValue::get(makeBinaryAtomicValue(cgf, atomicOpkind, e));
|
||||
return RValue::get(cgf.makeBinaryAtomicValue(atomicOpkind, e));
|
||||
}
|
||||
|
||||
template <typename BinOp>
|
||||
|
|
@ -234,8 +235,8 @@ static RValue emitBinaryAtomicPost(CIRGenFunction &cgf,
|
|||
mlir::Value emittedArgValue;
|
||||
mlir::Type originalArgType;
|
||||
clang::QualType typ = e->getType();
|
||||
mlir::Value result = makeBinaryAtomicValue(
|
||||
cgf, atomicOpkind, e, &originalArgType, &emittedArgValue);
|
||||
mlir::Value result = cgf.makeBinaryAtomicValue(
|
||||
atomicOpkind, e, &originalArgType, &emittedArgValue);
|
||||
clang::CIRGen::CIRGenBuilderTy &builder = cgf.getBuilder();
|
||||
result = BinOp::create(builder, result.getLoc(), result, emittedArgValue);
|
||||
|
||||
|
|
|
|||
|
|
@ -1074,12 +1074,26 @@ static mlir::Value emitCommonNeonBuiltinExpr(
|
|||
case NEON::BI__builtin_neon_vsm3tt1bq_u32:
|
||||
case NEON::BI__builtin_neon_vsm3tt2aq_u32:
|
||||
case NEON::BI__builtin_neon_vsm3tt2bq_u32:
|
||||
cgf.cgm.errorNYI(expr->getSourceRange(),
|
||||
std::string("unimplemented AArch64 builtin call: ") +
|
||||
ctx.BuiltinInfo.getName(builtinID));
|
||||
return mlir::Value{};
|
||||
case NEON::BI__builtin_neon_vst1_x2_v:
|
||||
case NEON::BI__builtin_neon_vst1q_x2_v:
|
||||
case NEON::BI__builtin_neon_vst1_x3_v:
|
||||
case NEON::BI__builtin_neon_vst1q_x3_v:
|
||||
case NEON::BI__builtin_neon_vst1_x4_v:
|
||||
case NEON::BI__builtin_neon_vst1q_x4_v:
|
||||
case NEON::BI__builtin_neon_vst1q_x4_v: {
|
||||
// The builtin call has the pointer first, but the AArch64 st1x2/3/4
|
||||
// intrinsics take the vector operands first and the pointer last.
|
||||
std::rotate(ops.begin(), ops.begin() + 1, ops.end());
|
||||
llvm::SmallVector<mlir::Type> argTypes(ops.size() - 1, ty);
|
||||
argTypes.push_back(cgf.getBuilder().getVoidPtrTy());
|
||||
llvm::StringRef llvmIntrName = getLLVMIntrNameNoPrefix(
|
||||
static_cast<llvm::Intrinsic::ID>(llvmIntrinsic));
|
||||
return emitNeonCall(cgf.getCIRGenModule(), cgf.getBuilder(), argTypes, ops,
|
||||
llvmIntrName, cgf.cgm.voidTy, loc);
|
||||
}
|
||||
case NEON::BI__builtin_neon_vtrn_v:
|
||||
case NEON::BI__builtin_neon_vtrnq_v:
|
||||
case NEON::BI__builtin_neon_vtst_v:
|
||||
|
|
@ -2359,6 +2373,12 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr,
|
|||
assert(error == ASTContext::GE_None && "Should not codegen an error");
|
||||
llvm::SmallVector<mlir::Value> ops;
|
||||
|
||||
// Captures the pointer and its alignment for builtins that store/load
|
||||
// directly through the first argument, i.e. operand 0 (set in the
|
||||
// arg-gathering loop below, used later when lowering the store/load
|
||||
// itself).
|
||||
Address ptrOp0 = Address::invalid();
|
||||
|
||||
// Skip extra arguments used to discriminate vector types and that are
|
||||
// intended for Sema checking.
|
||||
bool hasExtraArg = hasExtraNeonArgument(builtinID);
|
||||
|
|
@ -2372,20 +2392,29 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr,
|
|||
case NEON::BI__builtin_neon_vld1q_dup_v:
|
||||
case NEON::BI__builtin_neon_vld1_lane_v:
|
||||
case NEON::BI__builtin_neon_vld1q_lane_v:
|
||||
case NEON::BI__builtin_neon_vst1_v:
|
||||
case NEON::BI__builtin_neon_vst1q_v:
|
||||
case NEON::BI__builtin_neon_vst1_lane_v:
|
||||
case NEON::BI__builtin_neon_vst1q_lane_v:
|
||||
case NEON::BI__builtin_neon_vldap1_lane_s64:
|
||||
case NEON::BI__builtin_neon_vldap1q_lane_s64:
|
||||
case NEON::BI__builtin_neon_vstl1_lane_s64:
|
||||
case NEON::BI__builtin_neon_vstl1q_lane_s64:
|
||||
// Get the alignment for the argument in addition to the value;
|
||||
// we'll use it later.
|
||||
cgm.errorNYI(
|
||||
expr->getSourceRange(),
|
||||
std::string("unimplemented AArch64 builtin argument handling ") +
|
||||
getContext().BuiltinInfo.getName(builtinID));
|
||||
break;
|
||||
case NEON::BI__builtin_neon_vst1_v:
|
||||
case NEON::BI__builtin_neon_vst1q_v:
|
||||
case NEON::BI__builtin_neon_vst1_lane_v:
|
||||
case NEON::BI__builtin_neon_vst1q_lane_v:
|
||||
// Get the alignment for the argument in addition to the value;
|
||||
// we'll use it later.
|
||||
ptrOp0 = emitPointerWithAlignment(expr->getArg(0));
|
||||
ops.push_back(ptrOp0.getPointer());
|
||||
continue;
|
||||
case NEON::BI__builtin_neon_vldap1_lane_s64:
|
||||
case NEON::BI__builtin_neon_vldap1q_lane_s64:
|
||||
case NEON::BI__builtin_neon_vstl1_lane_s64:
|
||||
case NEON::BI__builtin_neon_vstl1q_lane_s64:
|
||||
cgm.errorNYI(
|
||||
expr->getSourceRange(),
|
||||
std::string("unimplemented AArch64 builtin argument handling ") +
|
||||
getContext().BuiltinInfo.getName(builtinID));
|
||||
break;
|
||||
}
|
||||
}
|
||||
ops.push_back(
|
||||
|
|
@ -3211,16 +3240,35 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr,
|
|||
}
|
||||
case NEON::BI__builtin_neon_vld1_v:
|
||||
case NEON::BI__builtin_neon_vld1q_v:
|
||||
cgm.errorNYI(expr->getSourceRange(),
|
||||
std::string("unimplemented AArch64 builtin call: ") +
|
||||
getContext().BuiltinInfo.getName(builtinID));
|
||||
return mlir::Value{};
|
||||
case NEON::BI__builtin_neon_vst1_v:
|
||||
case NEON::BI__builtin_neon_vst1q_v:
|
||||
case NEON::BI__builtin_neon_vst1q_v: {
|
||||
ops[1] = builder.createBitcast(ops[1], ty);
|
||||
builder.createStore(loc, ops[1], ptrOp0.withElementType(builder, ty));
|
||||
return nullptr;
|
||||
}
|
||||
case NEON::BI__builtin_neon_vld1_lane_v:
|
||||
case NEON::BI__builtin_neon_vld1q_lane_v:
|
||||
case NEON::BI__builtin_neon_vldap1_lane_s64:
|
||||
case NEON::BI__builtin_neon_vldap1q_lane_s64:
|
||||
case NEON::BI__builtin_neon_vld1_dup_v:
|
||||
case NEON::BI__builtin_neon_vld1q_dup_v:
|
||||
cgm.errorNYI(expr->getSourceRange(),
|
||||
std::string("unimplemented AArch64 builtin call: ") +
|
||||
getContext().BuiltinInfo.getName(builtinID));
|
||||
return mlir::Value{};
|
||||
case NEON::BI__builtin_neon_vst1_lane_v:
|
||||
case NEON::BI__builtin_neon_vst1q_lane_v:
|
||||
case NEON::BI__builtin_neon_vst1q_lane_v: {
|
||||
ops[1] = builder.createBitcast(ops[1], ty);
|
||||
mlir::Value scalar = builder.createExtractElement(
|
||||
loc, ops[1], static_cast<uint64_t>(getIntValueFromConstOp(ops[2])));
|
||||
builder.createStore(loc, scalar,
|
||||
ptrOp0.withElementType(builder, scalar.getType()));
|
||||
return nullptr;
|
||||
}
|
||||
case NEON::BI__builtin_neon_vstl1_lane_s64:
|
||||
case NEON::BI__builtin_neon_vstl1q_lane_s64:
|
||||
case NEON::BI__builtin_neon_vld2_v:
|
||||
|
|
|
|||
|
|
@ -39,38 +39,38 @@ CIRGenFunction::emitNVPTXBuiltinExpr(unsigned builtinId, const CallExpr *expr) {
|
|||
case NVPTX::BI__nvvm_atom_add_gen_i:
|
||||
case NVPTX::BI__nvvm_atom_add_gen_l:
|
||||
case NVPTX::BI__nvvm_atom_add_gen_ll:
|
||||
cgm.errorNYI(expr->getSourceRange(),
|
||||
std::string("unimplemented NVPTX builtin call: ") +
|
||||
getContext().BuiltinInfo.getName(builtinId));
|
||||
return mlir::Value{};
|
||||
return makeBinaryAtomicValue(cir::AtomicFetchKind::Add, expr,
|
||||
/*originalArgType=*/nullptr,
|
||||
/*emittedArgValue=*/nullptr,
|
||||
cir::MemOrder::Relaxed);
|
||||
case NVPTX::BI__nvvm_atom_sub_gen_i:
|
||||
case NVPTX::BI__nvvm_atom_sub_gen_l:
|
||||
case NVPTX::BI__nvvm_atom_sub_gen_ll:
|
||||
cgm.errorNYI(expr->getSourceRange(),
|
||||
std::string("unimplemented NVPTX builtin call: ") +
|
||||
getContext().BuiltinInfo.getName(builtinId));
|
||||
return mlir::Value{};
|
||||
return makeBinaryAtomicValue(cir::AtomicFetchKind::Sub, expr,
|
||||
/*originalArgType=*/nullptr,
|
||||
/*emittedArgValue=*/nullptr,
|
||||
cir::MemOrder::Relaxed);
|
||||
case NVPTX::BI__nvvm_atom_and_gen_i:
|
||||
case NVPTX::BI__nvvm_atom_and_gen_l:
|
||||
case NVPTX::BI__nvvm_atom_and_gen_ll:
|
||||
cgm.errorNYI(expr->getSourceRange(),
|
||||
std::string("unimplemented NVPTX builtin call: ") +
|
||||
getContext().BuiltinInfo.getName(builtinId));
|
||||
return mlir::Value{};
|
||||
return makeBinaryAtomicValue(cir::AtomicFetchKind::And, expr,
|
||||
/*originalArgType=*/nullptr,
|
||||
/*emittedArgValue=*/nullptr,
|
||||
cir::MemOrder::Relaxed);
|
||||
case NVPTX::BI__nvvm_atom_or_gen_i:
|
||||
case NVPTX::BI__nvvm_atom_or_gen_l:
|
||||
case NVPTX::BI__nvvm_atom_or_gen_ll:
|
||||
cgm.errorNYI(expr->getSourceRange(),
|
||||
std::string("unimplemented NVPTX builtin call: ") +
|
||||
getContext().BuiltinInfo.getName(builtinId));
|
||||
return mlir::Value{};
|
||||
return makeBinaryAtomicValue(cir::AtomicFetchKind::Or, expr,
|
||||
/*originalArgType=*/nullptr,
|
||||
/*emittedArgValue=*/nullptr,
|
||||
cir::MemOrder::Relaxed);
|
||||
case NVPTX::BI__nvvm_atom_xor_gen_i:
|
||||
case NVPTX::BI__nvvm_atom_xor_gen_l:
|
||||
case NVPTX::BI__nvvm_atom_xor_gen_ll:
|
||||
cgm.errorNYI(expr->getSourceRange(),
|
||||
std::string("unimplemented NVPTX builtin call: ") +
|
||||
getContext().BuiltinInfo.getName(builtinId));
|
||||
return mlir::Value{};
|
||||
return makeBinaryAtomicValue(cir::AtomicFetchKind::Xor, expr,
|
||||
/*originalArgType=*/nullptr,
|
||||
/*emittedArgValue=*/nullptr,
|
||||
cir::MemOrder::Relaxed);
|
||||
case NVPTX::BI__nvvm_atom_xchg_gen_i:
|
||||
case NVPTX::BI__nvvm_atom_xchg_gen_l:
|
||||
case NVPTX::BI__nvvm_atom_xchg_gen_ll:
|
||||
|
|
@ -81,31 +81,31 @@ CIRGenFunction::emitNVPTXBuiltinExpr(unsigned builtinId, const CallExpr *expr) {
|
|||
case NVPTX::BI__nvvm_atom_max_gen_i:
|
||||
case NVPTX::BI__nvvm_atom_max_gen_l:
|
||||
case NVPTX::BI__nvvm_atom_max_gen_ll:
|
||||
cgm.errorNYI(expr->getSourceRange(),
|
||||
std::string("unimplemented NVPTX builtin call: ") +
|
||||
getContext().BuiltinInfo.getName(builtinId));
|
||||
return mlir::Value{};
|
||||
return makeBinaryAtomicValue(cir::AtomicFetchKind::Max, expr,
|
||||
/*originalArgType=*/nullptr,
|
||||
/*emittedArgValue=*/nullptr,
|
||||
cir::MemOrder::Relaxed);
|
||||
case NVPTX::BI__nvvm_atom_max_gen_ui:
|
||||
case NVPTX::BI__nvvm_atom_max_gen_ul:
|
||||
case NVPTX::BI__nvvm_atom_max_gen_ull:
|
||||
cgm.errorNYI(expr->getSourceRange(),
|
||||
std::string("unimplemented NVPTX builtin call: ") +
|
||||
getContext().BuiltinInfo.getName(builtinId));
|
||||
return mlir::Value{};
|
||||
return makeBinaryAtomicValue(cir::AtomicFetchKind::Max, expr,
|
||||
/*originalArgType=*/nullptr,
|
||||
/*emittedArgValue=*/nullptr,
|
||||
cir::MemOrder::Relaxed);
|
||||
case NVPTX::BI__nvvm_atom_min_gen_i:
|
||||
case NVPTX::BI__nvvm_atom_min_gen_l:
|
||||
case NVPTX::BI__nvvm_atom_min_gen_ll:
|
||||
cgm.errorNYI(expr->getSourceRange(),
|
||||
std::string("unimplemented NVPTX builtin call: ") +
|
||||
getContext().BuiltinInfo.getName(builtinId));
|
||||
return mlir::Value{};
|
||||
return makeBinaryAtomicValue(cir::AtomicFetchKind::Min, expr,
|
||||
/*originalArgType=*/nullptr,
|
||||
/*emittedArgValue=*/nullptr,
|
||||
cir::MemOrder::Relaxed);
|
||||
case NVPTX::BI__nvvm_atom_min_gen_ui:
|
||||
case NVPTX::BI__nvvm_atom_min_gen_ul:
|
||||
case NVPTX::BI__nvvm_atom_min_gen_ull:
|
||||
cgm.errorNYI(expr->getSourceRange(),
|
||||
std::string("unimplemented NVPTX builtin call: ") +
|
||||
getContext().BuiltinInfo.getName(builtinId));
|
||||
return mlir::Value{};
|
||||
return makeBinaryAtomicValue(cir::AtomicFetchKind::Min, expr,
|
||||
/*originalArgType=*/nullptr,
|
||||
/*emittedArgValue=*/nullptr,
|
||||
cir::MemOrder::Relaxed);
|
||||
case NVPTX::BI__nvvm_atom_cas_gen_us:
|
||||
case NVPTX::BI__nvvm_atom_cas_gen_i:
|
||||
case NVPTX::BI__nvvm_atom_cas_gen_l:
|
||||
|
|
@ -122,15 +122,15 @@ CIRGenFunction::emitNVPTXBuiltinExpr(unsigned builtinId, const CallExpr *expr) {
|
|||
getContext().BuiltinInfo.getName(builtinId));
|
||||
return mlir::Value{};
|
||||
case NVPTX::BI__nvvm_atom_inc_gen_ui:
|
||||
cgm.errorNYI(expr->getSourceRange(),
|
||||
std::string("unimplemented NVPTX builtin call: ") +
|
||||
getContext().BuiltinInfo.getName(builtinId));
|
||||
return mlir::Value{};
|
||||
return makeBinaryAtomicValue(cir::AtomicFetchKind::UIncWrap, expr,
|
||||
/*originalArgType=*/nullptr,
|
||||
/*emittedArgValue=*/nullptr,
|
||||
cir::MemOrder::Relaxed);
|
||||
case NVPTX::BI__nvvm_atom_dec_gen_ui:
|
||||
cgm.errorNYI(expr->getSourceRange(),
|
||||
std::string("unimplemented NVPTX builtin call: ") +
|
||||
getContext().BuiltinInfo.getName(builtinId));
|
||||
return mlir::Value{};
|
||||
return makeBinaryAtomicValue(cir::AtomicFetchKind::UDecWrap, expr,
|
||||
/*originalArgType=*/nullptr,
|
||||
/*emittedArgValue=*/nullptr,
|
||||
cir::MemOrder::Relaxed);
|
||||
case NVPTX::BI__nvvm_ldg_c:
|
||||
case NVPTX::BI__nvvm_ldg_sc:
|
||||
case NVPTX::BI__nvvm_ldg_c2:
|
||||
|
|
|
|||
|
|
@ -811,6 +811,49 @@ static mlir::Value emitX86MaskedLoad(CIRGenBuilderTy &builder,
|
|||
return builder.createMaskedLoad(loc, ty, ptr, alignment, maskVec, ops[1]);
|
||||
}
|
||||
|
||||
static mlir::Value emitX86VPerm2f128(CIRGenBuilderTy &builder,
|
||||
mlir::Location loc,
|
||||
llvm::SmallVector<mlir::Value> ops) {
|
||||
auto inputType = cast<cir::VectorType>(ops[0].getType());
|
||||
assert(!inputType.getIsScalable() &&
|
||||
"This is only intended for fixed-width vectors");
|
||||
|
||||
const uint8_t imm = CIRGenFunction::getZExtIntValueFromConstOp(ops[2]);
|
||||
mlir::Value zeroVec = builder.getZero(loc, inputType);
|
||||
|
||||
// If both lanes are zero, return a zero result.
|
||||
if ((imm & 0x80) && (imm & 0x08))
|
||||
return zeroVec;
|
||||
|
||||
mlir::Value lanes[2];
|
||||
llvm::SmallVector<mlir::Attribute, 64> mask;
|
||||
|
||||
cir::IntType i32Ty = builder.getSInt32Ty();
|
||||
const unsigned numElts = inputType.getSize();
|
||||
// We must evaluated each lane(128 bits) separetely
|
||||
for (auto lane : llvm::seq(0, 2)) {
|
||||
bool isZeroBit = imm & (1 << ((lane * 4) + 3)),
|
||||
isSourceB = imm & (1 << ((lane * 4) + 1)),
|
||||
isUpperHalf = imm & (1 << (lane * 4));
|
||||
|
||||
// Determine the source for this lane
|
||||
if (isZeroBit)
|
||||
lanes[lane] = zeroVec;
|
||||
else
|
||||
lanes[lane] = isSourceB ? ops[1] : ops[0];
|
||||
|
||||
// We need to built the shuffle mask selecting the right half
|
||||
for (auto elt : llvm::seq(0u, numElts / 2u)) {
|
||||
unsigned idx = (lane * numElts) + elt;
|
||||
if (isUpperHalf)
|
||||
idx += numElts / 2;
|
||||
mask.push_back(cir::IntAttr::get(i32Ty, idx));
|
||||
}
|
||||
}
|
||||
|
||||
return builder.createVecShuffle(loc, lanes[0], lanes[1], mask);
|
||||
}
|
||||
|
||||
static mlir::Value emitX86PackedByteShift(CIRGenBuilderTy &builder,
|
||||
unsigned builtinID,
|
||||
mlir::Location loc,
|
||||
|
|
@ -1855,10 +1898,7 @@ CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) {
|
|||
case X86::BI__builtin_ia32_vperm2f128_ps256:
|
||||
case X86::BI__builtin_ia32_vperm2f128_si256:
|
||||
case X86::BI__builtin_ia32_permti256:
|
||||
cgm.errorNYI(expr->getSourceRange(),
|
||||
std::string("unimplemented X86 builtin call: ") +
|
||||
getContext().BuiltinInfo.getName(builtinID));
|
||||
return mlir::Value{};
|
||||
return emitX86VPerm2f128(builder, getLoc(expr->getExprLoc()), ops);
|
||||
case X86::BI__builtin_ia32_pslldqi128_byteshift:
|
||||
case X86::BI__builtin_ia32_pslldqi256_byteshift:
|
||||
case X86::BI__builtin_ia32_pslldqi512_byteshift:
|
||||
|
|
|
|||
|
|
@ -156,12 +156,68 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
mlir::Attribute updateBitfieldInit(CIRGenModule &cgm, cir::IntAttr existingVal,
|
||||
llvm::APInt bitfieldStorageToAPInt(mlir::Attribute attr, unsigned storageSize,
|
||||
bool isBigEndian) {
|
||||
// An empty attribute is just zero of the correct size.
|
||||
if (!attr)
|
||||
return llvm::APInt(storageSize, 0);
|
||||
// An int type is just the value held in the attribute.
|
||||
if (auto intAttr = mlir::dyn_cast<cir::IntAttr>(attr))
|
||||
return intAttr.getValue();
|
||||
|
||||
// Else we are in the array case, we have to create the big APInt, and fill it
|
||||
// up.
|
||||
llvm::APInt result(storageSize, 0);
|
||||
auto elts = mlir::cast<mlir::ArrayAttr>(
|
||||
mlir::cast<cir::ConstArrayAttr>(attr).getElts());
|
||||
|
||||
unsigned numBytes = elts.size();
|
||||
for (unsigned i = 0; i != numBytes; ++i) {
|
||||
unsigned byteIdx = isBigEndian ? numBytes - 1 - i : i;
|
||||
llvm::APInt byte =
|
||||
mlir::cast<cir::IntAttr>(elts[i]).getValue().zextOrTrunc(8);
|
||||
result.insertBits(byte, byteIdx * 8);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
mlir::Attribute apIntToBitfieldStorage(CIRGenModule &cgm,
|
||||
mlir::Type storageType,
|
||||
const llvm::APInt &value,
|
||||
bool isBigEndian) {
|
||||
// If we'ere an int, just return the new value.
|
||||
if (mlir::isa<cir::IntTypeInterface>(storageType))
|
||||
return cir::IntAttr::get(storageType, value);
|
||||
|
||||
// Array of bytes case, fill up an array.
|
||||
CIRGenBuilderTy &builder = cgm.getBuilder();
|
||||
auto arrayTy = mlir::cast<cir::ArrayType>(storageType);
|
||||
|
||||
unsigned numBytes = arrayTy.getSize();
|
||||
cir::IntType byteTy = builder.getUInt8Ty();
|
||||
llvm::SmallVector<mlir::Attribute, 8> bytes(numBytes);
|
||||
|
||||
for (unsigned i = 0; i != numBytes; ++i) {
|
||||
unsigned byteIdx = isBigEndian ? numBytes - 1 - i : i;
|
||||
bytes[i] = cir::IntAttr::get(byteTy, value.extractBits(8, byteIdx * 8));
|
||||
}
|
||||
return cir::ConstArrayAttr::get(
|
||||
arrayTy, mlir::ArrayAttr::get(builder.getContext(), bytes));
|
||||
}
|
||||
|
||||
// Bitfields are lowered to either an integer type, or a series of bytes, see
|
||||
// getBitfieldStorageType. Because of this, we have to figure out how to store
|
||||
// this init value in those. Do this by converting the current value in the
|
||||
// 'storage' type to an APInt so we can do our masking correctly, then convert
|
||||
// back. The int path is trivial (getValue/create a new one with the new
|
||||
// value). The array type requires breaking it up into its constituent values.
|
||||
mlir::Attribute updateBitfieldInit(CIRGenModule &cgm,
|
||||
mlir::Attribute existingVal,
|
||||
cir::IntAttr newVal, bool isSigned,
|
||||
const CIRGenBitFieldInfo &bfInfo) {
|
||||
llvm::APInt result(bfInfo.storageSize, 0);
|
||||
if (existingVal)
|
||||
result = existingVal.getValue();
|
||||
bool isBigEndian = cgm.getDataLayout().isBigEndian();
|
||||
llvm::APInt result =
|
||||
bitfieldStorageToAPInt(existingVal, bfInfo.storageSize, isBigEndian);
|
||||
|
||||
llvm::APInt curValue = newVal.getValue();
|
||||
// Make sure we truncate (or properly extend) the existing value for the
|
||||
|
|
@ -175,18 +231,16 @@ mlir::Attribute updateBitfieldInit(CIRGenModule &cgm, cir::IntAttr existingVal,
|
|||
// Extend to the full storage size so we can shift/mask.
|
||||
curValue = curValue.zext(bfInfo.storageSize);
|
||||
|
||||
unsigned offset = bfInfo.offset;
|
||||
if (cgm.getDataLayout().isBigEndian())
|
||||
offset = bfInfo.storageSize - bfInfo.size - offset;
|
||||
|
||||
curValue = curValue.shl(offset);
|
||||
// bfInfo.offset is already adjusted for endianness, so no endian-changes need
|
||||
// to happen here.
|
||||
curValue = curValue.shl(bfInfo.offset);
|
||||
llvm::APInt mask(bfInfo.storageSize, 0);
|
||||
mask.setBits(offset, offset + bfInfo.size);
|
||||
mask.setBits(bfInfo.offset, bfInfo.offset + bfInfo.size);
|
||||
|
||||
result &= ~mask;
|
||||
result |= curValue;
|
||||
|
||||
return cir::IntAttr::get(bfInfo.storageType, result);
|
||||
return apIntToBitfieldStorage(cgm, bfInfo.storageType, result, isBigEndian);
|
||||
}
|
||||
|
||||
mlir::Attribute
|
||||
|
|
@ -204,7 +258,7 @@ setBitfieldInit(CIRGenModule &cgm, const CIRGenRecordLayout &cirLayout,
|
|||
}
|
||||
|
||||
return updateBitfieldInit(
|
||||
cgm, dyn_cast_if_present<cir::IntAttr>(existingVal), intAttr,
|
||||
cgm, existingVal, intAttr,
|
||||
field->getType()->isSignedIntegerOrEnumerationType(), info);
|
||||
}
|
||||
|
||||
|
|
@ -1044,7 +1098,7 @@ static mlir::TypedAttr emitNullConstant(CIRGenModule &cgm, const RecordDecl *rd,
|
|||
: layout.getBaseSubobjectCIRType());
|
||||
auto recordTy = mlir::cast<cir::RecordType>(ty);
|
||||
|
||||
unsigned numElements = recordTy.getNumElements();
|
||||
unsigned numElements = rd->isUnion() ? 1 : recordTy.getNumElements();
|
||||
SmallVector<mlir::Attribute> elements(numElements);
|
||||
|
||||
auto *cxxrd = dyn_cast<CXXRecordDecl>(rd);
|
||||
|
|
|
|||
|
|
@ -1648,6 +1648,12 @@ public:
|
|||
const Expr *memOrder, bool isStore, bool isLoad, bool isFence,
|
||||
llvm::function_ref<void(cir::MemOrder)> emitAtomicOp);
|
||||
|
||||
mlir::Value makeBinaryAtomicValue(
|
||||
cir::AtomicFetchKind kind, const clang::CallExpr *expr,
|
||||
mlir::Type *originalArgType = nullptr,
|
||||
mlir::Value *emittedArgValue = nullptr,
|
||||
cir::MemOrder ordering = cir::MemOrder::SequentiallyConsistent);
|
||||
|
||||
mlir::LogicalResult emitAttributedStmt(const AttributedStmt &s);
|
||||
|
||||
AutoVarEmission emitAutoVarAlloca(const clang::VarDecl &d,
|
||||
|
|
|
|||
|
|
@ -835,11 +835,10 @@ void CIRRecordLowering::lowerUnion(bool nonVirtualBaseType) {
|
|||
// an enclosing [[no_unique_address]] union field must use this smaller type.
|
||||
CharUnits layoutSize = nonVirtualBaseType ? astRecordLayout.getDataSize()
|
||||
: astRecordLayout.getSize();
|
||||
mlir::Type storageType = nullptr;
|
||||
bool seenNamedMember = false;
|
||||
// Accumulate bitfields and fields, and figure out what our difference between
|
||||
// storage type and padding is.
|
||||
|
||||
// Iterate through the fields setting bitFieldInfo and the Fields array. Also
|
||||
// locate the "most appropriate" storage type.
|
||||
// First, accumulate all the types.
|
||||
for (const FieldDecl *field : recordDecl->fields()) {
|
||||
mlir::Type fieldType;
|
||||
if (field->isBitField()) {
|
||||
|
|
@ -851,59 +850,52 @@ void CIRRecordLowering::lowerUnion(bool nonVirtualBaseType) {
|
|||
fieldType = getStorageType(field);
|
||||
}
|
||||
|
||||
// This maps a field to its index. For unions, the index is always 0.
|
||||
fieldIdxMap[field->getCanonicalDecl()] = 0;
|
||||
|
||||
// Compute zero-initializable status.
|
||||
// This union might not be zero initialized: it may contain a pointer to
|
||||
// data member which might have some exotic initialization sequence.
|
||||
// If this is the case, then we ought not to try and come up with a "better"
|
||||
// type, it might not be very easy to come up with a Constant which
|
||||
// correctly initializes it.
|
||||
if (!seenNamedMember) {
|
||||
seenNamedMember = field->getIdentifier();
|
||||
if (!seenNamedMember)
|
||||
if (const RecordDecl *fieldRD = field->getType()->getAsRecordDecl())
|
||||
seenNamedMember = fieldRD->findFirstNamedDataMember();
|
||||
if (seenNamedMember && !isZeroInitializable(field)) {
|
||||
zeroInitializable = zeroInitializableAsBase = false;
|
||||
storageType = fieldType;
|
||||
}
|
||||
}
|
||||
|
||||
// Because our union isn't zero initializable, we won't be getting a better
|
||||
// storage type.
|
||||
if (!zeroInitializable)
|
||||
continue;
|
||||
|
||||
// Conditionally update our storage type if we've got a new "better" one.
|
||||
if (!storageType || getAlignment(fieldType) > getAlignment(storageType) ||
|
||||
(getAlignment(fieldType) == getAlignment(storageType) &&
|
||||
getSize(fieldType) > getSize(storageType)))
|
||||
storageType = fieldType;
|
||||
|
||||
// NOTE(cir): Track all union member's types, not just the largest one. It
|
||||
// allows for proper type-checking and retain more info for analisys.
|
||||
//
|
||||
// The base-subobject type instead uses a single (possibly clipped) storage
|
||||
// type, mirroring classic CodeGen, so that it exposes the union's reusable
|
||||
// tail padding.
|
||||
if (!nonVirtualBaseType)
|
||||
fieldTypes.push_back(fieldType);
|
||||
fieldTypes.push_back(fieldType);
|
||||
}
|
||||
|
||||
if (!storageType) {
|
||||
// Compute zero-initializable status.
|
||||
// This union might not be zero initialized: it may contain a pointer to
|
||||
// data member which might have some exotic initialization sequence.
|
||||
// This chooses the first 'named' member and is zero-initializable based on
|
||||
// that.
|
||||
auto hasNamedMember = [](const FieldDecl *curField) -> bool {
|
||||
const auto *rd = curField->getType()->getAsRecordDecl();
|
||||
return rd && rd->findFirstNamedDataMember();
|
||||
};
|
||||
// Whether this is usable for zero-init as a 'named member'. It is a field
|
||||
// with a name (or a record type with a named member itself), that isn't a
|
||||
// zero-width bitfield.
|
||||
auto isNamedMember = [hasNamedMember](const FieldDecl *curField) -> bool {
|
||||
if (curField->isZeroLengthBitField())
|
||||
return false;
|
||||
return curField->getIdentifier() || hasNamedMember(curField);
|
||||
};
|
||||
auto firstNamedMemberItr = llvm::find_if(recordDecl->fields(), isNamedMember);
|
||||
|
||||
if (firstNamedMemberItr != recordDecl->fields().end() &&
|
||||
!isZeroInitializable(*firstNamedMemberItr))
|
||||
zeroInitializable = zeroInitializableAsBase = false;
|
||||
|
||||
// If we have no candidates for storage, we are JUST padding.
|
||||
if (fieldTypes.empty()) {
|
||||
appendPaddingBytes(layoutSize);
|
||||
return;
|
||||
}
|
||||
|
||||
mlir::Type storageType =
|
||||
cir::UnionType::getUnionStorageType(dataLayout.layout, fieldTypes);
|
||||
|
||||
// If our storage size was bigger than our required size (can happen in the
|
||||
// case of packed bitfields on Itanium) then just use an I8 array.
|
||||
if (layoutSize < getSize(storageType))
|
||||
storageType = getByteArrayType(layoutSize);
|
||||
|
||||
// The base-subobject record is built as a struct from fieldTypes, so add
|
||||
// the storage type and any trailing padding as ordinary fields rather than
|
||||
// routing padding through the union's single tail-padding slot.
|
||||
if (nonVirtualBaseType) {
|
||||
// The base-subobject record is built as a struct from fieldTypes, so add
|
||||
// the storage type and any trailing padding as ordinary fields rather than
|
||||
// routing padding through the union's single tail-padding slot.
|
||||
fieldTypes.clear();
|
||||
fieldTypes.push_back(storageType);
|
||||
CharUnits padding = layoutSize - getSize(storageType);
|
||||
if (!padding.isZero()) {
|
||||
|
|
@ -911,12 +903,10 @@ void CIRRecordLowering::lowerUnion(bool nonVirtualBaseType) {
|
|||
padded = true;
|
||||
}
|
||||
} else {
|
||||
// Else we just add padding normally.
|
||||
appendPaddingBytes(layoutSize - getSize(storageType));
|
||||
}
|
||||
|
||||
// Set packed if we need it.
|
||||
if (!layoutSize.isMultipleOf(getAlignment(storageType)))
|
||||
packed = true;
|
||||
packed = !layoutSize.isMultipleOf(getAlignment(storageType));
|
||||
}
|
||||
|
||||
bool CIRRecordLowering::hasOwnStorage(const CXXRecordDecl *decl,
|
||||
|
|
|
|||
|
|
@ -488,7 +488,11 @@ void UnionType::complete(ArrayRef<Type> members, bool packed,
|
|||
|
||||
mlir::Type
|
||||
UnionType::getUnionStorageType(const mlir::DataLayout &dataLayout) const {
|
||||
llvm::ArrayRef<mlir::Type> members = getMembers();
|
||||
return getUnionStorageType(dataLayout, getMembers());
|
||||
}
|
||||
|
||||
mlir::Type UnionType::getUnionStorageType(const mlir::DataLayout &dataLayout,
|
||||
llvm::ArrayRef<mlir::Type> members) {
|
||||
if (members.empty())
|
||||
return {};
|
||||
return *std::max_element(
|
||||
|
|
|
|||
|
|
@ -570,84 +570,11 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstArrayAttr attr) {
|
|||
return result;
|
||||
}
|
||||
|
||||
// Figure out if we want mark the new struct 'packed' if it isn't already. IF
|
||||
// it is already, we have to keep that behavior. We pack it with logic similar
|
||||
// to classic codegen, though will end up missing cases, since we don't want to
|
||||
// change the type other than the FAM.
|
||||
// We can do so if:
|
||||
// 1- Packing it won't change any of the field offsets.
|
||||
// 2- the non-padded struct would add padding beyond the
|
||||
// flexible array member. We don't pack if the flexible array member manages
|
||||
// to not cause trailing padding.
|
||||
static bool shouldPackFAMStruct(const mlir::DataLayout &dataLayout,
|
||||
llvm::ArrayRef<mlir::Type> members) {
|
||||
uint64_t maxAlign = 1;
|
||||
uint64_t totalSize = 0;
|
||||
for (mlir::Type member : members) {
|
||||
uint64_t align = dataLayout.getTypeABIAlignment(member);
|
||||
maxAlign = std::max(maxAlign, align);
|
||||
uint64_t size = dataLayout.getTypeSize(member).getFixedValue();
|
||||
|
||||
if (llvm::alignTo(totalSize, align) != totalSize)
|
||||
return false;
|
||||
|
||||
totalSize += size;
|
||||
}
|
||||
return llvm::alignTo(totalSize, maxAlign) != totalSize;
|
||||
}
|
||||
|
||||
// CIR supports flexible-array-members in its struct types. That is, a
|
||||
// zero-length array as the last element, which can be initialized with an
|
||||
// arbitrary number of elements. A ConstRecordAttr can be created with one of
|
||||
// these, and our verifier allows it. However, the LLVM implementation does NOT
|
||||
// permit this. So we have to replace this type in LLVM with special struct for
|
||||
// this value.
|
||||
// This function is used to adjust any place we could run into a
|
||||
// ConstRecordAttr (that is, a global?) that is initialized. It'll return the
|
||||
// type value unchanged if this isn't a flexible array member case.
|
||||
static mlir::Type
|
||||
adjustGlobalTypeForFlexibleArrayInit(mlir::Type llvmType, mlir::Attribute init,
|
||||
const mlir::TypeConverter &converter,
|
||||
const mlir::DataLayout &dataLayout) {
|
||||
// This only applies to ConstRecordAttr initialization.
|
||||
auto constRecord = mlir::dyn_cast_if_present<cir::ConstRecordAttr>(init);
|
||||
if (!constRecord)
|
||||
return llvmType;
|
||||
|
||||
// If this isn't of struct-type, or doesn't have any members, there is nothing
|
||||
// to do.
|
||||
auto structTy = mlir::dyn_cast<mlir::LLVM::LLVMStructType>(llvmType);
|
||||
if (!structTy || structTy.getBody().empty())
|
||||
return llvmType;
|
||||
|
||||
// If this isn't a zero-sized array, it isn't a flexible array member.
|
||||
auto fam = dyn_cast<mlir::LLVM::LLVMArrayType>(structTy.getBody().back());
|
||||
if (!fam || fam.getNumElements() != 0)
|
||||
return llvmType;
|
||||
|
||||
llvm::ArrayRef<mlir::Attribute> initMembers =
|
||||
constRecord.getMembers().getValue();
|
||||
mlir::Type lastInitType = cast<mlir::TypedAttr>(initMembers.back()).getType();
|
||||
|
||||
// Don't touch it if we don't need to do non-zero elements.
|
||||
if (cast<cir::ArrayType>(lastInitType).getSize() == 0)
|
||||
return llvmType;
|
||||
|
||||
llvm::SmallVector<mlir::Type> newBody{structTy.getBody()};
|
||||
newBody[newBody.size() - 1] = converter.convertType(lastInitType);
|
||||
|
||||
bool packed = structTy.isPacked() || shouldPackFAMStruct(dataLayout, newBody);
|
||||
|
||||
return mlir::LLVM::LLVMStructType::getLiteral(structTy.getContext(), newBody,
|
||||
packed);
|
||||
}
|
||||
|
||||
/// ConstRecord visitor.
|
||||
mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstRecordAttr constRecord) {
|
||||
mlir::Type llvmTy = converter->convertType(constRecord.getType());
|
||||
mlir::DataLayout dataLayout(parentOp->getParentOfType<mlir::ModuleOp>());
|
||||
llvmTy = adjustGlobalTypeForFlexibleArrayInit(llvmTy, constRecord, *converter,
|
||||
dataLayout);
|
||||
llvmTy = adjustGlobalTypeForInit(llvmTy, constRecord, *converter, dataLayout);
|
||||
const mlir::Location loc = parentOp->getLoc();
|
||||
mlir::Value result = mlir::LLVM::UndefOp::create(rewriter, loc, llvmTy);
|
||||
|
||||
|
|
@ -2538,8 +2465,8 @@ void CIRToLLVMGlobalOpLowering::setupRegionInitializedLLVMGlobalOp(
|
|||
// Keep the global's type in sync with the value built by CIRAttrToValue: a
|
||||
// flexible array member initializer requires an oversized anonymous struct.
|
||||
if (std::optional<mlir::Attribute> init = op.getInitialValue())
|
||||
llvmType = adjustGlobalTypeForFlexibleArrayInit(
|
||||
llvmType, *init, *getTypeConverter(), dataLayout);
|
||||
llvmType = adjustGlobalTypeForInit(llvmType, *init, *getTypeConverter(),
|
||||
dataLayout);
|
||||
|
||||
// FIXME: These default values are placeholders until the the equivalent
|
||||
// attributes are available on cir.global ops. This duplicates code
|
||||
|
|
@ -2615,8 +2542,8 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
|
|||
// record's declared type, so the global must use an oversized anonymous
|
||||
// struct instead.
|
||||
if (init.has_value())
|
||||
llvmType = adjustGlobalTypeForFlexibleArrayInit(
|
||||
llvmType, *init, *getTypeConverter(), dataLayout);
|
||||
llvmType = adjustGlobalTypeForInit(llvmType, *init, *getTypeConverter(),
|
||||
dataLayout);
|
||||
|
||||
// FIXME: These default values are placeholders until the the equivalent
|
||||
// attributes are available on cir.global ops.
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@
|
|||
#include "clang/CIR/LoweringHelpers.h"
|
||||
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
|
||||
#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
|
||||
#include "mlir/IR/BuiltinTypes.h"
|
||||
#include "mlir/IR/SymbolTable.h"
|
||||
#include "mlir/Interfaces/DataLayoutInterfaces.h"
|
||||
|
||||
static unsigned getIntOrBoolBitWidth(mlir::Type ty) {
|
||||
if (auto intTy = mlir::dyn_cast<cir::IntType>(ty))
|
||||
|
|
@ -314,6 +316,165 @@ lowerConstRecordMemberAttr(mlir::Attribute attr,
|
|||
return lowerPointerElementAttr(attr, ctx, moduleOp, converter);
|
||||
}
|
||||
|
||||
// Figure out if we want mark the new struct 'packed' if it isn't already. IF
|
||||
// it is already, we have to keep that behavior. We pack it with logic similar
|
||||
// to classic codegen, though will end up missing cases, since we don't want to
|
||||
// change the type other than the FAM.
|
||||
// We can do so if:
|
||||
// 1- Packing it won't change any of the field offsets.
|
||||
// 2- the non-padded struct would add padding beyond the
|
||||
// flexible array member. We don't pack if the flexible array member manages
|
||||
// to not cause trailing padding.
|
||||
static bool shouldPackFAMStruct(const mlir::DataLayout &dataLayout,
|
||||
llvm::ArrayRef<mlir::Type> members) {
|
||||
uint64_t maxAlign = 1;
|
||||
uint64_t totalSize = 0;
|
||||
for (mlir::Type member : members) {
|
||||
uint64_t align = dataLayout.getTypeABIAlignment(member);
|
||||
maxAlign = std::max(maxAlign, align);
|
||||
uint64_t size = dataLayout.getTypeSize(member).getFixedValue();
|
||||
|
||||
if (llvm::alignTo(totalSize, align) != totalSize)
|
||||
return false;
|
||||
|
||||
totalSize += size;
|
||||
}
|
||||
return llvm::alignTo(totalSize, maxAlign) != totalSize;
|
||||
}
|
||||
|
||||
// CIR supports flexible-array-members in its struct types. That is, a
|
||||
// zero-length array as the last element, which can be initialized with an
|
||||
// arbitrary number of elements. A ConstRecordAttr can be created with one of
|
||||
// these, and our verifier allows it. However, the LLVM implementation does NOT
|
||||
// permit this. So we have to replace this type in LLVM with special struct for
|
||||
// this value.
|
||||
//
|
||||
// Additionally, the struct itself could contain a struct with a FAM or a union
|
||||
// that needed adjustment, so it recurses to check those. If no such type has
|
||||
// been found/no adjustment needed, this returns the type unchanged.
|
||||
static mlir::Type adjustGlobalStructTypeForInit(
|
||||
mlir::LLVM::LLVMStructType structTy, cir::ConstRecordAttr constRecord,
|
||||
const mlir::TypeConverter &converter, const mlir::DataLayout &dataLayout) {
|
||||
|
||||
llvm::ArrayRef<mlir::Attribute> initMembers =
|
||||
constRecord.getMembers().getValue();
|
||||
llvm::SmallVector<mlir::Type> newBody{structTy.getBody()};
|
||||
bool changed = false;
|
||||
|
||||
// Recursively adjust each member. A member that is itself a union (or a
|
||||
// struct containing one) lowers to a type that differs from its declared
|
||||
// field type, and this struct has to adopt that adjusted type so the
|
||||
// enclosing insertvalue chain type-checks.
|
||||
for (auto [idx, member] : llvm::enumerate(initMembers)) {
|
||||
if (idx >= newBody.size())
|
||||
break;
|
||||
mlir::Type adjusted =
|
||||
adjustGlobalTypeForInit(newBody[idx], member, converter, dataLayout);
|
||||
if (adjusted != newBody[idx]) {
|
||||
newBody[idx] = adjusted;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// CIR supports flexible-array-members in its struct types. That is, a
|
||||
// zero-length array as the last element, which can be initialized with an
|
||||
// arbitrary number of elements. A ConstRecordAttr can be created with one of
|
||||
// these, and our verifier allows it. However, the LLVM implementation does
|
||||
// NOT permit this, so we widen that trailing member to the initializer's
|
||||
// array type (packing the struct if that changes the layout).
|
||||
bool packed = structTy.isPacked();
|
||||
if (auto fam =
|
||||
mlir::dyn_cast<mlir::LLVM::LLVMArrayType>(structTy.getBody().back());
|
||||
fam && fam.getNumElements() == 0) {
|
||||
mlir::Type lastInitType =
|
||||
mlir::cast<mlir::TypedAttr>(initMembers.back()).getType();
|
||||
if (mlir::cast<cir::ArrayType>(lastInitType).getSize() != 0) {
|
||||
newBody.back() = converter.convertType(lastInitType);
|
||||
packed = packed || shouldPackFAMStruct(dataLayout, newBody);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!changed)
|
||||
return structTy;
|
||||
|
||||
return mlir::LLVM::LLVMStructType::getLiteral(structTy.getContext(), newBody,
|
||||
packed);
|
||||
}
|
||||
|
||||
// A union constant only initializes its active member, but a union is lowered
|
||||
// to its most-aligned member (its 'storage' type), which need not be the
|
||||
// initialized one -- e.g. `union { char buf[16]; long cap; }` stores as `long`
|
||||
// (higher alignment) but may be initialized through `buf`. So the storage type
|
||||
// (and thus structTy) generally can't hold the active member's value. Rebuild
|
||||
// an anonymous struct `{ <active member>, [pad x i8] }` that holds the active
|
||||
// member followed by enough byte padding to span the union's full allocated
|
||||
// size, mirroring classic codegen.
|
||||
static mlir::Type adjustGlobalUnionTypeForInit(
|
||||
mlir::LLVM::LLVMStructType structTy, cir::ConstRecordAttr constRecord,
|
||||
const mlir::TypeConverter &converter, const mlir::DataLayout &dataLayout) {
|
||||
|
||||
auto unionTy = mlir::cast<cir::UnionType>(constRecord.getType());
|
||||
|
||||
// Unions can only initialize one field, so this has to be sizeof-one.
|
||||
assert(constRecord.getMembers().size() == 1);
|
||||
mlir::Attribute member = constRecord.getMembers()[0];
|
||||
mlir::Type memberTy =
|
||||
converter.convertType(mlir::cast<mlir::TypedAttr>(member).getType());
|
||||
|
||||
// The active member may itself need adjusting (e.g. it is a nested union, or
|
||||
// a struct containing one), so recurse before using its type below.
|
||||
memberTy = adjustGlobalTypeForInit(memberTy, member, converter, dataLayout);
|
||||
|
||||
// The converted union type is { storage, [padding] }, where storage is the
|
||||
// union's most-aligned member. When the active member IS that storage type,
|
||||
// the converted type already describes this initializer exactly (the pad we
|
||||
// would compute equals the union's declared pad), so there is nothing to do.
|
||||
if (memberTy == structTy.getBody().front())
|
||||
return structTy;
|
||||
|
||||
uint64_t unionSize = dataLayout.getTypeSize(unionTy).getFixedValue();
|
||||
uint64_t initSize = dataLayout.getTypeSize(memberTy).getFixedValue();
|
||||
assert(initSize <= unionSize && "union initializer larger than the union");
|
||||
|
||||
llvm::SmallVector<mlir::Type> newBody;
|
||||
newBody.push_back(memberTy);
|
||||
|
||||
// Fill the rest of the union's allocated size with byte padding.
|
||||
if (initSize < unionSize)
|
||||
newBody.push_back(mlir::LLVM::LLVMArrayType::get(
|
||||
mlir::IntegerType::get(structTy.getContext(), 8),
|
||||
unionSize - initSize));
|
||||
|
||||
return mlir::LLVM::LLVMStructType::getLiteral(structTy.getContext(), newBody,
|
||||
unionTy.getPacked());
|
||||
}
|
||||
|
||||
// Apply various adjustments required for struct/union types.
|
||||
mlir::Type adjustGlobalTypeForInit(mlir::Type llvmType, mlir::Attribute init,
|
||||
const mlir::TypeConverter &converter,
|
||||
const mlir::DataLayout &dataLayout) {
|
||||
// Conversions for both only happen if we have a record init.
|
||||
auto constRecord = mlir::dyn_cast_if_present<cir::ConstRecordAttr>(init);
|
||||
if (!constRecord)
|
||||
return llvmType;
|
||||
|
||||
// If this isn't of struct-type, or doesn't have any members, there is nothing
|
||||
// to do.
|
||||
auto structTy = mlir::dyn_cast<mlir::LLVM::LLVMStructType>(llvmType);
|
||||
if (!structTy || structTy.getBody().empty())
|
||||
return llvmType;
|
||||
|
||||
// Structs can have a flexible array member, adjust that.
|
||||
if (mlir::isa<cir::StructType>(constRecord.getType()))
|
||||
return adjustGlobalStructTypeForInit(structTy, constRecord, converter,
|
||||
dataLayout);
|
||||
if (mlir::isa<cir::UnionType>(constRecord.getType()))
|
||||
return adjustGlobalUnionTypeForInit(structTy, constRecord, converter,
|
||||
dataLayout);
|
||||
return llvmType;
|
||||
}
|
||||
|
||||
std::optional<mlir::Attribute>
|
||||
lowerConstRecordAttr(cir::ConstRecordAttr constRecord,
|
||||
const mlir::TypeConverter *converter,
|
||||
|
|
@ -333,15 +494,19 @@ lowerConstRecordAttr(cir::ConstRecordAttr constRecord,
|
|||
loweredMembers.push_back(*lowered);
|
||||
}
|
||||
|
||||
// For a union, the CIR representation is a single field. However, if the
|
||||
// union has padding, we would have added that as an LLVM field, so make sure
|
||||
// we have a corresponding undef for that spot.
|
||||
if (auto unionTy = mlir::dyn_cast<cir::UnionType>(constRecord.getType());
|
||||
unionTy && unionTy.getPadded()) {
|
||||
assert(loweredMembers.size() == 1);
|
||||
loweredMembers.push_back(
|
||||
mlir::LLVM::UndefAttr::get(constRecord.getContext()));
|
||||
}
|
||||
// The lowered LLVM type may have more fields than the CIR record has members
|
||||
// -- e.g. a union lowers to { active-member, [pad x i8] } (see
|
||||
// adjustGlobalTypeForInit, the single source of truth for the shape). Fill
|
||||
// any such synthesized (padding) fields with undef so this ArrayAttr has
|
||||
// exactly one entry per LLVM field, matching the type the global is declared
|
||||
// with.
|
||||
mlir::Type adjustedTy = adjustGlobalTypeForInit(
|
||||
converter->convertType(constRecord.getType()), constRecord, *converter,
|
||||
mlir::DataLayout(moduleOp));
|
||||
if (auto structTy = mlir::dyn_cast<mlir::LLVM::LLVMStructType>(adjustedTy))
|
||||
while (loweredMembers.size() < structTy.getBody().size())
|
||||
loweredMembers.push_back(
|
||||
mlir::LLVM::UndefAttr::get(constRecord.getContext()));
|
||||
|
||||
return mlir::ArrayAttr::get(constRecord.getContext(), loweredMembers);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -443,6 +443,7 @@ PrintingPolicy CGDebugInfo::getPrintingPolicy() const {
|
|||
PP.UsePreferredNames = false;
|
||||
PP.AlwaysIncludeTypeForTemplateArgument = true;
|
||||
PP.UseEnumerators = false;
|
||||
PP.PrettyEnums = false;
|
||||
|
||||
// Apply -fdebug-prefix-map.
|
||||
PP.Callbacks = &PrintCB;
|
||||
|
|
|
|||
|
|
@ -5021,6 +5021,8 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
|
|||
divisor = CGF.CGM.getSize(elementSize);
|
||||
}
|
||||
|
||||
if (CGF.getLangOpts().StablePointerSubtraction)
|
||||
return Builder.CreateSDiv(diffInChars, divisor, "sub.ptr.div");
|
||||
// Otherwise, do a full sdiv. This uses the "exact" form of sdiv, since
|
||||
// pointer difference in C is only defined in the case where both operands
|
||||
// are pointing to elements of an array.
|
||||
|
|
|
|||
|
|
@ -332,10 +332,8 @@ clang::CodeGen::LoopInfo::createLoopDistributeMetadata(
|
|||
SmallVector<Metadata *, 4> NewLoopProperties;
|
||||
if (Enabled == false) {
|
||||
NewLoopProperties.append(LoopProperties.begin(), LoopProperties.end());
|
||||
NewLoopProperties.push_back(
|
||||
MDNode::get(Ctx, {MDString::get(Ctx, "llvm.loop.distribute.enable"),
|
||||
ConstantAsMetadata::get(ConstantInt::get(
|
||||
llvm::Type::getInt1Ty(Ctx), 0))}));
|
||||
NewLoopProperties.push_back(MDNode::get(
|
||||
Ctx, {MDString::get(Ctx, "llvm.loop.distribute.disable")}));
|
||||
LoopProperties = NewLoopProperties;
|
||||
}
|
||||
return createLoopVectorizeMetadata(Attrs, LoopProperties,
|
||||
|
|
@ -349,11 +347,8 @@ clang::CodeGen::LoopInfo::createLoopDistributeMetadata(
|
|||
SmallVector<Metadata *, 4> Args;
|
||||
Args.append(LoopProperties.begin(), LoopProperties.end());
|
||||
|
||||
Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.distribute.enable"),
|
||||
ConstantAsMetadata::get(ConstantInt::get(
|
||||
llvm::Type::getInt1Ty(Ctx),
|
||||
(Attrs.DistributeEnable == LoopAttributes::Enable)))};
|
||||
Args.push_back(MDNode::get(Ctx, Vals));
|
||||
Args.push_back(
|
||||
MDNode::get(Ctx, {MDString::get(Ctx, "llvm.loop.distribute.enable")}));
|
||||
|
||||
if (FollowupHasTransforms)
|
||||
Args.push_back(
|
||||
|
|
|
|||
|
|
@ -1225,6 +1225,14 @@ ToolChain::path_list ToolChain::getArchSpecificLibPaths() const {
|
|||
};
|
||||
|
||||
AddPath({getTriple().str()});
|
||||
|
||||
// Handle the legacy AMDGPU triple case as well.
|
||||
if (getTriple().getArchName() == "amdgcn") {
|
||||
llvm::Triple Canon(getTriple());
|
||||
Canon.setArchName("amdgpu");
|
||||
AddPath({Canon.str()});
|
||||
}
|
||||
|
||||
AddPath({getOSLibName(), llvm::Triple::getArchTypeName(getArch())});
|
||||
return Paths;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5386,6 +5386,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
|||
CmdArgs.push_back("-funified-lto");
|
||||
}
|
||||
|
||||
if (Args.hasArg(options::OPT_fdefined_pointer_subtraction))
|
||||
CmdArgs.push_back("-fdefined-pointer-subtraction");
|
||||
|
||||
// If CollectArgsForIntegratedAssembler() isn't called below, claim the args
|
||||
// it claims when not running an assembler. Otherwise, clang would emit
|
||||
// "argument unused" warnings for assembler flags when e.g. adding "-E" to
|
||||
|
|
|
|||
|
|
@ -831,7 +831,7 @@ public:
|
|||
tok::kw_decltype, tok::kw_noexcept, tok::kw_static_assert,
|
||||
tok::kw__Atomic,
|
||||
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) tok::kw___##Trait,
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
tok::kw_requires);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -450,7 +450,7 @@ private:
|
|||
} else if (PrevNonComment->isOneOf(TT_TypenameMacro, tok::kw_decltype,
|
||||
tok::kw_typeof,
|
||||
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) tok::kw___##Trait,
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
tok::kw__Atomic)) {
|
||||
OpeningParen.setType(TT_TypeDeclarationParen);
|
||||
// decltype() and typeof() usually contain expressions.
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ namespace {
|
|||
} else if (OutputKind == Print) {
|
||||
PrintingPolicy Policy(D->getASTContext().getLangOpts());
|
||||
Policy.IncludeTagDefinition = true;
|
||||
Policy.PrettyEnums = false;
|
||||
D->print(Out, Policy, /*Indentation=*/0, /*PrintInstantiation=*/true);
|
||||
} else if (OutputKind != None) {
|
||||
D->dump(Out, OutputKind == DumpFull, OutputFormat);
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ bool Token::isSimpleTypeSpecifier(const LangOptions &LangOpts) const {
|
|||
case tok::kw__Fract:
|
||||
case tok::kw__Sat:
|
||||
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
case tok::kw___auto_type:
|
||||
case tok::kw_char16_t:
|
||||
case tok::kw_char32_t:
|
||||
|
|
|
|||
|
|
@ -1609,7 +1609,7 @@ static bool IsBuiltinTrait(Token &Tok) {
|
|||
switch (Tok.getKind()) {
|
||||
default:
|
||||
return false;
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4631,7 +4631,7 @@ void Parser::ParseDeclarationSpecifiers(
|
|||
continue;
|
||||
|
||||
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
// HACK: libstdc++ already uses '__remove_cv' as an alias template so we
|
||||
// work around this by expecting all transform type traits to be suffixed
|
||||
// with '('. They're an identifier otherwise.
|
||||
|
|
|
|||
|
|
@ -1241,7 +1241,7 @@ DeclSpec::TST Parser::TypeTransformTokToDeclSpec() {
|
|||
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \
|
||||
case tok::kw___##Trait: \
|
||||
return DeclSpec::TST_##Trait;
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
default:
|
||||
llvm_unreachable("passed in an unhandled type transformation built-in");
|
||||
}
|
||||
|
|
@ -1604,7 +1604,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
|||
!Tok.isAnnotation() && Tok.getIdentifierInfo() &&
|
||||
Tok.isOneOf(
|
||||
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) tok::kw___##Trait,
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
tok::kw___is_abstract,
|
||||
tok::kw___is_aggregate,
|
||||
tok::kw___is_arithmetic,
|
||||
|
|
|
|||
|
|
@ -710,7 +710,7 @@ bool Parser::isRevertibleTypeTrait(const IdentifierInfo *II,
|
|||
REVERTIBLE_TYPE_TRAIT(__reference_binds_to_temporary);
|
||||
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \
|
||||
REVERTIBLE_TYPE_TRAIT(RTT_JOIN(__, Trait));
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
#undef REVERTIBLE_TYPE_TRAIT
|
||||
#undef RTT_JOIN
|
||||
}
|
||||
|
|
@ -1563,7 +1563,7 @@ Parser::ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand,
|
|||
return ExprError();
|
||||
}
|
||||
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
// HACK: libstdc++ uses some of the transform-type-traits as alias
|
||||
// templates, so we need to work around this.
|
||||
if (!NextToken().is(tok::l_paren)) {
|
||||
|
|
|
|||
|
|
@ -375,7 +375,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
|
|||
|
||||
switch (Tok.getKind()) {
|
||||
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
if (!NextToken().is(tok::l_paren)) {
|
||||
Tok.setKind(tok::identifier);
|
||||
Diag(Tok, diag::ext_keyword_as_ident)
|
||||
|
|
@ -2881,7 +2881,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType,
|
|||
|
||||
switch (Tok.getKind()) {
|
||||
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
if (!NextToken().is(tok::l_paren)) {
|
||||
Tok.setKind(tok::identifier);
|
||||
Diag(Tok, diag::ext_keyword_as_ident)
|
||||
|
|
@ -3464,7 +3464,7 @@ case tok::kw_ ## Spelling: return BTT_ ## Name;
|
|||
#include "clang/Basic/TokenKinds.def"
|
||||
#define TYPE_TRAIT_N(Spelling, Name, Key) \
|
||||
case tok::kw_ ## Spelling: return TT_ ## Name;
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3475,7 +3475,7 @@ static ArrayTypeTrait ArrayTypeTraitFromTokKind(tok::TokenKind kind) {
|
|||
#define ARRAY_TYPE_TRAIT(Spelling, Name, Key) \
|
||||
case tok::kw_##Spelling: \
|
||||
return ATT_##Name;
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3486,7 +3486,7 @@ static ExpressionTrait ExpressionTraitFromTokKind(tok::TokenKind kind) {
|
|||
#define EXPRESSION_TRAIT(Spelling, Name, Key) \
|
||||
case tok::kw_##Spelling: \
|
||||
return ET_##Name;
|
||||
#include "clang/Basic/TokenKinds.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ Retry:
|
|||
|
||||
switch (Tok.getKind()) {
|
||||
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
if (NextToken().is(tok::less)) {
|
||||
Tok.setKind(tok::identifier);
|
||||
Diag(Tok, diag::ext_keyword_as_ident)
|
||||
|
|
@ -2345,6 +2345,9 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc,
|
|||
// the other parts.
|
||||
getCurScope()->EnterLoopBody(PrecedingLabel);
|
||||
|
||||
bool BodyStartsWithAttr = Tok.isOneOf(tok::l_square, tok::kw___attribute);
|
||||
SourceLocation BodyBeginLoc = Tok.getLocation();
|
||||
|
||||
// C99 6.8.5p5 - In C99, the body of the for statement is a scope, even if
|
||||
// there is no compound stmt. C90 does not have this clause. We only do this
|
||||
// if the body isn't a compound statement to avoid push/pop in common cases.
|
||||
|
|
@ -2395,6 +2398,14 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc,
|
|||
return StmtError();
|
||||
}
|
||||
|
||||
// attribute-specifier without attribute (`[[]]`) isn't in AST.
|
||||
// `__declspec()` is only applied to declarations, so we can ignore it.
|
||||
if (!isa<CompoundStmt>(Body.get()) || BodyStartsWithAttr)
|
||||
Diag(BodyBeginLoc,
|
||||
isa<CompoundStmt>(Body.get()->stripLabelLikeStatements())
|
||||
? diag::ext_expansion_stmt_body_attr
|
||||
: diag::ext_expansion_stmt_body_not_compound_stmt);
|
||||
|
||||
return Actions.FinishCXXExpansionStmt(ForRangeStmt.get(), Body.get());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ Parser::TPResult Parser::TryConsumeDeclarationSpecifier() {
|
|||
case tok::kw_typeof_unqual:
|
||||
case tok::kw___attribute:
|
||||
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
{
|
||||
ConsumeToken();
|
||||
if (Tok.isNot(tok::l_paren))
|
||||
|
|
@ -1550,7 +1550,7 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename,
|
|||
}
|
||||
|
||||
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
return TPResult::True;
|
||||
|
||||
// C11 _Alignas
|
||||
|
|
@ -1594,7 +1594,7 @@ bool Parser::isCXXDeclarationSpecifierAType() {
|
|||
case tok::kw_typeof:
|
||||
case tok::kw_typeof_unqual:
|
||||
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
return true;
|
||||
|
||||
// elaborated-type-specifier
|
||||
|
|
|
|||
|
|
@ -365,7 +365,7 @@ bool Declarator::isDeclarationOfFunction() const {
|
|||
return false;
|
||||
|
||||
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case TST_##Trait:
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
case TST_typename:
|
||||
case TST_typeof_unqualType:
|
||||
case TST_typeofType: {
|
||||
|
|
@ -573,7 +573,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T,
|
|||
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \
|
||||
case DeclSpec::TST_##Trait: \
|
||||
return "__" #Trait;
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
case DeclSpec::TST_unknown_anytype: return "__unknown_anytype";
|
||||
case DeclSpec::TST_atomic: return "_Atomic";
|
||||
case DeclSpec::TST_BFloat16: return "__bf16";
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ static CXXRecordDecl *getCurrentInstantiationOf(QualType T,
|
|||
|
||||
DeclContext *Sema::computeDeclContext(QualType T) {
|
||||
if (!T->isDependentType())
|
||||
if (auto *D = T->getAsTagDecl())
|
||||
if (auto *D = T->getAsRecordDecl())
|
||||
return D;
|
||||
return ::getCurrentInstantiationOf(T, CurContext);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/ExprConcepts.h"
|
||||
#include "clang/AST/RecursiveASTVisitor.h"
|
||||
#include "clang/AST/TextNodeDumper.h"
|
||||
#include "clang/Basic/OperatorPrecedence.h"
|
||||
#include "clang/Sema/EnterExpressionEvaluationContext.h"
|
||||
#include "clang/Sema/Initialization.h"
|
||||
|
|
@ -30,6 +31,7 @@
|
|||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/Support/SaveAndRestore.h"
|
||||
#include "llvm/Support/ScopedPrinter.h"
|
||||
#include "llvm/Support/TimeProfiler.h"
|
||||
|
||||
using namespace clang;
|
||||
|
|
@ -2974,3 +2976,148 @@ bool SubsumptionChecker::Subsumes(Literal A, Literal B) {
|
|||
}
|
||||
llvm_unreachable("unknown literal kind");
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class DumpNormalizedConstraint {
|
||||
raw_ostream &OS;
|
||||
const PrintingPolicy &PP;
|
||||
TextNodeDumper TD;
|
||||
|
||||
public:
|
||||
DumpNormalizedConstraint(raw_ostream &OS, ASTContext &Context)
|
||||
: OS(OS), PP(Context.getPrintingPolicy()),
|
||||
TD(OS, Context, /*ShowColors=*/false) {}
|
||||
|
||||
void dump(const NormalizedConstraint &N) {
|
||||
TD.AddChild([&] { Traverse(N); });
|
||||
}
|
||||
|
||||
private:
|
||||
void Traverse(const NormalizedConstraint &N) {
|
||||
switch (N.getKind()) {
|
||||
case NormalizedConstraint::ConstraintKind::Compound:
|
||||
VisitCompound(static_cast<const CompoundConstraint &>(N));
|
||||
break;
|
||||
case NormalizedConstraint::ConstraintKind::Atomic:
|
||||
VisitAtomic(static_cast<const AtomicConstraint &>(N));
|
||||
break;
|
||||
case NormalizedConstraint::ConstraintKind::ConceptId:
|
||||
VisitConceptId(static_cast<const ConceptIdConstraint &>(N));
|
||||
break;
|
||||
case NormalizedConstraint::ConstraintKind::FoldExpanded:
|
||||
VisitFoldExpanded(static_cast<const FoldExpandedConstraint &>(N));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void WriteNodeHeader(const NormalizedConstraint &N, StringRef Kind) {
|
||||
OS << Kind;
|
||||
TD.dumpPointer(&N);
|
||||
TD.dumpSourceRange(N.getSourceRange());
|
||||
}
|
||||
|
||||
void WritePackIndex(const NormalizedConstraintWithParamMapping &N) {
|
||||
if (auto Idx = N.getPackSubstitutionIndex())
|
||||
OS << " SubstIndex=" << *Idx;
|
||||
}
|
||||
|
||||
void VisitCompound(const CompoundConstraint &C) {
|
||||
WriteNodeHeader(C, "CompoundConstraint");
|
||||
OS << " "
|
||||
<< (C.getCompoundKind() == NormalizedConstraint::CCK_Conjunction
|
||||
? "Conjunction"
|
||||
: "Disjunction");
|
||||
TD.AddChild([&] { Traverse(C.getLHS()); });
|
||||
TD.AddChild([&] { Traverse(C.getRHS()); });
|
||||
}
|
||||
|
||||
void VisitAtomic(const AtomicConstraint &A) {
|
||||
WriteNodeHeader(A, "AtomicConstraint");
|
||||
WritePackIndex(A);
|
||||
OS << " ";
|
||||
A.getConstraintExpr()->printPretty(OS, /*Helper=*/nullptr, PP);
|
||||
WriteParameterMapping(A);
|
||||
}
|
||||
|
||||
void VisitConceptId(const ConceptIdConstraint &C) {
|
||||
WriteNodeHeader(C, "ConceptIdConstraint");
|
||||
WritePackIndex(C);
|
||||
OS << " ";
|
||||
if (auto *CSE = C.getConceptSpecializationExpr()) {
|
||||
CSE->printPretty(OS, /*Helper=*/nullptr, PP);
|
||||
} else {
|
||||
C.getConceptId()->print(OS, PP);
|
||||
}
|
||||
WriteParameterMapping(C);
|
||||
TD.AddChild([&] { Traverse(C.getNormalizedConstraint()); });
|
||||
}
|
||||
|
||||
void VisitFoldExpanded(const FoldExpandedConstraint &F) {
|
||||
WriteNodeHeader(F, "FoldExpandedConstraint");
|
||||
OS << " "
|
||||
<< (F.getFoldOperator() == FoldExpandedConstraint::FoldOperatorKind::And
|
||||
? "And"
|
||||
: "Or");
|
||||
WritePackIndex(F);
|
||||
OS << " ";
|
||||
F.getPattern()->printPretty(OS, /*Helper=*/nullptr, PP);
|
||||
WriteParameterMapping(F);
|
||||
TD.AddChild([&] { Traverse(F.getNormalizedPattern()); });
|
||||
}
|
||||
|
||||
void WriteParameterMapping(const NormalizedConstraintWithParamMapping &N) {
|
||||
if (!N.hasParameterMapping() || N.mappingOccurenceList().none())
|
||||
return;
|
||||
TD.AddChild([this, Indexes(N.mappingOccurenceList()),
|
||||
IndexesForSub(N.mappingOccurenceListForSubsumption()),
|
||||
Mapping(N.getParameterMapping()),
|
||||
TPL(N.getUsedTemplateParamList())] {
|
||||
OS << "ParameterMapping";
|
||||
WriteOccurenceList("Indexes", Indexes);
|
||||
WriteOccurenceList("IndexesForSubsumption", IndexesForSub);
|
||||
unsigned Slot = 0;
|
||||
for (unsigned ParamIndex : Indexes.set_bits()) {
|
||||
TD.AddChild([this, Slot, ParamIndex, Mapping, TPL] {
|
||||
assert(TPL && Slot < TPL->size());
|
||||
const NamedDecl *Param = TPL->getParam(Slot);
|
||||
OS << "#" << ParamIndex << ": <";
|
||||
Param->print(OS, PP);
|
||||
OS << "> -> ";
|
||||
Mapping[Slot].getArgument().print(PP, OS,
|
||||
/*IncludeType=*/false);
|
||||
TD.AddChild([this, Slot, Mapping] {
|
||||
const TemplateArgument &TA = Mapping[Slot].getArgument();
|
||||
OS << "TemplateArgument " << TA.getKindName();
|
||||
TD.dumpPointer(&TA);
|
||||
});
|
||||
});
|
||||
++Slot;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void WriteOccurenceList(StringRef Label,
|
||||
const NormalizedConstraint::OccurenceList &BV) {
|
||||
if (BV.none())
|
||||
return;
|
||||
OS << " " << Label << "={"
|
||||
<< llvm::join(
|
||||
llvm::map_range(
|
||||
llvm::make_range(BV.set_bits_begin(), BV.set_bits_end()),
|
||||
[](unsigned I) { return llvm::to_string(I); }),
|
||||
", ")
|
||||
<< '}';
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
LLVM_DUMP_METHOD void NormalizedConstraint::dump(ASTContext &Context) const {
|
||||
dump(llvm::errs(), Context);
|
||||
}
|
||||
|
||||
LLVM_DUMP_METHOD void NormalizedConstraint::dump(llvm::raw_ostream &OS,
|
||||
ASTContext &Context) const {
|
||||
return DumpNormalizedConstraint(OS, Context).dump(*this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4768,7 +4768,11 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
|
|||
New->setInvalidDecl();
|
||||
}
|
||||
|
||||
if (NewTemplate && OldTemplate)
|
||||
mergeDeclAttributes(NewTemplate, OldTemplate);
|
||||
|
||||
mergeDeclAttributes(New, Old);
|
||||
|
||||
// Warn if an already-defined variable is made a weak_import in a subsequent
|
||||
// declaration
|
||||
if (New->hasAttr<WeakImportAttr>())
|
||||
|
|
@ -6226,7 +6230,7 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
|
|||
case DeclSpec::TST_typeofType:
|
||||
case DeclSpec::TST_typeof_unqualType:
|
||||
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case DeclSpec::TST_##Trait:
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
case DeclSpec::TST_atomic: {
|
||||
// Grab the type from the parser.
|
||||
TypeSourceInfo *TSI = nullptr;
|
||||
|
|
|
|||
|
|
@ -359,13 +359,15 @@ Sema::ActOnParamDefaultArgument(Decl *param, SourceLocation EqualLoc,
|
|||
return ActOnParamDefaultArgumentError(param, EqualLoc, DefaultArg);
|
||||
}
|
||||
|
||||
// Check for unexpanded parameter packs.
|
||||
if (DiagnoseUnexpandedParameterPack(DefaultArg, UPPC_DefaultArgument))
|
||||
return ActOnParamDefaultArgumentError(param, EqualLoc, DefaultArg);
|
||||
|
||||
// C++11 [dcl.fct.default]p3
|
||||
// A default argument expression [...] shall not be specified for a
|
||||
// parameter pack.
|
||||
//
|
||||
// Check this before looking for unexpanded parameter packs in DefaultArg:
|
||||
// if DefaultArg references a pack from an enclosing lambda/block, that
|
||||
// check would (incorrectly) mark the lambda as containing an unexpanded
|
||||
// pack that never actually appears in the final AST once we discard
|
||||
// DefaultArg below.
|
||||
if (Param->isParameterPack()) {
|
||||
Diag(EqualLoc, diag::err_param_default_argument_on_parameter_pack)
|
||||
<< DefaultArg->getSourceRange();
|
||||
|
|
@ -374,6 +376,10 @@ Sema::ActOnParamDefaultArgument(Decl *param, SourceLocation EqualLoc,
|
|||
return;
|
||||
}
|
||||
|
||||
// Check for unexpanded parameter packs.
|
||||
if (DiagnoseUnexpandedParameterPack(DefaultArg, UPPC_DefaultArgument))
|
||||
return ActOnParamDefaultArgumentError(param, EqualLoc, DefaultArg);
|
||||
|
||||
ExprResult Result = ConvertParamDefaultArgument(Param, DefaultArg, EqualLoc);
|
||||
if (Result.isInvalid())
|
||||
return ActOnParamDefaultArgumentError(param, EqualLoc, DefaultArg);
|
||||
|
|
|
|||
|
|
@ -15221,6 +15221,24 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
|
|||
return CheckForImmediateInvocation(CE, CE->getDirectCallee());
|
||||
}
|
||||
|
||||
void Sema::LookupOverloadedUnaryOp(OverloadCandidateSet &CandidateSet,
|
||||
OverloadedOperatorKind Op,
|
||||
const UnresolvedSetImpl &Fns,
|
||||
ArrayRef<Expr *> Args, bool PerformADL) {
|
||||
assert(Op != OO_None && "Invalid opcode for overloaded unary operator");
|
||||
|
||||
SourceLocation OpLoc = CandidateSet.getLocation();
|
||||
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
|
||||
|
||||
AddNonMemberOperatorCandidates(Fns, Args, CandidateSet);
|
||||
AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet);
|
||||
if (PerformADL)
|
||||
AddArgumentDependentLookupCandidates(OpName, OpLoc, Args,
|
||||
/*ExplicitTemplateArgs*/ nullptr,
|
||||
CandidateSet);
|
||||
AddBuiltinOperatorCandidates(Op, OpLoc, Args, CandidateSet);
|
||||
}
|
||||
|
||||
ExprResult
|
||||
Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
|
||||
const UnresolvedSetImpl &Fns,
|
||||
|
|
@ -15274,22 +15292,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
|
|||
|
||||
// Build an empty overload set.
|
||||
OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator);
|
||||
|
||||
// Add the candidates from the given function set.
|
||||
AddNonMemberOperatorCandidates(Fns, ArgsArray, CandidateSet);
|
||||
|
||||
// Add operator candidates that are member functions.
|
||||
AddMemberOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet);
|
||||
|
||||
// Add candidates from ADL.
|
||||
if (PerformADL) {
|
||||
AddArgumentDependentLookupCandidates(OpName, OpLoc, ArgsArray,
|
||||
/*ExplicitTemplateArgs*/nullptr,
|
||||
CandidateSet);
|
||||
}
|
||||
|
||||
// Add builtin operator candidates.
|
||||
AddBuiltinOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet);
|
||||
LookupOverloadedUnaryOp(CandidateSet, Op, Fns, ArgsArray, PerformADL);
|
||||
|
||||
bool HadMultipleCandidates = (CandidateSet.size() > 1);
|
||||
|
||||
|
|
|
|||
|
|
@ -2289,8 +2289,10 @@ DeclResult Sema::CheckClassTemplate(
|
|||
|
||||
ProcessDeclAttributeList(S, NewClass, Attr);
|
||||
|
||||
if (PrevClassTemplate)
|
||||
if (PrevClassTemplate) {
|
||||
mergeDeclAttributes(NewTemplate, PrevClassTemplate);
|
||||
mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl());
|
||||
}
|
||||
|
||||
AddPushedVisibilityAttribute(NewClass);
|
||||
inferGslOwnerPointerAttribute(NewClass);
|
||||
|
|
|
|||
|
|
@ -2538,6 +2538,8 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateDecl(VarTemplateDecl *D) {
|
|||
}
|
||||
|
||||
Owner->addDecl(Inst);
|
||||
SemaRef.InstantiateAttrsForDecl(TemplateArgs, D, Inst, LateAttrs,
|
||||
StartingScope);
|
||||
|
||||
if (!PrevVarTemplate) {
|
||||
// Queue up any out-of-line partial specializations of this member
|
||||
|
|
|
|||
|
|
@ -1145,7 +1145,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
|
|||
case TST_typeof_unqualType:
|
||||
case TST_typeofType:
|
||||
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case TST_##Trait:
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
case TST_atomic: {
|
||||
QualType T = DS.getRepAsType().get();
|
||||
if (!T.isNull() && T->containsUnexpandedParameterPack())
|
||||
|
|
|
|||
|
|
@ -887,7 +887,7 @@ TSTToUnaryTransformType(DeclSpec::TST SwitchTST) {
|
|||
#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait) \
|
||||
case TST_##Trait: \
|
||||
return UnaryTransformType::Enum;
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
default:
|
||||
llvm_unreachable("attempted to parse a non-unary transform builtin");
|
||||
}
|
||||
|
|
@ -1307,7 +1307,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
|
|||
}
|
||||
|
||||
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case DeclSpec::TST_##Trait:
|
||||
#include "clang/Basic/TransformTypeTraits.def"
|
||||
#include "clang/Basic/Traits.inc"
|
||||
Result = S.GetTypeFromParser(DS.getRepAsType());
|
||||
assert(!Result.isNull() && "Didn't get a type for the transformation?");
|
||||
Result = S.BuildUnaryTransformType(
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue