Merge branch 'main' into users/c8ef/generator

This commit is contained in:
Connector Switch 2026-07-21 19:48:14 +08:00 committed by GitHub
commit 1ff848a50f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
1042 changed files with 80624 additions and 58304 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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();

View file

@ -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 =

View file

@ -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

View file

@ -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
----------------------

View file

@ -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 "")

View file

@ -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)

View file

@ -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

View file

@ -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:

View file

@ -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

View file

@ -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)=

View file

@ -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)

View file

@ -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; }

View file

@ -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:

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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">;

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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

View 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];
}

View file

@ -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

View file

@ -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;

View file

@ -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 = {});

View file

@ -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);

View file

@ -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>,

View file

@ -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();

View file

@ -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.
///

View file

@ -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 *

View file

@ -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(); }

View file

@ -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(); }

View file

@ -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,

View file

@ -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 * }

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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"
}
}

View file

@ -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()) << " ";

View file

@ -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()) {

View file

@ -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"
}
}

View file

@ -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());

View file

@ -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_");

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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 {

View file

@ -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) {

View file

@ -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.

View file

@ -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>;

View file

@ -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

View file

@ -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 {

View file

@ -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

View file

@ -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.

View file

@ -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 {

View file

@ -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 {

View file

@ -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 {

View file

@ -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

View file

@ -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!");

View file

@ -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);

View file

@ -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:

View file

@ -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:

View file

@ -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:

View file

@ -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);

View file

@ -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,

View file

@ -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,

View file

@ -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(

View file

@ -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.

View file

@ -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);
}

View file

@ -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;

View file

@ -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.

View file

@ -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(

View file

@ -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;
}

View file

@ -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

View file

@ -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);
}

View file

@ -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.

View file

@ -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);

View file

@ -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:

View file

@ -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"
}
}

View file

@ -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.

View file

@ -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,

View file

@ -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)) {

View file

@ -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"
}
}

View file

@ -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());
}

View file

@ -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

View file

@ -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";

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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())

View file

@ -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